Merge tag 'x86-cpu-2021-08-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
[linux-2.6-microblaze.git] / arch / arm / mach-imx / suspend-imx6.S
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)