]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/arm/mach-tegra/sleep-tegra20.S
Merge remote-tracking branch 'idle/next'
[karo-tx-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