[U-Boot] [PATCH V2 08/13] ARM: tegra: add SPL/AVP (arm720t) CPU files for Tegra124

Stephen Warren swarren at wwwdotorg.org
Fri Jan 24 01:42:55 CET 2014


From: Tom Warren <twarren.nvidia at gmail.com>

This provides SPL support for Tegra124 boards - AVP early init, plus
CPU (A15) init/jump to main U-Boot.

Signed-off-by: Tom Warren <twarren at nvidia.com>
Signed-off-by: Stephen Warren <swarren at nvidia.com>
---
v2:
* Convert to Kconfig-style make Makefiles.
* Update AVP/PLLP clock programming to match Tegra114.
* Extracted changes to PLLX programming order into a separate patch.
* Use PLL_LOCK_MASK constant instead of a hard-coded value.
* No need to read-modify-write pmc_pwrgate_toggle or
  crc_clk_cpu_cmplx_clr.
* s/1x4/Tegra124/
* don't mangle (c) header in cpu.c.
* Remove leading space from debug() messages.
* Fix comment re: CPUPWRGOOD_TIMER
* Various code formatting fixes and redundant bracket and comment
  removal.
---
 arch/arm/cpu/arm720t/tegra-common/cpu.c |  30 +++-
 arch/arm/cpu/arm720t/tegra-common/cpu.h |   4 +-
 arch/arm/cpu/arm720t/tegra124/Makefile  |   8 +
 arch/arm/cpu/arm720t/tegra124/config.mk |   7 +
 arch/arm/cpu/arm720t/tegra124/cpu.c     | 265 ++++++++++++++++++++++++++++++++
 5 files changed, 312 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/cpu/arm720t/tegra124/Makefile
 create mode 100644 arch/arm/cpu/arm720t/tegra124/config.mk
 create mode 100644 arch/arm/cpu/arm720t/tegra124/cpu.c

diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.c b/arch/arm/cpu/arm720t/tegra-common/cpu.c
index d62bb9e370e0..b2074157c01a 100644
--- a/arch/arm/cpu/arm720t/tegra-common/cpu.c
+++ b/arch/arm/cpu/arm720t/tegra-common/cpu.c
@@ -112,6 +112,22 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
 		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */
 		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */
 	},
+
+	/*
+	 * T124: 700 MHz
+	 *
+	 * Register   Field  Bits   Width
+	 * ------------------------------
+	 * PLLX_BASE  p      23:20    4
+	 * PLLX_BASE  n      15: 8    8
+	 * PLLX_BASE  m       7: 0    8
+	 */
+	{
+		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */
+		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */
+		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */
+		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */
+	},
 };
 
 int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
@@ -128,6 +144,18 @@ int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
 
 	debug(" pllx_set_rate entry\n");
 
+#if defined(CONFIG_TEGRA124)
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+	/* Disable IDDQ */
+	reg = readl(&clkrst->crc_pllx_misc3);
+	reg &= ~PLLX_IDDQ_MASK;
+	writel(reg, &clkrst->crc_pllx_misc3);
+	udelay(2);
+	debug("%s: IDDQ: PLLX IDDQ = 0x%08X\n", __func__,
+	      readl(&clkrst->crc_pllx_misc3));
+#endif	/* CONFIG_TEGRA124 */
+
 	/* Set BYPASS, m, n and p to PLLX_BASE */
 	reg = PLL_BYPASS_MASK | (divm << PLL_DIVM_SHIFT);
 	reg |= ((divn << PLL_DIVN_SHIFT) | (divp << PLL_DIVP_SHIFT));
