Skip to contentSkip to conversation

Add A9 CPU complex support

PATCH New Tom Warren 4 participants 16 messages Feb 16, 2011 – Mar 18, 2011

Subsystems (2)
lore
Share & tools
lore

Tom Warren

author
#0 lore raw

PATCH 1/1 Add A9 CPU complex support

This patch adds code to initialize the A9 dual CPU complex in the Tegra2 SoC. The code is run on the AVP first to set up the A9 and Coresight clocks, then the AVP is halted, the A9 CPU is brought out of reset, and the code executes again on the CPU, but down a slightly different path. Normal POST then proceeds using the A9 CPU.

Tom Warren (1):
arm: Tegra2: add support for A9 CPU init

 arch/arm/cpu/armv7/start.S                 |    6 +
 arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
 arch/arm/cpu/armv7/tegra2/ap20.c           |  490 ++++++++++++++++++++++++++++
 arch/arm/cpu/armv7/tegra2/ap20.h           |  105 ++++++
 arch/arm/include/asm/arch-tegra2/clk_rst.h |   27 ++
 arch/arm/include/asm/arch-tegra2/pmc.h     |    8 +
 arch/arm/include/asm/arch-tegra2/scu.h     |   43 +++
 arch/arm/include/asm/arch-tegra2/tegra2.h  |    5 +
 board/nvidia/common/board.c                |   10 +
 board/nvidia/common/board.h                |   29 ++
 include/configs/harmony.h                  |    1 +
 include/configs/seaboard.h                 |    1 +
 include/configs/tegra2-common.h            |    2 +
 13 files changed, 728 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/tegra2/ap20.c
 create mode 100644 arch/arm/cpu/armv7/tegra2/ap20.h
 create mode 100644 arch/arm/include/asm/arch-tegra2/scu.h
 create mode 100644 board/nvidia/common/board.h
Signature · 1 line
1.7.4.1
author
#1 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

---
 arch/arm/cpu/armv7/start.S                 |    6 +
 arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
 arch/arm/cpu/armv7/tegra2/ap20.c           |  490 ++++++++++++++++++++++++++++
 arch/arm/cpu/armv7/tegra2/ap20.h           |  105 ++++++
 arch/arm/include/asm/arch-tegra2/clk_rst.h |   27 ++
 arch/arm/include/asm/arch-tegra2/pmc.h     |    8 +
 arch/arm/include/asm/arch-tegra2/scu.h     |   43 +++
 arch/arm/include/asm/arch-tegra2/tegra2.h  |    5 +
 board/nvidia/common/board.c                |   10 +
 board/nvidia/common/board.h                |   29 ++
 include/configs/harmony.h                  |    1 +
 include/configs/seaboard.h                 |    1 +
 include/configs/tegra2-common.h            |    2 +
 13 files changed, 728 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/cpu/armv7/tegra2/ap20.c
 create mode 100644 arch/arm/cpu/armv7/tegra2/ap20.h
 create mode 100644 arch/arm/include/asm/arch-tegra2/scu.h
 create mode 100644 board/nvidia/common/board.h
arch/arm/cpu/armv7/start.S +6 -0
index 684f2d2..50a1725 100644
@@ -70,6 +70,12 @@ _end_vect:
 _TEXT_BASE:
 	.word	CONFIG_SYS_TEXT_BASE
 
+#ifdef CONFIG_TEGRA2
+.globl _armboot_start
+_armboot_start:
+        .word _start
+#endif
+
 /*
  * These are defined in the board-specific linker script.
  */
arch/arm/cpu/armv7/tegra2/Makefile +1 -1
index 687c887..f1ea915 100644
@@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk
 LIB	=  $(obj)lib$(SOC).o
 
 SOBJS	:= lowlevel_init.o
-COBJS	:= board.o sys_info.o timer.o
+COBJS	:= ap20.o board.o sys_info.o timer.o
 
 SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
arch/arm/cpu/armv7/tegra2/ap20.c new file +490 -0

490 lines not on this page · raw message

arch/arm/cpu/armv7/tegra2/ap20.h new file +105 -0

105 lines not on this page · raw message

arch/arm/include/asm/arch-tegra2/clk_rst.h +27 -0
index 6d573bf..d67a5d7 100644
@@ -149,6 +149,9 @@ struct clk_rst_ctlr {
 	uint crc_clk_src_csite;		/*_CSITE_0,		0x1D4 */
 	uint crc_reserved19[9];		/*			0x1D8-1F8 */
 	uint crc_clk_src_osc;		/*_OSC_0,		0x1FC */
+	uint crc_reserved20[80];	/*			0x200-33C */
+	uint crc_cpu_cmplx_set;		/* _CPU_CMPLX_SET_0,	0x340 */
+	uint crc_cpu_cmplx_clr;		/* _CPU_CMPLX_CLR_0,	0x344 */
 };
 
 #define PLL_BYPASS		(1 << 31)
@@ -162,4 +165,28 @@ struct clk_rst_ctlr {
 #define SWR_UARTA_RST		(1 << 6)
 #define CLK_ENB_UARTA		(1 << 6)
 
+#define SWR_CPU_RST		(1 << 0)
+#define CLK_ENB_CPU		(1 << 0)
+#define SWR_CSITE_RST		(1 << 9)
+#define CLK_ENB_CSITE		(1 << 9)
+
+#define SET_CPURESET0		(1 << 0)
+#define SET_DERESET0		(1 << 4)
+#define SET_DBGRESET0		(1 << 12)
+
+#define SET_CPURESET1		(1 << 1)
+#define SET_DERESET1		(1 << 5)
+#define SET_DBGRESET1		(1 << 13)
+
+#define CLR_CPURESET0		(1 << 0)
+#define CLR_DERESET0		(1 << 4)
+#define CLR_DBGRESET0		(1 << 12)
+
+#define CLR_CPURESET1		(1 << 1)
+#define CLR_DERESET1		(1 << 5)
+#define CLR_DBGRESET1		(1 << 13)
+
+#define CPU0_CLK_STP		(1 << 8)
+#define CPU1_CLK_STP		(1 << 9)
+
 #endif	/* CLK_RST_H */
arch/arm/include/asm/arch-tegra2/pmc.h +8 -0
index 7ec9eeb..b1d47cd 100644
@@ -121,4 +121,12 @@ struct pmc_ctlr {
 	uint pmc_gate;			/* _GATE_0, offset 15C */
 };
 
+#define CPU_PWRED	1
+#define CPU_CLMP	1
+
+#define PARTID_CP	0xFFFFFFF8
+#define START_CP	(1 << 8)
+
+#define CPUPWRREQ_OE	(1 << 16)
+
 #endif	/* PMC_H */
arch/arm/include/asm/arch-tegra2/scu.h new file +43 -0

43 lines not on this page · raw message

arch/arm/include/asm/arch-tegra2/tegra2.h +5 -0
index 9001b68..5813cd9 100644
@@ -25,8 +25,12 @@
 #define _TEGRA2_H_
 
 #define NV_PA_SDRAM_BASE	0x00000000
+#define NV_PA_ARM_PERIPHBASE	0x50040000
+#define NV_PA_PG_UP_BASE	0x60000000
 #define NV_PA_TMRUS_BASE	0x60005010
 #define NV_PA_CLK_RST_BASE	0x60006000
+#define NV_PA_FLOW_BASE		0x60007000
+#define NV_PA_EVP_BASE		0x6000F000
 #define NV_PA_APB_MISC_BASE	0x70000000
 #define NV_PA_APB_UARTA_BASE	(NV_PA_APB_MISC_BASE + 0x6000)
 #define NV_PA_APB_UARTB_BASE	(NV_PA_APB_MISC_BASE + 0x6040)
@@ -34,6 +38,7 @@
 #define NV_PA_APB_UARTD_BASE	(NV_PA_APB_MISC_BASE + 0x6300)
 #define NV_PA_APB_UARTE_BASE	(NV_PA_APB_MISC_BASE + 0x6400)
 #define NV_PA_PMC_BASE		0x7000E400
+#define NV_PA_CSITE_BASE	0x70040000
 
 #define TEGRA2_SDRC_CS0		NV_PA_SDRAM_BASE
 #define LOW_LEVEL_SRAM_STACK	0x4000FFFC
board/nvidia/common/board.c +10 -0
index b2c412c..078547b 100644
@@ -30,6 +30,7 @@
 #include <asm/arch/clk_rst.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/uart.h>
+#include "board.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -37,6 +38,15 @@ const struct tegra2_sysinfo sysinfo = {
 	CONFIG_TEGRA2_BOARD_STRING
 };
 
+#ifdef CONFIG_BOARD_EARLY_INIT_F
+int board_early_init_f(void)
+{
+	debug("Board Early Init\n");
+	tegra2_start();
+	return 0;
+}
+#endif	/* EARLY_INIT */
+
 /*
  * Routine: timer_init
  * Description: init the timestamp and lastinc value
board/nvidia/common/board.h new file +29 -0
new file mode 100644
index 0000000..47c7885
@@ -0,0 +1,29 @@
+/*
+ *  (C) Copyright 2010,2011
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _BOARD_H_
+#define _BOARD_H_
+
+void tegra2_start(void);
+
+#endif	/* BOARD_H */
include/configs/harmony.h +1 -0
index d004f31..34bd899 100644
@@ -46,4 +46,5 @@
 #define CONFIG_MACH_TYPE		MACH_TYPE_HARMONY
 #define CONFIG_SYS_BOARD_ODMDATA	0x300d8011 /* lp1, 1GB */
 
+#define CONFIG_BOARD_EARLY_INIT_F
 #endif /* __CONFIG_H */
include/configs/seaboard.h +1 -0
index fd87560..b7b72bb 100644
@@ -40,4 +40,5 @@
 #define CONFIG_MACH_TYPE		MACH_TYPE_TEGRA_SEABOARD
 #define CONFIG_SYS_BOARD_ODMDATA	0x300d8011 /* lp1, 1GB */
 
+#define CONFIG_BOARD_EARLY_INIT_F
 #endif /* __CONFIG_H */
include/configs/tegra2-common.h +2 -0
index 4f4374a..2924325 100644
@@ -33,6 +33,8 @@
 #define CONFIG_MACH_TEGRA_GENERIC	/* which is a Tegra generic machine */
 #define CONFIG_L2_OFF			/* No L2 cache */
 
+#define CONFIG_ENABLE_CORTEXA9		/* enable CPU (A9 complex) */
+
 #include <asm/arch/tegra2.h>		/* get chip and board defs */
 
 /*
Signature · 1 line
1.7.4.1
author
#2 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Anyone willing to review this? I'd like to get it pulled in to Albert's arm repo ASAP.

Thanks,

Tom

Quoted 892 lines · Tom Warren

---

?arch/arm/cpu/armv7/start.S ? ? ? ? ? ? ? ? | ? ?6 +
?arch/arm/cpu/armv7/tegra2/Makefile ? ? ? ? | ? ?2 +-
?arch/arm/cpu/armv7/tegra2/ap20.c ? ? ? ? ? | ?490 ++++++++++++++++++++++++++++
?arch/arm/cpu/armv7/tegra2/ap20.h ? ? ? ? ? | ?105 ++++++
?arch/arm/include/asm/arch-tegra2/clk_rst.h | ? 27 ++
?arch/arm/include/asm/arch-tegra2/pmc.h ? ? | ? ?8 +
?arch/arm/include/asm/arch-tegra2/scu.h ? ? | ? 43 +++
?arch/arm/include/asm/arch-tegra2/tegra2.h ?| ? ?5 +
?board/nvidia/common/board.c ? ? ? ? ? ? ? ?| ? 10 +
?board/nvidia/common/board.h ? ? ? ? ? ? ? ?| ? 29 ++
?include/configs/harmony.h ? ? ? ? ? ? ? ? ?| ? ?1 +
?include/configs/seaboard.h ? ? ? ? ? ? ? ? | ? ?1 +
?include/configs/tegra2-common.h ? ? ? ? ? ?| ? ?2 +

?13 files changed, 728 insertions(+), 1 deletions(-) ?create mode 100644 arch/arm/cpu/armv7/tegra2/ap20.c ?create mode 100644 arch/arm/cpu/armv7/tegra2/ap20.h ?create mode 100644 arch/arm/include/asm/arch-tegra2/scu.h ?create mode 100644 board/nvidia/common/board.h

arch/arm/cpu/armv7/start.S +0 -0
index 684f2d2..50a1725 100644
@@ -70,6 +70,12 @@ _end_vect:

?_TEXT_BASE:
? ? ? ?.word ? CONFIG_SYS_TEXT_BASE

arch/arm/cpu/armv7/start.S +6 -0
+#ifdef CONFIG_TEGRA2
+.globl _armboot_start
+_armboot_start:
+ ? ? ? ?.word _start
+#endif
+

?/*
?* These are defined in the board-specific linker script. ?*/

arch/arm/cpu/armv7/tegra2/Makefile +0 -0
index 687c887..f1ea915 100644
@@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk

?LIB ? ?= ?$(obj)lib$(SOC).o

?SOBJS ?:= lowlevel_init.o

arch/arm/cpu/armv7/tegra2/Makefile +1 -1
-COBJS ?:= board.o sys_info.o timer.o
+COBJS ?:= ap20.o board.o sys_info.o timer.o

?SRCS ? := $(SOBJS:.o=.S) $(COBJS:.o=.c)
?OBJS ? := $(addprefix $(obj),$(COBJS) $(SOBJS))

