PageRenderTime 27ms CodeModel.GetById 11ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 1ms

/arch/arm/mach-omap/sleep.S

https://bitbucket.org/evzijst/gittest
Assembly | 314 lines | 277 code | 37 blank | 0 comment | 7 complexity | 9bf182448eb90c16b0ae071ffc301377 MD5 | raw file
  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
 56ENTRY(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
 80l_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
101ENTRY(omap1510_idle_loop_suspend_sz)
102	.word	. - omap1510_idle_loop_suspend
103#endif /* CONFIG_ARCH_OMAP1510 */
104
105#if defined(CONFIG_ARCH_OMAP16XX)
106ENTRY(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
130l_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
151ENTRY(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
173ENTRY(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
221l_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
242ENTRY(omap1510_cpu_suspend_sz)
243	.word	. - omap1510_cpu_suspend
244#endif /* CONFIG_ARCH_OMAP1510 */
245
246#if defined(CONFIG_ARCH_OMAP16XX)
247ENTRY(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
291l_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
312ENTRY(omap1610_cpu_suspend_sz)
313	.word	. - omap1610_cpu_suspend
314#endif /* CONFIG_ARCH_OMAP16XX */