Commit | Line | Data |
---|---|---|
97991657 MD |
1 | /* |
2 | * sh7372 lowlevel sleep code for "Core Standby Mode" | |
3 | * | |
4 | * Copyright (C) 2011 Magnus Damm | |
5 | * | |
6 | * In "Core Standby Mode" the ARM core is off, but L2 cache is still on | |
7 | * | |
8 | * Based on mach-omap2/sleep34xx.S | |
9 | * | |
10 | * (C) Copyright 2007 Texas Instruments | |
11 | * Karthik Dasu <karthik-dp@ti.com> | |
12 | * | |
13 | * (C) Copyright 2004 Texas Instruments, <www.ti.com> | |
14 | * Richard Woodruff <r-woodruff2@ti.com> | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or | |
17 | * modify it under the terms of the GNU General Public License as | |
18 | * published by the Free Software Foundation; either version 2 of | |
19 | * the License, or (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
29 | * MA 02111-1307 USA | |
30 | */ | |
31 | ||
32 | #include <linux/linkage.h> | |
33 | #include <asm/assembler.h> | |
34 | ||
35 | #define SMFRAM 0xe6a70000 | |
36 | ||
37 | .align | |
38 | kernel_flush: | |
39 | .word v7_flush_dcache_all | |
40 | ||
41 | .align 3 | |
42 | ENTRY(sh7372_cpu_suspend) | |
43 | stmfd sp!, {r0-r12, lr} @ save registers on stack | |
44 | ||
45 | ldr r8, =SMFRAM | |
46 | ||
47 | mov r4, sp @ Store sp | |
48 | mrs r5, spsr @ Store spsr | |
49 | mov r6, lr @ Store lr | |
50 | stmia r8!, {r4-r6} | |
51 | ||
52 | mrc p15, 0, r4, c1, c0, 2 @ Coprocessor access control register | |
53 | mrc p15, 0, r5, c2, c0, 0 @ TTBR0 | |
54 | mrc p15, 0, r6, c2, c0, 1 @ TTBR1 | |
55 | mrc p15, 0, r7, c2, c0, 2 @ TTBCR | |
56 | stmia r8!, {r4-r7} | |
57 | ||
58 | mrc p15, 0, r4, c3, c0, 0 @ Domain access Control Register | |
59 | mrc p15, 0, r5, c10, c2, 0 @ PRRR | |
60 | mrc p15, 0, r6, c10, c2, 1 @ NMRR | |
61 | stmia r8!,{r4-r6} | |
62 | ||
63 | mrc p15, 0, r4, c13, c0, 1 @ Context ID | |
64 | mrc p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID | |
65 | mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address | |
66 | mrs r7, cpsr @ Store current cpsr | |
67 | stmia r8!, {r4-r7} | |
68 | ||
69 | mrc p15, 0, r4, c1, c0, 0 @ save control register | |
70 | stmia r8!, {r4} | |
71 | ||
72 | /* | |
73 | * jump out to kernel flush routine | |
74 | * - reuse that code is better | |
75 | * - it executes in a cached space so is faster than refetch per-block | |
76 | * - should be faster and will change with kernel | |
77 | * - 'might' have to copy address, load and jump to it | |
78 | * Flush all data from the L1 data cache before disabling | |
79 | * SCTLR.C bit. | |
80 | */ | |
81 | ldr r1, kernel_flush | |
82 | mov lr, pc | |
83 | bx r1 | |
84 | ||
85 | /* | |
86 | * Clear the SCTLR.C bit to prevent further data cache | |
87 | * allocation. Clearing SCTLR.C would make all the data accesses | |
88 | * strongly ordered and would not hit the cache. | |
89 | */ | |
90 | mrc p15, 0, r0, c1, c0, 0 | |
91 | bic r0, r0, #(1 << 2) @ Disable the C bit | |
92 | mcr p15, 0, r0, c1, c0, 0 | |
93 | isb | |
94 | ||
95 | /* | |
96 | * Invalidate L1 data cache. Even though only invalidate is | |
97 | * necessary exported flush API is used here. Doing clean | |
98 | * on already clean cache would be almost NOP. | |
99 | */ | |
100 | ldr r1, kernel_flush | |
101 | blx r1 | |
102 | /* | |
103 | * The kernel doesn't interwork: v7_flush_dcache_all in particluar will | |
104 | * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled. | |
105 | * This sequence switches back to ARM. Note that .align may insert a | |
106 | * nop: bx pc needs to be word-aligned in order to work. | |
107 | */ | |
108 | THUMB( .thumb ) | |
109 | THUMB( .align ) | |
110 | THUMB( bx pc ) | |
111 | THUMB( nop ) | |
112 | .arm | |
113 | ||
114 | /* Data memory barrier and Data sync barrier */ | |
115 | dsb | |
116 | dmb | |
117 | ||
118 | /* | |
119 | * =================================== | |
120 | * == WFI instruction => Enter idle == | |
121 | * =================================== | |
122 | */ | |
123 | wfi @ wait for interrupt | |
124 | ||
125 | /* | |
126 | * =================================== | |
127 | * == Resume path for non-OFF modes == | |
128 | * =================================== | |
129 | */ | |
130 | mrc p15, 0, r0, c1, c0, 0 | |
131 | tst r0, #(1 << 2) @ Check C bit enabled? | |
132 | orreq r0, r0, #(1 << 2) @ Enable the C bit if cleared | |
133 | mcreq p15, 0, r0, c1, c0, 0 | |
134 | isb | |
135 | ||
136 | /* | |
137 | * =================================== | |
138 | * == Exit point from non-OFF modes == | |
139 | * =================================== | |
140 | */ | |
141 | ldmfd sp!, {r0-r12, pc} @ restore regs and return | |
142 | ||
143 | .pool | |
144 | ||
145 | .align 12 | |
146 | .text | |
147 | .global sh7372_cpu_resume | |
148 | sh7372_cpu_resume: | |
149 | ||
150 | mov r1, #0 | |
151 | /* | |
152 | * Invalidate all instruction caches to PoU | |
153 | * and flush branch target cache | |
154 | */ | |
155 | mcr p15, 0, r1, c7, c5, 0 | |
156 | ||
157 | ldr r3, =SMFRAM | |
158 | ||
159 | ldmia r3!, {r4-r6} | |
160 | mov sp, r4 @ Restore sp | |
161 | msr spsr_cxsf, r5 @ Restore spsr | |
162 | mov lr, r6 @ Restore lr | |
163 | ||
164 | ldmia r3!, {r4-r7} | |
165 | mcr p15, 0, r4, c1, c0, 2 @ Coprocessor access Control Register | |
166 | mcr p15, 0, r5, c2, c0, 0 @ TTBR0 | |
167 | mcr p15, 0, r6, c2, c0, 1 @ TTBR1 | |
168 | mcr p15, 0, r7, c2, c0, 2 @ TTBCR | |
169 | ||
170 | ldmia r3!,{r4-r6} | |
171 | mcr p15, 0, r4, c3, c0, 0 @ Domain access Control Register | |
172 | mcr p15, 0, r5, c10, c2, 0 @ PRRR | |
173 | mcr p15, 0, r6, c10, c2, 1 @ NMRR | |
174 | ||
175 | ldmia r3!,{r4-r7} | |
176 | mcr p15, 0, r4, c13, c0, 1 @ Context ID | |
177 | mcr p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID | |
178 | mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address | |
179 | msr cpsr, r7 @ store cpsr | |
180 | ||
181 | /* Starting to enable MMU here */ | |
182 | mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl | |
183 | /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */ | |
184 | and r7, #0x7 | |
185 | cmp r7, #0x0 | |
186 | beq usettbr0 | |
187 | ttbr_error: | |
188 | /* | |
189 | * More work needs to be done to support N[0:2] value other than 0 | |
190 | * So looping here so that the error can be detected | |
191 | */ | |
192 | b ttbr_error | |
193 | ||
194 | .align | |
195 | cache_pred_disable_mask: | |
196 | .word 0xFFFFE7FB | |
197 | ttbrbit_mask: | |
198 | .word 0xFFFFC000 | |
199 | table_index_mask: | |
200 | .word 0xFFF00000 | |
201 | table_entry: | |
202 | .word 0x00000C02 | |
203 | usettbr0: | |
204 | ||
205 | mrc p15, 0, r2, c2, c0, 0 | |
206 | ldr r5, ttbrbit_mask | |
207 | and r2, r5 | |
208 | mov r4, pc | |
209 | ldr r5, table_index_mask | |
210 | and r4, r5 @ r4 = 31 to 20 bits of pc | |
211 | /* Extract the value to be written to table entry */ | |
212 | ldr r6, table_entry | |
213 | /* r6 has the value to be written to table entry */ | |
214 | add r6, r6, r4 | |
215 | /* Getting the address of table entry to modify */ | |
216 | lsr r4, #18 | |
217 | /* r2 has the location which needs to be modified */ | |
218 | add r2, r4 | |
219 | ldr r4, [r2] | |
220 | str r6, [r2] /* modify the table entry */ | |
221 | ||
222 | mov r7, r6 | |
223 | mov r5, r2 | |
224 | mov r6, r4 | |
225 | /* r5 = original page table address */ | |
226 | /* r6 = original page table data */ | |
227 | ||
228 | mov r0, #0 | |
229 | mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer | |
230 | mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array | |
231 | mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB | |
232 | mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB | |
233 | ||
234 | /* | |
235 | * Restore control register. This enables the MMU. | |
236 | * The caches and prediction are not enabled here, they | |
237 | * will be enabled after restoring the MMU table entry. | |
238 | */ | |
239 | ldmia r3!, {r4} | |
240 | stmia r3!, {r5} /* save original page table address */ | |
241 | stmia r3!, {r6} /* save original page table data */ | |
242 | stmia r3!, {r7} /* save modified page table data */ | |
243 | ||
244 | ldr r2, cache_pred_disable_mask | |
245 | and r4, r2 | |
246 | mcr p15, 0, r4, c1, c0, 0 | |
247 | dsb | |
248 | isb | |
249 | ||
250 | ldr r0, =restoremmu_on | |
251 | bx r0 | |
252 | ||
253 | /* | |
254 | * ============================== | |
255 | * == Exit point from OFF mode == | |
256 | * ============================== | |
257 | */ | |
258 | restoremmu_on: | |
259 | ||
260 | ldmfd sp!, {r0-r12, pc} @ restore regs and return |