Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/arch/arm/mach-omap1/sleep.S
0003  *
0004  * Low-level OMAP7XX/1510/1610 sleep/wakeUp support
0005  *
0006  * Initial SA1110 code:
0007  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
0008  *
0009  * Adapted for PXA by Nicolas Pitre:
0010  * Copyright (c) 2002 Monta Vista Software, Inc.
0011  *
0012  * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
0013  *
0014  * This program is free software; you can redistribute it and/or modify it
0015  * under the terms of the GNU General Public License as published by the
0016  * Free Software Foundation; either version 2 of the License, or (at your
0017  * option) any later version.
0018  *
0019  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
0020  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
0021  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
0022  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0024  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0025  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
0026  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0028  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029  *
0030  * You should have received a copy of the GNU General Public License along
0031  * with this program; if not, write to the Free Software Foundation, Inc.,
0032  * 675 Mass Ave, Cambridge, MA 02139, USA.
0033  */
0034 
0035 #include <linux/linkage.h>
0036 
0037 #include <asm/assembler.h>
0038 
0039 #include "hardware.h"
0040 
0041 #include "iomap.h"
0042 #include "pm.h"
0043 
0044         .text
0045 
0046 
0047 /*
0048  * Forces OMAP into deep sleep state
0049  *
0050  * omapXXXX_cpu_suspend()
0051  *
0052  * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
0053  * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
0054  * in register r1.
0055  *
0056  * Note: This code get's copied to internal SRAM at boot. When the OMAP
0057  *   wakes up it continues execution at the point it went to sleep.
0058  *
0059  * Note: Because of errata work arounds we have processor specific functions
0060  *       here. They are mostly the same, but slightly different.
0061  *
0062  */
0063 
0064 #if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
0065     .align  3
0066 ENTRY(omap7xx_cpu_suspend)
0067 
0068     @ save registers on stack
0069     stmfd   sp!, {r0 - r12, lr}
0070 
0071     @ Drain write cache
0072     mov r4, #0
0073     mcr p15, 0, r0, c7, c10, 4
0074     nop
0075 
0076     @ load base address of Traffic Controller
0077     mov r6, #TCMIF_ASM_BASE & 0xff000000
0078     orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
0079     orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
0080 
0081     @ prepare to put SDRAM into self-refresh manually
0082     ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
0083     orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
0084     orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
0085     str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
0086 
0087     @ prepare to put EMIFS to Sleep
0088     ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0089     orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
0090     str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0091 
0092     @ load base address of ARM_IDLECT1 and ARM_IDLECT2
0093     mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
0094     orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
0095     orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
0096 
0097     @ turn off clock domains
0098     @ do not disable PERCK (0x04)
0099     mov r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff
0100     orr r5, r5, #OMAP7XX_IDLECT2_SLEEP_VAL & 0xff00
0101     strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
0102 
0103     @ request ARM idle
0104     mov r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff
0105     orr r3, r3, #OMAP7XX_IDLECT1_SLEEP_VAL & 0xff00
0106     strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
0107 
0108     @ disable instruction cache
0109     mrc p15, 0, r9, c1, c0, 0
0110     bic r2, r9, #0x1000
0111     mcr p15, 0, r2, c1, c0, 0
0112     nop
0113 
0114 /*
0115  * Let's wait for the next wake up event to wake us up. r0 can't be
0116  * used here because r0 holds ARM_IDLECT1
0117  */
0118     mov r2, #0
0119     mcr p15, 0, r2, c7, c0, 4       @ wait for interrupt
0120 /*
0121  * omap7xx_cpu_suspend()'s resume point.
0122  *
0123  * It will just start executing here, so we'll restore stuff from the
0124  * stack.
0125  */
0126     @ re-enable Icache
0127     mcr p15, 0, r9, c1, c0, 0
0128 
0129     @ reset the ARM_IDLECT1 and ARM_IDLECT2.
0130     strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
0131     strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
0132 
0133     @ Restore EMIFF controls
0134     str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
0135     str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0136 
0137     @ restore regs and return
0138     ldmfd   sp!, {r0 - r12, pc}
0139 
0140 ENTRY(omap7xx_cpu_suspend_sz)
0141     .word   . - omap7xx_cpu_suspend
0142 #endif /* CONFIG_ARCH_OMAP730 || CONFIG_ARCH_OMAP850 */
0143 
0144 #ifdef CONFIG_ARCH_OMAP15XX
0145     .align  3
0146 ENTRY(omap1510_cpu_suspend)
0147 
0148     @ save registers on stack
0149     stmfd   sp!, {r0 - r12, lr}
0150 
0151     @ load base address of Traffic Controller
0152     mov r4, #TCMIF_ASM_BASE & 0xff000000
0153     orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
0154     orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
0155 
0156     @ work around errata of OMAP1510 PDE bit for TC shut down
0157     @ clear PDE bit
0158     ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0159     bic r5, r5, #PDE_BIT & 0xff
0160     str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0161 
0162     @ set PWD_EN bit
0163     and r5, r5, #PWD_EN_BIT & 0xff
0164     str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0165 
0166     @ prepare to put SDRAM into self-refresh manually
0167     ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
0168     orr r5, r5, #SELF_REFRESH_MODE & 0xff000000
0169     orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff
0170     str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
0171 
0172     @ prepare to put EMIFS to Sleep
0173     ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0174     orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff
0175     str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0176 
0177     @ load base address of ARM_IDLECT1 and ARM_IDLECT2
0178     mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
0179     orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
0180     orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
0181 
0182     @ turn off clock domains
0183     mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
0184     orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
0185     strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
0186 
0187     @ request ARM idle
0188     mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
0189     orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
0190     strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
0191 
0192     mov r5, #IDLE_WAIT_CYCLES & 0xff
0193     orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
0194 l_1510_2:
0195     subs    r5, r5, #1
0196     bne l_1510_2
0197 /*
0198  * Let's wait for the next wake up event to wake us up. r0 can't be
0199  * used here because r0 holds ARM_IDLECT1
0200  */
0201     mov r2, #0
0202     mcr p15, 0, r2, c7, c0, 4       @ wait for interrupt
0203 /*
0204  * omap1510_cpu_suspend()'s resume point.
0205  *
0206  * It will just start executing here, so we'll restore stuff from the
0207  * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
0208  */
0209     strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
0210     strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
0211 
0212     @ restore regs and return
0213     ldmfd   sp!, {r0 - r12, pc}
0214 
0215 ENTRY(omap1510_cpu_suspend_sz)
0216     .word   . - omap1510_cpu_suspend
0217 #endif /* CONFIG_ARCH_OMAP15XX */
0218 
0219 #if defined(CONFIG_ARCH_OMAP16XX)
0220     .align  3
0221 ENTRY(omap1610_cpu_suspend)
0222 
0223     @ save registers on stack
0224     stmfd   sp!, {r0 - r12, lr}
0225 
0226     @ Drain write cache
0227     mov r4, #0
0228     mcr p15, 0, r0, c7, c10, 4
0229     nop
0230 
0231     @ Load base address of Traffic Controller
0232     mov r6, #TCMIF_ASM_BASE & 0xff000000
0233     orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
0234     orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
0235 
0236     @ Prepare to put SDRAM into self-refresh manually
0237     ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
0238     orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
0239     orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
0240     str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
0241 
0242     @ Prepare to put EMIFS to Sleep
0243     ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0244     orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
0245     str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0246 
0247     @ Load base address of ARM_IDLECT1 and ARM_IDLECT2
0248     mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
0249     orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
0250     orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
0251 
0252     @ Turn off clock domains
0253     @ Do not disable PERCK (0x04)
0254     mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
0255     orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
0256     strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
0257 
0258     @ Request ARM idle
0259     mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
0260     orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
0261     strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
0262 
0263 /*
0264  * Let's wait for the next wake up event to wake us up. r0 can't be
0265  * used here because r0 holds ARM_IDLECT1
0266  */
0267     mov r2, #0
0268     mcr p15, 0, r2, c7, c0, 4       @ wait for interrupt
0269 
0270     @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions
0271     @ according to this formula:
0272     @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV
0273     @ Max DPLL_MULT = 18
0274     @ DPLL_DIV = 1
0275     @ ARMDIV = 1
0276     @ => 74 nop-instructions
0277     nop
0278     nop
0279     nop
0280     nop
0281     nop
0282     nop
0283     nop
0284     nop
0285     nop
0286     nop @10
0287     nop
0288     nop
0289     nop
0290     nop
0291     nop
0292     nop
0293     nop
0294     nop
0295     nop
0296     nop @20
0297     nop
0298     nop
0299     nop
0300     nop
0301     nop
0302     nop
0303     nop
0304     nop
0305     nop
0306     nop @30
0307     nop
0308     nop
0309     nop
0310     nop
0311     nop
0312     nop
0313     nop
0314     nop
0315     nop
0316     nop @40
0317     nop
0318     nop
0319     nop
0320     nop
0321     nop
0322     nop
0323     nop
0324     nop
0325     nop
0326     nop @50
0327     nop
0328     nop
0329     nop
0330     nop
0331     nop
0332     nop
0333     nop
0334     nop
0335     nop
0336     nop @60
0337     nop
0338     nop
0339     nop
0340     nop
0341     nop
0342     nop
0343     nop
0344     nop
0345     nop
0346     nop @70
0347     nop
0348     nop
0349     nop
0350     nop @74
0351 /*
0352  * omap1610_cpu_suspend()'s resume point.
0353  *
0354  * It will just start executing here, so we'll restore stuff from the
0355  * stack.
0356  */
0357     @ Restore the ARM_IDLECT1 and ARM_IDLECT2.
0358     strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
0359     strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
0360 
0361     @ Restore EMIFF controls
0362     str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
0363     str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
0364 
0365     @ Restore regs and return
0366     ldmfd   sp!, {r0 - r12, pc}
0367 
0368 ENTRY(omap1610_cpu_suspend_sz)
0369     .word   . - omap1610_cpu_suspend
0370 #endif /* CONFIG_ARCH_OMAP16XX */