]>
Commit | Line | Data |
---|---|---|
5e1c5ff4 | 1 | /* |
670c104a | 2 | * linux/arch/arm/mach-omap1/sleep.S |
5e1c5ff4 | 3 | * |
1a8bfa1e | 4 | * Low-level OMAP730/1510/1610 sleep/wakeUp support |
5e1c5ff4 TL |
5 | * |
6 | * Initial SA1110 code: | |
7 | * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> | |
8 | * | |
9 | * Adapted for PXA by Nicolas Pitre: | |
10 | * Copyright (c) 2002 Monta Vista Software, Inc. | |
11 | * | |
12 | * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify it | |
15 | * under the terms of the GNU General Public License as published by the | |
16 | * Free Software Foundation; either version 2 of the License, or (at your | |
17 | * option) any later version. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
20 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
22 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
25 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
26 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License along | |
31 | * with this program; if not, write to the Free Software Foundation, Inc., | |
32 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
33 | */ | |
34 | ||
5e1c5ff4 TL |
35 | #include <linux/linkage.h> |
36 | #include <asm/assembler.h> | |
a09e64fb RK |
37 | #include <mach/io.h> |
38 | #include <mach/pm.h> | |
5e1c5ff4 TL |
39 | |
40 | .text | |
41 | ||
5e1c5ff4 TL |
42 | |
43 | /* | |
44 | * Forces OMAP into deep sleep state | |
45 | * | |
46 | * omapXXXX_cpu_suspend() | |
47 | * | |
48 | * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed | |
49 | * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1 | |
50 | * in register r1. | |
51 | * | |
52 | * Note: This code get's copied to internal SRAM at boot. When the OMAP | |
53 | * wakes up it continues execution at the point it went to sleep. | |
54 | * | |
55 | * Note: Because of errata work arounds we have processor specific functions | |
56 | * here. They are mostly the same, but slightly different. | |
57 | * | |
58 | */ | |
59 | ||
1a8bfa1e TL |
60 | #if defined(CONFIG_ARCH_OMAP730) |
61 | ENTRY(omap730_cpu_suspend) | |
62 | ||
63 | @ save registers on stack | |
64 | stmfd sp!, {r0 - r12, lr} | |
65 | ||
66 | @ Drain write cache | |
67 | mov r4, #0 | |
68 | mcr p15, 0, r0, c7, c10, 4 | |
69 | nop | |
70 | ||
71 | @ load base address of Traffic Controller | |
72 | mov r6, #TCMIF_ASM_BASE & 0xff000000 | |
73 | orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
74 | orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
75 | ||
76 | @ prepare to put SDRAM into self-refresh manually | |
77 | ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
78 | orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
79 | orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
80 | str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
81 | ||
82 | @ prepare to put EMIFS to Sleep | |
83 | ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
84 | orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
85 | str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
86 | ||
87 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
88 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
89 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
90 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
91 | ||
92 | @ turn off clock domains | |
93 | @ do not disable PERCK (0x04) | |
94 | mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | |
95 | orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | |
96 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
97 | ||
98 | @ request ARM idle | |
99 | mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff | |
100 | orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00 | |
101 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
102 | ||
103 | @ disable instruction cache | |
104 | mrc p15, 0, r9, c1, c0, 0 | |
105 | bic r2, r9, #0x1000 | |
106 | mcr p15, 0, r2, c1, c0, 0 | |
107 | nop | |
108 | ||
109 | /* | |
110 | * Let's wait for the next wake up event to wake us up. r0 can't be | |
111 | * used here because r0 holds ARM_IDLECT1 | |
112 | */ | |
113 | mov r2, #0 | |
114 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
115 | /* | |
116 | * omap730_cpu_suspend()'s resume point. | |
117 | * | |
118 | * It will just start executing here, so we'll restore stuff from the | |
119 | * stack. | |
120 | */ | |
121 | @ re-enable Icache | |
122 | mcr p15, 0, r9, c1, c0, 0 | |
123 | ||
124 | @ reset the ARM_IDLECT1 and ARM_IDLECT2. | |
125 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
126 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
127 | ||
128 | @ Restore EMIFF controls | |
129 | str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
130 | str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
131 | ||
132 | @ restore regs and return | |
133 | ldmfd sp!, {r0 - r12, pc} | |
134 | ||
135 | ENTRY(omap730_cpu_suspend_sz) | |
136 | .word . - omap730_cpu_suspend | |
137 | #endif /* CONFIG_ARCH_OMAP730 */ | |
138 | ||
139 | #ifdef CONFIG_ARCH_OMAP15XX | |
5e1c5ff4 TL |
140 | ENTRY(omap1510_cpu_suspend) |
141 | ||
142 | @ save registers on stack | |
143 | stmfd sp!, {r0 - r12, lr} | |
144 | ||
145 | @ load base address of Traffic Controller | |
146 | mov r4, #TCMIF_ASM_BASE & 0xff000000 | |
147 | orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 | |
148 | orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 | |
149 | ||
150 | @ work around errata of OMAP1510 PDE bit for TC shut down | |
151 | @ clear PDE bit | |
152 | ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
153 | bic r5, r5, #PDE_BIT & 0xff | |
154 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
155 | ||
156 | @ set PWD_EN bit | |
157 | and r5, r5, #PWD_EN_BIT & 0xff | |
158 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
159 | ||
160 | @ prepare to put SDRAM into self-refresh manually | |
161 | ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
162 | orr r5, r5, #SELF_REFRESH_MODE & 0xff000000 | |
163 | orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff | |
164 | str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
165 | ||
166 | @ prepare to put EMIFS to Sleep | |
167 | ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
168 | orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff | |
169 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
170 | ||
171 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
172 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
173 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
174 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
175 | ||
176 | @ turn off clock domains | |
177 | mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff | |
92105bb7 | 178 | orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 |
5e1c5ff4 TL |
179 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
180 | ||
181 | @ request ARM idle | |
182 | mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff | |
183 | orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00 | |
184 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
185 | ||
186 | mov r5, #IDLE_WAIT_CYCLES & 0xff | |
92105bb7 | 187 | orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 |
5e1c5ff4 TL |
188 | l_1510_2: |
189 | subs r5, r5, #1 | |
190 | bne l_1510_2 | |
191 | /* | |
192 | * Let's wait for the next wake up event to wake us up. r0 can't be | |
193 | * used here because r0 holds ARM_IDLECT1 | |
194 | */ | |
195 | mov r2, #0 | |
196 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
197 | /* | |
198 | * omap1510_cpu_suspend()'s resume point. | |
199 | * | |
200 | * It will just start executing here, so we'll restore stuff from the | |
201 | * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
202 | */ | |
203 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
204 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
205 | ||
206 | @ restore regs and return | |
92105bb7 | 207 | ldmfd sp!, {r0 - r12, pc} |
5e1c5ff4 TL |
208 | |
209 | ENTRY(omap1510_cpu_suspend_sz) | |
210 | .word . - omap1510_cpu_suspend | |
1a8bfa1e | 211 | #endif /* CONFIG_ARCH_OMAP15XX */ |
5e1c5ff4 TL |
212 | |
213 | #if defined(CONFIG_ARCH_OMAP16XX) | |
214 | ENTRY(omap1610_cpu_suspend) | |
215 | ||
216 | @ save registers on stack | |
217 | stmfd sp!, {r0 - r12, lr} | |
218 | ||
92105bb7 TL |
219 | @ Drain write cache |
220 | mov r4, #0 | |
221 | mcr p15, 0, r0, c7, c10, 4 | |
222 | nop | |
223 | ||
670c104a | 224 | @ Load base address of Traffic Controller |
92105bb7 TL |
225 | mov r6, #TCMIF_ASM_BASE & 0xff000000 |
226 | orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
227 | orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
5e1c5ff4 | 228 | |
670c104a | 229 | @ Prepare to put SDRAM into self-refresh manually |
92105bb7 TL |
230 | ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] |
231 | orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
232 | orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
233 | str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
5e1c5ff4 | 234 | |
670c104a | 235 | @ Prepare to put EMIFS to Sleep |
92105bb7 TL |
236 | ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] |
237 | orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
238 | str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
5e1c5ff4 | 239 | |
670c104a | 240 | @ Load base address of ARM_IDLECT1 and ARM_IDLECT2 |
5e1c5ff4 TL |
241 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 |
242 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
243 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
244 | ||
670c104a TL |
245 | @ Turn off clock domains |
246 | @ Do not disable PERCK (0x04) | |
92105bb7 TL |
247 | mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff |
248 | orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | |
5e1c5ff4 TL |
249 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
250 | ||
670c104a | 251 | @ Request ARM idle |
92105bb7 TL |
252 | mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff |
253 | orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 | |
5e1c5ff4 TL |
254 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
255 | ||
5e1c5ff4 TL |
256 | /* |
257 | * Let's wait for the next wake up event to wake us up. r0 can't be | |
258 | * used here because r0 holds ARM_IDLECT1 | |
259 | */ | |
260 | mov r2, #0 | |
261 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
670c104a TL |
262 | |
263 | @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions | |
264 | @ according to this formula: | |
265 | @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV | |
266 | @ Max DPLL_MULT = 18 | |
267 | @ DPLL_DIV = 1 | |
268 | @ ARMDIV = 1 | |
269 | @ => 74 nop-instructions | |
270 | nop | |
271 | nop | |
272 | nop | |
273 | nop | |
274 | nop | |
275 | nop | |
276 | nop | |
277 | nop | |
278 | nop | |
279 | nop @10 | |
280 | nop | |
281 | nop | |
282 | nop | |
283 | nop | |
284 | nop | |
285 | nop | |
286 | nop | |
287 | nop | |
288 | nop | |
289 | nop @20 | |
290 | nop | |
291 | nop | |
292 | nop | |
293 | nop | |
294 | nop | |
295 | nop | |
296 | nop | |
297 | nop | |
298 | nop | |
299 | nop @30 | |
300 | nop | |
301 | nop | |
302 | nop | |
303 | nop | |
304 | nop | |
305 | nop | |
306 | nop | |
307 | nop | |
308 | nop | |
309 | nop @40 | |
310 | nop | |
311 | nop | |
312 | nop | |
313 | nop | |
314 | nop | |
315 | nop | |
316 | nop | |
317 | nop | |
318 | nop | |
319 | nop @50 | |
320 | nop | |
321 | nop | |
322 | nop | |
323 | nop | |
324 | nop | |
325 | nop | |
326 | nop | |
327 | nop | |
328 | nop | |
329 | nop @60 | |
330 | nop | |
331 | nop | |
332 | nop | |
333 | nop | |
334 | nop | |
335 | nop | |
336 | nop | |
337 | nop | |
338 | nop | |
339 | nop @70 | |
340 | nop | |
341 | nop | |
342 | nop | |
343 | nop @74 | |
5e1c5ff4 TL |
344 | /* |
345 | * omap1610_cpu_suspend()'s resume point. | |
346 | * | |
347 | * It will just start executing here, so we'll restore stuff from the | |
92105bb7 | 348 | * stack. |
5e1c5ff4 | 349 | */ |
670c104a | 350 | @ Restore the ARM_IDLECT1 and ARM_IDLECT2. |
5e1c5ff4 TL |
351 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
352 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
353 | ||
92105bb7 TL |
354 | @ Restore EMIFF controls |
355 | str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
356 | str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
357 | ||
670c104a | 358 | @ Restore regs and return |
92105bb7 | 359 | ldmfd sp!, {r0 - r12, pc} |
5e1c5ff4 TL |
360 | |
361 | ENTRY(omap1610_cpu_suspend_sz) | |
362 | .word . - omap1610_cpu_suspend | |
363 | #endif /* CONFIG_ARCH_OMAP16XX */ |