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