]>
Commit | Line | Data |
---|---|---|
8bd22949 KH |
1 | /* |
2 | * linux/arch/arm/mach-omap2/sleep.S | |
3 | * | |
4 | * (C) Copyright 2007 | |
5 | * Texas Instruments | |
6 | * Karthik Dasu <karthik-dp@ti.com> | |
7 | * | |
8 | * (C) Copyright 2004 | |
9 | * Texas Instruments, <www.ti.com> | |
10 | * Richard Woodruff <r-woodruff2@ti.com> | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU General Public License as | |
14 | * published by the Free Software Foundation; either version 2 of | |
15 | * the License, or (at your option) any later version. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License | |
23 | * along with this program; if not, write to the Free Software | |
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
25 | * MA 02111-1307 USA | |
26 | */ | |
27 | #include <linux/linkage.h> | |
28 | #include <asm/assembler.h> | |
29 | #include <mach/io.h> | |
ce491cf8 | 30 | #include <plat/control.h> |
8bd22949 KH |
31 | |
32 | #include "prm.h" | |
33 | #include "sdrc.h" | |
34 | ||
35 | #define PM_PREPWSTST_CORE_V OMAP34XX_PRM_REGADDR(CORE_MOD, \ | |
36 | OMAP3430_PM_PREPWSTST) | |
37 | #define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \ | |
38 | OMAP3430_PM_PREPWSTST) | |
61255ab9 | 39 | #define PM_PWSTCTRL_MPU_P OMAP3430_PRM_BASE + MPU_MOD + PM_PWSTCTRL |
8bd22949 KH |
40 | #define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is |
41 | * available */ | |
61255ab9 RN |
42 | #define SCRATCHPAD_BASE_P (OMAP343X_CTRL_BASE + OMAP343X_CONTROL_MEM_WKUP\ |
43 | + SCRATCHPAD_MEM_OFFS) | |
8bd22949 KH |
44 | #define SDRC_POWER_V OMAP34XX_SDRC_REGADDR(SDRC_POWER) |
45 | ||
46 | .text | |
47 | /* Function call to get the restore pointer for resume from OFF */ | |
48 | ENTRY(get_restore_pointer) | |
49 | stmfd sp!, {lr} @ save registers on stack | |
50 | adr r0, restore | |
51 | ldmfd sp!, {pc} @ restore regs and return | |
52 | ENTRY(get_restore_pointer_sz) | |
53 | .word . - get_restore_pointer_sz | |
54 | /* | |
55 | * Forces OMAP into idle state | |
56 | * | |
57 | * omap34xx_suspend() - This bit of code just executes the WFI | |
58 | * for normal idles. | |
59 | * | |
60 | * Note: This code get's copied to internal SRAM at boot. When the OMAP | |
61 | * wakes up it continues execution at the point it went to sleep. | |
62 | */ | |
63 | ENTRY(omap34xx_cpu_suspend) | |
64 | stmfd sp!, {r0-r12, lr} @ save registers on stack | |
65 | loop: | |
66 | /*b loop*/ @Enable to debug by stepping through code | |
67 | /* r0 contains restore pointer in sdram */ | |
68 | /* r1 contains information about saving context */ | |
69 | ldr r4, sdrc_power @ read the SDRC_POWER register | |
70 | ldr r5, [r4] @ read the contents of SDRC_POWER | |
71 | orr r5, r5, #0x40 @ enable self refresh on idle req | |
72 | str r5, [r4] @ write back to SDRC_POWER register | |
73 | ||
74 | cmp r1, #0x0 | |
75 | /* If context save is required, do that and execute wfi */ | |
76 | bne save_context_wfi | |
77 | /* Data memory barrier and Data sync barrier */ | |
78 | mov r1, #0 | |
79 | mcr p15, 0, r1, c7, c10, 4 | |
80 | mcr p15, 0, r1, c7, c10, 5 | |
81 | ||
82 | wfi @ wait for interrupt | |
83 | ||
84 | nop | |
85 | nop | |
86 | nop | |
87 | nop | |
88 | nop | |
89 | nop | |
90 | nop | |
91 | nop | |
92 | nop | |
93 | nop | |
94 | bl i_dll_wait | |
95 | ||
96 | ldmfd sp!, {r0-r12, pc} @ restore regs and return | |
97 | restore: | |
61255ab9 | 98 | /* b restore*/ @ Enable to debug restore code |
8bd22949 KH |
99 | /* Check what was the reason for mpu reset and store the reason in r9*/ |
100 | /* 1 - Only L1 and logic lost */ | |
101 | /* 2 - Only L2 lost - In this case, we wont be here */ | |
102 | /* 3 - Both L1 and L2 lost */ | |
103 | ldr r1, pm_pwstctrl_mpu | |
104 | ldr r2, [r1] | |
105 | and r2, r2, #0x3 | |
106 | cmp r2, #0x0 @ Check if target power state was OFF or RET | |
107 | moveq r9, #0x3 @ MPU OFF => L1 and L2 lost | |
108 | movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation | |
109 | bne logic_l1_restore | |
110 | /* Execute smi to invalidate L2 cache */ | |
111 | mov r12, #0x1 @ set up to invalide L2 | |
112 | smi: .word 0xE1600070 @ Call SMI monitor (smieq) | |
113 | logic_l1_restore: | |
114 | mov r1, #0 | |
115 | /* Invalidate all instruction caches to PoU | |
116 | * and flush branch target cache */ | |
117 | mcr p15, 0, r1, c7, c5, 0 | |
118 | ||
119 | ldr r4, scratchpad_base | |
120 | ldr r3, [r4,#0xBC] | |
121 | ldmia r3!, {r4-r6} | |
122 | mov sp, r4 | |
123 | msr spsr_cxsf, r5 | |
124 | mov lr, r6 | |
125 | ||
126 | ldmia r3!, {r4-r9} | |
127 | /* Coprocessor access Control Register */ | |
128 | mcr p15, 0, r4, c1, c0, 2 | |
129 | ||
130 | /* TTBR0 */ | |
131 | MCR p15, 0, r5, c2, c0, 0 | |
132 | /* TTBR1 */ | |
133 | MCR p15, 0, r6, c2, c0, 1 | |
134 | /* Translation table base control register */ | |
135 | MCR p15, 0, r7, c2, c0, 2 | |
136 | /*domain access Control Register */ | |
137 | MCR p15, 0, r8, c3, c0, 0 | |
138 | /* data fault status Register */ | |
139 | MCR p15, 0, r9, c5, c0, 0 | |
140 | ||
141 | ldmia r3!,{r4-r8} | |
142 | /* instruction fault status Register */ | |
143 | MCR p15, 0, r4, c5, c0, 1 | |
144 | /*Data Auxiliary Fault Status Register */ | |
145 | MCR p15, 0, r5, c5, c1, 0 | |
146 | /*Instruction Auxiliary Fault Status Register*/ | |
147 | MCR p15, 0, r6, c5, c1, 1 | |
148 | /*Data Fault Address Register */ | |
149 | MCR p15, 0, r7, c6, c0, 0 | |
150 | /*Instruction Fault Address Register*/ | |
151 | MCR p15, 0, r8, c6, c0, 2 | |
152 | ldmia r3!,{r4-r7} | |
153 | ||
154 | /* user r/w thread and process ID */ | |
155 | MCR p15, 0, r4, c13, c0, 2 | |
156 | /* user ro thread and process ID */ | |
157 | MCR p15, 0, r5, c13, c0, 3 | |
158 | /*Privileged only thread and process ID */ | |
159 | MCR p15, 0, r6, c13, c0, 4 | |
160 | /* cache size selection */ | |
161 | MCR p15, 2, r7, c0, c0, 0 | |
162 | ldmia r3!,{r4-r8} | |
163 | /* Data TLB lockdown registers */ | |
164 | MCR p15, 0, r4, c10, c0, 0 | |
165 | /* Instruction TLB lockdown registers */ | |
166 | MCR p15, 0, r5, c10, c0, 1 | |
167 | /* Secure or Nonsecure Vector Base Address */ | |
168 | MCR p15, 0, r6, c12, c0, 0 | |
169 | /* FCSE PID */ | |
170 | MCR p15, 0, r7, c13, c0, 0 | |
171 | /* Context PID */ | |
172 | MCR p15, 0, r8, c13, c0, 1 | |
173 | ||
174 | ldmia r3!,{r4-r5} | |
175 | /* primary memory remap register */ | |
176 | MCR p15, 0, r4, c10, c2, 0 | |
177 | /*normal memory remap register */ | |
178 | MCR p15, 0, r5, c10, c2, 1 | |
179 | ||
180 | /* Restore cpsr */ | |
181 | ldmia r3!,{r4} /*load CPSR from SDRAM*/ | |
182 | msr cpsr, r4 /*store cpsr */ | |
183 | ||
184 | /* Enabling MMU here */ | |
185 | mrc p15, 0, r7, c2, c0, 2 /* Read TTBRControl */ | |
186 | /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/ | |
187 | and r7, #0x7 | |
188 | cmp r7, #0x0 | |
189 | beq usettbr0 | |
190 | ttbr_error: | |
191 | /* More work needs to be done to support N[0:2] value other than 0 | |
192 | * So looping here so that the error can be detected | |
193 | */ | |
194 | b ttbr_error | |
195 | usettbr0: | |
196 | mrc p15, 0, r2, c2, c0, 0 | |
197 | ldr r5, ttbrbit_mask | |
198 | and r2, r5 | |
199 | mov r4, pc | |
200 | ldr r5, table_index_mask | |
201 | and r4, r5 /* r4 = 31 to 20 bits of pc */ | |
202 | /* Extract the value to be written to table entry */ | |
203 | ldr r1, table_entry | |
204 | add r1, r1, r4 /* r1 has value to be written to table entry*/ | |
205 | /* Getting the address of table entry to modify */ | |
206 | lsr r4, #18 | |
207 | add r2, r4 /* r2 has the location which needs to be modified */ | |
208 | /* Storing previous entry of location being modified */ | |
209 | ldr r5, scratchpad_base | |
210 | ldr r4, [r2] | |
211 | str r4, [r5, #0xC0] | |
212 | /* Modify the table entry */ | |
213 | str r1, [r2] | |
214 | /* Storing address of entry being modified | |
215 | * - will be restored after enabling MMU */ | |
216 | ldr r5, scratchpad_base | |
217 | str r2, [r5, #0xC4] | |
218 | ||
219 | mov r0, #0 | |
220 | mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer | |
221 | mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array | |
222 | mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB | |
223 | mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB | |
224 | /* Restore control register but dont enable caches here*/ | |
225 | /* Caches will be enabled after restoring MMU table entry */ | |
226 | ldmia r3!, {r4} | |
227 | /* Store previous value of control register in scratchpad */ | |
228 | str r4, [r5, #0xC8] | |
229 | ldr r2, cache_pred_disable_mask | |
230 | and r4, r2 | |
231 | mcr p15, 0, r4, c1, c0, 0 | |
232 | ||
233 | ldmfd sp!, {r0-r12, pc} @ restore regs and return | |
234 | save_context_wfi: | |
235 | /*b save_context_wfi*/ @ enable to debug save code | |
236 | mov r8, r0 /* Store SDRAM address in r8 */ | |
237 | /* Check what that target sleep state is:stored in r1*/ | |
238 | /* 1 - Only L1 and logic lost */ | |
239 | /* 2 - Only L2 lost */ | |
240 | /* 3 - Both L1 and L2 lost */ | |
241 | cmp r1, #0x2 /* Only L2 lost */ | |
242 | beq clean_l2 | |
243 | cmp r1, #0x1 /* L2 retained */ | |
244 | /* r9 stores whether to clean L2 or not*/ | |
245 | moveq r9, #0x0 /* Dont Clean L2 */ | |
246 | movne r9, #0x1 /* Clean L2 */ | |
247 | l1_logic_lost: | |
248 | /* Store sp and spsr to SDRAM */ | |
249 | mov r4, sp | |
250 | mrs r5, spsr | |
251 | mov r6, lr | |
252 | stmia r8!, {r4-r6} | |
253 | /* Save all ARM registers */ | |
254 | /* Coprocessor access control register */ | |
255 | mrc p15, 0, r6, c1, c0, 2 | |
256 | stmia r8!, {r6} | |
257 | /* TTBR0, TTBR1 and Translation table base control */ | |
258 | mrc p15, 0, r4, c2, c0, 0 | |
259 | mrc p15, 0, r5, c2, c0, 1 | |
260 | mrc p15, 0, r6, c2, c0, 2 | |
261 | stmia r8!, {r4-r6} | |
262 | /* Domain access control register, data fault status register, | |
263 | and instruction fault status register */ | |
264 | mrc p15, 0, r4, c3, c0, 0 | |
265 | mrc p15, 0, r5, c5, c0, 0 | |
266 | mrc p15, 0, r6, c5, c0, 1 | |
267 | stmia r8!, {r4-r6} | |
268 | /* Data aux fault status register, instruction aux fault status, | |
269 | datat fault address register and instruction fault address register*/ | |
270 | mrc p15, 0, r4, c5, c1, 0 | |
271 | mrc p15, 0, r5, c5, c1, 1 | |
272 | mrc p15, 0, r6, c6, c0, 0 | |
273 | mrc p15, 0, r7, c6, c0, 2 | |
274 | stmia r8!, {r4-r7} | |
275 | /* user r/w thread and process ID, user r/o thread and process ID, | |
276 | priv only thread and process ID, cache size selection */ | |
277 | mrc p15, 0, r4, c13, c0, 2 | |
278 | mrc p15, 0, r5, c13, c0, 3 | |
279 | mrc p15, 0, r6, c13, c0, 4 | |
280 | mrc p15, 2, r7, c0, c0, 0 | |
281 | stmia r8!, {r4-r7} | |
282 | /* Data TLB lockdown, instruction TLB lockdown registers */ | |
283 | mrc p15, 0, r5, c10, c0, 0 | |
284 | mrc p15, 0, r6, c10, c0, 1 | |
285 | stmia r8!, {r5-r6} | |
286 | /* Secure or non secure vector base address, FCSE PID, Context PID*/ | |
287 | mrc p15, 0, r4, c12, c0, 0 | |
288 | mrc p15, 0, r5, c13, c0, 0 | |
289 | mrc p15, 0, r6, c13, c0, 1 | |
290 | stmia r8!, {r4-r6} | |
291 | /* Primary remap, normal remap registers */ | |
292 | mrc p15, 0, r4, c10, c2, 0 | |
293 | mrc p15, 0, r5, c10, c2, 1 | |
294 | stmia r8!,{r4-r5} | |
295 | ||
296 | /* Store current cpsr*/ | |
297 | mrs r2, cpsr | |
298 | stmia r8!, {r2} | |
299 | ||
300 | mrc p15, 0, r4, c1, c0, 0 | |
301 | /* save control register */ | |
302 | stmia r8!, {r4} | |
303 | clean_caches: | |
304 | /* Clean Data or unified cache to POU*/ | |
305 | /* How to invalidate only L1 cache???? - #FIX_ME# */ | |
306 | /* mcr p15, 0, r11, c7, c11, 1 */ | |
307 | cmp r9, #1 /* Check whether L2 inval is required or not*/ | |
308 | bne skip_l2_inval | |
309 | clean_l2: | |
310 | /* read clidr */ | |
311 | mrc p15, 1, r0, c0, c0, 1 | |
312 | /* extract loc from clidr */ | |
313 | ands r3, r0, #0x7000000 | |
314 | /* left align loc bit field */ | |
315 | mov r3, r3, lsr #23 | |
316 | /* if loc is 0, then no need to clean */ | |
317 | beq finished | |
318 | /* start clean at cache level 0 */ | |
319 | mov r10, #0 | |
320 | loop1: | |
321 | /* work out 3x current cache level */ | |
322 | add r2, r10, r10, lsr #1 | |
323 | /* extract cache type bits from clidr*/ | |
324 | mov r1, r0, lsr r2 | |
325 | /* mask of the bits for current cache only */ | |
326 | and r1, r1, #7 | |
327 | /* see what cache we have at this level */ | |
328 | cmp r1, #2 | |
329 | /* skip if no cache, or just i-cache */ | |
330 | blt skip | |
331 | /* select current cache level in cssr */ | |
332 | mcr p15, 2, r10, c0, c0, 0 | |
333 | /* isb to sych the new cssr&csidr */ | |
334 | isb | |
335 | /* read the new csidr */ | |
336 | mrc p15, 1, r1, c0, c0, 0 | |
337 | /* extract the length of the cache lines */ | |
338 | and r2, r1, #7 | |
339 | /* add 4 (line length offset) */ | |
340 | add r2, r2, #4 | |
341 | ldr r4, assoc_mask | |
342 | /* find maximum number on the way size */ | |
343 | ands r4, r4, r1, lsr #3 | |
344 | /* find bit position of way size increment */ | |
345 | clz r5, r4 | |
346 | ldr r7, numset_mask | |
347 | /* extract max number of the index size*/ | |
348 | ands r7, r7, r1, lsr #13 | |
349 | loop2: | |
350 | mov r9, r4 | |
351 | /* create working copy of max way size*/ | |
352 | loop3: | |
353 | /* factor way and cache number into r11 */ | |
354 | orr r11, r10, r9, lsl r5 | |
355 | /* factor index number into r11 */ | |
356 | orr r11, r11, r7, lsl r2 | |
357 | /*clean & invalidate by set/way */ | |
358 | mcr p15, 0, r11, c7, c10, 2 | |
359 | /* decrement the way*/ | |
360 | subs r9, r9, #1 | |
361 | bge loop3 | |
362 | /*decrement the index */ | |
363 | subs r7, r7, #1 | |
364 | bge loop2 | |
365 | skip: | |
366 | add r10, r10, #2 | |
367 | /* increment cache number */ | |
368 | cmp r3, r10 | |
369 | bgt loop1 | |
370 | finished: | |
371 | /*swith back to cache level 0 */ | |
372 | mov r10, #0 | |
373 | /* select current cache level in cssr */ | |
374 | mcr p15, 2, r10, c0, c0, 0 | |
375 | isb | |
376 | skip_l2_inval: | |
377 | /* Data memory barrier and Data sync barrier */ | |
378 | mov r1, #0 | |
379 | mcr p15, 0, r1, c7, c10, 4 | |
380 | mcr p15, 0, r1, c7, c10, 5 | |
381 | ||
382 | wfi @ wait for interrupt | |
383 | nop | |
384 | nop | |
385 | nop | |
386 | nop | |
387 | nop | |
388 | nop | |
389 | nop | |
390 | nop | |
391 | nop | |
392 | nop | |
393 | bl i_dll_wait | |
394 | /* restore regs and return */ | |
395 | ldmfd sp!, {r0-r12, pc} | |
396 | ||
397 | i_dll_wait: | |
398 | ldr r4, clk_stabilize_delay | |
399 | ||
400 | i_dll_delay: | |
401 | subs r4, r4, #0x1 | |
402 | bne i_dll_delay | |
403 | ldr r4, sdrc_power | |
404 | ldr r5, [r4] | |
405 | bic r5, r5, #0x40 | |
406 | str r5, [r4] | |
407 | bx lr | |
408 | pm_prepwstst_core: | |
409 | .word PM_PREPWSTST_CORE_V | |
410 | pm_prepwstst_mpu: | |
411 | .word PM_PREPWSTST_MPU_V | |
412 | pm_pwstctrl_mpu: | |
413 | .word PM_PWSTCTRL_MPU_P | |
414 | scratchpad_base: | |
415 | .word SCRATCHPAD_BASE_P | |
416 | sdrc_power: | |
417 | .word SDRC_POWER_V | |
8bd22949 KH |
418 | clk_stabilize_delay: |
419 | .word 0x000001FF | |
420 | assoc_mask: | |
421 | .word 0x3ff | |
422 | numset_mask: | |
423 | .word 0x7fff | |
424 | ttbrbit_mask: | |
425 | .word 0xFFFFC000 | |
426 | table_index_mask: | |
427 | .word 0xFFF00000 | |
428 | table_entry: | |
429 | .word 0x00000C02 | |
430 | cache_pred_disable_mask: | |
431 | .word 0xFFFFE7FB | |
432 | ENTRY(omap34xx_cpu_suspend_sz) | |
433 | .word . - omap34xx_cpu_suspend |