Version:  2.0.40 2.2.26 2.4.37 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8

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_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 was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us