diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-02-06 10:48:39 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2011-02-22 12:11:23 -0500 |
commit | f6b0fa02e8b0708d17d631afce456524eadf87ff (patch) | |
tree | 900fcd2149a03ba229bb29e982d3d6a5f3d3fcfc /arch/arm/kernel/sleep.S | |
parent | 753790e713d80b50b867fa1ed32ec0eb5e82ae8e (diff) |
ARM: pm: add generic CPU suspend/resume support
This adds core support for saving and restoring CPU coprocessor
registers for suspend/resume support. This contains support for suspend
with ARM920, ARM926, SA11x0, PXA25x, PXA27x, PXA3xx, V6 and V7 CPUs.
Tested on Assabet and Tegra 2.
Tested-by: Colin Cross <ccross@android.com>
Tested-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel/sleep.S')
-rw-r--r-- | arch/arm/kernel/sleep.S | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S new file mode 100644 index 000000000000..2ba17946619e --- /dev/null +++ b/arch/arm/kernel/sleep.S | |||
@@ -0,0 +1,109 @@ | |||
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 | ||