Merge branch 'semaphore' of git://git.kernel.org/pub/scm/linux/kernel/git/willy/misc
[linux-2.6] / arch / arm / mach-omap2 / sleep.S
1 /*
2  * linux/arch/arm/mach-omap2/sleep.S
3  *
4  * (C) Copyright 2004
5  * Texas Instruments, <www.ti.com>
6  * Richard Woodruff <r-woodruff2@ti.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <linux/linkage.h>
25 #include <asm/assembler.h>
26 #include <asm/arch/io.h>
27 #include <asm/arch/pm.h>
28
29 #include "sdrc.h"
30
31 /* First address of reserved address space?  apparently valid for OMAP2 & 3 */
32 #define A_SDRC0_V               (0xC0000000)
33
34         .text
35
36 /*
37  * Forces OMAP into idle state
38  *
39  * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI
40  * for normal idles.
41  *
42  * Note: This code get's copied to internal SRAM at boot. When the OMAP
43  *       wakes up it continues execution at the point it went to sleep.
44  */
45 ENTRY(omap24xx_idle_loop_suspend)
46         stmfd   sp!, {r0, lr}           @ save registers on stack
47         mov     r0, #0                  @ clear for mcr setup
48         mcr     p15, 0, r0, c7, c0, 4   @ wait for interrupt
49         ldmfd   sp!, {r0, pc}           @ restore regs and return
50
51 ENTRY(omap24xx_idle_loop_suspend_sz)
52         .word   . - omap24xx_idle_loop_suspend
53
54 /*
55  * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing
56  * SDRC shutdown then ARM shutdown.  Upon wake MPU is back on so just restore
57  * SDRC.
58  *
59  * Input:
60  * R0 : DLL ctrl value pre-Sleep
61  * R1 : Processor+Revision
62  *      2420: 0x21 = 242xES1, 0x26 = 242xES2.2
63  *      2430: 0x31 = 2430ES1, 0x32 = 2430ES2
64  *
65  * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on
66  * when we get called, but the DLL probably isn't.  We will wait a bit more in
67  * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even
68  * if in unlocked mode.
69  *
70  * For less than 242x-ES2.2 upon wake from a sleep mode where the external
71  * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz
72  * clock can pass into the PRCM can cause problems at DSP and IVA.
73  * To work around this the code will switch to the 32kHz source prior to sleep.
74  * Post sleep we will shift back to using the DPLL.  Apparently,
75  * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait
76  * 3x12MHz + 3x32kHz clocks for a full switch.
77  *
78  * The DLL load value is not kept in RETENTION or OFF.  It needs to be restored
79  * at wake
80  */
81 ENTRY(omap24xx_cpu_suspend)
82         stmfd   sp!, {r0 - r12, lr}     @ save registers on stack
83         mov     r3, #0x0                @ clear for mrc call
84         mcr     p15, 0, r3, c7, c10, 4  @ memory barrier, hope SDR/DDR finished
85         nop
86         nop
87         ldr     r3, A_SDRC_POWER        @ addr of sdrc power
88         ldr     r4, [r3]                @ value of sdrc power
89         orr     r4, r4, #0x40           @ enable self refresh on idle req
90         mov     r5, #0x2000             @ set delay (DPLL relock + DLL relock)
91         str     r4, [r3]                @ make it so
92         mov     r2, #0
93         nop
94         mcr     p15, 0, r2, c7, c0, 4   @ wait for interrupt
95         nop
96 loop:
97         subs    r5, r5, #0x1            @ awake, wait just a bit
98         bne     loop
99
100         /* The DPLL has on before we take the DDR out of self refresh */
101         bic     r4, r4, #0x40           @ now clear self refresh bit.
102         str     r4, [r3]                @ put vlaue back.
103         ldr     r4, A_SDRC0             @ make a clock happen
104         ldr     r4, [r4]
105         nop                             @ start auto refresh only after clk ok
106         movs    r0, r0                  @ see if DDR or SDR
107         ldrne   r1, A_SDRC_DLLA_CTRL_S  @ get addr of DLL ctrl
108         strne   r0, [r1]                @ rewrite DLLA to force DLL reload
109         addne   r1, r1, #0x8            @ move to DLLB
110         strne   r0, [r1]                @ rewrite DLLB to force DLL reload
111
112         mov     r5, #0x1000
113 loop2:
114         subs    r5, r5, #0x1
115         bne     loop2
116         /* resume*/
117         ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
118
119 A_SDRC_POWER:
120         .word OMAP242X_SDRC_REGADDR(SDRC_POWER)
121 A_SDRC0:
122         .word A_SDRC0_V
123 A_SDRC_DLLA_CTRL_S:
124         .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
125
126 ENTRY(omap24xx_cpu_suspend_sz)
127         .word   . - omap24xx_cpu_suspend
128