diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 | 
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/mach-omap/sleep.S | |
| download | olio-linux-3.10-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.xz olio-linux-3.10-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.zip  | |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/arm/mach-omap/sleep.S')
| -rw-r--r-- | arch/arm/mach-omap/sleep.S | 314 | 
1 files changed, 314 insertions, 0 deletions
diff --git a/arch/arm/mach-omap/sleep.S b/arch/arm/mach-omap/sleep.S new file mode 100644 index 00000000000..4d426d10582 --- /dev/null +++ b/arch/arm/mach-omap/sleep.S @@ -0,0 +1,314 @@ +/* + * linux/arch/arm/mach-omap/sleep.S + * + * Low-level OMAP1510/1610 sleep/wakeUp support + * + * Initial SA1110 code: + * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> + * + * Adapted for PXA by Nicolas Pitre: + * Copyright (c) 2002 Monta Vista Software, Inc. + * + * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/config.h> +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/arch/io.h> +#include <asm/arch/pm.h> + +		.text + +/* + * Forces OMAP into idle state + * + * omapXXXX_idle_loop_suspend() + * + * Note: This code get's copied to internal SRAM at boot. When the OMAP + *	 wakes up it continues execution at the point it went to sleep. + * + * Note: Because of slightly different configuration values we have + *       processor specific functions here. + */ + +#ifdef CONFIG_ARCH_OMAP1510 +ENTRY(omap1510_idle_loop_suspend) + +	stmfd	sp!, {r0 - r12, lr}		@ save registers on stack + +	@ load base address of ARM_IDLECT1 and ARM_IDLECT2 +	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000 +	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 +	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 + +	@ turn off clock domains +	@ get ARM_IDLECT2 into r2 +	ldrh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] +	mov	r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff + 	orr	r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 +	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] + +	@ request ARM idle +	@ get ARM_IDLECT1 into r1 +	ldrh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] +	orr	r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff +	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] + +	mov	r5, #IDLE_WAIT_CYCLES & 0xff +	orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00 +l_1510:	subs	r5, r5, #1 +	bne	l_1510 +/* + * Let's wait for the next clock tick to wake us up. + */ +	mov	r0, #0 +	mcr	p15, 0, r0, c7, c0, 4		@ wait for interrupt +/* + * omap1510_idle_loop_suspend()'s resume point. + * + * It will just start executing here, so we'll restore stuff from the + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. + */ + +	@ restore ARM_IDLECT1 and ARM_IDLECT2 and return +	@ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 +	strh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] +	strh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] + +	ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return + +ENTRY(omap1510_idle_loop_suspend_sz) +	.word	. - omap1510_idle_loop_suspend +#endif /* CONFIG_ARCH_OMAP1510 */ + +#if defined(CONFIG_ARCH_OMAP16XX) +ENTRY(omap1610_idle_loop_suspend) + +	stmfd	sp!, {r0 - r12, lr}		@ save registers on stack + +	@ load base address of ARM_IDLECT1 and ARM_IDLECT2 +	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000 +	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 +	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 + +	@ turn off clock domains +	@ get ARM_IDLECT2 into r2 +	ldrh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] +	mov	r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff + 	orr	r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00 +	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] + +	@ request ARM idle +	@ get ARM_IDLECT1 into r1 +	ldrh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] +	orr	r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff +	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] + +	mov	r5, #IDLE_WAIT_CYCLES & 0xff +	orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00 +l_1610:	subs	r5, r5, #1 +	bne	l_1610 +/* + * Let's wait for the next clock tick to wake us up. + */ +	mov	r0, #0 +	mcr	p15, 0, r0, c7, c0, 4		@ wait for interrupt +/* + * omap1610_idle_loop_suspend()'s resume point. + * + * It will just start executing here, so we'll restore stuff from the + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. + */ + +	@ restore ARM_IDLECT1 and ARM_IDLECT2 and return +	@ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 +	strh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] +	strh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] + +	ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return + +ENTRY(omap1610_idle_loop_suspend_sz) +	.word	. - omap1610_idle_loop_suspend +#endif /* CONFIG_ARCH_OMAP16XX */ + +/* + * Forces OMAP into deep sleep state + * + * omapXXXX_cpu_suspend() + * + * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed + * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1 + * in register r1. + * + * Note: This code get's copied to internal SRAM at boot. When the OMAP + *	 wakes up it continues execution at the point it went to sleep. + * + * Note: Because of errata work arounds we have processor specific functions + *       here. They are mostly the same, but slightly different. + * + */ + +#ifdef CONFIG_ARCH_OMAP1510 +ENTRY(omap1510_cpu_suspend) + +	@ save registers on stack +	stmfd	sp!, {r0 - r12, lr} + +	@ load base address of Traffic Controller +	mov	r4, #TCMIF_ASM_BASE & 0xff000000 +	orr	r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 +	orr	r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 + +	@ work around errata of OMAP1510 PDE bit for TC shut down +	@ clear PDE bit +	ldr	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] +	bic	r5, r5, #PDE_BIT & 0xff +	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] + +	@ set PWD_EN bit +	and	r5, r5, #PWD_EN_BIT & 0xff +	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] + +	@ prepare to put SDRAM into self-refresh manually +	ldr	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] +	orr	r5, r5, #SELF_REFRESH_MODE & 0xff000000 +	orr	r5, r5, #SELF_REFRESH_MODE & 0x000000ff +	str	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] + +	@ prepare to put EMIFS to Sleep +	ldr	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] +	orr	r5, r5, #IDLE_EMIFS_REQUEST & 0xff +	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] + +	@ load base address of ARM_IDLECT1 and ARM_IDLECT2 +	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000 +	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 +	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 + +	@ turn off clock domains +	mov	r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff + 	orr	r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 +	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] + +	@ request ARM idle +	mov	r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff +	orr	r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00 +	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] + +	mov	r5, #IDLE_WAIT_CYCLES & 0xff +	orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00 +l_1510_2: +	subs	r5, r5, #1 +	bne	l_1510_2 +/* + * Let's wait for the next wake up event to wake us up. r0 can't be + * used here because r0 holds ARM_IDLECT1 + */ +	mov	r2, #0 +	mcr	p15, 0, r2, c7, c0, 4		@ wait for interrupt +/* + * omap1510_cpu_suspend()'s resume point. + * + * It will just start executing here, so we'll restore stuff from the + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. + */ +	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] +	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] + +	@ restore regs and return +	ldmfd   sp!, {r0 - r12, pc} + +ENTRY(omap1510_cpu_suspend_sz) +	.word	. - omap1510_cpu_suspend +#endif /* CONFIG_ARCH_OMAP1510 */ + +#if defined(CONFIG_ARCH_OMAP16XX) +ENTRY(omap1610_cpu_suspend) + +	@ save registers on stack +	stmfd	sp!, {r0 - r12, lr} + +	@ load base address of Traffic Controller +	mov	r4, #TCMIF_ASM_BASE & 0xff000000 +	orr	r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 +	orr	r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 + +	@ prepare to put SDRAM into self-refresh manually +	ldr	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] +	orr	r5, r5, #SELF_REFRESH_MODE & 0xff000000 +	orr	r5, r5, #SELF_REFRESH_MODE & 0x000000ff +	str	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] + +	@ prepare to put EMIFS to Sleep +	ldr	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] +	orr	r5, r5, #IDLE_EMIFS_REQUEST & 0xff +	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] + +	@ load base address of ARM_IDLECT1 and ARM_IDLECT2 +	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000 +	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 +	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 + +	@ turn off clock domains +	mov	r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff + 	orr	r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00 +	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] + +	@ work around errata of OMAP1610/5912. Enable (!) peripheral +	@ clock to let the chip go into deep sleep +	ldrh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] + 	orr	r5,r5, #EN_PERCK_BIT & 0xff +	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] + +	@ request ARM idle +	mov	r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff +	orr	r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00 +	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] + +	mov	r5, #IDLE_WAIT_CYCLES & 0xff +	orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00 +l_1610_2: +	subs	r5, r5, #1 +	bne	l_1610_2 +/* + * Let's wait for the next wake up event to wake us up. r0 can't be + * used here because r0 holds ARM_IDLECT1 + */ +	mov	r2, #0 +	mcr	p15, 0, r2, c7, c0, 4		@ wait for interrupt +/* + * omap1610_cpu_suspend()'s resume point. + * + * It will just start executing here, so we'll restore stuff from the + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. + */ +	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] +	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] + +	@ restore regs and return +	ldmfd   sp!, {r0 - r12, pc} + +ENTRY(omap1610_cpu_suspend_sz) +	.word	. - omap1610_cpu_suspend +#endif /* CONFIG_ARCH_OMAP16XX */  |