]>
Commit | Line | Data |
---|---|---|
5e1c5ff4 | 1 | /* |
670c104a | 2 | * linux/arch/arm/mach-omap1/sleep.S |
5e1c5ff4 | 3 | * |
7c006926 | 4 | * Low-level OMAP7XX/1510/1610 sleep/wakeUp support |
5e1c5ff4 TL |
5 | * |
6 | * Initial SA1110 code: | |
7 | * Copyright (c) 2001 Cliff Brake <[email protected]> | |
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 <[email protected]> | |
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 | 35 | #include <linux/linkage.h> |
2e3ee9f4 | 36 | |
5e1c5ff4 | 37 | #include <asm/assembler.h> |
2e3ee9f4 | 38 | |
4e969010 TL |
39 | #include <mach/hardware.h> |
40 | ||
2e3ee9f4 | 41 | #include "iomap.h" |
c912f7e1 | 42 | #include "pm.h" |
5e1c5ff4 TL |
43 | |
44 | .text | |
45 | ||
5e1c5ff4 TL |
46 | |
47 | /* | |
48 | * Forces OMAP into deep sleep state | |
49 | * | |
50 | * omapXXXX_cpu_suspend() | |
51 | * | |
52 | * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed | |
53 | * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1 | |
54 | * in register r1. | |
55 | * | |
56 | * Note: This code get's copied to internal SRAM at boot. When the OMAP | |
57 | * wakes up it continues execution at the point it went to sleep. | |
58 | * | |
59 | * Note: Because of errata work arounds we have processor specific functions | |
60 | * here. They are mostly the same, but slightly different. | |
61 | * | |
62 | */ | |
63 | ||
7c006926 | 64 | #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850) |
b6338bdc | 65 | .align 3 |
7c006926 | 66 | ENTRY(omap7xx_cpu_suspend) |
1a8bfa1e TL |
67 | |
68 | @ save registers on stack | |
69 | stmfd sp!, {r0 - r12, lr} | |
70 | ||
71 | @ Drain write cache | |
72 | mov r4, #0 | |
73 | mcr p15, 0, r0, c7, c10, 4 | |
74 | nop | |
75 | ||
76 | @ load base address of Traffic Controller | |
77 | mov r6, #TCMIF_ASM_BASE & 0xff000000 | |
78 | orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
79 | orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
80 | ||
81 | @ prepare to put SDRAM into self-refresh manually | |
82 | ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
83 | orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
84 | orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
85 | str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
86 | ||
87 | @ prepare to put EMIFS to Sleep | |
88 | ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
89 | orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
90 | str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
91 | ||
92 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
93 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
94 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
95 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
96 | ||
97 | @ turn off clock domains | |
98 | @ do not disable PERCK (0x04) | |
7c006926 AB |
99 | mov r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff |
100 | orr r5, r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff00 | |
1a8bfa1e TL |
101 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
102 | ||
103 | @ request ARM idle | |
7c006926 AB |
104 | mov r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff |
105 | orr r3, r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff00 | |
1a8bfa1e TL |
106 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
107 | ||
108 | @ disable instruction cache | |
109 | mrc p15, 0, r9, c1, c0, 0 | |
110 | bic r2, r9, #0x1000 | |
111 | mcr p15, 0, r2, c1, c0, 0 | |
112 | nop | |
113 | ||
114 | /* | |
115 | * Let's wait for the next wake up event to wake us up. r0 can't be | |
116 | * used here because r0 holds ARM_IDLECT1 | |
117 | */ | |
118 | mov r2, #0 | |
119 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
120 | /* | |
7c006926 | 121 | * omap7xx_cpu_suspend()'s resume point. |
1a8bfa1e TL |
122 | * |
123 | * It will just start executing here, so we'll restore stuff from the | |
124 | * stack. | |
125 | */ | |
126 | @ re-enable Icache | |
127 | mcr p15, 0, r9, c1, c0, 0 | |
128 | ||
129 | @ reset the ARM_IDLECT1 and ARM_IDLECT2. | |
130 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
131 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
132 | ||
133 | @ Restore EMIFF controls | |
134 | str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
135 | str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
136 | ||
137 | @ restore regs and return | |
138 | ldmfd sp!, {r0 - r12, pc} | |
139 | ||
7c006926 AB |
140 | ENTRY(omap7xx_cpu_suspend_sz) |
141 | .word . - omap7xx_cpu_suspend | |
142 | #endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */ | |
1a8bfa1e TL |
143 | |
144 | #ifdef CONFIG_ARCH_OMAP15XX | |
b6338bdc | 145 | .align 3 |
5e1c5ff4 TL |
146 | ENTRY(omap1510_cpu_suspend) |
147 | ||
148 | @ save registers on stack | |
149 | stmfd sp!, {r0 - r12, lr} | |
150 | ||
151 | @ load base address of Traffic Controller | |
152 | mov r4, #TCMIF_ASM_BASE & 0xff000000 | |
153 | orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 | |
154 | orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 | |
155 | ||
156 | @ work around errata of OMAP1510 PDE bit for TC shut down | |
157 | @ clear PDE bit | |
158 | ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
159 | bic r5, r5, #PDE_BIT & 0xff | |
160 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
161 | ||
162 | @ set PWD_EN bit | |
163 | and r5, r5, #PWD_EN_BIT & 0xff | |
164 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
165 | ||
166 | @ prepare to put SDRAM into self-refresh manually | |
167 | ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
168 | orr r5, r5, #SELF_REFRESH_MODE & 0xff000000 | |
169 | orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff | |
170 | str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
171 | ||
172 | @ prepare to put EMIFS to Sleep | |
173 | ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
174 | orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff | |
175 | str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
176 | ||
177 | @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
178 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
179 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
180 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
181 | ||
182 | @ turn off clock domains | |
183 | mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff | |
92105bb7 | 184 | orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 |
5e1c5ff4 TL |
185 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
186 | ||
187 | @ request ARM idle | |
188 | mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff | |
189 | orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00 | |
190 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
191 | ||
192 | mov r5, #IDLE_WAIT_CYCLES & 0xff | |
92105bb7 | 193 | orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 |
5e1c5ff4 TL |
194 | l_1510_2: |
195 | subs r5, r5, #1 | |
196 | bne l_1510_2 | |
197 | /* | |
198 | * Let's wait for the next wake up event to wake us up. r0 can't be | |
199 | * used here because r0 holds ARM_IDLECT1 | |
200 | */ | |
201 | mov r2, #0 | |
202 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
203 | /* | |
204 | * omap1510_cpu_suspend()'s resume point. | |
205 | * | |
206 | * It will just start executing here, so we'll restore stuff from the | |
207 | * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
208 | */ | |
209 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
210 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
211 | ||
212 | @ restore regs and return | |
92105bb7 | 213 | ldmfd sp!, {r0 - r12, pc} |
5e1c5ff4 TL |
214 | |
215 | ENTRY(omap1510_cpu_suspend_sz) | |
216 | .word . - omap1510_cpu_suspend | |
1a8bfa1e | 217 | #endif /* CONFIG_ARCH_OMAP15XX */ |
5e1c5ff4 TL |
218 | |
219 | #if defined(CONFIG_ARCH_OMAP16XX) | |
b6338bdc | 220 | .align 3 |
5e1c5ff4 TL |
221 | ENTRY(omap1610_cpu_suspend) |
222 | ||
223 | @ save registers on stack | |
224 | stmfd sp!, {r0 - r12, lr} | |
225 | ||
92105bb7 TL |
226 | @ Drain write cache |
227 | mov r4, #0 | |
228 | mcr p15, 0, r0, c7, c10, 4 | |
229 | nop | |
230 | ||
670c104a | 231 | @ Load base address of Traffic Controller |
92105bb7 TL |
232 | mov r6, #TCMIF_ASM_BASE & 0xff000000 |
233 | orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
234 | orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
5e1c5ff4 | 235 | |
670c104a | 236 | @ Prepare to put SDRAM into self-refresh manually |
92105bb7 TL |
237 | ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] |
238 | orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
239 | orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
240 | str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
5e1c5ff4 | 241 | |
670c104a | 242 | @ Prepare to put EMIFS to Sleep |
92105bb7 TL |
243 | ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] |
244 | orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
245 | str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
5e1c5ff4 | 246 | |
670c104a | 247 | @ Load base address of ARM_IDLECT1 and ARM_IDLECT2 |
5e1c5ff4 TL |
248 | mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 |
249 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
250 | orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
251 | ||
670c104a TL |
252 | @ Turn off clock domains |
253 | @ Do not disable PERCK (0x04) | |
92105bb7 TL |
254 | mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff |
255 | orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | |
5e1c5ff4 TL |
256 | strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
257 | ||
670c104a | 258 | @ Request ARM idle |
92105bb7 TL |
259 | mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff |
260 | orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 | |
5e1c5ff4 TL |
261 | strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] |
262 | ||
5e1c5ff4 TL |
263 | /* |
264 | * Let's wait for the next wake up event to wake us up. r0 can't be | |
265 | * used here because r0 holds ARM_IDLECT1 | |
266 | */ | |
267 | mov r2, #0 | |
268 | mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
670c104a TL |
269 | |
270 | @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions | |
271 | @ according to this formula: | |
272 | @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV | |
273 | @ Max DPLL_MULT = 18 | |
274 | @ DPLL_DIV = 1 | |
275 | @ ARMDIV = 1 | |
276 | @ => 74 nop-instructions | |
277 | nop | |
278 | nop | |
279 | nop | |
280 | nop | |
281 | nop | |
282 | nop | |
283 | nop | |
284 | nop | |
285 | nop | |
286 | nop @10 | |
287 | nop | |
288 | nop | |
289 | nop | |
290 | nop | |
291 | nop | |
292 | nop | |
293 | nop | |
294 | nop | |
295 | nop | |
296 | nop @20 | |
297 | nop | |
298 | nop | |
299 | nop | |
300 | nop | |
301 | nop | |
302 | nop | |
303 | nop | |
304 | nop | |
305 | nop | |
306 | nop @30 | |
307 | nop | |
308 | nop | |
309 | nop | |
310 | nop | |
311 | nop | |
312 | nop | |
313 | nop | |
314 | nop | |
315 | nop | |
316 | nop @40 | |
317 | nop | |
318 | nop | |
319 | nop | |
320 | nop | |
321 | nop | |
322 | nop | |
323 | nop | |
324 | nop | |
325 | nop | |
326 | nop @50 | |
327 | nop | |
328 | nop | |
329 | nop | |
330 | nop | |
331 | nop | |
332 | nop | |
333 | nop | |
334 | nop | |
335 | nop | |
336 | nop @60 | |
337 | nop | |
338 | nop | |
339 | nop | |
340 | nop | |
341 | nop | |
342 | nop | |
343 | nop | |
344 | nop | |
345 | nop | |
346 | nop @70 | |
347 | nop | |
348 | nop | |
349 | nop | |
350 | nop @74 | |
5e1c5ff4 TL |
351 | /* |
352 | * omap1610_cpu_suspend()'s resume point. | |
353 | * | |
354 | * It will just start executing here, so we'll restore stuff from the | |
92105bb7 | 355 | * stack. |
5e1c5ff4 | 356 | */ |
670c104a | 357 | @ Restore the ARM_IDLECT1 and ARM_IDLECT2. |
5e1c5ff4 TL |
358 | strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] |
359 | strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
360 | ||
92105bb7 TL |
361 | @ Restore EMIFF controls |
362 | str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
363 | str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
364 | ||
670c104a | 365 | @ Restore regs and return |
92105bb7 | 366 | ldmfd sp!, {r0 - r12, pc} |
5e1c5ff4 TL |
367 | |
368 | ENTRY(omap1610_cpu_suspend_sz) | |
369 | .word . - omap1610_cpu_suspend | |
370 | #endif /* CONFIG_ARCH_OMAP16XX */ |