xref: /openbmc/linux/arch/sh/kernel/cpu/shmobile/sleep.S (revision 323ef8db)
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	/* call self-refresh entering code if needed */
56	mov.l	@(SH_SLEEP_MODE, r5), r0
57	tst	#SUSP_SH_SF, r0
58	bt	skip_set_sf
59
60	mov.l	@(SH_SLEEP_SF_PRE, r5), r0
61	jsr	@r0
62	 nop
63
64skip_set_sf:
65	mov.l	@(SH_SLEEP_MODE, r5), r0
66	tst	#SUSP_SH_STANDBY, r0
67	bt	test_rstandby
68
69	/* set mode to "software standby mode" */
70	bra	do_sleep
71	 mov	#0x80, r1
72
73test_rstandby:
74	tst	#SUSP_SH_RSTANDBY, r0
75	bt	test_ustandby
76
77	/* set mode to "r-standby mode" */
78	bra	do_sleep
79	 mov	#0x20, r1
80
81test_ustandby:
82	tst	#SUSP_SH_USTANDBY, r0
83	bt	force_sleep
84
85	/* set mode to "u-standby mode" */
86	bra	do_sleep
87	 mov	#0x10, r1
88
89force_sleep:
90
91	/* set mode to "sleep mode" */
92	mov	#0x00, r1
93
94do_sleep:
95	/* setup and enter selected standby mode */
96	bsr     get_register
97	 mov    #SH_SLEEP_REG_STBCR, r0
98	mov.l	r1, @r0
99again:
100	sleep
101	bra	again
102	 nop
103
104save_register:
105	add	#SH_SLEEP_BASE_ADDR, r0
106	mov.l	@(r0, r5), r1
107	add	#-SH_SLEEP_BASE_ADDR, r0
108	mov.l	@r1, r1
109	add	#SH_SLEEP_BASE_DATA, r0
110	mov.l	r1, @(r0, r5)
111	add	#-SH_SLEEP_BASE_DATA, r0
112	rts
113	 nop
114
115get_register:
116	add	#SH_SLEEP_BASE_ADDR, r0
117	mov.l	@(r0, r5), r0
118	rts
119	 nop
120ENTRY(sh_mobile_sleep_enter_end)
121
122	.balign 4
123ENTRY(sh_mobile_sleep_resume_start)
124
125	/* figure out start address */
126	bsr	0f
127	 nop
1280:
129	sts	pr, k1
130	mov.l	1f, k0
131	and	k0, k1
132
133	/* store pointer to data area in VBR */
134	ldc	k1, vbr
135
136	/* setup sr with saved sr */
137	mov.l	@(SH_SLEEP_SR, k1), k0
138	ldc	k0, sr
139
140	/* now: user register set! */
141	stc	vbr, r5
142
143	/* setup spc with return address to c code */
144	mov.l	@(SH_SLEEP_SPC, r5), r0
145	ldc	r0, spc
146
147	/* restore vbr */
148	mov.l	@(SH_SLEEP_VBR, r5), r0
149	ldc	r0, vbr
150
151	/* setup ssr with saved sr */
152	mov.l	@(SH_SLEEP_SR, r5), r0
153	ldc	r0, ssr
154
155	/* restore sleep mode register */
156	bsr     restore_register
157	 mov    #SH_SLEEP_REG_STBCR, r0
158
159	/* call self-refresh resume code if needed */
160	mov.l	@(SH_SLEEP_MODE, r5), r0
161	tst	#SUSP_SH_SF, r0
162	bt	skip_restore_sf
163
164	mov.l	@(SH_SLEEP_SF_POST, r5), r0
165	jsr	@r0
166	 nop
167
168skip_restore_sf:
169	rte
170	 nop
171
172restore_register:
173	add	#SH_SLEEP_BASE_DATA, r0
174	mov.l	@(r0, r5), r1
175	add	#-SH_SLEEP_BASE_DATA, r0
176	add	#SH_SLEEP_BASE_ADDR, r0
177	mov.l	@(r0, r5), r0
178	mov.l	r1, @r0
179	rts
180	 nop
181
182	.balign 4
1831:	.long	~0x7ff
184ENTRY(sh_mobile_sleep_resume_end)
185