diff options
Diffstat (limited to 'arch/arm/kernel/sleep.S')
-rw-r--r-- | arch/arm/kernel/sleep.S | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S new file mode 100644 index 000000000000..bfad698a02e7 --- /dev/null +++ b/arch/arm/kernel/sleep.S | |||
@@ -0,0 +1,134 @@ | |||
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 | sub sp, sp, r0 @ allocate CPU state on stack | ||
44 | mov r0, sp @ save pointer | ||
45 | stmfd sp!, {r1, r2, r3} @ save v:p, virt SP, return fn | ||
46 | ldr r3, =sleep_save_sp | ||
47 | add r2, sp, r1 @ convert SP to phys | ||
48 | #ifdef CONFIG_SMP | ||
49 | ALT_SMP(mrc p15, 0, lr, c0, c0, 5) | ||
50 | ALT_UP(mov lr, #0) | ||
51 | and lr, lr, #15 | ||
52 | str r2, [r3, lr, lsl #2] @ save phys SP | ||
53 | #else | ||
54 | str r2, [r3] @ save phys SP | ||
55 | #endif | ||
56 | bl cpu_do_suspend | ||
57 | #endif | ||
58 | |||
59 | @ flush data cache | ||
60 | #ifdef MULTI_CACHE | ||
61 | ldr r10, =cpu_cache | ||
62 | mov lr, r9 | ||
63 | ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] | ||
64 | #else | ||
65 | mov lr, r9 | ||
66 | b __cpuc_flush_kern_all | ||
67 | #endif | ||
68 | ENDPROC(cpu_suspend) | ||
69 | .ltorg | ||
70 | |||
71 | /* | ||
72 | * r0 = control register value | ||
73 | * r1 = v:p offset (preserved by cpu_do_resume) | ||
74 | * r2 = phys page table base | ||
75 | * r3 = L1 section flags | ||
76 | */ | ||
77 | ENTRY(cpu_resume_mmu) | ||
78 | adr r4, cpu_resume_turn_mmu_on | ||
79 | mov r4, r4, lsr #20 | ||
80 | orr r3, r3, r4, lsl #20 | ||
81 | ldr r5, [r2, r4, lsl #2] @ save old mapping | ||
82 | str r3, [r2, r4, lsl #2] @ setup 1:1 mapping for mmu code | ||
83 | sub r2, r2, r1 | ||
84 | ldr r3, =cpu_resume_after_mmu | ||
85 | bic r1, r0, #CR_C @ ensure D-cache is disabled | ||
86 | b cpu_resume_turn_mmu_on | ||
87 | ENDPROC(cpu_resume_mmu) | ||
88 | .ltorg | ||
89 | .align 5 | ||
90 | cpu_resume_turn_mmu_on: | ||
91 | mcr p15, 0, r1, c1, c0, 0 @ turn on MMU, I-cache, etc | ||
92 | mrc p15, 0, r1, c0, c0, 0 @ read id reg | ||
93 | mov r1, r1 | ||
94 | mov r1, r1 | ||
95 | mov pc, r3 @ jump to virtual address | ||
96 | ENDPROC(cpu_resume_turn_mmu_on) | ||
97 | cpu_resume_after_mmu: | ||
98 | str r5, [r2, r4, lsl #2] @ restore old mapping | ||
99 | mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache | ||
100 | mov pc, lr | ||
101 | ENDPROC(cpu_resume_after_mmu) | ||
102 | |||
103 | /* | ||
104 | * Note: Yes, part of the following code is located into the .data section. | ||
105 | * This is to allow sleep_save_sp to be accessed with a relative load | ||
106 | * while we can't rely on any MMU translation. We could have put | ||
107 | * sleep_save_sp in the .text section as well, but some setups might | ||
108 | * insist on it to be truly read-only. | ||
109 | */ | ||
110 | .data | ||
111 | .align | ||
112 | ENTRY(cpu_resume) | ||
113 | #ifdef CONFIG_SMP | ||
114 | adr r0, sleep_save_sp | ||
115 | ALT_SMP(mrc p15, 0, r1, c0, c0, 5) | ||
116 | ALT_UP(mov r1, #0) | ||
117 | and r1, r1, #15 | ||
118 | ldr r0, [r0, r1, lsl #2] @ stack phys addr | ||
119 | #else | ||
120 | ldr r0, sleep_save_sp @ stack phys addr | ||
121 | #endif | ||
122 | msr cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE @ set SVC, irqs off | ||
123 | #ifdef MULTI_CPU | ||
124 | ldmia r0!, {r1, sp, lr, pc} @ load v:p, stack, return fn, resume fn | ||
125 | #else | ||
126 | ldmia r0!, {r1, sp, lr} @ load v:p, stack, return fn | ||
127 | b cpu_do_resume | ||
128 | #endif | ||
129 | ENDPROC(cpu_resume) | ||
130 | |||
131 | sleep_save_sp: | ||
132 | .rept CONFIG_NR_CPUS | ||
133 | .long 0 @ preserve stack phys ptr here | ||
134 | .endr | ||