1 /* $NetBSD: cpufunc_asm_xscale.S,v 1.16 2002/08/17 16:36:32 thorpej Exp $ */
4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
7 * Written by Allen Briggs and Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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.
40 * Copyright (c) 2001 Matt Thomas.
41 * Copyright (c) 1997,1998 Mark Brinicombe.
42 * Copyright (c) 1997 Causality Limited
43 * All rights reserved.
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
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
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
72 * XScale assembly functions for CPU / MMU / TLB specific operations
74 #include <machine/asm.h>
75 __FBSDID("$FreeBSD$");
77 #include <machine/armreg.h>
80 * Size of the XScale core D-cache.
82 #define DCACHE_SIZE 0x00008000
85 * CPWAIT -- Canonical method to wait for CP15 update.
86 * From: Intel 80200 manual, section 2.3.3.
88 * NOTE: Clobbers the specified temp reg.
90 #define CPWAIT_BRANCH \
94 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\
95 mov tmp, tmp /* wait for it to complete */ ;\
96 CPWAIT_BRANCH /* branch to next insn */
98 #define CPWAIT_AND_RETURN_SHIFTER lsr #32
100 #define CPWAIT_AND_RETURN(tmp) \
101 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\
102 /* Wait for it to complete and branch to the return address */ \
103 sub pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER
106 CPWAIT_AND_RETURN(r0)
110 * We need a separate cpu_control() entry point, since we have to
111 * invalidate the Branch Target Buffer in the event the BPRD bit
112 * changes in the control register.
114 ENTRY(xscale_control)
115 mrc CP15_SCTLR(r3) /* Read the control register */
116 bic r2, r3, r0 /* Clear bits */
117 eor r2, r2, r1 /* XOR bits */
119 teq r2, r3 /* Only write if there was a change */
120 mcrne p15, 0, r0, c7, c5, 6 /* Invalidate the BTB */
121 mcrne CP15_SCTLR(r2) /* Write new control register */
122 mov r0, r3 /* Return old value */
124 CPWAIT_AND_RETURN(r1)
128 * Functions to set the MMU Translation Table Base register
130 * We need to clean and flush the cache as it uses virtual
131 * addresses that are about to change.
134 #ifdef CACHE_CLEAN_BLOCK_INTR
136 orr r1, r3, #(PSR_I | PSR_F)
139 stmfd sp!, {r0-r3, lr}
140 bl _C_LABEL(xscale_cache_cleanID)
141 mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */
142 mcr p15, 0, r0, c7, c10, 4 /* drain write and fill buffer */
146 ldmfd sp!, {r0-r3, lr}
149 mcr p15, 0, r0, c2, c0, 0
151 /* If we have updated the TTB we must flush the TLB */
152 mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLB */
154 /* The cleanID above means we only need to flush the I cache here */
155 mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */
159 #ifdef CACHE_CLEAN_BLOCK_INTR
169 ENTRY(xscale_tlb_flushID_SE)
170 mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */
171 mcr p15, 0, r0, c8, c5, 1 /* flush I tlb single entry */
172 CPWAIT_AND_RETURN(r0)
173 END(xscale_tlb_flushID_SE)
178 ENTRY(xscale_cache_flushID)
179 mcr p15, 0, r0, c7, c7, 0 /* flush I+D cache */
180 CPWAIT_AND_RETURN(r0)
181 END(xscale_cache_flushID)
183 ENTRY(xscale_cache_flushI)
184 mcr p15, 0, r0, c7, c5, 0 /* flush I cache */
185 CPWAIT_AND_RETURN(r0)
186 END(xscale_cache_flushI)
188 ENTRY(xscale_cache_flushD)
189 mcr p15, 0, r0, c7, c6, 0 /* flush D cache */
190 CPWAIT_AND_RETURN(r0)
191 END(xscale_cache_flushD)
193 ENTRY(xscale_cache_flushI_SE)
194 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */
195 CPWAIT_AND_RETURN(r0)
196 END(xscale_cache_flushI_SE)
198 ENTRY(xscale_cache_flushD_SE)
200 * Errata (rev < 2): Must clean-dcache-line to an address
201 * before invalidate-dcache-line to an address, or dirty
202 * bits will not be cleared in the dcache array.
204 mcr p15, 0, r0, c7, c10, 1
205 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
206 CPWAIT_AND_RETURN(r0)
207 END(xscale_cache_flushD_SE)
209 ENTRY(xscale_cache_cleanD_E)
210 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
211 CPWAIT_AND_RETURN(r0)
212 END(xscale_cache_cleanD_E)
215 * Information for the XScale cache clean/purge functions:
217 * * Virtual address of the memory region to use
218 * * Size of memory region
220 * Note the virtual address for the Data cache clean operation
221 * does not need to be backed by physical memory, since no loads
222 * will actually be performed by the allocate-line operation.
224 * Note that the Mini-Data cache MUST be cleaned by executing
225 * loads from memory mapped into a region reserved exclusively
226 * for cleaning of the Mini-Data cache.
230 .global _C_LABEL(xscale_cache_clean_addr)
231 _C_LABEL(xscale_cache_clean_addr):
234 .global _C_LABEL(xscale_cache_clean_size)
235 _C_LABEL(xscale_cache_clean_size):
238 .global _C_LABEL(xscale_minidata_clean_addr)
239 _C_LABEL(xscale_minidata_clean_addr):
242 .global _C_LABEL(xscale_minidata_clean_size)
243 _C_LABEL(xscale_minidata_clean_size):
248 .Lxscale_cache_clean_addr:
249 .word _C_LABEL(xscale_cache_clean_addr)
250 .Lxscale_cache_clean_size:
251 .word _C_LABEL(xscale_cache_clean_size)
253 .Lxscale_minidata_clean_addr:
254 .word _C_LABEL(xscale_minidata_clean_addr)
255 .Lxscale_minidata_clean_size:
256 .word _C_LABEL(xscale_minidata_clean_size)
258 #ifdef CACHE_CLEAN_BLOCK_INTR
259 #define XSCALE_CACHE_CLEAN_BLOCK \
261 orr r0, r3, #(PSR_I | PSR_F) ; \
264 #define XSCALE_CACHE_CLEAN_UNBLOCK \
267 #define XSCALE_CACHE_CLEAN_BLOCK
269 #define XSCALE_CACHE_CLEAN_UNBLOCK
270 #endif /* CACHE_CLEAN_BLOCK_INTR */
272 #define XSCALE_CACHE_CLEAN_PROLOGUE \
273 XSCALE_CACHE_CLEAN_BLOCK ; \
274 ldr r2, .Lxscale_cache_clean_addr ; \
275 ldmia r2, {r0, r1} ; \
279 * The XScale core has a strange cache eviction bug, which \
280 * requires us to use 2x the cache size for the cache clean \
281 * and for that area to be aligned to 2 * cache size. \
283 * The work-around is to use 2 areas for cache clean, and to \
284 * alternate between them whenever this is done. No one knows \
285 * why the work-around works (mmm!). \
287 eor r0, r0, #(DCACHE_SIZE) ; \
291 #define XSCALE_CACHE_CLEAN_EPILOGUE \
292 XSCALE_CACHE_CLEAN_UNBLOCK
294 ENTRY_NP(xscale_cache_syncI)
296 EENTRY_NP(xscale_cache_purgeID)
297 mcr p15, 0, r0, c7, c5, 0 /* flush I cache (D cleaned below) */
298 EENTRY_NP(xscale_cache_cleanID)
299 EENTRY_NP(xscale_cache_purgeD)
300 EENTRY(xscale_cache_cleanD)
301 XSCALE_CACHE_CLEAN_PROLOGUE
304 mcr p15, 0, r0, c7, c2, 5 /* allocate cache line */
310 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
314 XSCALE_CACHE_CLEAN_EPILOGUE
316 EEND(xscale_cache_cleanD)
317 EEND(xscale_cache_purgeD)
318 EEND(xscale_cache_cleanID)
319 EEND(xscale_cache_purgeID)
320 END(xscale_cache_syncI)
323 * Clean the mini-data cache.
325 * It's expected that we only use the mini-data cache for
326 * kernel addresses, so there is no need to purge it on
327 * context switch, and no need to prevent userspace access
330 ENTRY(xscale_cache_clean_minidata)
331 ldr r2, .Lxscale_minidata_clean_addr
337 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
339 CPWAIT_AND_RETURN(r1)
340 END(xscale_cache_clean_minidata)
342 ENTRY(xscale_cache_purgeID_E)
343 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
345 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
346 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */
347 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
348 CPWAIT_AND_RETURN(r1)
349 END(xscale_cache_purgeID_E)
351 ENTRY(xscale_cache_purgeD_E)
352 mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
354 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
355 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
356 CPWAIT_AND_RETURN(r1)
357 END(xscale_cache_purgeD_E)
362 /* xscale_cache_syncI is identical to xscale_cache_purgeID */
364 EENTRY(xscale_cache_cleanID_rng)
365 ENTRY(xscale_cache_cleanD_rng)
367 bcs _C_LABEL(xscale_cache_cleanID)
373 1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
380 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
382 CPWAIT_AND_RETURN(r0)
383 /*END(xscale_cache_cleanID_rng)*/
384 END(xscale_cache_cleanD_rng)
386 ENTRY(xscale_cache_purgeID_rng)
388 bcs _C_LABEL(xscale_cache_purgeID)
394 1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
395 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
396 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */
403 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
405 CPWAIT_AND_RETURN(r0)
406 END(xscale_cache_purgeID_rng)
408 ENTRY(xscale_cache_purgeD_rng)
410 bcs _C_LABEL(xscale_cache_purgeD)
416 1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
417 mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
424 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
426 CPWAIT_AND_RETURN(r0)
427 END(xscale_cache_purgeD_rng)
429 ENTRY(xscale_cache_syncI_rng)
431 bcs _C_LABEL(xscale_cache_syncI)
437 1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
438 mcr p15, 0, r0, c7, c5, 1 /* flush I cache single entry */
445 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
447 CPWAIT_AND_RETURN(r0)
448 END(xscale_cache_syncI_rng)
450 ENTRY(xscale_cache_flushD_rng)
455 1: mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
460 mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
462 CPWAIT_AND_RETURN(r0)
463 END(xscale_cache_flushD_rng)
468 * These is the CPU-specific parts of the context switcher cpu_switch()
469 * These functions actually perform the TTB reload.
471 * NOTE: Special calling convention
472 * r1, r4-r13 must be preserved
474 ENTRY(xscale_context_switch)
476 * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this.
477 * Thus the data cache will contain only kernel data and the
478 * instruction cache will contain only kernel code, and all
479 * kernel mappings are shared by all processes.
483 mcr p15, 0, r0, c2, c0, 0
485 /* If we have updated the TTB we must flush the TLB */
486 mcr p15, 0, r0, c8, c7, 0 /* flush the I+D tlb */
488 CPWAIT_AND_RETURN(r0)
489 END(xscale_context_switch)
494 * This is called when there is nothing on any of the run queues.
495 * We go into IDLE mode so that any IRQ or FIQ will awaken us.
497 * If this is called with anything other than ARM_SLEEP_MODE_IDLE,
500 ENTRY(xscale_cpu_sleep)
504 mcr p14, 0, r0, c7, c0, 0
508 END(xscale_cpu_sleep)