Version:  2.0.40 2.2.26 2.4.37 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us