Linux-2.6.12-rc2
[linux-2.6.git] / arch / arm / mach-omap / sleep.S
1 /*
2  * linux/arch/arm/mach-omap/sleep.S
3  *
4  * Low-level OMAP1510/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 #ifdef CONFIG_ARCH_OMAP1510
56 ENTRY(omap1510_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, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
69         orr     r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 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, #OMAP1510_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_1510: subs    r5, r5, #1
81         bne     l_1510
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  * omap1510_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(omap1510_idle_loop_suspend_sz)
102         .word   . - omap1510_idle_loop_suspend
103 #endif /* CONFIG_ARCH_OMAP1510 */
104
105 #if defined(CONFIG_ARCH_OMAP16XX)
106 ENTRY(omap1610_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, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
119         orr     r5,r5, #OMAP1610_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, #OMAP1610_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_1610: subs    r5, r5, #1
131         bne     l_1610
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  * omap1610_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(omap1610_idle_loop_suspend_sz)
152         .word   . - omap1610_idle_loop_suspend
153 #endif /* CONFIG_ARCH_OMAP16XX */
154
155 /*
156  * Forces OMAP into deep sleep state
157  *
158  * omapXXXX_cpu_suspend()
159  *
160  * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
161  * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
162  * in register r1.
163  *
164  * Note: This code get's copied to internal SRAM at boot. When the OMAP
165  *       wakes up it continues execution at the point it went to sleep.
166  *
167  * Note: Because of errata work arounds we have processor specific functions
168  *       here. They are mostly the same, but slightly different.
169  *
170  */
171
172 #ifdef CONFIG_ARCH_OMAP1510
173 ENTRY(omap1510_cpu_suspend)
174
175         @ save registers on stack
176         stmfd   sp!, {r0 - r12, lr}
177
178         @ load base address of Traffic Controller
179         mov     r4, #TCMIF_ASM_BASE & 0xff000000
180         orr     r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
181         orr     r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
182
183         @ work around errata of OMAP1510 PDE bit for TC shut down
184         @ clear PDE bit
185         ldr     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
186         bic     r5, r5, #PDE_BIT & 0xff
187         str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
188
189         @ set PWD_EN bit
190         and     r5, r5, #PWD_EN_BIT & 0xff
191         str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
192
193         @ prepare to put SDRAM into self-refresh manually
194         ldr     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
195         orr     r5, r5, #SELF_REFRESH_MODE & 0xff000000
196         orr     r5, r5, #SELF_REFRESH_MODE & 0x000000ff
197         str     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
198
199         @ prepare to put EMIFS to Sleep
200         ldr     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
201         orr     r5, r5, #IDLE_EMIFS_REQUEST & 0xff
202         str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
203
204         @ load base address of ARM_IDLECT1 and ARM_IDLECT2
205         mov     r4, #CLKGEN_REG_ASM_BASE & 0xff000000
206         orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
207         orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
208
209         @ turn off clock domains
210         mov     r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
211         orr     r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
212         strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
213
214         @ request ARM idle
215         mov     r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
216         orr     r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
217         strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
218
219         mov     r5, #IDLE_WAIT_CYCLES & 0xff
220         orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
221 l_1510_2:
222         subs    r5, r5, #1
223         bne     l_1510_2
224 /*
225  * Let's wait for the next wake up event to wake us up. r0 can't be
226  * used here because r0 holds ARM_IDLECT1
227  */
228         mov     r2, #0
229         mcr     p15, 0, r2, c7, c0, 4           @ wait for interrupt
230 /*
231  * omap1510_cpu_suspend()'s resume point.
232  *
233  * It will just start executing here, so we'll restore stuff from the
234  * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
235  */
236         strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
237         strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
238
239         @ restore regs and return
240         ldmfd   sp!, {r0 - r12, pc}
241
242 ENTRY(omap1510_cpu_suspend_sz)
243         .word   . - omap1510_cpu_suspend
244 #endif /* CONFIG_ARCH_OMAP1510 */
245
246 #if defined(CONFIG_ARCH_OMAP16XX)
247 ENTRY(omap1610_cpu_suspend)
248
249         @ save registers on stack
250         stmfd   sp!, {r0 - r12, lr}
251
252         @ load base address of Traffic Controller
253         mov     r4, #TCMIF_ASM_BASE & 0xff000000
254         orr     r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
255         orr     r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
256
257         @ prepare to put SDRAM into self-refresh manually
258         ldr     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
259         orr     r5, r5, #SELF_REFRESH_MODE & 0xff000000
260         orr     r5, r5, #SELF_REFRESH_MODE & 0x000000ff
261         str     r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
262
263         @ prepare to put EMIFS to Sleep
264         ldr     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
265         orr     r5, r5, #IDLE_EMIFS_REQUEST & 0xff
266         str     r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
267
268         @ load base address of ARM_IDLECT1 and ARM_IDLECT2
269         mov     r4, #CLKGEN_REG_ASM_BASE & 0xff000000
270         orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
271         orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
272
273         @ turn off clock domains
274         mov     r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
275         orr     r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
276         strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
277
278         @ work around errata of OMAP1610/5912. Enable (!) peripheral
279         @ clock to let the chip go into deep sleep
280         ldrh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
281         orr     r5,r5, #EN_PERCK_BIT & 0xff
282         strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
283
284         @ request ARM idle
285         mov     r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff
286         orr     r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00
287         strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
288
289         mov     r5, #IDLE_WAIT_CYCLES & 0xff
290         orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
291 l_1610_2:
292         subs    r5, r5, #1
293         bne     l_1610_2
294 /*
295  * Let's wait for the next wake up event to wake us up. r0 can't be
296  * used here because r0 holds ARM_IDLECT1
297  */
298         mov     r2, #0
299         mcr     p15, 0, r2, c7, c0, 4           @ wait for interrupt
300 /*
301  * omap1610_cpu_suspend()'s resume point.
302  *
303  * It will just start executing here, so we'll restore stuff from the
304  * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
305  */
306         strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
307         strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
308
309         @ restore regs and return
310         ldmfd   sp!, {r0 - r12, pc}
311
312 ENTRY(omap1610_cpu_suspend_sz)
313         .word   . - omap1610_cpu_suspend
314 #endif /* CONFIG_ARCH_OMAP16XX */