~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-imx/suspend-imx6.S

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php