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
41ENTRY(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
521:
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
59skip_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 */
67wait_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
802:
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
91skip_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
1073:
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
114skip_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 */
122wait_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
131ENDPROC(imx53_suspend)
132
133ENTRY(imx53_suspend_sz)
134 .word . - imx53_suspend
135

source code of linux/arch/arm/mach-imx/suspend-imx53.S