1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
#include <linux/linkage.h>
#include <linux/threads.h>
#include <asm/asm-offsets.h>
#include <asm/assembler.h>
#include <asm/glue-cache.h>
#include <asm/glue-proc.h>
#include "entry-header.S"
.text
.macro dormant_va_log tag
stmfd sp!, {r0 - r2}
mrc p15, 0, r0, c0, c0, 5
ands r0, r0, #0xff
ldr r1, =sleep_aee_rec_cpu_dormant_va
ldr r1, [r1]
cmp r1, #0
beq 1f
ldr r2, =\tag
str r2, [r1, r0, lsl #3]
1:
ldmfd sp!, {r0 - r2}
.endm
.macro dormant_pa_log tag
mrc p15, 0, r0, c0, c0, 5
ands r0, r0, #0xff
adr r1, sleep_aee_rec_cpu_dormant
ldr r1, [r1]
cmp r1, #0
beq 1f
ldr r2, =\tag
str r2, [r1, r0, lsl #3]
1:
.endm
/*
* Save CPU state for a suspend. This saves the CPU general purpose
* registers, and allocates space on the kernel stack to save the CPU
* specific registers and some other data for resume.
* r0 = suspend function arg0
* r1 = suspend function
*/
ENTRY(__cpu_suspend)
stmfd sp!, {r4 - r11, lr}
#ifdef MULTI_CPU
ldr r10, =processor
ldr r4, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
#else
ldr r4, =cpu_suspend_size
#endif
dormant_va_log 0x202
mov r5, sp @ current virtual SP
add r4, r4, #12 @ Space for pgd, virt sp, phys resume fn
sub sp, sp, r4 @ allocate CPU state on stack
stmfd sp!, {r0, r1} @ save suspend func arg and pointer
add r0, sp, #8 @ save pointer to save block
mov r1, r4 @ size of save block
mov r2, r5 @ virtual SP
ldr r3, =sleep_save_sp
#ifdef CONFIG_SMP
get_thread_info r5
ldr lr, [r5, #TI_CPU] @ cpu logical index
add r3, r3, lr, lsl #2
#endif
bl __cpu_suspend_save
adr lr, BSYM(cpu_suspend_abort)
ldmfd sp!, {r0, pc} @ call suspend fn
ENDPROC(__cpu_suspend)
.ltorg
cpu_suspend_abort:
ldmia sp!, {r1 - r3} @ pop phys pgd, virt SP, phys resume fn
teq r0, #0
moveq r0, #1 @ force non-zero value
mov sp, r2
ldmfd sp!, {r4 - r11, pc}
ENDPROC(cpu_suspend_abort)
/*
* r0 = control register value
*/
.align 5
.pushsection .idmap.text,"ax"
ENTRY(cpu_resume_mmu)
ldr r3, =cpu_resume_after_mmu
instr_sync
mcr p15, 0, r0, c1, c0, 0 @ turn on MMU, I-cache, etc
mrc p15, 0, r0, c0, c0, 0 @ read id reg
instr_sync
mov r0, r0
mov r0, r0
mov pc, r3 @ jump to virtual address
ENDPROC(cpu_resume_mmu)
.popsection
cpu_resume_after_mmu:
dormant_va_log 0x503
bl cpu_init @ restore the und/abt/irq banked regs
mov r0, #0 @ return zero on success
ldmfd sp!, {r4 - r11, pc}
ENDPROC(cpu_resume_after_mmu)
/*
* Note: Yes, part of the following code is located into the .data section.
* This is to allow sleep_save_sp to be accessed with a relative load
* while we can't rely on any MMU translation. We could have put
* sleep_save_sp in the .text section as well, but some setups might
* insist on it to be truly read-only.
*/
.data
.align
ENTRY(cpu_resume)
dormant_pa_log 0x501
bl v7_invalidate_l1
#ifdef CONFIG_SMP
mov r1, #0 @ fall-back logical index for UP
ALT_SMP(mrc p15, 0, r0, c0, c0, 5)
ALT_UP_B(1f)
bic r0, #0xff000000
bl cpu_logical_index @ return logical index in r1
1:
adr r0, sleep_save_sp
ldr r0, [r0, r1, lsl #2] @ stack phys addr
#else
ldr r0, sleep_save_sp @ stack phys addr
#endif
setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off
@ load phys pgd, stack, resume fn
ARM( ldmia r0!, {r1, sp, pc} )
THUMB( ldmia r0!, {r1, r2, r3} )
THUMB( mov sp, r2 )
THUMB( bx r3 )
ENDPROC(cpu_resume)
sleep_save_sp:
.rept CONFIG_NR_CPUS
.long 0 @ preserve stack phys ptr here
.endr
#ifdef CONFIG_SMP
cpu_logical_index:
adr r3, cpu_map_ptr
ldr r2, [r3]
add r3, r3, r2 @ virt_to_phys(__cpu_logical_map)
mov r1, #0
1:
ldr r2, [r3, r1, lsl #2]
cmp r2, r0
moveq pc, lr
add r1, r1, #1
b 1b
cpu_map_ptr:
.long __cpu_logical_map - .
#endif
.type sleep_aee_rec_cpu_dormant, #object
ENTRY(sleep_aee_rec_cpu_dormant)
.long 0 // dormant log
.type sleep_aee_rec_cpu_dormant_va, #object
ENTRY(sleep_aee_rec_cpu_dormant_va)
.long 0 // dormant log
|