Loading...
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
31ENTRY(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
88skip_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
148skip_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
158skip_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
167test_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
181test_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
189force_sleep:
190
191 /* set mode to "sleep mode" */
192 mov #0x00, r1
193
194do_sleep:
195 /* setup and enter selected standby mode */
196 bsr get_register
197 mov #SH_SLEEP_REG_STBCR, r0
198 mov.l r1, @r0
199again:
200 sleep
201 bra again
202 nop
203
204save_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
215get_register:
216 add #SH_SLEEP_BASE_ADDR, r0
217 mov.l @(r0, r5), r0
218 rts
219 nop
220
221set_sr:
222 stc sr, r8
223 and r9, r8
224 or r10, r8
225 ldc r8, sr
226 rts
227 nop
228
229save_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
241rb_bit: .long 0x20000000 ! RB=1
242
243ENTRY(sh_mobile_sleep_enter_end)
244
245 .balign 4
246ENTRY(sh_mobile_sleep_resume_start)
247
248 /* figure out start address */
249 bsr 0f
250 nop
2510:
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
294skip_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
335skip_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
369skip_restore_regs:
370 rte
371 nop
372
373restore_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
391restore_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
4041: .long ~0x7ff
405ENTRY(sh_mobile_sleep_resume_end)
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
31ENTRY(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
88skip_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
148skip_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
158skip_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
167test_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
181test_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
189force_sleep:
190
191 /* set mode to "sleep mode" */
192 mov #0x00, r1
193
194do_sleep:
195 /* setup and enter selected standby mode */
196 bsr get_register
197 mov #SH_SLEEP_REG_STBCR, r0
198 mov.l r1, @r0
199again:
200 sleep
201 bra again
202 nop
203
204save_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
215get_register:
216 add #SH_SLEEP_BASE_ADDR, r0
217 mov.l @(r0, r5), r0
218 rts
219 nop
220
221set_sr:
222 stc sr, r8
223 and r9, r8
224 or r10, r8
225 ldc r8, sr
226 rts
227 nop
228
229save_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
241rb_bit: .long 0x20000000 ! RB=1
242
243ENTRY(sh_mobile_sleep_enter_end)
244
245 .balign 4
246ENTRY(sh_mobile_sleep_resume_start)
247
248 /* figure out start address */
249 bsr 0f
250 nop
2510:
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
294skip_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
335skip_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
369skip_restore_regs:
370 rte
371 nop
372
373restore_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
391restore_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
4041: .long ~0x7ff
405ENTRY(sh_mobile_sleep_resume_end)