]> git.sur5r.net Git - u-boot/commitdiff
ARM: tegra: add SPL/AVP (arm720t) CPU files for Tegra124
authorTom Warren <twarren.nvidia@gmail.com>
Fri, 24 Jan 2014 19:46:14 +0000 (12:46 -0700)
committerTom Warren <twarren@nvidia.com>
Mon, 3 Feb 2014 16:46:46 +0000 (09:46 -0700)
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@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Tested-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
arch/arm/cpu/arm720t/tegra-common/cpu.c
arch/arm/cpu/arm720t/tegra-common/cpu.h
arch/arm/cpu/arm720t/tegra124/Makefile [new file with mode: 0644]
arch/arm/cpu/arm720t/tegra124/config.mk [new file with mode: 0644]
arch/arm/cpu/arm720t/tegra124/cpu.c [new file with mode: 0644]

index d62bb9e370e0d4007e28c5ce1063182388b1090c..2c5cd63917d3bffe1bac1cf723359723a710623c 100644 (file)
@@ -112,8 +112,40 @@ 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 */
+       },
 };
 
+static inline void pllx_set_iddq(void)
+{
+#if defined(CONFIG_TEGRA124)
+       struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       u32 reg;
+
+       /* 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
+}
+
 int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
                u32 divp, u32 cpcon)
 {
@@ -128,6 +160,8 @@ int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
 
        debug(" pllx_set_rate entry\n");
 
+       pllx_set_iddq();
+
        /* 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 +357,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
                 */
index d1520ce2cc885712951328ea0f658e00287ff290..b4ca44fce18a71288a0197dbf35f06e0e2b708cb 100644 (file)
@@ -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 (file)
index 0000000..61abf45
--- /dev/null
@@ -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 (file)
index 0000000..5e10701
--- /dev/null
@@ -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 (file)
index 0000000..c03aaf1
--- /dev/null
@@ -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 partid)
+{
+       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 & (1 << partid));
+}
+
+static void power_partition(u32 partid)
+{
+       struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+       debug("%s: part ID = %08X\n", __func__, partid);
+       /* Is the partition already on? */
+       if (!is_partition_powered(partid)) {
+               /* 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(partid))
+                       ;
+
+               /* 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);
+
+       /* Power up the fast cluster non-CPU partition */
+       debug("powerup_cpus: C0NC\n");
+       power_partition(C0NC);
+
+       /* Power up the fast cluster CPU0 partition */
+       debug("powerup_cpus: CE0\n");
+       power_partition(CE0);
+
+       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");
+}