Signed-off-by: Tom Warren <twar...@nvidia.com>
---
 arch/arm/cpu/arm720t/tegra30/Makefile  |   48 +++
 arch/arm/cpu/arm720t/tegra30/board.h   |   25 ++
 arch/arm/cpu/arm720t/tegra30/config.mk |   26 ++
 arch/arm/cpu/arm720t/tegra30/cpu.c     |  570 ++++++++++++++++++++++++++++++++
 arch/arm/cpu/arm720t/tegra30/cpu.h     |   65 ++++
 arch/arm/cpu/arm720t/tegra30/spl.c     |  132 ++++++++
 6 files changed, 866 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/cpu/arm720t/tegra30/Makefile
 create mode 100644 arch/arm/cpu/arm720t/tegra30/board.h
 create mode 100644 arch/arm/cpu/arm720t/tegra30/config.mk
 create mode 100644 arch/arm/cpu/arm720t/tegra30/cpu.c
 create mode 100644 arch/arm/cpu/arm720t/tegra30/cpu.h
 create mode 100644 arch/arm/cpu/arm720t/tegra30/spl.c

diff --git a/arch/arm/cpu/arm720t/tegra30/Makefile 
b/arch/arm/cpu/arm720t/tegra30/Makefile
new file mode 100644
index 0000000..96e722c
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/Makefile
@@ -0,0 +1,48 @@
+#
+# (C) Copyright 2010-2012 Nvidia Corporation.
+#
+# (C) Copyright 2000-2008
+# Wolfgang Denk, DENX Software Engineering, w...@denx.de.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB    = $(obj)lib$(SOC).o
+
+COBJS-y        += cpu.o
+COBJS-$(CONFIG_SPL_BUILD) += spl.o
+
+SRCS   := $(COBJS-y:.o=.c)
+OBJS   := $(addprefix $(obj),$(COBJS-y))
+
+all:   $(obj).depend $(LIB)
+
+$(LIB):        $(OBJS)
+       $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/arm720t/tegra30/board.h 
b/arch/arm/cpu/arm720t/tegra30/board.h
new file mode 100644
index 0000000..fc11a7b
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/board.h
@@ -0,0 +1,25 @@
+/*
+ * (C) Copyright 2010-2012
+ * 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
+ */
+
+void board_init_uart_f(void);
+void gpio_config_uart(void);
diff --git a/arch/arm/cpu/arm720t/tegra30/config.mk 
b/arch/arm/cpu/arm720t/tegra30/config.mk
new file mode 100644
index 0000000..ca9c6ea
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/config.mk
@@ -0,0 +1,26 @@
+#
+# (C) Copyright 2010-2012
+# NVIDIA Corporation <www.nvidia.com>
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <ga...@denx.de>
+#
+# 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
+#
+USE_PRIVATE_LIBGCC = yes
diff --git a/arch/arm/cpu/arm720t/tegra30/cpu.c 
b/arch/arm/cpu/arm720t/tegra30/cpu.c
new file mode 100644
index 0000000..f7d9b87
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/cpu.c
@@ -0,0 +1,570 @@
+/*
+ * (C) Copyright 2010-2012
+ * 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 <common.h>
+#include <asm/io.h>
+#include <asm/arch/tegra30.h>
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/flow.h>
+#include <asm/arch/fuse.h>
+#include <asm/arch/tegra_i2c.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/pmc.h>
+#include <asm/arch/scu.h>
+#include "cpu.h"
+
+struct clk_pll_table {
+       u16             n;
+       u16             m;
+       u8              p;
+       u8              cpcon;
+};
+
+/* ~0=uninitialized/unknown, 0=false, 1=true */
+uint32_t is_tegra_processor_reset = 0xffffffff;
+
+/*
+ * Timing tables for each SOC for all four oscillator options.
+ */
+static struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_COUNT]
+                                               [CLOCK_OSC_FREQ_COUNT] = {
+       /* T20: 1 GHz */
+       {{ 1000, 13, 0, 12},    /* OSC 13M */
+        { 625,  12, 0, 8},     /* OSC 19.2M */
+        { 1000, 12, 0, 12},    /* OSC 12M */
+        { 1000, 26, 0, 12},    /* OSC 26M */
+       },
+
+       /* T25: 1.2 GHz */
+       {{ 923, 10, 0, 12},
+        { 750, 12, 0, 8},
+        { 600,  6, 0, 12},
+        { 600, 13, 0, 12},
+       },
+
+       /* T30(slow): 1.0 GHz */
+       {{ 1000,  13, 0, 8},
+        { 625,  12, 0, 4},
+        { 1000, 12, 0, 8},
+        { 1000,  26, 0, 8},
+       },
+
+       /* T30(high): 1.4 GHz */
+       {{ 862, 8, 0, 8},
+        { 583, 8, 0, 4},
+        { 700, 6, 0, 8},
+        { 700, 13, 0, 8},
+       },
+
+       /* TEGRA_SOC2_SLOW: 312 MHz */
+       {{ 312, 13, 0, 12},     /* OSC 13M */
+        { 260, 16, 0, 8},      /* OSC 19.2M */
+        { 312, 12, 0, 12},     /* OSC 12M */
+        { 312, 26, 0, 12},     /* OSC 26M */
+       },
+};
+
+enum tegra_family_t {
+       TEGRA_FAMILY_T2x,
+       TEGRA_FAMILY_T3x,
+};
+
+int tegra_get_chip_type(void)
+{
+       struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
+       uint tegra_sku_id;
+
+       debug("tegra_get_chip_type entry\n");
+       tegra_sku_id = readl(&fuse->sku_info) & 0xff;
+       debug("  tegra_get_chip_type: sku_id = %d\n", tegra_sku_id);
+
+       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;
+       case SKU_ID_T30:
+               /*
+                * T30 has two options. We will return TEGRA_SOC_T30 until
+                * we have the fdt set up when it may change to
+                * TEGRA_SOC_T30_408MHZ depending on what we set PLLP to.
+                */
+               if (clock_get_rate(CLOCK_ID_PERIPH) == 408000000)
+                       return TEGRA_SOC_T30_408MHZ;
+               else
+                       return TEGRA_SOC_T30;
+
+       default:
+               /* unknown sku id */
+               return TEGRA_SOC_UNKNOWN;
+       }
+}
+
+static enum tegra_family_t get_family(void)
+{
+       u32 reg, chip_id;
+
+       debug("tegra_get_family entry\n");
+       reg = readl(NV_PA_APB_MISC_BASE + GP_HIDREV);
+
+       chip_id = reg >> 8;
+       chip_id &= 0xff;
+       debug("  tegra_get_family: chip_id = %x\n", chip_id);
+       if (chip_id == 0x30)
+               return TEGRA_FAMILY_T3x;
+       else
+               return TEGRA_FAMILY_T2x;
+}
+
+int get_num_cpus(void)
+{
+       return get_family() == TEGRA_FAMILY_T3x ? 4 : 2;
+}
+
+/* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */
+int 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);
+}
+
+static void adjust_pllp_out_freqs(void)
+{
+       struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_PERIPH];
+       u32 reg;
+
+       /* Set T30 PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */
+       reg = readl(&pll->pll_out);     /* OUTA, contains OUT2 / OUT1 */
+       reg |= (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO) | PLLP_OUT2_OVR
+               | (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO) | PLLP_OUT1_OVR;
+       writel(reg, &pll->pll_out);
+
+       reg = readl(&pll->pll_out_b);   /* OUTB, contains OUT4 / OUT3 */
+       reg |= (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO) | PLLP_OUT4_OVR
+               | (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO) | PLLP_OUT3_OVR;
+       writel(reg, &pll->pll_out_b);
+}
+
+static int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
+               u32 divp, u32 cpcon)
+{
+       u32 reg;
+
+       /* If PLLX is already enabled, just return */
+       if (readl(&pll->pll_base) & PLL_ENABLE_MASK) {
+               debug("pllx_set_rate: PLLX already enabled, returning\n");
+               return 0;
+       }
+
+       debug(" pllx_set_rate entry\n");
+
+       /* 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));
+       writel(reg, &pll->pll_base);
+
+       /* Set cpcon to PLLX_MISC */
+       reg = (cpcon << PLL_CPCON_SHIFT);
+
+       /* Set dccon to PLLX_MISC if freq > 600MHz */
+       if (divn > 600)
+               reg |= (1 << PLL_DCCON_SHIFT);
+       writel(reg, &pll->pll_misc);
+
+       /* Enable PLLX */
+       reg = readl(&pll->pll_base);
+       reg |= PLL_ENABLE_MASK;
+
+       /* Disable BYPASS */
+       reg &= ~PLL_BYPASS_MASK;
+       writel(reg, &pll->pll_base);
+
+       /* Set lock_enable to PLLX_MISC */
+       reg = readl(&pll->pll_misc);
+       reg |= PLL_LOCK_ENABLE_MASK;
+       writel(reg, &pll->pll_misc);
+
+       return 0;
+}
+
+void init_pllx(int slow)
+{
+       struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       struct clk_pll_simple *pll = &clkrst->crc_pll_simple[SIMPLE_PLLX];
+       int chip_type;
+       enum clock_osc_freq osc;
+       struct clk_pll_table *sel;
+
+       debug("init_pllx entry\n");
+
+       /* get chip type. If unknown, assign to T30 */
+       chip_type = tegra_get_chip_type();
+       if (chip_type == TEGRA_SOC_UNKNOWN)
+               chip_type = TEGRA_SOC_T30;
+       debug(" init_pllx: chip_type = %d\n", chip_type);
+
+       /* get osc freq */
+       osc = clock_get_osc_freq();
+       debug("  init_pllx: osc = %d\n", osc);
+
+       /* set pllx */
+       sel = &tegra_pll_x_table[chip_type][osc];
+       pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon);
+
+       /* once we are out of slow mode, set up the T30 PLLs also */
+       if (!slow && chip_type == TEGRA_SOC_T30_408MHZ) {
+               debug("  init_pllx: adjusting PLLP out freqs\n");
+               adjust_pllp_out_freqs();
+       }
+}
+
+static void enable_cpu_clock(int enable)
+{
+       struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       u32 clk;
+
+       debug("enable_cpu_clock entry, enable = %d\n", enable);
+       /*
+        * 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.
+        */
+
+       if (enable) {
+               /* Initialize PLLX in 'slow' mode */
+               init_pllx(1);
+
+               /* Wait until all clocks are stable */
+               udelay(PLL_STABILIZATION_DELAY);
+
+               writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol);
+               writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div);
+       }
+
+       /*
+        * Read the register containing the individual CPU clock enables and
+        * always stop the clock to CPUs 1, 2 & 3.
+        */
+       clk = readl(&clkrst->crc_clk_cpu_cmplx);
+       clk |= 1 << CPU1_CLK_STP_SHIFT;
+       clk |= 1 << CPU2_CLK_STP_SHIFT;
+       clk |= 1 << CPU3_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);
+
+       clock_enable(PERIPH_ID_CPU);
+       debug("enable_cpu_clock entry, enabled CPU clock\n");
+}
+
+static int is_cpu_powered(void)
+{
+       struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+
+       debug("is_cpu_powered entry\n");
+       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;
+       u32 reg;
+
+       debug("remove_cpu_io_clamps entry\n");
+       /* 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(IO_STABILIZATION_DELAY);
+}
+
+static void powerup_cpu(void)
+{
+       struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+       u32 reg;
+       int timeout = IO_STABILIZATION_DELAY;
+
+       debug("powerup_cpu entry\n");
+       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()) {
+                       if (timeout-- == 0)
+                               printf("CPU failed to power up!\n");
+                       else
+                               udelay(10);
+               }
+
+               /*
+                * 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();
+       }
+}
+
+void tegra_i2c_ll_write_addr(uint addr, uint config)
+{
+       struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+
+       writel(addr, &reg->cmd_addr0);
+       writel(config, &reg->cnfg);
+}
+
+void tegra_i2c_ll_write_data(uint data, uint config)
+{
+       struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE;
+
+       writel(data, &reg->cmd_data1);
+       writel(config, &reg->cnfg);
+}
+
+static void enable_cpu_power_rail(void)
+{
+       struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
+       u32 reg;
+
+       debug("enable_cpu_power_rail entry\n");
+       reg = readl(&pmc->pmc_cntrl);
+       reg |= CPUPWRREQ_OE;
+       writel(reg, &pmc->pmc_cntrl);
+
+       /*
+        * Pulse PWRREQ via I2C.  We need to find out what this is
+        * doing, tidy up the code and maybe find a better place for it.
+        */
+       tegra_i2c_ll_write_addr(0x005a, 0x0002);
+       tegra_i2c_ll_write_data(0x2328, 0x0a02);
+       udelay(1000);
+       tegra_i2c_ll_write_data(0x0127, 0x0a02);
+       udelay(10 * 1000);
+
+       /*
+        * The TI PMU65861C needs a 3.75ms delay between enabling
+        * the power rail and enabling the CPU clock.  This delay
+        * between SM1EN and SM1 is for switching time + the ramp
+        * up of the voltage to the CPU (VDD_CPU from PMU). We use 0xf00 as
+        * is is ARM-friendly (can fit in a single ARMv4T mov immmediate
+        * instruction).
+        */
+       udelay(3840);
+}
+
+static void reset_A9_cpu(int reset)
+{
+       /*
+       * 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.
+       */
+       int mask = crc_rst_cpu | crc_rst_de | crc_rst_debug;
+       int num_cpus = get_num_cpus();
+       int cpu;
+
+       debug("reset_a9_cpu entry\n");
+       /* Hold CPUs 1 onwards in reset, and CPU 0 if asked */
+       for (cpu = 1; cpu < num_cpus; cpu++)
+               reset_cmplx_set_enable(cpu, mask, 1);
+       reset_cmplx_set_enable(0, mask, reset);
+
+       /* Enable/Disable master CPU reset */
+       reset_set_enable(PERIPH_ID_CPU, reset);
+}
+
+/**
+ * The T30 requires some special clock initialization, including setting up
+ * the dvc i2c, turning on mselect and selecting the G CPU cluster
+ */
+void t30_init_clocks(void)
+{
+       /*
+       * Sadly our clock functions don't support the V and W clocks of T30
+       * yet, as well as a few other functions, so use low-level register
+       * access for now. This eventual removal of low-level code from
+       * ap20.c is the same process we went through for T20.
+       */
+       struct clk_rst_ctlr *clkrst =
+                       (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+       struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+       u32 val;
+
+       debug("t30_init_clocks entry\n");
+       /* Set active CPU cluster to G */
+       clrbits_le32(flow->cluster_control, 1 << 0);
+
+       /*
+        * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run
+        * at 108 MHz. This is glitch free as only the source is changed, no
+        * special precaution needed.
+        */
+       val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
+               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
+               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
+               (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
+               (SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
+       writel(val, &clkrst->crc_sclk_brst_pol);
+
+       writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
+
+       val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) |
+               (1 << CLK_SYS_RATE_AHB_RATE_SHIFT) |
+               (0 << CLK_SYS_RATE_PCLK_DISABLE_SHIFT) |
+               (0 << CLK_SYS_RATE_APB_RATE_SHIFT);
+       writel(val, &clkrst->crc_clk_sys_rate);
+
+       /* Put i2c, mselect in reset and enable clocks */
+       reset_set_enable(PERIPH_ID_DVC_I2C, 1);
+       clock_set_enable(PERIPH_ID_DVC_I2C, 1);
+       reset_set_enable(PERIPH_ID_MSELECT, 1);
+       clock_set_enable(PERIPH_ID_MSELECT, 1);
+
+       /* Switch MSELECT clock to PLLP (00) */
+       clock_ll_set_source(PERIPH_ID_MSELECT, 0);
+
+       /*
+        * Our high-level clock routines are not available prior to
+        * relocation. We use the low-level functions which require a
+        * hard-coded divisor. Use CLK_M with divide by (n + 1 = 17)
+        */
+       clock_ll_set_source_divisor(PERIPH_ID_DVC_I2C, 3, 16);
+
+       /*
+        * Give clocks time to stabilize, then take i2c and mselect out of
+        * reset
+        */
+       udelay(1000);
+       reset_set_enable(PERIPH_ID_DVC_I2C, 0);
+       reset_set_enable(PERIPH_ID_MSELECT, 0);
+}
+
+static void clock_enable_coresight(int enable)
+{
+       u32 rst, src;
+
+       debug("clock_enable_coresight entry\n");
+       clock_set_enable(PERIPH_ID_CORESIGHT, enable);
+       reset_set_enable(PERIPH_ID_CORESIGHT, !enable);
+
+       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)
+                *
+                * Clock divider request for 204MHz would setup CSITE clock as
+                * 144MHz for PLLP base 216MHz and 204MHz for PLLP base 408MHz
+                */
+               if (tegra_get_chip_type() == TEGRA_SOC_T30_408MHZ)
+                       src = CLK_DIVIDER(NVBL_PLLP_KHZ, 204000);
+               else
+                       src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000);
+               clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src);
+
+               /* Unlock the CPU CoreSight interfaces */
+               rst = CORESIGHT_UNLOCK;
+               writel(rst, CSITE_CPU_DBG0_LAR);
+               writel(rst, CSITE_CPU_DBG1_LAR);
+               writel(rst, CSITE_CPU_DBG2_LAR);
+               writel(rst, CSITE_CPU_DBG3_LAR);
+       }
+}
+
+static void set_cpu_running(int run)
+{
+       struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+
+       debug("set_cpu_running entry, run = %d\n", run);
+       writel(run ? FLOW_MODE_NONE : FLOW_MODE_STOP, &flow->halt_cpu_events);
+}
+
+void start_cpu(u32 reset_vector)
+{
+       debug("start_cpu entry, reset_vector = %x\n", reset_vector);
+       t30_init_clocks();
+
+       /* Enable VDD_CPU */
+       enable_cpu_power_rail();
+
+       set_cpu_running(0);
+
+       /* Hold the CPUs in reset */
+       reset_A9_cpu(1);
+
+       /* Disable the CPU clock */
+       enable_cpu_clock(0);
+
+       /* Enable CoreSight */
+       clock_enable_coresight(1);
+
+       /*
+        * Set the entry point for CPU execution from reset,
+        *  if it's a non-zero value.
+        */
+       if (reset_vector)
+               writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR);
+
+       /* Enable the CPU clock */
+       enable_cpu_clock(1);
+
+       /* If the CPU doesn't already have power, power it up */
+       powerup_cpu();
+
+       /* Take the CPU out of reset */
+       reset_A9_cpu(0);
+
+       set_cpu_running(1);
+}
+
+
+void halt_avp(void)
+{
+       debug("halt_avp entry\n");
+       for (;;) {
+               writel((HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \
+                       | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29)),
+                       FLOW_CTLR_HALT_COP_EVENTS);
+       }
+}
diff --git a/arch/arm/cpu/arm720t/tegra30/cpu.h 
b/arch/arm/cpu/arm720t/tegra30/cpu.h
new file mode 100644
index 0000000..a5c0474
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/cpu.h
@@ -0,0 +1,65 @@
+/*
+ * (C) Copyright 2010-2012
+ * 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>
+
+/* Stabilization delays, in usec */
+#define PLL_STABILIZATION_DELAY (300)
+#define IO_STABILIZATION_DELAY (1000)
+
+#define NVBL_PLLP_KHZ  (216000)
+
+#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
+
+#define CORESIGHT_UNLOCK       0xC5ACCE55;
+
+#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 CSITE_CPU_DBG2_LAR             (NV_PA_CSITE_BASE + 0x14FB0)
+#define CSITE_CPU_DBG3_LAR             (NV_PA_CSITE_BASE + 0x16FB0)
+
+#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)
+
+#define GP_HIDREV              0x804
+#define FLOW_MODE_NONE         0
+
+#define SIMPLE_PLLX     (CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE)
+
+void start_cpu(u32 reset_vector);
+void halt_avp(void)  __attribute__ ((noreturn));
diff --git a/arch/arm/cpu/arm720t/tegra30/spl.c 
b/arch/arm/cpu/arm720t/tegra30/spl.c
new file mode 100644
index 0000000..c391746
--- /dev/null
+++ b/arch/arm/cpu/arm720t/tegra30/spl.c
@@ -0,0 +1,132 @@
+/*
+ * (C) Copyright 2012
+ * NVIDIA Inc, <www.nvidia.com>
+ *
+ * Allen Martin <amar...@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 <common.h>
+#include <asm/u-boot.h>
+#include <asm/utils.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/clock.h>
+#include <nand.h>
+#include <mmc.h>
+#include <fat.h>
+#include <version.h>
+#include <i2c.h>
+#include <image.h>
+#include <malloc.h>
+#include <linux/compiler.h>
+#include "board.h"
+#include "cpu.h"
+
+#include <asm/io.h>
+#include <asm/arch/tegra30.h>
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/pmc.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/scu.h>
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Define global data structure pointer to it*/
+static gd_t gdata __attribute__ ((section(".data")));
+static bd_t bdata __attribute__ ((section(".data")));
+
+inline void hang(void)
+{
+       puts("### ERROR ### Please RESET the board ###\n");
+       for (;;)
+               ;
+}
+
+void board_init_f(ulong dummy)
+{
+       board_init_uart_f();
+
+       /* Initialize periph GPIOs */
+#ifdef CONFIG_SPI_UART_SWITCH
+       gpio_early_init_uart();
+#else
+       gpio_config_uart();
+#endif
+
+       /*
+        * We call relocate_code() with relocation target same as the
+        * CONFIG_SYS_SPL_TEXT_BASE. This will result in relocation getting
+        * skipped. Instead, only .bss initialization will happen. That's
+        * all we need
+        */
+       debug(">>board_init_f()\n");
+       relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);
+}
+
+/* This requires UART clocks to be enabled */
+static void preloader_console_init(void)
+{
+       const char *u_boot_rev = U_BOOT_VERSION;
+
+       gd = &gdata;
+       gd->bd = &bdata;
+       gd->flags |= GD_FLG_RELOC;
+       gd->baudrate = CONFIG_BAUDRATE;
+
+       serial_init();          /* serial communications setup */
+
+       gd->have_console = 1;
+
+       /* Avoid a second "U-Boot" coming from this string */
+       u_boot_rev = &u_boot_rev[7];
+
+       printf("\nU-Boot SPL %s (%s - %s)\n", u_boot_rev, U_BOOT_DATE,
+               U_BOOT_TIME);
+}
+
+void board_init_r(gd_t *id, ulong dummy)
+{
+       struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+
+       /* enable JTAG */
+       writel(0xC0, &pmt->pmt_cfg_ctl);
+
+       debug(">>spl:board_init_r()\n");
+
+       mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
+                       CONFIG_SYS_SPL_MALLOC_SIZE);
+
+#ifdef CONFIG_SPL_BOARD_INIT
+       spl_board_init();
+#endif
+
+       clock_early_init();
+       preloader_console_init();
+
+       start_cpu((u32)CONFIG_SYS_TEXT_BASE);
+       halt_avp();
+       /* not reached */
+}
+
+int board_usb_init(const void *blob)
+{
+       return 0;
+}
-- 
1.7.0.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to