cpufunc_asm_xscale.S revision 248361
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: head/sys/arm/arm/cpufunc_asm_xscale.S 248361 2013-03-16 02:48:49Z andrew $");
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
107ENTRY(xscale_cpwait)
108	CPWAIT_AND_RETURN(r0)
109END(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 */
116ENTRY(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)
127END(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 */
135ENTRY(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
172END(xscale_setttb)
173
174/*
175 * TLB functions
176 *
177 */
178ENTRY(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)
182END(xscale_tlb_flushID_SE)
183
184/*
185 * Cache functions
186 */
187ENTRY(xscale_cache_flushID)
188	mcr	p15, 0, r0, c7, c7, 0	/* flush I+D cache */
189	CPWAIT_AND_RETURN(r0)
190END(xscale_cache_flushID)
191
192ENTRY(xscale_cache_flushI)
193	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache */
194	CPWAIT_AND_RETURN(r0)
195END(xscale_cache_flushI)
196
197ENTRY(xscale_cache_flushD)
198	mcr	p15, 0, r0, c7, c6, 0	/* flush D cache */
199	CPWAIT_AND_RETURN(r0)
200END(xscale_cache_flushD)
201
202ENTRY(xscale_cache_flushI_SE)
203	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
204	CPWAIT_AND_RETURN(r0)
205END(xscale_cache_flushI_SE)
206
207ENTRY(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)
216END(xscale_cache_flushD_SE)
217
218ENTRY(xscale_cache_cleanD_E)
219	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
220	CPWAIT_AND_RETURN(r0)
221END(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
308ENTRY_NP(xscale_cache_syncI)
309ENTRY_NP(xscale_cache_purgeID)
310	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache (D cleaned below) */
311ENTRY_NP(xscale_cache_cleanID)
312ENTRY_NP(xscale_cache_purgeD)
313ENTRY(xscale_cache_cleanD)
314	XSCALE_CACHE_CLEAN_PROLOGUE
315
3161:	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
329END(xscale_cache_syncI)
330END(xscale_cache_purgeID)
331END(xscale_cache_cleanID)
332END(xscale_cache_purgeD)
333END(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 */
343ENTRY(xscale_cache_clean_minidata)
344	ldr	r2, .Lxscale_minidata_clean_addr
345	ldmia	r2, {r0, r1}
3461:	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)
353END(xscale_cache_clean_minidata)
354
355ENTRY(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)
362END(xscale_cache_purgeID_E)
363
364ENTRY(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)
370END(xscale_cache_purgeD_E)
371
372/*
373 * Soft functions
374 */
375/* xscale_cache_syncI is identical to xscale_cache_purgeID */
376
377ENTRY(xscale_cache_cleanID_rng)
378ENTRY(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
3861:	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)
396END(xscale_cache_cleanID_rng)
397END(xscale_cache_cleanD_rng)
398
399ENTRY(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
4071:	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)
419END(xscale_cache_purgeID_rng)
420
421ENTRY(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
4291:	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)
440END(xscale_cache_purgeD_rng)
441
442ENTRY(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
4501:	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)
461END(xscale_cache_syncI_rng)
462
463ENTRY(xscale_cache_flushD_rng)
464	and	r2, r0, #0x1f
465	add	r1, r1, r2
466	bic	r0, r0, #0x1f
467
4681:	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)
476END(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 */
487ENTRY(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)
502END(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 */
513ENTRY(xscale_cpu_sleep)
514	tst	r0, #0x00000000
515	bne	1f
516	mov	r0, #0x1
517	mcr	p14, 0, r0, c7, c0, 0
518
5191:
520	RET
521END(xscale_cpu_sleep)
522
523