summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/suspend-imx53.S
blob: 5ed078ad110aa3bdcf054204d0ebd739061c6601 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
 */
/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

#include <linux/linkage.h>

#define M4IF_MCR0_OFFSET			(0x008C)
#define M4IF_MCR0_FDVFS				(0x1 << 11)
#define M4IF_MCR0_FDVACK			(0x1 << 27)

	.align 3

/*
 * ==================== low level suspend ====================
 *
 * On entry
 * r0: pm_info structure address;
 *
 * suspend ocram space layout:
 * ======================== high address ======================
 *                              .
 *                              .
 *                              .
 *                              ^
 *                              ^
 *                              ^
 *                      imx53_suspend code
 *              PM_INFO structure(imx53_suspend_info)
 * ======================== low address =======================
 */

/* Offsets of members of struct imx53_suspend_info */
#define SUSPEND_INFO_MX53_M4IF_V_OFFSET		0x0
#define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET	0x4
#define SUSPEND_INFO_MX53_IO_COUNT_OFFSET	0x8
#define SUSPEND_INFO_MX53_IO_STATE_OFFSET	0xc

ENTRY(imx53_suspend)
	stmfd	sp!, {r4,r5,r6,r7}

	/* Save pad config */
	ldr	r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
	cmp	r1, #0
	beq	skip_pad_conf_1

	add	r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
	ldr	r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]

1:
	ldr	r5, [r2], #12	/* IOMUXC register offset */
	ldr	r6, [r3, r5]	/* current value */
	str	r6, [r2], #4	/* save area */
	subs	r1, r1, #1
	bne	1b

skip_pad_conf_1:
	/* Set FDVFS bit of M4IF_MCR0 to request DDR to enter self-refresh */
	ldr	r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
	ldr	r2,[r1, #M4IF_MCR0_OFFSET]
	orr	r2, r2, #M4IF_MCR0_FDVFS
	str	r2,[r1, #M4IF_MCR0_OFFSET]

	/* Poll FDVACK bit of M4IF_MCR to wait for DDR to enter self-refresh */
wait_sr_ack:
	ldr	r2,[r1, #M4IF_MCR0_OFFSET]
	ands	r2, r2, #M4IF_MCR0_FDVACK
	beq	wait_sr_ack

	/* Set pad config */
	ldr	r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
	cmp	r1, #0
	beq	skip_pad_conf_2

	add	r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
	ldr	r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]

2:
	ldr	r5, [r2], #4	/* IOMUXC register offset */
	ldr	r6, [r2], #4	/* clear */
	ldr	r7, [r3, r5]
	bic	r7, r7, r6
	ldr	r6, [r2], #8	/* set */
	orr	r7, r7, r6
	str	r7, [r3, r5]
	subs	r1, r1, #1
	bne	2b

skip_pad_conf_2:
	/* Zzz, enter stop mode */
	wfi
	nop
	nop
	nop
	nop

	/* Restore pad config */
	ldr	r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET]
	cmp	r1, #0
	beq	skip_pad_conf_3

	add	r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET
	ldr	r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET]

3:
	ldr	r5, [r2], #12	/* IOMUXC register offset */
	ldr	r6, [r2], #4	/* saved value */
	str	r6, [r3, r5]
	subs	r1, r1, #1
	bne	3b

skip_pad_conf_3:
	/* Clear FDVFS bit of M4IF_MCR0 to request DDR to exit self-refresh */
	ldr	r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET]
	ldr	r2,[r1, #M4IF_MCR0_OFFSET]
	bic	r2, r2, #M4IF_MCR0_FDVFS
	str	r2,[r1, #M4IF_MCR0_OFFSET]

	/* Poll FDVACK bit of M4IF_MCR to wait for DDR to exit self-refresh */
wait_ar_ack:
	ldr	r2,[r1, #M4IF_MCR0_OFFSET]
	ands	r2, r2, #M4IF_MCR0_FDVACK
	bne	wait_ar_ack

	/* Restore registers */
	ldmfd	sp!, {r4,r5,r6,r7}
	mov	pc, lr

ENDPROC(imx53_suspend)

ENTRY(imx53_suspend_sz)
        .word   . - imx53_suspend
OpenPOWER on IntegriCloud