xref: /openbmc/linux/arch/sh/kernel/cpu/shmobile/sleep.S (revision 323ef8db)
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
55323ef8dbSMagnus Damm	/* call self-refresh entering code if needed */
56323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
57e9edb3feSPaul Mundt	tst	#SUSP_SH_SF, r0
58e9edb3feSPaul Mundt	bt	skip_set_sf
59237674e0SMagnus Damm
60323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SF_PRE, r5), r0
61323ef8dbSMagnus Damm	jsr	@r0
62323ef8dbSMagnus Damm	 nop
63e9edb3feSPaul Mundt
64e9edb3feSPaul Mundtskip_set_sf:
65323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
66e9edb3feSPaul Mundt	tst	#SUSP_SH_STANDBY, r0
67e9edb3feSPaul Mundt	bt	test_rstandby
68e9edb3feSPaul Mundt
69e9edb3feSPaul Mundt	/* set mode to "software standby mode" */
70e9edb3feSPaul Mundt	bra	do_sleep
71e9edb3feSPaul Mundt	 mov	#0x80, r1
72e9edb3feSPaul Mundt
73e9edb3feSPaul Mundttest_rstandby:
74e9edb3feSPaul Mundt	tst	#SUSP_SH_RSTANDBY, r0
75e9edb3feSPaul Mundt	bt	test_ustandby
76e9edb3feSPaul Mundt
77e9edb3feSPaul Mundt	/* set mode to "r-standby mode" */
78e9edb3feSPaul Mundt	bra	do_sleep
79e9edb3feSPaul Mundt	 mov	#0x20, r1
80e9edb3feSPaul Mundt
81e9edb3feSPaul Mundttest_ustandby:
82e9edb3feSPaul Mundt	tst	#SUSP_SH_USTANDBY, r0
83309214afSMagnus Damm	bt	force_sleep
84e9edb3feSPaul Mundt
85e9edb3feSPaul Mundt	/* set mode to "u-standby mode" */
86309214afSMagnus Damm	bra	do_sleep
87e9edb3feSPaul Mundt	 mov	#0x10, r1
88e9edb3feSPaul Mundt
89309214afSMagnus Dammforce_sleep:
90309214afSMagnus Damm
91309214afSMagnus Damm	/* set mode to "sleep mode" */
92309214afSMagnus Damm	mov	#0x00, r1
93e9edb3feSPaul Mundt
94e9edb3feSPaul Mundtdo_sleep:
95e9edb3feSPaul Mundt	/* setup and enter selected standby mode */
96323ef8dbSMagnus Damm	bsr     get_register
97323ef8dbSMagnus Damm	 mov    #SH_SLEEP_REG_STBCR, r0
98323ef8dbSMagnus Damm	mov.l	r1, @r0
99309214afSMagnus Dammagain:
100e9edb3feSPaul Mundt	sleep
101309214afSMagnus Damm	bra	again
102309214afSMagnus Damm	 nop
103309214afSMagnus Damm
104323ef8dbSMagnus Dammsave_register:
105323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
106323ef8dbSMagnus Damm	mov.l	@(r0, r5), r1
107323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_ADDR, r0
108323ef8dbSMagnus Damm	mov.l	@r1, r1
109323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_DATA, r0
110323ef8dbSMagnus Damm	mov.l	r1, @(r0, r5)
111323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_DATA, r0
112323ef8dbSMagnus Damm	rts
113323ef8dbSMagnus Damm	 nop
114323ef8dbSMagnus Damm
115323ef8dbSMagnus Dammget_register:
116323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
117323ef8dbSMagnus Damm	mov.l	@(r0, r5), r0
118323ef8dbSMagnus Damm	rts
119323ef8dbSMagnus Damm	 nop
120323ef8dbSMagnus DammENTRY(sh_mobile_sleep_enter_end)
121323ef8dbSMagnus Damm
122323ef8dbSMagnus Damm	.balign 4
123323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_start)
124323ef8dbSMagnus Damm
125323ef8dbSMagnus Damm	/* figure out start address */
126323ef8dbSMagnus Damm	bsr	0f
127323ef8dbSMagnus Damm	 nop
128323ef8dbSMagnus Damm0:
129323ef8dbSMagnus Damm	sts	pr, k1
130323ef8dbSMagnus Damm	mov.l	1f, k0
131323ef8dbSMagnus Damm	and	k0, k1
132323ef8dbSMagnus Damm
133323ef8dbSMagnus Damm	/* store pointer to data area in VBR */
134323ef8dbSMagnus Damm	ldc	k1, vbr
135323ef8dbSMagnus Damm
136323ef8dbSMagnus Damm	/* setup sr with saved sr */
137323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SR, k1), k0
138323ef8dbSMagnus Damm	ldc	k0, sr
139323ef8dbSMagnus Damm
140323ef8dbSMagnus Damm	/* now: user register set! */
141323ef8dbSMagnus Damm	stc	vbr, r5
142323ef8dbSMagnus Damm
143309214afSMagnus Damm	/* setup spc with return address to c code */
144323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SPC, r5), r0
145323ef8dbSMagnus Damm	ldc	r0, spc
146309214afSMagnus Damm
147309214afSMagnus Damm	/* restore vbr */
148323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_VBR, r5), r0
149323ef8dbSMagnus Damm	ldc	r0, vbr
150309214afSMagnus Damm
151309214afSMagnus Damm	/* setup ssr with saved sr */
152323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SR, r5), r0
153323ef8dbSMagnus Damm	ldc	r0, ssr
154309214afSMagnus Damm
155323ef8dbSMagnus Damm	/* restore sleep mode register */
156323ef8dbSMagnus Damm	bsr     restore_register
157323ef8dbSMagnus Damm	 mov    #SH_SLEEP_REG_STBCR, r0
158e9edb3feSPaul Mundt
159323ef8dbSMagnus Damm	/* call self-refresh resume code if needed */
160323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_MODE, r5), r0
161323ef8dbSMagnus Damm	tst	#SUSP_SH_SF, r0
162e9edb3feSPaul Mundt	bt	skip_restore_sf
163e9edb3feSPaul Mundt
164323ef8dbSMagnus Damm	mov.l	@(SH_SLEEP_SF_POST, r5), r0
165323ef8dbSMagnus Damm	jsr	@r0
166237674e0SMagnus Damm	 nop
167237674e0SMagnus Damm
168e9edb3feSPaul Mundtskip_restore_sf:
169323ef8dbSMagnus Damm	rte
170323ef8dbSMagnus Damm	 nop
171323ef8dbSMagnus Damm
172323ef8dbSMagnus Dammrestore_register:
173323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_DATA, r0
174323ef8dbSMagnus Damm	mov.l	@(r0, r5), r1
175323ef8dbSMagnus Damm	add	#-SH_SLEEP_BASE_DATA, r0
176323ef8dbSMagnus Damm	add	#SH_SLEEP_BASE_ADDR, r0
177323ef8dbSMagnus Damm	mov.l	@(r0, r5), r0
178323ef8dbSMagnus Damm	mov.l	r1, @r0
179323ef8dbSMagnus Damm	rts
180e9edb3feSPaul Mundt	 nop
181e9edb3feSPaul Mundt
182e9edb3feSPaul Mundt	.balign 4
183323ef8dbSMagnus Damm1:	.long	~0x7ff
184323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_end)
185