xref: /openbmc/linux/arch/sh/kernel/cpu/shmobile/sleep.S (revision bb3e0eed)
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 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
108skip_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
118skip_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
127test_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
141test_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
149force_sleep:
150
151	/* set mode to "sleep mode" */
152	mov	#0x00, r1
153
154do_sleep:
155	/* setup and enter selected standby mode */
156	bsr     get_register
157	 mov    #SH_SLEEP_REG_STBCR, r0
158	mov.l	r1, @r0
159again:
160	sleep
161	bra	again
162	 nop
163
164save_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
175get_register:
176	add	#SH_SLEEP_BASE_ADDR, r0
177	mov.l	@(r0, r5), r0
178	rts
179	 nop
180ENTRY(sh_mobile_sleep_enter_end)
181
182	.balign 4
183ENTRY(sh_mobile_sleep_resume_start)
184
185	/* figure out start address */
186	bsr	0f
187	 nop
1880:
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
231skip_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
272skip_restore_mmu:
273	rte
274	 nop
275
276restore_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
2871:	.long	~0x7ff
288ENTRY(sh_mobile_sleep_resume_end)
289