arch/arm/cpu/armv7/tegra2/ap20.c new file +490 -0
new file mode 100644
index 0000000..89d0d5e
@@ -0,0 +1,490 @@
+/*
+* (C) Copyright 2010-2011
+* NVIDIA Corporation <www.nvidia.com>
+*
+* See file CREDITS for list of people who contributed to this
+* project.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation; either version 2 of
+* the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+* MA 02111-1307 USA
+*/
+
+#include "ap20.h"
+#include <asm/io.h>
+#include <asm/arch/tegra2.h>
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/pmc.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/scu.h>
+#include <common.h>
+
+static void init_pll_x(void)
+{
+ ? ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? ? u32 ? ? reg;
+
+ ? ? ? /* Is PLL-X already running? */
+ ? ? ? reg = readl(&clkrst->crc_pllx_base);
+ ? ? ? if (reg & PLL_ENABLE)
+ ? ? ? ? ? ? ? return;
+
+ ? ? ? /* Do PLLX init if it isn't running, but BootROM sets it, so TBD */
+}
+
+static void set_cpu_reset_vector(u32 vector)
+{
+ ? ? ? writel(vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+}
+
+static void enable_cpu_clock(int enable)
+{
+ ? ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? ? u32 ? reg, clk;
+
+ ? ? ? /*
+ ? ? ? ?* NOTE:
+ ? ? ? ?* Regardless of whether the request is to enable or disable the CPU
+ ? ? ? ?* clock, every processor in the CPU complex except the master (CPU 0)
+ ? ? ? ?* will have it's clock stopped because the AVP only talks to the
+ ? ? ? ?* master. The AVP does not know (nor does it need to know) that there
+ ? ? ? ?* are multiple processors in the CPU complex.
+ ? ? ? ?*/
+
+ ? ? ? /* Need to initialize PLLX? */
+ ? ? ? if (enable) {
+ ? ? ? ? ? ? ? /* Initialize PLL */
+ ? ? ? ? ? ? ? init_pll_x();
+
+ ? ? ? ? ? ? ? /* Wait until stable */
+ ? ? ? ? ? ? ? udelay(NVBOOT_CLOCKS_PLL_STABILIZATION_DELAY);
+
+ ? ? ? ? ? ? ? reg = CCLK_BURST_POLICY;
+ ? ? ? ? ? ? ? writel(reg, &clkrst->crc_cclk_brst_pol);
+
+ ? ? ? ? ? ? ? reg = SUPER_CCLK_DIVIDER;
+ ? ? ? ? ? ? ? writel(reg, &clkrst->crc_super_cclk_div);
+ ? ? ? }
+
+ ? ? ? /* Fetch the register containing the main CPU complex clock enable */
+ ? ? ? reg = readl(&clkrst->crc_clk_out_enb_l);
+
+ ? ? ? /*
+ ? ? ? ?* Read the register containing the individual CPU clock enables and
+ ? ? ? ?* always stop the clock to CPU 1.
+ ? ? ? ?*/
+ ? ? ? clk = readl(&clkrst->crc_clk_cpu_cmplx);
+ ? ? ? clk |= CPU1_CLK_STP;
+
+ ? ? ? if (enable) {
+ ? ? ? ? ? ? ? /* Enable the CPU clock */
+ ? ? ? ? ? ? ? reg = readl(&clkrst->crc_clk_out_enb_l);
+ ? ? ? ? ? ? ? reg |= CLK_ENB_CPU;
+ ? ? ? ? ? ? ? clk = readl(&clkrst->crc_clk_cpu_cmplx);
+ ? ? ? ? ? ? ? clk &= ~CPU0_CLK_STP;
+ ? ? ? } else {
+ ? ? ? ? ? ? ? /* Disable the CPU clock */
+ ? ? ? ? ? ? ? reg = readl(&clkrst->crc_clk_out_enb_l);
+ ? ? ? ? ? ? ? reg |= CLK_ENB_CPU;
+ ? ? ? ? ? ? ? clk = readl(&clkrst->crc_clk_cpu_cmplx);
+ ? ? ? ? ? ? ? clk |= CPU0_CLK_STP;
+ ? ? ? }
+
+ ? ? ? writel(clk, &clkrst->crc_clk_cpu_cmplx);
+ ? ? ? writel(reg, &clkrst->crc_clk_out_enb_l);
+}
+
+static int is_cpu_powered(void)
+{
+ ? ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? ? u32 ? reg;
+
+ ? ? ? reg = readl(&pmc->pmc_pwrgate_status);
+
+ ? ? ? if (reg & CPU_PWRED)
+ ? ? ? ? ? ? ? return TRUE;
+
+ ? ? ? return FALSE;
+}
+
+static void remove_cpu_io_clamps(void)
+{
+ ? ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? ? u32 ? reg;
+
+ ? ? ? /* Remove the clamps on the CPU I/O signals */
+ ? ? ? reg = readl(&pmc->pmc_remove_clamping);
+ ? ? ? reg |= CPU_CLMP;
+ ? ? ? writel(reg, &pmc->pmc_remove_clamping);
+
+ ? ? ? /* Give I/O signals time to stabilize */
+ ? ? ? udelay(1000);
+}
+
+static void powerup_cpu(void)
+{
+ ? ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? ? u32 ? reg;
+
+ ? ? ? if (!is_cpu_powered()) {
+ ? ? ? ? ? ? ? /* Toggle the CPU power state (OFF -> ON) */
+ ? ? ? ? ? ? ? reg = readl(&pmc->pmc_pwrgate_toggle);
+ ? ? ? ? ? ? ? reg &= (PARTID_CP);
+ ? ? ? ? ? ? ? reg |= START_CP;
+ ? ? ? ? ? ? ? writel(reg, &pmc->pmc_pwrgate_toggle);
+
+ ? ? ? ? ? ? ? /* Wait for the power to come up */
+ ? ? ? ? ? ? ? while (!is_cpu_powered())
+ ? ? ? ? ? ? ? ? ? ? ? ; ? ? ? ? ? ? ? ? ? ? ? /* Do nothing */
+
+ ? ? ? ? ? ? ? /*
+ ? ? ? ? ? ? ? ?* Remove the I/O clamps from CPU power partition.
+ ? ? ? ? ? ? ? ?* Recommended only on a Warm boot, if the CPU partition gets
+ ? ? ? ? ? ? ? ?* power gated. Shouldn't cause any harm when called after a
+ ? ? ? ? ? ? ? ?* cold boot according to HW, probably just redundant.
+ ? ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? ? remove_cpu_io_clamps();
+ ? ? ? }
+}
+
+static void enable_cpu_power_rail(void)
+{
+ ? ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? ? u32 ? reg;
+
+ ? ? ? reg = readl(&pmc->pmc_cntrl);
+ ? ? ? reg |= CPUPWRREQ_OE;
+ ? ? ? writel(reg, &pmc->pmc_cntrl);
+
+ ? ? ? /* Delay to allow for stable power (CPU_PWR_REQ -> VDD_CPU from PMU) */
+ ? ? ? udelay(3750);
+}
+
+static void reset_A9_cpu(int reset)
+{
+ ? ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? ? u32 ? reg, cpu;
+
+ ? ? ? /*
+ ? ? ? * NOTE: ?Regardless of whether the request is to hold the CPU in reset
+ ? ? ? * ? ? ? ?or take it out of reset, every processor in the CPU complex
+ ? ? ? * ? ? ? ?except the master (CPU 0) will be held in reset because the
+ ? ? ? * ? ? ? ?AVP only talks to the master. The AVP does not know that there
+ ? ? ? * ? ? ? ?are multiple processors in the CPU complex.
+ ? ? ? */
+
+ ? ? ? /* Hold CPU 1 in reset */
+ ? ? ? cpu = SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1;
+ ? ? ? writel(cpu, &clkrst->crc_cpu_cmplx_set);
+
+ ? ? ? reg = readl(&clkrst->crc_rst_dev_l);
+ ? ? ? if (reset) {
+ ? ? ? ? ? ? ? /* Place CPU0 into reset */
+ ? ? ? ? ? ? ? cpu = SET_DBGRESET0 | SET_DERESET0 | SET_CPURESET0;
+ ? ? ? ? ? ? ? writel(cpu, &clkrst->crc_cpu_cmplx_set);
+
+ ? ? ? ? ? ? ? /* Enable master CPU reset */
+ ? ? ? ? ? ? ? reg |= SWR_CPU_RST;
+
+ ? ? ? } else {
+ ? ? ? ? ? ? ? /* Take CPU0 out of reset */
+ ? ? ? ? ? ? ? cpu = CLR_DBGRESET0 | CLR_DERESET0 | CLR_CPURESET0;
+ ? ? ? ? ? ? ? writel(cpu, &clkrst->crc_cpu_cmplx_clr);
+
+ ? ? ? ? ? ? ? /* Disable master CPU reset */
+ ? ? ? ? ? ? ? reg &= ~SWR_CPU_RST;
+ ? ? ? }
+
+ ? ? ? writel(reg, &clkrst->crc_rst_dev_l);
+}
+
+static void clock_enable_coresight(int enable)
+{
+ ? ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? ? u32 ? rst, clk, src;
+
+ ? ? ? rst = readl(&clkrst->crc_rst_dev_u);
+ ? ? ? clk = readl(&clkrst->crc_clk_out_enb_u);
+
+ ? ? ? if (enable) {
+ ? ? ? ? ? ? ? rst &= ~SWR_CSITE_RST;
+ ? ? ? ? ? ? ? clk |= CLK_ENB_CSITE;
+ ? ? ? } else {
+ ? ? ? ? ? ? ? rst |= SWR_CSITE_RST;
+ ? ? ? ? ? ? ? clk &= ~CLK_ENB_CSITE;
+ ? ? ? }
+
+ ? ? ? writel(clk, &clkrst->crc_clk_out_enb_u);
+ ? ? ? writel(rst, &clkrst->crc_rst_dev_u);
+
+ ? ? ? if (enable) {
+ ? ? ? ? ? ? ? /*
+ ? ? ? ? ? ? ? ?* Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by
+ ? ? ? ? ? ? ? ?* ?1.5, giving an effective frequency of 144MHz.
+ ? ? ? ? ? ? ? ?* Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor
+ ? ? ? ? ? ? ? ?* ?(bits 7:0), so 00000001b == 1.5 (n+1 + .5)
+ ? ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? ? src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
+ ? ? ? ? ? ? ? writel(src, &clkrst->crc_clk_src_csite);
+
+ ? ? ? ? ? ? ? /* Unlock the CPU CoreSight interfaces */
+ ? ? ? ? ? ? ? rst = 0xC5ACCE55;
+ ? ? ? ? ? ? ? writel(rst, CSITE_CPU_DBG0_LAR);
+ ? ? ? ? ? ? ? writel(rst, CSITE_CPU_DBG1_LAR);
+ ? ? ? }
+}
+
+void start_cpu(u32 reset_vector)
+{
+ ? ? ? /* Enable VDD_CPU */
+ ? ? ? enable_cpu_power_rail();
+
+ ? ? ? /* Hold the CPUs in reset */
+ ? ? ? reset_A9_cpu(TRUE);
+
+ ? ? ? /* Disable the CPU clock */
+ ? ? ? enable_cpu_clock(FALSE);
+
+ ? ? ? /* Enable CoreSight */
+ ? ? ? clock_enable_coresight(TRUE);
+
+ ? ? ? /*
+ ? ? ? * Set the entry point for CPU execution from reset,
+ ? ? ? * ?if it's a non-zero value.
+ ? ? ? */
+ ? ? ? if (reset_vector)
+ ? ? ? ? ? ? ? set_cpu_reset_vector(reset_vector);
+
+ ? ? ? /* Enable the CPU clock */
+ ? ? ? enable_cpu_clock(TRUE);
+
+ ? ? ? /* If the CPU doesn't already have power, power it up */
+ ? ? ? if (!is_cpu_powered())
+ ? ? ? ? ? ? ? powerup_cpu();
+
+ ? ? ? /* Take the CPU out of reset */
+ ? ? ? reset_A9_cpu(FALSE);
+}
+
+
+void halt_avp(void)
+{
+ ? ? ? u32 ? reg;
+
+ ? ? ? for (;;) {
+ ? ? ? ? ? ? ? reg = HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \
+ ? ? ? ? ? ? ? ? ? ? ? | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29);
+ ? ? ? ? ? ? ? writel(reg, FLOW_CTLR_HALT_COP_EVENTS);
+ ? ? ? }
+ ? ? ? /* Should never get here */
+ ? ? ? for (;;)
+ ? ? ? ? ? ? ? ;
+}
+
+void startup_cpu(void)
+{
+ ? ? ? /* Initialize the AVP, clocks, and memory controller */
+ ? ? ? /* SDRAM is guaranteed to be on at this point */
+
+ ? ? ? asm volatile(
+
+ ? ? ? /* Start the CPU */
+ ? ? ? /* R0 = reset vector for CPU */
+ ? ? ? "ldr ? ? r0, =cold_boot ? ? ?\n"
+ ? ? ? "bl ? ? ?start_cpu ? ? ? ? ? \n"
+
+ ? ? ? /* Transfer control to the AVP code */
+ ? ? ? "bl ? ? ?halt_avp ? ? ? ? ? ?\n"
+
+ ? ? ? /* Should never get here */
+ ? ? ? "b ? ? ? . ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? );
+}
+
+extern ulong _armboot_start;
+u32 cpu_boot_stack = CPU_EARLY_BOOT_STACK_LIMIT;
+u32 avp_boot_stack = AVP_EARLY_BOOT_STACK_LIMIT;
+u32 proc_tag = PG_UP_TAG_0_PID_CPU & 0xFF;
+u32 deadbeef = 0xdeadbeef;
+
+void cold_boot(void)
+{
+ ? ? ? asm volatile(
+
+ ? ? ? "msr ? ? cpsr_c, #0xd3 ? ? ? ? ? ?\n"
+ ? ? ? /*
+ ? ? ? * Check current processor: CPU or AVP?
+ ? ? ? * If AVP, go to AVP boot code, else continue on.
+ ? ? ? */
+ ? ? ? "mov ? ? r0, %0 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "ldrb ? ?r2, [r0, %1] ? ? ? ? ? ? \n"
+ ? ? ? /* are we the CPU? */
+ ? ? ? "cmp ? ? r2, %2 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "mov ? ? sp, %3 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? /* leave in some symbols for release debugging */
+ ? ? ? "mov ? ? r3, %6 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? ? /* ?yep, we are the CPU */
+ ? ? ? "bxeq ? ? %4 ? ? ? ? ? ? ? ? ? ? ?\n"
+ ? ? ? /* AVP Initialization follows this path */
+ ? ? ? "mov ? ? sp, %5 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? /* leave in some symbols for release debugging */
+ ? ? ? "mov ? ? r3, %6 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+
+ ? ? ? /* Init and Start CPU */
+ ? ? ? "b ? ? ? startup_cpu ? ? ? ? ? ? ?\n"
+ ? ? ? :
+ ? ? ? : "i"(NV_PA_PG_UP_BASE),
+ ? ? ? "i"(PG_UP_TAG_0),
+ ? ? ? "r"(proc_tag),
+ ? ? ? "r"(cpu_boot_stack),
+ ? ? ? "r"(_armboot_start),
+ ? ? ? "r"(avp_boot_stack),
+ ? ? ? "r"(deadbeef)
+ ? ? ? : "r0", "r2", "r3", "cc", "lr"
+ ? ? ? );
+}
+
+void enable_scu(void)
+{
+ ? ? ? struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE;
+ ? ? ? u32 reg;
+
+ ? ? ? reg = readl(&scu->scu_ctrl);
+ ? ? ? if (reg & SCU_ENABLE) {
+ ? ? ? ? ? ? ? /* SCU already enabled, return */
+ ? ? ? ? ? ? ? return;
+ ? ? ? }
+
+ ? ? ? /* Invalidate all ways for all processors */
+ ? ? ? writel(0xFFFF, &scu->scu_inv_all);
+
+ ? ? ? /* Enable SCU - bit 0 */
+ ? ? ? reg = readl(&scu->scu_ctrl);
+ ? ? ? reg |= SCU_ENABLE;
+ ? ? ? writel(reg, &scu->scu_ctrl);
+
+ ? ? ? return;
+}
+
+void cache_configure(void)
+{
+ ? ? ? asm volatile(
+
+ ? ? ? "stmdb r13!,{r14} ? ? ? ? ? ? ? ? \n"
+ ? ? ? /* invalidate instruction cache */
+ ? ? ? "mov r1, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "mcr p15, 0, r1, c7, c5, 0 ? ? ? ?\n"
+
+ ? ? ? /* invalidate the i&d tlb entries */
+ ? ? ? "mcr p15, 0, r1, c8, c5, 0 ? ? ? ?\n"
+ ? ? ? "mcr p15, 0, r1, c8, c6, 0 ? ? ? ?\n"
+
+ ? ? ? /* enable instruction cache */
+ ? ? ? "mrc ?p15, 0, r1, c1, c0, 0 ? ? ? \n"
+ ? ? ? "orr ?r1, r1, #(1<<12) ? ? ? ? ? ?\n"
+ ? ? ? "mcr ?p15, 0, r1, c1, c0, 0 ? ? ? \n"
+
+ ? ? ? "bl enable_scu ? ? ? ? ? ? ? ? ? ?\n"
+
+ ? ? ? /* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */
+ ? ? ? "mrc p15, 0, r0, c1, c0, 1 ? ? ? ?\n"
+ ? ? ? "orr r0, r0, #0x41 ? ? ? ? ? ? ? ?\n"
+ ? ? ? "mcr p15, 0, r0, c1, c0, 1 ? ? ? ?\n"
+
+ ? ? ? /* Now flush the Dcache */
+ ? ? ? "mov r0, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? /* 256 cache lines */
+ ? ? ? "mov r1, #256 ? ? ? ? ? ? ? ? ? ? \n"
+
+ ? ? ? "invalidate_loop: ? ? ? ? ? ? ? ? \n"
+
+ ? ? ? "add r1, r1, #-1 ? ? ? ? ? ? ? ? ?\n"
+ ? ? ? "mov r0, r1, lsl #5 ? ? ? ? ? ? ? \n"
+ ? ? ? /* invalidate d-cache using line (way0) */
+ ? ? ? "mcr p15, 0, r0, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? ? "orr r2, r0, #(1<<30) ? ? ? ? ? ? \n"
+ ? ? ? /* invalidate d-cache using line (way1) */
+ ? ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? ? "orr r2, r0, #(2<<30) ? ? ? ? ? ? \n"
+ ? ? ? /* invalidate d-cache using line (way2) */
+ ? ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? ? "orr r2, r0, #(3<<30) ? ? ? ? ? ? \n"
+ ? ? ? /* invalidate d-cache using line (way3) */
+ ? ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+ ? ? ? "cmp r1, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "bne invalidate_loop ? ? ? ? ? ? ?\n"
+
+ ? ? ? /* FIXME: should have ap20's L2 disabled too */
+ ? ? ? "invalidate_done: ? ? ? ? ? ? ? ? \n"
+ ? ? ? "ldmia r13!,{pc} ? ? ? ? ? ? ? ? ?\n"
+ ? ? ? ".ltorg ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? );
+}
+
+void init_pmc_scratch(void)
+{
+ ? ? ? struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+ ? ? ? /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */
+ ? ? ? memset(&pmc->pmc_scratch1, 0, 23*4);
+ ? ? ? writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20);
+}
+
+u32 s_first_boot = 1;
+
+void cpu_start(void)
+{
+ ? ? ? struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+
+ ? ? ? /* enable JTAG */
+ ? ? ? writel(0xC0, &pmt->pmt_cfg_ctl);
+
+ ? ? ? if (s_first_boot) {
+ ? ? ? ? ? ? ? /*
+ ? ? ? ? ? ? ? ?* Need to set this before cold-booting,
+ ? ? ? ? ? ? ? ?* ?otherwise we'll end up in an infinite loop.
+ ? ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? ? s_first_boot = 0;
+ ? ? ? ? ? ? ? cold_boot();
+ ? ? ? }
+
+ ? ? ? return;
+}
+
+void tegra2_start()
+{
+ ? ? ? if (s_first_boot) {
+ ? ? ? ? ? ? ? /* Init Debug UART Port (115200 8n1) */
+ ? ? ? ? ? ? ? uart_init();
+
+ ? ? ? ? ? ? ? /* Init PMC scratch memory */
+ ? ? ? ? ? ? ? init_pmc_scratch();
+ ? ? ? }
+
+#ifdef CONFIG_ENABLE_CORTEXA9
+ ? ? ? /* take the mpcore out of reset */
+ ? ? ? cpu_start();
+
+ ? ? ? /* configure cache */
+ ? ? ? cache_configure();
+#endif
+}
+
arch/arm/cpu/armv7/tegra2/ap20.h new file +105 -0
new file mode 100644
index 0000000..de7622d
@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright 2010-2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <asm/types.h>
+
+#ifndef ? ? ? ?FALSE
+#define FALSE ?0
+#endif
+#ifndef TRUE
+#define TRUE ? 1
+#endif
+
+#define NVBL_PLLP_KHZ ?(432000/2)
+/* The stabilization delay in usec */
+#define NVBOOT_CLOCKS_PLL_STABILIZATION_DELAY (300)
+
+#define PLLX_ENABLED ? ? ? ? ? (1 << 30)
+#define CCLK_BURST_POLICY ? ? ?0x20008888
+#define SUPER_CCLK_DIVIDER ? ? 0x80000000
+
+/* Calculate clock fractional divider value from ref and target frequencies */
+#define CLK_DIVIDER(REF, FREQ) ?((((REF) * 2) / FREQ) - 2)
+
+/* Calculate clock frequency value from reference and clock divider value */
+#define CLK_FREQUENCY(REF, REG) ?(((REF) * 2) / (REG + 2))
+
+/* AVP/CPU ID */
+#define PG_UP_TAG_0_PID_CPU ? ?0x55555555 ? ? ?/* CPU aka "a9" aka "mpcore" */
+#define PG_UP_TAG_0 ? ? ? ? ? ? 0x0
+
+/* AP20-Specific Base Addresses */
+
+/* AP20 Base physical address of SDRAM. */
+#define AP20_BASE_PA_SDRAM ? ? ?0x00000000
+/* AP20 Base physical address of internal SRAM. */
+#define AP20_BASE_PA_SRAM ? ? ? 0x40000000
+/* AP20 Size of internal SRAM (256KB). */
+#define AP20_BASE_PA_SRAM_SIZE ?0x00040000
+/* AP20 Base physical address of flash. */
+#define AP20_BASE_PA_NOR_FLASH ?0xD0000000
+/* AP20 Base physical address of boot information table. */
+#define AP20_BASE_PA_BOOT_INFO ?AP20_BASE_PA_SRAM
+
+/*
+ * Super-temporary stacks for EXTREMELY early startup. The values chosen for
+ * these addresses must be valid on ALL SOCs because this value is used before
+ * we are able to differentiate between the SOC types.
+ *
+ * NOTE: The since CPU's stack will eventually be moved from IRAM to SDRAM, its
+ * ? ? ? stack is placed below the AVP stack. Once the CPU stack has been moved,
+ * ? ? ? the AVP is free to use the IRAM the CPU stack previously occupied if
+ * ? ? ? it should need to do so.
+ *
+ * NOTE: In multi-processor CPU complex configurations, each processor will have
+ * ? ? ? its own stack of size CPU_EARLY_BOOT_STACK_SIZE. CPU 0 will have a
+ * ? ? ? limit of CPU_EARLY_BOOT_STACK_LIMIT. Each successive CPU will have a
+ * ? ? ? stack limit that is CPU_EARLY_BOOT_STACK_SIZE less then the previous
+ * ? ? ? CPU.
+ */
+
+/* Common AVP early boot stack limit */
+#define AVP_EARLY_BOOT_STACK_LIMIT ? ? \
+ ? ? ? (AP20_BASE_PA_SRAM + (AP20_BASE_PA_SRAM_SIZE/2))
+/* Common AVP early boot stack size */
+#define AVP_EARLY_BOOT_STACK_SIZE ? ? ?0x1000
+/* Common CPU early boot stack limit */
+#define CPU_EARLY_BOOT_STACK_LIMIT ? ? \
+ ? ? ? (AVP_EARLY_BOOT_STACK_LIMIT - AVP_EARLY_BOOT_STACK_SIZE)
+/* Common CPU early boot stack size */
+#define CPU_EARLY_BOOT_STACK_SIZE ? ? ?0x1000
+
+#define EXCEP_VECTOR_CPU_RESET_VECTOR ?(NV_PA_EVP_BASE + 0x100)
+#define CSITE_CPU_DBG0_LAR ? ? ? ? ? ? (NV_PA_CSITE_BASE + 0x10FB0)
+#define CSITE_CPU_DBG1_LAR ? ? ? ? ? ? (NV_PA_CSITE_BASE + 0x12FB0)
+
+#define FLOW_CTLR_HALT_COP_EVENTS ? ? ?(NV_PA_FLOW_BASE + 4)
+#define FLOW_MODE_STOP ? ? ? ? ? ? ? ? 2
+#define HALT_COP_EVENT_JTAG ? ? ? ? ? ?(1 << 28)
+#define HALT_COP_EVENT_IRQ_1 ? ? ? ? ? (1 << 11)
+#define HALT_COP_EVENT_FIQ_1 ? ? ? ? ? (1 << 9)
+
+/* Prototypes */
+
+void tegra2_start(void);
+void uart_init(void);
+void udelay(unsigned long);
arch/arm/include/asm/arch-tegra2/clk_rst.h +0 -0
index 6d573bf..d67a5d7 100644
@@ -149,6 +149,9 @@ struct clk_rst_ctlr {

? ? ? ?uint crc_clk_src_csite; ? ? ? ? /*_CSITE_0, ? ? ? ? ? ? 0x1D4 */ ? ? ? ?uint crc_reserved19[9]; ? ? ? ? /* ? ? ? ? ? ? ? ? ? ? ?0x1D8-1F8 */ ? ? ? ?uint crc_clk_src_osc; ? ? ? ? ? /*_OSC_0, ? ? ? ? ? ? ? 0x1FC */
+ ? ? ? uint crc_reserved20[80]; ? ? ? ?/* ? ? ? ? ? ? ? ? ? ? ?0x200-33C */
+ ? ? ? uint crc_cpu_cmplx_set; ? ? ? ? /* _CPU_CMPLX_SET_0, ? ?0x340 */
+ ? ? ? uint crc_cpu_cmplx_clr; ? ? ? ? /* _CPU_CMPLX_CLR_0, ? ?0x344 */ ?};

?#define PLL_BYPASS ? ? ? ? ? ? (1 << 31)

arch/arm/include/asm/arch-tegra2/clk_rst.h +24 -0
@@ -162,4 +165,28 @@ struct clk_rst_ctlr {
 ?#define SWR_UARTA_RST ? ? ? ? ?(1 << 6)
 ?#define CLK_ENB_UARTA ? ? ? ? ?(1 << 6)
 
+#define SWR_CPU_RST ? ? ? ? ? ?(1 << 0)
+#define CLK_ENB_CPU ? ? ? ? ? ?(1 << 0)
+#define SWR_CSITE_RST ? ? ? ? ?(1 << 9)
+#define CLK_ENB_CSITE ? ? ? ? ?(1 << 9)
+
+#define SET_CPURESET0 ? ? ? ? ?(1 << 0)
+#define SET_DERESET0 ? ? ? ? ? (1 << 4)
+#define SET_DBGRESET0 ? ? ? ? ?(1 << 12)
+
+#define SET_CPURESET1 ? ? ? ? ?(1 << 1)
+#define SET_DERESET1 ? ? ? ? ? (1 << 5)
+#define SET_DBGRESET1 ? ? ? ? ?(1 << 13)
+
+#define CLR_CPURESET0 ? ? ? ? ?(1 << 0)
+#define CLR_DERESET0 ? ? ? ? ? (1 << 4)
+#define CLR_DBGRESET0 ? ? ? ? ?(1 << 12)
+
+#define CLR_CPURESET1 ? ? ? ? ?(1 << 1)
+#define CLR_DERESET1 ? ? ? ? ? (1 << 5)
+#define CLR_DBGRESET1 ? ? ? ? ?(1 << 13)
+
+#define CPU0_CLK_STP ? ? ? ? ? (1 << 8)
+#define CPU1_CLK_STP ? ? ? ? ? (1 << 9)
+

?#endif /* CLK_RST_H */

arch/arm/include/asm/arch-tegra2/pmc.h +0 -0
index 7ec9eeb..b1d47cd 100644
@@ -121,4 +121,12 @@ struct pmc_ctlr {

? ? ? ?uint pmc_gate; ? ? ? ? ? ? ? ? ?/* _GATE_0, offset 15C */ ?};

arch/arm/include/asm/arch-tegra2/pmc.h +8 -0
+#define CPU_PWRED ? ? ?1
+#define CPU_CLMP ? ? ? 1
+
+#define PARTID_CP ? ? ?0xFFFFFFF8
+#define START_CP ? ? ? (1 << 8)
+
+#define CPUPWRREQ_OE ? (1 << 16)
+

?#endif /* PMC_H */

arch/arm/include/asm/arch-tegra2/scu.h new file +43 -0
new file mode 100644
index 0000000..d2faa6f
@@ -0,0 +1,43 @@
+/*
+ * ?(C) Copyright 2010,2011
+ * ?NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _SCU_H_
+#define _SCU_H_
+
+/* ARM Snoop Control Unit (SCU) registers */
+struct scu_ctlr {
+ ? ? ? uint scu_ctrl; ? ? ? ? ?/* SCU Control Register, offset 00 */
+ ? ? ? uint scu_cfg; ? ? ? ? ? /* SCU Config Register, offset 04 */
+ ? ? ? uint scu_cpu_pwr_stat; ?/* SCU CPU Power Status Register, offset 08 */
+ ? ? ? uint scu_inv_all; ? ? ? /* SCU Invalidate All Register, offset 0C */
+ ? ? ? uint scu_reserved0[12]; /* reserved, offset 10-3C */
+ ? ? ? uint scu_filt_start; ? ?/* SCU Filtering Start Address Reg, offset 40 */
+ ? ? ? uint scu_filt_end; ? ? ?/* SCU Filtering End Address Reg, offset 44 */
+ ? ? ? uint scu_reserved1[2]; ?/* reserved, offset 48-4C */
+ ? ? ? uint scu_acc_ctl; ? ? ? /* SCU Access Control Register, offset 50 */
+ ? ? ? uint scu_ns_acc_ctl; ? ?/* SCU Non-secure Access Cntrl Reg, offset 54 */
+};
+
+#define SCU_ENABLE ? ? 1
+
+#endif /* SCU_H */
arch/arm/include/asm/arch-tegra2/tegra2.h +0 -0
index 9001b68..5813cd9 100644
@@ -25,8 +25,12 @@

?#define _TEGRA2_H_

?#define NV_PA_SDRAM_BASE ? ? ? 0x00000000

arch/arm/include/asm/arch-tegra2/tegra2.h +2 -0
+#define NV_PA_ARM_PERIPHBASE ? 0x50040000
+#define NV_PA_PG_UP_BASE ? ? ? 0x60000000

?#define NV_PA_TMRUS_BASE ? ? ? 0x60005010
?#define NV_PA_CLK_RST_BASE ? ? 0x60006000

arch/arm/include/asm/arch-tegra2/tegra2.h +2 -0
+#define NV_PA_FLOW_BASE ? ? ? ? ? ? ? ?0x60007000
+#define NV_PA_EVP_BASE ? ? ? ? 0x6000F000

?#define NV_PA_APB_MISC_BASE ? ?0x70000000
?#define NV_PA_APB_UARTA_BASE ? (NV_PA_APB_MISC_BASE + 0x6000) ?#define NV_PA_APB_UARTB_BASE ? (NV_PA_APB_MISC_BASE + 0x6040)

arch/arm/include/asm/arch-tegra2/tegra2.h +0 -0
@@ -34,6 +38,7 @@
 ?#define NV_PA_APB_UARTD_BASE ? (NV_PA_APB_MISC_BASE + 0x6300)
 ?#define NV_PA_APB_UARTE_BASE ? (NV_PA_APB_MISC_BASE + 0x6400)

?#define NV_PA_PMC_BASE ? ? ? ? 0x7000E400
+#define NV_PA_CSITE_BASE ? ? ? 0x70040000

?#define TEGRA2_SDRC_CS0 ? ? ? ? ? ? ? ?NV_PA_SDRAM_BASE ?#define LOW_LEVEL_SRAM_STACK ? 0x4000FFFC

board/nvidia/common/board.c +0 -0
index b2c412c..078547b 100644
@@ -30,6 +30,7 @@

?#include <asm/arch/clk_rst.h>
?#include <asm/arch/pinmux.h>
?#include <asm/arch/uart.h>
+#include "board.h"

?DECLARE_GLOBAL_DATA_PTR;

board/nvidia/common/board.c +0 -0
@@ -37,6 +38,15 @@ const struct tegra2_sysinfo sysinfo = {

? ? ? ?CONFIG_TEGRA2_BOARD_STRING
?};

board/nvidia/common/board.c +9 -0
+#ifdef CONFIG_BOARD_EARLY_INIT_F
+int board_early_init_f(void)
+{
+ ? ? ? debug("Board Early Init\n");
+ ? ? ? tegra2_start();
+ ? ? ? return 0;
+}
+#endif /* EARLY_INIT */
+

?/*
?* Routine: timer_init
?* Description: init the timestamp and lastinc value

board/nvidia/common/board.h new file +29 -0
new file mode 100644
index 0000000..47c7885
@@ -0,0 +1,29 @@
+/*
+ * ?(C) Copyright 2010,2011
+ * ?NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _BOARD_H_
+#define _BOARD_H_
+
+void tegra2_start(void);
+
+#endif /* BOARD_H */
include/configs/harmony.h +0 -0
index d004f31..34bd899 100644
@@ -46,4 +46,5 @@

?#define CONFIG_MACH_TYPE ? ? ? ? ? ? ? MACH_TYPE_HARMONY ?#define CONFIG_SYS_BOARD_ODMDATA ? ? ? 0x300d8011 /* lp1, 1GB */

+#define CONFIG_BOARD_EARLY_INIT_F
?#endif /* __CONFIG_H */

include/configs/seaboard.h +0 -0
index fd87560..b7b72bb 100644
@@ -40,4 +40,5 @@

?#define CONFIG_MACH_TYPE ? ? ? ? ? ? ? MACH_TYPE_TEGRA_SEABOARD ?#define CONFIG_SYS_BOARD_ODMDATA ? ? ? 0x300d8011 /* lp1, 1GB */

+#define CONFIG_BOARD_EARLY_INIT_F
?#endif /* __CONFIG_H */

include/configs/tegra2-common.h +0 -0
index 4f4374a..2924325 100644
@@ -33,6 +33,8 @@

?#define CONFIG_MACH_TEGRA_GENERIC ? ? ?/* which is a Tegra generic machine */ ?#define CONFIG_L2_OFF ? ? ? ? ? ? ? ? ?/* No L2 cache */

include/configs/tegra2-common.h +2 -0
+#define CONFIG_ENABLE_CORTEXA9 ? ? ? ? /* enable CPU (A9 complex) */
+

?#include <asm/arch/tegra2.h> ? ? ? ? ? /* get chip and board defs */

?/*
--
1.7.4.1

#3 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Hi Tom,

Le 23/02/2011 00:41, Tom Warren a ?crit :

Quoted 2 lines

Anyone willing to review this? I'd like to get it pulled in to Albert's arm repo ASAP.

I should be able to review it during the week-end--not before, sorry.

Note however that since this is not a bugfix and it came after the merge window closed, it would go to u-boot-arm/next, not /master; it will go to u-boot-arm/master after the the upcoming release (and then to u-boot/master when the next merge window closes).

Quoted 3 lines

Thanks,

Tom

Amicalement,

Signature · 1 line
Albert.
author
#4 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Albert,

Quoted 9 lines · Albert ARIBAUD

Hi Tom,

Le 23/02/2011 00:41, Tom Warren a ?crit :

Quoted 3 lines

Anyone willing to review this? I'd like to get it pulled in to Albert's arm repo ASAP.

I should be able to review it during the week-end--not before, sorry.

Thank you. That would be fine - no rush.

Quoted 4 lines

Note however that since this is not a bugfix and it came after the merge window closed, it would go to u-boot-arm/next, not /master; it will go to u-boot-arm/master after the the upcoming release (and then to u-boot/master when the next merge window closes).

Understood. Just wanted an ACK, etc. so I can sign off on the CPU work and move on to the drivers.

Quoted 9 lines
Quoted 4 lines

Thanks,

Tom

Amicalement,
--
Albert.

Thanks for your help,

Tom

author
#5 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

In reply to Albert ARIBAUD

Albert,

Quoted 9 lines · Albert ARIBAUD

Hi Tom,

Le 23/02/2011 00:41, Tom Warren a ?crit :

Quoted 3 lines

Anyone willing to review this? I'd like to get it pulled in to Albert's arm repo ASAP.

I should be able to review it during the week-end--not before, sorry.

Any chance you can give this some bandwidth? I'd like to get it into the arm tree.

As far as I know, it should still apply, but let me know if I need to rebase it against next (or master).

Thanks,
Tom

Quoted 13 lines

Note however that since this is not a bugfix and it came after the merge window closed, it would go to u-boot-arm/next, not /master; it will go to u-boot-arm/master after the the upcoming release (and then to u-boot/master when the next merge window closes).

Quoted 3 lines

Thanks,

Tom

Amicalement,
--
Albert.

#6 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

In reply to Tom Warren

Le 16/02/2011 21:26, Tom Warren a ?crit :

Quoted 6 lines
---
  arch/arm/cpu/armv7/start.S                 |    6 +
  arch/arm/cpu/armv7/tegra2/Makefile         |    2 +-
  arch/arm/cpu/armv7/tegra2/ap20.c           |  490 ++++++++++++++++++++++++++++

This one has an extra empty line at end of file.

Quoted 21 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +21 -0
+void cold_boot(void)
+{
+	asm volatile(
+
+	"msr     cpsr_c, #0xd3            \n"
+	/*
+	* Check current processor: CPU or AVP?
+	* If AVP, go to AVP boot code, else continue on.
+	*/
+	"mov     r0, %0                   \n"
+	"ldrb    r2, [r0, %1]             \n"
+	/* are we the CPU? */
+	"cmp     r2, %2                   \n"
+	"mov     sp, %3                   \n"
+	/* leave in some symbols for release debugging */
+	"mov     r3, %6                   \n"
+	"str     r3, [sp, #-4]!           \n"
+	"str     r3, [sp, #-4]!           \n"
+	/*  yep, we are the CPU */
+	"bxeq     %4                      \n"
+	/* AVP Initialization follows this path */

arch/arm/cpu/armv7/tegra2/ap20.c line 351

Quoted 10 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +10 -0
+	"mov     sp, %5                   \n"
+	/* leave in some symbols for release debugging */
+	"mov     r3, %6                   \n"
+	"str     r3, [sp, #-4]!           \n"
+	"str     r3, [sp, #-4]!           \n"
+
+	/* Init and Start CPU */
+	"b       startup_cpu              \n"
+	:
+	: "i"(NV_PA_PG_UP_BASE),

If I'm not mistaken, NV_PA_PG_UP_BASE could be used just as well directly in the asm statement instead of via %0 and i(), as anyway the asm will be preprocessed and the macro will turn to a number. That would simplify the asm instruction as a whole and make the asm statement more understandable (also applies to other macros used similarly).

Apart from that, I must admit I don't know the Tegra2/A9 well enough to comment further.

amicalement,
Amicalement,

Signature · 1 line
Albert.
author
#7 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Albert,

Quoted 7 lines · Albert ARIBAUD

Le 16/02/2011 21:26, Tom Warren a ?crit :

Quoted 5 lines

---
?arch/arm/cpu/armv7/start.S ? ? ? ? ? ? ? ? | ? ?6 + ?arch/arm/cpu/armv7/tegra2/Makefile ? ? ? ? | ? ?2 +-

Quoted 5 lines
Quoted 2 lines

?arch/arm/cpu/armv7/tegra2/ap20.c ? ? ? ? ? | ?490
++++++++++++++++++++++++++++

This one has an extra empty line at end of file.

Thanks - I'll remove it.

Quoted 29 lines
Quoted 29 lines
(quoted diff) +29 -0
+void cold_boot(void)
+{
+ ? ? ? asm volatile(
+
+ ? ? ? "msr ? ? cpsr_c, #0xd3 ? ? ? ? ? ?\n"
+ ? ? ? /*
+ ? ? ? * Check current processor: CPU or AVP?
+ ? ? ? * If AVP, go to AVP boot code, else continue on.
+ ? ? ? */
+ ? ? ? "mov ? ? r0, %0 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "ldrb ? ?r2, [r0, %1] ? ? ? ? ? ? \n"
+ ? ? ? /* are we the CPU? */
+ ? ? ? "cmp ? ? r2, %2 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "mov ? ? sp, %3 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? /* leave in some symbols for release debugging */
+ ? ? ? "mov ? ? r3, %6 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? ? /* ?yep, we are the CPU */
+ ? ? ? "bxeq ? ? %4 ? ? ? ? ? ? ? ? ? ? ?\n"
+ ? ? ? /* AVP Initialization follows this path */
+ ? ? ? "mov ? ? sp, %5 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? /* leave in some symbols for release debugging */
+ ? ? ? "mov ? ? r3, %6 ? ? ? ? ? ? ? ? ? \n"
+ ? ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+
+ ? ? ? /* Init and Start CPU */
+ ? ? ? "b ? ? ? startup_cpu ? ? ? ? ? ? ?\n"
Quoted 9 lines
Quoted 2 lines

+ ? ? ? :
+ ? ? ? : "i"(NV_PA_PG_UP_BASE),

If I'm not mistaken, NV_PA_PG_UP_BASE could be used just as well directly in the asm statement instead of via %0 and i(), as anyway the asm will be preprocessed and the macro will turn to a number. That would simplify the asm instruction as a whole and make the asm statement more understandable (also applies to other macros used similarly).

Yeah, this code came this way from our bringup group for out in-house bootloader, and it's always been confusing.
I'll try to simplify it when I incorporate Peter's critiques. Thanks.

Quoted 7 lines

Apart from that, I must admit I don't know the Tegra2/A9 well enough to comment further.

amicalement,
Amicalement,
--
Albert.

Thanks for the input,
Tom

Quoted 1 line
#8 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

In reply to Tom Warren

Hi Tom,
I'm not too familiar with the architecture, so many comments are aesthetic. It would be a good idea to run the patch through checkpatch.pl too.

Quoted 5 lines
arch/arm/cpu/armv7/start.S +0 -0
index 684f2d2..50a1725 100644

arch/arm/cpu/armv7/start.S _end_vect: · line 78

Quoted 9 lines
arch/arm/cpu/armv7/start.S +6 -0
@@ -70,6 +70,12 @@ _end_vect:
 _TEXT_BASE:
 	.word	CONFIG_SYS_TEXT_BASE
 
+#ifdef CONFIG_TEGRA2
+.globl _armboot_start
+_armboot_start:
+        .word _start
+#endif
+

It'd be good to add a comment about what's going on above, and why its tegra2-specific. Eg why is it needed?

<snip>

arch/arm/cpu/armv7/start.S _end_vect:

Quoted 4 lines
arch/arm/cpu/armv7/start.S +4 -0
+static void init_pll_x(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32	reg;

The spaces in front of "reg" can be removed. Ditto for all functions/variables.

arch/arm/cpu/armv7/start.S

Quoted 7 lines
arch/arm/cpu/armv7/start.S +7 -0
+	/* Is PLL-X already running? */
+	reg = readl(&clkrst->crc_pllx_base);
+	if (reg & PLL_ENABLE)
+		return;
+
+	/* Do PLLX init if it isn't running, but BootROM sets it, so TBD */
+}

The above function looks incorrect.

arch/arm/cpu/armv7/start.S

Quoted 4 lines
arch/arm/cpu/armv7/start.S +4 -0
+static void set_cpu_reset_vector(u32 vector)
+{
+	writel(vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+}

Is it worth breaking this out into its own function? The define names make it pretty clear what is being done, and its only called from 1 location.

Quoted 14 lines
arch/arm/cpu/armv7/start.S +14 -0
+static void enable_cpu_clock(int enable)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32   reg, clk;
+
+	/*
+	 * NOTE:
+	 * Regardless of whether the request is to enable or disable the CPU
+	 * clock, every processor in the CPU complex except the master (CPU 0)
+	 * will have it's clock stopped because the AVP only talks to the
+	 * master. The AVP does not know (nor does it need to know) that there
+	 * are multiple processors in the CPU complex.
+	 */
+

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	/* Need to initialize PLLX? */
+	if (enable) {
+		/* Initialize PLL */
+		init_pll_x();
+
+		/* Wait until stable */
+		udelay(NVBOOT_CLOCKS_PLL_STABILIZATION_DELAY);
+
+		reg = CCLK_BURST_POLICY;
+		writel(reg, &clkrst->crc_cclk_brst_pol);

It'd look cleaner to not set "reg" for each access, just use the define directly. I'd personally use less temporary variables in general and only use them when it made the code cleaner and easier to understand.

arch/arm/cpu/armv7/start.S

Quoted 6 lines
arch/arm/cpu/armv7/start.S +6 -0
+		reg = SUPER_CCLK_DIVIDER;
+		writel(reg, &clkrst->crc_super_cclk_div);
+	}
+
+	/* Fetch the register containing the main CPU complex clock enable */
+	reg = readl(&clkrst->crc_clk_out_enb_l);

Is this read necessary? You overwrite reg unconditionally below.

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	/*
+	 * Read the register containing the individual CPU clock enables and
+	 * always stop the clock to CPU 1.
+	 */
+	clk = readl(&clkrst->crc_clk_cpu_cmplx);
+	clk |= CPU1_CLK_STP;
+
+	if (enable) {
+		/* Enable the CPU clock */
+		reg = readl(&clkrst->crc_clk_out_enb_l);

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+		reg |= CLK_ENB_CPU;
+		clk = readl(&clkrst->crc_clk_cpu_cmplx);
+		clk &= ~CPU0_CLK_STP;
+	} else {
+		/* Disable the CPU clock */
+		reg = readl(&clkrst->crc_clk_out_enb_l);
+		reg |= CLK_ENB_CPU;
+		clk = readl(&clkrst->crc_clk_cpu_cmplx);
+		clk |= CPU0_CLK_STP;
+	}

For if/elses that share common code, the common code should be broken out. eg above only the one-line |=/&= operations should be conditional.

arch/arm/cpu/armv7/start.S

Quoted 13 lines
arch/arm/cpu/armv7/start.S +13 -0
+	writel(clk, &clkrst->crc_clk_cpu_cmplx);
+	writel(reg, &clkrst->crc_clk_out_enb_l);
+}
+
+static int is_cpu_powered(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32   reg;
+
+	reg = readl(&pmc->pmc_pwrgate_status);
+
+	if (reg & CPU_PWRED)
+		return TRUE;

I'd remove the reg variable. eg something like:
return readl(&pmc->pmc_pwrgate_status & CPU_PWRED ? 1 : 0);

Quoted 5 lines
arch/arm/cpu/armv7/start.S +5 -0
+	return FALSE;
+}
+
+static void remove_cpu_io_clamps(void)
+{

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32   reg;
+
+	/* Remove the clamps on the CPU I/O signals */
+	reg = readl(&pmc->pmc_remove_clamping);
+	reg |= CPU_CLMP;
+	writel(reg, &pmc->pmc_remove_clamping);
+
+	/* Give I/O signals time to stabilize */
+	udelay(1000);

For magic delays it'd be good to reference why you're waiting a specific amount of time. Does a manual state 1 ms? Did testing show 1ms was required?

arch/arm/cpu/armv7/start.S

Quoted 12 lines
arch/arm/cpu/armv7/start.S +12 -0
+}
+
+static void powerup_cpu(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32   reg;
+
+	if (!is_cpu_powered()) {
+		/* Toggle the CPU power state (OFF -> ON) */
+		reg = readl(&pmc->pmc_pwrgate_toggle);
+		reg &= (PARTID_CP);
+		reg |= START_CP;

Why ()'s on one operation, but not the other?

Quoted 17 lines
arch/arm/cpu/armv7/start.S +17 -0
+		writel(reg, &pmc->pmc_pwrgate_toggle);
+
+		/* Wait for the power to come up */
+		while (!is_cpu_powered())
+			;			/* Do nothing */
+
+		/*
+		 * Remove the I/O clamps from CPU power partition.
+		 * Recommended only on a Warm boot, if the CPU partition gets
+		 * power gated. Shouldn't cause any harm when called after a
+		 * cold boot according to HW, probably just redundant.
+		 */
+		remove_cpu_io_clamps();
+	}
+}
+
+static void enable_cpu_power_rail(void)

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32   reg;
+
+	reg = readl(&pmc->pmc_cntrl);
+	reg |= CPUPWRREQ_OE;
+	writel(reg, &pmc->pmc_cntrl);
+
+	/* Delay to allow for stable power (CPU_PWR_REQ -> VDD_CPU from PMU) */
+	udelay(3750);

Ditto for description.

Quoted 8 lines
arch/arm/cpu/armv7/start.S +8 -0
+}
+
+static void reset_A9_cpu(int reset)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32   reg, cpu;
+
+	/*

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	* NOTE:  Regardless of whether the request is to hold the CPU in reset
+	*        or take it out of reset, every processor in the CPU complex
+	*        except the master (CPU 0) will be held in reset because the
+	*        AVP only talks to the master. The AVP does not know that there
+	*        are multiple processors in the CPU complex.
+	*/
+
+	/* Hold CPU 1 in reset */
+	cpu = SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1;
+	writel(cpu, &clkrst->crc_cpu_cmplx_set);

The cpu variable can be removed.

arch/arm/cpu/armv7/start.S

Quoted 9 lines
arch/arm/cpu/armv7/start.S +9 -0
+	reg = readl(&clkrst->crc_rst_dev_l);
+	if (reset) {
+		/* Place CPU0 into reset */
+		cpu = SET_DBGRESET0 | SET_DERESET0 | SET_CPURESET0;
+		writel(cpu, &clkrst->crc_cpu_cmplx_set);
+
+		/* Enable master CPU reset */
+		reg |= SWR_CPU_RST;
+

Extra newline.

Quoted 33 lines
arch/arm/cpu/armv7/start.S +33 -0
+	} else {
+		/* Take CPU0 out of reset */
+		cpu = CLR_DBGRESET0 | CLR_DERESET0 | CLR_CPURESET0;
+		writel(cpu, &clkrst->crc_cpu_cmplx_clr);
+
+		/* Disable master CPU reset */
+		reg &= ~SWR_CPU_RST;
+	}
+
+	writel(reg, &clkrst->crc_rst_dev_l);
+}
+
+static void clock_enable_coresight(int enable)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32   rst, clk, src;
+
+	rst = readl(&clkrst->crc_rst_dev_u);
+	clk = readl(&clkrst->crc_clk_out_enb_u);
+
+	if (enable) {
+		rst &= ~SWR_CSITE_RST;
+		clk |= CLK_ENB_CSITE;
+	} else {
+		rst |= SWR_CSITE_RST;
+		clk &= ~CLK_ENB_CSITE;
+	}
+
+	writel(clk, &clkrst->crc_clk_out_enb_u);
+	writel(rst, &clkrst->crc_rst_dev_u);
+
+	if (enable) {
+		/*

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+		 * Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by
+		 *  1.5, giving an effective frequency of 144MHz.
+		 * Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor
+		 *  (bits 7:0), so 00000001b == 1.5 (n+1 + .5)
+		 */
+		src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
+		writel(src, &clkrst->crc_clk_src_csite);
+
+		/* Unlock the CPU CoreSight interfaces */
+		rst = 0xC5ACCE55;

What's this number? Is there a define that could be used instead?

Quoted 13 lines
arch/arm/cpu/armv7/start.S +13 -0
+		writel(rst, CSITE_CPU_DBG0_LAR);
+		writel(rst, CSITE_CPU_DBG1_LAR);
+	}
+}
+
+void start_cpu(u32 reset_vector)
+{
+	/* Enable VDD_CPU */
+	enable_cpu_power_rail();
+
+	/* Hold the CPUs in reset */
+	reset_A9_cpu(TRUE);
+

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	/* Disable the CPU clock */
+	enable_cpu_clock(FALSE);
+
+	/* Enable CoreSight */
+	clock_enable_coresight(TRUE);
+
+	/*
+	* Set the entry point for CPU execution from reset,
+	*  if it's a non-zero value.
+	*/

Spaces should be added above.

Quoted 17 lines
arch/arm/cpu/armv7/start.S +17 -0
+	if (reset_vector)
+		set_cpu_reset_vector(reset_vector);
+
+	/* Enable the CPU clock */
+	enable_cpu_clock(TRUE);
+
+	/* If the CPU doesn't already have power, power it up */
+	if (!is_cpu_powered())
+		powerup_cpu();
+
+	/* Take the CPU out of reset */
+	reset_A9_cpu(FALSE);
+}
+
+
+void halt_avp(void)
+{

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	u32   reg;
+
+	for (;;) {
+		reg = HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \
+			| HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29);
+		writel(reg, FLOW_CTLR_HALT_COP_EVENTS);
+	}
+	/* Should never get here */
+	for (;;)
+		;

I'd remove the use of reg, and a secondary infinite loop seems necessary.

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+}
+
+void startup_cpu(void)
+{
+	/* Initialize the AVP, clocks, and memory controller */
+	/* SDRAM is guaranteed to be on at this point */
+
+	asm volatile(
+
+	/* Start the CPU */

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	/* R0 = reset vector for CPU */
+	"ldr     r0, =cold_boot      \n"
+	"bl      start_cpu           \n"
+
+	/* Transfer control to the AVP code */
+	"bl      halt_avp            \n"
+
+	/* Should never get here */
+	"b       .                   \n"
+	);

The assembly code should be indented. Actually, is there a reason not to move all these assembly functions into a seperate assembly file?

Quoted 37 lines
arch/arm/cpu/armv7/start.S +37 -0
+}
+
+extern ulong _armboot_start;
+u32 cpu_boot_stack = CPU_EARLY_BOOT_STACK_LIMIT;
+u32 avp_boot_stack = AVP_EARLY_BOOT_STACK_LIMIT;
+u32 proc_tag = PG_UP_TAG_0_PID_CPU & 0xFF;
+u32 deadbeef = 0xdeadbeef;
+
+void cold_boot(void)
+{
+	asm volatile(
+
+	"msr     cpsr_c, #0xd3            \n"
+	/*
+	* Check current processor: CPU or AVP?
+	* If AVP, go to AVP boot code, else continue on.
+	*/
+	"mov     r0, %0                   \n"
+	"ldrb    r2, [r0, %1]             \n"
+	/* are we the CPU? */
+	"cmp     r2, %2                   \n"
+	"mov     sp, %3                   \n"
+	/* leave in some symbols for release debugging */
+	"mov     r3, %6                   \n"
+	"str     r3, [sp, #-4]!           \n"
+	"str     r3, [sp, #-4]!           \n"
+	/*  yep, we are the CPU */
+	"bxeq     %4                      \n"
+	/* AVP Initialization follows this path */
+	"mov     sp, %5                   \n"
+	/* leave in some symbols for release debugging */
+	"mov     r3, %6                   \n"
+	"str     r3, [sp, #-4]!           \n"
+	"str     r3, [sp, #-4]!           \n"
+
+	/* Init and Start CPU */
+	"b       startup_cpu              \n"

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	:
+	: "i"(NV_PA_PG_UP_BASE),
+	"i"(PG_UP_TAG_0),
+	"r"(proc_tag),
+	"r"(cpu_boot_stack),
+	"r"(_armboot_start),
+	"r"(avp_boot_stack),
+	"r"(deadbeef)
+	: "r0", "r2", "r3", "cc", "lr"
+	);

Ditto on indentation/move.

arch/arm/cpu/armv7/start.S

Quoted 12 lines
arch/arm/cpu/armv7/start.S +12 -0
+}
+
+void enable_scu(void)
+{
+	struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE;
+	u32 reg;
+
+	reg = readl(&scu->scu_ctrl);
+	if (reg & SCU_ENABLE) {
+		/* SCU already enabled, return */
+		return;
+	}

I'd not use reg above, and not use brackets, eg:
/* If the SCU is already enabled, we have nothing to do */ if (readl(&scu_ctrl) & SCU_ENABLE)

	return;

arch/arm/cpu/armv7/start.S

Quoted 9 lines
arch/arm/cpu/armv7/start.S +9 -0
+	/* Invalidate all ways for all processors */
+	writel(0xFFFF, &scu->scu_inv_all);
+
+	/* Enable SCU - bit 0 */
+	reg = readl(&scu->scu_ctrl);
+	reg |= SCU_ENABLE;
+	writel(reg, &scu->scu_ctrl);
+
+	return;

Remove return.

Quoted 48 lines
arch/arm/cpu/armv7/start.S +48 -0
+}
+
+void cache_configure(void)
+{
+	asm volatile(
+
+	"stmdb r13!,{r14}                 \n"
+	/* invalidate instruction cache */
+	"mov r1, #0                       \n"
+	"mcr p15, 0, r1, c7, c5, 0        \n"
+
+	/* invalidate the i&d tlb entries */
+	"mcr p15, 0, r1, c8, c5, 0        \n"
+	"mcr p15, 0, r1, c8, c6, 0        \n"
+
+	/* enable instruction cache */
+	"mrc  p15, 0, r1, c1, c0, 0       \n"
+	"orr  r1, r1, #(1<<12)            \n"
+	"mcr  p15, 0, r1, c1, c0, 0       \n"
+
+	"bl enable_scu                    \n"
+
+	/* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */
+	"mrc p15, 0, r0, c1, c0, 1        \n"
+	"orr r0, r0, #0x41                \n"
+	"mcr p15, 0, r0, c1, c0, 1        \n"
+
+	/* Now flush the Dcache */
+	"mov r0, #0                       \n"
+	/* 256 cache lines */
+	"mov r1, #256                     \n"
+
+	"invalidate_loop:                 \n"
+
+	"add r1, r1, #-1                  \n"
+	"mov r0, r1, lsl #5               \n"
+	/* invalidate d-cache using line (way0) */
+	"mcr p15, 0, r0, c7, c6, 2        \n"
+
+	"orr r2, r0, #(1<<30)             \n"
+	/* invalidate d-cache using line (way1) */
+	"mcr p15, 0, r2, c7, c6, 2        \n"
+
+	"orr r2, r0, #(2<<30)             \n"
+	/* invalidate d-cache using line (way2) */
+	"mcr p15, 0, r2, c7, c6, 2        \n"
+
+	"orr r2, r0, #(3<<30)             \n"

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	/* invalidate d-cache using line (way3) */
+	"mcr p15, 0, r2, c7, c6, 2        \n"
+	"cmp r1, #0                       \n"
+	"bne invalidate_loop              \n"
+
+	/* FIXME: should have ap20's L2 disabled too */
+	"invalidate_done:                 \n"
+	"ldmia r13!,{pc}                  \n"
+	".ltorg                           \n"
+	);

Ditto on indentation/move.

arch/arm/cpu/armv7/start.S

Quoted 8 lines
arch/arm/cpu/armv7/start.S +8 -0
+}
+
+void init_pmc_scratch(void)
+{
+	struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	/* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */
+	memset(&pmc->pmc_scratch1, 0, 23*4);

Is it safe to memset on IO regions here? A for loop of writel's would be safer, and more consistent.

arch/arm/cpu/armv7/start.S

Quoted 4 lines
arch/arm/cpu/armv7/start.S +4 -0
+	writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20);
+}
+
+u32 s_first_boot = 1;

