summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2011-10-03 15:24:16 -0700
committerSimon Glass <sjg@chromium.org>2011-10-20 11:26:11 -0700
commit88c96779f8429c9d2e934a33407e4d3d937b5002 (patch)
treed9ed66c2752461d71db757c02754c76537b0181d /arch
parentb166ce8bdde0a2b7c506a93d4d60f92e932c64d4 (diff)
tegra3: Add T30 support
This adds support for T30 init to ap20.c, and modifies the board file to cope with it also. The only thing missing at this point is the pinmux setup. BUG=chromium-os:21033 TEST=build and boot on Seaboard Change-Id: I3e75245c1fdb99bc15eadcf60b173e6f0d9bb56c Reviewed-on: http://gerrit.chromium.org/gerrit/8704 Reviewed-by: Tom Warren <twarren@nvidia.com> Reviewed-by: Jimmy Zhang <jimmzhang@nvidia.com> Tested-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/cpu/armv7/tegra-common/ap20.c124
1 files changed, 117 insertions, 7 deletions
diff --git a/arch/arm/cpu/armv7/tegra-common/ap20.c b/arch/arm/cpu/armv7/tegra-common/ap20.c
index 3a7e402b0c..a3e7858e63 100644
--- a/arch/arm/cpu/armv7/tegra-common/ap20.c
+++ b/arch/arm/cpu/armv7/tegra-common/ap20.c
@@ -21,15 +21,17 @@
* MA 02111-1307 USA
*/
+#include <common.h>
#include <asm/io.h>
#include <asm/arch/tegra.h>
#include <asm/arch-tegra/bitfield.h>
#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch-tegra/flow.h>
#include <asm/arch/clock.h>
#include <asm/arch-tegra/pmc.h>
#include <asm/arch/pinmux.h>
#include <asm/arch-tegra/scu.h>
-#include <common.h>
+#include <asm/arch-tegra/i2c.h>
#include <asm/arch-tegra/warmboot.h>
#include <asm/arch-tegra/ap20.h>
#include "../../../../../board/nvidia/common/board.h"
@@ -58,10 +60,24 @@ static struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_COUNT]
/* T25: 1.2 GHz */
{{ 923, 10, 0, 12},
- { 750, 12, 0, 8},
+ { 750, 12, 0, 8},
{ 600, 6, 0, 12},
{ 600, 13, 0, 12},
},
+
+ /* T30: 1.5 GHz with slower PLLP */
+ {{ 0xd8, 13, 1, 8},
+ { 0xb4, 22, 1, 4},
+ { 0x1b0, 12, 1, 8},
+ { 0xd8, 26, 1, 8},
+ },
+
+ /* T30: 1.5 GHz with 408MHz PLLP */
+ {{ 0x198, 13, 0, 8},
+ { 0x154, 22, 0, 4},
+ { 0x198, 12, 0, 8},
+ { 0x198, 26, 0, 8},
+ },
};
enum tegra_family_t {
@@ -236,7 +252,7 @@ static void powerup_cpu(void)
}
}
-static void enable_cpu_power_rail(void)
+static void enable_cpu_power_rail(enum tegra_family_t family)
{
struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE;
u32 reg;
@@ -245,6 +261,19 @@ static void enable_cpu_power_rail(void)
reg |= CPUPWRREQ_OE;
writel(reg, &pmc->pmc_cntrl);
+ if (family == TEGRA_FAMILY_T3x) {
+ /*
+ * TODO(sjg):
+ * Fow now we do this here. We need to find out what this is
+ * doing, tidy up the code and 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
@@ -278,6 +307,72 @@ static void reset_A9_cpu(int 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 removable 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;
+
+ /* Set active CPU cluster to G */
+ clrbits_le32(flow->control, 1 << 0);
+
+ /*
+ * Switch system clock to PLLP_out 4 (108 MHz) 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);
+ setbits_le32(&clkrst->crc_clk_out_enb_v, 1 << 3);
+
+ /* Switch MSELECT clock to PLLP */
+ val = readl(&clkrst->crc_clk_source_mselect);
+ val &= ~MSELECT_CLK_M_MASK;
+ writel(val, &clkrst->crc_clk_source_mselect);
+
+ /*
+ * 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);
+ clrbits_le32(&clkrst->crc_rst_devices_v, 1 << 3);
+}
+
static void clock_enable_coresight(int enable)
{
u32 rst, src;
@@ -302,10 +397,23 @@ static void clock_enable_coresight(int enable)
}
}
-void start_cpu(u32 reset_vector)
+static void set_cpu_running(int run)
{
+ struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE;
+
+ writel(run ? FLOW_MODE_NONE : FLOW_MODE_STOP, &flow->halt_cpu_events);
+}
+
+void start_cpu(enum tegra_family_t family, u32 reset_vector)
+{
+ if (family == TEGRA_FAMILY_T3x)
+ t30_init_clocks();
+
/* Enable VDD_CPU */
- enable_cpu_power_rail();
+ enable_cpu_power_rail(family);
+
+ if (family == TEGRA_FAMILY_T3x)
+ set_cpu_running(0);
/* Hold the CPUs in reset */
reset_A9_cpu(1);
@@ -331,8 +439,10 @@ void start_cpu(u32 reset_vector)
/* Take the CPU out of reset */
reset_A9_cpu(0);
-}
+ if (family == TEGRA_FAMILY_T3x)
+ set_cpu_running(1);
+}
void halt_avp(void)
{
@@ -397,7 +507,7 @@ void tegra_start(void)
asm volatile("ldr sp, =%c0\n"
: : "i"(AVP_EARLY_BOOT_STACK_LIMIT));
- start_cpu((u32)_start);
+ start_cpu(ap20_get_family(), (u32)_start);
halt_avp();
/* not reached */
}