1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright 2014 Freescale Semiconductor, Inc.
4  */
5 
6 #include <linux/linkage.h>
7 #include <asm/assembler.h>
8 #include <asm/asm-offsets.h>
9 #include <asm/hardware/cache-l2x0.h>
10 #include "hardware.h"
11 
12 /*
13  * ==================== low level suspend ====================
14  *
15  * Better to follow below rules to use ARM registers:
16  * r0: pm_info structure address;
17  * r1 ~ r4: for saving pm_info members;
18  * r5 ~ r10: free registers;
19  * r11: io base address.
20  *
21  * suspend ocram space layout:
22  * ======================== high address ======================
23  *                              .
24  *                              .
25  *                              .
26  *                              ^
27  *                              ^
28  *                              ^
29  *                      imx6_suspend code
30  *              PM_INFO structure(imx6_cpu_pm_info)
31  * ======================== low address =======================
32  */
33 
34 /*
35  * Below offsets are based on struct imx6_cpu_pm_info
36  * which defined in arch/arm/mach-imx/pm-imx6q.c, this
37  * structure contains necessary pm info for low level
38  * suspend related code.
39  */
40 #define PM_INFO_PBASE_OFFSET			0x0
41 #define PM_INFO_RESUME_ADDR_OFFSET		0x4
42 #define PM_INFO_DDR_TYPE_OFFSET			0x8
43 #define PM_INFO_PM_INFO_SIZE_OFFSET		0xC
44 #define PM_INFO_MX6Q_MMDC_P_OFFSET		0x10
45 #define PM_INFO_MX6Q_MMDC_V_OFFSET		0x14
46 #define PM_INFO_MX6Q_SRC_P_OFFSET		0x18
47 #define PM_INFO_MX6Q_SRC_V_OFFSET		0x1C
48 #define PM_INFO_MX6Q_IOMUXC_P_OFFSET		0x20
49 #define PM_INFO_MX6Q_IOMUXC_V_OFFSET		0x24
50 #define PM_INFO_MX6Q_CCM_P_OFFSET		0x28
51 #define PM_INFO_MX6Q_CCM_V_OFFSET		0x2C
52 #define PM_INFO_MX6Q_GPC_P_OFFSET		0x30
53 #define PM_INFO_MX6Q_GPC_V_OFFSET		0x34
54 #define PM_INFO_MX6Q_L2_P_OFFSET		0x38
55 #define PM_INFO_MX6Q_L2_V_OFFSET		0x3C
56 #define PM_INFO_MMDC_IO_NUM_OFFSET		0x40
57 #define PM_INFO_MMDC_IO_VAL_OFFSET		0x44
58 
59 #define MX6Q_SRC_GPR1	0x20
60 #define MX6Q_SRC_GPR2	0x24
61 #define MX6Q_MMDC_MAPSR	0x404
62 #define MX6Q_MMDC_MPDGCTRL0	0x83c
63 #define MX6Q_GPC_IMR1	0x08
64 #define MX6Q_GPC_IMR2	0x0c
65 #define MX6Q_GPC_IMR3	0x10
66 #define MX6Q_GPC_IMR4	0x14
67 #define MX6Q_CCM_CCR	0x0
68 
69 	.align 3
70 	.arm
71 
72 	.macro  sync_l2_cache
73 
74 	/* sync L2 cache to drain L2's buffers to DRAM. */
75 #ifdef CONFIG_CACHE_L2X0
76 	ldr	r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
77 	teq	r11, #0
78 	beq	6f
79 	mov	r6, #0x0
80 	str	r6, [r11, #L2X0_CACHE_SYNC]
81 1:
82 	ldr	r6, [r11, #L2X0_CACHE_SYNC]
83 	ands	r6, r6, #0x1
84 	bne	1b
85 6:
86 #endif
87 
88 	.endm
89 
90 	.macro	resume_mmdc
91 
92 	/* restore MMDC IO */
93 	cmp	r5, #0x0
94 	ldreq	r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
95 	ldrne	r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
96 
97 	ldr	r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
98 	ldr	r7, =PM_INFO_MMDC_IO_VAL_OFFSET
99 	add	r7, r7, r0
100 1:
101 	ldr	r8, [r7], #0x4
102 	ldr	r9, [r7], #0x4
103 	str	r9, [r11, r8]
104 	subs	r6, r6, #0x1
105 	bne	1b
106 
107 	cmp	r5, #0x0
108 	ldreq	r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
109 	ldrne	r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
110 
111 	cmp	r3, #IMX_DDR_TYPE_LPDDR2
112 	bne	4f
113 
114 	/* reset read FIFO, RST_RD_FIFO */
115 	ldr	r7, =MX6Q_MMDC_MPDGCTRL0
116 	ldr	r6, [r11, r7]
117 	orr     r6, r6, #(1 << 31)
118 	str	r6, [r11, r7]
119 2:
120 	ldr	r6, [r11, r7]
121 	ands	r6, r6, #(1 << 31)
122 	bne	2b
123 
124 	/* reset FIFO a second time */
125 	ldr	r6, [r11, r7]
126 	orr     r6, r6, #(1 << 31)
127 	str	r6, [r11, r7]
128 3:
129 	ldr	r6, [r11, r7]
130 	ands	r6, r6, #(1 << 31)
131 	bne	3b
132 4:
133 	/* let DDR out of self-refresh */
134 	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
135 	bic	r7, r7, #(1 << 21)
136 	str	r7, [r11, #MX6Q_MMDC_MAPSR]
137 5:
138 	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
139 	ands	r7, r7, #(1 << 25)
140 	bne	5b
141 
142 	/* enable DDR auto power saving */
143 	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
144 	bic	r7, r7, #0x1
145 	str	r7, [r11, #MX6Q_MMDC_MAPSR]
146 
147 	.endm
148 
149 ENTRY(imx6_suspend)
150 	ldr	r1, [r0, #PM_INFO_PBASE_OFFSET]
151 	ldr	r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
152 	ldr	r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
153 	ldr	r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
154 
155 	/*
156 	 * counting the resume address in iram
157 	 * to set it in SRC register.
158 	 */
159 	ldr	r6, =imx6_suspend
160 	ldr	r7, =resume
161 	sub	r7, r7, r6
162 	add	r8, r1, r4
163 	add	r9, r8, r7
164 
165 	/*
166 	 * make sure TLB contain the addr we want,
167 	 * as we will access them after MMDC IO floated.
168 	 */
169 
170 	ldr	r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
171 	ldr	r6, [r11, #0x0]
172 	ldr	r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
173 	ldr	r6, [r11, #0x0]
174 	ldr	r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
175 	ldr	r6, [r11, #0x0]
176 
177 	/* use r11 to store the IO address */
178 	ldr	r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
179 	/* store physical resume addr and pm_info address. */
180 	str	r9, [r11, #MX6Q_SRC_GPR1]
181 	str	r1, [r11, #MX6Q_SRC_GPR2]
182 
183 	/* need to sync L2 cache before DSM. */
184 	sync_l2_cache
185 
186 	ldr	r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
187 	/*
188 	 * put DDR explicitly into self-refresh and
189 	 * disable automatic power savings.
190 	 */
191 	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
192 	orr	r7, r7, #0x1
193 	str	r7, [r11, #MX6Q_MMDC_MAPSR]
194 
195 	/* make the DDR explicitly enter self-refresh. */
196 	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
197 	orr	r7, r7, #(1 << 21)
198 	str	r7, [r11, #MX6Q_MMDC_MAPSR]
199 
200 poll_dvfs_set:
201 	ldr	r7, [r11, #MX6Q_MMDC_MAPSR]
202 	ands	r7, r7, #(1 << 25)
203 	beq	poll_dvfs_set
204 
205 	ldr	r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
206 	ldr	r6, =0x0
207 	ldr	r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
208 	ldr	r8, =PM_INFO_MMDC_IO_VAL_OFFSET
209 	add	r8, r8, r0
210 	/* LPDDR2's last 3 IOs need special setting */
211 	cmp	r3, #IMX_DDR_TYPE_LPDDR2
212 	subeq	r7, r7, #0x3
213 set_mmdc_io_lpm:
214 	ldr	r9, [r8], #0x8
215 	str	r6, [r11, r9]
216 	subs	r7, r7, #0x1
217 	bne	set_mmdc_io_lpm
218 
219 	cmp 	r3, #IMX_DDR_TYPE_LPDDR2
220 	bne	set_mmdc_io_lpm_done
221 	ldr	r6, =0x1000
222 	ldr	r9, [r8], #0x8
223 	str	r6, [r11, r9]
224 	ldr	r9, [r8], #0x8
225 	str	r6, [r11, r9]
226 	ldr	r6, =0x80000
227 	ldr	r9, [r8]
228 	str	r6, [r11, r9]
229 set_mmdc_io_lpm_done:
230 
231 	/*
232 	 * mask all GPC interrupts before
233 	 * enabling the RBC counters to
234 	 * avoid the counter starting too
235 	 * early if an interupt is already
236 	 * pending.
237 	 */
238 	ldr	r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
239 	ldr	r6, [r11, #MX6Q_GPC_IMR1]
240 	ldr	r7, [r11, #MX6Q_GPC_IMR2]
241 	ldr	r8, [r11, #MX6Q_GPC_IMR3]
242 	ldr	r9, [r11, #MX6Q_GPC_IMR4]
243 
244 	ldr	r10, =0xffffffff
245 	str	r10, [r11, #MX6Q_GPC_IMR1]
246 	str	r10, [r11, #MX6Q_GPC_IMR2]
247 	str	r10, [r11, #MX6Q_GPC_IMR3]
248 	str	r10, [r11, #MX6Q_GPC_IMR4]
249 
250 	/*
251 	 * enable the RBC bypass counter here
252 	 * to hold off the interrupts. RBC counter
253 	 * = 32 (1ms), Minimum RBC delay should be
254 	 * 400us for the analog LDOs to power down.
255 	 */
256 	ldr	r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
257 	ldr	r10, [r11, #MX6Q_CCM_CCR]
258 	bic	r10, r10, #(0x3f << 21)
259 	orr	r10, r10, #(0x20 << 21)
260 	str	r10, [r11, #MX6Q_CCM_CCR]
261 
262 	/* enable the counter. */
263 	ldr	r10, [r11, #MX6Q_CCM_CCR]
264 	orr	r10, r10, #(0x1 << 27)
265 	str	r10, [r11, #MX6Q_CCM_CCR]
266 
267 	/* unmask all the GPC interrupts. */
268 	ldr	r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
269 	str	r6, [r11, #MX6Q_GPC_IMR1]
270 	str	r7, [r11, #MX6Q_GPC_IMR2]
271 	str	r8, [r11, #MX6Q_GPC_IMR3]
272 	str	r9, [r11, #MX6Q_GPC_IMR4]
273 
274 	/*
275 	 * now delay for a short while (3usec)
276 	 * ARM is at 1GHz at this point
277 	 * so a short loop should be enough.
278 	 * this delay is required to ensure that
279 	 * the RBC counter can start counting in
280 	 * case an interrupt is already pending
281 	 * or in case an interrupt arrives just
282 	 * as ARM is about to assert DSM_request.
283 	 */
284 	ldr	r6, =2000
285 rbc_loop:
286 	subs	r6, r6, #0x1
287 	bne	rbc_loop
288 
289 	/* Zzz, enter stop mode */
290 	wfi
291 	nop
292 	nop
293 	nop
294 	nop
295 
296 	/*
297 	 * run to here means there is pending
298 	 * wakeup source, system should auto
299 	 * resume, we need to restore MMDC IO first
300 	 */
301 	mov	r5, #0x0
302 	resume_mmdc
303 
304 	/* return to suspend finish */
305 	ret	lr
306 
307 resume:
308 	/* invalidate L1 I-cache first */
309 	mov     r6, #0x0
310 	mcr     p15, 0, r6, c7, c5, 0
311 	mcr     p15, 0, r6, c7, c5, 6
312 	/* enable the Icache and branch prediction */
313 	mov     r6, #0x1800
314 	mcr     p15, 0, r6, c1, c0, 0
315 	isb
316 
317 	/* get physical resume address from pm_info. */
318 	ldr	lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
319 	/* clear core0's entry and parameter */
320 	ldr	r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]
321 	mov	r7, #0x0
322 	str	r7, [r11, #MX6Q_SRC_GPR1]
323 	str	r7, [r11, #MX6Q_SRC_GPR2]
324 
325 	ldr	r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
326 	mov	r5, #0x1
327 	resume_mmdc
328 
329 	ret	lr
330 ENDPROC(imx6_suspend)
331