Merge tag 'sound-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / mn10300 / mm / cache-inv-by-reg.S
1 /* MN10300 CPU cache invalidation routines, using automatic purge registers
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11 #include <linux/sys.h>
12 #include <linux/linkage.h>
13 #include <asm/smp.h>
14 #include <asm/page.h>
15 #include <asm/cache.h>
16 #include <asm/irqflags.h>
17 #include <asm/cacheflush.h>
18 #include "cache.inc"
19
20 #define mn10300_local_dcache_inv_range_intr_interval \
21 +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
22
23 #if mn10300_local_dcache_inv_range_intr_interval > 0xff
24 #error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
25 #endif
26
27 .am33_2
28
29 #ifndef CONFIG_SMP
30 .globl mn10300_icache_inv
31 .globl mn10300_icache_inv_page
32 .globl mn10300_icache_inv_range
33 .globl mn10300_icache_inv_range2
34 .globl mn10300_dcache_inv
35 .globl mn10300_dcache_inv_page
36 .globl mn10300_dcache_inv_range
37 .globl mn10300_dcache_inv_range2
38
39 mn10300_icache_inv = mn10300_local_icache_inv
40 mn10300_icache_inv_page = mn10300_local_icache_inv_page
41 mn10300_icache_inv_range = mn10300_local_icache_inv_range
42 mn10300_icache_inv_range2 = mn10300_local_icache_inv_range2
43 mn10300_dcache_inv = mn10300_local_dcache_inv
44 mn10300_dcache_inv_page = mn10300_local_dcache_inv_page
45 mn10300_dcache_inv_range = mn10300_local_dcache_inv_range
46 mn10300_dcache_inv_range2 = mn10300_local_dcache_inv_range2
47
48 #endif /* !CONFIG_SMP */
49
50 ###############################################################################
51 #
52 # void mn10300_local_icache_inv(void)
53 # Invalidate the entire icache
54 #
55 ###############################################################################
56 ALIGN
57 .globl mn10300_local_icache_inv
58 .type mn10300_local_icache_inv,@function
59 mn10300_local_icache_inv:
60 mov CHCTR,a0
61
62 movhu (a0),d0
63 btst CHCTR_ICEN,d0
64 beq mn10300_local_icache_inv_end
65
66 invalidate_icache 1
67
68 mn10300_local_icache_inv_end:
69 ret [],0
70 .size mn10300_local_icache_inv,.-mn10300_local_icache_inv
71
72 ###############################################################################
73 #
74 # void mn10300_local_dcache_inv(void)
75 # Invalidate the entire dcache
76 #
77 ###############################################################################
78 ALIGN
79 .globl mn10300_local_dcache_inv
80 .type mn10300_local_dcache_inv,@function
81 mn10300_local_dcache_inv:
82 mov CHCTR,a0
83
84 movhu (a0),d0
85 btst CHCTR_DCEN,d0
86 beq mn10300_local_dcache_inv_end
87
88 invalidate_dcache 1
89
90 mn10300_local_dcache_inv_end:
91 ret [],0
92 .size mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
93
94 ###############################################################################
95 #
96 # void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
97 # void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
98 # void mn10300_local_dcache_inv_page(unsigned long start)
99 # Invalidate a range of addresses on a page in the dcache
100 #
101 ###############################################################################
102 ALIGN
103 .globl mn10300_local_dcache_inv_page
104 .globl mn10300_local_dcache_inv_range
105 .globl mn10300_local_dcache_inv_range2
106 .type mn10300_local_dcache_inv_page,@function
107 .type mn10300_local_dcache_inv_range,@function
108 .type mn10300_local_dcache_inv_range2,@function
109 mn10300_local_dcache_inv_page:
110 and ~(PAGE_SIZE-1),d0
111 mov PAGE_SIZE,d1
112 mn10300_local_dcache_inv_range2:
113 add d0,d1
114 mn10300_local_dcache_inv_range:
115 # If we are in writeback mode we check the start and end alignments,
116 # and if they're not cacheline-aligned, we must flush any bits outside
117 # the range that share cachelines with stuff inside the range
118 #ifdef CONFIG_MN10300_CACHE_WBACK
119 btst ~L1_CACHE_TAG_MASK,d0
120 bne 1f
121 btst ~L1_CACHE_TAG_MASK,d1
122 beq 2f
123 1:
124 bra mn10300_local_dcache_flush_inv_range
125 2:
126 #endif /* CONFIG_MN10300_CACHE_WBACK */
127
128 movm [d2,d3,a2],(sp)
129
130 mov CHCTR,a0
131 movhu (a0),d2
132 btst CHCTR_DCEN,d2
133 beq mn10300_local_dcache_inv_range_end
134
135 # round the addresses out to be full cachelines, unless we're in
136 # writeback mode, in which case we would be in flush and invalidate by
137 # now
138 #ifndef CONFIG_MN10300_CACHE_WBACK
139 and L1_CACHE_TAG_MASK,d0 # round start addr down
140
141 mov L1_CACHE_BYTES-1,d2
142 add d2,d1
143 and L1_CACHE_TAG_MASK,d1 # round end addr up
144 #endif /* !CONFIG_MN10300_CACHE_WBACK */
145
146 sub d0,d1,d2 # calculate the total size
147 mov d0,a2 # A2 = start address
148 mov d1,a1 # A1 = end address
149
150 LOCAL_CLI_SAVE(d3)
151
152 mov DCPGCR,a0 # make sure the purger isn't busy
153 setlb
154 mov (a0),d0
155 btst DCPGCR_DCPGBSY,d0
156 lne
157
158 # skip initial address alignment calculation if address is zero
159 mov d2,d1
160 cmp 0,a2
161 beq 1f
162
163 dcivloop:
164 /* calculate alignsize
165 *
166 * alignsize = L1_CACHE_BYTES;
167 * while (! start & alignsize) {
168 * alignsize <<=1;
169 * }
170 * d1 = alignsize;
171 */
172 mov L1_CACHE_BYTES,d1
173 lsr 1,d1
174 setlb
175 add d1,d1
176 mov d1,d0
177 and a2,d0
178 leq
179
180 1:
181 /* calculate invsize
182 *
183 * if (totalsize > alignsize) {
184 * invsize = alignsize;
185 * } else {
186 * invsize = totalsize;
187 * tmp = 0x80000000;
188 * while (! invsize & tmp) {
189 * tmp >>= 1;
190 * }
191 * invsize = tmp;
192 * }
193 * d1 = invsize
194 */
195 cmp d2,d1
196 bns 2f
197 mov d2,d1
198
199 mov 0x80000000,d0 # start from 31bit=1
200 setlb
201 lsr 1,d0
202 mov d0,e0
203 and d1,e0
204 leq
205 mov d0,d1
206
207 2:
208 /* set mask
209 *
210 * mask = ~(invsize-1);
211 * DCPGMR = mask;
212 */
213 mov d1,d0
214 add -1,d0
215 not d0
216 mov d0,(DCPGMR)
217
218 # invalidate area
219 mov a2,d0
220 or DCPGCR_DCI,d0
221 mov d0,(a0) # DCPGCR = (mask & start) | DCPGCR_DCI
222
223 setlb # wait for the purge to complete
224 mov (a0),d0
225 btst DCPGCR_DCPGBSY,d0
226 lne
227
228 sub d1,d2 # decrease size remaining
229 add d1,a2 # increase next start address
230
231 /* check invalidating of end address
232 *
233 * a2 = a2 + invsize
234 * if (a2 < end) {
235 * goto dcivloop;
236 * } */
237 cmp a1,a2
238 bns dcivloop
239
240 LOCAL_IRQ_RESTORE(d3)
241
242 mn10300_local_dcache_inv_range_end:
243 ret [d2,d3,a2],12
244 .size mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
245 .size mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
246 .size mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
247
248 ###############################################################################
249 #
250 # void mn10300_local_icache_inv_page(unsigned long start)
251 # void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size)
252 # void mn10300_local_icache_inv_range(unsigned long start, unsigned long end)
253 # Invalidate a range of addresses on a page in the icache
254 #
255 ###############################################################################
256 ALIGN
257 .globl mn10300_local_icache_inv_page
258 .globl mn10300_local_icache_inv_range
259 .globl mn10300_local_icache_inv_range2
260 .type mn10300_local_icache_inv_page,@function
261 .type mn10300_local_icache_inv_range,@function
262 .type mn10300_local_icache_inv_range2,@function
263 mn10300_local_icache_inv_page:
264 and ~(PAGE_SIZE-1),d0
265 mov PAGE_SIZE,d1
266 mn10300_local_icache_inv_range2:
267 add d0,d1
268 mn10300_local_icache_inv_range:
269 movm [d2,d3,a2],(sp)
270
271 mov CHCTR,a0
272 movhu (a0),d2
273 btst CHCTR_ICEN,d2
274 beq mn10300_local_icache_inv_range_reg_end
275
276 /* calculate alignsize
277 *
278 * alignsize = L1_CACHE_BYTES;
279 * for (i = (end - start - 1) / L1_CACHE_BYTES ; i > 0; i >>= 1) {
280 * alignsize <<= 1;
281 * }
282 * d2 = alignsize;
283 */
284 mov L1_CACHE_BYTES,d2
285 sub d0,d1,d3
286 add -1,d3
287 lsr L1_CACHE_SHIFT,d3
288 beq 2f
289 1:
290 add d2,d2
291 lsr 1,d3
292 bne 1b
293 2:
294
295 /* a1 = end */
296 mov d1,a1
297
298 LOCAL_CLI_SAVE(d3)
299
300 mov ICIVCR,a0
301 /* wait for busy bit of area invalidation */
302 setlb
303 mov (a0),d1
304 btst ICIVCR_ICIVBSY,d1
305 lne
306
307 /* set mask
308 *
309 * mask = ~(alignsize-1);
310 * ICIVMR = mask;
311 */
312 mov d2,d1
313 add -1,d1
314 not d1
315 mov d1,(ICIVMR)
316 /* a2 = mask & start */
317 and d1,d0,a2
318
319 icivloop:
320 /* area invalidate
321 *
322 * ICIVCR = (mask & start) | ICIVCR_ICI
323 */
324 mov a2,d0
325 or ICIVCR_ICI,d0
326 mov d0,(a0)
327
328 /* wait for busy bit of area invalidation */
329 setlb
330 mov (a0),d1
331 btst ICIVCR_ICIVBSY,d1
332 lne
333
334 /* check invalidating of end address
335 *
336 * a2 = a2 + alignsize
337 * if (a2 < end) {
338 * goto icivloop;
339 * } */
340 add d2,a2
341 cmp a1,a2
342 bns icivloop
343
344 LOCAL_IRQ_RESTORE(d3)
345
346 mn10300_local_icache_inv_range_reg_end:
347 ret [d2,d3,a2],12
348 .size mn10300_local_icache_inv_page,.-mn10300_local_icache_inv_page
349 .size mn10300_local_icache_inv_range,.-mn10300_local_icache_inv_range
350 .size mn10300_local_icache_inv_range2,.-mn10300_local_icache_inv_range2