* MA 02111-1307 USA
*/
-#include "ap20.h"
#include <asm/io.h>
#include <asm/arch/tegra2.h>
+#include <asm/arch/ap20.h>
#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/fuse.h>
+#include <asm/arch/gp_padctrl.h>
#include <asm/arch/pmc.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/scu.h>
+#include <asm/arch/warmboot.h>
#include <common.h>
-u32 s_first_boot = 1;
+int tegra_get_chip_type(void)
+{
+ struct apb_misc_gp_ctlr *gp;
+ struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE;
+ uint tegra_sku_id, rev;
+
+ /*
+ * This is undocumented, Chip ID is bits 15:8 of the register
+ * APB_MISC + 0x804, and has value 0x20 for Tegra20, 0x30 for
+ * Tegra30
+ */
+ gp = (struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE;
+ rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT;
+
+ tegra_sku_id = readl(&fuse->sku_info) & 0xff;
+
+ switch (rev) {
+ case CHIPID_TEGRA2:
+ switch (tegra_sku_id) {
+ case SKU_ID_T20:
+ return TEGRA_SOC_T20;
+ case SKU_ID_T25SE:
+ case SKU_ID_AP25:
+ case SKU_ID_T25:
+ case SKU_ID_AP25E:
+ case SKU_ID_T25E:
+ return TEGRA_SOC_T25;
+ }
+ break;
+ }
+ /* unknown sku id */
+ return TEGRA_SOC_UNKNOWN;
+}
+
+/* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */
+static int ap20_cpu_is_cortexa9(void)
+{
+ u32 id = readb(NV_PA_PG_UP_BASE + PG_UP_TAG_0);
+ return id == (PG_UP_TAG_0_PID_CPU & 0xff);
+}
void init_pllx(void)
{
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+ struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_XCPU];
u32 reg;
/* If PLLX is already enabled, just return */
- reg = readl(&clkrst->crc_pllx_base);
- if (reg & PLL_ENABLE)
+ if (readl(&pll->pll_base) & PLL_ENABLE_MASK)
return;
/* Set PLLX_MISC */
- reg = CPCON; /* CPCON[11:8] = 0001 */
- writel(reg, &clkrst->crc_pllx_misc);
+ writel(1 << PLL_CPCON_SHIFT, &pll->pll_misc);
/* Use 12MHz clock here */
- reg = (PLL_BYPASS | PLL_DIVM);
- reg |= (1000 << 8); /* DIVN = 0x3E8 */
- writel(reg, &clkrst->crc_pllx_base);
+ reg = PLL_BYPASS_MASK | (12 << PLL_DIVM_SHIFT);
+ reg |= 1000 << PLL_DIVN_SHIFT;
+ writel(reg, &pll->pll_base);
- reg |= PLL_ENABLE;
- writel(reg, &clkrst->crc_pllx_base);
+ reg |= PLL_ENABLE_MASK;
+ writel(reg, &pll->pll_base);
- reg &= ~PLL_BYPASS;
- writel(reg, &clkrst->crc_pllx_base);
+ reg &= ~PLL_BYPASS_MASK;
+ writel(reg, &pll->pll_base);
}
static void enable_cpu_clock(int enable)
{
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
- u32 reg, clk;
+ u32 clk;
/*
* NOTE:
writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
}
- /* Fetch the register containing the main CPU complex clock enable */
- reg = readl(&clkrst->crc_clk_out_enb_l);
- reg |= CLK_ENB_CPU;
-
/*
* 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) {
- /* Unstop the CPU clock */
- clk &= ~CPU0_CLK_STP;
- } else {
- /* Stop the CPU clock */
- clk |= CPU0_CLK_STP;
- }
+ clk |= 1 << CPU1_CLK_STP_SHIFT;
+ /* Stop/Unstop the CPU clock */
+ clk &= ~CPU0_CLK_STP_MASK;
+ clk |= !enable << CPU0_CLK_STP_SHIFT;
writel(clk, &clkrst->crc_clk_cpu_cmplx);
- writel(reg, &clkrst->crc_clk_out_enb_l);
+
+ clock_enable(PERIPH_ID_CPU);
}
static int is_cpu_powered(void)
{
- struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE;
return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0;
}
static void remove_cpu_io_clamps(void)
{
- struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE;
u32 reg;
/* Remove the clamps on the CPU I/O signals */
static void powerup_cpu(void)
{
- struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE;
u32 reg;
int timeout = IO_STABILIZATION_DELAY;
static void enable_cpu_power_rail(void)
{
- struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE;
u32 reg;
reg = readl(&pmc->pmc_cntrl);
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
* 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) {
- /* Now 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;
- }
+ /* Hold CPU 1 in reset, and CPU 0 if asked */
+ reset_cmplx_set_enable(1, crc_rst_cpu | crc_rst_de | crc_rst_debug, 1);
+ reset_cmplx_set_enable(0, crc_rst_cpu | crc_rst_de | crc_rst_debug,
+ reset);
- writel(reg, &clkrst->crc_rst_dev_l);
+ /* Enable/Disable master CPU reset */
+ reset_set_enable(PERIPH_ID_CPU, reset);
}
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;
- }
+ u32 rst, src;
- writel(clk, &clkrst->crc_clk_out_enb_u);
- writel(rst, &clkrst->crc_rst_dev_u);
+ clock_set_enable(PERIPH_ID_CORESIGHT, enable);
+ reset_set_enable(PERIPH_ID_CORESIGHT, !enable);
if (enable) {
/*
* (bits 7:0), so 00000001b == 1.5 (n+1 + .5)
*/
src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
- writel(src, &clkrst->crc_clk_src_csite);
+ clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src);
/* Unlock the CPU CoreSight interfaces */
rst = 0xC5ACCE55;
void init_pmc_scratch(void)
{
- struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+ struct pmc_ctlr *const pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE;
int i;
/* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */
/* ODMDATA is for kernel use to determine RAM size, LP config, etc. */
writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20);
+
+#ifdef CONFIG_TEGRA2_LP0
+ /* save Sdram params to PMC 2, 4, and 24 for WB0 */
+ warmboot_save_sdram_params();
+#endif
}
-void cpu_start(void)
+void tegra2_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 we are the AVP, start up the first Cortex-A9 */
+ if (!ap20_cpu_is_cortexa9()) {
+ /* 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.
+ * If we are ARM7 - give it a different stack. We are about to
+ * start up the A9 which will want to use this one.
*/
- s_first_boot = 0;
- cold_boot();
+ asm volatile("mov sp, %0\n"
+ : : "r"(AVP_EARLY_BOOT_STACK_LIMIT));
+
+ start_cpu((u32)_start);
+ halt_avp();
+ /* not reached */
}
-}
-void tegra2_start()
-{
- if (s_first_boot) {
- /* Init Debug UART Port (115200 8n1) */
- uart_init();
+ /* Init PMC scratch memory */
+ init_pmc_scratch();
- /* Init PMC scratch memory */
- init_pmc_scratch();
- }
+ enable_scu();
-#ifdef CONFIG_ENABLE_CORTEXA9
- /* take the mpcore out of reset */
- cpu_start();
+ /* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */
+ asm volatile(
+ "mrc p15, 0, r0, c1, c0, 1\n"
+ "orr r0, r0, #0x41\n"
+ "mcr p15, 0, r0, c1, c0, 1\n");
- /* configure cache */
- cache_configure();
-#endif
+ /* FIXME: should have ap20's L2 disabled too? */
}