I'd move all global variables to the top of the file.

Quoted 8 lines
arch/arm/cpu/armv7/start.S +8 -0
+
+void cpu_start(void)
+{
+	struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+
+	/* enable JTAG */
+	writel(0xC0, &pmt->pmt_cfg_ctl);
+

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+	if (s_first_boot) {
+		/*
+		 * Need to set this before cold-booting,
+		 *  otherwise we'll end up in an infinite loop.
+		 */
+		s_first_boot = 0;
+		cold_boot();
+	}
+
+	return;

Remove return.

Quoted 47 lines
arch/arm/cpu/armv7/start.S +21 -0
+}
+
+void tegra2_start()
+{
+	if (s_first_boot) {
+		/* Init Debug UART Port (115200 8n1) */
+		uart_init();
+
+		/* Init PMC scratch memory */
+		init_pmc_scratch();
+	}
+
+#ifdef CONFIG_ENABLE_CORTEXA9
+	/* take the mpcore out of reset */
+	cpu_start();
+
+	/* configure cache */
+	cache_configure();
+#endif
+}
+
arch/arm/cpu/armv7/tegra2/ap20.h new file +20 -0
new file mode 100644
index 0000000..de7622d
@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright 2010-2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,

arch/arm/cpu/armv7/tegra2/ap20.h line 30

