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