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