Linux 5.7.7
[linux/fpc-iii.git] / arch / arm / mach-imx / suspend-imx6.S
blob1eabf2d2834be79c6a6a695262ca4f1af2edcfc2
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright 2014 Freescale Semiconductor, Inc.
4  */
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"
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  */
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
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
69         .align 3
71         .macro  sync_l2_cache
73         /* sync L2 cache to drain L2's buffers to DRAM. */
74 #ifdef CONFIG_CACHE_L2X0
75         ldr     r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
76         teq     r11, #0
77         beq     6f
78         mov     r6, #0x0
79         str     r6, [r11, #L2X0_CACHE_SYNC]
81         ldr     r6, [r11, #L2X0_CACHE_SYNC]
82         ands    r6, r6, #0x1
83         bne     1b
85 #endif
87         .endm
89         .macro  resume_mmdc
91         /* restore MMDC IO */
92         cmp     r5, #0x0
93         ldreq   r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
94         ldrne   r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
96         ldr     r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
97         ldr     r7, =PM_INFO_MMDC_IO_VAL_OFFSET
98         add     r7, r7, r0
100         ldr     r8, [r7], #0x4
101         ldr     r9, [r7], #0x4
102         str     r9, [r11, r8]
103         subs    r6, r6, #0x1
104         bne     1b
106         cmp     r5, #0x0
107         ldreq   r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
108         ldrne   r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
110         cmp     r3, #IMX_DDR_TYPE_LPDDR2
111         bne     4f
113         /* reset read FIFO, RST_RD_FIFO */
114         ldr     r7, =MX6Q_MMDC_MPDGCTRL0
115         ldr     r6, [r11, r7]
116         orr     r6, r6, #(1 << 31)
117         str     r6, [r11, r7]
119         ldr     r6, [r11, r7]
120         ands    r6, r6, #(1 << 31)
121         bne     2b
123         /* reset FIFO a second time */
124         ldr     r6, [r11, r7]
125         orr     r6, r6, #(1 << 31)
126         str     r6, [r11, r7]
128         ldr     r6, [r11, r7]
129         ands    r6, r6, #(1 << 31)
130         bne     3b
132         /* let DDR out of self-refresh */
133         ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
134         bic     r7, r7, #(1 << 21)
135         str     r7, [r11, #MX6Q_MMDC_MAPSR]
137         ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
138         ands    r7, r7, #(1 << 25)
139         bne     5b
141         /* enable DDR auto power saving */
142         ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
143         bic     r7, r7, #0x1
144         str     r7, [r11, #MX6Q_MMDC_MAPSR]
146         .endm
148 ENTRY(imx6_suspend)
149         ldr     r1, [r0, #PM_INFO_PBASE_OFFSET]
150         ldr     r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
151         ldr     r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
152         ldr     r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
154         /*
155          * counting the resume address in iram
156          * to set it in SRC register.
157          */
158         ldr     r6, =imx6_suspend
159         ldr     r7, =resume
160         sub     r7, r7, r6
161         add     r8, r1, r4
162         add     r9, r8, r7
164         /*
165          * make sure TLB contain the addr we want,
166          * as we will access them after MMDC IO floated.
167          */
169         ldr     r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
170         ldr     r6, [r11, #0x0]
171         ldr     r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
172         ldr     r6, [r11, #0x0]
173         ldr     r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
174         ldr     r6, [r11, #0x0]
176         /* use r11 to store the IO address */
177         ldr     r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
178         /* store physical resume addr and pm_info address. */
179         str     r9, [r11, #MX6Q_SRC_GPR1]
180         str     r1, [r11, #MX6Q_SRC_GPR2]
182         /* need to sync L2 cache before DSM. */
183         sync_l2_cache
185         ldr     r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
186         /*
187          * put DDR explicitly into self-refresh and
188          * disable automatic power savings.
189          */
190         ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
191         orr     r7, r7, #0x1
192         str     r7, [r11, #MX6Q_MMDC_MAPSR]
194         /* make the DDR explicitly enter self-refresh. */
195         ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
196         orr     r7, r7, #(1 << 21)
197         str     r7, [r11, #MX6Q_MMDC_MAPSR]
199 poll_dvfs_set:
200         ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
201         ands    r7, r7, #(1 << 25)
202         beq     poll_dvfs_set
204         ldr     r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
205         ldr     r6, =0x0
206         ldr     r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
207         ldr     r8, =PM_INFO_MMDC_IO_VAL_OFFSET
208         add     r8, r8, r0
209         /* LPDDR2's last 3 IOs need special setting */
210         cmp     r3, #IMX_DDR_TYPE_LPDDR2
211         subeq   r7, r7, #0x3
212 set_mmdc_io_lpm:
213         ldr     r9, [r8], #0x8
214         str     r6, [r11, r9]
215         subs    r7, r7, #0x1
216         bne     set_mmdc_io_lpm
218         cmp     r3, #IMX_DDR_TYPE_LPDDR2
219         bne     set_mmdc_io_lpm_done
220         ldr     r6, =0x1000
221         ldr     r9, [r8], #0x8
222         str     r6, [r11, r9]
223         ldr     r9, [r8], #0x8
224         str     r6, [r11, r9]
225         ldr     r6, =0x80000
226         ldr     r9, [r8]
227         str     r6, [r11, r9]
228 set_mmdc_io_lpm_done:
230         /*
231          * mask all GPC interrupts before
232          * enabling the RBC counters to
233          * avoid the counter starting too
234          * early if an interupt is already
235          * pending.
236          */
237         ldr     r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
238         ldr     r6, [r11, #MX6Q_GPC_IMR1]
239         ldr     r7, [r11, #MX6Q_GPC_IMR2]
240         ldr     r8, [r11, #MX6Q_GPC_IMR3]
241         ldr     r9, [r11, #MX6Q_GPC_IMR4]
243         ldr     r10, =0xffffffff
244         str     r10, [r11, #MX6Q_GPC_IMR1]
245         str     r10, [r11, #MX6Q_GPC_IMR2]
246         str     r10, [r11, #MX6Q_GPC_IMR3]
247         str     r10, [r11, #MX6Q_GPC_IMR4]
249         /*
250          * enable the RBC bypass counter here
251          * to hold off the interrupts. RBC counter
252          * = 32 (1ms), Minimum RBC delay should be
253          * 400us for the analog LDOs to power down.
254          */
255         ldr     r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
256         ldr     r10, [r11, #MX6Q_CCM_CCR]
257         bic     r10, r10, #(0x3f << 21)
258         orr     r10, r10, #(0x20 << 21)
259         str     r10, [r11, #MX6Q_CCM_CCR]
261         /* enable the counter. */
262         ldr     r10, [r11, #MX6Q_CCM_CCR]
263         orr     r10, r10, #(0x1 << 27)
264         str     r10, [r11, #MX6Q_CCM_CCR]
266         /* unmask all the GPC interrupts. */
267         ldr     r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
268         str     r6, [r11, #MX6Q_GPC_IMR1]
269         str     r7, [r11, #MX6Q_GPC_IMR2]
270         str     r8, [r11, #MX6Q_GPC_IMR3]
271         str     r9, [r11, #MX6Q_GPC_IMR4]
273         /*
274          * now delay for a short while (3usec)
275          * ARM is at 1GHz at this point
276          * so a short loop should be enough.
277          * this delay is required to ensure that
278          * the RBC counter can start counting in
279          * case an interrupt is already pending
280          * or in case an interrupt arrives just
281          * as ARM is about to assert DSM_request.
282          */
283         ldr     r6, =2000
284 rbc_loop:
285         subs    r6, r6, #0x1
286         bne     rbc_loop
288         /* Zzz, enter stop mode */
289         wfi
290         nop
291         nop
292         nop
293         nop
295         /*
296          * run to here means there is pending
297          * wakeup source, system should auto
298          * resume, we need to restore MMDC IO first
299          */
300         mov     r5, #0x0
301         resume_mmdc
303         /* return to suspend finish */
304         ret     lr
306 resume:
307         /* invalidate L1 I-cache first */
308         mov     r6, #0x0
309         mcr     p15, 0, r6, c7, c5, 0
310         mcr     p15, 0, r6, c7, c5, 6
311         /* enable the Icache and branch prediction */
312         mov     r6, #0x1800
313         mcr     p15, 0, r6, c1, c0, 0
314         isb
316         /* get physical resume address from pm_info. */
317         ldr     lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
318         /* clear core0's entry and parameter */
319         ldr     r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]
320         mov     r7, #0x0
321         str     r7, [r11, #MX6Q_SRC_GPR1]
322         str     r7, [r11, #MX6Q_SRC_GPR2]
324         ldr     r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
325         mov     r5, #0x1
326         resume_mmdc
328         ret     lr
329 ENDPROC(imx6_suspend)