Quoted 10 lines
arch/arm/cpu/armv7/tegra2/ap20.h new file +10 -0
+ * MA 02111-1307 USA
+ */
+#include <asm/types.h>
+
+#ifndef	FALSE
+#define FALSE	0
+#endif
+#ifndef TRUE
+#define TRUE	1
+#endif

These shouldn't be added here. They should be somewhere common, or shouldn't be used (my preference).

Quoted 172 lines
arch/arm/cpu/armv7/tegra2/ap20.h new file +75 -0
+
+#define NVBL_PLLP_KHZ	(432000/2)
+/* The stabilization delay in usec */
+#define NVBOOT_CLOCKS_PLL_STABILIZATION_DELAY (300)
+
+#define PLLX_ENABLED		(1 << 30)
+#define CCLK_BURST_POLICY	0x20008888
+#define SUPER_CCLK_DIVIDER	0x80000000
+
+/* Calculate clock fractional divider value from ref and target frequencies */
+#define CLK_DIVIDER(REF, FREQ)  ((((REF) * 2) / FREQ) - 2)
+
+/* Calculate clock frequency value from reference and clock divider value */
+#define CLK_FREQUENCY(REF, REG)  (((REF) * 2) / (REG + 2))
+
+/* AVP/CPU ID */
+#define PG_UP_TAG_0_PID_CPU	0x55555555	/* CPU aka "a9" aka "mpcore" */
+#define PG_UP_TAG_0             0x0
+
+/* AP20-Specific Base Addresses */
+
+/* AP20 Base physical address of SDRAM. */
+#define AP20_BASE_PA_SDRAM      0x00000000
+/* AP20 Base physical address of internal SRAM. */
+#define AP20_BASE_PA_SRAM       0x40000000
+/* AP20 Size of internal SRAM (256KB). */
+#define AP20_BASE_PA_SRAM_SIZE  0x00040000
+/* AP20 Base physical address of flash. */
+#define AP20_BASE_PA_NOR_FLASH  0xD0000000
+/* AP20 Base physical address of boot information table. */
+#define AP20_BASE_PA_BOOT_INFO  AP20_BASE_PA_SRAM
+
+/*
+ * Super-temporary stacks for EXTREMELY early startup. The values chosen for
+ * these addresses must be valid on ALL SOCs because this value is used before
+ * we are able to differentiate between the SOC types.
+ *
+ * NOTE: The since CPU's stack will eventually be moved from IRAM to SDRAM, its
+ *       stack is placed below the AVP stack. Once the CPU stack has been moved,
+ *       the AVP is free to use the IRAM the CPU stack previously occupied if
+ *       it should need to do so.
+ *
+ * NOTE: In multi-processor CPU complex configurations, each processor will have
+ *       its own stack of size CPU_EARLY_BOOT_STACK_SIZE. CPU 0 will have a
+ *       limit of CPU_EARLY_BOOT_STACK_LIMIT. Each successive CPU will have a
+ *       stack limit that is CPU_EARLY_BOOT_STACK_SIZE less then the previous
+ *       CPU.
+ */
+
+/* Common AVP early boot stack limit */
+#define AVP_EARLY_BOOT_STACK_LIMIT	\
+	(AP20_BASE_PA_SRAM + (AP20_BASE_PA_SRAM_SIZE/2))
+/* Common AVP early boot stack size */
+#define AVP_EARLY_BOOT_STACK_SIZE	0x1000
+/* Common CPU early boot stack limit */
+#define CPU_EARLY_BOOT_STACK_LIMIT	\
+	(AVP_EARLY_BOOT_STACK_LIMIT - AVP_EARLY_BOOT_STACK_SIZE)
+/* Common CPU early boot stack size */
+#define CPU_EARLY_BOOT_STACK_SIZE	0x1000
+
+#define EXCEP_VECTOR_CPU_RESET_VECTOR	(NV_PA_EVP_BASE + 0x100)
+#define CSITE_CPU_DBG0_LAR		(NV_PA_CSITE_BASE + 0x10FB0)
+#define CSITE_CPU_DBG1_LAR		(NV_PA_CSITE_BASE + 0x12FB0)
+
+#define FLOW_CTLR_HALT_COP_EVENTS	(NV_PA_FLOW_BASE + 4)
+#define FLOW_MODE_STOP			2
+#define HALT_COP_EVENT_JTAG		(1 << 28)
+#define HALT_COP_EVENT_IRQ_1		(1 << 11)
+#define HALT_COP_EVENT_FIQ_1		(1 << 9)
+
+/* Prototypes */
+
+void tegra2_start(void);
+void uart_init(void);
+void udelay(unsigned long);
arch/arm/include/asm/arch-tegra2/clk_rst.h +27 -0
index 6d573bf..d67a5d7 100644
@@ -149,6 +149,9 @@ struct clk_rst_ctlr {
 	uint crc_clk_src_csite;		/*_CSITE_0,		0x1D4 */
 	uint crc_reserved19[9];		/*			0x1D8-1F8 */
 	uint crc_clk_src_osc;		/*_OSC_0,		0x1FC */
+	uint crc_reserved20[80];	/*			0x200-33C */
+	uint crc_cpu_cmplx_set;		/* _CPU_CMPLX_SET_0,	0x340 */
+	uint crc_cpu_cmplx_clr;		/* _CPU_CMPLX_CLR_0,	0x344 */
 };
 
 #define PLL_BYPASS		(1 << 31)
