/*1* linux/arch/arm/mach-omap1/sleep.S2*3* Low-level OMAP7XX/1510/1610 sleep/wakeUp support4*5* Initial SA1110 code:6* Copyright (c) 2001 Cliff Brake <[email protected]>7*8* Adapted for PXA by Nicolas Pitre:9* Copyright (c) 2002 Monta Vista Software, Inc.10*11* Support for OMAP1510/1610 by Dirk Behme <[email protected]>12*13* This program is free software; you can redistribute it and/or modify it14* under the terms of the GNU General Public License as published by the15* Free Software Foundation; either version 2 of the License, or (at your16* option) any later version.17*18* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED19* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF20* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN21* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,22* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT23* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF24* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON25* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT26* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF27* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.28*29* You should have received a copy of the GNU General Public License along30* with this program; if not, write to the Free Software Foundation, Inc.,31* 675 Mass Ave, Cambridge, MA 02139, USA.32*/3334#include <linux/linkage.h>3536#include <asm/assembler.h>3738#include "hardware.h"3940#include "iomap.h"41#include "pm.h"4243.text444546/*47* Forces OMAP into deep sleep state48*49* omapXXXX_cpu_suspend()50*51* The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed52* as arg0 and arg1 from caller. arg0 is stored in register r0 and arg153* in register r1.54*55* Note: This code get's copied to internal SRAM at boot. When the OMAP56* wakes up it continues execution at the point it went to sleep.57*58* Note: Because of errata work arounds we have processor specific functions59* here. They are mostly the same, but slightly different.60*61*/6263#ifdef CONFIG_ARCH_OMAP15XX64.align 365ENTRY(omap1510_cpu_suspend)6667@ save registers on stack68stmfd sp!, {r0 - r12, lr}6970@ load base address of Traffic Controller71mov r4, #TCMIF_ASM_BASE & 0xff00000072orr r4, r4, #TCMIF_ASM_BASE & 0x00ff000073orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff007475@ work around errata of OMAP1510 PDE bit for TC shut down76@ clear PDE bit77ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]78bic r5, r5, #PDE_BIT & 0xff79str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]8081@ set PWD_EN bit82and r5, r5, #PWD_EN_BIT & 0xff83str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]8485@ prepare to put SDRAM into self-refresh manually86ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]87orr r5, r5, #SELF_REFRESH_MODE & 0xff00000088orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff89str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]9091@ prepare to put EMIFS to Sleep92ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]93orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff94str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]9596@ load base address of ARM_IDLECT1 and ARM_IDLECT297mov r4, #CLKGEN_REG_ASM_BASE & 0xff00000098orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff000099orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00100101@ turn off clock domains102mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff103orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00104strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]105106@ request ARM idle107mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff108orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00109strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]110111mov r5, #IDLE_WAIT_CYCLES & 0xff112orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00113l_1510_2:114subs r5, r5, #1115bne l_1510_2116/*117* Let's wait for the next wake up event to wake us up. r0 can't be118* used here because r0 holds ARM_IDLECT1119*/120mov r2, #0121mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt122/*123* omap1510_cpu_suspend()'s resume point.124*125* It will just start executing here, so we'll restore stuff from the126* stack, reset the ARM_IDLECT1 and ARM_IDLECT2.127*/128strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]129strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]130131@ restore regs and return132ldmfd sp!, {r0 - r12, pc}133134ENTRY(omap1510_cpu_suspend_sz)135.word . - omap1510_cpu_suspend136#endif /* CONFIG_ARCH_OMAP15XX */137138#if defined(CONFIG_ARCH_OMAP16XX)139.align 3140ENTRY(omap1610_cpu_suspend)141142@ save registers on stack143stmfd sp!, {r0 - r12, lr}144145@ Drain write cache146mov r4, #0147mcr p15, 0, r0, c7, c10, 4148nop149150@ Load base address of Traffic Controller151mov r6, #TCMIF_ASM_BASE & 0xff000000152orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000153orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00154155@ Prepare to put SDRAM into self-refresh manually156ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]157orr r9, r7, #SELF_REFRESH_MODE & 0xff000000158orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff159str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]160161@ Prepare to put EMIFS to Sleep162ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]163orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff164str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]165166@ Load base address of ARM_IDLECT1 and ARM_IDLECT2167mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000168orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000169orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00170171@ Turn off clock domains172@ Do not disable PERCK (0x04)173mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff174orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00175strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]176177@ Request ARM idle178mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff179orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00180strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]181182/*183* Let's wait for the next wake up event to wake us up. r0 can't be184* used here because r0 holds ARM_IDLECT1185*/186mov r2, #0187mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt188189@ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions190@ according to this formula:191@ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV192@ Max DPLL_MULT = 18193@ DPLL_DIV = 1194@ ARMDIV = 1195@ => 74 nop-instructions196nop197nop198nop199nop200nop201nop202nop203nop204nop205nop @10206nop207nop208nop209nop210nop211nop212nop213nop214nop215nop @20216nop217nop218nop219nop220nop221nop222nop223nop224nop225nop @30226nop227nop228nop229nop230nop231nop232nop233nop234nop235nop @40236nop237nop238nop239nop240nop241nop242nop243nop244nop245nop @50246nop247nop248nop249nop250nop251nop252nop253nop254nop255nop @60256nop257nop258nop259nop260nop261nop262nop263nop264nop265nop @70266nop267nop268nop269nop @74270/*271* omap1610_cpu_suspend()'s resume point.272*273* It will just start executing here, so we'll restore stuff from the274* stack.275*/276@ Restore the ARM_IDLECT1 and ARM_IDLECT2.277strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]278strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]279280@ Restore EMIFF controls281str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]282str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]283284@ Restore regs and return285ldmfd sp!, {r0 - r12, pc}286287ENTRY(omap1610_cpu_suspend_sz)288.word . - omap1610_cpu_suspend289#endif /* CONFIG_ARCH_OMAP16XX */290291292