aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/sleep.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/sleep.S')
-rw-r--r--arch/arm/mach-tegra/sleep.S467
1 files changed, 467 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
new file mode 100644
index 00000000000..973c8677baf
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep.S
@@ -0,0 +1,467 @@
1/*
2 * arch/arm/mach-tegra/sleep.S
3 *
4 * Copyright (c) 2010-2011, NVIDIA Corporation.
5 * Copyright (c) 2011, Google, Inc.
6 *
7 * Author: Colin Cross <ccross@android.com>
8 * Gary King <gking@nvidia.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25#include <linux/const.h>
26#include <linux/init.h>
27#include <linux/linkage.h>
28
29#include <asm/assembler.h>
30#include <asm/cache.h>
31#include <asm/domain.h>
32#include <asm/memory.h>
33#include <asm/page.h>
34#include <asm/ptrace.h>
35#include <asm/asm-offsets.h>
36#include <asm/glue-cache.h>
37#include <asm/glue-proc.h>
38#include <asm/system.h>
39
40#include <mach/iomap.h>
41#include <mach/io.h>
42
43#include "asm_macros.h"
44#include "sleep.h"
45
46#define CLK_RESET_CCLK_BURST 0x20
47#define CLK_RESET_CCLK_DIVIDER 0x24
48
49#define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
50#define TEGRA_CLK_RESET_VIRT (TEGRA_CLK_RESET_BASE - IO_PPSB_PHYS + IO_PPSB_VIRT)
51
52/*
53 * tegra_pen_lock
54 *
55 * spinlock implementation with no atomic test-and-set and no coherence
56 * using Peterson's algorithm on strongly-ordered registers
57 * used to synchronize a cpu waking up from wfi with entering lp2 on idle
58 *
59 * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
60 * on cpu 0:
61 * SCRATCH38 = r2 = flag[0]
62 * SCRATCH39 = r3 = flag[1]
63 * on cpu1:
64 * SCRATCH39 = r2 = flag[1]
65 * SCRATCH38 = r3 = flag[0]
66 *
67 * must be called with MMU on
68 * corrupts r0-r3, r12
69 */
70ENTRY(tegra_pen_lock)
71 mov32 r3, TEGRA_PMC_VIRT
72 cpu_id r0
73 add r1, r3, #PMC_SCRATCH37
74 cmp r0, #0
75 addeq r2, r3, #PMC_SCRATCH38
76 addeq r3, r3, #PMC_SCRATCH39
77 addne r2, r3, #PMC_SCRATCH39
78 addne r3, r3, #PMC_SCRATCH38
79
80 mov r12, #1
81 str r12, [r2] @ flag[cpu] = 1
82 dsb
83 str r12, [r1] @ !turn = cpu
841: dsb
85 ldr r12, [r3]
86 cmp r12, #1 @ flag[!cpu] == 1?
87 ldreq r12, [r1]
88 cmpeq r12, r0 @ !turn == cpu?
89 beq 1b @ while !turn == cpu && flag[!cpu] == 1
90
91 mov pc, lr @ locked
92ENDPROC(tegra_pen_lock)
93
94ENTRY(tegra_pen_unlock)
95 dsb
96 mov32 r3, TEGRA_PMC_VIRT
97 cpu_id r0
98 cmp r0, #0
99 addeq r2, r3, #PMC_SCRATCH38
100 addne r2, r3, #PMC_SCRATCH39
101 mov r12, #0
102 str r12, [r2]
103 mov pc, lr
104ENDPROC(tegra_pen_unlock)
105
106/*
107 * tegra_cpu_wfi
108 *
109 * puts current CPU in wfi
110 * CPU core clock-gates itself during wfi
111 *
112 * corrupts r0-r3
113 * must be called with MMU on
114 */
115ENTRY(tegra_cpu_wfi)
116 dsb
117 wfi
118 mov pc, lr
119ENDPROC(tegra_cpu_wfi)
120
121/*
122 * tegra_cpu_exit_coherency
123 *
124 * Exits SMP coherency.
125 * corrupts r4-r5
126 */
127ENTRY(tegra_cpu_exit_coherency)
128 exit_smp r4, r5
129 mov pc, lr
130ENDPROC(tegra_cpu_exit_coherency)
131
132#ifdef CONFIG_PM_SLEEP
133/*
134 * Restore CPU state for a suspend
135 *
136 * NOTE: This is a copy of cpu_resume in arch/arm/sleep.S that has been
137 * modified to work with an L2 cache.
138 */
139 .align L1_CACHE_SHIFT
140ENTRY(tegra_cpu_resume_phys)
141#if USE_TEGRA_CPU_SUSPEND
142#ifdef CONFIG_SMP
143 adr r0, tegra_phys_sleep_sp
144 ALT_SMP(mrc p15, 0, r1, c0, c0, 5)
145 ALT_UP(mov r1, #0)
146 and r1, r1, #15
147 ldr r0, [r0, r1, lsl #2] @ stack phys addr
148#else
149 ldr r0, tegra_phys_sleep_sp @ stack phys addr
150#endif
151 setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off
152 @ load v:p, stack, resume fn
153 ARM( ldmia r0!, {r1, sp, pc} )
154THUMB( ldmia r0!, {r1, r2, r3} )
155THUMB( mov sp, r2 )
156THUMB( bx r3 )
157#else
158 /* Use the standard cpu_resume. */
159 b cpu_resume
160#endif
161ENDPROC(tegra_cpu_resume_phys)
162
163#if USE_TEGRA_CPU_SUSPEND
164tegra_phys_sleep_sp:
165 .rept 4
166 .long 0 @ preserve stack phys ptr here
167 .endr
168#endif
169
170/*
171 * tegra_cpu_suspend
172 *
173 * Save CPU suspend state
174 * NOTE: This is a copy of cpu_suspend in arch/arm/sleep.S that has been
175 * modified to work with an L2 cache.
176 *
177 * Input:
178 * r1 = v:p offset
179 * lr = return to the caller of this function
180 * Output:
181 * sp is decremented to allocate space for CPU state on stack
182 * r0-r3,r8,r9,ip,lr corrupted
183 */
184 .align L1_CACHE_SHIFT
185ENTRY(tegra_cpu_suspend)
186 mov r9, lr
187 adr lr, tegra_cpu_resume
188#if USE_TEGRA_CPU_SUSPEND
189 stmfd sp!, {r4 - r11, lr}
190#ifdef MULTI_CPU
191 mov32 r10, processor
192 ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
193 ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function
194#else
195 mov32 r5, cpu_suspend_size
196 mov32 ip, cpu_do_resume
197#endif
198 mov r6, sp @ current virtual SP
199 sub sp, sp, r5 @ allocate CPU state on stack
200 mov r0, sp @ save pointer to CPU save block
201 add ip, ip, r1 @ convert resume fn to phys
202 stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn
203
204#ifdef MULTI_CPU
205 mov lr, pc
206 ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state
207#else
208 bl cpu_do_suspend
209#endif
210 dsb
211
212 /* Disable the data cache */
213 mrc p15, 0, r10, c1, c0, 0
214 bic r10, r10, #CR_C
215 dsb
216 mcr p15, 0, r10, c1, c0, 0
217 isb
218
219 /* Flush data cache */
220#ifdef MULTI_CACHE
221 mov32 r10, cpu_cache
222 mov lr, pc
223 ldr pc, [r10, #CACHE_FLUSH_KERN_ALL]
224#else
225 bl __cpuc_flush_kern_all
226#endif
227#ifdef CONFIG_CACHE_L2X0
228#ifdef CONFIG_ARCH_TEGRA_2x_SOC
229 cpu_id r2
230 cmp r2, #0
231 bne no_l2_sync
232#endif
233 /* Issue a PL310 cache sync operation */
234 dsb
235 mov32 r2, TEGRA_PL310_VIRT
236 movw r1, 0x730 @ cache sync
237 add r2, r2, r1
238 mov r1, #0
239 str r1, [r2]
240#endif
241
242no_l2_sync:
243 /* Invalidate the TLBs & BTAC */
244 mov r1, #0
245 mcr p15, 0, r1, c8, c3, 0 @ invalidate shared TLBs
246 mcr p15, 0, r1, c7, c1, 6 @ invalidate shared BTAC
247 dsb
248 isb
249
250 /* Turn off SMP coherency */
251 exit_smp r1, r2
252
253 /* Convert SP from virtual to physical address. */
254 movw r1, #0xFFF
255 bic r2, sp, r1 @ VA & 0xFFFFF000
256 mcr p15, 0, r2, c7, c8, 0 @ V2PPRPC
257 mrc p15, 0, r2, c7, c4, 0 @ PAR
258 bic r2, r2, r1 @ PA & 0xFFFFF000
259 and r0, sp, r1 @ VA & 0x00000FFF
260 orr r2, r0, r2 @ (PA & 0xFFFFF000) | (VA & 0x00000FFF)
261
262 mov32 r3, tegra_phys_sleep_sp @ per-CPU phys SP save area
263
264#ifdef CONFIG_SMP
265 ALT_SMP(mrc p15, 0, lr, c0, c0, 5)
266 ALT_UP(mov lr, #0)
267 and lr, lr, #15
268#else
269 mov lr, #0
270#endif
271
272 /* Save the normal PRRR value */
273 mrc p15, 0, r0, c10, c2, 0 @ PRRR
274
275 /* Override all remappings to strongly ordered */
276 mov r1, #0
277 mcr p15, 0, r1, c10, c2, 0 @ PRRR
278 mcr p15, 0, r1, c8, c7, 0 @ invalidate local TLBs
279 dsb
280 isb
281
282 /* Save the physical stack pointer */
283 str r2, [r3, lr, lsl #2] @ save phys SP
284
285 /* Restore the regular remappings */
286 mcr p15, 0, r0, c10, c2, 0 @ PRRR
287 mcr p15, 0, r1, c8, c7, 0 @ invalidate local TLBs
288 dsb
289 isb
290#else
291 /* Use the standard cpu_suspend. */
292 adr r3, BSYM(tegra_finish_suspend)
293 b __cpu_suspend
294
295tegra_finish_suspend:
296 /* Turn off SMP coherency */
297 exit_smp r1, r6
298#endif
299 mov pc, r9
300ENDPROC(tegra_cpu_suspend)
301
302/*
303 * tegra_cpu_save
304 *
305 * Input:
306 * r0 = v:p offset
307 * r12 = return to the caller of this function
308 * Output:
309 * r0 = v:p offset
310 * r7 = SP after saving the registers but before cpu_suspend, suitable
311 * for restoring an aborted suspend
312 * sp = SP after tegra_cpu_suspend (the 'real' SP)
313 * Saves r4-r11 on the stack
314 * Corrupts r1, r3-r11
315 */
316
317ENTRY(tegra_cpu_save)
318 push_ctx_regs r1 @ save context registers
319
320 mov r7, sp @ SP after reg save, before suspend
321
322#if USE_TEGRA_CPU_SUSPEND
323 cpu_id r4
324 mov32 r5, tegra_cpu_context @ address of non-cacheable context page
325 ldr r5, [r5] @ non-cacheable context save area
326 mov r6, #0x400 @ size of one CPU context stack area
327 add r4, r4, #1
328 smlabb sp, r6, r4, r5 @ context area for this CPU
329 push_stack_token r4 @ debug check word
330 stmfd sp!, {r7} @ save the real stack pointer
331 push_stack_token r4 @ debug check word
332#endif
333
334 mov r4, r12
335 mov r8, r0
336 mov r11, r2
337 mov r1, r0
338 bl tegra_cpu_suspend
339 mov r0, r8
340 mov r2, r11
341 mov pc, r4
342ENDPROC(tegra_cpu_save)
343
344/*
345 * tegra_sleep_cpu_save(unsigned long v2p)
346 *
347 * enters suspend in LP2 by turning off the mmu and jumping to
348 * tegra?_tear_down_cpu
349 */
350ENTRY(tegra_sleep_cpu_save)
351 mov r12, pc @ return here is via r12
352 b tegra_cpu_save
353
354#ifdef CONFIG_ARCH_TEGRA_2x_SOC
355 mov32 r1, tegra2_tear_down_cpu
356#else
357 mov32 r1, tegra3_tear_down_cpu
358#endif
359 add r1, r1, r0
360 b tegra_turn_off_mmu
361ENDPROC(tegra_sleep_cpu_save)
362
363/*
364 * tegra_cpu_resume
365 *
366 * reloads the volatile CPU state from the context area
367 * initializes the processor mode stacks
368 * the mmu should be on and the CPU should be coherent before this is called
369 */
370 .align L1_CACHE_SHIFT
371tegra_cpu_resume:
372 mov r0, #0
373 mcr p15, 0, r0, c8, c3, 0 @ invalidate TLB
374 mcr p15, 0, r0, c7, c5, 6 @ flush BTAC
375 mcr p15, 0, r0, c7, c5, 0 @ flush instruction cache
376 dsb
377 isb
378
379#if USE_TEGRA_CPU_SUSPEND
380 pop_stack_token r4, r5 @ check stack debug token
381 ldmfd sp!, {r0} @ get the real stack pointer
382 pop_stack_token r4, r5 @ check stack debug token
383 mov sp, r0 @ switch to the real stack pointer
384#endif
385
386 bl cpu_init
387
388 pop_ctx_regs r1, r2 @ restore context registers
389 mov pc, lr
390
391/*
392 * tegra_turn_off_mmu
393 *
394 * r0 = v2p
395 * r1 = physical address to jump to with mmu off
396 */
397ENTRY(tegra_turn_off_mmu)
398 mov32 r3, tegra_shut_off_mmu
399 add r3, r3, r0
400 mov r0, r1
401 mov pc, r3
402ENDPROC(tegra_turn_off_mmu)
403
404tegra_pgd_phys_address:
405 .word tegra_pgd_phys
406
407/*
408 * tegra_shut_off_mmu
409 *
410 * r0 = physical address to jump to with mmu off
411 *
412 * called with VA=PA mapping
413 * turns off MMU, icache, dcache and branch prediction
414 */
415 .align L1_CACHE_SHIFT
416tegra_shut_off_mmu:
417 mrc p15, 0, r3, c1, c0, 0
418 movw r2, #CR_I | CR_Z | CR_C | CR_M
419 bic r3, r3, r2
420 dsb
421 mcr p15, 0, r3, c1, c0, 0
422 isb
423 mov pc, r0
424
425/*
426 * tegra_cpu_clk32k
427 *
428 * In LP2 the normal cpu clock pllx will be turned off. Switch the CPU to pllp
429 */
430ENTRY(tegra_cpu_pllp)
431 /* in LP2 idle (SDRAM active), set the CPU burst policy to PLLP */
432 mov32 r5, TEGRA_CLK_RESET_BASE
433 mov r0, #(2 << 28) @ burst policy = run mode
434 orr r0, r0, #(4 << 4) @ use PLLP in run mode burst
435 str r0, [r5, #CLK_RESET_CCLK_BURST]
436 mov r0, #0
437 str r0, [r5, #CLK_RESET_CCLK_DIVIDER]
438 mov pc, lr
439ENDPROC(tegra_cpu_pllp)
440#endif
441
442#ifdef CONFIG_TRUSTED_FOUNDATIONS
443/*
444 * tegra_generic_smc
445 *
446 * r0 = smc type
447 * r1 = smc subtype
448 * r2 = argument passed to smc
449 *
450 * issues SMC (secure monitor call) instruction with
451 * the specified parameters.
452 */
453ENTRY(tegra_generic_smc)
454 adr r3, __tegra_smc_stack
455 stmia r3, {r4-r12, lr}
456 mov r3, #0
457 mov r4, #0
458 dsb
459 smc #0
460 adr r3, __tegra_smc_stack
461 ldmia r3, {r4-r12, pc}
462ENDPROC(tegra_generic_smc)
463 .type __tegra_smc_stack, %object
464__tegra_smc_stack:
465 .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
466 .size __tegra_smc_stack, . - __tegra_smc_stack
467#endif