1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2016 Broadcom Corporation
4  */
5 
6 #include <asm/asm.h>
7 #include <asm/regdef.h>
8 #include <asm/mipsregs.h>
9 #include <asm/stackframe.h>
10 
11 #include "pm.h"
12 
13 	.text
14 	.set	noreorder
15 	.align	5
16 
17 /*
18  * a0: u32 params array
19  */
20 LEAF(brcm_pm_do_s2)
21 
22 	subu	sp, 64
23 	sw	ra, 0(sp)
24 	sw	s0, 4(sp)
25 	sw	s1, 8(sp)
26 	sw	s2, 12(sp)
27 	sw	s3, 16(sp)
28 	sw	s4, 20(sp)
29 	sw	s5, 24(sp)
30 	sw	s6, 28(sp)
31 	sw	s7, 32(sp)
32 
33 	/*
34 	 * Dereference the params array
35 	 * s0: AON_CTRL base register
36 	 * s1: DDR_PHY base register
37 	 * s2: TIMERS base register
38 	 * s3: I-Cache line size
39 	 * s4: Restart vector address
40 	 * s5: Restart vector size
41 	 */
42 	move	t0, a0
43 
44 	lw	s0, 0(t0)
45 	lw	s1, 4(t0)
46 	lw	s2, 8(t0)
47 	lw	s3, 12(t0)
48 	lw	s4, 16(t0)
49 	lw	s5, 20(t0)
50 
51 	/* Lock this asm section into the I-cache */
52 	addiu	t1, s3, -1
53 	not	t1
54 
55 	la	t0, brcm_pm_do_s2
56 	and	t0, t1
57 
58 	la	t2, asm_end
59 	and	t2, t1
60 
61 1:	cache	0x1c, 0(t0)
62 	bne	t0, t2, 1b
63 	addu	t0, s3
64 
65 	/* Lock the interrupt vector into the I-cache */
66 	move	t0, zero
67 
68 2:	move	t1, s4
69 	cache 	0x1c, 0(t1)
70 	addu	t1, s3
71 	addu	t0, s3
72 	ble	t0, s5, 2b
73 	nop
74 
75 	sync
76 
77 	/* Power down request */
78 	li	t0, PM_S2_COMMAND
79 	sw	zero, AON_CTRL_PM_CTRL(s0)
80 	lw	zero, AON_CTRL_PM_CTRL(s0)
81 	sw	t0, AON_CTRL_PM_CTRL(s0)
82 	lw	t0, AON_CTRL_PM_CTRL(s0)
83 
84 	/* Enable CP0 interrupt 2 and wait for interrupt */
85 	mfc0	t0, CP0_STATUS
86 	/* Save cp0 sr for restoring later */
87 	move	s6, t0
88 
89 	li	t1, ~(ST0_IM | ST0_IE)
90 	and	t0, t1
91 	ori	t0, STATUSF_IP2
92 	mtc0	t0, CP0_STATUS
93 	nop
94 	nop
95 	nop
96 	ori	t0, ST0_IE
97 	mtc0	t0, CP0_STATUS
98 
99 	/* Wait for interrupt */
100 	wait
101 	nop
102 
103 	/* Wait for memc0 */
104 1:	lw	t0, DDR40_PHY_CONTROL_REGS_0_PLL_STATUS(s1)
105 	andi	t0, 1
106 	beqz	t0, 1b
107 	nop
108 
109 	/* 1ms delay needed for stable recovery */
110 	/* Use TIMER1 to count 1 ms */
111 	li	t0, RESET_TIMER
112 	sw	t0, TIMER_TIMER1_CTRL(s2)
113 	lw	t0, TIMER_TIMER1_CTRL(s2)
114 
115 	li	t0, START_TIMER
116 	sw	t0, TIMER_TIMER1_CTRL(s2)
117 	lw	t0, TIMER_TIMER1_CTRL(s2)
118 
119 	/* Prepare delay */
120 	li	t0, TIMER_MASK
121 	lw	t1, TIMER_TIMER1_STAT(s2)
122 	and	t1, t0
123 	/* 1ms delay */
124 	addi	t1, 27000
125 
126 	/* Wait for the timer value to exceed t1 */
127 1:	lw	t0, TIMER_TIMER1_STAT(s2)
128 	sgtu	t2, t1, t0
129 	bnez	t2, 1b
130 	nop
131 
132 	/* Power back up */
133 	li	t1, 1
134 	sw	t1, AON_CTRL_HOST_MISC_CMDS(s0)
135 	lw	t1, AON_CTRL_HOST_MISC_CMDS(s0)
136 
137 	sw	zero, AON_CTRL_PM_CTRL(s0)
138 	lw	zero, AON_CTRL_PM_CTRL(s0)
139 
140 	/* Unlock I-cache */
141 	addiu	t1, s3, -1
142 	not	t1
143 
144 	la	t0, brcm_pm_do_s2
145 	and 	t0, t1
146 
147 	la	t2, asm_end
148 	and	t2, t1
149 
150 1:	cache	0x00, 0(t0)
151 	bne	t0, t2, 1b
152 	addu	t0, s3
153 
154 	/* Unlock interrupt vector */
155 	move	t0, zero
156 
157 2:	move	t1, s4
158 	cache 	0x00, 0(t1)
159 	addu	t1, s3
160 	addu	t0, s3
161 	ble	t0, s5, 2b
162 	nop
163 
164 	/* Restore cp0 sr */
165 	sync
166 	nop
167 	mtc0	s6, CP0_STATUS
168 	nop
169 
170 	/* Set return value to success */
171 	li	v0, 0
172 
173 	/* Return to caller */
174 	lw	s7, 32(sp)
175 	lw	s6, 28(sp)
176 	lw	s5, 24(sp)
177 	lw	s4, 20(sp)
178 	lw	s3, 16(sp)
179 	lw	s2, 12(sp)
180 	lw	s1, 8(sp)
181 	lw	s0, 4(sp)
182 	lw	ra, 0(sp)
183 	addiu	sp, 64
184 
185 	jr ra
186 	nop
187 END(brcm_pm_do_s2)
188 
189 	.globl asm_end
190 asm_end:
191 	nop
192 
193