]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/arm/arm/cpufunc_asm_xscale.S
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / arm / arm / cpufunc_asm_xscale.S
1 /*      $NetBSD: cpufunc_asm_xscale.S,v 1.16 2002/08/17 16:36:32 thorpej Exp $  */
2
3 /*-
4  * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Allen Briggs and Jason R. Thorpe for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed for the NetBSD Project by
20  *      Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  */
38
39 /*-
40  * Copyright (c) 2001 Matt Thomas.
41  * Copyright (c) 1997,1998 Mark Brinicombe.
42  * Copyright (c) 1997 Causality Limited
43  * All rights reserved.
44  *
45  * Redistribution and use in source and binary forms, with or without
46  * modification, are permitted provided that the following conditions
47  * are met:
48  * 1. Redistributions of source code must retain the above copyright
49  *    notice, this list of conditions and the following disclaimer.
50  * 2. Redistributions in binary form must reproduce the above copyright
51  *    notice, this list of conditions and the following disclaimer in the
52  *    documentation and/or other materials provided with the distribution.
53  * 3. All advertising materials mentioning features or use of this software
54  *    must display the following acknowledgement:
55  *      This product includes software developed by Causality Limited.
56  * 4. The name of Causality Limited may not be used to endorse or promote
57  *    products derived from this software without specific prior written
58  *    permission.
59  *
60  * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
61  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
62  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
63  * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
64  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
65  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
66  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70  * SUCH DAMAGE.
71  *
72  * XScale assembly functions for CPU / MMU / TLB specific operations
73  */
74
75 #include <machine/asm.h>
76 __FBSDID("$FreeBSD$");
77
78 /*
79  * Size of the XScale core D-cache.
80  */
81 #define DCACHE_SIZE             0x00008000
82
83 .Lblock_userspace_access:
84         .word   _C_LABEL(block_userspace_access)
85
86 /*
87  * CPWAIT -- Canonical method to wait for CP15 update.
88  * From: Intel 80200 manual, section 2.3.3.
89  *
90  * NOTE: Clobbers the specified temp reg.
91  */
92 #define CPWAIT_BRANCH                                                    \
93         sub     pc, pc, #4
94
95 #define CPWAIT(tmp)                                                      \
96         mrc     p15, 0, tmp, c2, c0, 0  /* arbitrary read of CP15 */    ;\
97         mov     tmp, tmp                /* wait for it to complete */   ;\
98         CPWAIT_BRANCH                   /* branch to next insn */
99
100 #define CPWAIT_AND_RETURN_SHIFTER       lsr #32
101
102 #define CPWAIT_AND_RETURN(tmp)                                           \
103         mrc     p15, 0, tmp, c2, c0, 0  /* arbitrary read of CP15 */    ;\
104         /* Wait for it to complete and branch to the return address */   \
105         sub     pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER
106
107 ENTRY(xscale_cpwait)
108         CPWAIT_AND_RETURN(r0)
109 END(xscale_cpwait)
110
111 /*
112  * We need a separate cpu_control() entry point, since we have to
113  * invalidate the Branch Target Buffer in the event the BPRD bit
114  * changes in the control register.
115  */
116 ENTRY(xscale_control)
117         mrc     p15, 0, r3, c1, c0, 0   /* Read the control register */
118         bic     r2, r3, r0              /* Clear bits */
119         eor     r2, r2, r1              /* XOR bits */
120
121         teq     r2, r3                  /* Only write if there was a change */
122         mcrne   p15, 0, r0, c7, c5, 6   /* Invalidate the BTB */
123         mcrne   p15, 0, r2, c1, c0, 0   /* Write new control register */
124         mov     r0, r3                  /* Return old value */
125
126         CPWAIT_AND_RETURN(r1)
127 END(xscale_control)
128
129 /*
130  * Functions to set the MMU Translation Table Base register
131  *
132  * We need to clean and flush the cache as it uses virtual
133  * addresses that are about to change.
134  */
135 ENTRY(xscale_setttb)
136 #ifdef CACHE_CLEAN_BLOCK_INTR
137         mrs     r3, cpsr_all
138         orr     r1, r3, #(I32_bit | F32_bit)
139         msr     cpsr_all, r1
140 #else
141         ldr     r3, .Lblock_userspace_access
142         ldr     r2, [r3]
143         orr     r1, r2, #1
144         str     r1, [r3]
145 #endif
146         stmfd   sp!, {r0-r3, lr}
147         bl      _C_LABEL(xscale_cache_cleanID)
148         mcr     p15, 0, r0, c7, c5, 0   /* invalidate I$ and BTB */
149         mcr     p15, 0, r0, c7, c10, 4  /* drain write and fill buffer */
150
151         CPWAIT(r0)
152
153         ldmfd   sp!, {r0-r3, lr}
154
155         /* Write the TTB */
156         mcr     p15, 0, r0, c2, c0, 0
157
158         /* If we have updated the TTB we must flush the TLB */
159         mcr     p15, 0, r0, c8, c7, 0   /* invalidate I+D TLB */
160
161         /* The cleanID above means we only need to flush the I cache here */
162         mcr     p15, 0, r0, c7, c5, 0   /* invalidate I$ and BTB */
163
164         CPWAIT(r0)
165
166 #ifdef CACHE_CLEAN_BLOCK_INTR
167         msr     cpsr_all, r3
168 #else
169         str     r2, [r3]
170 #endif
171         RET
172 END(xscale_setttb)
173
174 /*
175  * TLB functions
176  *
177  */
178 ENTRY(xscale_tlb_flushID_SE)
179         mcr     p15, 0, r0, c8, c6, 1   /* flush D tlb single entry */
180         mcr     p15, 0, r0, c8, c5, 1   /* flush I tlb single entry */
181         CPWAIT_AND_RETURN(r0)
182 END(xscale_tlb_flushID_SE)
183
184 /*
185  * Cache functions
186  */
187 ENTRY(xscale_cache_flushID)
188         mcr     p15, 0, r0, c7, c7, 0   /* flush I+D cache */
189         CPWAIT_AND_RETURN(r0)
190 END(xscale_cache_flushID)
191
192 ENTRY(xscale_cache_flushI)
193         mcr     p15, 0, r0, c7, c5, 0   /* flush I cache */
194         CPWAIT_AND_RETURN(r0)
195 END(xscale_cache_flushI)
196
197 ENTRY(xscale_cache_flushD)
198         mcr     p15, 0, r0, c7, c6, 0   /* flush D cache */
199         CPWAIT_AND_RETURN(r0)
200 END(xscale_cache_flushD)
201
202 ENTRY(xscale_cache_flushI_SE)
203         mcr     p15, 0, r0, c7, c5, 1   /* flush I cache single entry */
204         CPWAIT_AND_RETURN(r0)
205 END(xscale_cache_flushI_SE)
206
207 ENTRY(xscale_cache_flushD_SE)
208         /*
209          * Errata (rev < 2): Must clean-dcache-line to an address
210          * before invalidate-dcache-line to an address, or dirty
211          * bits will not be cleared in the dcache array.
212          */
213         mcr     p15, 0, r0, c7, c10, 1
214         mcr     p15, 0, r0, c7, c6, 1   /* flush D cache single entry */
215         CPWAIT_AND_RETURN(r0)
216 END(xscale_cache_flushD_SE)
217
218 ENTRY(xscale_cache_cleanD_E)
219         mcr     p15, 0, r0, c7, c10, 1  /* clean D cache entry */
220         CPWAIT_AND_RETURN(r0)
221 END(xscale_cache_cleanD_E)
222
223 /*
224  * Information for the XScale cache clean/purge functions:
225  *
226  *      * Virtual address of the memory region to use
227  *      * Size of memory region
228  *
229  * Note the virtual address for the Data cache clean operation
230  * does not need to be backed by physical memory, since no loads
231  * will actually be performed by the allocate-line operation.
232  *
233  * Note that the Mini-Data cache MUST be cleaned by executing
234  * loads from memory mapped into a region reserved exclusively
235  * for cleaning of the Mini-Data cache.
236  */
237         .data
238
239         .global _C_LABEL(xscale_cache_clean_addr)
240 _C_LABEL(xscale_cache_clean_addr):
241         .word   0x00000000
242
243         .global _C_LABEL(xscale_cache_clean_size)
244 _C_LABEL(xscale_cache_clean_size):
245         .word   DCACHE_SIZE
246
247         .global _C_LABEL(xscale_minidata_clean_addr)
248 _C_LABEL(xscale_minidata_clean_addr):
249         .word   0x00000000
250
251         .global _C_LABEL(xscale_minidata_clean_size)
252 _C_LABEL(xscale_minidata_clean_size):
253         .word   0x00000800
254
255         .text
256
257 .Lxscale_cache_clean_addr:
258         .word   _C_LABEL(xscale_cache_clean_addr)
259 .Lxscale_cache_clean_size:
260         .word   _C_LABEL(xscale_cache_clean_size)
261
262 .Lxscale_minidata_clean_addr:
263         .word   _C_LABEL(xscale_minidata_clean_addr)
264 .Lxscale_minidata_clean_size:
265         .word   _C_LABEL(xscale_minidata_clean_size)
266
267 #ifdef CACHE_CLEAN_BLOCK_INTR
268 #define XSCALE_CACHE_CLEAN_BLOCK                                        \
269         mrs     r3, cpsr_all                                    ;       \
270         orr     r0, r3, #(I32_bit | F32_bit)                    ;       \
271         msr     cpsr_all, r0
272
273 #define XSCALE_CACHE_CLEAN_UNBLOCK                                      \
274         msr     cpsr_all, r3
275 #else
276 #define XSCALE_CACHE_CLEAN_BLOCK                                        \
277         ldr     r3, .Lblock_userspace_access                    ;       \
278         ldr     ip, [r3]                                        ;       \
279         orr     r0, ip, #1                                      ;       \
280         str     r0, [r3]
281
282 #define XSCALE_CACHE_CLEAN_UNBLOCK                                      \
283         str     ip, [r3]
284 #endif /* CACHE_CLEAN_BLOCK_INTR */
285
286 #define XSCALE_CACHE_CLEAN_PROLOGUE                                     \
287         XSCALE_CACHE_CLEAN_BLOCK                                ;       \
288         ldr     r2, .Lxscale_cache_clean_addr                   ;       \
289         ldmia   r2, {r0, r1}                                    ;       \
290         /*                                                              \
291          * BUG ALERT!                                                   \
292          *                                                              \
293          * The XScale core has a strange cache eviction bug, which      \
294          * requires us to use 2x the cache size for the cache clean     \
295          * and for that area to be aligned to 2 * cache size.           \
296          *                                                              \
297          * The work-around is to use 2 areas for cache clean, and to    \
298          * alternate between them whenever this is done.  No one knows  \
299          * why the work-around works (mmm!).                            \
300          */                                                             \
301         eor     r0, r0, #(DCACHE_SIZE)                          ;       \
302         str     r0, [r2]                                        ;       \
303         add     r0, r0, r1
304
305 #define XSCALE_CACHE_CLEAN_EPILOGUE                                     \
306         XSCALE_CACHE_CLEAN_UNBLOCK
307
308 ENTRY_NP(xscale_cache_syncI)
309 ENTRY_NP(xscale_cache_purgeID)
310         mcr     p15, 0, r0, c7, c5, 0   /* flush I cache (D cleaned below) */
311 ENTRY_NP(xscale_cache_cleanID)
312 ENTRY_NP(xscale_cache_purgeD)
313 ENTRY(xscale_cache_cleanD)
314         XSCALE_CACHE_CLEAN_PROLOGUE
315
316 1:      subs    r0, r0, #32
317         mcr     p15, 0, r0, c7, c2, 5   /* allocate cache line */
318         subs    r1, r1, #32
319         bne     1b
320
321         CPWAIT(r0)
322
323         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
324
325         CPWAIT(r0)
326
327         XSCALE_CACHE_CLEAN_EPILOGUE
328         RET
329 END(xscale_cache_syncI)
330 END(xscale_cache_purgeID)
331 END(xscale_cache_cleanID)
332 END(xscale_cache_purgeD)
333 END(xscale_cache_cleanD)
334
335 /*
336  * Clean the mini-data cache.
337  *
338  * It's expected that we only use the mini-data cache for
339  * kernel addresses, so there is no need to purge it on
340  * context switch, and no need to prevent userspace access
341  * while we clean it.
342  */
343 ENTRY(xscale_cache_clean_minidata)
344         ldr     r2, .Lxscale_minidata_clean_addr
345         ldmia   r2, {r0, r1}
346 1:      ldr     r3, [r0], #32
347         subs    r1, r1, #32
348         bne     1b
349
350         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
351
352         CPWAIT_AND_RETURN(r1)
353 END(xscale_cache_clean_minidata)
354
355 ENTRY(xscale_cache_purgeID_E)
356         mcr     p15, 0, r0, c7, c10, 1  /* clean D cache entry */
357         CPWAIT(r1)
358         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
359         mcr     p15, 0, r0, c7, c5, 1   /* flush I cache single entry */
360         mcr     p15, 0, r0, c7, c6, 1   /* flush D cache single entry */
361         CPWAIT_AND_RETURN(r1)
362 END(xscale_cache_purgeID_E)
363
364 ENTRY(xscale_cache_purgeD_E)
365         mcr     p15, 0, r0, c7, c10, 1  /* clean D cache entry */
366         CPWAIT(r1)
367         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
368         mcr     p15, 0, r0, c7, c6, 1   /* flush D cache single entry */
369         CPWAIT_AND_RETURN(r1)
370 END(xscale_cache_purgeD_E)
371
372 /*
373  * Soft functions
374  */
375 /* xscale_cache_syncI is identical to xscale_cache_purgeID */
376
377 ENTRY(xscale_cache_cleanID_rng)
378 ENTRY(xscale_cache_cleanD_rng)
379         cmp     r1, #0x4000
380         bcs     _C_LABEL(xscale_cache_cleanID)
381
382         and     r2, r0, #0x1f
383         add     r1, r1, r2
384         bic     r0, r0, #0x1f
385
386 1:      mcr     p15, 0, r0, c7, c10, 1  /* clean D cache entry */
387         add     r0, r0, #32
388         subs    r1, r1, #32
389         bhi     1b
390
391         CPWAIT(r0)
392
393         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
394
395         CPWAIT_AND_RETURN(r0)
396 END(xscale_cache_cleanID_rng)
397 END(xscale_cache_cleanD_rng)
398
399 ENTRY(xscale_cache_purgeID_rng)
400         cmp     r1, #0x4000
401         bcs     _C_LABEL(xscale_cache_purgeID)
402
403         and     r2, r0, #0x1f
404         add     r1, r1, r2
405         bic     r0, r0, #0x1f
406
407 1:      mcr     p15, 0, r0, c7, c10, 1  /* clean D cache entry */
408         mcr     p15, 0, r0, c7, c6, 1   /* flush D cache single entry */
409         mcr     p15, 0, r0, c7, c5, 1   /* flush I cache single entry */
410         add     r0, r0, #32
411         subs    r1, r1, #32
412         bhi     1b
413
414         CPWAIT(r0)
415
416         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
417
418         CPWAIT_AND_RETURN(r0)
419 END(xscale_cache_purgeID_rng)
420
421 ENTRY(xscale_cache_purgeD_rng)
422         cmp     r1, #0x4000
423         bcs     _C_LABEL(xscale_cache_purgeD)
424
425         and     r2, r0, #0x1f
426         add     r1, r1, r2
427         bic     r0, r0, #0x1f
428
429 1:      mcr     p15, 0, r0, c7, c10, 1  /* clean D cache entry */
430         mcr     p15, 0, r0, c7, c6, 1   /* flush D cache single entry */
431         add     r0, r0, #32
432         subs    r1, r1, #32
433         bhi     1b
434
435         CPWAIT(r0)
436
437         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
438
439         CPWAIT_AND_RETURN(r0)
440 END(xscale_cache_purgeD_rng)
441
442 ENTRY(xscale_cache_syncI_rng)
443         cmp     r1, #0x4000
444         bcs     _C_LABEL(xscale_cache_syncI)
445
446         and     r2, r0, #0x1f
447         add     r1, r1, r2
448         bic     r0, r0, #0x1f
449
450 1:      mcr     p15, 0, r0, c7, c10, 1  /* clean D cache entry */
451         mcr     p15, 0, r0, c7, c5, 1   /* flush I cache single entry */
452         add     r0, r0, #32
453         subs    r1, r1, #32
454         bhi     1b
455
456         CPWAIT(r0)
457
458         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
459
460         CPWAIT_AND_RETURN(r0)
461 END(xscale_cache_syncI_rng)
462
463 ENTRY(xscale_cache_flushD_rng)
464         and     r2, r0, #0x1f
465         add     r1, r1, r2
466         bic     r0, r0, #0x1f
467
468 1:      mcr     p15, 0, r0, c7, c6, 1   /* flush D cache single entry */
469         add     r0, r0, #32
470         subs    r1, r1, #32
471         bhi     1b
472
473         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
474
475         CPWAIT_AND_RETURN(r0)
476 END(xscale_cache_flushD_rng)
477
478 /*
479  * Context switch.
480  *
481  * These is the CPU-specific parts of the context switcher cpu_switch()
482  * These functions actually perform the TTB reload.
483  *
484  * NOTE: Special calling convention
485  *      r1, r4-r13 must be preserved
486  */
487 ENTRY(xscale_context_switch)
488         /*
489          * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this.
490          * Thus the data cache will contain only kernel data and the
491          * instruction cache will contain only kernel code, and all
492          * kernel mappings are shared by all processes.
493          */
494
495         /* Write the TTB */
496         mcr     p15, 0, r0, c2, c0, 0
497
498         /* If we have updated the TTB we must flush the TLB */
499         mcr     p15, 0, r0, c8, c7, 0   /* flush the I+D tlb */
500
501         CPWAIT_AND_RETURN(r0)
502 END(xscale_context_switch)
503
504 /*
505  * xscale_cpu_sleep
506  *
507  * This is called when there is nothing on any of the run queues.
508  * We go into IDLE mode so that any IRQ or FIQ will awaken us.
509  *
510  * If this is called with anything other than ARM_SLEEP_MODE_IDLE,
511  * ignore it.
512  */
513 ENTRY(xscale_cpu_sleep)
514         tst     r0, #0x00000000
515         bne     1f
516         mov     r0, #0x1
517         mcr     p14, 0, r0, c7, c0, 0
518
519 1:
520         RET
521 END(xscale_cpu_sleep)
522