]>
Commit | Line | Data |
---|---|---|
c037c93b AM |
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 <asm/io.h> | |
25 | #include <asm/arch/tegra20.h> | |
26 | #include <asm/arch/clk_rst.h> | |
27 | #include <asm/arch/clock.h> | |
28 | #include <asm/arch/pmc.h> | |
29 | #include <asm/arch/pinmux.h> | |
30 | #include <asm/arch/scu.h> | |
31 | #include <common.h> | |
3064f322 | 32 | #include "../tegra-common/cpu.h" |
c037c93b AM |
33 | |
34 | /* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */ | |
35 | int ap20_cpu_is_cortexa9(void) | |
36 | { | |
37 | u32 id = readb(NV_PA_PG_UP_BASE + PG_UP_TAG_0); | |
38 | return id == (PG_UP_TAG_0_PID_CPU & 0xff); | |
39 | } | |
40 | ||
41 | void init_pllx(void) | |
42 | { | |
43 | struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; | |
44 | struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_XCPU]; | |
45 | u32 reg; | |
46 | ||
47 | /* If PLLX is already enabled, just return */ | |
48 | if (readl(&pll->pll_base) & PLL_ENABLE_MASK) | |
49 | return; | |
50 | ||
51 | /* Set PLLX_MISC */ | |
52 | writel(1 << PLL_CPCON_SHIFT, &pll->pll_misc); | |
53 | ||
54 | /* Use 12MHz clock here */ | |
55 | reg = PLL_BYPASS_MASK | (12 << PLL_DIVM_SHIFT); | |
56 | reg |= 1000 << PLL_DIVN_SHIFT; | |
57 | writel(reg, &pll->pll_base); | |
58 | ||
59 | reg |= PLL_ENABLE_MASK; | |
60 | writel(reg, &pll->pll_base); | |
61 | ||
62 | reg &= ~PLL_BYPASS_MASK; | |
63 | writel(reg, &pll->pll_base); | |
64 | } | |
65 | ||
66 | static void enable_cpu_clock(int enable) | |
67 | { | |
68 | struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; | |
69 | u32 clk; | |
70 | ||
71 | /* | |
72 | * NOTE: | |
73 | * Regardless of whether the request is to enable or disable the CPU | |
74 | * clock, every processor in the CPU complex except the master (CPU 0) | |
75 | * will have it's clock stopped because the AVP only talks to the | |
76 | * master. The AVP does not know (nor does it need to know) that there | |
77 | * are multiple processors in the CPU complex. | |
78 | */ | |
79 | ||
80 | if (enable) { | |
81 | /* Initialize PLLX */ | |
82 | init_pllx(); | |
83 | ||
84 | /* Wait until all clocks are stable */ | |
85 | udelay(PLL_STABILIZATION_DELAY); | |
86 | ||
87 | writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol); | |
88 | writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); | |
89 | } | |
90 | ||
91 | /* | |
92 | * Read the register containing the individual CPU clock enables and | |
93 | * always stop the clock to CPU 1. | |
94 | */ | |
95 | clk = readl(&clkrst->crc_clk_cpu_cmplx); | |
96 | clk |= 1 << CPU1_CLK_STP_SHIFT; | |
97 | ||
98 | /* Stop/Unstop the CPU clock */ | |
99 | clk &= ~CPU0_CLK_STP_MASK; | |
100 | clk |= !enable << CPU0_CLK_STP_SHIFT; | |
101 | writel(clk, &clkrst->crc_clk_cpu_cmplx); | |
102 | ||
103 | clock_enable(PERIPH_ID_CPU); | |
104 | } | |
105 | ||
106 | static int is_cpu_powered(void) | |
107 | { | |
29f3e3f2 | 108 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
c037c93b AM |
109 | |
110 | return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0; | |
111 | } | |
112 | ||
113 | static void remove_cpu_io_clamps(void) | |
114 | { | |
29f3e3f2 | 115 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
c037c93b AM |
116 | u32 reg; |
117 | ||
118 | /* Remove the clamps on the CPU I/O signals */ | |
119 | reg = readl(&pmc->pmc_remove_clamping); | |
120 | reg |= CPU_CLMP; | |
121 | writel(reg, &pmc->pmc_remove_clamping); | |
122 | ||
123 | /* Give I/O signals time to stabilize */ | |
124 | udelay(IO_STABILIZATION_DELAY); | |
125 | } | |
126 | ||
127 | static void powerup_cpu(void) | |
128 | { | |
29f3e3f2 | 129 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
c037c93b AM |
130 | u32 reg; |
131 | int timeout = IO_STABILIZATION_DELAY; | |
132 | ||
133 | if (!is_cpu_powered()) { | |
134 | /* Toggle the CPU power state (OFF -> ON) */ | |
135 | reg = readl(&pmc->pmc_pwrgate_toggle); | |
136 | reg &= PARTID_CP; | |
137 | reg |= START_CP; | |
138 | writel(reg, &pmc->pmc_pwrgate_toggle); | |
139 | ||
140 | /* Wait for the power to come up */ | |
141 | while (!is_cpu_powered()) { | |
142 | if (timeout-- == 0) | |
143 | printf("CPU failed to power up!\n"); | |
144 | else | |
145 | udelay(10); | |
146 | } | |
147 | ||
148 | /* | |
149 | * Remove the I/O clamps from CPU power partition. | |
150 | * Recommended only on a Warm boot, if the CPU partition gets | |
151 | * power gated. Shouldn't cause any harm when called after a | |
152 | * cold boot according to HW, probably just redundant. | |
153 | */ | |
154 | remove_cpu_io_clamps(); | |
155 | } | |
156 | } | |
157 | ||
158 | static void enable_cpu_power_rail(void) | |
159 | { | |
29f3e3f2 | 160 | struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; |
c037c93b AM |
161 | u32 reg; |
162 | ||
163 | reg = readl(&pmc->pmc_cntrl); | |
164 | reg |= CPUPWRREQ_OE; | |
165 | writel(reg, &pmc->pmc_cntrl); | |
166 | ||
167 | /* | |
168 | * The TI PMU65861C needs a 3.75ms delay between enabling | |
169 | * the power rail and enabling the CPU clock. This delay | |
170 | * between SM1EN and SM1 is for switching time + the ramp | |
171 | * up of the voltage to the CPU (VDD_CPU from PMU). | |
172 | */ | |
173 | udelay(3750); | |
174 | } | |
175 | ||
176 | static void reset_A9_cpu(int reset) | |
177 | { | |
178 | /* | |
179 | * NOTE: Regardless of whether the request is to hold the CPU in reset | |
180 | * or take it out of reset, every processor in the CPU complex | |
181 | * except the master (CPU 0) will be held in reset because the | |
182 | * AVP only talks to the master. The AVP does not know that there | |
183 | * are multiple processors in the CPU complex. | |
184 | */ | |
185 | ||
186 | /* Hold CPU 1 in reset, and CPU 0 if asked */ | |
187 | reset_cmplx_set_enable(1, crc_rst_cpu | crc_rst_de | crc_rst_debug, 1); | |
188 | reset_cmplx_set_enable(0, crc_rst_cpu | crc_rst_de | crc_rst_debug, | |
189 | reset); | |
190 | ||
191 | /* Enable/Disable master CPU reset */ | |
192 | reset_set_enable(PERIPH_ID_CPU, reset); | |
193 | } | |
194 | ||
195 | static void clock_enable_coresight(int enable) | |
196 | { | |
197 | u32 rst, src; | |
198 | ||
199 | clock_set_enable(PERIPH_ID_CORESIGHT, enable); | |
200 | reset_set_enable(PERIPH_ID_CORESIGHT, !enable); | |
201 | ||
202 | if (enable) { | |
203 | /* | |
204 | * Put CoreSight on PLLP_OUT0 (216 MHz) and divide it down by | |
205 | * 1.5, giving an effective frequency of 144MHz. | |
206 | * Set PLLP_OUT0 [bits31:30 = 00], and use a 7.1 divisor | |
207 | * (bits 7:0), so 00000001b == 1.5 (n+1 + .5) | |
208 | */ | |
209 | src = CLK_DIVIDER(NVBL_PLLP_KHZ, 144000); | |
210 | clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src); | |
211 | ||
212 | /* Unlock the CPU CoreSight interfaces */ | |
213 | rst = 0xC5ACCE55; | |
214 | writel(rst, CSITE_CPU_DBG0_LAR); | |
215 | writel(rst, CSITE_CPU_DBG1_LAR); | |
216 | } | |
217 | } | |
218 | ||
219 | void start_cpu(u32 reset_vector) | |
220 | { | |
221 | /* Enable VDD_CPU */ | |
222 | enable_cpu_power_rail(); | |
223 | ||
224 | /* Hold the CPUs in reset */ | |
225 | reset_A9_cpu(1); | |
226 | ||
227 | /* Disable the CPU clock */ | |
228 | enable_cpu_clock(0); | |
229 | ||
230 | /* Enable CoreSight */ | |
231 | clock_enable_coresight(1); | |
232 | ||
233 | /* | |
234 | * Set the entry point for CPU execution from reset, | |
235 | * if it's a non-zero value. | |
236 | */ | |
237 | if (reset_vector) | |
238 | writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); | |
239 | ||
240 | /* Enable the CPU clock */ | |
241 | enable_cpu_clock(1); | |
242 | ||
243 | /* If the CPU doesn't already have power, power it up */ | |
244 | powerup_cpu(); | |
245 | ||
246 | /* Take the CPU out of reset */ | |
247 | reset_A9_cpu(0); | |
248 | } | |
249 | ||
250 | ||
251 | void halt_avp(void) | |
252 | { | |
253 | for (;;) { | |
254 | writel((HALT_COP_EVENT_JTAG | HALT_COP_EVENT_IRQ_1 \ | |
255 | | HALT_COP_EVENT_FIQ_1 | (FLOW_MODE_STOP<<29)), | |
256 | FLOW_CTLR_HALT_COP_EVENTS); | |
257 | } | |
258 | } |