ARM: pm: add generic CPU suspend/resume support
[linux-2.6-block.git] / arch / arm / kernel / sleep.S
1 #include <linux/linkage.h>
2 #include <asm/asm-offsets.h>
3 #include <asm/assembler.h>
4 #include <asm/glue-cache.h>
5 #include <asm/glue-proc.h>
6 #include <asm/system.h>
7         .text
8
9 /*
10  * Save CPU state for a suspend
11  *  r1 = v:p offset
12  *  r3 = virtual return function
13  * Note: sp is decremented to allocate space for CPU state on stack
14  * r0-r3,r9,r10,lr corrupted
15  */
16 ENTRY(cpu_suspend)
17         mov     r9, lr
18 #ifdef MULTI_CPU
19         ldr     r10, =processor
20         mov     r2, sp                  @ current virtual SP
21         ldr     r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
22         ldr     ip, [r10, #CPU_DO_RESUME] @ virtual resume function
23         sub     sp, sp, r0              @ allocate CPU state on stack
24         mov     r0, sp                  @ save pointer
25         add     ip, ip, r1              @ convert resume fn to phys
26         stmfd   sp!, {r1, r2, r3, ip}   @ save v:p, virt SP, retfn, phys resume fn
27         ldr     r3, =sleep_save_sp
28         add     r2, sp, r1              @ convert SP to phys
29         str     r2, [r3]                @ save phys SP
30         mov     lr, pc
31         ldr     pc, [r10, #CPU_DO_SUSPEND] @ save CPU state
32 #else
33         mov     r2, sp                  @ current virtual SP
34         ldr     r0, =cpu_suspend_size
35         sub     sp, sp, r0              @ allocate CPU state on stack
36         mov     r0, sp                  @ save pointer
37         stmfd   sp!, {r1, r2, r3}       @ save v:p, virt SP, return fn
38         ldr     r3, =sleep_save_sp
39         add     r2, sp, r1              @ convert SP to phys
40         str     r2, [r3]                @ save phys SP
41         bl      cpu_do_suspend
42 #endif
43
44         @ flush data cache
45 #ifdef MULTI_CACHE
46         ldr     r10, =cpu_cache
47         mov     lr, r9
48         ldr     pc, [r10, #CACHE_FLUSH_KERN_ALL]
49 #else
50         mov     lr, r9
51         b       __cpuc_flush_kern_all
52 #endif
53 ENDPROC(cpu_suspend)
54         .ltorg
55
56 /*
57  * r0 = control register value
58  * r1 = v:p offset (preserved by cpu_do_resume)
59  * r2 = phys page table base
60  * r3 = L1 section flags
61  */
62 ENTRY(cpu_resume_mmu)
63         adr     r4, cpu_resume_turn_mmu_on
64         mov     r4, r4, lsr #20
65         orr     r3, r3, r4, lsl #20
66         ldr     r5, [r2, r4, lsl #2]    @ save old mapping
67         str     r3, [r2, r4, lsl #2]    @ setup 1:1 mapping for mmu code
68         sub     r2, r2, r1
69         ldr     r3, =cpu_resume_after_mmu
70         bic     r1, r0, #CR_C           @ ensure D-cache is disabled
71         b       cpu_resume_turn_mmu_on
72 ENDPROC(cpu_resume_mmu)
73         .ltorg
74         .align  5
75 cpu_resume_turn_mmu_on:
76         mcr     p15, 0, r1, c1, c0, 0   @ turn on MMU, I-cache, etc
77         mrc     p15, 0, r1, c0, c0, 0   @ read id reg
78         mov     r1, r1
79         mov     r1, r1
80         mov     pc, r3                  @ jump to virtual address
81 ENDPROC(cpu_resume_turn_mmu_on)
82 cpu_resume_after_mmu:
83         str     r5, [r2, r4, lsl #2]    @ restore old mapping
84         mcr     p15, 0, r0, c1, c0, 0   @ turn on D-cache
85         mov     pc, lr
86 ENDPROC(cpu_resume_after_mmu)
87
88 /*
89  * Note: Yes, part of the following code is located into the .data section.
90  *       This is to allow sleep_save_sp to be accessed with a relative load
91  *       while we can't rely on any MMU translation.  We could have put
92  *       sleep_save_sp in the .text section as well, but some setups might
93  *       insist on it to be truly read-only.
94  */
95         .data
96         .align
97 ENTRY(cpu_resume)
98         ldr     r0, sleep_save_sp       @ stack phys addr
99         msr     cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE @ set SVC, irqs off
100 #ifdef MULTI_CPU
101         ldmia   r0!, {r1, sp, lr, pc}   @ load v:p, stack, return fn, resume fn
102 #else
103         ldmia   r0!, {r1, sp, lr}       @ load v:p, stack, return fn
104         b       cpu_do_resume
105 #endif
106 ENDPROC(cpu_resume)
107
108 sleep_save_sp:
109         .word   0                               @ preserve stack phys ptr here