xref: /openbmc/linux/arch/sh/kernel/cpu/shmobile/sleep.S (revision bb3e0eed)
1e9edb3feSPaul Mundt/*
2e9edb3feSPaul Mundt * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S
3e9edb3feSPaul Mundt *
4e9edb3feSPaul Mundt * Sleep mode and Standby modes support for SuperH Mobile
5e9edb3feSPaul Mundt *
6e9edb3feSPaul Mundt *  Copyright (C) 2009 Magnus Damm
7e9edb3feSPaul Mundt *
8e9edb3feSPaul Mundt * This file is subject to the terms and conditions of the GNU General Public
9e9edb3feSPaul Mundt * License.  See the file "COPYING" in the main directory of this archive
10e9edb3feSPaul Mundt * for more details.
11e9edb3feSPaul Mundt */
12e9edb3feSPaul Mundt
13e9edb3feSPaul Mundt#include <linux/sys.h>
14e9edb3feSPaul Mundt#include <linux/errno.h>
15e9edb3feSPaul Mundt#include <linux/linkage.h>
16e9edb3feSPaul Mundt#include <asm/asm-offsets.h>
17e9edb3feSPaul Mundt#include <asm/suspend.h>
18e9edb3feSPaul Mundt
19309214afSMagnus Damm/*
20309214afSMagnus Damm * Kernel mode register usage, see entry.S:
21309214afSMagnus Damm *	k0	scratch
22309214afSMagnus Damm *	k1	scratch
23309214afSMagnus Damm */
24309214afSMagnus Damm#define k0	r0
25309214afSMagnus Damm#define k1	r1
26309214afSMagnus Damm
27323ef8dbSMagnus Damm/* manage self-refresh and enter standby mode. must be self-contained.
28e9edb3feSPaul Mundt * this code will be copied to on-chip memory and executed from there.
29e9edb3feSPaul Mundt */
30323ef8dbSMagnus Damm	.balign 4
31323ef8dbSMagnus DammENTRY(sh_mobile_sleep_enter_start)
32e9edb3feSPaul Mundt
33323ef8dbSMagnus Damm	/* save mode flags */
34323ef8dbSMagnus Damm	mov.l	r4, @(SH_SLEEP_MODE, r5)
35309214afSMagnus Damm
36309214afSMagnus Damm	/* save original vbr */
37323ef8dbSMagnus Damm	stc	vbr, r0
38323ef8dbSMagnus Damm	mov.l	r0, @(SH_SLEEP_VBR, r5)
39309214afSMagnus Damm
40309214afSMagnus Damm	/* point vbr to our on-chip memory page */
41309214afSMagnus Damm	ldc	r5, vbr
42309214afSMagnus Damm
43309214afSMagnus Damm	/* save return address */
44323ef8dbSMagnus Damm	sts	pr, r0
45323ef8dbSMagnus Damm	mov.l	r0, @(SH_SLEEP_SPC, r5)
46309214afSMagnus Damm
47309214afSMagnus Damm	/* save sr */
48323ef8dbSMagnus Damm	stc	sr, r0
49323ef8dbSMagnus Damm	mov.l	r0, @(SH_SLEEP_SR, r5)
50309214afSMagnus Damm
51bb3e0eedSMagnus Damm	/* save sp */
52bb3e0eedSMagnus Damm	mov.l	r15, @(SH_SLEEP_SP, r5)
53bb3e0eedSMagnus Damm
54323ef8dbSMagnus Damm	/* save stbcr */
55323ef8dbSMagnus Damm	bsr     save_register
56323ef8dbSMagnus Damm	 mov    #SH_SLEEP_REG_STBCR, r0
57309214afSMagnus Damm
5899675a7aSMagnus Damm	/* save mmu and cache context if needed */
5999675a7aSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
6099675a7aSMagnus Damm	tst	#SUSP_SH_MMU, r0
6199675a7aSMagnus Damm	bt	skip_mmu_save_disable
6299675a7aSMagnus Damm
6399675a7aSMagnus Damm       /* save mmu state */
6499675a7aSMagnus Damm	bsr	save_register
6599675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEH, r0
6699675a7aSMagnus Damm
6799675a7aSMagnus Damm	bsr	save_register
6899675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEL, r0
6999675a7aSMagnus Damm
7099675a7aSMagnus Damm	bsr	save_register
7199675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_TTB, r0
7299675a7aSMagnus Damm
7399675a7aSMagnus Damm	bsr	save_register
7499675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_TEA, r0
7599675a7aSMagnus Damm
7699675a7aSMagnus Damm	bsr	save_register
7799675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_MMUCR, r0
7899675a7aSMagnus Damm
7999675a7aSMagnus Damm	bsr	save_register
8099675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEA, r0
8199675a7aSMagnus Damm
8299675a7aSMagnus Damm	bsr	save_register
8399675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PASCR, r0
8499675a7aSMagnus Damm
8599675a7aSMagnus Damm	bsr	save_register
8699675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_IRMCR, r0
8799675a7aSMagnus Damm
8899675a7aSMagnus Damm	/* invalidate TLBs and disable the MMU */
8999675a7aSMagnus Damm	bsr	get_register
9099675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_MMUCR, r0
9199675a7aSMagnus Damm	mov	#4, r1
9299675a7aSMagnus Damm	mov.l	r1, @r0
9399675a7aSMagnus Damm	icbi	@r0
9499675a7aSMagnus Damm
9599675a7aSMagnus Damm	/* save cache registers and disable caches */
9699675a7aSMagnus Damm	bsr	save_register
9799675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_CCR, r0
9899675a7aSMagnus Damm
9999675a7aSMagnus Damm	bsr	save_register
10099675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_RAMCR, r0
10199675a7aSMagnus Damm
10299675a7aSMagnus Damm	bsr	get_register
10399675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_CCR, r0
10499675a7aSMagnus Damm	mov	#0, r1
10599675a7aSMagnus Damm	mov.l	r1, @r0
10699675a7aSMagnus Damm	icbi	@r0
10799675a7aSMagnus Damm
10899675a7aSMagnus Dammskip_mmu_save_disable:
109323ef8dbSMagnus Damm	/* call self-refresh entering code if needed */
110323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
111e9edb3feSPaul Mundt	tst	#SUSP_SH_SF, r0
112e9edb3feSPaul Mundt	bt	skip_set_sf
113237674e0SMagnus Damm
114323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SF_PRE, r5), r0
115323ef8dbSMagnus Damm	jsr	@r0
116323ef8dbSMagnus Damm	 nop
117e9edb3feSPaul Mundt
118e9edb3feSPaul Mundtskip_set_sf:
119323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
120e9edb3feSPaul Mundt	tst	#SUSP_SH_STANDBY, r0
121e9edb3feSPaul Mundt	bt	test_rstandby
122e9edb3feSPaul Mundt
123e9edb3feSPaul Mundt	/* set mode to "software standby mode" */
124e9edb3feSPaul Mundt	bra	do_sleep
125e9edb3feSPaul Mundt	 mov	#0x80, r1
126e9edb3feSPaul Mundt
127e9edb3feSPaul Mundttest_rstandby:
128e9edb3feSPaul Mundt	tst	#SUSP_SH_RSTANDBY, r0
129e9edb3feSPaul Mundt	bt	test_ustandby
130e9edb3feSPaul Mundt
131bb3e0eedSMagnus Damm	/* setup BAR register */
132bb3e0eedSMagnus Damm	bsr	get_register
133bb3e0eedSMagnus Damm	 mov	#SH_SLEEP_REG_BAR, r0
134bb3e0eedSMagnus Damm	mov.l	@(SH_SLEEP_RESUME, r5), r1
135bb3e0eedSMagnus Damm	mov.l	r1, @r0
136bb3e0eedSMagnus Damm
137e9edb3feSPaul Mundt	/* set mode to "r-standby mode" */
138e9edb3feSPaul Mundt	bra	do_sleep
139e9edb3feSPaul Mundt	 mov	#0x20, r1
140e9edb3feSPaul Mundt
141e9edb3feSPaul Mundttest_ustandby:
142e9edb3feSPaul Mundt	tst	#SUSP_SH_USTANDBY, r0
143309214afSMagnus Damm	bt	force_sleep
144e9edb3feSPaul Mundt
145e9edb3feSPaul Mundt	/* set mode to "u-standby mode" */
146309214afSMagnus Damm	bra	do_sleep
147e9edb3feSPaul Mundt	 mov	#0x10, r1
148e9edb3feSPaul Mundt
149309214afSMagnus Dammforce_sleep:
150309214afSMagnus Damm
151309214afSMagnus Damm	/* set mode to "sleep mode" */
152309214afSMagnus Damm	mov	#0x00, r1
153e9edb3feSPaul Mundt
154e9edb3feSPaul Mundtdo_sleep:
155e9edb3feSPaul Mundt	/* setup and enter selected standby mode */
156323ef8dbSMagnus Damm	bsr     get_register
157323ef8dbSMagnus Damm	 mov    #SH_SLEEP_REG_STBCR, r0
158323ef8dbSMagnus Damm	mov.l	r1, @r0
159309214afSMagnus Dammagain:
160e9edb3feSPaul Mundt	sleep
161309214afSMagnus Damm	bra	again
162309214afSMagnus Damm	 nop
163309214afSMagnus Damm
164323ef8dbSMagnus Dammsave_register:
165323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
166323ef8dbSMagnus Damm	mov.l	@(r0, r5), r1
167323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_ADDR, r0
168323ef8dbSMagnus Damm	mov.l	@r1, r1
169323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_DATA, r0
170323ef8dbSMagnus Damm	mov.l	r1, @(r0, r5)
171323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_DATA, r0
172323ef8dbSMagnus Damm	rts
173323ef8dbSMagnus Damm	 nop
174323ef8dbSMagnus Damm
175323ef8dbSMagnus Dammget_register:
176323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
177323ef8dbSMagnus Damm	mov.l	@(r0, r5), r0
178323ef8dbSMagnus Damm	rts
179323ef8dbSMagnus Damm	 nop
180323ef8dbSMagnus DammENTRY(sh_mobile_sleep_enter_end)
181323ef8dbSMagnus Damm
182323ef8dbSMagnus Damm	.balign 4
183323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_start)
184323ef8dbSMagnus Damm
185323ef8dbSMagnus Damm	/* figure out start address */
186323ef8dbSMagnus Damm	bsr	0f
187323ef8dbSMagnus Damm	 nop
188323ef8dbSMagnus Damm0:
189323ef8dbSMagnus Damm	sts	pr, k1
190323ef8dbSMagnus Damm	mov.l	1f, k0
191323ef8dbSMagnus Damm	and	k0, k1
192323ef8dbSMagnus Damm
193323ef8dbSMagnus Damm	/* store pointer to data area in VBR */
194323ef8dbSMagnus Damm	ldc	k1, vbr
195323ef8dbSMagnus Damm
196323ef8dbSMagnus Damm	/* setup sr with saved sr */
197323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SR, k1), k0
198323ef8dbSMagnus Damm	ldc	k0, sr
199323ef8dbSMagnus Damm
200323ef8dbSMagnus Damm	/* now: user register set! */
201323ef8dbSMagnus Damm	stc	vbr, r5
202323ef8dbSMagnus Damm
203309214afSMagnus Damm	/* setup spc with return address to c code */
204323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SPC, r5), r0
205323ef8dbSMagnus Damm	ldc	r0, spc
206309214afSMagnus Damm
207309214afSMagnus Damm	/* restore vbr */
208323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_VBR, r5), r0
209323ef8dbSMagnus Damm	ldc	r0, vbr
210309214afSMagnus Damm
211309214afSMagnus Damm	/* setup ssr with saved sr */
212323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SR, r5), r0
213323ef8dbSMagnus Damm	ldc	r0, ssr
214309214afSMagnus Damm
215bb3e0eedSMagnus Damm	/* restore sp */
216bb3e0eedSMagnus Damm	mov.l   @(SH_SLEEP_SP, r5), r15
217bb3e0eedSMagnus Damm
218323ef8dbSMagnus Damm	/* restore sleep mode register */
219323ef8dbSMagnus Damm	bsr     restore_register
220323ef8dbSMagnus Damm	 mov    #SH_SLEEP_REG_STBCR, r0
221e9edb3feSPaul Mundt
222323ef8dbSMagnus Damm	/* call self-refresh resume code if needed */
223323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
224323ef8dbSMagnus Damm	tst	#SUSP_SH_SF, r0
225e9edb3feSPaul Mundt	bt	skip_restore_sf
226e9edb3feSPaul Mundt
227323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SF_POST, r5), r0
228323ef8dbSMagnus Damm	jsr	@r0
229237674e0SMagnus Damm	 nop
230237674e0SMagnus Damm
231e9edb3feSPaul Mundtskip_restore_sf:
23299675a7aSMagnus Damm	/* restore mmu and cache state if needed */
23399675a7aSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
23499675a7aSMagnus Damm	tst	#SUSP_SH_MMU, r0
23599675a7aSMagnus Damm	bt	skip_restore_mmu
23699675a7aSMagnus Damm
23799675a7aSMagnus Damm	/* restore mmu state */
23899675a7aSMagnus Damm	bsr	restore_register
23999675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEH, r0
24099675a7aSMagnus Damm
24199675a7aSMagnus Damm	bsr	restore_register
24299675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEL, r0
24399675a7aSMagnus Damm
24499675a7aSMagnus Damm	bsr	restore_register
24599675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_TTB, r0
24699675a7aSMagnus Damm
24799675a7aSMagnus Damm	bsr	restore_register
24899675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_TEA, r0
24999675a7aSMagnus Damm
25099675a7aSMagnus Damm	bsr	restore_register
25199675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEA, r0
25299675a7aSMagnus Damm
25399675a7aSMagnus Damm	bsr	restore_register
25499675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PASCR, r0
25599675a7aSMagnus Damm
25699675a7aSMagnus Damm	bsr	restore_register
25799675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_IRMCR, r0
25899675a7aSMagnus Damm
25999675a7aSMagnus Damm	bsr	restore_register
26099675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_MMUCR, r0
26199675a7aSMagnus Damm	icbi	@r0
26299675a7aSMagnus Damm
26399675a7aSMagnus Damm	/* restore cache settings */
26499675a7aSMagnus Damm	bsr	restore_register
26599675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_RAMCR, r0
26699675a7aSMagnus Damm	icbi	@r0
26799675a7aSMagnus Damm
26899675a7aSMagnus Damm	bsr	restore_register
26999675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_CCR, r0
27099675a7aSMagnus Damm	icbi	@r0
27199675a7aSMagnus Damm
27299675a7aSMagnus Dammskip_restore_mmu:
273323ef8dbSMagnus Damm	rte
274323ef8dbSMagnus Damm	 nop
275323ef8dbSMagnus Damm
276323ef8dbSMagnus Dammrestore_register:
277323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_DATA, r0
278323ef8dbSMagnus Damm	mov.l	@(r0, r5), r1
279323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_DATA, r0
280323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
281323ef8dbSMagnus Damm	mov.l	@(r0, r5), r0
282323ef8dbSMagnus Damm	mov.l	r1, @r0
283323ef8dbSMagnus Damm	rts
284e9edb3feSPaul Mundt	 nop
285e9edb3feSPaul Mundt
286e9edb3feSPaul Mundt	.balign 4
287323ef8dbSMagnus Damm1:	.long	~0x7ff
288323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_end)
289