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(imx5_cpu_suspend_info) |
32 | * ======================== low address ======================= |
33 | */ |
34 | |
35 | /* Offsets of members of struct imx5_cpu_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 |
135 | |