Commit | Line | Data |
---|---|---|
efc1bb8a SN |
1 | /* |
2 | * (C) Copyright 2009, Texas Instruments, Inc. http://www.ti.com/ | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * version 2 as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program; if not, write to the Free Software | |
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
16 | * MA 02111-1307 USA | |
17 | */ | |
18 | ||
19 | /* replicated define because linux/bitops.h cannot be included in assembly */ | |
20 | #define BIT(nr) (1 << (nr)) | |
21 | ||
22 | #include <linux/linkage.h> | |
23 | #include <asm/assembler.h> | |
24 | #include <mach/psc.h> | |
0020afb3 | 25 | #include <mach/ddr2.h> |
efc1bb8a SN |
26 | |
27 | #include "clock.h" | |
28 | ||
29 | /* Arbitrary, hardware currently does not update PHYRDY correctly */ | |
30 | #define PHYRDY_CYCLES 0x1000 | |
31 | ||
32 | /* Assume 25 MHz speed for the cycle conversions since PLLs are bypassed */ | |
33 | #define PLL_BYPASS_CYCLES (PLL_BYPASS_TIME * 25) | |
34 | #define PLL_RESET_CYCLES (PLL_RESET_TIME * 25) | |
35 | #define PLL_LOCK_CYCLES (PLL_LOCK_TIME * 25) | |
36 | ||
37 | #define DEEPSLEEP_SLEEPENABLE_BIT BIT(31) | |
38 | ||
39 | .text | |
40 | /* | |
41 | * Move DaVinci into deep sleep state | |
42 | * | |
43 | * Note: This code is copied to internal SRAM by PM code. When the DaVinci | |
44 | * wakes up it continues execution at the point it went to sleep. | |
45 | * Register Usage: | |
46 | * r0: contains virtual base for DDR2 controller | |
47 | * r1: contains virtual base for DDR2 Power and Sleep controller (PSC) | |
48 | * r2: contains PSC number for DDR2 | |
49 | * r3: contains virtual base DDR2 PLL controller | |
50 | * r4: contains virtual address of the DEEPSLEEP register | |
51 | */ | |
52 | ENTRY(davinci_cpu_suspend) | |
53 | stmfd sp!, {r0-r12, lr} @ save registers on stack | |
54 | ||
55 | ldr ip, CACHE_FLUSH | |
56 | blx ip | |
57 | ||
58 | ldmia r0, {r0-r4} | |
59 | ||
60 | /* | |
61 | * Switch DDR to self-refresh mode. | |
62 | */ | |
63 | ||
64 | /* calculate SDRCR address */ | |
65 | ldr ip, [r0, #DDR2_SDRCR_OFFSET] | |
66 | bic ip, ip, #DDR2_SRPD_BIT | |
67 | orr ip, ip, #DDR2_LPMODEN_BIT | |
68 | str ip, [r0, #DDR2_SDRCR_OFFSET] | |
69 | ||
70 | ldr ip, [r0, #DDR2_SDRCR_OFFSET] | |
71 | orr ip, ip, #DDR2_MCLKSTOPEN_BIT | |
72 | str ip, [r0, #DDR2_SDRCR_OFFSET] | |
73 | ||
74 | mov ip, #PHYRDY_CYCLES | |
75 | 1: subs ip, ip, #0x1 | |
76 | bne 1b | |
77 | ||
78 | /* Disable DDR2 LPSC */ | |
79 | mov r7, r0 | |
80 | mov r0, #0x2 | |
81 | bl davinci_ddr_psc_config | |
82 | mov r0, r7 | |
83 | ||
84 | /* Disable clock to DDR PHY */ | |
85 | ldr ip, [r3, #PLLDIV1] | |
86 | bic ip, ip, #PLLDIV_EN | |
87 | str ip, [r3, #PLLDIV1] | |
88 | ||
89 | /* Put the DDR PLL in bypass and power down */ | |
90 | ldr ip, [r3, #PLLCTL] | |
91 | bic ip, ip, #PLLCTL_PLLENSRC | |
92 | bic ip, ip, #PLLCTL_PLLEN | |
93 | str ip, [r3, #PLLCTL] | |
94 | ||
95 | /* Wait for PLL to switch to bypass */ | |
96 | mov ip, #PLL_BYPASS_CYCLES | |
97 | 2: subs ip, ip, #0x1 | |
98 | bne 2b | |
99 | ||
100 | /* Power down the PLL */ | |
101 | ldr ip, [r3, #PLLCTL] | |
102 | orr ip, ip, #PLLCTL_PLLPWRDN | |
103 | str ip, [r3, #PLLCTL] | |
104 | ||
105 | /* Go to deep sleep */ | |
106 | ldr ip, [r4] | |
107 | orr ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT | |
108 | /* System goes to sleep beyond after this instruction */ | |
109 | str ip, [r4] | |
110 | ||
111 | /* Wake up from sleep */ | |
112 | ||
113 | /* Clear sleep enable */ | |
114 | ldr ip, [r4] | |
115 | bic ip, ip, #DEEPSLEEP_SLEEPENABLE_BIT | |
116 | str ip, [r4] | |
117 | ||
118 | /* initialize the DDR PLL controller */ | |
119 | ||
120 | /* Put PLL in reset */ | |
121 | ldr ip, [r3, #PLLCTL] | |
122 | bic ip, ip, #PLLCTL_PLLRST | |
123 | str ip, [r3, #PLLCTL] | |
124 | ||
125 | /* Clear PLL power down */ | |
126 | ldr ip, [r3, #PLLCTL] | |
127 | bic ip, ip, #PLLCTL_PLLPWRDN | |
128 | str ip, [r3, #PLLCTL] | |
129 | ||
130 | mov ip, #PLL_RESET_CYCLES | |
131 | 3: subs ip, ip, #0x1 | |
132 | bne 3b | |
133 | ||
134 | /* Bring PLL out of reset */ | |
135 | ldr ip, [r3, #PLLCTL] | |
136 | orr ip, ip, #PLLCTL_PLLRST | |
137 | str ip, [r3, #PLLCTL] | |
138 | ||
139 | /* Wait for PLL to lock (assume prediv = 1, 25MHz OSCIN) */ | |
140 | mov ip, #PLL_LOCK_CYCLES | |
141 | 4: subs ip, ip, #0x1 | |
142 | bne 4b | |
143 | ||
144 | /* Remove PLL from bypass mode */ | |
145 | ldr ip, [r3, #PLLCTL] | |
146 | bic ip, ip, #PLLCTL_PLLENSRC | |
147 | orr ip, ip, #PLLCTL_PLLEN | |
148 | str ip, [r3, #PLLCTL] | |
149 | ||
150 | /* Start 2x clock to DDR2 */ | |
151 | ||
152 | ldr ip, [r3, #PLLDIV1] | |
153 | orr ip, ip, #PLLDIV_EN | |
154 | str ip, [r3, #PLLDIV1] | |
155 | ||
156 | /* Enable VCLK */ | |
157 | ||
158 | /* Enable DDR2 LPSC */ | |
159 | mov r7, r0 | |
160 | mov r0, #0x3 | |
161 | bl davinci_ddr_psc_config | |
162 | mov r0, r7 | |
163 | ||
164 | /* clear MCLKSTOPEN */ | |
165 | ||
166 | ldr ip, [r0, #DDR2_SDRCR_OFFSET] | |
167 | bic ip, ip, #DDR2_MCLKSTOPEN_BIT | |
168 | str ip, [r0, #DDR2_SDRCR_OFFSET] | |
169 | ||
170 | ldr ip, [r0, #DDR2_SDRCR_OFFSET] | |
171 | bic ip, ip, #DDR2_LPMODEN_BIT | |
172 | str ip, [r0, #DDR2_SDRCR_OFFSET] | |
173 | ||
174 | /* Restore registers and return */ | |
175 | ldmfd sp!, {r0-r12, pc} | |
176 | ||
177 | ENDPROC(davinci_cpu_suspend) | |
178 | ||
179 | /* | |
180 | * Disables or Enables DDR2 LPSC | |
181 | * Register Usage: | |
182 | * r0: Enable or Disable LPSC r0 = 0x3 => Enable, r0 = 0x2 => Disable LPSC | |
183 | * r1: contains virtual base for DDR2 Power and Sleep controller (PSC) | |
184 | * r2: contains PSC number for DDR2 | |
185 | */ | |
186 | ENTRY(davinci_ddr_psc_config) | |
187 | /* Set next state in mdctl for DDR2 */ | |
188 | mov r6, #MDCTL | |
189 | add r6, r6, r2, lsl #2 | |
190 | ldr ip, [r1, r6] | |
191 | bic ip, ip, #MDSTAT_STATE_MASK | |
192 | orr ip, ip, r0 | |
193 | str ip, [r1, r6] | |
194 | ||
195 | /* Enable the Power Domain Transition Command */ | |
196 | ldr ip, [r1, #PTCMD] | |
197 | orr ip, ip, #0x1 | |
198 | str ip, [r1, #PTCMD] | |
199 | ||
200 | /* Check for Transition Complete (PTSTAT) */ | |
201 | ptstat_done: | |
202 | ldr ip, [r1, #PTSTAT] | |
203 | and ip, ip, #0x1 | |
204 | cmp ip, #0x0 | |
205 | bne ptstat_done | |
206 | ||
207 | /* Check for DDR2 clock disable completion; */ | |
208 | mov r6, #MDSTAT | |
209 | add r6, r6, r2, lsl #2 | |
210 | ddr2clk_stop_done: | |
211 | ldr ip, [r1, r6] | |
212 | and ip, ip, #MDSTAT_STATE_MASK | |
213 | cmp ip, r0 | |
214 | bne ddr2clk_stop_done | |
215 | ||
6ebbf2ce | 216 | ret lr |
efc1bb8a SN |
217 | ENDPROC(davinci_ddr_psc_config) |
218 | ||
219 | CACHE_FLUSH: | |
897a6a1a LW |
220 | #ifdef CONFIG_CPU_V6 |
221 | .word v6_flush_kern_cache_all | |
222 | #else | |
223 | .word arm926_flush_kern_cache_all | |
224 | #endif | |
efc1bb8a SN |
225 | |
226 | ENTRY(davinci_cpu_suspend_sz) | |
227 | .word . - davinci_cpu_suspend | |
228 | ENDPROC(davinci_cpu_suspend_sz) |