1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
4 */
5 /*
6 */
7
8 #include <linux/linkage.h>
9
10 #define M4IF_MCR0_OFFSET (0x008C)
11 #define M4IF_MCR0_FDVFS (0x1 << 11)
12 #define M4IF_MCR0_FDVACK (0x1 << 27)
13
14 .align 3
15
16 /*
17 * ==================== low level suspend ====================
18 *
19 * On entry
20 * r0: pm_info structure address;
21 *
22 * suspend ocram space layout:
23 * ======================== high address ======================
24 * .
25 * .
26 * .
27 * ^
28 * ^
29 * ^
30 * imx53_suspend code
31 * PM_INFO structure(imx53_suspend_info)
32 * ======================== low address =======================
33 */
34
35 /* Offsets of members of struct imx53_suspend_info */
36 #define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0
37 #define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4
38 #define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8
39 #define SUSPEND_INFO_MX53_IO_STATE_OFFSET 0xc
40
41 ENTRY(imx53_suspend)
42 stmfd sp!, {r4,r5,r6,r7}
43
44 /* Save pad config */
45 ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
46 cmp r1, #0
47 beq skip_pad_conf_1
48
49 add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
50 ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
51
52 1:
53 ldr r5, [r2], #12 /* IOMUXC register offset */
54 ldr r6, [r3, r5] /* current value */
55 str r6, [r2], #4 /* save area */
56 subs r1, r1, #1
57 bne 1b
58
59 skip_pad_conf_1:
60 /* Set FDVFS bit of M4IF_MCR0 to request DDR to enter self-refresh */
61 ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
62 ldr r2,[r1, #M4IF_MCR0_OFFSET]
63 orr r2, r2, #M4IF_MCR0_FDVFS
64 str r2,[r1, #M4IF_MCR0_OFFSET]
65
66 /* Poll FDVACK bit of M4IF_MCR to wait for DDR to enter self-refresh */
67 wait_sr_ack:
68 ldr r2,[r1, #M4IF_MCR0_OFFSET]
69 ands r2, r2, #M4IF_MCR0_FDVACK
70 beq wait_sr_ack
71
72 /* Set pad config */
73 ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
74 cmp r1, #0
75 beq skip_pad_conf_2
76
77 add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
78 ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
79
80 2:
81 ldr r5, [r2], #4 /* IOMUXC register offset */
82 ldr r6, [r2], #4 /* clear */
83 ldr r7, [r3, r5]
84 bic r7, r7, r6
85 ldr r6, [r2], #8 /* set */
86 orr r7, r7, r6
87 str r7, [r3, r5]
88 subs r1, r1, #1
89 bne 2b
90
91 skip_pad_conf_2:
92 /* Zzz, enter stop mode */
93 wfi
94 nop
95 nop
96 nop
97 nop
98
99 /* Restore pad config */
100 ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
101 cmp r1, #0
102 beq skip_pad_conf_3
103
104 add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
105 ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]
106
107 3:
108 ldr r5, [r2], #12 /* IOMUXC register offset */
109 ldr r6, [r2], #4 /* saved value */
110 str r6, [r3, r5]
111 subs r1, r1, #1
112 bne 3b
113
114 skip_pad_conf_3:
115 /* Clear FDVFS bit of M4IF_MCR0 to request DDR to exit self-refresh */
116 ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
117 ldr r2,[r1, #M4IF_MCR0_OFFSET]
118 bic r2, r2, #M4IF_MCR0_FDVFS
119 str r2,[r1, #M4IF_MCR0_OFFSET]
120
121 /* Poll FDVACK bit of M4IF_MCR to wait for DDR to exit self-refresh */
122 wait_ar_ack:
123 ldr r2,[r1, #M4IF_MCR0_OFFSET]
124 ands r2, r2, #M4IF_MCR0_FDVACK
125 bne wait_ar_ack
126
127 /* Restore registers */
128 ldmfd sp!, {r4,r5,r6,r7}
129 mov pc, lr
130
131 ENDPROC(imx53_suspend)
132
133 ENTRY(imx53_suspend_sz)
134 .word . - imx53_suspend