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