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