Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/sh/kernel/cpu/shmobile/sleep.S
17372 views
1
/*
2
* arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S
3
*
4
* Sleep mode and Standby modes support for SuperH Mobile
5
*
6
* Copyright (C) 2009 Magnus Damm
7
*
8
* This file is subject to the terms and conditions of the GNU General Public
9
* License. See the file "COPYING" in the main directory of this archive
10
* for more details.
11
*/
12
13
#include <linux/sys.h>
14
#include <linux/errno.h>
15
#include <linux/linkage.h>
16
#include <asm/asm-offsets.h>
17
#include <asm/suspend.h>
18
19
/*
20
* Kernel mode register usage, see entry.S:
21
* k0 scratch
22
* k1 scratch
23
*/
24
#define k0 r0
25
#define k1 r1
26
27
/* manage self-refresh and enter standby mode. must be self-contained.
28
* this code will be copied to on-chip memory and executed from there.
29
*/
30
.balign 4
31
ENTRY(sh_mobile_sleep_enter_start)
32
33
/* save mode flags */
34
mov.l r4, @(SH_SLEEP_MODE, r5)
35
36
/* save original vbr */
37
stc vbr, r0
38
mov.l r0, @(SH_SLEEP_VBR, r5)
39
40
/* point vbr to our on-chip memory page */
41
ldc r5, vbr
42
43
/* save return address */
44
sts pr, r0
45
mov.l r0, @(SH_SLEEP_SPC, r5)
46
47
/* save sr */
48
stc sr, r0
49
mov.l r0, @(SH_SLEEP_SR, r5)
50
51
/* save general purpose registers to stack if needed */
52
mov.l @(SH_SLEEP_MODE, r5), r0
53
tst #SUSP_SH_REGS, r0
54
bt skip_regs_save
55
56
sts.l pr, @-r15
57
mov.l r14, @-r15
58
mov.l r13, @-r15
59
mov.l r12, @-r15
60
mov.l r11, @-r15
61
mov.l r10, @-r15
62
mov.l r9, @-r15
63
mov.l r8, @-r15
64
65
/* make sure bank0 is selected, save low registers */
66
mov.l rb_bit, r9
67
not r9, r9
68
bsr set_sr
69
mov #0, r10
70
71
bsr save_low_regs
72
nop
73
74
/* switch to bank 1, save low registers */
75
mov.l rb_bit, r10
76
bsr set_sr
77
mov #-1, r9
78
79
bsr save_low_regs
80
nop
81
82
/* switch back to bank 0 */
83
mov.l rb_bit, r9
84
not r9, r9
85
bsr set_sr
86
mov #0, r10
87
88
skip_regs_save:
89
90
/* save sp, also set to internal ram */
91
mov.l r15, @(SH_SLEEP_SP, r5)
92
mov r5, r15
93
94
/* save stbcr */
95
bsr save_register
96
mov #SH_SLEEP_REG_STBCR, r0
97
98
/* save mmu and cache context if needed */
99
mov.l @(SH_SLEEP_MODE, r5), r0
100
tst #SUSP_SH_MMU, r0
101
bt skip_mmu_save_disable
102
103
/* save mmu state */
104
bsr save_register
105
mov #SH_SLEEP_REG_PTEH, r0
106
107
bsr save_register
108
mov #SH_SLEEP_REG_PTEL, r0
109
110
bsr save_register
111
mov #SH_SLEEP_REG_TTB, r0
112
113
bsr save_register
114
mov #SH_SLEEP_REG_TEA, r0
115
116
bsr save_register
117
mov #SH_SLEEP_REG_MMUCR, r0
118
119
bsr save_register
120
mov #SH_SLEEP_REG_PTEA, r0
121
122
bsr save_register
123
mov #SH_SLEEP_REG_PASCR, r0
124
125
bsr save_register
126
mov #SH_SLEEP_REG_IRMCR, r0
127
128
/* invalidate TLBs and disable the MMU */
129
bsr get_register
130
mov #SH_SLEEP_REG_MMUCR, r0
131
mov #4, r1
132
mov.l r1, @r0
133
icbi @r0
134
135
/* save cache registers and disable caches */
136
bsr save_register
137
mov #SH_SLEEP_REG_CCR, r0
138
139
bsr save_register
140
mov #SH_SLEEP_REG_RAMCR, r0
141
142
bsr get_register
143
mov #SH_SLEEP_REG_CCR, r0
144
mov #0, r1
145
mov.l r1, @r0
146
icbi @r0
147
148
skip_mmu_save_disable:
149
/* call self-refresh entering code if needed */
150
mov.l @(SH_SLEEP_MODE, r5), r0
151
tst #SUSP_SH_SF, r0
152
bt skip_set_sf
153
154
mov.l @(SH_SLEEP_SF_PRE, r5), r0
155
jsr @r0
156
nop
157
158
skip_set_sf:
159
mov.l @(SH_SLEEP_MODE, r5), r0
160
tst #SUSP_SH_STANDBY, r0
161
bt test_rstandby
162
163
/* set mode to "software standby mode" */
164
bra do_sleep
165
mov #0x80, r1
166
167
test_rstandby:
168
tst #SUSP_SH_RSTANDBY, r0
169
bt test_ustandby
170
171
/* setup BAR register */
172
bsr get_register
173
mov #SH_SLEEP_REG_BAR, r0
174
mov.l @(SH_SLEEP_RESUME, r5), r1
175
mov.l r1, @r0
176
177
/* set mode to "r-standby mode" */
178
bra do_sleep
179
mov #0x20, r1
180
181
test_ustandby:
182
tst #SUSP_SH_USTANDBY, r0
183
bt force_sleep
184
185
/* set mode to "u-standby mode" */
186
bra do_sleep
187
mov #0x10, r1
188
189
force_sleep:
190
191
/* set mode to "sleep mode" */
192
mov #0x00, r1
193
194
do_sleep:
195
/* setup and enter selected standby mode */
196
bsr get_register
197
mov #SH_SLEEP_REG_STBCR, r0
198
mov.l r1, @r0
199
again:
200
sleep
201
bra again
202
nop
203
204
save_register:
205
add #SH_SLEEP_BASE_ADDR, r0
206
mov.l @(r0, r5), r1
207
add #-SH_SLEEP_BASE_ADDR, r0
208
mov.l @r1, r1
209
add #SH_SLEEP_BASE_DATA, r0
210
mov.l r1, @(r0, r5)
211
add #-SH_SLEEP_BASE_DATA, r0
212
rts
213
nop
214
215
get_register:
216
add #SH_SLEEP_BASE_ADDR, r0
217
mov.l @(r0, r5), r0
218
rts
219
nop
220
221
set_sr:
222
stc sr, r8
223
and r9, r8
224
or r10, r8
225
ldc r8, sr
226
rts
227
nop
228
229
save_low_regs:
230
mov.l r7, @-r15
231
mov.l r6, @-r15
232
mov.l r5, @-r15
233
mov.l r4, @-r15
234
mov.l r3, @-r15
235
mov.l r2, @-r15
236
mov.l r1, @-r15
237
rts
238
mov.l r0, @-r15
239
240
.balign 4
241
rb_bit: .long 0x20000000 ! RB=1
242
243
ENTRY(sh_mobile_sleep_enter_end)
244
245
.balign 4
246
ENTRY(sh_mobile_sleep_resume_start)
247
248
/* figure out start address */
249
bsr 0f
250
nop
251
0:
252
sts pr, k1
253
mov.l 1f, k0
254
and k0, k1
255
256
/* store pointer to data area in VBR */
257
ldc k1, vbr
258
259
/* setup sr with saved sr */
260
mov.l @(SH_SLEEP_SR, k1), k0
261
ldc k0, sr
262
263
/* now: user register set! */
264
stc vbr, r5
265
266
/* setup spc with return address to c code */
267
mov.l @(SH_SLEEP_SPC, r5), r0
268
ldc r0, spc
269
270
/* restore vbr */
271
mov.l @(SH_SLEEP_VBR, r5), r0
272
ldc r0, vbr
273
274
/* setup ssr with saved sr */
275
mov.l @(SH_SLEEP_SR, r5), r0
276
ldc r0, ssr
277
278
/* restore sp */
279
mov.l @(SH_SLEEP_SP, r5), r15
280
281
/* restore sleep mode register */
282
bsr restore_register
283
mov #SH_SLEEP_REG_STBCR, r0
284
285
/* call self-refresh resume code if needed */
286
mov.l @(SH_SLEEP_MODE, r5), r0
287
tst #SUSP_SH_SF, r0
288
bt skip_restore_sf
289
290
mov.l @(SH_SLEEP_SF_POST, r5), r0
291
jsr @r0
292
nop
293
294
skip_restore_sf:
295
/* restore mmu and cache state if needed */
296
mov.l @(SH_SLEEP_MODE, r5), r0
297
tst #SUSP_SH_MMU, r0
298
bt skip_restore_mmu
299
300
/* restore mmu state */
301
bsr restore_register
302
mov #SH_SLEEP_REG_PTEH, r0
303
304
bsr restore_register
305
mov #SH_SLEEP_REG_PTEL, r0
306
307
bsr restore_register
308
mov #SH_SLEEP_REG_TTB, r0
309
310
bsr restore_register
311
mov #SH_SLEEP_REG_TEA, r0
312
313
bsr restore_register
314
mov #SH_SLEEP_REG_PTEA, r0
315
316
bsr restore_register
317
mov #SH_SLEEP_REG_PASCR, r0
318
319
bsr restore_register
320
mov #SH_SLEEP_REG_IRMCR, r0
321
322
bsr restore_register
323
mov #SH_SLEEP_REG_MMUCR, r0
324
icbi @r0
325
326
/* restore cache settings */
327
bsr restore_register
328
mov #SH_SLEEP_REG_RAMCR, r0
329
icbi @r0
330
331
bsr restore_register
332
mov #SH_SLEEP_REG_CCR, r0
333
icbi @r0
334
335
skip_restore_mmu:
336
337
/* restore general purpose registers if needed */
338
mov.l @(SH_SLEEP_MODE, r5), r0
339
tst #SUSP_SH_REGS, r0
340
bt skip_restore_regs
341
342
/* switch to bank 1, restore low registers */
343
mov.l _rb_bit, r10
344
bsr _set_sr
345
mov #-1, r9
346
347
bsr restore_low_regs
348
nop
349
350
/* switch to bank0, restore low registers */
351
mov.l _rb_bit, r9
352
not r9, r9
353
bsr _set_sr
354
mov #0, r10
355
356
bsr restore_low_regs
357
nop
358
359
/* restore the rest of the registers */
360
mov.l @r15+, r8
361
mov.l @r15+, r9
362
mov.l @r15+, r10
363
mov.l @r15+, r11
364
mov.l @r15+, r12
365
mov.l @r15+, r13
366
mov.l @r15+, r14
367
lds.l @r15+, pr
368
369
skip_restore_regs:
370
rte
371
nop
372
373
restore_register:
374
add #SH_SLEEP_BASE_DATA, r0
375
mov.l @(r0, r5), r1
376
add #-SH_SLEEP_BASE_DATA, r0
377
add #SH_SLEEP_BASE_ADDR, r0
378
mov.l @(r0, r5), r0
379
mov.l r1, @r0
380
rts
381
nop
382
383
_set_sr:
384
stc sr, r8
385
and r9, r8
386
or r10, r8
387
ldc r8, sr
388
rts
389
nop
390
391
restore_low_regs:
392
mov.l @r15+, r0
393
mov.l @r15+, r1
394
mov.l @r15+, r2
395
mov.l @r15+, r3
396
mov.l @r15+, r4
397
mov.l @r15+, r5
398
mov.l @r15+, r6
399
rts
400
mov.l @r15+, r7
401
402
.balign 4
403
_rb_bit: .long 0x20000000 ! RB=1
404
1: .long ~0x7ff
405
ENTRY(sh_mobile_sleep_resume_end)
406
407