@@ -162,4 +165,28 @@ struct clk_rst_ctlr {
 #define SWR_UARTA_RST		(1 << 6)
 #define CLK_ENB_UARTA		(1 << 6)
 
+#define SWR_CPU_RST		(1 << 0)
+#define CLK_ENB_CPU		(1 << 0)
+#define SWR_CSITE_RST		(1 << 9)
+#define CLK_ENB_CSITE		(1 << 9)
+
+#define SET_CPURESET0		(1 << 0)
+#define SET_DERESET0		(1 << 4)
+#define SET_DBGRESET0		(1 << 12)
+
+#define SET_CPURESET1		(1 << 1)
+#define SET_DERESET1		(1 << 5)
+#define SET_DBGRESET1		(1 << 13)
+
+#define CLR_CPURESET0		(1 << 0)
+#define CLR_DERESET0		(1 << 4)
+#define CLR_DBGRESET0		(1 << 12)
+
+#define CLR_CPURESET1		(1 << 1)
+#define CLR_DERESET1		(1 << 5)
+#define CLR_DBGRESET1		(1 << 13)
+
+#define CPU0_CLK_STP		(1 << 8)
+#define CPU1_CLK_STP		(1 << 9)
+
 #endif	/* CLK_RST_H */
arch/arm/include/asm/arch-tegra2/pmc.h +8 -0
index 7ec9eeb..b1d47cd 100644
@@ -121,4 +121,12 @@ struct pmc_ctlr {
 	uint pmc_gate;			/* _GATE_0, offset 15C */
 };
 
+#define CPU_PWRED	1
+#define CPU_CLMP	1
+
+#define PARTID_CP	0xFFFFFFF8
+#define START_CP	(1 << 8)
+
+#define CPUPWRREQ_OE	(1 << 16)
+
 #endif	/* PMC_H */
arch/arm/include/asm/arch-tegra2/scu.h new file +31 -0
new file mode 100644
index 0000000..d2faa6f
@@ -0,0 +1,43 @@
+/*
+ *  (C) Copyright 2010,2011
+ *  NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _SCU_H_
+#define _SCU_H_
+
+/* ARM Snoop Control Unit (SCU) registers */
+struct scu_ctlr {
+	uint scu_ctrl;		/* SCU Control Register, offset 00 */
+	uint scu_cfg;		/* SCU Config Register, offset 04 */
+	uint scu_cpu_pwr_stat;	/* SCU CPU Power Status Register, offset 08 */

arch/arm/include/asm/arch-tegra2/scu.h line 41

Quoted 10 lines
arch/arm/include/asm/arch-tegra2/scu.h new file +10 -0
+	uint scu_inv_all;	/* SCU Invalidate All Register, offset 0C */
+	uint scu_reserved0[12];	/* reserved, offset 10-3C */
+	uint scu_filt_start;	/* SCU Filtering Start Address Reg, offset 40 */
+	uint scu_filt_end;	/* SCU Filtering End Address Reg, offset 44 */
+	uint scu_reserved1[2];	/* reserved, offset 48-4C */
+	uint scu_acc_ctl;	/* SCU Access Control Register, offset 50 */
+	uint scu_ns_acc_ctl;	/* SCU Non-secure Access Cntrl Reg, offset 54 */
+};
+
+#define SCU_ENABLE	1

Should this be here? Seems like its not the proper location to enable things...

arch/arm/include/asm/arch-tegra2/scu.h line 43

Quoted 2 lines
arch/arm/include/asm/arch-tegra2/scu.h new file +2 -0
+
+#endif	/* SCU_H */

Best,
Peter

author
#9 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Peter,

Quoted 4 lines · Peter Tyser

Hi Tom,
I'm not too familiar with the architecture, so many comments are aesthetic. ?It would be a good idea to run the patch through checkpatch.pl too.

I run checkpatch on every submission. Only 1 warning was generated (about an extern), and no errors.

Quoted 9 lines
Quoted 9 lines
arch/arm/cpu/armv7/start.S +0 -0
index 684f2d2..50a1725 100644
@@ -70,6 +70,12 @@ _end_vect:

?_TEXT_BASE:
? ? ? .word ? CONFIG_SYS_TEXT_BASE

Quoted 9 lines

arch/arm/cpu/armv7/start.S _end_vect: · line 78

Quoted 6 lines
arch/arm/cpu/armv7/start.S +6 -0
+#ifdef CONFIG_TEGRA2
+.globl _armboot_start
+_armboot_start:
+ ? ? ? ?.word _start
+#endif
+

It'd be good to add a comment about what's going on above, and why its tegra2-specific. ?Eg why is it needed?

Tegra uses 2 separate CPUs - the AVP (ARM7TDI) and the dual-core A9. A bootloader first runs on the AVP and sets things up for the CPU complex to take over.
The CPU complex jumps here during it's init phase/boot (from it's reset vector). It needs a dereferenced jump to the _start code in start.S (which in turn chains to the reset code).
I'll add a comment about this in the next patch.

Quoted 9 lines

<snip>

arch/arm/cpu/armv7/start.S

Quoted 4 lines
arch/arm/cpu/armv7/start.S +4 -0
+static void init_pll_x(void)
+{
+ ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? u32 ? ? reg;

The spaces in front of "reg" can be removed. ?Ditto for all functions/variables.

Not sure what you mean, here, Peter. There are no spaces here in my ap20.c file, just tabs.
Please clarify.

Quoted 10 lines

arch/arm/cpu/armv7/start.S

Quoted 8 lines

+ ? ? /* Is PLL-X already running? */
+ ? ? reg = readl(&clkrst->crc_pllx_base);
+ ? ? if (reg & PLL_ENABLE)
+ ? ? ? ? ? ? return;

arch/arm/cpu/armv7/start.S +3 -0
+
+ ? ? /* Do PLLX init if it isn't running, but BootROM sets it, so TBD */
+}

The above function looks incorrect.

What looks incorrect? It checks to see if the PLL is already running/enabled, and returns if it is.
Tegra2 mask ROM (BootROM) currently always sets PLLX, so this will always return, but the comment is there for future chips that may not set up PLLX.

Quoted 9 lines

arch/arm/cpu/armv7/start.S

