1 /*
2  * linux/arch/arm/mach-omap1/sleep.S
3  *
4  * Low-level OMAP7XX/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 
37 #include <asm/assembler.h>
38 
39 #include <mach/hardware.h>
40 
41 #include "iomap.h"
42 #include "pm.h"
43 
44 		.text
45 
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 
64 #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
65 	.align	3
66 ENTRY(omap7xx_cpu_suspend)
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)
99 	mov	r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff
100 	orr	r5, r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff00
101 	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
102 
103 	@ request ARM idle
104 	mov	r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff
105 	orr	r3, r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff00
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 /*
121  * omap7xx_cpu_suspend()'s resume point.
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 
140 ENTRY(omap7xx_cpu_suspend_sz)
141 	.word	. - omap7xx_cpu_suspend
142 #endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */
143 
144 #ifdef CONFIG_ARCH_OMAP15XX
145 	.align	3
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
184 	orr	r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
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
193 	orr	r5, r5, #IDLE_WAIT_CYCLES & 0xff00
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
213 	ldmfd	sp!, {r0 - r12, pc}
214 
215 ENTRY(omap1510_cpu_suspend_sz)
216 	.word	. - omap1510_cpu_suspend
217 #endif /* CONFIG_ARCH_OMAP15XX */
218 
219 #if defined(CONFIG_ARCH_OMAP16XX)
220 	.align	3
221 ENTRY(omap1610_cpu_suspend)
222 
223 	@ save registers on stack
224 	stmfd	sp!, {r0 - r12, lr}
225 
226 	@ Drain write cache
227 	mov	r4, #0
228 	mcr	p15, 0, r0, c7, c10, 4
229 	nop
230 
231 	@ Load base address of Traffic Controller
232 	mov	r6, #TCMIF_ASM_BASE & 0xff000000
233 	orr	r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
234 	orr	r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
235 
236 	@ Prepare to put SDRAM into self-refresh manually
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]
241 
242 	@ Prepare to put EMIFS to Sleep
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]
246 
247 	@ Load base address of ARM_IDLECT1 and ARM_IDLECT2
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 
252 	@ Turn off clock domains
253 	@ Do not disable PERCK (0x04)
254 	mov	r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
255 	orr	r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
256 	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
257 
258 	@ Request ARM idle
259 	mov	r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
260 	orr	r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
261 	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
262 
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
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
351 /*
352  * omap1610_cpu_suspend()'s resume point.
353  *
354  * It will just start executing here, so we'll restore stuff from the
355  * stack.
356  */
357 	@ Restore the ARM_IDLECT1 and ARM_IDLECT2.
358 	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
359 	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
360 
361 	@ Restore EMIFF controls
362 	str	r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
363 	str	r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
364 
365 	@ Restore regs and return
366 	ldmfd	sp!, {r0 - r12, pc}
367 
368 ENTRY(omap1610_cpu_suspend_sz)
369 	.word	. - omap1610_cpu_suspend
370 #endif /* CONFIG_ARCH_OMAP16XX */
371