xref: /linux/arch/arm/mach-omap1/sleep.S (revision f3d9478b2ce468c3115b02ecae7e975990697f15)
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)
56ENTRY(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
80l_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
101ENTRY(omap730_idle_loop_suspend_sz)
102	.word	. - omap730_idle_loop_suspend
103#endif /* CONFIG_ARCH_OMAP730 */
104
105#ifdef CONFIG_ARCH_OMAP15XX
106ENTRY(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
130l_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
151ENTRY(omap1510_idle_loop_suspend_sz)
152	.word	. - omap1510_idle_loop_suspend
153#endif /* CONFIG_ARCH_OMAP15XX */
154
155#if defined(CONFIG_ARCH_OMAP16XX)
156ENTRY(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
180l_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
201ENTRY(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)
223ENTRY(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
297ENTRY(omap730_cpu_suspend_sz)
298	.word	. - omap730_cpu_suspend
299#endif /* CONFIG_ARCH_OMAP730 */
300
301#ifdef CONFIG_ARCH_OMAP15XX
302ENTRY(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
350l_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
371ENTRY(omap1510_cpu_suspend_sz)
372	.word	. - omap1510_cpu_suspend
373#endif /* CONFIG_ARCH_OMAP15XX */
374
375#if defined(CONFIG_ARCH_OMAP16XX)
376ENTRY(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
523ENTRY(omap1610_cpu_suspend_sz)
524	.word	. - omap1610_cpu_suspend
525#endif /* CONFIG_ARCH_OMAP16XX */
526