Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[sfrench/cifs-2.6.git] / arch / sh / kernel / cpu / shmobile / sleep.S
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 sp */
52         mov.l   r15, @(SH_SLEEP_SP, r5)
53
54         /* save stbcr */
55         bsr     save_register
56          mov    #SH_SLEEP_REG_STBCR, r0
57
58         /* save mmu and cache context if needed */
59         mov.l   @(SH_SLEEP_MODE, r5), r0
60         tst     #SUSP_SH_MMU, r0
61         bt      skip_mmu_save_disable
62
63        /* save mmu state */
64         bsr     save_register
65          mov    #SH_SLEEP_REG_PTEH, r0
66
67         bsr     save_register
68          mov    #SH_SLEEP_REG_PTEL, r0
69
70         bsr     save_register
71          mov    #SH_SLEEP_REG_TTB, r0
72
73         bsr     save_register
74          mov    #SH_SLEEP_REG_TEA, r0
75
76         bsr     save_register
77          mov    #SH_SLEEP_REG_MMUCR, r0
78
79         bsr     save_register
80          mov    #SH_SLEEP_REG_PTEA, r0
81
82         bsr     save_register
83          mov    #SH_SLEEP_REG_PASCR, r0
84
85         bsr     save_register
86          mov    #SH_SLEEP_REG_IRMCR, r0
87
88         /* invalidate TLBs and disable the MMU */
89         bsr     get_register
90          mov    #SH_SLEEP_REG_MMUCR, r0
91         mov     #4, r1
92         mov.l   r1, @r0
93         icbi    @r0
94
95         /* save cache registers and disable caches */
96         bsr     save_register
97          mov    #SH_SLEEP_REG_CCR, r0
98
99         bsr     save_register
100          mov    #SH_SLEEP_REG_RAMCR, r0
101
102         bsr     get_register
103          mov    #SH_SLEEP_REG_CCR, r0
104         mov     #0, r1
105         mov.l   r1, @r0
106         icbi    @r0
107
108 skip_mmu_save_disable:
109         /* call self-refresh entering code if needed */
110         mov.l   @(SH_SLEEP_MODE, r5), r0
111         tst     #SUSP_SH_SF, r0
112         bt      skip_set_sf
113
114         mov.l   @(SH_SLEEP_SF_PRE, r5), r0
115         jsr     @r0
116          nop
117
118 skip_set_sf:
119         mov.l   @(SH_SLEEP_MODE, r5), r0
120         tst     #SUSP_SH_STANDBY, r0
121         bt      test_rstandby
122
123         /* set mode to "software standby mode" */
124         bra     do_sleep
125          mov    #0x80, r1
126
127 test_rstandby:
128         tst     #SUSP_SH_RSTANDBY, r0
129         bt      test_ustandby
130
131         /* setup BAR register */
132         bsr     get_register
133          mov    #SH_SLEEP_REG_BAR, r0
134         mov.l   @(SH_SLEEP_RESUME, r5), r1
135         mov.l   r1, @r0
136
137         /* set mode to "r-standby mode" */
138         bra     do_sleep
139          mov    #0x20, r1
140
141 test_ustandby:
142         tst     #SUSP_SH_USTANDBY, r0
143         bt      force_sleep
144
145         /* set mode to "u-standby mode" */
146         bra     do_sleep
147          mov    #0x10, r1
148
149 force_sleep:
150
151         /* set mode to "sleep mode" */
152         mov     #0x00, r1
153
154 do_sleep:
155         /* setup and enter selected standby mode */
156         bsr     get_register
157          mov    #SH_SLEEP_REG_STBCR, r0
158         mov.l   r1, @r0
159 again:
160         sleep
161         bra     again
162          nop
163
164 save_register:
165         add     #SH_SLEEP_BASE_ADDR, r0
166         mov.l   @(r0, r5), r1
167         add     #-SH_SLEEP_BASE_ADDR, r0
168         mov.l   @r1, r1
169         add     #SH_SLEEP_BASE_DATA, r0
170         mov.l   r1, @(r0, r5)
171         add     #-SH_SLEEP_BASE_DATA, r0
172         rts
173          nop
174
175 get_register:
176         add     #SH_SLEEP_BASE_ADDR, r0
177         mov.l   @(r0, r5), r0
178         rts
179          nop
180 ENTRY(sh_mobile_sleep_enter_end)
181
182         .balign 4
183 ENTRY(sh_mobile_sleep_resume_start)
184
185         /* figure out start address */
186         bsr     0f
187          nop
188 0:
189         sts     pr, k1
190         mov.l   1f, k0
191         and     k0, k1
192
193         /* store pointer to data area in VBR */
194         ldc     k1, vbr
195
196         /* setup sr with saved sr */
197         mov.l   @(SH_SLEEP_SR, k1), k0
198         ldc     k0, sr
199
200         /* now: user register set! */
201         stc     vbr, r5
202
203         /* setup spc with return address to c code */
204         mov.l   @(SH_SLEEP_SPC, r5), r0
205         ldc     r0, spc
206
207         /* restore vbr */
208         mov.l   @(SH_SLEEP_VBR, r5), r0
209         ldc     r0, vbr
210
211         /* setup ssr with saved sr */
212         mov.l   @(SH_SLEEP_SR, r5), r0
213         ldc     r0, ssr
214
215         /* restore sp */
216         mov.l   @(SH_SLEEP_SP, r5), r15
217
218         /* restore sleep mode register */
219         bsr     restore_register
220          mov    #SH_SLEEP_REG_STBCR, r0
221
222         /* call self-refresh resume code if needed */
223         mov.l   @(SH_SLEEP_MODE, r5), r0
224         tst     #SUSP_SH_SF, r0
225         bt      skip_restore_sf
226
227         mov.l   @(SH_SLEEP_SF_POST, r5), r0
228         jsr     @r0
229          nop
230
231 skip_restore_sf:
232         /* restore mmu and cache state if needed */
233         mov.l   @(SH_SLEEP_MODE, r5), r0
234         tst     #SUSP_SH_MMU, r0
235         bt      skip_restore_mmu
236
237         /* restore mmu state */
238         bsr     restore_register
239          mov    #SH_SLEEP_REG_PTEH, r0
240
241         bsr     restore_register
242          mov    #SH_SLEEP_REG_PTEL, r0
243
244         bsr     restore_register
245          mov    #SH_SLEEP_REG_TTB, r0
246
247         bsr     restore_register
248          mov    #SH_SLEEP_REG_TEA, r0
249
250         bsr     restore_register
251          mov    #SH_SLEEP_REG_PTEA, r0
252
253         bsr     restore_register
254          mov    #SH_SLEEP_REG_PASCR, r0
255
256         bsr     restore_register
257          mov    #SH_SLEEP_REG_IRMCR, r0
258
259         bsr     restore_register
260          mov    #SH_SLEEP_REG_MMUCR, r0
261         icbi    @r0
262
263         /* restore cache settings */
264         bsr     restore_register
265          mov    #SH_SLEEP_REG_RAMCR, r0
266         icbi    @r0
267
268         bsr     restore_register
269          mov    #SH_SLEEP_REG_CCR, r0
270         icbi    @r0
271
272 skip_restore_mmu:
273         rte
274          nop
275
276 restore_register:
277         add     #SH_SLEEP_BASE_DATA, r0
278         mov.l   @(r0, r5), r1
279         add     #-SH_SLEEP_BASE_DATA, r0
280         add     #SH_SLEEP_BASE_ADDR, r0
281         mov.l   @(r0, r5), r0
282         mov.l   r1, @r0
283         rts
284          nop
285
286         .balign 4
287 1:      .long   ~0x7ff
288 ENTRY(sh_mobile_sleep_resume_end)