Merge tag 'locks-v3.16-2' of git://git.samba.org/jlayton/linux
[linux/fpc-iii.git] / arch / sh / kernel / cpu / shmobile / sleep.S
blobe6aac65f5750495c61ae17949b65f17a29cfac10
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  */
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>
20  * Kernel mode register usage, see entry.S:
21  *      k0      scratch
22  *      k1      scratch
23  */
24 #define k0      r0
25 #define k1      r1
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)
33         /* save mode flags */
34         mov.l   r4, @(SH_SLEEP_MODE, r5)
36         /* save original vbr */
37         stc     vbr, r0
38         mov.l   r0, @(SH_SLEEP_VBR, r5)
40         /* point vbr to our on-chip memory page */
41         ldc     r5, vbr
43         /* save return address */
44         sts     pr, r0
45         mov.l   r0, @(SH_SLEEP_SPC, r5)
47         /* save sr */
48         stc     sr, r0
49         mov.l   r0, @(SH_SLEEP_SR, r5)
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
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
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
71         bsr     save_low_regs
72          nop
74         /* switch to bank 1, save low registers */
75         mov.l   rb_bit, r10
76         bsr     set_sr
77          mov    #-1, r9
79         bsr     save_low_regs
80          nop
82         /* switch back to bank 0 */
83         mov.l   rb_bit, r9
84         not     r9, r9
85         bsr     set_sr
86          mov    #0, r10
88 skip_regs_save:
90         /* save sp, also set to internal ram */
91         mov.l   r15, @(SH_SLEEP_SP, r5)
92         mov     r5, r15
94         /* save stbcr */
95         bsr     save_register
96          mov    #SH_SLEEP_REG_STBCR, r0
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
103         /* save mmu state */
104         bsr     save_register
105          mov    #SH_SLEEP_REG_PTEH, r0
107         bsr     save_register
108          mov    #SH_SLEEP_REG_PTEL, r0
110         bsr     save_register
111          mov    #SH_SLEEP_REG_TTB, r0
113         bsr     save_register
114          mov    #SH_SLEEP_REG_TEA, r0
116         bsr     save_register
117          mov    #SH_SLEEP_REG_MMUCR, r0
119         bsr     save_register
120          mov    #SH_SLEEP_REG_PTEA, r0
122         bsr     save_register
123          mov    #SH_SLEEP_REG_PASCR, r0
125         bsr     save_register
126          mov    #SH_SLEEP_REG_IRMCR, r0
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
135         /* save cache registers and disable caches */
136         bsr     save_register
137          mov    #SH_SLEEP_REG_CCR, r0
139         bsr     save_register
140          mov    #SH_SLEEP_REG_RAMCR, r0
142         bsr     get_register
143          mov    #SH_SLEEP_REG_CCR, r0
144         mov     #0, r1
145         mov.l   r1, @r0
146         icbi    @r0
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
154         mov.l   @(SH_SLEEP_SF_PRE, r5), r0
155         jsr     @r0
156          nop
158 skip_set_sf:
159         mov.l   @(SH_SLEEP_MODE, r5), r0
160         tst     #SUSP_SH_STANDBY, r0
161         bt      test_rstandby
163         /* set mode to "software standby mode" */
164         bra     do_sleep
165          mov    #0x80, r1
167 test_rstandby:
168         tst     #SUSP_SH_RSTANDBY, r0
169         bt      test_ustandby
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
177         /* set mode to "r-standby mode" */
178         bra     do_sleep
179          mov    #0x20, r1
181 test_ustandby:
182         tst     #SUSP_SH_USTANDBY, r0
183         bt      force_sleep
185         /* set mode to "u-standby mode" */
186         bra     do_sleep
187          mov    #0x10, r1
189 force_sleep:
191         /* set mode to "sleep mode" */
192         mov     #0x00, r1
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
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
215 get_register:
216         add     #SH_SLEEP_BASE_ADDR, r0
217         mov.l   @(r0, r5), r0
218         rts
219          nop
221 set_sr:
222         stc     sr, r8
223         and     r9, r8
224         or      r10, r8
225         ldc     r8, sr
226         rts
227          nop
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
240         .balign 4
241 rb_bit: .long   0x20000000 ! RB=1
243 ENTRY(sh_mobile_sleep_enter_end)
245         .balign 4
246 ENTRY(sh_mobile_sleep_resume_start)
248         /* figure out start address */
249         bsr     0f
250          nop
252         sts     pr, k1
253         mov.l   1f, k0
254         and     k0, k1
256         /* store pointer to data area in VBR */
257         ldc     k1, vbr
259         /* setup sr with saved sr */
260         mov.l   @(SH_SLEEP_SR, k1), k0
261         ldc     k0, sr
263         /* now: user register set! */
264         stc     vbr, r5
266         /* setup spc with return address to c code */
267         mov.l   @(SH_SLEEP_SPC, r5), r0
268         ldc     r0, spc
270         /* restore vbr */
271         mov.l   @(SH_SLEEP_VBR, r5), r0
272         ldc     r0, vbr
274         /* setup ssr with saved sr */
275         mov.l   @(SH_SLEEP_SR, r5), r0
276         ldc     r0, ssr
278         /* restore sp */
279         mov.l   @(SH_SLEEP_SP, r5), r15
281         /* restore sleep mode register */
282         bsr     restore_register
283          mov    #SH_SLEEP_REG_STBCR, r0
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
290         mov.l   @(SH_SLEEP_SF_POST, r5), r0
291         jsr     @r0
292          nop
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
300         /* restore mmu state */
301         bsr     restore_register
302          mov    #SH_SLEEP_REG_PTEH, r0
304         bsr     restore_register
305          mov    #SH_SLEEP_REG_PTEL, r0
307         bsr     restore_register
308          mov    #SH_SLEEP_REG_TTB, r0
310         bsr     restore_register
311          mov    #SH_SLEEP_REG_TEA, r0
313         bsr     restore_register
314          mov    #SH_SLEEP_REG_PTEA, r0
316         bsr     restore_register
317          mov    #SH_SLEEP_REG_PASCR, r0
319         bsr     restore_register
320          mov    #SH_SLEEP_REG_IRMCR, r0
322         bsr     restore_register
323          mov    #SH_SLEEP_REG_MMUCR, r0
324         icbi    @r0
326         /* restore cache settings */
327         bsr     restore_register
328          mov    #SH_SLEEP_REG_RAMCR, r0
329         icbi    @r0
331         bsr     restore_register
332          mov    #SH_SLEEP_REG_CCR, r0
333         icbi    @r0
335 skip_restore_mmu:
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
342         /* switch to bank 1, restore low registers */
343         mov.l   _rb_bit, r10
344         bsr     _set_sr
345          mov    #-1, r9
347         bsr     restore_low_regs
348          nop
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
356         bsr     restore_low_regs
357          nop
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
369 skip_restore_regs:
370         rte
371          nop
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
383 _set_sr:
384         stc     sr, r8
385         and     r9, r8
386         or      r10, r8
387         ldc     r8, sr
388         rts
389          nop
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
402         .balign 4
403 _rb_bit:        .long   0x20000000 ! RB=1
404 1:      .long   ~0x7ff
405 ENTRY(sh_mobile_sleep_resume_end)