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