diff options
Diffstat (limited to 'arch/arm/mach-omap1/sleep.S')
-rw-r--r-- | arch/arm/mach-omap1/sleep.S | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/arch/arm/mach-omap1/sleep.S b/arch/arm/mach-omap1/sleep.S new file mode 100644 index 000000000000..e58295e2d3b2 --- /dev/null +++ b/arch/arm/mach-omap1/sleep.S | |||
@@ -0,0 +1,525 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap1/sleep.S | ||
3 | * | ||
4 | * Low-level OMAP730/1510/1610 sleep/wakeUp support | ||
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 | |||
35 | #include <linux/config.h> | ||
36 | #include <linux/linkage.h> | ||
37 | #include <asm/assembler.h> | ||
38 | #include <asm/arch/io.h> | ||
39 | #include <asm/arch/pm.h> | ||
40 | |||
41 | .text | ||
42 | |||
43 | /* | ||
44 | * Forces OMAP into idle state | ||
45 | * | ||
46 | * omapXXXX_idle_loop_suspend() | ||
47 | * | ||
48 | * Note: This code get's copied to internal SRAM at boot. When the OMAP | ||
49 | * wakes up it continues execution at the point it went to sleep. | ||
50 | * | ||
51 | * Note: Because of slightly different configuration values we have | ||
52 | * processor specific functions here. | ||
53 | */ | ||
54 | |||
55 | #if defined(CONFIG_ARCH_OMAP730) | ||
56 | ENTRY(omap730_idle_loop_suspend) | ||
57 | |||
58 | stmfd sp!, {r0 - r12, lr} @ save registers on stack | ||
59 | |||
60 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | ||
61 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | ||
62 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | ||
63 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | ||
64 | |||
65 | @ turn off clock domains | ||
66 | @ get ARM_IDLECT2 into r2 | ||
67 | ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
68 | mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | ||
69 | orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | ||
70 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
71 | |||
72 | @ request ARM idle | ||
73 | @ get ARM_IDLECT1 into r1 | ||
74 | ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
75 | orr r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff | ||
76 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
77 | |||
78 | mov r5, #IDLE_WAIT_CYCLES & 0xff | ||
79 | orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | ||
80 | l_730: subs r5, r5, #1 | ||
81 | bne l_730 | ||
82 | /* | ||
83 | * Let's wait for the next clock tick to wake us up. | ||
84 | */ | ||
85 | mov r0, #0 | ||
86 | mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | ||
87 | /* | ||
88 | * omap730_idle_loop_suspend()'s resume point. | ||
89 | * | ||
90 | * It will just start executing here, so we'll restore stuff from the | ||
91 | * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | ||
92 | */ | ||
93 | |||
94 | @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | ||
95 | @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | ||
96 | strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
97 | strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
98 | |||
99 | ldmfd sp!, {r0 - r12, pc} @ restore regs and return | ||
100 | |||
101 | ENTRY(omap730_idle_loop_suspend_sz) | ||
102 | .word . - omap730_idle_loop_suspend | ||
103 | #endif /* CONFIG_ARCH_OMAP730 */ | ||
104 | |||
105 | #ifdef CONFIG_ARCH_OMAP15XX | ||
106 | ENTRY(omap1510_idle_loop_suspend) | ||
107 | |||
108 | stmfd sp!, {r0 - r12, lr} @ save registers on stack | ||
109 | |||
110 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | ||
111 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | ||
112 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | ||
113 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | ||
114 | |||
115 | @ turn off clock domains | ||
116 | @ get ARM_IDLECT2 into r2 | ||
117 | ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
118 | mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff | ||
119 | orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | ||
120 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
121 | |||
122 | @ request ARM idle | ||
123 | @ get ARM_IDLECT1 into r1 | ||
124 | ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
125 | orr r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff | ||
126 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
127 | |||
128 | mov r5, #IDLE_WAIT_CYCLES & 0xff | ||
129 | orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | ||
130 | l_1510: subs r5, r5, #1 | ||
131 | bne l_1510 | ||
132 | /* | ||
133 | * Let's wait for the next clock tick to wake us up. | ||
134 | */ | ||
135 | mov r0, #0 | ||
136 | mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | ||
137 | /* | ||
138 | * omap1510_idle_loop_suspend()'s resume point. | ||
139 | * | ||
140 | * It will just start executing here, so we'll restore stuff from the | ||
141 | * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | ||
142 | */ | ||
143 | |||
144 | @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | ||
145 | @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | ||
146 | strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
147 | strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
148 | |||
149 | ldmfd sp!, {r0 - r12, pc} @ restore regs and return | ||
150 | |||
151 | ENTRY(omap1510_idle_loop_suspend_sz) | ||
152 | .word . - omap1510_idle_loop_suspend | ||
153 | #endif /* CONFIG_ARCH_OMAP15XX */ | ||
154 | |||
155 | #if defined(CONFIG_ARCH_OMAP16XX) | ||
156 | ENTRY(omap1610_idle_loop_suspend) | ||
157 | |||
158 | stmfd sp!, {r0 - r12, lr} @ save registers on stack | ||
159 | |||
160 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | ||
161 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | ||
162 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | ||
163 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | ||
164 | |||
165 | @ turn off clock domains | ||
166 | @ get ARM_IDLECT2 into r2 | ||
167 | ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
168 | mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff | ||
169 | orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | ||
170 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
171 | |||
172 | @ request ARM idle | ||
173 | @ get ARM_IDLECT1 into r1 | ||
174 | ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
175 | orr r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff | ||
176 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
177 | |||
178 | mov r5, #IDLE_WAIT_CYCLES & 0xff | ||
179 | orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | ||
180 | l_1610: subs r5, r5, #1 | ||
181 | bne l_1610 | ||
182 | /* | ||
183 | * Let's wait for the next clock tick to wake us up. | ||
184 | */ | ||
185 | mov r0, #0 | ||
186 | mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | ||
187 | /* | ||
188 | * omap1610_idle_loop_suspend()'s resume point. | ||
189 | * | ||
190 | * It will just start executing here, so we'll restore stuff from the | ||
191 | * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | ||
192 | */ | ||
193 | |||
194 | @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | ||
195 | @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | ||
196 | strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
197 | strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
198 | |||
199 | ldmfd sp!, {r0 - r12, pc} @ restore regs and return | ||
200 | |||
201 | ENTRY(omap1610_idle_loop_suspend_sz) | ||
202 | .word . - omap1610_idle_loop_suspend | ||
203 | #endif /* CONFIG_ARCH_OMAP16XX */ | ||
204 | |||
205 | /* | ||
206 | * Forces OMAP into deep sleep state | ||
207 | * | ||
208 | * omapXXXX_cpu_suspend() | ||
209 | * | ||
210 | * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed | ||
211 | * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1 | ||
212 | * in register r1. | ||
213 | * | ||
214 | * Note: This code get's copied to internal SRAM at boot. When the OMAP | ||
215 | * wakes up it continues execution at the point it went to sleep. | ||
216 | * | ||
217 | * Note: Because of errata work arounds we have processor specific functions | ||
218 | * here. They are mostly the same, but slightly different. | ||
219 | * | ||
220 | */ | ||
221 | |||
222 | #if defined(CONFIG_ARCH_OMAP730) | ||
223 | ENTRY(omap730_cpu_suspend) | ||
224 | |||
225 | @ save registers on stack | ||
226 | stmfd sp!, {r0 - r12, lr} | ||
227 | |||
228 | @ Drain write cache | ||
229 | mov r4, #0 | ||
230 | mcr p15, 0, r0, c7, c10, 4 | ||
231 | nop | ||
232 | |||
233 | @ load base address of Traffic Controller | ||
234 | mov r6, #TCMIF_ASM_BASE & 0xff000000 | ||
235 | orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | ||
236 | orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | ||
237 | |||
238 | @ prepare to put SDRAM into self-refresh manually | ||
239 | ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
240 | orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | ||
241 | orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | ||
242 | str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
243 | |||
244 | @ prepare to put EMIFS to Sleep | ||
245 | ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
246 | orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | ||
247 | str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
248 | |||
249 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | ||
250 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | ||
251 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | ||
252 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | ||
253 | |||
254 | @ turn off clock domains | ||
255 | @ do not disable PERCK (0x04) | ||
256 | mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | ||
257 | orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | ||
258 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
259 | |||
260 | @ request ARM idle | ||
261 | mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff | ||
262 | orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00 | ||
263 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
264 | |||
265 | @ disable instruction cache | ||
266 | mrc p15, 0, r9, c1, c0, 0 | ||
267 | bic r2, r9, #0x1000 | ||
268 | mcr p15, 0, r2, c1, c0, 0 | ||
269 | nop | ||
270 | |||
271 | /* | ||
272 | * Let's wait for the next wake up event to wake us up. r0 can't be | ||
273 | * used here because r0 holds ARM_IDLECT1 | ||
274 | */ | ||
275 | mov r2, #0 | ||
276 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | ||
277 | /* | ||
278 | * omap730_cpu_suspend()'s resume point. | ||
279 | * | ||
280 | * It will just start executing here, so we'll restore stuff from the | ||
281 | * stack. | ||
282 | */ | ||
283 | @ re-enable Icache | ||
284 | mcr p15, 0, r9, c1, c0, 0 | ||
285 | |||
286 | @ reset the ARM_IDLECT1 and ARM_IDLECT2. | ||
287 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
288 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
289 | |||
290 | @ Restore EMIFF controls | ||
291 | str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
292 | str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
293 | |||
294 | @ restore regs and return | ||
295 | ldmfd sp!, {r0 - r12, pc} | ||
296 | |||
297 | ENTRY(omap730_cpu_suspend_sz) | ||
298 | .word . - omap730_cpu_suspend | ||
299 | #endif /* CONFIG_ARCH_OMAP730 */ | ||
300 | |||
301 | #ifdef CONFIG_ARCH_OMAP15XX | ||
302 | ENTRY(omap1510_cpu_suspend) | ||
303 | |||
304 | @ save registers on stack | ||
305 | stmfd sp!, {r0 - r12, lr} | ||
306 | |||
307 | @ load base address of Traffic Controller | ||
308 | mov r4, #TCMIF_ASM_BASE & 0xff000000 | ||
309 | orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 | ||
310 | orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 | ||
311 | |||
312 | @ work around errata of OMAP1510 PDE bit for TC shut down | ||
313 | @ clear PDE bit | ||
314 | ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
315 | bic r5, r5, #PDE_BIT & 0xff | ||
316 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
317 | |||
318 | @ set PWD_EN bit | ||
319 | and r5, r5, #PWD_EN_BIT & 0xff | ||
320 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
321 | |||
322 | @ prepare to put SDRAM into self-refresh manually | ||
323 | ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
324 | orr r5, r5, #SELF_REFRESH_MODE & 0xff000000 | ||
325 | orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff | ||
326 | str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
327 | |||
328 | @ prepare to put EMIFS to Sleep | ||
329 | ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
330 | orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff | ||
331 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
332 | |||
333 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | ||
334 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | ||
335 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | ||
336 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | ||
337 | |||
338 | @ turn off clock domains | ||
339 | mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff | ||
340 | orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | ||
341 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
342 | |||
343 | @ request ARM idle | ||
344 | mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff | ||
345 | orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00 | ||
346 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
347 | |||
348 | mov r5, #IDLE_WAIT_CYCLES & 0xff | ||
349 | orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | ||
350 | l_1510_2: | ||
351 | subs r5, r5, #1 | ||
352 | bne l_1510_2 | ||
353 | /* | ||
354 | * Let's wait for the next wake up event to wake us up. r0 can't be | ||
355 | * used here because r0 holds ARM_IDLECT1 | ||
356 | */ | ||
357 | mov r2, #0 | ||
358 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | ||
359 | /* | ||
360 | * omap1510_cpu_suspend()'s resume point. | ||
361 | * | ||
362 | * It will just start executing here, so we'll restore stuff from the | ||
363 | * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | ||
364 | */ | ||
365 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
366 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
367 | |||
368 | @ restore regs and return | ||
369 | ldmfd sp!, {r0 - r12, pc} | ||
370 | |||
371 | ENTRY(omap1510_cpu_suspend_sz) | ||
372 | .word . - omap1510_cpu_suspend | ||
373 | #endif /* CONFIG_ARCH_OMAP15XX */ | ||
374 | |||
375 | #if defined(CONFIG_ARCH_OMAP16XX) | ||
376 | ENTRY(omap1610_cpu_suspend) | ||
377 | |||
378 | @ save registers on stack | ||
379 | stmfd sp!, {r0 - r12, lr} | ||
380 | |||
381 | @ Drain write cache | ||
382 | mov r4, #0 | ||
383 | mcr p15, 0, r0, c7, c10, 4 | ||
384 | nop | ||
385 | |||
386 | @ Load base address of Traffic Controller | ||
387 | mov r6, #TCMIF_ASM_BASE & 0xff000000 | ||
388 | orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | ||
389 | orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | ||
390 | |||
391 | @ Prepare to put SDRAM into self-refresh manually | ||
392 | ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
393 | orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | ||
394 | orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | ||
395 | str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
396 | |||
397 | @ Prepare to put EMIFS to Sleep | ||
398 | ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
399 | orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | ||
400 | str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
401 | |||
402 | @ Load base address of ARM_IDLECT1 and ARM_IDLECT2 | ||
403 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | ||
404 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | ||
405 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | ||
406 | |||
407 | @ Turn off clock domains | ||
408 | @ Do not disable PERCK (0x04) | ||
409 | mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff | ||
410 | orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | ||
411 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
412 | |||
413 | @ Request ARM idle | ||
414 | mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff | ||
415 | orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 | ||
416 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
417 | |||
418 | /* | ||
419 | * Let's wait for the next wake up event to wake us up. r0 can't be | ||
420 | * used here because r0 holds ARM_IDLECT1 | ||
421 | */ | ||
422 | mov r2, #0 | ||
423 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | ||
424 | |||
425 | @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions | ||
426 | @ according to this formula: | ||
427 | @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV | ||
428 | @ Max DPLL_MULT = 18 | ||
429 | @ DPLL_DIV = 1 | ||
430 | @ ARMDIV = 1 | ||
431 | @ => 74 nop-instructions | ||
432 | nop | ||
433 | nop | ||
434 | nop | ||
435 | nop | ||
436 | nop | ||
437 | nop | ||
438 | nop | ||
439 | nop | ||
440 | nop | ||
441 | nop @10 | ||
442 | nop | ||
443 | nop | ||
444 | nop | ||
445 | nop | ||
446 | nop | ||
447 | nop | ||
448 | nop | ||
449 | nop | ||
450 | nop | ||
451 | nop @20 | ||
452 | nop | ||
453 | nop | ||
454 | nop | ||
455 | nop | ||
456 | nop | ||
457 | nop | ||
458 | nop | ||
459 | nop | ||
460 | nop | ||
461 | nop @30 | ||
462 | nop | ||
463 | nop | ||
464 | nop | ||
465 | nop | ||
466 | nop | ||
467 | nop | ||
468 | nop | ||
469 | nop | ||
470 | nop | ||
471 | nop @40 | ||
472 | nop | ||
473 | nop | ||
474 | nop | ||
475 | nop | ||
476 | nop | ||
477 | nop | ||
478 | nop | ||
479 | nop | ||
480 | nop | ||
481 | nop @50 | ||
482 | nop | ||
483 | nop | ||
484 | nop | ||
485 | nop | ||
486 | nop | ||
487 | nop | ||
488 | nop | ||
489 | nop | ||
490 | nop | ||
491 | nop @60 | ||
492 | nop | ||
493 | nop | ||
494 | nop | ||
495 | nop | ||
496 | nop | ||
497 | nop | ||
498 | nop | ||
499 | nop | ||
500 | nop | ||
501 | nop @70 | ||
502 | nop | ||
503 | nop | ||
504 | nop | ||
505 | nop @74 | ||
506 | /* | ||
507 | * omap1610_cpu_suspend()'s resume point. | ||
508 | * | ||
509 | * It will just start executing here, so we'll restore stuff from the | ||
510 | * stack. | ||
511 | */ | ||
512 | @ Restore the ARM_IDLECT1 and ARM_IDLECT2. | ||
513 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | ||
514 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | ||
515 | |||
516 | @ Restore EMIFF controls | ||
517 | str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | ||
518 | str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | ||
519 | |||
520 | @ Restore regs and return | ||
521 | ldmfd sp!, {r0 - r12, pc} | ||
522 | |||
523 | ENTRY(omap1610_cpu_suspend_sz) | ||
524 | .word . - omap1610_cpu_suspend | ||
525 | #endif /* CONFIG_ARCH_OMAP16XX */ | ||