Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 1 | /* |
| 2 | * (C) Copyright 2010-2011 |
| 3 | * NVIDIA Corporation <www.nvidia.com> |
| 4 | * |
| 5 | * See file CREDITS for list of people who contributed to this |
| 6 | * project. |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or |
| 9 | * modify it under the terms of the GNU General Public License as |
| 10 | * published by the Free Software Foundation; either version 2 of |
| 11 | * the License, or (at your option) any later version. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program; if not, write to the Free Software |
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 21 | * MA 02111-1307 USA |
| 22 | */ |
| 23 | |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 24 | #include <asm/io.h> |
| 25 | #include <asm/arch/tegra2.h> |
Simon Glass | 84a8dcf | 2012-04-02 13:18:46 +0000 | [diff] [blame] | 26 | #include <asm/arch/ap20.h> |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 27 | #include <asm/arch/clk_rst.h> |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 28 | #include <asm/arch/clock.h> |
Simon Glass | 1fed82a | 2012-04-02 13:18:50 +0000 | [diff] [blame] | 29 | #include <asm/arch/fuse.h> |
| 30 | #include <asm/arch/gp_padctrl.h> |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 31 | #include <asm/arch/pmc.h> |
| 32 | #include <asm/arch/pinmux.h> |
| 33 | #include <asm/arch/scu.h> |
Yen Lin | cb3c0d1 | 2012-04-02 13:18:56 +0000 | [diff] [blame] | 34 | #include <asm/arch/warmboot.h> |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 35 | #include <common.h> |
| 36 | |
Simon Glass | 1fed82a | 2012-04-02 13:18:50 +0000 | [diff] [blame] | 37 | int tegra_get_chip_type(void) |
| 38 | { |
| 39 | struct apb_misc_gp_ctlr *gp; |
| 40 | struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE; |
| 41 | uint tegra_sku_id, rev; |
| 42 | |
| 43 | /* |
| 44 | * This is undocumented, Chip ID is bits 15:8 of the register |
| 45 | * APB_MISC + 0x804, and has value 0x20 for Tegra20, 0x30 for |
| 46 | * Tegra30 |
| 47 | */ |
| 48 | gp = (struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE; |
| 49 | rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT; |
| 50 | |
| 51 | tegra_sku_id = readl(&fuse->sku_info) & 0xff; |
| 52 | |
| 53 | switch (rev) { |
| 54 | case CHIPID_TEGRA2: |
| 55 | switch (tegra_sku_id) { |
| 56 | case SKU_ID_T20: |
| 57 | return TEGRA_SOC_T20; |
| 58 | case SKU_ID_T25SE: |
| 59 | case SKU_ID_AP25: |
| 60 | case SKU_ID_T25: |
| 61 | case SKU_ID_AP25E: |
| 62 | case SKU_ID_T25E: |
| 63 | return TEGRA_SOC_T25; |
| 64 | } |
| 65 | break; |
| 66 | } |
| 67 | /* unknown sku id */ |
| 68 | return TEGRA_SOC_UNKNOWN; |
| 69 | } |
| 70 | |
Simon Glass | ec8dab4 | 2011-11-05 03:56:50 +0000 | [diff] [blame] | 71 | /* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */ |
| 72 | static int ap20_cpu_is_cortexa9(void) |
| 73 | { |
| 74 | u32 id = readb(NV_PA_PG_UP_BASE + PG_UP_TAG_0); |
| 75 | return id == (PG_UP_TAG_0_PID_CPU & 0xff); |
| 76 | } |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 77 | |
Tom Warren | 30e80f6 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 78 | void init_pllx(void) |
| 79 | { |
Simon Glass | 563b46f | 2012-04-19 08:04:39 +0000 | [diff] [blame] | 80 | struct clk_rst_ctlr *clkrst = |
| 81 | (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; |
| 82 | struct clk_pll_simple *pll = |
| 83 | &clkrst->crc_pll_simple[CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE]; |
Tom Warren | 30e80f6 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 84 | u32 reg; |
| 85 | |
| 86 | /* If PLLX is already enabled, just return */ |
Simon Glass | e2deddd | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 87 | if (readl(&pll->pll_base) & PLL_ENABLE_MASK) |
Tom Warren | 30e80f6 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 88 | return; |
| 89 | |
| 90 | /* Set PLLX_MISC */ |
Simon Glass | e2deddd | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 91 | writel(1 << PLL_CPCON_SHIFT, &pll->pll_misc); |
Tom Warren | 30e80f6 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 92 | |
| 93 | /* Use 12MHz clock here */ |
Simon Glass | e2deddd | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 94 | reg = PLL_BYPASS_MASK | (12 << PLL_DIVM_SHIFT); |
| 95 | reg |= 1000 << PLL_DIVN_SHIFT; |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 96 | writel(reg, &pll->pll_base); |
Tom Warren | 30e80f6 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 97 | |
Simon Glass | e2deddd | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 98 | reg |= PLL_ENABLE_MASK; |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 99 | writel(reg, &pll->pll_base); |
Tom Warren | 30e80f6 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 100 | |
Simon Glass | e2deddd | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 101 | reg &= ~PLL_BYPASS_MASK; |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 102 | writel(reg, &pll->pll_base); |
Tom Warren | 30e80f6 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 103 | } |
| 104 | |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 105 | static void enable_cpu_clock(int enable) |
| 106 | { |
| 107 | struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 108 | u32 clk; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 109 | |
| 110 | /* |
| 111 | * NOTE: |
| 112 | * Regardless of whether the request is to enable or disable the CPU |
| 113 | * clock, every processor in the CPU complex except the master (CPU 0) |
| 114 | * will have it's clock stopped because the AVP only talks to the |
| 115 | * master. The AVP does not know (nor does it need to know) that there |
| 116 | * are multiple processors in the CPU complex. |
| 117 | */ |
| 118 | |
| 119 | if (enable) { |
Tom Warren | 30e80f6 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 120 | /* Initialize PLLX */ |
| 121 | init_pllx(); |
| 122 | |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 123 | /* Wait until all clocks are stable */ |
| 124 | udelay(PLL_STABILIZATION_DELAY); |
| 125 | |
| 126 | writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol); |
| 127 | writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); |
| 128 | } |
| 129 | |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 130 | /* |
| 131 | * Read the register containing the individual CPU clock enables and |
| 132 | * always stop the clock to CPU 1. |
| 133 | */ |
| 134 | clk = readl(&clkrst->crc_clk_cpu_cmplx); |
Simon Glass | e2deddd | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 135 | clk |= 1 << CPU1_CLK_STP_SHIFT; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 136 | |
Simon Glass | e2deddd | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 137 | /* Stop/Unstop the CPU clock */ |
| 138 | clk &= ~CPU0_CLK_STP_MASK; |
| 139 | clk |= !enable << CPU0_CLK_STP_SHIFT; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 140 | writel(clk, &clkrst->crc_clk_cpu_cmplx); |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 141 | |
| 142 | clock_enable(PERIPH_ID_CPU); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | static int is_cpu_powered(void) |
| 146 | { |
Simon Glass | cad1a27 | 2012-02-03 15:13:52 +0000 | [diff] [blame] | 147 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 148 | |
| 149 | return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0; |
| 150 | } |
| 151 | |
| 152 | static void remove_cpu_io_clamps(void) |
| 153 | { |
Simon Glass | cad1a27 | 2012-02-03 15:13:52 +0000 | [diff] [blame] | 154 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 155 | u32 reg; |
| 156 | |
| 157 | /* Remove the clamps on the CPU I/O signals */ |
| 158 | reg = readl(&pmc->pmc_remove_clamping); |
| 159 | reg |= CPU_CLMP; |
| 160 | writel(reg, &pmc->pmc_remove_clamping); |
| 161 | |
| 162 | /* Give I/O signals time to stabilize */ |
| 163 | udelay(IO_STABILIZATION_DELAY); |
| 164 | } |
| 165 | |
| 166 | static void powerup_cpu(void) |
| 167 | { |
Simon Glass | cad1a27 | 2012-02-03 15:13:52 +0000 | [diff] [blame] | 168 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 169 | u32 reg; |
| 170 | int timeout = IO_STABILIZATION_DELAY; |
| 171 | |
| 172 | if (!is_cpu_powered()) { |
| 173 | /* Toggle the CPU power state (OFF -> ON) */ |
| 174 | reg = readl(&pmc->pmc_pwrgate_toggle); |
| 175 | reg &= PARTID_CP; |
| 176 | reg |= START_CP; |
| 177 | writel(reg, &pmc->pmc_pwrgate_toggle); |
| 178 | |
| 179 | /* Wait for the power to come up */ |
| 180 | while (!is_cpu_powered()) { |
| 181 | if (timeout-- == 0) |
| 182 | printf("CPU failed to power up!\n"); |
| 183 | else |
| 184 | udelay(10); |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | * Remove the I/O clamps from CPU power partition. |
| 189 | * Recommended only on a Warm boot, if the CPU partition gets |
| 190 | * power gated. Shouldn't cause any harm when called after a |
| 191 | * cold boot according to HW, probably just redundant. |
| 192 | */ |
| 193 | remove_cpu_io_clamps(); |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | static void enable_cpu_power_rail(void) |
| 198 | { |
Simon Glass | cad1a27 | 2012-02-03 15:13:52 +0000 | [diff] [blame] | 199 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 200 | u32 reg; |
| 201 | |
| 202 | reg = readl(&pmc->pmc_cntrl); |
| 203 | reg |= CPUPWRREQ_OE; |
| 204 | writel(reg, &pmc->pmc_cntrl); |
| 205 | |
| 206 | /* |
| 207 | * The TI PMU65861C needs a 3.75ms delay between enabling |
| 208 | * the power rail and enabling the CPU clock. This delay |
| 209 | * between SM1EN and SM1 is for switching time + the ramp |
| 210 | * up of the voltage to the CPU (VDD_CPU from PMU). |
| 211 | */ |
| 212 | udelay(3750); |
| 213 | } |
| 214 | |
| 215 | static void reset_A9_cpu(int reset) |
| 216 | { |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 217 | /* |
| 218 | * NOTE: Regardless of whether the request is to hold the CPU in reset |
| 219 | * or take it out of reset, every processor in the CPU complex |
| 220 | * except the master (CPU 0) will be held in reset because the |
| 221 | * AVP only talks to the master. The AVP does not know that there |
| 222 | * are multiple processors in the CPU complex. |
| 223 | */ |
| 224 | |
Simon Glass | e2deddd | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 225 | /* Hold CPU 1 in reset, and CPU 0 if asked */ |
| 226 | reset_cmplx_set_enable(1, crc_rst_cpu | crc_rst_de | crc_rst_debug, 1); |
| 227 | reset_cmplx_set_enable(0, crc_rst_cpu | crc_rst_de | crc_rst_debug, |
| 228 | reset); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 229 | |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 230 | /* Enable/Disable master CPU reset */ |
| 231 | reset_set_enable(PERIPH_ID_CPU, reset); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | static void clock_enable_coresight(int enable) |
| 235 | { |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 236 | u32 rst, src; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 237 | |
Simon Glass | 16134fd | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 238 | clock_set_enable(PERIPH_ID_CORESIGHT, enable); |
| 239 | reset_set_enable(PERIPH_ID_CORESIGHT, !enable); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 240 | |
| 241 | if (enable) { |
| 242 | /* |
| 243 | * Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by |
| 244 | * 1.5, giving an effective frequency of 144MHz. |
| 245 | * Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor |
| 246 | * (bits 7:0), so 00000001b == 1.5 (n+1 + .5) |
| 247 | */ |
| 248 | src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000); |
Simon Glass | c2ea5e4 | 2011-09-21 12:40:04 +0000 | [diff] [blame] | 249 | clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 250 | |
| 251 | /* Unlock the CPU CoreSight interfaces */ |
| 252 | rst = 0xC5ACCE55; |
| 253 | writel(rst, CSITE_CPU_DBG0_LAR); |
| 254 | writel(rst, CSITE_CPU_DBG1_LAR); |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | void start_cpu(u32 reset_vector) |
| 259 | { |
| 260 | /* Enable VDD_CPU */ |
| 261 | enable_cpu_power_rail(); |
| 262 | |
| 263 | /* Hold the CPUs in reset */ |
| 264 | reset_A9_cpu(1); |
| 265 | |
| 266 | /* Disable the CPU clock */ |
| 267 | enable_cpu_clock(0); |
| 268 | |
| 269 | /* Enable CoreSight */ |
| 270 | clock_enable_coresight(1); |
| 271 | |
| 272 | /* |
| 273 | * Set the entry point for CPU execution from reset, |
| 274 | * if it's a non-zero value. |
| 275 | */ |
| 276 | if (reset_vector) |
| 277 | writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); |
| 278 | |
| 279 | /* Enable the CPU clock */ |
| 280 | enable_cpu_clock(1); |
| 281 | |
| 282 | /* If the CPU doesn't already have power, power it up */ |
| 283 | powerup_cpu(); |
| 284 | |
| 285 | /* Take the CPU out of reset */ |
| 286 | reset_A9_cpu(0); |
| 287 | } |
| 288 | |
| 289 | |
| 290 | void halt_avp(void) |
| 291 | { |
| 292 | for (;;) { |
| 293 | writel((HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \ |
| 294 | | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29)), |
| 295 | FLOW_CTLR_HALT_COP_EVENTS); |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | void enable_scu(void) |
| 300 | { |
| 301 | struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE; |
| 302 | u32 reg; |
| 303 | |
| 304 | /* If SCU already setup/enabled, return */ |
| 305 | if (readl(&scu->scu_ctrl) & SCU_CTRL_ENABLE) |
| 306 | return; |
| 307 | |
| 308 | /* Invalidate all ways for all processors */ |
| 309 | writel(0xFFFF, &scu->scu_inv_all); |
| 310 | |
| 311 | /* Enable SCU - bit 0 */ |
| 312 | reg = readl(&scu->scu_ctrl); |
| 313 | reg |= SCU_CTRL_ENABLE; |
| 314 | writel(reg, &scu->scu_ctrl); |
| 315 | } |
| 316 | |
Tom Warren | 7ee52b0 | 2012-05-30 14:06:09 -0700 | [diff] [blame] | 317 | static u32 get_odmdata(void) |
| 318 | { |
| 319 | /* |
| 320 | * ODMDATA is stored in the BCT in IRAM by the BootROM. |
| 321 | * The BCT start and size are stored in the BIT in IRAM. |
| 322 | * Read the data @ bct_start + (bct_size - 12). This works |
| 323 | * on T20 and T30 BCTs, which are locked down. If this changes |
| 324 | * in new chips (T114, etc.), we can revisit this algorithm. |
| 325 | */ |
| 326 | |
| 327 | u32 bct_start, odmdata; |
| 328 | |
| 329 | bct_start = readl(AP20_BASE_PA_SRAM + NVBOOTINFOTABLE_BCTPTR); |
| 330 | odmdata = readl(bct_start + BCT_ODMDATA_OFFSET); |
| 331 | |
| 332 | return odmdata; |
| 333 | } |
| 334 | |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 335 | void init_pmc_scratch(void) |
| 336 | { |
Simon Glass | cad1a27 | 2012-02-03 15:13:52 +0000 | [diff] [blame] | 337 | struct pmc_ctlr *const pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE; |
Tom Warren | 7ee52b0 | 2012-05-30 14:06:09 -0700 | [diff] [blame] | 338 | u32 odmdata; |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 339 | int i; |
| 340 | |
| 341 | /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */ |
| 342 | for (i = 0; i < 23; i++) |
| 343 | writel(0, &pmc->pmc_scratch1+i); |
| 344 | |
| 345 | /* ODMDATA is for kernel use to determine RAM size, LP config, etc. */ |
Tom Warren | 7ee52b0 | 2012-05-30 14:06:09 -0700 | [diff] [blame] | 346 | odmdata = get_odmdata(); |
| 347 | writel(odmdata, &pmc->pmc_scratch20); |
Yen Lin | cb3c0d1 | 2012-04-02 13:18:56 +0000 | [diff] [blame] | 348 | |
| 349 | #ifdef CONFIG_TEGRA2_LP0 |
| 350 | /* save Sdram params to PMC 2, 4, and 24 for WB0 */ |
| 351 | warmboot_save_sdram_params(); |
| 352 | #endif |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 353 | } |
| 354 | |
Simon Glass | ec8dab4 | 2011-11-05 03:56:50 +0000 | [diff] [blame] | 355 | void tegra2_start(void) |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 356 | { |
| 357 | struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; |
| 358 | |
Simon Glass | ec8dab4 | 2011-11-05 03:56:50 +0000 | [diff] [blame] | 359 | /* If we are the AVP, start up the first Cortex-A9 */ |
| 360 | if (!ap20_cpu_is_cortexa9()) { |
| 361 | /* enable JTAG */ |
| 362 | writel(0xC0, &pmt->pmt_cfg_ctl); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 363 | |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 364 | /* |
Tom Warren | 8b75b8f | 2012-02-17 06:01:21 +0000 | [diff] [blame] | 365 | * If we are ARM7 - give it a different stack. We are about to |
| 366 | * start up the A9 which will want to use this one. |
| 367 | */ |
| 368 | asm volatile("mov sp, %0\n" |
| 369 | : : "r"(AVP_EARLY_BOOT_STACK_LIMIT)); |
Simon Glass | ec8dab4 | 2011-11-05 03:56:50 +0000 | [diff] [blame] | 370 | |
| 371 | start_cpu((u32)_start); |
| 372 | halt_avp(); |
| 373 | /* not reached */ |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 374 | } |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 375 | |
Simon Glass | ec8dab4 | 2011-11-05 03:56:50 +0000 | [diff] [blame] | 376 | /* Init PMC scratch memory */ |
| 377 | init_pmc_scratch(); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 378 | |
Simon Glass | ec8dab4 | 2011-11-05 03:56:50 +0000 | [diff] [blame] | 379 | enable_scu(); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 380 | |
Simon Glass | ec8dab4 | 2011-11-05 03:56:50 +0000 | [diff] [blame] | 381 | /* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */ |
| 382 | asm volatile( |
| 383 | "mrc p15, 0, r0, c1, c0, 1\n" |
| 384 | "orr r0, r0, #0x41\n" |
| 385 | "mcr p15, 0, r0, c1, c0, 1\n"); |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 386 | |
Simon Glass | ec8dab4 | 2011-11-05 03:56:50 +0000 | [diff] [blame] | 387 | /* FIXME: should have ap20's L2 disabled too? */ |
Tom Warren | 112a188 | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 388 | } |