2 * Copyright 2014 Freescale Semiconductor, Inc.
4 * The code contained herein is licensed under the GNU General Public
5 * License. You may obtain a copy of the GNU General Public License
6 * Version 2 or later at the following locations:
8 * http://www.opensource.org/licenses/gpl-license.html
9 * http://www.gnu.org/copyleft/gpl.html
12 #include <linux/linkage.h>
13 #include <asm/assembler.h>
14 #include <asm/asm-offsets.h>
15 #include <asm/hardware/cache-l2x0.h>
19 * ==================== low level suspend ====================
21 * Better to follow below rules to use ARM registers:
22 * r0: pm_info structure address;
23 * r1 ~ r4: for saving pm_info members;
24 * r5 ~ r10: free registers;
25 * r11: io base address.
27 * suspend ocram space layout:
28 * ======================== high address ======================
36 * PM_INFO structure(imx6_cpu_pm_info)
37 * ======================== low address =======================
41 * Below offsets are based on struct imx6_cpu_pm_info
42 * which defined in arch/arm/mach-imx/pm-imx6q.c, this
43 * structure contains necessary pm info for low level
44 * suspend related code.
46 #define PM_INFO_PBASE_OFFSET 0x0
47 #define PM_INFO_RESUME_ADDR_OFFSET 0x4
48 #define PM_INFO_DDR_TYPE_OFFSET 0x8
49 #define PM_INFO_PM_INFO_SIZE_OFFSET 0xC
50 #define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10
51 #define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14
52 #define PM_INFO_MX6Q_SRC_P_OFFSET 0x18
53 #define PM_INFO_MX6Q_SRC_V_OFFSET 0x1C
54 #define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x20
55 #define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x24
56 #define PM_INFO_MX6Q_CCM_P_OFFSET 0x28
57 #define PM_INFO_MX6Q_CCM_V_OFFSET 0x2C
58 #define PM_INFO_MX6Q_GPC_P_OFFSET 0x30
59 #define PM_INFO_MX6Q_GPC_V_OFFSET 0x34
60 #define PM_INFO_MX6Q_L2_P_OFFSET 0x38
61 #define PM_INFO_MX6Q_L2_V_OFFSET 0x3C
62 #define PM_INFO_MMDC_IO_NUM_OFFSET 0x40
63 #define PM_INFO_MMDC_IO_VAL_OFFSET 0x44
65 #define MX6Q_SRC_GPR1 0x20
66 #define MX6Q_SRC_GPR2 0x24
67 #define MX6Q_MMDC_MAPSR 0x404
68 #define MX6Q_MMDC_MPDGCTRL0 0x83c
69 #define MX6Q_GPC_IMR1 0x08
70 #define MX6Q_GPC_IMR2 0x0c
71 #define MX6Q_GPC_IMR3 0x10
72 #define MX6Q_GPC_IMR4 0x14
73 #define MX6Q_CCM_CCR 0x0
80 /* sync L2 cache to drain L2's buffers to DRAM. */
81 #ifdef CONFIG_CACHE_L2X0
82 ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
86 str r6, [r11, #L2X0_CACHE_SYNC]
88 ldr r6, [r11, #L2X0_CACHE_SYNC]
100 ldreq r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
101 ldrne r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
103 ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
104 ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET
114 ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
115 ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
117 cmp r3, #IMX_DDR_TYPE_LPDDR2
120 /* reset read FIFO, RST_RD_FIFO */
121 ldr r7, =MX6Q_MMDC_MPDGCTRL0
123 orr r6, r6, #(1 << 31)
127 ands r6, r6, #(1 << 31)
130 /* reset FIFO a second time */
132 orr r6, r6, #(1 << 31)
136 ands r6, r6, #(1 << 31)
139 /* let DDR out of self-refresh */
140 ldr r7, [r11, #MX6Q_MMDC_MAPSR]
141 bic r7, r7, #(1 << 21)
142 str r7, [r11, #MX6Q_MMDC_MAPSR]
144 ldr r7, [r11, #MX6Q_MMDC_MAPSR]
145 ands r7, r7, #(1 << 25)
148 /* enable DDR auto power saving */
149 ldr r7, [r11, #MX6Q_MMDC_MAPSR]
151 str r7, [r11, #MX6Q_MMDC_MAPSR]
156 ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
157 ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
158 ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
159 ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
162 * counting the resume address in iram
163 * to set it in SRC register.
165 ldr r6, =imx6_suspend
172 * make sure TLB contain the addr we want,
173 * as we will access them after MMDC IO floated.
176 ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
178 ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
180 ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
183 /* use r11 to store the IO address */
184 ldr r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
185 /* store physical resume addr and pm_info address. */
186 str r9, [r11, #MX6Q_SRC_GPR1]
187 str r1, [r11, #MX6Q_SRC_GPR2]
189 /* need to sync L2 cache before DSM. */
192 ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
194 * put DDR explicitly into self-refresh and
195 * disable automatic power savings.
197 ldr r7, [r11, #MX6Q_MMDC_MAPSR]
199 str r7, [r11, #MX6Q_MMDC_MAPSR]
201 /* make the DDR explicitly enter self-refresh. */
202 ldr r7, [r11, #MX6Q_MMDC_MAPSR]
203 orr r7, r7, #(1 << 21)
204 str r7, [r11, #MX6Q_MMDC_MAPSR]
207 ldr r7, [r11, #MX6Q_MMDC_MAPSR]
208 ands r7, r7, #(1 << 25)
211 ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
213 ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
214 ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET
216 /* LPDDR2's last 3 IOs need special setting */
217 cmp r3, #IMX_DDR_TYPE_LPDDR2
225 cmp r3, #IMX_DDR_TYPE_LPDDR2
226 bne set_mmdc_io_lpm_done
235 set_mmdc_io_lpm_done:
238 * mask all GPC interrupts before
239 * enabling the RBC counters to
240 * avoid the counter starting too
241 * early if an interupt is already
244 ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
245 ldr r6, [r11, #MX6Q_GPC_IMR1]
246 ldr r7, [r11, #MX6Q_GPC_IMR2]
247 ldr r8, [r11, #MX6Q_GPC_IMR3]
248 ldr r9, [r11, #MX6Q_GPC_IMR4]
251 str r10, [r11, #MX6Q_GPC_IMR1]
252 str r10, [r11, #MX6Q_GPC_IMR2]
253 str r10, [r11, #MX6Q_GPC_IMR3]
254 str r10, [r11, #MX6Q_GPC_IMR4]
257 * enable the RBC bypass counter here
258 * to hold off the interrupts. RBC counter
259 * = 32 (1ms), Minimum RBC delay should be
260 * 400us for the analog LDOs to power down.
262 ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
263 ldr r10, [r11, #MX6Q_CCM_CCR]
264 bic r10, r10, #(0x3f << 21)
265 orr r10, r10, #(0x20 << 21)
266 str r10, [r11, #MX6Q_CCM_CCR]
268 /* enable the counter. */
269 ldr r10, [r11, #MX6Q_CCM_CCR]
270 orr r10, r10, #(0x1 << 27)
271 str r10, [r11, #MX6Q_CCM_CCR]
273 /* unmask all the GPC interrupts. */
274 ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
275 str r6, [r11, #MX6Q_GPC_IMR1]
276 str r7, [r11, #MX6Q_GPC_IMR2]
277 str r8, [r11, #MX6Q_GPC_IMR3]
278 str r9, [r11, #MX6Q_GPC_IMR4]
281 * now delay for a short while (3usec)
282 * ARM is at 1GHz at this point
283 * so a short loop should be enough.
284 * this delay is required to ensure that
285 * the RBC counter can start counting in
286 * case an interrupt is already pending
287 * or in case an interrupt arrives just
288 * as ARM is about to assert DSM_request.
295 /* Zzz, enter stop mode */
303 * run to here means there is pending
304 * wakeup source, system should auto
305 * resume, we need to restore MMDC IO first
310 /* return to suspend finish */
314 /* invalidate L1 I-cache first */
316 mcr p15, 0, r6, c7, c5, 0
317 mcr p15, 0, r6, c7, c5, 6
318 /* enable the Icache and branch prediction */
320 mcr p15, 0, r6, c1, c0, 0
323 /* get physical resume address from pm_info. */
324 ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
325 /* clear core0's entry and parameter */
326 ldr r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]
328 str r7, [r11, #MX6Q_SRC_GPR1]
329 str r7, [r11, #MX6Q_SRC_GPR2]
331 ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
336 ENDPROC(imx6_suspend)