diff options
Diffstat (limited to 'arch/arm/mach-tegra/sleep-t3.S')
-rw-r--r-- | arch/arm/mach-tegra/sleep-t3.S | 715 |
1 files changed, 715 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/sleep-t3.S b/arch/arm/mach-tegra/sleep-t3.S new file mode 100644 index 00000000000..5ea7334c45f --- /dev/null +++ b/arch/arm/mach-tegra/sleep-t3.S | |||
@@ -0,0 +1,715 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-tegra/include/mach/sleep-t3.S | ||
3 | * | ||
4 | * Copyright (c) 2010-2011, NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/const.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/linkage.h> | ||
24 | |||
25 | #include <asm/assembler.h> | ||
26 | #include <asm/cache.h> | ||
27 | #include <asm/domain.h> | ||
28 | #include <asm/memory.h> | ||
29 | #include <asm/page.h> | ||
30 | #include <asm/ptrace.h> | ||
31 | #include <asm/asm-offsets.h> | ||
32 | #include <asm/glue-cache.h> | ||
33 | #include <asm/glue-proc.h> | ||
34 | #include <asm/system.h> | ||
35 | |||
36 | #include <mach/iomap.h> | ||
37 | #include <mach/io.h> | ||
38 | |||
39 | #include "asm_macros.h" | ||
40 | #include "sleep.h" | ||
41 | #include "clock.h" | ||
42 | |||
43 | #define EMC_CFG 0xc | ||
44 | #define EMC_ADR_CFG 0x10 | ||
45 | #define EMC_TIMING_CONTROL 0x28 | ||
46 | #define EMC_REFRESH 0x70 | ||
47 | #define EMC_NOP 0xdc | ||
48 | #define EMC_SELF_REF 0xe0 | ||
49 | #define EMC_MRW 0xe8 | ||
50 | #define EMC_REQ_CTRL 0x2b0 | ||
51 | #define EMC_EMC_STATUS 0x2b4 | ||
52 | #define EMC_FBIO_CFG5 0x104 | ||
53 | #define EMC_AUTO_CAL_CONFIG 0x2a4 | ||
54 | #define EMC_AUTO_CAL_INTERVAL 0x2a8 | ||
55 | #define EMC_AUTO_CAL_STATUS 0x2ac | ||
56 | #define EMC_CFG_DIG_DLL 0x2bc | ||
57 | #define EMC_ZCAL_INTERVAL 0x2e0 | ||
58 | #define EMC_ZQ_CAL 0x2ec | ||
59 | #define EMC_XM2VTTGENPADCTRL 0x310 | ||
60 | #define EMC_XM2VTTGENPADCTRL2 0x314 | ||
61 | |||
62 | #define PMC_CTRL 0x0 | ||
63 | #define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */ | ||
64 | |||
65 | #define PMC_PWRGATE_TOGGLE 0x30 | ||
66 | #define PMC_REMOVE_CLAMPING_CMD 0x34 | ||
67 | #define PMC_PWRGATE_STATUS 0x38 | ||
68 | |||
69 | #define PMC_PWRGATE_PARTID_L2C (0x5) | ||
70 | |||
71 | #define PMC_IO_DPD_REQ 0x1b8 | ||
72 | #define PMC_IO_DPD_STATUS 0x1bc | ||
73 | |||
74 | #define CLK_RESET_CCLK_BURST 0x20 | ||
75 | #define CLK_RESET_CCLK_DIVIDER 0x24 | ||
76 | #define CLK_RESET_SCLK_BURST 0x28 | ||
77 | #define CLK_RESET_SCLK_DIVIDER 0x2c | ||
78 | |||
79 | #define CLK_RESET_PLLC_BASE 0x80 | ||
80 | #define CLK_RESET_PLLM_BASE 0x90 | ||
81 | #define CLK_RESET_PLLP_BASE 0xa0 | ||
82 | #define CLK_RESET_PLLA_BASE 0xb0 | ||
83 | #define CLK_RESET_PLLX_BASE 0xe0 | ||
84 | |||
85 | #define CLK_RESET_PLLC_MISC 0x8c | ||
86 | #define CLK_RESET_PLLM_MISC 0x9c | ||
87 | #define CLK_RESET_PLLP_MISC 0xac | ||
88 | #define CLK_RESET_PLLA_MISC 0xbc | ||
89 | #define CLK_RESET_PLLX_MISC 0xe4 | ||
90 | |||
91 | #define CLK_RESET_PLLP_OUTA 0xa4 | ||
92 | #define CLK_RESET_PLLP_OUTB 0xa8 | ||
93 | |||
94 | #define PMC_PLLP_WB0_OVERRIDE 0xf8 | ||
95 | |||
96 | #define CLK_RESET_CLK_SOURCE_MSELECT 0x3b4 | ||
97 | |||
98 | #define MSELECT_CLKM (0x3 << 30) | ||
99 | |||
100 | #if USE_PLL_LOCK_BITS | ||
101 | #define LOCK_DELAY PLL_POST_LOCK_DELAY | ||
102 | #else | ||
103 | #define LOCK_DELAY 0xff /* 255uS delay for PLL stabilization */ | ||
104 | #endif | ||
105 | |||
106 | #define USE_PLLP_ON_SLEEP_ENTRY 0 | ||
107 | |||
108 | .macro emc_device_mask, rd, base | ||
109 | ldr \rd, [\base, #EMC_ADR_CFG] | ||
110 | tst \rd, #0x1 | ||
111 | moveq \rd, #(0x1<<8) @ just 1 device | ||
112 | movne \rd, #(0x3<<8) @ 2 devices | ||
113 | .endm | ||
114 | |||
115 | .macro emc_timing_update, rd, base | ||
116 | mov \rd, #1 | ||
117 | str \rd, [\base, #EMC_TIMING_CONTROL] | ||
118 | 1001: | ||
119 | ldr \rd, [\base, #EMC_EMC_STATUS] | ||
120 | tst \rd, #(0x1<<23) @ wait until EMC_STATUS_TIMING_UPDATE_STALLED is clear | ||
121 | bne 1001b | ||
122 | .endm | ||
123 | |||
124 | #ifdef CONFIG_HOTPLUG_CPU | ||
125 | /* | ||
126 | * tegra3_hotplug_shutdown(void) | ||
127 | * | ||
128 | * Powergates the current CPU. | ||
129 | * Should never return. | ||
130 | */ | ||
131 | ENTRY(tegra3_hotplug_shutdown) | ||
132 | mov r6, lr | ||
133 | bl tegra_cpu_exit_coherency | ||
134 | |||
135 | /* Powergate this CPU. */ | ||
136 | mov r0, #TEGRA_POWER_HOTPLUG_SHUTDOWN | ||
137 | bl tegra3_cpu_reset | ||
138 | mov pc, r6 @ should never get here | ||
139 | ENDPROC(tegra3_hotplug_shutdown) | ||
140 | #endif | ||
141 | |||
142 | #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) | ||
143 | /* | ||
144 | * tegra3_cpu_reset(unsigned long flags) | ||
145 | * | ||
146 | * Puts the current CPU in wait-for-event mode on the flow controller | ||
147 | * and powergates it -- flags (in R0) indicate the request type. | ||
148 | * Must never be called for CPU 0. | ||
149 | * | ||
150 | * corrupts r0-r4, r12 | ||
151 | */ | ||
152 | ENTRY(tegra3_cpu_reset) | ||
153 | cpu_id r3 | ||
154 | cmp r3, #0 | ||
155 | moveq pc, lr @ Must never be called for CPU 0 | ||
156 | |||
157 | mov32 r12, TEGRA_FLOW_CTRL_VIRT | ||
158 | cpu_to_csr_reg r1, r3 | ||
159 | add r1, r1, r12 @ virtual CSR address for this CPU | ||
160 | cpu_to_halt_reg r2, r3 | ||
161 | add r2, r2, r12 @ virtual HALT_EVENTS address for this CPU | ||
162 | |||
163 | /* Clear this CPU's "event" and "interrupt" flags and power gate | ||
164 | it when halting but not before it is in the "WFE" state. */ | ||
165 | movw r12, FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | FLOW_CTRL_CSR_ENABLE | ||
166 | mov r4, #(1 << 4) | ||
167 | orr r12, r12, r4, lsl r3 | ||
168 | str r12, [r1] | ||
169 | |||
170 | /* Halt this CPU. */ | ||
171 | mov r3, #0x400 | ||
172 | delay_1: | ||
173 | subs r3, r3, #1 @ delay as a part of wfe war. | ||
174 | bge delay_1; | ||
175 | cpsid a @ disable imprecise aborts. | ||
176 | ldr r3, [r1] @ read CSR | ||
177 | str r3, [r1] @ clear CSR | ||
178 | tst r0, #TEGRA_POWER_HOTPLUG_SHUTDOWN | ||
179 | moveq r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT @ For LP2 | ||
180 | movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug | ||
181 | str r3, [r2] | ||
182 | ldr r0, [r2] | ||
183 | b wfe_war | ||
184 | |||
185 | __cpu_reset_again: | ||
186 | dsb | ||
187 | .align 5 | ||
188 | wfe @ CPU should be power gated here | ||
189 | wfe_war: | ||
190 | b __cpu_reset_again | ||
191 | |||
192 | /* 38 nop's, which fills reset of wfe cache line and 4 more cachelines with nop*/ | ||
193 | .rept 38 | ||
194 | nop | ||
195 | .endr | ||
196 | b . @ should never get here | ||
197 | |||
198 | ENDPROC(tegra3_cpu_reset) | ||
199 | #endif | ||
200 | |||
201 | #ifdef CONFIG_PM_SLEEP | ||
202 | |||
203 | /* | ||
204 | * tegra3_sleep_core(unsigned long v2p) | ||
205 | * | ||
206 | * enters suspend in LP0 or LP1 by turning off the mmu and jumping to | ||
207 | * tegra3_tear_down_core in IRAM | ||
208 | */ | ||
209 | ENTRY(tegra3_sleep_core) | ||
210 | mov r12, pc @ return here is via r12 | ||
211 | b tegra_cpu_save | ||
212 | |||
213 | /* preload all the address literals that are needed for the | ||
214 | * CPU power-gating process, to avoid loads from SDRAM (which are | ||
215 | * not supported once SDRAM is put into self-refresh. | ||
216 | * LP0 / LP1 use physical address, since the MMU needs to be | ||
217 | * disabled before putting SDRAM into self-refresh to avoid | ||
218 | * memory access due to page table walks */ | ||
219 | mov32 r4, TEGRA_PMC_BASE | ||
220 | mov32 r5, TEGRA_CLK_RESET_BASE | ||
221 | mov32 r6, TEGRA_FLOW_CTRL_BASE | ||
222 | mov32 r7, TEGRA_TMRUS_BASE | ||
223 | |||
224 | mov32 r1, tegra3_tear_down_core | ||
225 | mov32 r2, tegra3_iram_start | ||
226 | sub r1, r1, r2 | ||
227 | mov32 r2, TEGRA_IRAM_CODE_AREA | ||
228 | add r1, r1, r2 | ||
229 | b tegra_turn_off_mmu | ||
230 | ENDPROC(tegra3_sleep_core) | ||
231 | |||
232 | /* | ||
233 | * tegra3_sleep_cpu_secondary(unsigned long v2p) | ||
234 | * | ||
235 | * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU. | ||
236 | */ | ||
237 | ENTRY(tegra3_sleep_cpu_secondary) | ||
238 | mov r12, pc @ return here is via r12 | ||
239 | b tegra_cpu_save | ||
240 | |||
241 | /* Powergate this CPU. */ | ||
242 | mov r0, #0 @ power mode flags (!hotplug) | ||
243 | bl tegra3_cpu_reset | ||
244 | b . @ should never get here | ||
245 | ENDPROC(tegra3_sleep_cpu_secondary) | ||
246 | |||
247 | /* | ||
248 | * tegra3_tear_down_cpu | ||
249 | * | ||
250 | * Switches the CPU cluster to PLL-P and enters sleep. | ||
251 | */ | ||
252 | ENTRY(tegra3_tear_down_cpu) | ||
253 | mov32 r4, TEGRA_PMC_BASE | ||
254 | mov32 r5, TEGRA_CLK_RESET_BASE | ||
255 | mov32 r6, TEGRA_FLOW_CTRL_BASE | ||
256 | mov32 r7, TEGRA_TMRUS_BASE | ||
257 | #if USE_PLLP_ON_SLEEP_ENTRY | ||
258 | bl tegra_cpu_pllp | ||
259 | #endif | ||
260 | b tegra3_enter_sleep | ||
261 | ENDPROC(tegra3_tear_down_cpu) | ||
262 | |||
263 | /* START OF ROUTINES COPIED TO IRAM */ | ||
264 | .align L1_CACHE_SHIFT | ||
265 | .globl tegra3_iram_start | ||
266 | tegra3_iram_start: | ||
267 | |||
268 | /* | ||
269 | * tegra3_lp1_reset | ||
270 | * | ||
271 | * reset vector for LP1 restore; copied into IRAM during suspend. | ||
272 | * brings the system back up to a safe starting point (SDRAM out of | ||
273 | * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLP, | ||
274 | * system clock running on the same PLL that it suspended at), and | ||
275 | * jumps to tegra_lp2_startup to restore PLLX and virtual addressing. | ||
276 | * physical address of tegra_lp2_startup expected to be stored in | ||
277 | * PMC_SCRATCH41 | ||
278 | * | ||
279 | * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_CODE_AREA AND MUST BE FIRST. | ||
280 | */ | ||
281 | .macro pll_enable, rd, car, base, misc | ||
282 | ldr \rd, [\car, #\base] | ||
283 | tst \rd, #(1<<30) | ||
284 | orreq \rd, \rd, #(1<<30) | ||
285 | streq \rd, [\car, #\base] | ||
286 | #if USE_PLL_LOCK_BITS | ||
287 | ldr \rd, [\car, #\misc] | ||
288 | orr \rd, \rd, #(1<<18) | ||
289 | str \rd, [\car, #\misc] | ||
290 | #endif | ||
291 | .endm | ||
292 | |||
293 | .macro pll_locked, rd, car, base | ||
294 | #if USE_PLL_LOCK_BITS | ||
295 | 1: | ||
296 | ldr \rd, [\car, #\base] | ||
297 | tst \rd, #(1<<27) | ||
298 | beq 1b | ||
299 | #endif | ||
300 | .endm | ||
301 | |||
302 | ENTRY(tegra3_lp1_reset) | ||
303 | /* the CPU and system bus are running at 32KHz and executing from | ||
304 | * IRAM when this code is executed; immediately switch to CLKM and | ||
305 | * enable PLLP, PLLM, PLLC, PLLA and PLLX. */ | ||
306 | mov32 r0, TEGRA_CLK_RESET_BASE | ||
307 | #ifndef CONFIG_TRUSTED_FOUNDATIONS | ||
308 | /* secure code handles 32KHz to CLKM/OSC clock switch */ | ||
309 | mov r1, #(1<<28) | ||
310 | str r1, [r0, #CLK_RESET_SCLK_BURST] | ||
311 | str r1, [r0, #CLK_RESET_CCLK_BURST] | ||
312 | mov r1, #0 | ||
313 | str r1, [r0, #CLK_RESET_SCLK_DIVIDER] | ||
314 | str r1, [r0, #CLK_RESET_CCLK_DIVIDER] | ||
315 | #endif | ||
316 | /* enable PLLM via PMC */ | ||
317 | mov32 r2, TEGRA_PMC_BASE | ||
318 | ldr r1, [r2, #PMC_PLLP_WB0_OVERRIDE] | ||
319 | orr r1, r1, #(1<<12) | ||
320 | str r1, [r2, #PMC_PLLP_WB0_OVERRIDE] | ||
321 | |||
322 | pll_enable r1, r0, CLK_RESET_PLLM_BASE, CLK_RESET_PLLM_MISC | ||
323 | pll_enable r1, r0, CLK_RESET_PLLP_BASE, CLK_RESET_PLLP_MISC | ||
324 | pll_enable r1, r0, CLK_RESET_PLLA_BASE, CLK_RESET_PLLA_MISC | ||
325 | pll_enable r1, r0, CLK_RESET_PLLC_BASE, CLK_RESET_PLLC_MISC | ||
326 | pll_enable r1, r0, CLK_RESET_PLLX_BASE, CLK_RESET_PLLX_MISC | ||
327 | |||
328 | pll_locked r1, r0, CLK_RESET_PLLM_BASE | ||
329 | pll_locked r1, r0, CLK_RESET_PLLP_BASE | ||
330 | pll_locked r1, r0, CLK_RESET_PLLA_BASE | ||
331 | pll_locked r1, r0, CLK_RESET_PLLC_BASE | ||
332 | pll_locked r1, r0, CLK_RESET_PLLX_BASE | ||
333 | |||
334 | mov32 r7, TEGRA_TMRUS_BASE | ||
335 | ldr r1, [r7] | ||
336 | add r1, r1, #LOCK_DELAY | ||
337 | wait_until r1, r7, r3 | ||
338 | |||
339 | add r5, pc, #tegra3_sdram_pad_save-(.+8) @ r5 reserved for pad base | ||
340 | |||
341 | ldr r4, [r5, #0x18] | ||
342 | str r4, [r0, #CLK_RESET_CLK_SOURCE_MSELECT] | ||
343 | |||
344 | ldr r4, [r5, #0x1C] | ||
345 | str r4, [r0, #CLK_RESET_SCLK_BURST] | ||
346 | |||
347 | mov32 r4, ((1<<28) | (8)) @ burst policy is PLLX | ||
348 | str r4, [r0, #CLK_RESET_CCLK_BURST] | ||
349 | |||
350 | #if defined (CONFIG_CACHE_L2X0) | ||
351 | /* power up L2 */ | ||
352 | ldr r0, [r2, #PMC_PWRGATE_STATUS] | ||
353 | tst r0, #(1<<PMC_PWRGATE_PARTID_L2C) | ||
354 | bne powerup_l2_done | ||
355 | movw r0, #(1<<8) | PMC_PWRGATE_PARTID_L2C | ||
356 | str r0, [r2, #PMC_PWRGATE_TOGGLE] | ||
357 | powerup_l2_wait: | ||
358 | ldr r0, [r2, #PMC_PWRGATE_STATUS] | ||
359 | tst r0, #(1<<PMC_PWRGATE_PARTID_L2C) | ||
360 | beq powerup_l2_wait | ||
361 | powerup_l2_done: | ||
362 | mov r0, #PMC_PWRGATE_PARTID_L2C | ||
363 | str r0, [r2, #PMC_REMOVE_CLAMPING_CMD] | ||
364 | #endif | ||
365 | |||
366 | mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base | ||
367 | |||
368 | ldr r1, [r5, #0x14] @ PMC_IO_DPD_STATUS | ||
369 | mvn r1, r1 | ||
370 | bic r1, r1, #(0x1<<31) | ||
371 | orr r1, r1, #(0x1<<30) | ||
372 | str r1, [r2, #PMC_IO_DPD_REQ] | ||
373 | ldr r1, [r5, #0xC] | ||
374 | str r1, [r0, #EMC_XM2VTTGENPADCTRL] | ||
375 | ldr r1, [r5, #0x10] | ||
376 | str r1, [r0, #EMC_XM2VTTGENPADCTRL2] | ||
377 | ldr r1, [r5, #0x8] | ||
378 | str r1, [r0, #EMC_AUTO_CAL_INTERVAL] | ||
379 | |||
380 | ldr r1, [r0, #EMC_CFG_DIG_DLL] | ||
381 | orr r1, r1, #(0x1<<30) @ set DLL_RESET | ||
382 | str r1, [r0, #EMC_CFG_DIG_DLL] | ||
383 | |||
384 | emc_timing_update r1, r0 | ||
385 | |||
386 | ldr r1, [r0, #EMC_AUTO_CAL_CONFIG] | ||
387 | orr r1, r1, #(0x1<<31) @ set AUTO_CAL_ACTIVE | ||
388 | str r1, [r0, #EMC_AUTO_CAL_CONFIG] | ||
389 | |||
390 | emc_wait_audo_cal_onetime: | ||
391 | ldr r1, [r0, #EMC_AUTO_CAL_STATUS] | ||
392 | tst r1, #(0x1<<31) @ wait until AUTO_CAL_ACTIVE is clear | ||
393 | bne emc_wait_audo_cal_onetime | ||
394 | |||
395 | ldr r1, [r0, #EMC_CFG] | ||
396 | bic r1, r1, #(1<<31) @ disable DRAM_CLK_STOP | ||
397 | str r1, [r0, #EMC_CFG] | ||
398 | |||
399 | mov r1, #0 | ||
400 | str r1, [r0, #EMC_SELF_REF] @ take DRAM out of self refresh | ||
401 | mov r1, #1 | ||
402 | str r1, [r0, #EMC_NOP] | ||
403 | str r1, [r0, #EMC_NOP] | ||
404 | str r1, [r0, #EMC_REFRESH] | ||
405 | |||
406 | emc_device_mask r1, r0 | ||
407 | |||
408 | exit_selfrefresh_loop: | ||
409 | ldr r2, [r0, #EMC_EMC_STATUS] | ||
410 | ands r2, r2, r1 | ||
411 | bne exit_selfrefresh_loop | ||
412 | |||
413 | lsr r1, r1, #8 @ devSel, bit0:dev0 bit1:dev1 | ||
414 | |||
415 | mov32 r7, TEGRA_TMRUS_BASE | ||
416 | ldr r2, [r0, #EMC_FBIO_CFG5] | ||
417 | |||
418 | and r2, r2, #3 | ||
419 | cmp r2, #2 | ||
420 | beq emc_lpddr2 | ||
421 | |||
422 | mov32 r2, 0x80000011 | ||
423 | str r2, [r0, #EMC_ZQ_CAL] | ||
424 | ldr r2, [r7] | ||
425 | add r2, r2, #10 | ||
426 | wait_until r2, r7, r3 | ||
427 | |||
428 | tst r1, #2 | ||
429 | beq zcal_done | ||
430 | |||
431 | mov32 r2, 0x40000011 | ||
432 | str r2, [r0, #EMC_ZQ_CAL] | ||
433 | ldr r2, [r7] | ||
434 | add r2, r2, #10 | ||
435 | wait_until r2, r7, r3 | ||
436 | b zcal_done | ||
437 | |||
438 | emc_lpddr2: | ||
439 | |||
440 | mov32 r2, 0x800A00AB | ||
441 | str r2, [r0, #EMC_MRW] | ||
442 | ldr r2, [r7] | ||
443 | add r2, r2, #1 | ||
444 | wait_until r2, r7, r3 | ||
445 | |||
446 | tst r1, #2 | ||
447 | beq zcal_done | ||
448 | |||
449 | mov32 r2, 0x400A00AB | ||
450 | str r2, [r0, #EMC_MRW] | ||
451 | ldr r2, [r7] | ||
452 | add r2, r2, #1 | ||
453 | wait_until r2, r7, r3 | ||
454 | |||
455 | zcal_done: | ||
456 | |||
457 | mov r1, #0 | ||
458 | str r1, [r0, #EMC_REQ_CTRL] | ||
459 | ldr r1, [r5, #0x4] | ||
460 | str r1, [r0, #EMC_ZCAL_INTERVAL] | ||
461 | ldr r1, [r5, #0x0] | ||
462 | str r1, [r0, #EMC_CFG] | ||
463 | |||
464 | mov32 r0, TEGRA_PMC_BASE | ||
465 | ldr r0, [r0, #PMC_SCRATCH41] | ||
466 | mov pc, r0 | ||
467 | ENDPROC(tegra3_lp1_reset) | ||
468 | |||
469 | .align L1_CACHE_SHIFT | ||
470 | .type tegra3_sdram_pad_save, %object | ||
471 | tegra3_sdram_pad_save: | ||
472 | .word 0 | ||
473 | .word 0 | ||
474 | .word 0 | ||
475 | .word 0 | ||
476 | .word 0 | ||
477 | .word 0 | ||
478 | .word 0 | ||
479 | .word 0 | ||
480 | |||
481 | tegra3_sdram_pad_address: | ||
482 | .word TEGRA_EMC_BASE + EMC_CFG @0x0 | ||
483 | .word TEGRA_EMC_BASE + EMC_ZCAL_INTERVAL @0x4 | ||
484 | .word TEGRA_EMC_BASE + EMC_AUTO_CAL_INTERVAL @0x8 | ||
485 | .word TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL @0xc | ||
486 | .word TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL2 @0x10 | ||
487 | .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 | ||
488 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 | ||
489 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c | ||
490 | |||
491 | tegra3_sdram_pad_size: | ||
492 | .word tegra3_sdram_pad_address - tegra3_sdram_pad_save | ||
493 | |||
494 | /* | ||
495 | * tegra3_tear_down_core | ||
496 | * | ||
497 | * copied into and executed from IRAM | ||
498 | * puts memory in self-refresh for LP0 and LP1 | ||
499 | */ | ||
500 | tegra3_tear_down_core: | ||
501 | bl tegra3_sdram_self_refresh | ||
502 | bl tegra3_cpu_clk32k | ||
503 | b tegra3_enter_sleep | ||
504 | |||
505 | /* | ||
506 | * tegra3_cpu_clk32k | ||
507 | * | ||
508 | * In LP0 and LP1 all plls will be turned off. Switch the CPU and system clock | ||
509 | * to the 32khz clock (clks) | ||
510 | * r4 = TEGRA_PMC_BASE | ||
511 | * r5 = TEGRA_CLK_RESET_BASE | ||
512 | * r6 = TEGRA_FLOW_CTRL_BASE | ||
513 | * r7 = TEGRA_TMRUS_BASE | ||
514 | */ | ||
515 | tegra3_cpu_clk32k: | ||
516 | ldr r0, [r4, #PMC_CTRL] | ||
517 | tst r0, #PMC_CTRL_SIDE_EFFECT_LP0 | ||
518 | beq lp1_clocks_prepare | ||
519 | |||
520 | /* enable PLLM via PMC in LP0 */ | ||
521 | ldr r0, [r4, #PMC_PLLP_WB0_OVERRIDE] | ||
522 | orr r0, r0, #((1<<12) | (1 << 11)) | ||
523 | str r0, [r4, #PMC_PLLP_WB0_OVERRIDE] | ||
524 | mov pc, lr | ||
525 | |||
526 | /* start by jumping to clkm to safely disable PLLs, then jump | ||
527 | * to clks */ | ||
528 | lp1_clocks_prepare: | ||
529 | mov r0, #(1 << 28) | ||
530 | str r0, [r5, #CLK_RESET_SCLK_BURST] | ||
531 | str r0, [r5, #CLK_RESET_CCLK_BURST] | ||
532 | mov r0, #0 | ||
533 | str r0, [r5, #CLK_RESET_CCLK_DIVIDER] | ||
534 | str r0, [r5, #CLK_RESET_SCLK_DIVIDER] | ||
535 | |||
536 | /* switch the clock source for mselect to be CLK_M */ | ||
537 | ldr r0, [r5, #CLK_RESET_CLK_SOURCE_MSELECT] | ||
538 | orr r0, r0, #MSELECT_CLKM | ||
539 | str r0, [r5, #CLK_RESET_CLK_SOURCE_MSELECT] | ||
540 | |||
541 | /* 2 us delay between changing sclk and disabling PLLs */ | ||
542 | wait_for_us r1, r7, r9 | ||
543 | add r1, r1, #2 | ||
544 | wait_until r1, r7, r9 | ||
545 | |||
546 | #if 1 | ||
547 | /* switch to CLKS */ | ||
548 | mov r0, #0 /* burst policy = 32KHz */ | ||
549 | str r0, [r5, #CLK_RESET_SCLK_BURST] | ||
550 | #endif | ||
551 | |||
552 | /* disable PLLM via PMC in LP1 */ | ||
553 | ldr r0, [r4, #PMC_PLLP_WB0_OVERRIDE] | ||
554 | bic r0, r0, #(1<<12) | ||
555 | str r0, [r4, #PMC_PLLP_WB0_OVERRIDE] | ||
556 | b powerdown_pll_pcx | ||
557 | |||
558 | powerdown_pll_pcx: | ||
559 | /* disable PLLP, PLLA, PLLC, and PLLX in LP0 and LP1 states */ | ||
560 | ldr r0, [r4, #PMC_CTRL] | ||
561 | tst r0, #PMC_CTRL_SIDE_EFFECT_LP0 | ||
562 | beq powerdown_pll_cx | ||
563 | ldr r0, [r5, #CLK_RESET_PLLP_BASE] | ||
564 | bic r0, r0, #(1<<30) | ||
565 | str r0, [r5, #CLK_RESET_PLLP_BASE] | ||
566 | ldr r0, [r5, #CLK_RESET_PLLA_BASE] | ||
567 | bic r0, r0, #(1<<30) | ||
568 | str r0, [r5, #CLK_RESET_PLLA_BASE] | ||
569 | powerdown_pll_cx: | ||
570 | ldr r0, [r5, #CLK_RESET_PLLC_BASE] | ||
571 | bic r0, r0, #(1<<30) | ||
572 | str r0, [r5, #CLK_RESET_PLLC_BASE] | ||
573 | ldr r0, [r5, #CLK_RESET_PLLX_BASE] | ||
574 | bic r0, r0, #(1<<30) | ||
575 | str r0, [r5, #CLK_RESET_PLLX_BASE] | ||
576 | |||
577 | mov pc, lr | ||
578 | |||
579 | /* | ||
580 | * tegra3_enter_sleep | ||
581 | * | ||
582 | * uses flow controller to enter sleep state | ||
583 | * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1 | ||
584 | * executes from SDRAM with target state is LP2 | ||
585 | * r4 = TEGRA_PMC_BASE | ||
586 | * r5 = TEGRA_CLK_RESET_BASE | ||
587 | * r6 = TEGRA_FLOW_CTRL_BASE | ||
588 | * r7 = TEGRA_TMRUS_BASE | ||
589 | */ | ||
590 | tegra3_enter_sleep: | ||
591 | ldr r1, [r7] | ||
592 | str r1, [r4, #PMC_SCRATCH38] | ||
593 | dsb | ||
594 | cpu_id r1 | ||
595 | |||
596 | cpu_to_csr_reg r2, r1 | ||
597 | ldr r0, [r6, r2] | ||
598 | orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | ||
599 | orr r0, r0, #FLOW_CTRL_CSR_ENABLE | ||
600 | str r0, [r6, r2] | ||
601 | |||
602 | mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT | ||
603 | orr r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ | ||
604 | cpu_to_halt_reg r2, r1 | ||
605 | str r0, [r6, r2] | ||
606 | dsb | ||
607 | ldr r0, [r6, r2] /* memory barrier */ | ||
608 | |||
609 | halted: | ||
610 | isb | ||
611 | dsb | ||
612 | wfi /* CPU should be power gated here */ | ||
613 | |||
614 | /* !!!FIXME!!! Implement halt failure handler */ | ||
615 | b halted | ||
616 | |||
617 | /* | ||
618 | * tegra3_sdram_self_refresh | ||
619 | * | ||
620 | * called with MMU off and caches disabled | ||
621 | /* puts sdram in self refresh | ||
622 | * must execute from IRAM | ||
623 | * r4 = TEGRA_PMC_BASE | ||
624 | * r5 = TEGRA_CLK_RESET_BASE | ||
625 | * r6 = TEGRA_FLOW_CTRL_BASE | ||
626 | * r7 = TEGRA_TMRUS_BASE | ||
627 | */ | ||
628 | |||
629 | tegra3_sdram_self_refresh: | ||
630 | |||
631 | adr r2, tegra3_sdram_pad_address | ||
632 | adr r8, tegra3_sdram_pad_save | ||
633 | mov r9, #0 | ||
634 | |||
635 | padsave: | ||
636 | ldr r0, [r2, r9] @ r0 is emc register address | ||
637 | |||
638 | ldr r1, [r0] | ||
639 | str r1, [r8, r9] @ save emc register | ||
640 | |||
641 | add r9, r9, #4 | ||
642 | ldr r0, tegra3_sdram_pad_size | ||
643 | cmp r0, r9 | ||
644 | bne padsave | ||
645 | padsave_done: | ||
646 | |||
647 | dsb | ||
648 | |||
649 | mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base | ||
650 | |||
651 | mov r1, #0 | ||
652 | str r1, [r0, #EMC_ZCAL_INTERVAL] | ||
653 | str r1, [r0, #EMC_AUTO_CAL_INTERVAL] | ||
654 | ldr r1, [r0, #EMC_CFG] | ||
655 | bic r1, r1, #(1<<28) | ||
656 | str r1, [r0, #EMC_CFG] @ disable DYN_SELF_REF | ||
657 | |||
658 | emc_timing_update r1, r0 | ||
659 | |||
660 | ldr r1, [r7] | ||
661 | add r1, r1, #5 | ||
662 | wait_until r1, r7, r2 | ||
663 | |||
664 | emc_wait_audo_cal: | ||
665 | ldr r1, [r0, #EMC_AUTO_CAL_STATUS] | ||
666 | tst r1, #(0x1<<31) @ wait until AUTO_CAL_ACTIVE is clear | ||
667 | bne emc_wait_audo_cal | ||
668 | |||
669 | mov r1, #3 | ||
670 | str r1, [r0, #EMC_REQ_CTRL] @ stall incoming DRAM requests | ||
671 | |||
672 | emcidle: | ||
673 | ldr r1, [r0, #EMC_EMC_STATUS] | ||
674 | tst r1, #4 | ||
675 | beq emcidle | ||
676 | |||
677 | mov r1, #1 | ||
678 | str r1, [r0, #EMC_SELF_REF] | ||
679 | |||
680 | emc_device_mask r1, r0 | ||
681 | |||
682 | emcself: | ||
683 | ldr r2, [r0, #EMC_EMC_STATUS] | ||
684 | and r2, r2, r1 | ||
685 | cmp r2, r1 | ||
686 | bne emcself @ loop until DDR in self-refresh | ||
687 | |||
688 | ldr r1, [r0, #EMC_XM2VTTGENPADCTRL] | ||
689 | mov32 r2, 0xF8F8FFFF @ clear XM2VTTGEN_DRVUP and XM2VTTGEN_DRVDN | ||
690 | and r1, r1, r2 | ||
691 | str r1, [r0, #EMC_XM2VTTGENPADCTRL] | ||
692 | ldr r1, [r0, #EMC_XM2VTTGENPADCTRL2] | ||
693 | orr r1, r1, #7 @ set E_NO_VTTGEN | ||
694 | str r1, [r0, #EMC_XM2VTTGENPADCTRL2] | ||
695 | |||
696 | emc_timing_update r1, r0 | ||
697 | |||
698 | ldr r1, [r4, #PMC_CTRL] | ||
699 | tst r1, #PMC_CTRL_SIDE_EFFECT_LP0 | ||
700 | bne pmc_io_dpd_skip | ||
701 | mov32 r1, 0x8EC00000 | ||
702 | str r1, [r4, #PMC_IO_DPD_REQ] | ||
703 | pmc_io_dpd_skip: | ||
704 | |||
705 | dsb | ||
706 | |||
707 | mov pc, lr | ||
708 | |||
709 | .ltorg | ||
710 | /* dummy symbol for end of IRAM */ | ||
711 | .align L1_CACHE_SHIFT | ||
712 | .globl tegra3_iram_end | ||
713 | tegra3_iram_end: | ||
714 | b . | ||
715 | #endif | ||