Quoted 5 lines
arch/arm/cpu/armv7/start.S +4 -0
+static void set_cpu_reset_vector(u32 vector)
+{
+ ? ? writel(vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+}

Is it worth breaking this out into its own function? ?The define names make it pretty clear what is being done, and its only called from 1 location.

I can move the writel() to the called location and remove this func.

Quoted 21 lines
Quoted 21 lines
arch/arm/cpu/armv7/start.S +20 -0
+static void enable_cpu_clock(int enable)
+{
+ ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? u32 ? reg, clk;
+
+ ? ? /*
+ ? ? ?* NOTE:
+ ? ? ?* Regardless of whether the request is to enable or disable the CPU
+ ? ? ?* clock, every processor in the CPU complex except the master (CPU 0)
+ ? ? ?* will have it's clock stopped because the AVP only talks to the
+ ? ? ?* master. The AVP does not know (nor does it need to know) that there
+ ? ? ?* are multiple processors in the CPU complex.
+ ? ? ?*/
+
+ ? ? /* Need to initialize PLLX? */
+ ? ? if (enable) {
+ ? ? ? ? ? ? /* Initialize PLL */
+ ? ? ? ? ? ? init_pll_x();
+
+ ? ? ? ? ? ? /* Wait until stable */
Quoted 8 lines
Quoted 4 lines

+ ? ? ? ? ? ? udelay(NVBOOT_CLOCKS_PLL_STABILIZATION_DELAY); +
+ ? ? ? ? ? ? reg = CCLK_BURST_POLICY;
+ ? ? ? ? ? ? writel(reg, &clkrst->crc_cclk_brst_pol);

It'd look cleaner to not set "reg" for each access, just use the define directly. ?I'd personally use less temporary variables in general and only use them when it made the code cleaner and easier to understand.

Will do. This code was ported from our orignal, in-house bootloader, so it's going to be a bit hairy.

Quoted 9 lines
Quoted 7 lines

+ ? ? ? ? ? ? reg = SUPER_CCLK_DIVIDER;
+ ? ? ? ? ? ? writel(reg, &clkrst->crc_super_cclk_div);
+ ? ? }
+
+ ? ? /* Fetch the register containing the main CPU complex clock enable */
+ ? ? reg = readl(&clkrst->crc_clk_out_enb_l);

Is this read necessary? ?You overwrite reg unconditionally below.

Yeah, I saw that and did a rewrite a week or two ago, but was waiting to incorporate into the next patch to get everything in one place.

Quoted 22 lines
Quoted 13 lines

+ ? ? /*
+ ? ? ?* Read the register containing the individual CPU clock enables and
+ ? ? ?* always stop the clock to CPU 1.
+ ? ? ?*/
+ ? ? clk = readl(&clkrst->crc_clk_cpu_cmplx);
+ ? ? clk |= CPU1_CLK_STP;
+
+ ? ? if (enable) {
+ ? ? ? ? ? ? /* Enable the CPU clock */
+ ? ? ? ? ? ? reg = readl(&clkrst->crc_clk_out_enb_l);
+ ? ? ? ? ? ? reg |= CLK_ENB_CPU;
+ ? ? ? ? ? ? clk = readl(&clkrst->crc_clk_cpu_cmplx);

Quoted 8 lines

+ ? ? ? ? ? ? clk &= ~CPU0_CLK_STP;
+ ? ? } else {
+ ? ? ? ? ? ? /* Disable the CPU clock */
+ ? ? ? ? ? ? reg = readl(&clkrst->crc_clk_out_enb_l);
+ ? ? ? ? ? ? reg |= CLK_ENB_CPU;
+ ? ? ? ? ? ? clk = readl(&clkrst->crc_clk_cpu_cmplx);
+ ? ? ? ? ? ? clk |= CPU0_CLK_STP;
+ ? ? }

Quoted 2 lines

For if/elses that share common code, the common code should be broken out. ?eg above only the one-line |=/&= operations should be conditional.

Yep, already done as part of the previous cleanup. Just need to put it into the full patchset #2.

Quoted 17 lines
Quoted 4 lines

+ ? ? writel(clk, &clkrst->crc_clk_cpu_cmplx);
+ ? ? writel(reg, &clkrst->crc_clk_out_enb_l);

arch/arm/cpu/armv7/start.S +1 -0
+}

arch/arm/cpu/armv7/start.S

Quoted 10 lines
arch/arm/cpu/armv7/start.S +10 -0
+
+static int is_cpu_powered(void)
+{
+ ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? u32 ? reg;
+
+ ? ? reg = readl(&pmc->pmc_pwrgate_status);
+
+ ? ? if (reg & CPU_PWRED)
+ ? ? ? ? ? ? return TRUE;

I'd remove the reg variable. ?eg something like:
return readl(&pmc->pmc_pwrgate_status & CPU_PWRED ? 1 : 0);

Good. Will do.

Quoted 12 lines
Quoted 12 lines

+ ? ? return FALSE;

arch/arm/cpu/armv7/start.S +10 -0
+}
+
+static void remove_cpu_io_clamps(void)
+{
+ ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? u32 ? reg;
+
+ ? ? /* Remove the clamps on the CPU I/O signals */
+ ? ? reg = readl(&pmc->pmc_remove_clamping);
+ ? ? reg |= CPU_CLMP;
Quoted 8 lines
Quoted 4 lines

+ ? ? writel(reg, &pmc->pmc_remove_clamping);
+
+ ? ? /* Give I/O signals time to stabilize */
+ ? ? udelay(1000);

For magic delays it'd be good to reference why you're waiting a specific amount of time. ?Does a manual state 1 ms? ?Did testing show 1ms was required?

Not sure, since this code came from the dark ages of Tegra bringup, and was ported from our in-house bootloader.
The Tegra TRM doesn't call out a specific delay, and no one seems to be able to point to any reference for this.
I think the 'give I/O signals time to stabilize' will have to suffice here. I can make it a #define such as 'IO_STAB_TIME', if that'd help.

Quoted 15 lines

arch/arm/cpu/armv7/start.S

Quoted 13 lines
arch/arm/cpu/armv7/start.S +12 -0
+}
+
+static void powerup_cpu(void)
+{
+ ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? u32 ? reg;
+
+ ? ? if (!is_cpu_powered()) {
+ ? ? ? ? ? ? /* Toggle the CPU power state (OFF -> ON) */
+ ? ? ? ? ? ? reg = readl(&pmc->pmc_pwrgate_toggle);
+ ? ? ? ? ? ? reg &= (PARTID_CP);
+ ? ? ? ? ? ? reg |= START_CP;

Why ()'s on one operation, but not the other?

Don't know - part of the porting process. I'll remove 'em.

Quoted 22 lines
Quoted 22 lines

+ ? ? ? ? ? ? writel(reg, &pmc->pmc_pwrgate_toggle);

arch/arm/cpu/armv7/start.S +20 -0
+
+ ? ? ? ? ? ? /* Wait for the power to come up */
+ ? ? ? ? ? ? while (!is_cpu_powered())
+ ? ? ? ? ? ? ? ? ? ? ; ? ? ? ? ? ? ? ? ? ? ? /* Do nothing */
+
+ ? ? ? ? ? ? /*
+ ? ? ? ? ? ? ?* Remove the I/O clamps from CPU power partition.
+ ? ? ? ? ? ? ?* Recommended only on a Warm boot, if the CPU partition gets
+ ? ? ? ? ? ? ?* power gated. Shouldn't cause any harm when called after a
+ ? ? ? ? ? ? ?* cold boot according to HW, probably just redundant.
+ ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? remove_cpu_io_clamps();
+ ? ? }
+}
+
+static void enable_cpu_power_rail(void)
+{
+ ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? u32 ? reg;
+
Quoted 8 lines
Quoted 6 lines

+ ? ? reg = readl(&pmc->pmc_cntrl);
+ ? ? reg |= CPUPWRREQ_OE;
+ ? ? writel(reg, &pmc->pmc_cntrl);
+
+ ? ? /* Delay to allow for stable power (CPU_PWR_REQ -> VDD_CPU from PMU) */
+ ? ? udelay(3750);

Ditto for description.

Ditto on why the delay? In this case, I did find a reference to the time needed between the request from the chipset to the PMU, hence the comment.

Quoted 13 lines
Quoted 13 lines
arch/arm/cpu/armv7/start.S +12 -0
+}
+
+static void reset_A9_cpu(int reset)
+{
+ ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? u32 ? reg, cpu;
+
+ ? ? /*
+ ? ? * NOTE: ?Regardless of whether the request is to hold the CPU in reset
+ ? ? * ? ? ? ?or take it out of reset, every processor in the CPU complex
+ ? ? * ? ? ? ?except the master (CPU 0) will be held in reset because the
+ ? ? * ? ? ? ?AVP only talks to the master. The AVP does not know that there
Quoted 8 lines
Quoted 6 lines

+ ? ? * ? ? ? ?are multiple processors in the CPU complex.
+ ? ? */
+
+ ? ? /* Hold CPU 1 in reset */
+ ? ? cpu = SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1;
+ ? ? writel(cpu, &clkrst->crc_cpu_cmplx_set);

The cpu variable can be removed.

It could be, sure. But it makes the line longer, >80 chars, and hence it would have to be broken into two lines.
Actually, now that I look at the code again, it appears that 'cpu' later should be OR'd with the SET_/CLR_DBGRESET0, etc. bits, depending on the state of 'reset'.
I'll give it a rewrite for the next patch.

Quoted 12 lines

arch/arm/cpu/armv7/start.S

Quoted 10 lines

+ ? ? reg = readl(&clkrst->crc_rst_dev_l);
+ ? ? if (reset) {
+ ? ? ? ? ? ? /* Place CPU0 into reset */
+ ? ? ? ? ? ? cpu = SET_DBGRESET0 | SET_DERESET0 | SET_CPURESET0;
+ ? ? ? ? ? ? writel(cpu, &clkrst->crc_cpu_cmplx_set);

arch/arm/cpu/armv7/start.S +4 -0
+
+ ? ? ? ? ? ? /* Enable master CPU reset */
+ ? ? ? ? ? ? reg |= SWR_CPU_RST;
+

Extra newline.

OK.

Quoted 38 lines
Quoted 38 lines

+ ? ? } else {
+ ? ? ? ? ? ? /* Take CPU0 out of reset */
+ ? ? ? ? ? ? cpu = CLR_DBGRESET0 | CLR_DERESET0 | CLR_CPURESET0;
+ ? ? ? ? ? ? writel(cpu, &clkrst->crc_cpu_cmplx_clr);

arch/arm/cpu/armv7/start.S +33 -0
+
+ ? ? ? ? ? ? /* Disable master CPU reset */
+ ? ? ? ? ? ? reg &= ~SWR_CPU_RST;
+ ? ? }
+
+ ? ? writel(reg, &clkrst->crc_rst_dev_l);
+}
+
+static void clock_enable_coresight(int enable)
+{
+ ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? u32 ? rst, clk, src;
+
+ ? ? rst = readl(&clkrst->crc_rst_dev_u);
+ ? ? clk = readl(&clkrst->crc_clk_out_enb_u);
+
+ ? ? if (enable) {
+ ? ? ? ? ? ? rst &= ~SWR_CSITE_RST;
+ ? ? ? ? ? ? clk |= CLK_ENB_CSITE;
+ ? ? } else {
+ ? ? ? ? ? ? rst |= SWR_CSITE_RST;
+ ? ? ? ? ? ? clk &= ~CLK_ENB_CSITE;
+ ? ? }
+
+ ? ? writel(clk, &clkrst->crc_clk_out_enb_u);
+ ? ? writel(rst, &clkrst->crc_rst_dev_u);
+
+ ? ? if (enable) {
+ ? ? ? ? ? ? /*
+ ? ? ? ? ? ? ?* Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by
+ ? ? ? ? ? ? ?* ?1.5, giving an effective frequency of 144MHz.
+ ? ? ? ? ? ? ?* Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor
+ ? ? ? ? ? ? ?* ?(bits 7:0), so 00000001b == 1.5 (n+1 + .5)
Quoted 8 lines
Quoted 6 lines

+ ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
+ ? ? ? ? ? ? writel(src, &clkrst->crc_clk_src_csite); +
+ ? ? ? ? ? ? /* Unlock the CPU CoreSight interfaces */
+ ? ? ? ? ? ? rst = 0xC5ACCE55;

What's this number? ?Is there a define that could be used instead?

Sure, I can add a #define. Some magic ARM access sequence to unlock the CoreSight I/F, as the comment says

Quoted 18 lines
Quoted 18 lines

+ ? ? ? ? ? ? writel(rst, CSITE_CPU_DBG0_LAR);
+ ? ? ? ? ? ? writel(rst, CSITE_CPU_DBG1_LAR);
+ ? ? }

arch/arm/cpu/armv7/start.S +14 -0
+}
+
+void start_cpu(u32 reset_vector)
+{
+ ? ? /* Enable VDD_CPU */
+ ? ? enable_cpu_power_rail();
+
+ ? ? /* Hold the CPUs in reset */
+ ? ? reset_A9_cpu(TRUE);
+
+ ? ? /* Disable the CPU clock */
+ ? ? enable_cpu_clock(FALSE);
+
+ ? ? /* Enable CoreSight */
Quoted 8 lines
Quoted 6 lines

+ ? ? clock_enable_coresight(TRUE);
+
+ ? ? /*
+ ? ? * Set the entry point for CPU execution from reset,
+ ? ? * ?if it's a non-zero value.
+ ? ? */

Spaces should be added above.

Spaces where? Please be more specific. Again, checkpatch had no problem with this section.

Quoted 23 lines
Quoted 23 lines

+ ? ? if (reset_vector)
+ ? ? ? ? ? ? set_cpu_reset_vector(reset_vector);

arch/arm/cpu/armv7/start.S +20 -0
+
+ ? ? /* Enable the CPU clock */
+ ? ? enable_cpu_clock(TRUE);
+
+ ? ? /* If the CPU doesn't already have power, power it up */
+ ? ? if (!is_cpu_powered())
+ ? ? ? ? ? ? powerup_cpu();
+
+ ? ? /* Take the CPU out of reset */
+ ? ? reset_A9_cpu(FALSE);
+}
+
+
+void halt_avp(void)
+{
+ ? ? u32 ? reg;
+
+ ? ? for (;;) {
+ ? ? ? ? ? ? reg = HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \
+ ? ? ? ? ? ? ? ? ? ? | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29);
Quoted 8 lines
Quoted 5 lines

+ ? ? ? ? ? ? writel(reg, FLOW_CTLR_HALT_COP_EVENTS);
+ ? ? }
+ ? ? /* Should never get here */
+ ? ? for (;;)
+ ? ? ? ? ? ? ;

I'd remove the use of reg, and a secondary infinite loop seems necessary.

OK, I'll rewrite it.

Quoted 16 lines
Quoted 16 lines
arch/arm/cpu/armv7/start.S +15 -0
+}
+
+void startup_cpu(void)
+{
+ ? ? /* Initialize the AVP, clocks, and memory controller */
+ ? ? /* SDRAM is guaranteed to be on at this point */
+
+ ? ? asm volatile(
+
+ ? ? /* Start the CPU */
+ ? ? /* R0 = reset vector for CPU */
+ ? ? "ldr ? ? r0, =cold_boot ? ? ?\n"
+ ? ? "bl ? ? ?start_cpu ? ? ? ? ? \n"
+
+ ? ? /* Transfer control to the AVP code */
Quoted 8 lines
Quoted 5 lines

+ ? ? "bl ? ? ?halt_avp ? ? ? ? ? ?\n"
+
+ ? ? /* Should never get here */
+ ? ? "b ? ? ? . ? ? ? ? ? ? ? ? ? \n"
+ ? ? );

The assembly code should be indented. ?Actually, is there a reason not to move all these assembly functions into a seperate assembly file?

I can indent the asm code, no problem.
I don't see the need to move it to a .S file, though. Lots of examples of embedded assembly code in the U-Boot tree.
Unless I see some strong objections, I'm just going to indent it (and other asm statements).

Quoted 42 lines
Quoted 42 lines
arch/arm/cpu/armv7/start.S +41 -0
+}
+
+extern ulong _armboot_start;
+u32 cpu_boot_stack = CPU_EARLY_BOOT_STACK_LIMIT;
+u32 avp_boot_stack = AVP_EARLY_BOOT_STACK_LIMIT;
+u32 proc_tag = PG_UP_TAG_0_PID_CPU & 0xFF;
+u32 deadbeef = 0xdeadbeef;
+
+void cold_boot(void)
+{
+ ? ? asm volatile(
+
+ ? ? "msr ? ? cpsr_c, #0xd3 ? ? ? ? ? ?\n"
+ ? ? /*
+ ? ? * Check current processor: CPU or AVP?
+ ? ? * If AVP, go to AVP boot code, else continue on.
+ ? ? */
+ ? ? "mov ? ? r0, %0 ? ? ? ? ? ? ? ? ? \n"
+ ? ? "ldrb ? ?r2, [r0, %1] ? ? ? ? ? ? \n"
+ ? ? /* are we the CPU? */
+ ? ? "cmp ? ? r2, %2 ? ? ? ? ? ? ? ? ? \n"
+ ? ? "mov ? ? sp, %3 ? ? ? ? ? ? ? ? ? \n"
+ ? ? /* leave in some symbols for release debugging */
+ ? ? "mov ? ? r3, %6 ? ? ? ? ? ? ? ? ? \n"
+ ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? /* ?yep, we are the CPU */
+ ? ? "bxeq ? ? %4 ? ? ? ? ? ? ? ? ? ? ?\n"
+ ? ? /* AVP Initialization follows this path */
+ ? ? "mov ? ? sp, %5 ? ? ? ? ? ? ? ? ? \n"
+ ? ? /* leave in some symbols for release debugging */
+ ? ? "mov ? ? r3, %6 ? ? ? ? ? ? ? ? ? \n"
+ ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+ ? ? "str ? ? r3, [sp, #-4]! ? ? ? ? ? \n"
+
+ ? ? /* Init and Start CPU */
+ ? ? "b ? ? ? startup_cpu ? ? ? ? ? ? ?\n"
+ ? ? :
+ ? ? : "i"(NV_PA_PG_UP_BASE),
+ ? ? "i"(PG_UP_TAG_0),
+ ? ? "r"(proc_tag),
Quoted 8 lines
Quoted 6 lines

+ ? ? "r"(cpu_boot_stack),
+ ? ? "r"(_armboot_start),
+ ? ? "r"(avp_boot_stack),
+ ? ? "r"(deadbeef)
+ ? ? : "r0", "r2", "r3", "cc", "lr"
+ ? ? );

Ditto on indentation/move.

Albert pointed out that this code is kinda dense, and I agree. I'm going to rewrite without the %0 stuff, plus add indents.

Quoted 10 lines
Quoted 10 lines
arch/arm/cpu/armv7/start.S +9 -0
+}
+
+void enable_scu(void)
+{
+ ? ? struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE;
+ ? ? u32 reg;
+
+ ? ? reg = readl(&scu->scu_ctrl);
+ ? ? if (reg & SCU_ENABLE) {
Quoted 8 lines
Quoted 3 lines

+ ? ? ? ? ? ? /* SCU already enabled, return */
+ ? ? ? ? ? ? return;
+ ? ? }

I'd not use reg above, and not use brackets, eg:
/* If the SCU is already enabled, we have nothing to do */ if (readl(&scu_ctrl) & SCU_ENABLE)
? ? ? ?return;

Sure, I can do that.

Quoted 12 lines

arch/arm/cpu/armv7/start.S

Quoted 10 lines

+ ? ? /* Invalidate all ways for all processors */
+ ? ? writel(0xFFFF, &scu->scu_inv_all);

arch/arm/cpu/armv7/start.S +7 -0
+
+ ? ? /* Enable SCU - bit 0 */
+ ? ? reg = readl(&scu->scu_ctrl);
+ ? ? reg |= SCU_ENABLE;
+ ? ? writel(reg, &scu->scu_ctrl);
+
+ ? ? return;

Remove return.

OK.

Quoted 53 lines
Quoted 53 lines
arch/arm/cpu/armv7/start.S +52 -0
+}
+
+void cache_configure(void)
+{
+ ? ? asm volatile(
+
+ ? ? "stmdb r13!,{r14} ? ? ? ? ? ? ? ? \n"
+ ? ? /* invalidate instruction cache */
+ ? ? "mov r1, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? "mcr p15, 0, r1, c7, c5, 0 ? ? ? ?\n"
+
+ ? ? /* invalidate the i&d tlb entries */
+ ? ? "mcr p15, 0, r1, c8, c5, 0 ? ? ? ?\n"
+ ? ? "mcr p15, 0, r1, c8, c6, 0 ? ? ? ?\n"
+
+ ? ? /* enable instruction cache */
+ ? ? "mrc ?p15, 0, r1, c1, c0, 0 ? ? ? \n"
+ ? ? "orr ?r1, r1, #(1<<12) ? ? ? ? ? ?\n"
+ ? ? "mcr ?p15, 0, r1, c1, c0, 0 ? ? ? \n"
+
+ ? ? "bl enable_scu ? ? ? ? ? ? ? ? ? ?\n"
+
+ ? ? /* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */
+ ? ? "mrc p15, 0, r0, c1, c0, 1 ? ? ? ?\n"
+ ? ? "orr r0, r0, #0x41 ? ? ? ? ? ? ? ?\n"
+ ? ? "mcr p15, 0, r0, c1, c0, 1 ? ? ? ?\n"
+
+ ? ? /* Now flush the Dcache */
+ ? ? "mov r0, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? /* 256 cache lines */
+ ? ? "mov r1, #256 ? ? ? ? ? ? ? ? ? ? \n"
+
+ ? ? "invalidate_loop: ? ? ? ? ? ? ? ? \n"
+
+ ? ? "add r1, r1, #-1 ? ? ? ? ? ? ? ? ?\n"
+ ? ? "mov r0, r1, lsl #5 ? ? ? ? ? ? ? \n"
+ ? ? /* invalidate d-cache using line (way0) */
+ ? ? "mcr p15, 0, r0, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? "orr r2, r0, #(1<<30) ? ? ? ? ? ? \n"
+ ? ? /* invalidate d-cache using line (way1) */
+ ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? "orr r2, r0, #(2<<30) ? ? ? ? ? ? \n"
+ ? ? /* invalidate d-cache using line (way2) */
+ ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? "orr r2, r0, #(3<<30) ? ? ? ? ? ? \n"
+ ? ? /* invalidate d-cache using line (way3) */
+ ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+ ? ? "cmp r1, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? "bne invalidate_loop ? ? ? ? ? ? ?\n"
Quoted 8 lines
Quoted 6 lines

+
+ ? ? /* FIXME: should have ap20's L2 disabled too */
+ ? ? "invalidate_done: ? ? ? ? ? ? ? ? \n"
+ ? ? "ldmia r13!,{pc} ? ? ? ? ? ? ? ? ?\n"
+ ? ? ".ltorg ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? );

Ditto on indentation/move.

I'll indent it.

Quoted 12 lines

arch/arm/cpu/armv7/start.S

Quoted 9 lines
arch/arm/cpu/armv7/start.S +8 -0
+}
+
+void init_pmc_scratch(void)
+{
+ ? ? struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+ ? ? /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */
+ ? ? memset(&pmc->pmc_scratch1, 0, 23*4);

Is it safe to memset on IO regions here? ?A for loop of writel's would be safer, and more consistent.

The generated assembly looks OK. These are mem-mapped scratch registers, so there're no side-effects here.
I can convert to a loop if you insist.

Quoted 7 lines

arch/arm/cpu/armv7/start.S

Quoted 5 lines

+ ? ? writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20);

arch/arm/cpu/armv7/start.S +3 -0
+}
+
+u32 s_first_boot = 1;

I'd move all global variables to the top of the file.

OK, will do.

Quoted 13 lines
Quoted 13 lines
arch/arm/cpu/armv7/start.S +12 -0
+
+void cpu_start(void)
+{
+ ? ? struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+
+ ? ? /* enable JTAG */
+ ? ? writel(0xC0, &pmt->pmt_cfg_ctl);
+
+ ? ? if (s_first_boot) {
+ ? ? ? ? ? ? /*
+ ? ? ? ? ? ? ?* Need to set this before cold-booting,
+ ? ? ? ? ? ? ?* ?otherwise we'll end up in an infinite loop.
Quoted 8 lines
Quoted 6 lines

+ ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? s_first_boot = 0;
+ ? ? ? ? ? ? cold_boot();
+ ? ? }
+
+ ? ? return;

Remove return.

OK.

Quoted 53 lines
Quoted 53 lines
arch/arm/cpu/armv7/start.S +21 -0
+}
+
+void tegra2_start()
+{
+ ? ? if (s_first_boot) {
+ ? ? ? ? ? ? /* Init Debug UART Port (115200 8n1) */
+ ? ? ? ? ? ? uart_init();
+
+ ? ? ? ? ? ? /* Init PMC scratch memory */
+ ? ? ? ? ? ? init_pmc_scratch();
+ ? ? }
+
+#ifdef CONFIG_ENABLE_CORTEXA9
+ ? ? /* take the mpcore out of reset */
+ ? ? cpu_start();
+
+ ? ? /* configure cache */
+ ? ? cache_configure();
+#endif
+}
+
arch/arm/cpu/armv7/tegra2/ap20.h new file +25 -0
new file mode 100644
index 0000000..de7622d
@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright 2010-2011
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <asm/types.h>
+
+#ifndef ? ? ?FALSE
Quoted 8 lines

arch/arm/cpu/armv7/tegra2/ap20.h line 30

Quoted 5 lines
arch/arm/cpu/armv7/tegra2/ap20.h new file +5 -0
+#define FALSE ? ? ? ?0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif

These shouldn't be added here. ?They should be somewhere common, or shouldn't be used (my preference).

I would think they'd be in the ARM tree somewhere, but I couldn't find them so I added 'em here.
My preference is to use TRUE/FALSE - it carries more context than 1/0 to me.

Quoted 178 lines
Quoted 178 lines
arch/arm/cpu/armv7/tegra2/ap20.h new file +75 -0
+
+#define NVBL_PLLP_KHZ ? ? ? ?(432000/2)
+/* The stabilization delay in usec */
+#define NVBOOT_CLOCKS_PLL_STABILIZATION_DELAY (300)
+
+#define PLLX_ENABLED ? ? ? ? (1 << 30)
+#define CCLK_BURST_POLICY ? ?0x20008888
+#define SUPER_CCLK_DIVIDER ? 0x80000000
+
+/* Calculate clock fractional divider value from ref and target frequencies */
+#define CLK_DIVIDER(REF, FREQ) ?((((REF) * 2) / FREQ) - 2)
+
+/* Calculate clock frequency value from reference and clock divider value */
+#define CLK_FREQUENCY(REF, REG) ?(((REF) * 2) / (REG + 2))
+
+/* AVP/CPU ID */
+#define PG_UP_TAG_0_PID_CPU ?0x55555555 ? ? ?/* CPU aka "a9" aka "mpcore" */
+#define PG_UP_TAG_0 ? ? ? ? ? ? 0x0
+
+/* AP20-Specific Base Addresses */
+
+/* AP20 Base physical address of SDRAM. */
+#define AP20_BASE_PA_SDRAM ? ? ?0x00000000
+/* AP20 Base physical address of internal SRAM. */
+#define AP20_BASE_PA_SRAM ? ? ? 0x40000000
+/* AP20 Size of internal SRAM (256KB). */
+#define AP20_BASE_PA_SRAM_SIZE ?0x00040000
+/* AP20 Base physical address of flash. */
+#define AP20_BASE_PA_NOR_FLASH ?0xD0000000
+/* AP20 Base physical address of boot information table. */
+#define AP20_BASE_PA_BOOT_INFO ?AP20_BASE_PA_SRAM
+
+/*
+ * Super-temporary stacks for EXTREMELY early startup. The values chosen for
+ * these addresses must be valid on ALL SOCs because this value is used before
+ * we are able to differentiate between the SOC types.
+ *
+ * NOTE: The since CPU's stack will eventually be moved from IRAM to SDRAM, its
+ * ? ? ? stack is placed below the AVP stack. Once the CPU stack has been moved,
+ * ? ? ? the AVP is free to use the IRAM the CPU stack previously occupied if
+ * ? ? ? it should need to do so.
+ *
+ * NOTE: In multi-processor CPU complex configurations, each processor will have
+ * ? ? ? its own stack of size CPU_EARLY_BOOT_STACK_SIZE. CPU 0 will have a
+ * ? ? ? limit of CPU_EARLY_BOOT_STACK_LIMIT. Each successive CPU will have a
+ * ? ? ? stack limit that is CPU_EARLY_BOOT_STACK_SIZE less then the previous
+ * ? ? ? CPU.
+ */
+
+/* Common AVP early boot stack limit */
+#define AVP_EARLY_BOOT_STACK_LIMIT ? \
+ ? ? (AP20_BASE_PA_SRAM + (AP20_BASE_PA_SRAM_SIZE/2))
+/* Common AVP early boot stack size */
+#define AVP_EARLY_BOOT_STACK_SIZE ? ?0x1000
+/* Common CPU early boot stack limit */
+#define CPU_EARLY_BOOT_STACK_LIMIT ? \
+ ? ? (AVP_EARLY_BOOT_STACK_LIMIT - AVP_EARLY_BOOT_STACK_SIZE)
+/* Common CPU early boot stack size */
+#define CPU_EARLY_BOOT_STACK_SIZE ? ?0x1000
+
+#define EXCEP_VECTOR_CPU_RESET_VECTOR ? ? ? ?(NV_PA_EVP_BASE + 0x100)
+#define CSITE_CPU_DBG0_LAR ? ? ? ? ? (NV_PA_CSITE_BASE + 0x10FB0)
+#define CSITE_CPU_DBG1_LAR ? ? ? ? ? (NV_PA_CSITE_BASE + 0x12FB0)
+
+#define FLOW_CTLR_HALT_COP_EVENTS ? ?(NV_PA_FLOW_BASE + 4)
+#define FLOW_MODE_STOP ? ? ? ? ? ? ? ? ? ? ? 2
+#define HALT_COP_EVENT_JTAG ? ? ? ? ?(1 << 28)
+#define HALT_COP_EVENT_IRQ_1 ? ? ? ? (1 << 11)
+#define HALT_COP_EVENT_FIQ_1 ? ? ? ? (1 << 9)
+
+/* Prototypes */
+
+void tegra2_start(void);
+void uart_init(void);
+void udelay(unsigned long);
arch/arm/include/asm/arch-tegra2/clk_rst.h +0 -0
index 6d573bf..d67a5d7 100644
@@ -149,6 +149,9 @@ struct clk_rst_ctlr {

? ? ? uint crc_clk_src_csite; ? ? ? ? /*_CSITE_0, ? ? ? ? ? ? 0x1D4 */ ? ? ? uint crc_reserved19[9]; ? ? ? ? /* ? ? ? ? ? ? ? ? ? ? ?0x1D8-1F8 */ ? ? ? uint crc_clk_src_osc; ? ? ? ? ? /*_OSC_0, ? ? ? ? ? ? ? 0x1FC */
+ ? ? uint crc_reserved20[80]; ? ? ? ?/* ? ? ? ? ? ? ? ? ? ? ?0x200-33C */
+ ? ? uint crc_cpu_cmplx_set; ? ? ? ? /* _CPU_CMPLX_SET_0, ? ?0x340 */
+ ? ? uint crc_cpu_cmplx_clr; ? ? ? ? /* _CPU_CMPLX_CLR_0, ? ?0x344 */ ?};

?#define PLL_BYPASS ? ? ? ? ? (1 << 31)

arch/arm/include/asm/arch-tegra2/clk_rst.h +24 -0
@@ -162,4 +165,28 @@ struct clk_rst_ctlr {
 ?#define SWR_UARTA_RST ? ? ? ? ? ? ? ?(1 << 6)
 ?#define CLK_ENB_UARTA ? ? ? ? ? ? ? ?(1 << 6)
 
+#define SWR_CPU_RST ? ? ? ? ?(1 << 0)
+#define CLK_ENB_CPU ? ? ? ? ?(1 << 0)
+#define SWR_CSITE_RST ? ? ? ? ? ? ? ?(1 << 9)
+#define CLK_ENB_CSITE ? ? ? ? ? ? ? ?(1 << 9)
+
+#define SET_CPURESET0 ? ? ? ? ? ? ? ?(1 << 0)
+#define SET_DERESET0 ? ? ? ? (1 << 4)
+#define SET_DBGRESET0 ? ? ? ? ? ? ? ?(1 << 12)
+
+#define SET_CPURESET1 ? ? ? ? ? ? ? ?(1 << 1)
+#define SET_DERESET1 ? ? ? ? (1 << 5)
+#define SET_DBGRESET1 ? ? ? ? ? ? ? ?(1 << 13)
+
+#define CLR_CPURESET0 ? ? ? ? ? ? ? ?(1 << 0)
+#define CLR_DERESET0 ? ? ? ? (1 << 4)
+#define CLR_DBGRESET0 ? ? ? ? ? ? ? ?(1 << 12)
+
+#define CLR_CPURESET1 ? ? ? ? ? ? ? ?(1 << 1)
+#define CLR_DERESET1 ? ? ? ? (1 << 5)
+#define CLR_DBGRESET1 ? ? ? ? ? ? ? ?(1 << 13)
+
+#define CPU0_CLK_STP ? ? ? ? (1 << 8)
+#define CPU1_CLK_STP ? ? ? ? (1 << 9)
+

?#endif ? ? ? /* CLK_RST_H */

arch/arm/include/asm/arch-tegra2/pmc.h +0 -0
index 7ec9eeb..b1d47cd 100644
@@ -121,4 +121,12 @@ struct pmc_ctlr {

? ? ? uint pmc_gate; ? ? ? ? ? ? ? ? ?/* _GATE_0, offset 15C */ ?};

arch/arm/include/asm/arch-tegra2/pmc.h +8 -0
+#define CPU_PWRED ? ?1
+#define CPU_CLMP ? ? 1
+
+#define PARTID_CP ? ?0xFFFFFFF8
+#define START_CP ? ? (1 << 8)
+
+#define CPUPWRREQ_OE (1 << 16)
+

?#endif ? ? ? /* PMC_H */

arch/arm/include/asm/arch-tegra2/scu.h new file +36 -0
new file mode 100644
index 0000000..d2faa6f
@@ -0,0 +1,43 @@
+/*
+ * ?(C) Copyright 2010,2011
+ * ?NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _SCU_H_
+#define _SCU_H_
+
+/* ARM Snoop Control Unit (SCU) registers */
+struct scu_ctlr {
+ ? ? uint scu_ctrl; ? ? ? ? ?/* SCU Control Register, offset 00 */
+ ? ? uint scu_cfg; ? ? ? ? ? /* SCU Config Register, offset 04 */
+ ? ? uint scu_cpu_pwr_stat; ?/* SCU CPU Power Status Register, offset 08 */
+ ? ? uint scu_inv_all; ? ? ? /* SCU Invalidate All Register, offset 0C */
+ ? ? uint scu_reserved0[12]; /* reserved, offset 10-3C */
+ ? ? uint scu_filt_start; ? ?/* SCU Filtering Start Address Reg, offset 40 */
+ ? ? uint scu_filt_end; ? ? ?/* SCU Filtering End Address Reg, offset 44 */
+ ? ? uint scu_reserved1[2]; ?/* reserved, offset 48-4C */
Quoted 8 lines

arch/arm/include/asm/arch-tegra2/scu.h line 41

Quoted 5 lines
arch/arm/include/asm/arch-tegra2/scu.h new file +5 -0
+ ? ? uint scu_acc_ctl; ? ? ? /* SCU Access Control Register, offset 50 */
+ ? ? uint scu_ns_acc_ctl; ? ?/* SCU Non-secure Access Cntrl Reg, offset 54 */
+};
+
+#define SCU_ENABLE ? 1

Should this be here? ?Seems like its not the proper location to enable things...

It's a bit setting, for the scu_ctrl register. I could change it to (1 << 0), if you'd prefer.
There are other bits in the SCU, but since they aren't used in this code, I didn't declare 'em.

Quoted 6 lines

arch/arm/include/asm/arch-tegra2/scu.h line 43

Quoted 3 lines
arch/arm/include/asm/arch-tegra2/scu.h new file +2 -0
+
+#endif ? ? ? /* SCU_H */

Best,
Peter

Thanks for the review. I'll have a new patch in a couple of days, once I have your feedback on my questions, above.

Tom

Quoted 3 lines
#10 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Hi Tom,

<snip>

Quoted 10 lines
Quoted 7 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 36

Quoted 4 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +4 -0
+static void init_pll_x(void)
+{
+     struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+     u32     reg;

The spaces in front of "reg" can be removed. Ditto for all functions/variables.

Not sure what you mean, here, Peter. There are no spaces here in my ap20.c file, just tabs.
Please clarify.

My email client converted to spaces I was referring to the "u32 reg;"
above. I think it should be "u32<space>reg" instead of "u32<tab>reg". Other places in this patch spaces are used (eg in enable_cpu_clock, and in the struct declaration above), so at a minimum the tabs/spaces should be changed to be consistent, and <type><space><name> seems cleanest to me.

Quoted 10 lines
Quoted 10 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 44

Quoted 8 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +7 -0
+     /* Is PLL-X already running? */
+     reg = readl(&clkrst->crc_pllx_base);
+     if (reg & PLL_ENABLE)
+             return;
+
+     /* Do PLLX init if it isn't running, but BootROM sets it, so TBD */
+}

The above function looks incorrect.

Quoted 5 lines

What looks incorrect? It checks to see if the PLL is already running/enabled, and returns if it is.
Tegra2 mask ROM (BootROM) currently always sets PLLX, so this will always return, but the comment is there for future chips that may not set up PLLX.

It looks like a function that does a read of a value it doesn't care about, does an unnecessary comparison, and then returns either way, without doing anything:) If/when you want to do future stuff with the PLL-X, code should be added then - as is it doesn't do anything and is confusing. The general policy of U-Boot is not to add dead code.

<snip>

Quoted 13 lines
Quoted 5 lines
Quoted 5 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +5 -0
+static void enable_cpu_power_rail(void)
+{
+     struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+     u32   reg;
+
Quoted 8 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 171

Quoted 6 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +6 -0
+     reg = readl(&pmc->pmc_cntrl);
+     reg |= CPUPWRREQ_OE;
+     writel(reg, &pmc->pmc_cntrl);
+
+     /* Delay to allow for stable power (CPU_PWR_REQ -> VDD_CPU from PMU) */
+     udelay(3750);

Ditto for description.

Quoted 3 lines

Ditto on why the delay? In this case, I did find a reference to the time needed between the request from the chipset to the PMU, hence the comment.

It'd be nice mention that reference in the comment. For those designing boards around your chips, during debug they will look through the initialization code and wonder "I wonder if we need to delay longer", or "I'm not using the same power supply sequencer, I wonder if this might be a problem". If you more explicitly state where the delay came from, or what the delay specifically accomplishes, it saves others from having to guess and investigate.

Quoted 20 lines
Quoted 12 lines
Quoted 12 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +12 -0
+}
+
+static void reset_A9_cpu(int reset)
+{
+     struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+     u32   reg, cpu;
+
+     /*
+     * NOTE:  Regardless of whether the request is to hold the CPU in reset
+     *        or take it out of reset, every processor in the CPU complex
+     *        except the master (CPU 0) will be held in reset because the
+     *        AVP only talks to the master. The AVP does not know that there
Quoted 8 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 189

Quoted 6 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +6 -0
+     *        are multiple processors in the CPU complex.
+     */
+
+     /* Hold CPU 1 in reset */
+     cpu = SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1;
+     writel(cpu, &clkrst->crc_cpu_cmplx_set);

The cpu variable can be removed.

Quoted 6 lines

It could be, sure. But it makes the line longer, >80 chars, and hence it would have to be broken into two lines.
Actually, now that I look at the code again, it appears that 'cpu' later should be OR'd with the SET_/CLR_DBGRESET0, etc. bits, depending on the state of 'reset'.
I'll give it a rewrite for the next patch.

Its a matter of preference, but is acceptable either way. I think:
+ writel(SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1,
+ &clkrst->crc_cpu_cmplx_set);

makes it clearer what is going on. Setting 'cpu', then writing would imply to me that 'cpu' has some additional purpose, or is being used later. If you restructure the code, this comment will likely be moot.

<snip>

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +12 -0
+     if (enable) {
+             /*
+              * Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by
+              *  1.5, giving an effective frequency of 144MHz.
+              * Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor
+              *  (bits 7:0), so 00000001b == 1.5 (n+1 + .5)
+              */
+             src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
+             writel(src, &clkrst->crc_clk_src_csite);
+
+             /* Unlock the CPU CoreSight interfaces */
+             rst = 0xC5ACCE55;
Quoted 3 lines
Quoted 1 line

What's this number? Is there a define that could be used instead?

Sure, I can add a #define. Some magic ARM access sequence to unlock the CoreSight I/F, as the comment says

Its not clear what the number is from the comment. Is it a bitmask where each bit has some significance? Or is it just a "magic number" of some sort? If its a magic number with no other significance, a more verbose comment is fine stating so without adding a define.

Quoted 26 lines
Quoted 18 lines
Quoted 18 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +17 -0
+             writel(rst, CSITE_CPU_DBG0_LAR);
+             writel(rst, CSITE_CPU_DBG1_LAR);
+     }
+}
+
+void start_cpu(u32 reset_vector)
+{
+     /* Enable VDD_CPU */
+     enable_cpu_power_rail();
+
+     /* Hold the CPUs in reset */
+     reset_A9_cpu(TRUE);
+
+     /* Disable the CPU clock */
+     enable_cpu_clock(FALSE);
+
+     /* Enable CoreSight */
Quoted 8 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 265

Quoted 6 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +6 -0
+     clock_enable_coresight(TRUE);
+
+     /*
+     * Set the entry point for CPU execution from reset,
+     *  if it's a non-zero value.
+     */

Spaces should be added above.

Quoted 2 lines

Spaces where? Please be more specific. Again, checkpatch had no problem with this section.

The multiline comment is not aligned:
/*
*
*
*/
should be
/*
*
*/

<snip>

Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +7 -0
+void halt_avp(void)
+{
+     u32   reg;
+
+     for (;;) {
+             reg = HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \
+                     | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29);
Quoted 8 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 292

Quoted 5 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +5 -0
+             writel(reg, FLOW_CTLR_HALT_COP_EVENTS);
+     }
+     /* Should never get here */
+     for (;;)
+             ;

I'd remove the use of reg, and a secondary infinite loop seems necessary.

Quoted 1 line

OK, I'll rewrite it.

Sorry, should have said "unnecessary" instead of "necessary" in the original comment.

Quoted 21 lines
Quoted 13 lines
Quoted 13 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +13 -0
+void startup_cpu(void)
+{
+     /* Initialize the AVP, clocks, and memory controller */
+     /* SDRAM is guaranteed to be on at this point */
+
+     asm volatile(
+
+     /* Start the CPU */
+     /* R0 = reset vector for CPU */
+     "ldr     r0, =cold_boot      \n"
+     "bl      start_cpu           \n"
+
+     /* Transfer control to the AVP code */
Quoted 8 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 312

Quoted 5 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +5 -0
+     "bl      halt_avp            \n"
+
+     /* Should never get here */
+     "b       .                   \n"
+     );

The assembly code should be indented. Actually, is there a reason not to move all these assembly functions into a seperate assembly file?

Quoted 5 lines

I can indent the asm code, no problem.
I don't see the need to move it to a .S file, though. Lots of examples of embedded assembly code in the U-Boot tree.
Unless I see some strong objections, I'm just going to indent it (and other asm statements).

Agreed are lots of embedded assembly in C files, but they are generally small snippets that interact with surrounding C-code, or simple one-liners.

Eg look in arch/powerpc:
find grep -r asm arch/powerpc | grep vola | grep -v ";"

There are only a handful of multi-line inline assembly references, lots are in headers, and the remaining generally interact with surrounding code.

It looks like most of your uses are standalone functions that would function just fine on their own. Is there a reason you prefer to have them in a C-file instead of in an assembly file?

<snip>

Quoted 61 lines
Quoted 53 lines
Quoted 53 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +52 -0
+}
+
+void cache_configure(void)
+{
+     asm volatile(
+
+     "stmdb r13!,{r14}                 \n"
+     /* invalidate instruction cache */
+     "mov r1, #0                       \n"
+     "mcr p15, 0, r1, c7, c5, 0        \n"
+
+     /* invalidate the i&d tlb entries */
+     "mcr p15, 0, r1, c8, c5, 0        \n"
+     "mcr p15, 0, r1, c8, c6, 0        \n"
+
+     /* enable instruction cache */
+     "mrc  p15, 0, r1, c1, c0, 0       \n"
+     "orr  r1, r1, #(1<<12)            \n"
+     "mcr  p15, 0, r1, c1, c0, 0       \n"
+
+     "bl enable_scu                    \n"
+
+     /* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */
+     "mrc p15, 0, r0, c1, c0, 1        \n"
+     "orr r0, r0, #0x41                \n"
+     "mcr p15, 0, r0, c1, c0, 1        \n"
+
+     /* Now flush the Dcache */
+     "mov r0, #0                       \n"
+     /* 256 cache lines */
+     "mov r1, #256                     \n"
+
+     "invalidate_loop:                 \n"
+
+     "add r1, r1, #-1                  \n"
+     "mov r0, r1, lsl #5               \n"
+     /* invalidate d-cache using line (way0) */
+     "mcr p15, 0, r0, c7, c6, 2        \n"
+
+     "orr r2, r0, #(1<<30)             \n"
+     /* invalidate d-cache using line (way1) */
+     "mcr p15, 0, r2, c7, c6, 2        \n"
+
+     "orr r2, r0, #(2<<30)             \n"
+     /* invalidate d-cache using line (way2) */
+     "mcr p15, 0, r2, c7, c6, 2        \n"
+
+     "orr r2, r0, #(3<<30)             \n"
+     /* invalidate d-cache using line (way3) */
+     "mcr p15, 0, r2, c7, c6, 2        \n"
+     "cmp r1, #0                       \n"
+     "bne invalidate_loop              \n"
Quoted 8 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 439

Quoted 6 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +6 -0
+
+     /* FIXME: should have ap20's L2 disabled too */
+     "invalidate_done:                 \n"
+     "ldmia r13!,{pc}                  \n"
+     ".ltorg                           \n"
+     );

Ditto on indentation/move.

Quoted 1 line

I'll indent it.

That's a pretty big and ugly inline assembly function... I'd push to have it in an assembly file along with the few other assembly-only functions, but its not my say ultimately.

Quoted 12 lines
Quoted 12 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 447

Quoted 9 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +8 -0
+}
+
+void init_pmc_scratch(void)
+{
+     struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+     /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */
+     memset(&pmc->pmc_scratch1, 0, 23*4);

Is it safe to memset on IO regions here? A for loop of writel's would be safer, and more consistent.

Quoted 3 lines

The generated assembly looks OK. These are mem-mapped scratch registers, so there're no side-effects here.
I can convert to a loop if you insist.

The policy is if you are accessing registers, you should use proper IO access functions. The generated assembly and/or CPU may behave differently down the road, as others have ran into.

<snip>

Quoted 11 lines
Quoted 11 lines

arch/arm/cpu/armv7/tegra2/ap20.h line 30

Quoted 8 lines
arch/arm/cpu/armv7/tegra2/ap20.h new file +8 -0
+#include <asm/types.h>
+
+#ifndef      FALSE
+#define FALSE        0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif

These shouldn't be added here. They should be somewhere common, or shouldn't be used (my preference).

Quoted 3 lines

I would think they'd be in the ARM tree somewhere, but I couldn't find them so I added 'em here.
My preference is to use TRUE/FALSE - it carries more context than 1/0 to me.

If you prefer to use TRUE/FALSE, they should be moved into a common location so everywhere uses the same, once-defined definition. Their definitions are already littered over a few files, which would ideally be cleaned up. Perhaps moving all definitions into include/common.h, or somewhere similar would work. Others may have opinions about TRUE/FALSE vs 1/0 - it seems like TRUE/FALSE aren't generally used.

< snip>

Quoted 18 lines
Quoted 10 lines
Quoted 10 lines
arch/arm/include/asm/arch-tegra2/scu.h new file +10 -0
+/* ARM Snoop Control Unit (SCU) registers */
+struct scu_ctlr {
+     uint scu_ctrl;          /* SCU Control Register, offset 00 */
+     uint scu_cfg;           /* SCU Config Register, offset 04 */
+     uint scu_cpu_pwr_stat;  /* SCU CPU Power Status Register, offset 08 */
+     uint scu_inv_all;       /* SCU Invalidate All Register, offset 0C */
+     uint scu_reserved0[12]; /* reserved, offset 10-3C */
+     uint scu_filt_start;    /* SCU Filtering Start Address Reg, offset 40 */
+     uint scu_filt_end;      /* SCU Filtering End Address Reg, offset 44 */
+     uint scu_reserved1[2];  /* reserved, offset 48-4C */
Quoted 8 lines

arch/arm/include/asm/arch-tegra2/scu.h line 41

Quoted 5 lines
arch/arm/include/asm/arch-tegra2/scu.h new file +5 -0
+     uint scu_acc_ctl;       /* SCU Access Control Register, offset 50 */
+     uint scu_ns_acc_ctl;    /* SCU Non-secure Access Cntrl Reg, offset 54 */
+};
+
+#define SCU_ENABLE   1

Should this be here? Seems like its not the proper location to enable things...

Quoted 4 lines

It's a bit setting, for the scu_ctrl register. I could change it to (1 << 0), if you'd prefer.
There are other bits in the SCU, but since they aren't used in this code, I didn't declare 'em.

Ahh, I get it - wasn't thinking of a bit definition. I think (1 << 0) would be clearer, or a comment, or the inclusion of the other SCU registers. If its for a specific register, naming it similarly would help too, eg "SCU_CTRL_ENABLE".

Best,
Peter

author
#11 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Peter,

Quoted 15 lines · Peter Tyser

Hi Tom,

<snip>

Quoted 10 lines
Quoted 7 lines

arch/arm/cpu/armv7/tegra2/ap20.c

Quoted 4 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +4 -0
+static void init_pll_x(void)
+{
+ ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST _BASE;
+ ? ? u32 ? ? reg;

The spaces in front of "reg" can be removed. ?Ditto for all functions/variables.

Not sure what you mean, here, Peter. There are no spaces here in my ap20.c file, just tabs.
Please clarify.

Quoted 6 lines

My email client converted to spaces I was referring to the "u32 ? ?reg;" above. ?I think it should be "u32<space>reg" instead of "u32<tab>reg". Other places in this patch spaces are used (eg in enable_cpu_clock, and in the struct declaration above), so at a minimum the tabs/spaces should be changed to be consistent, and <type><space><name> seems cleanest to me.

I see. I can change to <type><space><name> globally, no problem.

Quoted 17 lines
Quoted 11 lines
Quoted 11 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 44

Quoted 9 lines

+ ? ? /* Is PLL-X already running? */
+ ? ? reg = readl(&clkrst->crc_pllx_base);
+ ? ? if (reg & PLL_ENABLE)
+ ? ? ? ? ? ? return;

arch/arm/cpu/armv7/tegra2/ap20.c new file +3 -0
+
+ ? ? /* Do PLLX init if it isn't running, but BootROM sets it, so TBD */
+}

The above function looks incorrect.

Quoted 5 lines

What looks incorrect? It checks to see if the PLL is already running/enabled, and returns if it is.
Tegra2 mask ROM (BootROM) currently always sets PLLX, so this will always return, but the comment is there for future chips that may not set up PLLX.

Quoted 5 lines

It looks like a function that does a read of a value it doesn't care about, does an unnecessary comparison, and then returns either way, without doing anything:) ?If/when you want to do future stuff with the PLL-X, code should be added then - as is it doesn't do anything and is confusing. ?The general policy of U-Boot is not to add dead code.

OK, so not really incorrect, just unnecessary. Agreed - again a vestigial leftover from our in-house code. I'll remove it.

Quoted 20 lines

<snip>

Quoted 13 lines
Quoted 5 lines
Quoted 5 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +5 -0
+static void enable_cpu_power_rail(void)
+{
+ ? ? struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ ? ? u32 ? reg;
+
Quoted 8 lines
Quoted 6 lines

+ ? ? reg = readl(&pmc->pmc_cntrl);
+ ? ? reg |= CPUPWRREQ_OE;
+ ? ? writel(reg, &pmc->pmc_cntrl);
+
+ ? ? /* Delay to allow for stable power (CPU_PWR_REQ -> VDD_CPU from PMU) */
+ ? ? udelay(3750);

Ditto for description.

Quoted 3 lines

Ditto on why the delay? In this case, I did find a reference to the time needed between the request from the chipset to the PMU, hence the comment.

Quoted 7 lines

It'd be nice mention that reference in the comment. ?For those designing boards around your chips, during debug they will look through the initialization code and wonder "I wonder if we need to delay longer", or "I'm not using the same power supply sequencer, I wonder if this might be a problem". ?If you more explicitly state where the delay came from, or what the delay specifically accomplishes, it saves others from having to guess and investigate.

OK, I'll expand the comment.

Quoted 51 lines
Quoted 21 lines
Quoted 13 lines
Quoted 13 lines
(quoted diff) +12 -0
+}
+
+static void reset_A9_cpu(int reset)
+{
+ ? ? struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ ? ? u32 ? reg, cpu;
+
+ ? ? /*
+ ? ? * NOTE: ?Regardless of whether the request is to hold the CPU in reset
+ ? ? * ? ? ? ?or take it out of reset, every processor in the CPU complex
+ ? ? * ? ? ? ?except the master (CPU 0) will be held in reset because the
+ ? ? * ? ? ? ?AVP only talks to the master. The AVP does not know that there
Quoted 8 lines
Quoted 6 lines

+ ? ? * ? ? ? ?are multiple processors in the CPU complex.
+ ? ? */
+
+ ? ? /* Hold CPU 1 in reset */
+ ? ? cpu = SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1;
+ ? ? writel(cpu, &clkrst->crc_cpu_cmplx_set);

The cpu variable can be removed.

Quoted 6 lines

It could be, sure. But it makes the line longer, >80 chars, and hence it would have to be broken into two lines.
Actually, now that I look at the code again, it appears that 'cpu' later should be OR'd with the SET_/CLR_DBGRESET0, etc. bits, depending on the state of 'reset'.
I'll give it a rewrite for the next patch.

Its a matter of preference, but is acceptable either way. ?I think:
+ ? ? ? writel(SET_DBGRESET1 | SET_DERESET1 | SET_CPURESET1,
+ ? ? ? ? ? ? ? &clkrst->crc_cpu_cmplx_set);

makes it clearer what is going on. ?Setting 'cpu', then writing would imply to me that 'cpu' has some additional purpose, or is being used later. ?If you restructure the code, this comment will likely be moot.

<snip>

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines

+ ? ? if (enable) {
+ ? ? ? ? ? ? /*
+ ? ? ? ? ? ? ?* Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by
+ ? ? ? ? ? ? ?* ?1.5, giving an effective frequency of 144MHz.
+ ? ? ? ? ? ? ?* Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor
+ ? ? ? ? ? ? ?* ?(bits 7:0), so 00000001b == 1.5 (n+1 + .5)
+ ? ? ? ? ? ? ?*/
+ ? ? ? ? ? ? src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
+ ? ? ? ? ? ? writel(src, &clkrst->crc_clk_src_csite);
+
+ ? ? ? ? ? ? /* Unlock the CPU CoreSight interfaces */
+ ? ? ? ? ? ? rst = 0xC5ACCE55;

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

What's this number? ?Is there a define that could be used instead?

Sure, I can add a #define. Some magic ARM access sequence to unlock the CoreSight I/F, as the comment says

Its not clear what the number is from the comment. ?Is it a bitmask where each bit has some significance? ?Or is it just a "magic number" of some sort? ?If its a magic number with no other significance, a more verbose comment is fine stating so without adding a define.

OK, I'll expand the comment.

Quoted 30 lines
Quoted 27 lines
Quoted 19 lines
Quoted 19 lines

+ ? ? ? ? ? ? writel(rst, CSITE_CPU_DBG0_LAR);
+ ? ? ? ? ? ? writel(rst, CSITE_CPU_DBG1_LAR);
+ ? ? }

arch/arm/cpu/armv7/tegra2/ap20.c new file +14 -0
+}
+
+void start_cpu(u32 reset_vector)
+{
+ ? ? /* Enable VDD_CPU */
+ ? ? enable_cpu_power_rail();
+
+ ? ? /* Hold the CPUs in reset */
+ ? ? reset_A9_cpu(TRUE);
+
+ ? ? /* Disable the CPU clock */
+ ? ? enable_cpu_clock(FALSE);
+
+ ? ? /* Enable CoreSight */
Quoted 8 lines
Quoted 6 lines

+ ? ? clock_enable_coresight(TRUE);
+
+ ? ? /*
+ ? ? * Set the entry point for CPU execution from reset,
+ ? ? * ?if it's a non-zero value.
+ ? ? */

Spaces should be added above.

Quoted 2 lines

Spaces where? Please be more specific. ?Again, checkpatch had no problem with this section.

Quoted 10 lines

The multiline comment is not aligned:
/*
*
*
*/
should be
/*
?*
?*/

OK, now I see it. Will fix, thanks.

Quoted 56 lines

<snip>

Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
(quoted diff) +7 -0
+void halt_avp(void)
+{
+ ? ? u32 ? reg;
+
+ ? ? for (;;) {
+ ? ? ? ? ? ? reg = HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \
+ ? ? ? ? ? ? ? ? ? ? | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29);
Quoted 8 lines
Quoted 5 lines

+ ? ? ? ? ? ? writel(reg, FLOW_CTLR_HALT_COP_EVENTS);
+ ? ? }
+ ? ? /* Should never get here */
+ ? ? for (;;)
+ ? ? ? ? ? ? ;

I'd remove the use of reg, and a secondary infinite loop seems necessary.

Quoted 1 line

OK, I'll rewrite it.

Sorry, should have said "unnecessary" instead of "necessary" in the original comment.

Quoted 21 lines
Quoted 13 lines
Quoted 13 lines
(quoted diff) +13 -0
+void startup_cpu(void)
+{
+ ? ? /* Initialize the AVP, clocks, and memory controller */
+ ? ? /* SDRAM is guaranteed to be on at this point */
+
+ ? ? asm volatile(
+
+ ? ? /* Start the CPU */
+ ? ? /* R0 = reset vector for CPU */
+ ? ? "ldr ? ? r0, =cold_boot ? ? ?\n"
+ ? ? "bl ? ? ?start_cpu ? ? ? ? ? \n"
+
+ ? ? /* Transfer control to the AVP code */
Quoted 8 lines
Quoted 5 lines

+ ? ? "bl ? ? ?halt_avp ? ? ? ? ? ?\n"
+
+ ? ? /* Should never get here */
+ ? ? "b ? ? ? . ? ? ? ? ? ? ? ? ? \n"
+ ? ? );

The assembly code should be indented. ?Actually, is there a reason not to move all these assembly functions into a seperate assembly file?

Quoted 5 lines

I can indent the asm code, no problem.
I don't see the need to move it to a .S file, though. Lots of examples of embedded assembly code in the U-Boot tree.
Unless I see some strong objections, I'm just going to indent it (and other asm statements).

Agreed are lots of embedded assembly in C files, but they are generally small snippets that interact with surrounding C-code, or simple one-liners.

Eg look in arch/powerpc:
find grep -r asm arch/powerpc | grep vola | grep -v ";"

Quoted 7 lines

There are only a handful of multi-line inline assembly references, lots are in headers, and the remaining generally interact with surrounding code.

It looks like most of your uses are standalone functions that would function just fine on their own. ?Is there a reason you prefer to have them in a C-file instead of in an assembly file?

Just laziness ;)
I'll move these to a new .S file in the next patchset.

Quoted 64 lines

<snip>

Quoted 61 lines
Quoted 61 lines
Quoted 49 lines
(quoted diff) +48 -0
+}
+
+void cache_configure(void)
+{
+ ? ? asm volatile(
+
+ ? ? "stmdb r13!,{r14} ? ? ? ? ? ? ? ? \n"
+ ? ? /* invalidate instruction cache */
+ ? ? "mov r1, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? "mcr p15, 0, r1, c7, c5, 0 ? ? ? ?\n"
+
+ ? ? /* invalidate the i&d tlb entries */
+ ? ? "mcr p15, 0, r1, c8, c5, 0 ? ? ? ?\n"
+ ? ? "mcr p15, 0, r1, c8, c6, 0 ? ? ? ?\n"
+
+ ? ? /* enable instruction cache */
+ ? ? "mrc ?p15, 0, r1, c1, c0, 0 ? ? ? \n"
+ ? ? "orr ?r1, r1, #(1<<12) ? ? ? ? ? ?\n"
+ ? ? "mcr ?p15, 0, r1, c1, c0, 0 ? ? ? \n"
+
+ ? ? "bl enable_scu ? ? ? ? ? ? ? ? ? ?\n"
+
+ ? ? /* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */
+ ? ? "mrc p15, 0, r0, c1, c0, 1 ? ? ? ?\n"
+ ? ? "orr r0, r0, #0x41 ? ? ? ? ? ? ? ?\n"
+ ? ? "mcr p15, 0, r0, c1, c0, 1 ? ? ? ?\n"
+
+ ? ? /* Now flush the Dcache */
+ ? ? "mov r0, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? /* 256 cache lines */
+ ? ? "mov r1, #256 ? ? ? ? ? ? ? ? ? ? \n"
+
+ ? ? "invalidate_loop: ? ? ? ? ? ? ? ? \n"
+
+ ? ? "add r1, r1, #-1 ? ? ? ? ? ? ? ? ?\n"
+ ? ? "mov r0, r1, lsl #5 ? ? ? ? ? ? ? \n"
+ ? ? /* invalidate d-cache using line (way0) */
+ ? ? "mcr p15, 0, r0, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? "orr r2, r0, #(1<<30) ? ? ? ? ? ? \n"
+ ? ? /* invalidate d-cache using line (way1) */
+ ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? "orr r2, r0, #(2<<30) ? ? ? ? ? ? \n"
+ ? ? /* invalidate d-cache using line (way2) */
+ ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+
+ ? ? "orr r2, r0, #(3<<30) ? ? ? ? ? ? \n"

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? /* invalidate d-cache using line (way3) */
+ ? ? "mcr p15, 0, r2, c7, c6, 2 ? ? ? ?\n"
+ ? ? "cmp r1, #0 ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? "bne invalidate_loop ? ? ? ? ? ? ?\n"
+
+ ? ? /* FIXME: should have ap20's L2 disabled too */
+ ? ? "invalidate_done: ? ? ? ? ? ? ? ? \n"
+ ? ? "ldmia r13!,{pc} ? ? ? ? ? ? ? ? ?\n"
+ ? ? ".ltorg ? ? ? ? ? ? ? ? ? ? ? ? ? \n"
+ ? ? );

Ditto on indentation/move.

Quoted 5 lines
Quoted 1 line

I'll indent it.

That's a pretty big and ugly inline assembly function... ?I'd push to have it in an assembly file along with the few other assembly-only functions, but its not my say ultimately.

No problem - I'll move to .S.

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines

arch/arm/cpu/armv7/tegra2/ap20.c

Quoted 10 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +8 -0
+}
+
+void init_pmc_scratch(void)
+{
+ ? ? struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+ ? ? /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */
+ ? ? memset(&pmc->pmc_scratch1, 0, 23*4);

Is it safe to memset on IO regions here? ?A for loop of writel's would be safer, and more consistent.

Quoted 7 lines
Quoted 3 lines

The generated assembly looks OK. These are mem-mapped scratch registers, so there're no side-effects here.
I can convert to a loop if you insist.

The policy is if you are accessing registers, you should use proper IO access functions. ?The generated assembly and/or CPU may behave differently down the road, as others have ran into.

All right. I'll put in a loop of writel()'s.

Quoted 18 lines

<snip>

Quoted 11 lines
Quoted 11 lines

arch/arm/cpu/armv7/tegra2/ap20.h line 30

Quoted 8 lines
arch/arm/cpu/armv7/tegra2/ap20.h new file +8 -0
+#include <asm/types.h>
+
+#ifndef ? ? ?FALSE
+#define FALSE ? ? ? ?0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif

These shouldn't be added here. ?They should be somewhere common, or shouldn't be used (my preference).

Quoted 3 lines

I would think they'd be in the ARM tree somewhere, but I couldn't find them so I added 'em here.
My preference is to use TRUE/FALSE - it carries more context than 1/0 to me.

Quoted 6 lines

If you prefer to use TRUE/FALSE, they should be moved into a common location so everywhere uses the same, once-defined definition. ?Their definitions are already littered over a few files, which would ideally be cleaned up. ?Perhaps moving all definitions into include/common.h, or somewhere similar would work. ?Others may have opinions about TRUE/FALSE vs 1/0 - it seems like TRUE/FALSE aren't generally used.

I don't want to pollute all builds by adding to include/common.h. I'll try to find a more central header in my own tree.

Quoted 26 lines

< snip>

Quoted 18 lines
Quoted 10 lines
Quoted 10 lines
(quoted diff) +10 -0
+/* ARM Snoop Control Unit (SCU) registers */
+struct scu_ctlr {
+ ? ? uint scu_ctrl; ? ? ? ? ?/* SCU Control Register, offset 00 */
+ ? ? uint scu_cfg; ? ? ? ? ? /* SCU Config Register, offset 04 */
+ ? ? uint scu_cpu_pwr_stat; ?/* SCU CPU Power Status Register, offset 08 */
+ ? ? uint scu_inv_all; ? ? ? /* SCU Invalidate All Register, offset 0C */
+ ? ? uint scu_reserved0[12]; /* reserved, offset 10-3C */
+ ? ? uint scu_filt_start; ? ?/* SCU Filtering Start Address Reg, offset 40 */
+ ? ? uint scu_filt_end; ? ? ?/* SCU Filtering End Address Reg, offset 44 */
+ ? ? uint scu_reserved1[2]; ?/* reserved, offset 48-4C */
Quoted 8 lines

arch/arm/include/asm/arch-tegra2/scu.h

Quoted 5 lines

+ ? ? uint scu_acc_ctl; ? ? ? /* SCU Access Control Register, offset 50 */
+ ? ? uint scu_ns_acc_ctl; ? ?/* SCU Non-secure Access Cntrl Reg, offset 54 */

arch/arm/include/asm/arch-tegra2/scu.h new file +3 -0
+};
+
+#define SCU_ENABLE ? 1

Should this be here? ?Seems like its not the proper location to enable things...

Quoted 4 lines

It's a bit setting, for the scu_ctrl register. I could change it to (1 << 0), if you'd prefer.
There are other bits in the SCU, but since they aren't used in this code, I didn't declare 'em.

Quoted 4 lines

Ahh, I get it - wasn't thinking of a bit definition. ?I think (1 << 0) would be clearer, or a comment, or the inclusion of the other SCU registers. ?If its for a specific register, naming it similarly would help too, eg "SCU_CTRL_ENABLE".

Good idea. I'll make it SCU_CTRL_ENABLE. Thanks.

Quoted 3 lines

Best,
Peter

Thanks,
Tom

Quoted 1 line
#12 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Hi Tom,

Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 10 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 44

Quoted 8 lines
arch/arm/cpu/armv7/tegra2/ap20.c new file +7 -0
+     /* Is PLL-X already running? */
+     reg = readl(&clkrst->crc_pllx_base);
+     if (reg & PLL_ENABLE)
+             return;
+
+     /* Do PLLX init if it isn't running, but BootROM sets it, so TBD */
+}

The above function looks incorrect.

What looks incorrect? It checks to see if the PLL is already running/enabled, and returns if it is.
Tegra2 mask ROM (BootROM) currently always sets PLLX, so this will always return, but the comment is there for future chips that may not set up PLLX.

Quoted 7 lines
Quoted 5 lines

It looks like a function that does a read of a value it doesn't care about, does an unnecessary comparison, and then returns either way, without doing anything:) If/when you want to do future stuff with the PLL-X, code should be added then - as is it doesn't do anything and is confusing. The general policy of U-Boot is not to add dead code.

OK, so not really incorrect, just unnecessary. Agreed - again a vestigial leftover from our in-house code. I'll remove it.

Unnecessary/misleading/dead code is inherently not correct:)

<snip>

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 11 lines

arch/arm/cpu/armv7/tegra2/ap20.h line 30

Quoted 8 lines
arch/arm/cpu/armv7/tegra2/ap20.h new file +8 -0
+#include <asm/types.h>
+
+#ifndef      FALSE
+#define FALSE        0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif

These shouldn't be added here. They should be somewhere common, or shouldn't be used (my preference).

I would think they'd be in the ARM tree somewhere, but I couldn't find them so I added 'em here.
My preference is to use TRUE/FALSE - it carries more context than 1/0 to me.

Quoted 8 lines
Quoted 6 lines

If you prefer to use TRUE/FALSE, they should be moved into a common location so everywhere uses the same, once-defined definition. Their definitions are already littered over a few files, which would ideally be cleaned up. Perhaps moving all definitions into include/common.h, or somewhere similar would work. Others may have opinions about TRUE/FALSE vs 1/0 - it seems like TRUE/FALSE aren't generally used.

I don't want to pollute all builds by adding to include/common.h. I'll try to find a more central header in my own tree.

My point is that there are already 32 definitions of TRUE/FALSE - adding a 33rd doesn't seem like a good thing to do. I view a 33rd identical definition as polluting the code more than 1 common definition that most people won't generally use.

Its not my decision, but I assume the powers that be would recommend one of:
- Not using TRUE/FALSE since using non-zero values and 0 are widely accepted as TRUE/FALSE. I think using TRUE/FALSE makes the code harder to understand and more open to bugs. Eg for other code that interacts with your code, or someone reviewing your code, they either have to either assume you defined TRUE as 1, FALSE as 0, or import your definitions. Anyway, I view their use as another layer of unnecessary abstraction with very little benefit.

- Consolidating the definition of TRUE/FALSE.

Wolfgang, do you have a preference about how TRUE/FALSE are generally used/defined?

Best,
Peter

author
#13 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Peter,

Quoted 59 lines · Peter Tyser

Hi Tom,

Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 10 lines

arch/arm/cpu/armv7/tegra2/ap20.c line 44

Quoted 8 lines

+ ? ? /* Is PLL-X already running? */
+ ? ? reg = readl(&clkrst->crc_pllx_base);
+ ? ? if (reg & PLL_ENABLE)
+ ? ? ? ? ? ? return;

arch/arm/cpu/armv7/tegra2/ap20.c new file +3 -0
+
+ ? ? /* Do PLLX init if it isn't running, but BootROM sets it, so TBD */
+}

The above function looks incorrect.

What looks incorrect? It checks to see if the PLL is already running/enabled, and returns if it is.
Tegra2 mask ROM (BootROM) currently always sets PLLX, so this will always return, but the comment is there for future chips that may not set up PLLX.

Quoted 7 lines
Quoted 5 lines

It looks like a function that does a read of a value it doesn't care about, does an unnecessary comparison, and then returns either way, without doing anything:) ?If/when you want to do future stuff with the PLL-X, code should be added then - as is it doesn't do anything and is confusing. ?The general policy of U-Boot is not to add dead code.

OK, so not really incorrect, just unnecessary. Agreed - again a vestigial leftover from our in-house code. I'll remove it.

Unnecessary/misleading/dead code is inherently not correct:)

<snip>

Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 11 lines

arch/arm/cpu/armv7/tegra2/ap20.h line 30

Quoted 8 lines
arch/arm/cpu/armv7/tegra2/ap20.h new file +8 -0
+#include <asm/types.h>
+
+#ifndef ? ? ?FALSE
+#define FALSE ? ? ? ?0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif

These shouldn't be added here. ?They should be somewhere common, or shouldn't be used (my preference).

I would think they'd be in the ARM tree somewhere, but I couldn't find them so I added 'em here.
My preference is to use TRUE/FALSE - it carries more context than 1/0 to me.

Quoted 8 lines
Quoted 6 lines

If you prefer to use TRUE/FALSE, they should be moved into a common location so everywhere uses the same, once-defined definition. ?Their definitions are already littered over a few files, which would ideally be cleaned up. ?Perhaps moving all definitions into include/common.h, or somewhere similar would work. ?Others may have opinions about TRUE/FALSE vs 1/0 - it seems like TRUE/FALSE aren't generally used.

I don't want to pollute all builds by adding to include/common.h. I'll try to find a more central header in my own tree.

My point is that there are already 32 definitions of TRUE/FALSE - adding a 33rd doesn't seem like a good thing to do. ?I view a 33rd identical definition as polluting the code more than 1 common definition that most people won't generally use.

Quoted 9 lines

Its not my decision, but I assume the powers that be would recommend one of:
- Not using TRUE/FALSE since using non-zero values and 0 are widely accepted as TRUE/FALSE. ?I think using TRUE/FALSE makes the code harder to understand and more open to bugs. ?Eg for other code that interacts with your code, or someone reviewing your code, they either have to either assume you defined TRUE as 1, FALSE as 0, or import your definitions. ?Anyway, I view their use as another layer of unnecessary abstraction with very little benefit.

I've removed both the defines and the use of TRUE/FALSE in ap20.* - there were only a few instances.

Quoted 8 lines

- Consolidating the definition of TRUE/FALSE.

Wolfgang, do you have a preference about how TRUE/FALSE are generally used/defined?

Best,
Peter

Thanks,
Tom

Quoted 4 lines
#14 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

In reply to Tom Warren
Quoted 7 lines
Quoted 4 lines

It looks like most of your uses are standalone functions that would function just fine on their own. Is there a reason you prefer to have them in a C-file instead of in an assembly file?

Just laziness ;)
I'll move these to a new .S file in the next patchset.

