Merge master.kernel.org:/pub/scm/linux/kernel/git/tmlind/linux-omap-upstream
[linux-2.6] / arch / arm / plat-omap / sleep.S
1 /*
2  * linux/arch/arm/plat-omap/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         @ disable instruction cache
419         mrc     p15, 0, r9, c1, c0, 0
420         bic     r2, r9, #0x1000
421         mcr     p15, 0, r2, c1, c0, 0
422         nop
423
424 /*
425  * Let's wait for the next wake up event to wake us up. r0 can't be
426  * used here because r0 holds ARM_IDLECT1
427  */
428         mov     r2, #0
429         mcr     p15, 0, r2, c7, c0, 4           @ wait for interrupt
430 /*
431  * omap1610_cpu_suspend()'s resume point.
432  *
433  * It will just start executing here, so we'll restore stuff from the
434  * stack.
435  */
436         @ re-enable Icache
437         mcr     p15, 0, r9, c1, c0, 0
438
439         @ reset the ARM_IDLECT1 and ARM_IDLECT2.
440         strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
441         strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
442
443         @ Restore EMIFF controls
444         str     r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
445         str     r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
446
447         @ restore regs and return
448         ldmfd   sp!, {r0 - r12, pc}
449
450 ENTRY(omap1610_cpu_suspend_sz)
451         .word   . - omap1610_cpu_suspend
452 #endif /* CONFIG_ARCH_OMAP16XX */