Merge tag 'v3.12'
[deliverable/linux.git] / arch / arm / mach-tegra / sleep-tegra20.S
1 /*
2 * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
3 * Copyright (c) 2011, Google, Inc.
4 *
5 * Author: Colin Cross <ccross@android.com>
6 * Gary King <gking@nvidia.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <linux/linkage.h>
22
23 #include <asm/assembler.h>
24 #include <asm/proc-fns.h>
25 #include <asm/cp15.h>
26 #include <asm/cache.h>
27
28 #include "sleep.h"
29 #include "flowctrl.h"
30
31 #define EMC_CFG 0xc
32 #define EMC_ADR_CFG 0x10
33 #define EMC_REFRESH 0x70
34 #define EMC_NOP 0xdc
35 #define EMC_SELF_REF 0xe0
36 #define EMC_REQ_CTRL 0x2b0
37 #define EMC_EMC_STATUS 0x2b4
38
39 #define CLK_RESET_CCLK_BURST 0x20
40 #define CLK_RESET_CCLK_DIVIDER 0x24
41 #define CLK_RESET_SCLK_BURST 0x28
42 #define CLK_RESET_SCLK_DIVIDER 0x2c
43 #define CLK_RESET_PLLC_BASE 0x80
44 #define CLK_RESET_PLLM_BASE 0x90
45 #define CLK_RESET_PLLP_BASE 0xa0
46
47 #define APB_MISC_XM2CFGCPADCTRL 0x8c8
48 #define APB_MISC_XM2CFGDPADCTRL 0x8cc
49 #define APB_MISC_XM2CLKCFGPADCTRL 0x8d0
50 #define APB_MISC_XM2COMPPADCTRL 0x8d4
51 #define APB_MISC_XM2VTTGENPADCTRL 0x8d8
52 #define APB_MISC_XM2CFGCPADCTRL2 0x8e4
53 #define APB_MISC_XM2CFGDPADCTRL2 0x8e8
54
55 .macro pll_enable, rd, r_car_base, pll_base
56 ldr \rd, [\r_car_base, #\pll_base]
57 tst \rd, #(1 << 30)
58 orreq \rd, \rd, #(1 << 30)
59 streq \rd, [\r_car_base, #\pll_base]
60 .endm
61
62 .macro emc_device_mask, rd, base
63 ldr \rd, [\base, #EMC_ADR_CFG]
64 tst \rd, #(0x3 << 24)
65 moveq \rd, #(0x1 << 8) @ just 1 device
66 movne \rd, #(0x3 << 8) @ 2 devices
67 .endm
68
69 #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
70 /*
71 * tegra20_hotplug_shutdown(void)
72 *
73 * puts the current cpu in reset
74 * should never return
75 */
76 ENTRY(tegra20_hotplug_shutdown)
77 /* Put this CPU down */
78 cpu_id r0
79 bl tegra20_cpu_shutdown
80 mov pc, lr @ should never get here
81 ENDPROC(tegra20_hotplug_shutdown)
82
83 /*
84 * tegra20_cpu_shutdown(int cpu)
85 *
86 * r0 is cpu to reset
87 *
88 * puts the specified CPU in wait-for-event mode on the flow controller
89 * and puts the CPU in reset
90 * can be called on the current cpu or another cpu
91 * if called on the current cpu, does not return
92 * MUST NOT BE CALLED FOR CPU 0.
93 *
94 * corrupts r0-r3, r12
95 */
96 ENTRY(tegra20_cpu_shutdown)
97 cmp r0, #0
98 moveq pc, lr @ must not be called for CPU 0
99 mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
100 mov r12, #CPU_RESETTABLE
101 str r12, [r1]
102
103 cpu_to_halt_reg r1, r0
104 ldr r3, =TEGRA_FLOW_CTRL_VIRT
105 mov r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
106 str r2, [r3, r1] @ put flow controller in wait event mode
107 ldr r2, [r3, r1]
108 isb
109 dsb
110 movw r1, 0x1011
111 mov r1, r1, lsl r0
112 ldr r3, =TEGRA_CLK_RESET_VIRT
113 str r1, [r3, #0x340] @ put slave CPU in reset
114 isb
115 dsb
116 cpu_id r3
117 cmp r3, r0
118 beq .
119 mov pc, lr
120 ENDPROC(tegra20_cpu_shutdown)
121 #endif
122
123 #ifdef CONFIG_PM_SLEEP
124 /*
125 * tegra_pen_lock
126 *
127 * spinlock implementation with no atomic test-and-set and no coherence
128 * using Peterson's algorithm on strongly-ordered registers
129 * used to synchronize a cpu waking up from wfi with entering lp2 on idle
130 *
131 * The reference link of Peterson's algorithm:
132 * http://en.wikipedia.org/wiki/Peterson's_algorithm
133 *
134 * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
135 * on cpu 0:
136 * r2 = flag[0] (in SCRATCH38)
137 * r3 = flag[1] (in SCRATCH39)
138 * on cpu1:
139 * r2 = flag[1] (in SCRATCH39)
140 * r3 = flag[0] (in SCRATCH38)
141 *
142 * must be called with MMU on
143 * corrupts r0-r3, r12
144 */
145 ENTRY(tegra_pen_lock)
146 mov32 r3, TEGRA_PMC_VIRT
147 cpu_id r0
148 add r1, r3, #PMC_SCRATCH37
149 cmp r0, #0
150 addeq r2, r3, #PMC_SCRATCH38
151 addeq r3, r3, #PMC_SCRATCH39
152 addne r2, r3, #PMC_SCRATCH39
153 addne r3, r3, #PMC_SCRATCH38
154
155 mov r12, #1
156 str r12, [r2] @ flag[cpu] = 1
157 dsb
158 str r12, [r1] @ !turn = cpu
159 1: dsb
160 ldr r12, [r3]
161 cmp r12, #1 @ flag[!cpu] == 1?
162 ldreq r12, [r1]
163 cmpeq r12, r0 @ !turn == cpu?
164 beq 1b @ while !turn == cpu && flag[!cpu] == 1
165
166 mov pc, lr @ locked
167 ENDPROC(tegra_pen_lock)
168
169 ENTRY(tegra_pen_unlock)
170 dsb
171 mov32 r3, TEGRA_PMC_VIRT
172 cpu_id r0
173 cmp r0, #0
174 addeq r2, r3, #PMC_SCRATCH38
175 addne r2, r3, #PMC_SCRATCH39
176 mov r12, #0
177 str r12, [r2]
178 mov pc, lr
179 ENDPROC(tegra_pen_unlock)
180
181 /*
182 * tegra20_cpu_clear_resettable(void)
183 *
184 * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when
185 * it is expected that the secondary CPU will be idle soon.
186 */
187 ENTRY(tegra20_cpu_clear_resettable)
188 mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
189 mov r12, #CPU_NOT_RESETTABLE
190 str r12, [r1]
191 mov pc, lr
192 ENDPROC(tegra20_cpu_clear_resettable)
193
194 /*
195 * tegra20_cpu_set_resettable_soon(void)
196 *
197 * Called to set the "resettable soon" flag in PMC_SCRATCH41 when
198 * it is expected that the secondary CPU will be idle soon.
199 */
200 ENTRY(tegra20_cpu_set_resettable_soon)
201 mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
202 mov r12, #CPU_RESETTABLE_SOON
203 str r12, [r1]
204 mov pc, lr
205 ENDPROC(tegra20_cpu_set_resettable_soon)
206
207 /*
208 * tegra20_cpu_is_resettable_soon(void)
209 *
210 * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been
211 * set because it is expected that the secondary CPU will be idle soon.
212 */
213 ENTRY(tegra20_cpu_is_resettable_soon)
214 mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
215 ldr r12, [r1]
216 cmp r12, #CPU_RESETTABLE_SOON
217 moveq r0, #1
218 movne r0, #0
219 mov pc, lr
220 ENDPROC(tegra20_cpu_is_resettable_soon)
221
222 /*
223 * tegra20_sleep_core_finish(unsigned long v2p)
224 *
225 * Enters suspend in LP0 or LP1 by turning off the mmu and jumping to
226 * tegra20_tear_down_core in IRAM
227 */
228 ENTRY(tegra20_sleep_core_finish)
229 /* Flush, disable the L1 data cache and exit SMP */
230 bl tegra_disable_clean_inv_dcache
231
232 mov32 r3, tegra_shut_off_mmu
233 add r3, r3, r0
234
235 mov32 r0, tegra20_tear_down_core
236 mov32 r1, tegra20_iram_start
237 sub r0, r0, r1
238 mov32 r1, TEGRA_IRAM_CODE_AREA
239 add r0, r0, r1
240
241 mov pc, r3
242 ENDPROC(tegra20_sleep_core_finish)
243
244 /*
245 * tegra20_sleep_cpu_secondary_finish(unsigned long v2p)
246 *
247 * Enters WFI on secondary CPU by exiting coherency.
248 */
249 ENTRY(tegra20_sleep_cpu_secondary_finish)
250 stmfd sp!, {r4-r11, lr}
251
252 mrc p15, 0, r11, c1, c0, 1 @ save actlr before exiting coherency
253
254 /* Flush and disable the L1 data cache */
255 mov r0, #TEGRA_FLUSH_CACHE_LOUIS
256 bl tegra_disable_clean_inv_dcache
257
258 mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
259 mov r3, #CPU_RESETTABLE
260 str r3, [r0]
261
262 bl tegra_cpu_do_idle
263
264 /*
265 * cpu may be reset while in wfi, which will return through
266 * tegra_resume to cpu_resume
267 * or interrupt may wake wfi, which will return here
268 * cpu state is unchanged - MMU is on, cache is on, coherency
269 * is off, and the data cache is off
270 *
271 * r11 contains the original actlr
272 */
273
274 bl tegra_pen_lock
275
276 mov32 r3, TEGRA_PMC_VIRT
277 add r0, r3, #PMC_SCRATCH41
278 mov r3, #CPU_NOT_RESETTABLE
279 str r3, [r0]
280
281 bl tegra_pen_unlock
282
283 /* Re-enable the data cache */
284 mrc p15, 0, r10, c1, c0, 0
285 orr r10, r10, #CR_C
286 mcr p15, 0, r10, c1, c0, 0
287 isb
288
289 mcr p15, 0, r11, c1, c0, 1 @ reenable coherency
290
291 /* Invalidate the TLBs & BTAC */
292 mov r1, #0
293 mcr p15, 0, r1, c8, c3, 0 @ invalidate shared TLBs
294 mcr p15, 0, r1, c7, c1, 6 @ invalidate shared BTAC
295 dsb
296 isb
297
298 /* the cpu was running with coherency disabled,
299 * caches may be out of date */
300 bl v7_flush_kern_cache_louis
301
302 ldmfd sp!, {r4 - r11, pc}
303 ENDPROC(tegra20_sleep_cpu_secondary_finish)
304
305 /*
306 * tegra20_tear_down_cpu
307 *
308 * Switches the CPU cluster to PLL-P and enters sleep.
309 */
310 ENTRY(tegra20_tear_down_cpu)
311 bl tegra_switch_cpu_to_pllp
312 b tegra20_enter_sleep
313 ENDPROC(tegra20_tear_down_cpu)
314
315 /* START OF ROUTINES COPIED TO IRAM */
316 .align L1_CACHE_SHIFT
317 .globl tegra20_iram_start
318 tegra20_iram_start:
319
320 /*
321 * tegra20_lp1_reset
322 *
323 * reset vector for LP1 restore; copied into IRAM during suspend.
324 * Brings the system back up to a safe staring point (SDRAM out of
325 * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLP,
326 * system clock running on the same PLL that it suspended at), and
327 * jumps to tegra_resume to restore virtual addressing and PLLX.
328 * The physical address of tegra_resume expected to be stored in
329 * PMC_SCRATCH41.
330 *
331 * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_CODE_AREA.
332 */
333 ENTRY(tegra20_lp1_reset)
334 /*
335 * The CPU and system bus are running at 32KHz and executing from
336 * IRAM when this code is executed; immediately switch to CLKM and
337 * enable PLLM, PLLP, PLLC.
338 */
339 mov32 r0, TEGRA_CLK_RESET_BASE
340
341 mov r1, #(1 << 28)
342 str r1, [r0, #CLK_RESET_SCLK_BURST]
343 str r1, [r0, #CLK_RESET_CCLK_BURST]
344 mov r1, #0
345 str r1, [r0, #CLK_RESET_CCLK_DIVIDER]
346 str r1, [r0, #CLK_RESET_SCLK_DIVIDER]
347
348 pll_enable r1, r0, CLK_RESET_PLLM_BASE
349 pll_enable r1, r0, CLK_RESET_PLLP_BASE
350 pll_enable r1, r0, CLK_RESET_PLLC_BASE
351
352 adr r2, tegra20_sdram_pad_address
353 adr r4, tegra20_sdram_pad_save
354 mov r5, #0
355
356 ldr r6, tegra20_sdram_pad_size
357 padload:
358 ldr r7, [r2, r5] @ r7 is the addr in the pad_address
359
360 ldr r1, [r4, r5]
361 str r1, [r7] @ restore the value in pad_save
362
363 add r5, r5, #4
364 cmp r6, r5
365 bne padload
366
367 padload_done:
368 /* 255uS delay for PLL stabilization */
369 mov32 r7, TEGRA_TMRUS_BASE
370 ldr r1, [r7]
371 add r1, r1, #0xff
372 wait_until r1, r7, r9
373
374 adr r4, tegra20_sclk_save
375 ldr r4, [r4]
376 str r4, [r0, #CLK_RESET_SCLK_BURST]
377 mov32 r4, ((1 << 28) | (4)) @ burst policy is PLLP
378 str r4, [r0, #CLK_RESET_CCLK_BURST]
379
380 mov32 r0, TEGRA_EMC_BASE
381 ldr r1, [r0, #EMC_CFG]
382 bic r1, r1, #(1 << 31) @ disable DRAM_CLK_STOP
383 str r1, [r0, #EMC_CFG]
384
385 mov r1, #0
386 str r1, [r0, #EMC_SELF_REF] @ take DRAM out of self refresh
387 mov r1, #1
388 str r1, [r0, #EMC_NOP]
389 str r1, [r0, #EMC_NOP]
390 str r1, [r0, #EMC_REFRESH]
391
392 emc_device_mask r1, r0
393
394 exit_selfrefresh_loop:
395 ldr r2, [r0, #EMC_EMC_STATUS]
396 ands r2, r2, r1
397 bne exit_selfrefresh_loop
398
399 mov r1, #0 @ unstall all transactions
400 str r1, [r0, #EMC_REQ_CTRL]
401
402 mov32 r0, TEGRA_PMC_BASE
403 ldr r0, [r0, #PMC_SCRATCH41]
404 mov pc, r0 @ jump to tegra_resume
405 ENDPROC(tegra20_lp1_reset)
406
407 /*
408 * tegra20_tear_down_core
409 *
410 * copied into and executed from IRAM
411 * puts memory in self-refresh for LP0 and LP1
412 */
413 tegra20_tear_down_core:
414 bl tegra20_sdram_self_refresh
415 bl tegra20_switch_cpu_to_clk32k
416 b tegra20_enter_sleep
417
418 /*
419 * tegra20_switch_cpu_to_clk32k
420 *
421 * In LP0 and LP1 all PLLs will be turned off. Switch the CPU and system clock
422 * to the 32KHz clock.
423 */
424 tegra20_switch_cpu_to_clk32k:
425 /*
426 * start by switching to CLKM to safely disable PLLs, then switch to
427 * CLKS.
428 */
429 mov r0, #(1 << 28)
430 str r0, [r5, #CLK_RESET_SCLK_BURST]
431 str r0, [r5, #CLK_RESET_CCLK_BURST]
432 mov r0, #0
433 str r0, [r5, #CLK_RESET_CCLK_DIVIDER]
434 str r0, [r5, #CLK_RESET_SCLK_DIVIDER]
435
436 /* 2uS delay delay between changing SCLK and disabling PLLs */
437 mov32 r7, TEGRA_TMRUS_BASE
438 ldr r1, [r7]
439 add r1, r1, #2
440 wait_until r1, r7, r9
441
442 /* disable PLLM, PLLP and PLLC */
443 ldr r0, [r5, #CLK_RESET_PLLM_BASE]
444 bic r0, r0, #(1 << 30)
445 str r0, [r5, #CLK_RESET_PLLM_BASE]
446 ldr r0, [r5, #CLK_RESET_PLLP_BASE]
447 bic r0, r0, #(1 << 30)
448 str r0, [r5, #CLK_RESET_PLLP_BASE]
449 ldr r0, [r5, #CLK_RESET_PLLC_BASE]
450 bic r0, r0, #(1 << 30)
451 str r0, [r5, #CLK_RESET_PLLC_BASE]
452
453 /* switch to CLKS */
454 mov r0, #0 /* brust policy = 32KHz */
455 str r0, [r5, #CLK_RESET_SCLK_BURST]
456
457 mov pc, lr
458
459 /*
460 * tegra20_enter_sleep
461 *
462 * uses flow controller to enter sleep state
463 * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
464 * executes from SDRAM with target state is LP2
465 */
466 tegra20_enter_sleep:
467 mov32 r6, TEGRA_FLOW_CTRL_BASE
468
469 mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
470 orr r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
471 cpu_id r1
472 cpu_to_halt_reg r1, r1
473 str r0, [r6, r1]
474 dsb
475 ldr r0, [r6, r1] /* memory barrier */
476
477 halted:
478 dsb
479 wfe /* CPU should be power gated here */
480 isb
481 b halted
482
483 /*
484 * tegra20_sdram_self_refresh
485 *
486 * called with MMU off and caches disabled
487 * puts sdram in self refresh
488 * must be executed from IRAM
489 */
490 tegra20_sdram_self_refresh:
491 mov32 r1, TEGRA_EMC_BASE @ r1 reserved for emc base addr
492
493 mov r2, #3
494 str r2, [r1, #EMC_REQ_CTRL] @ stall incoming DRAM requests
495
496 emcidle:
497 ldr r2, [r1, #EMC_EMC_STATUS]
498 tst r2, #4
499 beq emcidle
500
501 mov r2, #1
502 str r2, [r1, #EMC_SELF_REF]
503
504 emc_device_mask r2, r1
505
506 emcself:
507 ldr r3, [r1, #EMC_EMC_STATUS]
508 and r3, r3, r2
509 cmp r3, r2
510 bne emcself @ loop until DDR in self-refresh
511
512 adr r2, tegra20_sdram_pad_address
513 adr r3, tegra20_sdram_pad_safe
514 adr r4, tegra20_sdram_pad_save
515 mov r5, #0
516
517 ldr r6, tegra20_sdram_pad_size
518 padsave:
519 ldr r0, [r2, r5] @ r0 is the addr in the pad_address
520
521 ldr r1, [r0]
522 str r1, [r4, r5] @ save the content of the addr
523
524 ldr r1, [r3, r5]
525 str r1, [r0] @ set the save val to the addr
526
527 add r5, r5, #4
528 cmp r6, r5
529 bne padsave
530 padsave_done:
531
532 mov32 r5, TEGRA_CLK_RESET_BASE
533 ldr r0, [r5, #CLK_RESET_SCLK_BURST]
534 adr r2, tegra20_sclk_save
535 str r0, [r2]
536 dsb
537 mov pc, lr
538
539 tegra20_sdram_pad_address:
540 .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL
541 .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL
542 .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CLKCFGPADCTRL
543 .word TEGRA_APB_MISC_BASE + APB_MISC_XM2COMPPADCTRL
544 .word TEGRA_APB_MISC_BASE + APB_MISC_XM2VTTGENPADCTRL
545 .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL2
546 .word TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL2
547
548 tegra20_sdram_pad_size:
549 .word tegra20_sdram_pad_size - tegra20_sdram_pad_address
550
551 tegra20_sdram_pad_safe:
552 .word 0x8
553 .word 0x8
554 .word 0x0
555 .word 0x8
556 .word 0x5500
557 .word 0x08080040
558 .word 0x0
559
560 tegra20_sclk_save:
561 .word 0x0
562
563 tegra20_sdram_pad_save:
564 .rept (tegra20_sdram_pad_size - tegra20_sdram_pad_address) / 4
565 .long 0
566 .endr
567
568 .ltorg
569 /* dummy symbol for end of IRAM */
570 .align L1_CACHE_SHIFT
571 .globl tegra20_iram_end
572 tegra20_iram_end:
573 b .
574 #endif
This page took 0.048588 seconds and 6 git commands to generate.