Actually, writing assembly-only C functions is difficul and error-pronet. I've seen you use "r0" and other registers esplicitly, but this is not allowed in general.

I once wasted some hours in tracking why a non-submitted port of u-boot was not working with a newer compiler. The problem was just
that: the new compiler was inlining a void(void) function; the asm used "r0" and "r1" explicitly, which worked over a function call but was corrupting data when inlined by the newer and more optimizing compiler.

While your functions are currently not inlined (or, like cold_boot, they may be inlined in a place where no register needs to be preserved), another user may move them to a context where the semantics are different, for another board or another boot loader. If they are in a .S files, they will only be called by "bl" and you know the rules for register allocation appy. Besides, a _real_ lazy programmer avoids the extra quotes and \n in the code :)

/alessandro

author
#15 lore raw

PATCH 1/1 arm: Tegra2: add support for A9 CPU init

Allesandro,

Quoted 12 lines · Alessandro Rubini
Quoted 7 lines
Quoted 4 lines

It looks like most of your uses are standalone functions that would function just fine on their own. ?Is there a reason you prefer to have them in a C-file instead of in an assembly file?

Just laziness ;)
I'll move these to a new .S file in the next patchset.

Actually, writing assembly-only C functions is difficul and error-pronet. I've seen you use "r0" and other registers esplicitly, but this is not allowed in general.

Quoted 6 lines

I once wasted some hours in tracking why a non-submitted port of u-boot was not working with a newer compiler. The problem was just
that: the new compiler was inlining a void(void) function; the asm used "r0" and "r1" explicitly, which worked over a function call but was corrupting data when inlined by the newer and more optimizing compiler.

I've moved most of the in-line assembly to lowlevel_init.S. However, the cold_boot() code proved difficult - I got fixup errors, undefined constants, etc.
I've cleaned it up a bit, but left it in ap20.c, using the %vars - again, replacing them with the actual values caused errors that I couldn't resolve.
Maybe someone else on the list can help to port this code to the assembly file - I'm not expert enough in gcc/as and ARM to do it. New patch to follow RSN.

Quoted 10 lines

While your functions are currently not inlined (or, like cold_boot, they may be inlined in a place where no register needs to be preserved), another user may move them to a context where the semantics are different, for another board or another boot loader. ?If they are in a .S files, they will only be called by "bl" and you know the rules for register allocation appy. Besides, a _real_ lazy programmer avoids the extra quotes and \n in the code :)

/alessandro

Thanks for your insight,
Tom

Quoted 1 line