xref: /openbmc/linux/arch/sh/kernel/cpu/shmobile/sleep.S (revision 99675a7a)
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
51323ef8dbSMagnus Damm	/* save stbcr */
52323ef8dbSMagnus Damm	bsr     save_register
53323ef8dbSMagnus Damm	 mov    #SH_SLEEP_REG_STBCR, r0
54309214afSMagnus Damm
5599675a7aSMagnus Damm	/* save mmu and cache context if needed */
5699675a7aSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
5799675a7aSMagnus Damm	tst	#SUSP_SH_MMU, r0
5899675a7aSMagnus Damm	bt	skip_mmu_save_disable
5999675a7aSMagnus Damm
6099675a7aSMagnus Damm       /* save mmu state */
6199675a7aSMagnus Damm	bsr	save_register
6299675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEH, r0
6399675a7aSMagnus Damm
6499675a7aSMagnus Damm	bsr	save_register
6599675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEL, r0
6699675a7aSMagnus Damm
6799675a7aSMagnus Damm	bsr	save_register
6899675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_TTB, r0
6999675a7aSMagnus Damm
7099675a7aSMagnus Damm	bsr	save_register
7199675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_TEA, r0
7299675a7aSMagnus Damm
7399675a7aSMagnus Damm	bsr	save_register
7499675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_MMUCR, r0
7599675a7aSMagnus Damm
7699675a7aSMagnus Damm	bsr	save_register
7799675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEA, r0
7899675a7aSMagnus Damm
7999675a7aSMagnus Damm	bsr	save_register
8099675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PASCR, r0
8199675a7aSMagnus Damm
8299675a7aSMagnus Damm	bsr	save_register
8399675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_IRMCR, r0
8499675a7aSMagnus Damm
8599675a7aSMagnus Damm	/* invalidate TLBs and disable the MMU */
8699675a7aSMagnus Damm	bsr	get_register
8799675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_MMUCR, r0
8899675a7aSMagnus Damm	mov	#4, r1
8999675a7aSMagnus Damm	mov.l	r1, @r0
9099675a7aSMagnus Damm	icbi	@r0
9199675a7aSMagnus Damm
9299675a7aSMagnus Damm	/* save cache registers and disable caches */
9399675a7aSMagnus Damm	bsr	save_register
9499675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_CCR, r0
9599675a7aSMagnus Damm
9699675a7aSMagnus Damm	bsr	save_register
9799675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_RAMCR, r0
9899675a7aSMagnus Damm
9999675a7aSMagnus Damm	bsr	get_register
10099675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_CCR, r0
10199675a7aSMagnus Damm	mov	#0, r1
10299675a7aSMagnus Damm	mov.l	r1, @r0
10399675a7aSMagnus Damm	icbi	@r0
10499675a7aSMagnus Damm
10599675a7aSMagnus Dammskip_mmu_save_disable:
106323ef8dbSMagnus Damm	/* call self-refresh entering code if needed */
107323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
108e9edb3feSPaul Mundt	tst	#SUSP_SH_SF, r0
109e9edb3feSPaul Mundt	bt	skip_set_sf
110237674e0SMagnus Damm
111323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SF_PRE, r5), r0
112323ef8dbSMagnus Damm	jsr	@r0
113323ef8dbSMagnus Damm	 nop
114e9edb3feSPaul Mundt
115e9edb3feSPaul Mundtskip_set_sf:
116323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
117e9edb3feSPaul Mundt	tst	#SUSP_SH_STANDBY, r0
118e9edb3feSPaul Mundt	bt	test_rstandby
119e9edb3feSPaul Mundt
120e9edb3feSPaul Mundt	/* set mode to "software standby mode" */
121e9edb3feSPaul Mundt	bra	do_sleep
122e9edb3feSPaul Mundt	 mov	#0x80, r1
123e9edb3feSPaul Mundt
124e9edb3feSPaul Mundttest_rstandby:
125e9edb3feSPaul Mundt	tst	#SUSP_SH_RSTANDBY, r0
126e9edb3feSPaul Mundt	bt	test_ustandby
127e9edb3feSPaul Mundt
128e9edb3feSPaul Mundt	/* set mode to "r-standby mode" */
129e9edb3feSPaul Mundt	bra	do_sleep
130e9edb3feSPaul Mundt	 mov	#0x20, r1
131e9edb3feSPaul Mundt
132e9edb3feSPaul Mundttest_ustandby:
133e9edb3feSPaul Mundt	tst	#SUSP_SH_USTANDBY, r0
134309214afSMagnus Damm	bt	force_sleep
135e9edb3feSPaul Mundt
136e9edb3feSPaul Mundt	/* set mode to "u-standby mode" */
137309214afSMagnus Damm	bra	do_sleep
138e9edb3feSPaul Mundt	 mov	#0x10, r1
139e9edb3feSPaul Mundt
140309214afSMagnus Dammforce_sleep:
141309214afSMagnus Damm
142309214afSMagnus Damm	/* set mode to "sleep mode" */
143309214afSMagnus Damm	mov	#0x00, r1
144e9edb3feSPaul Mundt
145e9edb3feSPaul Mundtdo_sleep:
146e9edb3feSPaul Mundt	/* setup and enter selected standby mode */
147323ef8dbSMagnus Damm	bsr     get_register
148323ef8dbSMagnus Damm	 mov    #SH_SLEEP_REG_STBCR, r0
149323ef8dbSMagnus Damm	mov.l	r1, @r0
150309214afSMagnus Dammagain:
151e9edb3feSPaul Mundt	sleep
152309214afSMagnus Damm	bra	again
153309214afSMagnus Damm	 nop
154309214afSMagnus Damm
155323ef8dbSMagnus Dammsave_register:
156323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
157323ef8dbSMagnus Damm	mov.l	@(r0, r5), r1
158323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_ADDR, r0
159323ef8dbSMagnus Damm	mov.l	@r1, r1
160323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_DATA, r0
161323ef8dbSMagnus Damm	mov.l	r1, @(r0, r5)
162323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_DATA, r0
163323ef8dbSMagnus Damm	rts
164323ef8dbSMagnus Damm	 nop
165323ef8dbSMagnus Damm
166323ef8dbSMagnus Dammget_register:
167323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
168323ef8dbSMagnus Damm	mov.l	@(r0, r5), r0
169323ef8dbSMagnus Damm	rts
170323ef8dbSMagnus Damm	 nop
171323ef8dbSMagnus DammENTRY(sh_mobile_sleep_enter_end)
172323ef8dbSMagnus Damm
173323ef8dbSMagnus Damm	.balign 4
174323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_start)
175323ef8dbSMagnus Damm
176323ef8dbSMagnus Damm	/* figure out start address */
177323ef8dbSMagnus Damm	bsr	0f
178323ef8dbSMagnus Damm	 nop
179323ef8dbSMagnus Damm0:
180323ef8dbSMagnus Damm	sts	pr, k1
181323ef8dbSMagnus Damm	mov.l	1f, k0
182323ef8dbSMagnus Damm	and	k0, k1
183323ef8dbSMagnus Damm
184323ef8dbSMagnus Damm	/* store pointer to data area in VBR */
185323ef8dbSMagnus Damm	ldc	k1, vbr
186323ef8dbSMagnus Damm
187323ef8dbSMagnus Damm	/* setup sr with saved sr */
188323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SR, k1), k0
189323ef8dbSMagnus Damm	ldc	k0, sr
190323ef8dbSMagnus Damm
191323ef8dbSMagnus Damm	/* now: user register set! */
192323ef8dbSMagnus Damm	stc	vbr, r5
193323ef8dbSMagnus Damm
194309214afSMagnus Damm	/* setup spc with return address to c code */
195323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SPC, r5), r0
196323ef8dbSMagnus Damm	ldc	r0, spc
197309214afSMagnus Damm
198309214afSMagnus Damm	/* restore vbr */
199323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_VBR, r5), r0
200323ef8dbSMagnus Damm	ldc	r0, vbr
201309214afSMagnus Damm
202309214afSMagnus Damm	/* setup ssr with saved sr */
203323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SR, r5), r0
204323ef8dbSMagnus Damm	ldc	r0, ssr
205309214afSMagnus Damm
206323ef8dbSMagnus Damm	/* restore sleep mode register */
207323ef8dbSMagnus Damm	bsr     restore_register
208323ef8dbSMagnus Damm	 mov    #SH_SLEEP_REG_STBCR, r0
209e9edb3feSPaul Mundt
210323ef8dbSMagnus Damm	/* call self-refresh resume code if needed */
211323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
212323ef8dbSMagnus Damm	tst	#SUSP_SH_SF, r0
213e9edb3feSPaul Mundt	bt	skip_restore_sf
214e9edb3feSPaul Mundt
215323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SF_POST, r5), r0
216323ef8dbSMagnus Damm	jsr	@r0
217237674e0SMagnus Damm	 nop
218237674e0SMagnus Damm
219e9edb3feSPaul Mundtskip_restore_sf:
22099675a7aSMagnus Damm	/* restore mmu and cache state if needed */
22199675a7aSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
22299675a7aSMagnus Damm	tst	#SUSP_SH_MMU, r0
22399675a7aSMagnus Damm	bt	skip_restore_mmu
22499675a7aSMagnus Damm
22599675a7aSMagnus Damm	/* restore mmu state */
22699675a7aSMagnus Damm	bsr	restore_register
22799675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEH, r0
22899675a7aSMagnus Damm
22999675a7aSMagnus Damm	bsr	restore_register
23099675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEL, r0
23199675a7aSMagnus Damm
23299675a7aSMagnus Damm	bsr	restore_register
23399675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_TTB, r0
23499675a7aSMagnus Damm
23599675a7aSMagnus Damm	bsr	restore_register
23699675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_TEA, r0
23799675a7aSMagnus Damm
23899675a7aSMagnus Damm	bsr	restore_register
23999675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PTEA, r0
24099675a7aSMagnus Damm
24199675a7aSMagnus Damm	bsr	restore_register
24299675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_PASCR, r0
24399675a7aSMagnus Damm
24499675a7aSMagnus Damm	bsr	restore_register
24599675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_IRMCR, r0
24699675a7aSMagnus Damm
24799675a7aSMagnus Damm	bsr	restore_register
24899675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_MMUCR, r0
24999675a7aSMagnus Damm	icbi	@r0
25099675a7aSMagnus Damm
25199675a7aSMagnus Damm	/* restore cache settings */
25299675a7aSMagnus Damm	bsr	restore_register
25399675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_RAMCR, r0
25499675a7aSMagnus Damm	icbi	@r0
25599675a7aSMagnus Damm
25699675a7aSMagnus Damm	bsr	restore_register
25799675a7aSMagnus Damm	 mov	#SH_SLEEP_REG_CCR, r0
25899675a7aSMagnus Damm	icbi	@r0
25999675a7aSMagnus Damm
26099675a7aSMagnus Dammskip_restore_mmu:
261323ef8dbSMagnus Damm	rte
262323ef8dbSMagnus Damm	 nop
263323ef8dbSMagnus Damm
264323ef8dbSMagnus Dammrestore_register:
265323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_DATA, r0
266323ef8dbSMagnus Damm	mov.l	@(r0, r5), r1
267323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_DATA, r0
268323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
269323ef8dbSMagnus Damm	mov.l	@(r0, r5), r0
270323ef8dbSMagnus Damm	mov.l	r1, @r0
271323ef8dbSMagnus Damm	rts
272e9edb3feSPaul Mundt	 nop
273e9edb3feSPaul Mundt
274e9edb3feSPaul Mundt	.balign 4
275323ef8dbSMagnus Damm1:	.long	~0x7ff
276323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_end)
277