Tom Warren | 74652cf | 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 | |
| 24 | #include "ap20.h" |
| 25 | #include <asm/io.h> |
| 26 | #include <asm/arch/tegra2.h> |
| 27 | #include <asm/arch/clk_rst.h> |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 28 | #include <asm/arch/clock.h> |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 29 | #include <asm/arch/pmc.h> |
| 30 | #include <asm/arch/pinmux.h> |
| 31 | #include <asm/arch/scu.h> |
| 32 | #include <common.h> |
| 33 | |
| 34 | u32 s_first_boot = 1; |
| 35 | |
Tom Warren | 1436d51 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 36 | void init_pllx(void) |
| 37 | { |
| 38 | struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 39 | struct clk_pll *pll = &clkrst->crc_pll[CLOCK_PLL_ID_XCPU]; |
Tom Warren | 1436d51 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 40 | u32 reg; |
| 41 | |
| 42 | /* If PLLX is already enabled, just return */ |
Simon Glass | d07dc49 | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 43 | if (readl(&pll->pll_base) & PLL_ENABLE_MASK) |
Tom Warren | 1436d51 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 44 | return; |
| 45 | |
| 46 | /* Set PLLX_MISC */ |
Simon Glass | d07dc49 | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 47 | writel(1 << PLL_CPCON_SHIFT, &pll->pll_misc); |
Tom Warren | 1436d51 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 48 | |
| 49 | /* Use 12MHz clock here */ |
Simon Glass | d07dc49 | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 50 | reg = PLL_BYPASS_MASK | (12 << PLL_DIVM_SHIFT); |
| 51 | reg |= 1000 << PLL_DIVN_SHIFT; |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 52 | writel(reg, &pll->pll_base); |
Tom Warren | 1436d51 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 53 | |
Simon Glass | d07dc49 | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 54 | reg |= PLL_ENABLE_MASK; |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 55 | writel(reg, &pll->pll_base); |
Tom Warren | 1436d51 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 56 | |
Simon Glass | d07dc49 | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 57 | reg &= ~PLL_BYPASS_MASK; |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 58 | writel(reg, &pll->pll_base); |
Tom Warren | 1436d51 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 59 | } |
| 60 | |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 61 | static void enable_cpu_clock(int enable) |
| 62 | { |
| 63 | struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 64 | u32 clk; |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 65 | |
| 66 | /* |
| 67 | * NOTE: |
| 68 | * Regardless of whether the request is to enable or disable the CPU |
| 69 | * clock, every processor in the CPU complex except the master (CPU 0) |
| 70 | * will have it's clock stopped because the AVP only talks to the |
| 71 | * master. The AVP does not know (nor does it need to know) that there |
| 72 | * are multiple processors in the CPU complex. |
| 73 | */ |
| 74 | |
| 75 | if (enable) { |
Tom Warren | 1436d51 | 2011-04-14 12:09:39 +0000 | [diff] [blame] | 76 | /* Initialize PLLX */ |
| 77 | init_pllx(); |
| 78 | |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 79 | /* Wait until all clocks are stable */ |
| 80 | udelay(PLL_STABILIZATION_DELAY); |
| 81 | |
| 82 | writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol); |
| 83 | writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); |
| 84 | } |
| 85 | |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 86 | /* |
| 87 | * Read the register containing the individual CPU clock enables and |
| 88 | * always stop the clock to CPU 1. |
| 89 | */ |
| 90 | clk = readl(&clkrst->crc_clk_cpu_cmplx); |
Simon Glass | d07dc49 | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 91 | clk |= 1 << CPU1_CLK_STP_SHIFT; |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 92 | |
Simon Glass | d07dc49 | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 93 | /* Stop/Unstop the CPU clock */ |
| 94 | clk &= ~CPU0_CLK_STP_MASK; |
| 95 | clk |= !enable << CPU0_CLK_STP_SHIFT; |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 96 | writel(clk, &clkrst->crc_clk_cpu_cmplx); |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 97 | |
| 98 | clock_enable(PERIPH_ID_CPU); |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | static int is_cpu_powered(void) |
| 102 | { |
| 103 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
| 104 | |
| 105 | return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0; |
| 106 | } |
| 107 | |
| 108 | static void remove_cpu_io_clamps(void) |
| 109 | { |
| 110 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
| 111 | u32 reg; |
| 112 | |
| 113 | /* Remove the clamps on the CPU I/O signals */ |
| 114 | reg = readl(&pmc->pmc_remove_clamping); |
| 115 | reg |= CPU_CLMP; |
| 116 | writel(reg, &pmc->pmc_remove_clamping); |
| 117 | |
| 118 | /* Give I/O signals time to stabilize */ |
| 119 | udelay(IO_STABILIZATION_DELAY); |
| 120 | } |
| 121 | |
| 122 | static void powerup_cpu(void) |
| 123 | { |
| 124 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
| 125 | u32 reg; |
| 126 | int timeout = IO_STABILIZATION_DELAY; |
| 127 | |
| 128 | if (!is_cpu_powered()) { |
| 129 | /* Toggle the CPU power state (OFF -> ON) */ |
| 130 | reg = readl(&pmc->pmc_pwrgate_toggle); |
| 131 | reg &= PARTID_CP; |
| 132 | reg |= START_CP; |
| 133 | writel(reg, &pmc->pmc_pwrgate_toggle); |
| 134 | |
| 135 | /* Wait for the power to come up */ |
| 136 | while (!is_cpu_powered()) { |
| 137 | if (timeout-- == 0) |
| 138 | printf("CPU failed to power up!\n"); |
| 139 | else |
| 140 | udelay(10); |
| 141 | } |
| 142 | |
| 143 | /* |
| 144 | * Remove the I/O clamps from CPU power partition. |
| 145 | * Recommended only on a Warm boot, if the CPU partition gets |
| 146 | * power gated. Shouldn't cause any harm when called after a |
| 147 | * cold boot according to HW, probably just redundant. |
| 148 | */ |
| 149 | remove_cpu_io_clamps(); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | static void enable_cpu_power_rail(void) |
| 154 | { |
| 155 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
| 156 | u32 reg; |
| 157 | |
| 158 | reg = readl(&pmc->pmc_cntrl); |
| 159 | reg |= CPUPWRREQ_OE; |
| 160 | writel(reg, &pmc->pmc_cntrl); |
| 161 | |
| 162 | /* |
| 163 | * The TI PMU65861C needs a 3.75ms delay between enabling |
| 164 | * the power rail and enabling the CPU clock. This delay |
| 165 | * between SM1EN and SM1 is for switching time + the ramp |
| 166 | * up of the voltage to the CPU (VDD_CPU from PMU). |
| 167 | */ |
| 168 | udelay(3750); |
| 169 | } |
| 170 | |
| 171 | static void reset_A9_cpu(int reset) |
| 172 | { |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 173 | /* |
| 174 | * NOTE: Regardless of whether the request is to hold the CPU in reset |
| 175 | * or take it out of reset, every processor in the CPU complex |
| 176 | * except the master (CPU 0) will be held in reset because the |
| 177 | * AVP only talks to the master. The AVP does not know that there |
| 178 | * are multiple processors in the CPU complex. |
| 179 | */ |
| 180 | |
Simon Glass | d07dc49 | 2011-08-30 06:23:15 +0000 | [diff] [blame] | 181 | /* Hold CPU 1 in reset, and CPU 0 if asked */ |
| 182 | reset_cmplx_set_enable(1, crc_rst_cpu | crc_rst_de | crc_rst_debug, 1); |
| 183 | reset_cmplx_set_enable(0, crc_rst_cpu | crc_rst_de | crc_rst_debug, |
| 184 | reset); |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 185 | |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 186 | /* Enable/Disable master CPU reset */ |
| 187 | reset_set_enable(PERIPH_ID_CPU, reset); |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 188 | } |
| 189 | |
| 190 | static void clock_enable_coresight(int enable) |
| 191 | { |
| 192 | struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 193 | u32 rst, src; |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 194 | |
Simon Glass | b4ba2be | 2011-08-30 06:23:13 +0000 | [diff] [blame] | 195 | clock_set_enable(PERIPH_ID_CORESIGHT, enable); |
| 196 | reset_set_enable(PERIPH_ID_CORESIGHT, !enable); |
Tom Warren | 74652cf | 2011-04-14 12:18:06 +0000 | [diff] [blame] | 197 | |
| 198 | if (enable) { |
| 199 | /* |
| 200 | * Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by |
| 201 | * 1.5, giving an effective frequency of 144MHz. |
| 202 | * Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor |
| 203 | * (bits 7:0), so 00000001b == 1.5 (n+1 + .5) |
| 204 | */ |
| 205 | src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000); |
| 206 | writel(src, &clkrst->crc_clk_src_csite); |
| 207 | |
| 208 | /* Unlock the CPU CoreSight interfaces */ |
| 209 | rst = 0xC5ACCE55; |
| 210 | writel(rst, CSITE_CPU_DBG0_LAR); |
| 211 | writel(rst, CSITE_CPU_DBG1_LAR); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | void start_cpu(u32 reset_vector) |
| 216 | { |
| 217 | /* Enable VDD_CPU */ |
| 218 | enable_cpu_power_rail(); |
| 219 | |
| 220 | /* Hold the CPUs in reset */ |
| 221 | reset_A9_cpu(1); |
| 222 | |
| 223 | /* Disable the CPU clock */ |
| 224 | enable_cpu_clock(0); |
| 225 | |
| 226 | /* Enable CoreSight */ |
| 227 | clock_enable_coresight(1); |
| 228 | |
| 229 | /* |
| 230 | * Set the entry point for CPU execution from reset, |
| 231 | * if it's a non-zero value. |
| 232 | */ |
| 233 | if (reset_vector) |
| 234 | writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); |
| 235 | |
| 236 | /* Enable the CPU clock */ |
| 237 | enable_cpu_clock(1); |
| 238 | |
| 239 | /* If the CPU doesn't already have power, power it up */ |
| 240 | powerup_cpu(); |
| 241 | |
| 242 | /* Take the CPU out of reset */ |
| 243 | reset_A9_cpu(0); |
| 244 | } |
| 245 | |
| 246 | |
| 247 | void halt_avp(void) |
| 248 | { |
| 249 | for (;;) { |
| 250 | writel((HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \ |
| 251 | | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29)), |
| 252 | FLOW_CTLR_HALT_COP_EVENTS); |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | void enable_scu(void) |
| 257 | { |
| 258 | struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE; |
| 259 | u32 reg; |
| 260 | |
| 261 | /* If SCU already setup/enabled, return */ |
| 262 | if (readl(&scu->scu_ctrl) & SCU_CTRL_ENABLE) |
| 263 | return; |
| 264 | |
| 265 | /* Invalidate all ways for all processors */ |
| 266 | writel(0xFFFF, &scu->scu_inv_all); |
| 267 | |
| 268 | /* Enable SCU - bit 0 */ |
| 269 | reg = readl(&scu->scu_ctrl); |
| 270 | reg |= SCU_CTRL_ENABLE; |
| 271 | writel(reg, &scu->scu_ctrl); |
| 272 | } |
| 273 | |
| 274 | void init_pmc_scratch(void) |
| 275 | { |
| 276 | struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
| 277 | int i; |
| 278 | |
| 279 | /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */ |
| 280 | for (i = 0; i < 23; i++) |
| 281 | writel(0, &pmc->pmc_scratch1+i); |
| 282 | |
| 283 | /* ODMDATA is for kernel use to determine RAM size, LP config, etc. */ |
| 284 | writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20); |
| 285 | } |
| 286 | |
| 287 | void cpu_start(void) |
| 288 | { |
| 289 | struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; |
| 290 | |
| 291 | /* enable JTAG */ |
| 292 | writel(0xC0, &pmt->pmt_cfg_ctl); |
| 293 | |
| 294 | if (s_first_boot) { |
| 295 | /* |
| 296 | * Need to set this before cold-booting, |
| 297 | * otherwise we'll end up in an infinite loop. |
| 298 | */ |
| 299 | s_first_boot = 0; |
| 300 | cold_boot(); |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | void tegra2_start() |
| 305 | { |
| 306 | if (s_first_boot) { |
| 307 | /* Init Debug UART Port (115200 8n1) */ |
| 308 | uart_init(); |
| 309 | |
| 310 | /* Init PMC scratch memory */ |
| 311 | init_pmc_scratch(); |
| 312 | } |
| 313 | |
| 314 | #ifdef CONFIG_ENABLE_CORTEXA9 |
| 315 | /* take the mpcore out of reset */ |
| 316 | cpu_start(); |
| 317 | |
| 318 | /* configure cache */ |
| 319 | cache_configure(); |
| 320 | #endif |
| 321 | } |