@@ -323,7 +351,7 @@ void clock_enable_coresight(int enable)
 	if (enable) {
 		/*
 		 * Put CoreSight on PLLP_OUT0 and divide it down as per
-		 * PLLP base frequency based on SoC type (T20/T30/T114).
+		 * PLLP base frequency based on SoC type (T20/T30+).
 		 * Clock divider request would setup CSITE clock as 144MHz
 		 * for PLLP base 216MHz and 204MHz for PLLP base 408MHz
 		 */
diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.h b/arch/arm/cpu/arm720t/tegra-common/cpu.h
index d1520ce2cc88..b4ca44fce18a 100644
--- a/arch/arm/cpu/arm720t/tegra-common/cpu.h
+++ b/arch/arm/cpu/arm720t/tegra-common/cpu.h
@@ -13,7 +13,8 @@
 #if defined(CONFIG_TEGRA20)
 #define NVBL_PLLP_KHZ	216000
 #define CSITE_KHZ	144000
-#elif defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114)
+#elif defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114) || \
+	defined(CONFIG_TEGRA124)
 #define NVBL_PLLP_KHZ	408000
 #define CSITE_KHZ	204000
 #else
@@ -70,3 +71,4 @@ int tegra_get_chip(void);
 int tegra_get_sku_info(void);
 int tegra_get_chip_sku(void);
 void adjust_pllp_out_freqs(void);
+void pmic_enable_cpu_vdd(void);
diff --git a/arch/arm/cpu/arm720t/tegra124/Makefile b/arch/arm/cpu/arm720t/tegra124/Makefile
new file mode 100644
index 000000000000..61abf45d3d29
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra124/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2013-2014
+# NVIDIA Corporation <www.nvidia.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y	+= cpu.o
diff --git a/arch/arm/cpu/arm720t/tegra124/config.mk b/arch/arm/cpu/arm720t/tegra124/config.mk
new file mode 100644
index 000000000000..5e10701f0ea8
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra124/config.mk
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2010-2013
+# NVIDIA Corporation <www.nvidia.com>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#/
+USE_PRIVATE_LIBGCC = yes
diff --git a/arch/arm/cpu/arm720t/tegra124/cpu.c b/arch/arm/cpu/arm720t/tegra124/cpu.c
new file mode 100644
index 000000000000..9b9e11c3b4c5
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra124/cpu.c
@@ -0,0 +1,265 @@
+/*
+ * (C) Copyright 2013
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/ahb.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/flow.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/tegra.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/pmc.h>
+#include <asm/arch-tegra/ap.h>
+#include "../tegra-common/cpu.h"
+
+/* Tegra124-specific CPU init code */
+
+static void enable_cpu_power_rail(void)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("enable_cpu_power_rail entry\n");
+
+	/* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */
+	pinmux_tristate_disable(PINGRP_PWR_I2C_SCL);
+	pinmux_tristate_disable(PINGRP_PWR_I2C_SDA);
+
+	pmic_enable_cpu_vdd();
+
+	/*
+	 * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz),
+	 * set it for 5ms as per SysEng (102MHz*5ms = 510000 (7C830h).
+	 */
+	writel(0x7C830, &pmc->pmc_cpupwrgood_timer);
+
+	/* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */
+	clrbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_POL);
+	setbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_OE);
+}
+
+static void enable_cpu_clocks(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("enable_cpu_clocks entry\n");
+
+	/* Wait for PLL-X to lock */
+	do {
+		reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base);
+		debug("%s: PLLX base = 0x%08X\n", __func__, reg);
+	} while ((reg & PLL_LOCK_MASK) == 0);
+
+	debug("%s: PLLX locked, delay for stable clocks\n", __func__);
+	/* Wait until all clocks are stable */
+	udelay(PLL_STABILIZATION_DELAY);
+
+	debug("%s: Setting CCLK_BURST and DIVIDER\n", __func__);
+	writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
+	writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
+
+	debug("%s: Enabling clock to all CPUs\n", __func__);
+	/* Enable the clock to all CPUs */
+	reg = CLR_CPU3_CLK_STP | CLR_CPU2_CLK_STP | CLR_CPU1_CLK_STP |
+		CLR_CPU0_CLK_STP;
+	writel(reg, &clkrst->crc_clk_cpu_cmplx_clr);
+
+	debug("%s: Enabling main CPU complex clocks\n", __func__);
+	/* Always enable the main CPU complex clocks */
+	clock_enable(PERIPH_ID_CPU);
+	clock_enable(PERIPH_ID_CPULP);
+	clock_enable(PERIPH_ID_CPUG);
+
+	debug("%s: Done\n", __func__);
+}
+
+static void remove_cpu_resets(void)
+{
+	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 reg;
+
+	debug("remove_cpu_resets entry\n");
+
+	/* Take the slow and fast partitions out of reset */
+	reg = CLR_NONCPURESET;
+	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr);
+	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr);
+
+	/* Clear the SW-controlled reset of the slow cluster */
+	reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0 |
+		CLR_L2RESET | CLR_PRESETDBG;
+	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr);
+
+	/* Clear the SW-controlled reset of the fast cluster */
+	reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0 |
+		CLR_CPURESET1 | CLR_DBGRESET1 | CLR_CORERESET1 | CLR_CXRESET1 |
+		CLR_CPURESET2 | CLR_DBGRESET2 | CLR_CORERESET2 | CLR_CXRESET2 |
+		CLR_CPURESET3 | CLR_DBGRESET3 | CLR_CORERESET3 | CLR_CXRESET3 |
+		CLR_L2RESET | CLR_PRESETDBG;
+	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr);
+}
+
+/**
+ * The Tegra124 requires some special clock initialization, including setting up
+ * the DVC I2C, turning on MSELECT and selecting the G CPU cluster
+ */
+void tegra124_init_clocks(void)
+{
+	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 val;
+
+	debug("tegra124_init_clocks entry\n");
+
+	/* Set active CPU cluster to G */
+	clrbits_le32(&flow->cluster_control, 1);
+
+	/* Change the oscillator drive strength */
+	val = readl(&clkrst->crc_osc_ctrl);
+	val &= ~OSC_XOFS_MASK;
+	val |= (OSC_DRIVE_STRENGTH << OSC_XOFS_SHIFT);
+	writel(val, &clkrst->crc_osc_ctrl);
+
+	/* Update same value in PMC_OSC_EDPD_OVER XOFS field for warmboot */
+	val = readl(&pmc->pmc_osc_edpd_over);
+	val &= ~PMC_XOFS_MASK;
+	val |= (OSC_DRIVE_STRENGTH << PMC_XOFS_SHIFT);
+	writel(val, &pmc->pmc_osc_edpd_over);
+
+	/* Set HOLD_CKE_LOW_EN to 1 */
+	setbits_le32(&pmc->pmc_cntrl2, HOLD_CKE_LOW_EN);
+
+	debug("Setting up PLLX\n");
+	init_pllx();
+
+	val = (1 << CLK_SYS_RATE_AHB_RATE_SHIFT);
+	writel(val, &clkrst->crc_clk_sys_rate);
+
+	/* Enable clocks to required peripherals. TBD - minimize this list */
+	debug("Enabling clocks\n");
+
+	clock_set_enable(PERIPH_ID_CACHE2, 1);
+	clock_set_enable(PERIPH_ID_GPIO, 1);
+	clock_set_enable(PERIPH_ID_TMR, 1);
+	clock_set_enable(PERIPH_ID_CPU, 1);
+	clock_set_enable(PERIPH_ID_EMC, 1);
+	clock_set_enable(PERIPH_ID_I2C5, 1);
+	clock_set_enable(PERIPH_ID_APBDMA, 1);
+	clock_set_enable(PERIPH_ID_MEM, 1);
+	clock_set_enable(PERIPH_ID_CORESIGHT, 1);
+	clock_set_enable(PERIPH_ID_MSELECT, 1);
+	clock_set_enable(PERIPH_ID_DVFS, 1);
+
+	/*
+	 * Set MSELECT clock source as PLLP (00), and ask for a clock
+	 * divider that would set the MSELECT clock at 102MHz for a
+	 * PLLP base of 408MHz.
+	 */
+	clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0,
+				    CLK_DIVIDER(NVBL_PLLP_KHZ, 102000));
+
+	/* Give clock time to stabilize */
+	udelay(IO_STABILIZATION_DELAY);
+
+	/* I2C5 (DVC) gets CLK_M and a divisor of 17 */
+	clock_ll_set_source_divisor(PERIPH_ID_I2C5, 3, 16);
+
+	/* Give clock time to stabilize */
+	udelay(IO_STABILIZATION_DELAY);
+
+	/* Take required peripherals out of reset */
+	debug("Taking periphs out of reset\n");
+	reset_set_enable(PERIPH_ID_CACHE2, 0);
+	reset_set_enable(PERIPH_ID_GPIO, 0);
+	reset_set_enable(PERIPH_ID_TMR, 0);
+	reset_set_enable(PERIPH_ID_COP, 0);
+	reset_set_enable(PERIPH_ID_EMC, 0);
+	reset_set_enable(PERIPH_ID_I2C5, 0);
+	reset_set_enable(PERIPH_ID_APBDMA, 0);
+	reset_set_enable(PERIPH_ID_MEM, 0);
+	reset_set_enable(PERIPH_ID_CORESIGHT, 0);
+	reset_set_enable(PERIPH_ID_MSELECT, 0);
+	reset_set_enable(PERIPH_ID_DVFS, 0);
+
+	debug("tegra124_init_clocks exit\n");
+}
+
+static bool is_partition_powered(u32 mask)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+	u32 reg;
+
+	/* Get power gate status */
+	reg = readl(&pmc->pmc_pwrgate_status);
+	return (reg & mask) == mask;
+}
+
+static void power_partition(u32 status, u32 partid)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("%s: status = %08X, part ID = %08X\n", __func__, status, partid);
+	/* Is the partition already on? */
+	if (!is_partition_powered(status)) {
+		/* No, toggle the partition power state (OFF -> ON) */
+		debug("power_partition, toggling state\n");
+		writel(START_CP | partid, &pmc->pmc_pwrgate_toggle);
+
+		/* Wait for the power to come up */
+		while (!is_partition_powered(status))
+			;
+
+		/* Give I/O signals time to stabilize */
+		udelay(IO_STABILIZATION_DELAY);
+	}
+}
+
+void powerup_cpus(void)
+{
+	debug("powerup_cpus entry\n");
+
+	/* We boot to the fast cluster */
+	debug("powerup_cpus entry: G cluster\n");
+
+	/* Power up the fast cluster rail partition */
+	debug("powerup_cpus: CRAIL\n");
+	power_partition(CRAIL, CRAILID);
+
+	/* Power up the fast cluster non-CPU partition */
+	debug("powerup_cpus: C0NC\n");
+	power_partition(C0NC, C0NCID);
+
+	/* Power up the fast cluster CPU0 partition */
+	debug("powerup_cpus: CE0\n");
+	power_partition(CE0, CE0ID);
+
+	debug("powerup_cpus: done\n");
+}
+
+void start_cpu(u32 reset_vector)
+{
+	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+	debug("start_cpu entry, reset_vector = %x\n", reset_vector);
+
+	tegra124_init_clocks();
+
+	/* Set power-gating timer multiplier */
+	clrbits_le32(&pmc->pmc_pwrgate_timer_mult, TIMER_MULT_MASK);
+	setbits_le32(&pmc->pmc_pwrgate_timer_mult, MULT_8);
+
+	enable_cpu_power_rail();
+	enable_cpu_clocks();
+	clock_enable_coresight(1);
+	remove_cpu_resets();
+	writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+	powerup_cpus();
+	debug("start_cpu exit, should continue @ reset_vector\n");
+}
-- 
1.8.1.5



More information about the U-Boot mailing list