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