xref: /OK3568_Linux_fs/kernel/arch/mips/alchemy/common/sleeper.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-or-later */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun * Copyright 2002 Embedded Edge, LLC
4*4882a593Smuzhiyun * Author: dan@embeddededge.com
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Sleep helper for Au1xxx sleep mode.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun#include <asm/asm.h>
10*4882a593Smuzhiyun#include <asm/mipsregs.h>
11*4882a593Smuzhiyun#include <asm/regdef.h>
12*4882a593Smuzhiyun#include <asm/stackframe.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun	.extern __flush_cache_all
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun	.text
17*4882a593Smuzhiyun	.set noreorder
18*4882a593Smuzhiyun	.set noat
19*4882a593Smuzhiyun	.align	5
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun/* preparatory stuff */
23*4882a593Smuzhiyun.macro	SETUP_SLEEP
24*4882a593Smuzhiyun	subu	sp, PT_SIZE
25*4882a593Smuzhiyun	sw	$1, PT_R1(sp)
26*4882a593Smuzhiyun	sw	$2, PT_R2(sp)
27*4882a593Smuzhiyun	sw	$3, PT_R3(sp)
28*4882a593Smuzhiyun	sw	$4, PT_R4(sp)
29*4882a593Smuzhiyun	sw	$5, PT_R5(sp)
30*4882a593Smuzhiyun	sw	$6, PT_R6(sp)
31*4882a593Smuzhiyun	sw	$7, PT_R7(sp)
32*4882a593Smuzhiyun	sw	$16, PT_R16(sp)
33*4882a593Smuzhiyun	sw	$17, PT_R17(sp)
34*4882a593Smuzhiyun	sw	$18, PT_R18(sp)
35*4882a593Smuzhiyun	sw	$19, PT_R19(sp)
36*4882a593Smuzhiyun	sw	$20, PT_R20(sp)
37*4882a593Smuzhiyun	sw	$21, PT_R21(sp)
38*4882a593Smuzhiyun	sw	$22, PT_R22(sp)
39*4882a593Smuzhiyun	sw	$23, PT_R23(sp)
40*4882a593Smuzhiyun	sw	$26, PT_R26(sp)
41*4882a593Smuzhiyun	sw	$27, PT_R27(sp)
42*4882a593Smuzhiyun	sw	$28, PT_R28(sp)
43*4882a593Smuzhiyun	sw	$30, PT_R30(sp)
44*4882a593Smuzhiyun	sw	$31, PT_R31(sp)
45*4882a593Smuzhiyun	mfc0	k0, CP0_STATUS
46*4882a593Smuzhiyun	sw	k0, 0x20(sp)
47*4882a593Smuzhiyun	mfc0	k0, CP0_CONTEXT
48*4882a593Smuzhiyun	sw	k0, 0x1c(sp)
49*4882a593Smuzhiyun	mfc0	k0, CP0_PAGEMASK
50*4882a593Smuzhiyun	sw	k0, 0x18(sp)
51*4882a593Smuzhiyun	mfc0	k0, CP0_CONFIG
52*4882a593Smuzhiyun	sw	k0, 0x14(sp)
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun	/* flush caches to make sure context is in memory */
55*4882a593Smuzhiyun	la	t1, __flush_cache_all
56*4882a593Smuzhiyun	lw	t0, 0(t1)
57*4882a593Smuzhiyun	jalr	t0
58*4882a593Smuzhiyun	 nop
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun	/* Now set up the scratch registers so the boot rom will
61*4882a593Smuzhiyun	 * return to this point upon wakeup.
62*4882a593Smuzhiyun	 * sys_scratch0 : SP
63*4882a593Smuzhiyun	 * sys_scratch1 : RA
64*4882a593Smuzhiyun	 */
65*4882a593Smuzhiyun	lui	t3, 0xb190		/* sys_xxx */
66*4882a593Smuzhiyun	sw	sp, 0x0018(t3)
67*4882a593Smuzhiyun	la	k0, alchemy_sleep_wakeup	/* resume path */
68*4882a593Smuzhiyun	sw	k0, 0x001c(t3)
69*4882a593Smuzhiyun.endm
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun.macro	DO_SLEEP
72*4882a593Smuzhiyun	/* put power supply and processor to sleep */
73*4882a593Smuzhiyun	sw	zero, 0x0078(t3)	/* sys_slppwr */
74*4882a593Smuzhiyun	sync
75*4882a593Smuzhiyun	sw	zero, 0x007c(t3)	/* sys_sleep */
76*4882a593Smuzhiyun	sync
77*4882a593Smuzhiyun	nop
78*4882a593Smuzhiyun	nop
79*4882a593Smuzhiyun	nop
80*4882a593Smuzhiyun	nop
81*4882a593Smuzhiyun	nop
82*4882a593Smuzhiyun	nop
83*4882a593Smuzhiyun	nop
84*4882a593Smuzhiyun	nop
85*4882a593Smuzhiyun.endm
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun/* sleep code for Au1000/Au1100/Au1500 memory controller type */
88*4882a593SmuzhiyunLEAF(alchemy_sleep_au1000)
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun	SETUP_SLEEP
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun	/* cache following instructions, as memory gets put to sleep */
93*4882a593Smuzhiyun	la	t0, 1f
94*4882a593Smuzhiyun	.set	arch=r4000
95*4882a593Smuzhiyun	cache	0x14, 0(t0)
96*4882a593Smuzhiyun	cache	0x14, 32(t0)
97*4882a593Smuzhiyun	cache	0x14, 64(t0)
98*4882a593Smuzhiyun	cache	0x14, 96(t0)
99*4882a593Smuzhiyun	.set	mips0
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun1:	lui	a0, 0xb400		/* mem_xxx */
102*4882a593Smuzhiyun	sw	zero, 0x001c(a0)	/* Precharge */
103*4882a593Smuzhiyun	sync
104*4882a593Smuzhiyun	sw	zero, 0x0020(a0)	/* Auto Refresh */
105*4882a593Smuzhiyun	sync
106*4882a593Smuzhiyun	sw	zero, 0x0030(a0)	/* Sleep */
107*4882a593Smuzhiyun	sync
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun	DO_SLEEP
110*4882a593Smuzhiyun
111*4882a593SmuzhiyunEND(alchemy_sleep_au1000)
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun/* sleep code for Au1550/Au1200 memory controller type */
114*4882a593SmuzhiyunLEAF(alchemy_sleep_au1550)
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun	SETUP_SLEEP
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun	/* cache following instructions, as memory gets put to sleep */
119*4882a593Smuzhiyun	la	t0, 1f
120*4882a593Smuzhiyun	.set	arch=r4000
121*4882a593Smuzhiyun	cache	0x14, 0(t0)
122*4882a593Smuzhiyun	cache	0x14, 32(t0)
123*4882a593Smuzhiyun	cache	0x14, 64(t0)
124*4882a593Smuzhiyun	cache	0x14, 96(t0)
125*4882a593Smuzhiyun	.set	mips0
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun1:	lui	a0, 0xb400		/* mem_xxx */
128*4882a593Smuzhiyun	sw	zero, 0x08c0(a0)	/* Precharge */
129*4882a593Smuzhiyun	sync
130*4882a593Smuzhiyun	sw	zero, 0x08d0(a0)	/* Self Refresh */
131*4882a593Smuzhiyun	sync
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun	/* wait for sdram to enter self-refresh mode */
134*4882a593Smuzhiyun	lui	t0, 0x0100
135*4882a593Smuzhiyun2:	lw	t1, 0x0850(a0)		/* mem_sdstat */
136*4882a593Smuzhiyun	and	t2, t1, t0
137*4882a593Smuzhiyun	beq	t2, zero, 2b
138*4882a593Smuzhiyun	 nop
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun	/* disable SDRAM clocks */
141*4882a593Smuzhiyun	lui	t0, 0xcfff
142*4882a593Smuzhiyun	ori	t0, t0, 0xffff
143*4882a593Smuzhiyun	lw	t1, 0x0840(a0)		/* mem_sdconfiga */
144*4882a593Smuzhiyun	and	t1, t0, t1		/* clear CE[1:0] */
145*4882a593Smuzhiyun	sw	t1, 0x0840(a0)		/* mem_sdconfiga */
146*4882a593Smuzhiyun	sync
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun	DO_SLEEP
149*4882a593Smuzhiyun
150*4882a593SmuzhiyunEND(alchemy_sleep_au1550)
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun/* sleepcode for Au1300 memory controller type */
153*4882a593SmuzhiyunLEAF(alchemy_sleep_au1300)
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun	SETUP_SLEEP
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun	/* cache following instructions, as memory gets put to sleep */
158*4882a593Smuzhiyun	la	t0, 2f
159*4882a593Smuzhiyun	la	t1, 4f
160*4882a593Smuzhiyun	subu	t2, t1, t0
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun	.set	arch=r4000
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun1:	cache	0x14, 0(t0)
165*4882a593Smuzhiyun	subu	t2, t2, 32
166*4882a593Smuzhiyun	bgez	t2, 1b
167*4882a593Smuzhiyun	 addu	t0, t0, 32
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun	.set	mips0
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun2:	lui	a0, 0xb400		/* mem_xxx */
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun	/* disable all ports in mem_sdportcfga */
174*4882a593Smuzhiyun	sw	zero, 0x868(a0)		/* mem_sdportcfga */
175*4882a593Smuzhiyun	sync
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun	/* disable ODT */
178*4882a593Smuzhiyun	li	t0, 0x03010000
179*4882a593Smuzhiyun	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */
180*4882a593Smuzhiyun	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */
181*4882a593Smuzhiyun	sync
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun	/* precharge */
184*4882a593Smuzhiyun	li	t0, 0x23000400
185*4882a593Smuzhiyun	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */
186*4882a593Smuzhiyun	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */
187*4882a593Smuzhiyun	sync
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun	/* auto refresh */
190*4882a593Smuzhiyun	sw	zero, 0x08c8(a0)	/* mem_sdautoref */
191*4882a593Smuzhiyun	sync
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun	/* block access to the DDR */
194*4882a593Smuzhiyun	lw	t0, 0x0848(a0)		/* mem_sdconfigb */
195*4882a593Smuzhiyun	li	t1, (1 << 7 | 0x3F)
196*4882a593Smuzhiyun	or	t0, t0, t1
197*4882a593Smuzhiyun	sw	t0, 0x0848(a0)		/* mem_sdconfigb */
198*4882a593Smuzhiyun	sync
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun	/* issue the Self Refresh command */
201*4882a593Smuzhiyun	li	t0, 0x10000000
202*4882a593Smuzhiyun	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */
203*4882a593Smuzhiyun	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */
204*4882a593Smuzhiyun	sync
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun	/* wait for sdram to enter self-refresh mode */
207*4882a593Smuzhiyun	lui	t0, 0x0300
208*4882a593Smuzhiyun3:	lw	t1, 0x0850(a0)		/* mem_sdstat */
209*4882a593Smuzhiyun	and	t2, t1, t0
210*4882a593Smuzhiyun	bne	t2, t0, 3b
211*4882a593Smuzhiyun	 nop
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun	/* disable SDRAM clocks */
214*4882a593Smuzhiyun	li	t0, ~(3<<28)
215*4882a593Smuzhiyun	lw	t1, 0x0840(a0)		/* mem_sdconfiga */
216*4882a593Smuzhiyun	and	t1, t1, t0		/* clear CE[1:0] */
217*4882a593Smuzhiyun	sw	t1, 0x0840(a0)		/* mem_sdconfiga */
218*4882a593Smuzhiyun	sync
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun	DO_SLEEP
221*4882a593Smuzhiyun4:
222*4882a593Smuzhiyun
223*4882a593SmuzhiyunEND(alchemy_sleep_au1300)
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun	/* This is where we return upon wakeup.
227*4882a593Smuzhiyun	 * Reload all of the registers and return.
228*4882a593Smuzhiyun	 */
229*4882a593SmuzhiyunLEAF(alchemy_sleep_wakeup)
230*4882a593Smuzhiyun	lw	k0, 0x20(sp)
231*4882a593Smuzhiyun	mtc0	k0, CP0_STATUS
232*4882a593Smuzhiyun	lw	k0, 0x1c(sp)
233*4882a593Smuzhiyun	mtc0	k0, CP0_CONTEXT
234*4882a593Smuzhiyun	lw	k0, 0x18(sp)
235*4882a593Smuzhiyun	mtc0	k0, CP0_PAGEMASK
236*4882a593Smuzhiyun	lw	k0, 0x14(sp)
237*4882a593Smuzhiyun	mtc0	k0, CP0_CONFIG
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun	/* We need to catch the early Alchemy SOCs with
240*4882a593Smuzhiyun	 * the write-only Config[OD] bit and set it back to one...
241*4882a593Smuzhiyun	 */
242*4882a593Smuzhiyun	jal	au1x00_fixup_config_od
243*4882a593Smuzhiyun	 nop
244*4882a593Smuzhiyun	lw	$1, PT_R1(sp)
245*4882a593Smuzhiyun	lw	$2, PT_R2(sp)
246*4882a593Smuzhiyun	lw	$3, PT_R3(sp)
247*4882a593Smuzhiyun	lw	$4, PT_R4(sp)
248*4882a593Smuzhiyun	lw	$5, PT_R5(sp)
249*4882a593Smuzhiyun	lw	$6, PT_R6(sp)
250*4882a593Smuzhiyun	lw	$7, PT_R7(sp)
251*4882a593Smuzhiyun	lw	$16, PT_R16(sp)
252*4882a593Smuzhiyun	lw	$17, PT_R17(sp)
253*4882a593Smuzhiyun	lw	$18, PT_R18(sp)
254*4882a593Smuzhiyun	lw	$19, PT_R19(sp)
255*4882a593Smuzhiyun	lw	$20, PT_R20(sp)
256*4882a593Smuzhiyun	lw	$21, PT_R21(sp)
257*4882a593Smuzhiyun	lw	$22, PT_R22(sp)
258*4882a593Smuzhiyun	lw	$23, PT_R23(sp)
259*4882a593Smuzhiyun	lw	$26, PT_R26(sp)
260*4882a593Smuzhiyun	lw	$27, PT_R27(sp)
261*4882a593Smuzhiyun	lw	$28, PT_R28(sp)
262*4882a593Smuzhiyun	lw	$30, PT_R30(sp)
263*4882a593Smuzhiyun	lw	$31, PT_R31(sp)
264*4882a593Smuzhiyun	jr	ra
265*4882a593Smuzhiyun	 addiu	sp, PT_SIZE
266*4882a593SmuzhiyunEND(alchemy_sleep_wakeup)
267