xref: /netbsd-src/sys/arch/arm/arm/cpufunc_asm_xscale.S (revision beb9bdb00e5421761976d5c277c0da84fd703f9b)
1/*	$NetBSD: cpufunc_asm_xscale.S,v 1.25 2022/10/20 06:58:38 skrll 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 "assym.h"
75#include <arm/asm.h>
76#include <arm/locore.h>
77
78/*
79 * Size of the XScale core D-cache.
80 */
81#define	XSCALE_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
138	orr	r2, r3, #(I32_bit | F32_bit)
139	msr	cpsr_all, r2
140#else
141	ldr	r3, .Lblock_userspace_access
142	ldr	r2, [r3]
143	orr	ip, r2, #1
144	str	ip, [r3]
145#endif
146	cmp	r1, #0			/* flush cache/TLB? */
147	beq	1f			/*   nope, so don't */
148	stmfd	sp!, {r0-r3, lr}
149	bl	_C_LABEL(xscale_cache_cleanID)
150	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I$ and BTB */
151	mcr	p15, 0, r0, c7, c10, 4	/* drain write and fill buffer */
152
153	CPWAIT(r0)
154
155	ldmfd	sp!, {r0-r3, lr}
156	cmp	r0, #1
157
1581:	/* Write the TTB */
159	mcr	p15, 0, r0, c2, c0, 0
160
161	beq	2f			/*   nope, so don't */
162
163	/* If we have updated the TTB we must flush the TLB */
164	mcr	p15, 0, r0, c8, c7, 0	/* invalidate I+D TLB */
165
166	/* The cleanID above means we only need to flush the I cache here */
167	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I$ and BTB */
168
169	CPWAIT(r0)
170
1712:
172#ifdef CACHE_CLEAN_BLOCK_INTR
173	msr	cpsr_all, r3
174#else
175	str	r2, [r3]
176#endif
177	RET
178END(xscale_setttb)
179
180/*
181 * TLB functions
182 *
183 * Note: We don't need to worry about issuing a CPWAIT after
184 * TLB operations, because we expect a pmap_update() to follow.
185 */
186ENTRY(xscale_tlb_flushID_SE)
187	mcr	p15, 0, r0, c8, c6, 1	/* flush D tlb single entry */
188	mcr	p15, 0, r0, c8, c5, 1	/* flush I tlb single entry */
189#if PAGE_SIZE == 2 * L2_S_SIZE
190	add	r0, r0, #L2_S_SIZE
191	mcr	p15, 0, r0, c8, c6, 1	/* flush D tlb single entry */
192	mcr	p15, 0, r0, c8, c5, 1	/* flush I tlb single entry */
193#endif
194	RET
195END(xscale_tlb_flushID_SE)
196
197/*
198 * Cache functions
199 */
200ENTRY(xscale_cache_flushID)
201	mcr	p15, 0, r0, c7, c7, 0	/* flush I+D cache */
202	CPWAIT_AND_RETURN(r0)
203END(xscale_cache_flushID)
204
205ENTRY(xscale_cache_flushI)
206	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache */
207	CPWAIT_AND_RETURN(r0)
208END(xscale_cache_flushI)
209
210ENTRY(xscale_cache_flushD)
211	mcr	p15, 0, r0, c7, c6, 0	/* flush D cache */
212	CPWAIT_AND_RETURN(r0)
213END(xscale_cache_flushD)
214
215ENTRY(xscale_cache_flushI_SE)
216	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
217	CPWAIT_AND_RETURN(r0)
218END(xscale_cache_flushI_SE)
219
220ENTRY(xscale_cache_flushD_SE)
221	/*
222	 * Errata (rev < 2): Must clean-dcache-line to an address
223	 * before invalidate-dcache-line to an address, or dirty
224	 * bits will not be cleared in the dcache array.
225	 */
226	mcr	p15, 0, r0, c7, c10, 1
227	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
228	CPWAIT_AND_RETURN(r0)
229END(xscale_cache_flushD_SE)
230
231ENTRY(xscale_cache_cleanD_E)
232	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
233	CPWAIT_AND_RETURN(r0)
234END(xscale_cache_cleanD_E)
235
236/*
237 * Information for the XScale cache clean/purge functions:
238 *
239 *	* Virtual address of the memory region to use
240 *	* Size of memory region
241 *
242 * Note the virtual address for the Data cache clean operation
243 * does not need to be backed by physical memory, since no loads
244 * will actually be performed by the allocate-line operation.
245 *
246 * Note that the Mini-Data cache MUST be cleaned by executing
247 * loads from memory mapped into a region reserved exclusively
248 * for cleaning of the Mini-Data cache.
249 */
250	.data
251
252	.global	_C_LABEL(xscale_cache_clean_addr)
253_C_LABEL(xscale_cache_clean_addr):
254	.word	0x00000000
255
256	.global	_C_LABEL(xscale_cache_clean_size)
257_C_LABEL(xscale_cache_clean_size):
258	.word	XSCALE_DCACHE_SIZE
259
260	.global	_C_LABEL(xscale_minidata_clean_addr)
261_C_LABEL(xscale_minidata_clean_addr):
262	.word	0x00000000
263
264	.global	_C_LABEL(xscale_minidata_clean_size)
265_C_LABEL(xscale_minidata_clean_size):
266	.word	0x00000800
267
268	.text
269
270.Lxscale_cache_clean_addr:
271	.word	_C_LABEL(xscale_cache_clean_addr)
272.Lxscale_cache_clean_size:
273	.word	_C_LABEL(xscale_cache_clean_size)
274
275.Lxscale_minidata_clean_addr:
276	.word	_C_LABEL(xscale_minidata_clean_addr)
277.Lxscale_minidata_clean_size:
278	.word	_C_LABEL(xscale_minidata_clean_size)
279
280#ifdef CACHE_CLEAN_BLOCK_INTR
281#define	XSCALE_CACHE_CLEAN_BLOCK					\
282	mrs	r3, cpsr					;	\
283	orr	r0, r3, #(I32_bit | F32_bit)			;	\
284	msr	cpsr_all, r0
285
286#define	XSCALE_CACHE_CLEAN_UNBLOCK					\
287	msr	cpsr_all, r3
288#else
289#define	XSCALE_CACHE_CLEAN_BLOCK					\
290	ldr	r3, .Lblock_userspace_access			;	\
291	ldr	ip, [r3]					;	\
292	orr	r0, ip, #1					;	\
293	str	r0, [r3]
294
295#define	XSCALE_CACHE_CLEAN_UNBLOCK					\
296	str	ip, [r3]
297#endif /* CACHE_CLEAN_BLOCK_INTR */
298
299#define	XSCALE_CACHE_CLEAN_PROLOGUE					\
300	XSCALE_CACHE_CLEAN_BLOCK				;	\
301	ldr	r2, .Lxscale_cache_clean_addr			;	\
302	ldmia	r2, {r0, r1}					;	\
303	/*								\
304	 * BUG ALERT!							\
305	 *								\
306	 * The XScale core has a strange cache eviction bug, which	\
307	 * requires us to use 2x the cache size for the cache clean	\
308	 * and for that area to be aligned to 2 * cache size.		\
309	 *								\
310	 * The work-around is to use 2 areas for cache clean, and to	\
311	 * alternate between them whenever this is done.  No one knows	\
312	 * why the work-around works (mmm!).				\
313	 */								\
314	eor	r0, r0, #(XSCALE_DCACHE_SIZE)			;	\
315	str	r0, [r2]					;	\
316	add	r0, r0, r1
317
318#define	XSCALE_CACHE_CLEAN_EPILOGUE					\
319	XSCALE_CACHE_CLEAN_UNBLOCK
320
321ENTRY_NP(xscale_cache_syncI)
322ENTRY_NP(xscale_cache_purgeID)
323	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache (D cleaned below) */
324ENTRY_NP(xscale_cache_cleanID)
325ENTRY_NP(xscale_cache_purgeD)
326ENTRY(xscale_cache_cleanD)
327	XSCALE_CACHE_CLEAN_PROLOGUE
328
3291:	subs	r0, r0, #32
330	mcr	p15, 0, r0, c7, c2, 5	/* allocate cache line */
331	subs	r1, r1, #32
332	bne	1b
333
334	CPWAIT(r0)
335
336	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
337
338	CPWAIT(r0)
339
340	XSCALE_CACHE_CLEAN_EPILOGUE
341	RET
342END(xscale_cache_cleanD)
343END(xscale_cache_purgeD)
344END(xscale_cache_cleanID)
345END(xscale_cache_purgeID)
346END(xscale_cache_syncI)
347
348/*
349 * Clean the mini-data cache.
350 *
351 * It's expected that we only use the mini-data cache for
352 * kernel addresses, so there is no need to purge it on
353 * context switch, and no need to prevent userspace access
354 * while we clean it.
355 */
356ENTRY(xscale_cache_clean_minidata)
357	ldr	r2, .Lxscale_minidata_clean_addr
358	ldmia	r2, {r0, r1}
3591:	ldr	r3, [r0], #32
360	subs	r1, r1, #32
361	bne	1b
362
363	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
364
365	CPWAIT_AND_RETURN(r1)
366END(xscale_cache_clean_minidata)
367
368ENTRY(xscale_cache_purgeID_E)
369	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
370	CPWAIT(r1)
371	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
372	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
373	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
374	CPWAIT_AND_RETURN(r1)
375END(xscale_cache_purgeID_E)
376
377ENTRY(xscale_cache_purgeD_E)
378	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
379	CPWAIT(r1)
380	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
381	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
382	CPWAIT_AND_RETURN(r1)
383END(xscale_cache_purgeD_E)
384
385/*
386 * Soft functions
387 */
388/* xscale_cache_syncI is identical to xscale_cache_purgeID */
389
390ENTRY(xscale_cache_cleanID_rng)
391ENTRY(xscale_cache_cleanD_rng)
392	cmp	r1, #0x4000
393	bcs	_C_LABEL(xscale_cache_cleanID)
394
395	and	r2, r0, #0x1f
396	add	r1, r1, r2
397	bic	r0, r0, #0x1f
398
3991:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
400	add	r0, r0, #32
401	subs	r1, r1, #32
402	bhi	1b
403
404	CPWAIT(r0)
405
406	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
407
408	CPWAIT_AND_RETURN(r0)
409END(xscale_cache_cleanD_rng)
410END(xscale_cache_cleanID_rng)
411
412ENTRY(xscale_cache_purgeID_rng)
413	cmp	r1, #0x4000
414	bcs	_C_LABEL(xscale_cache_purgeID)
415
416	and	r2, r0, #0x1f
417	add	r1, r1, r2
418	bic	r0, r0, #0x1f
419
4201:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
421	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
422	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
423	add	r0, r0, #32
424	subs	r1, r1, #32
425	bhi	1b
426
427	CPWAIT(r0)
428
429	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
430
431	CPWAIT_AND_RETURN(r0)
432END(xscale_cache_purgeID_rng)
433
434ENTRY(xscale_cache_purgeD_rng)
435	cmp	r1, #0x4000
436	bcs	_C_LABEL(xscale_cache_purgeD)
437
438	and	r2, r0, #0x1f
439	add	r1, r1, r2
440	bic	r0, r0, #0x1f
441
4421:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
443	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
444	add	r0, r0, #32
445	subs	r1, r1, #32
446	bhi	1b
447
448	CPWAIT(r0)
449
450	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
451
452	CPWAIT_AND_RETURN(r0)
453END(xscale_cache_purgeD_rng)
454
455ENTRY(xscale_cache_syncI_rng)
456	cmp	r1, #0x4000
457	bcs	_C_LABEL(xscale_cache_syncI)
458
459	and	r2, r0, #0x1f
460	add	r1, r1, r2
461	bic	r0, r0, #0x1f
462
4631:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
464	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
465	add	r0, r0, #32
466	subs	r1, r1, #32
467	bhi	1b
468
469	CPWAIT(r0)
470
471	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
472
473	CPWAIT_AND_RETURN(r0)
474END(xscale_cache_syncI_rng)
475
476ENTRY(xscale_cache_flushD_rng)
477	and	r2, r0, #0x1f
478	add	r1, r1, r2
479	bic	r0, r0, #0x1f
480
4811:	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
482	add	r0, r0, #32
483	subs	r1, r1, #32
484	bhi	1b
485
486	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
487
488	CPWAIT_AND_RETURN(r0)
489END(xscale_cache_flushD_rng)
490
491/*
492 * Context switch.
493 *
494 * These are the CPU-specific parts of the context switcher cpu_switch()
495 * These functions actually perform the TTB reload.
496 */
497ENTRY(xscale_context_switch)
498	/*
499	 * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this.
500	 * Thus the data cache will contain only kernel data and the
501	 * instruction cache will contain only kernel code, and all
502	 * kernel mappings are shared by all processes.
503	 */
504
505	/* Write the TTB */
506	mcr	p15, 0, r0, c2, c0, 0
507
508	/* If we have updated the TTB we must flush the TLB */
509	mcr	p15, 0, r0, c8, c7, 0	/* flush the I+D tlb */
510
511	CPWAIT_AND_RETURN(r0)
512END(xscale_context_switch)
513
514/*
515 * xscale_cpu_sleep
516 *
517 * This is called when there is nothing on any of the run queues.
518 * We go into IDLE mode so that any IRQ or FIQ will awaken us.
519 *
520 * If this is called with anything other than ARM_SLEEP_MODE_IDLE,
521 * ignore it.
522 */
523ENTRY(xscale_cpu_sleep)
524	tst	r0, #0x00000000
525	RETc(ne)
526	mov	r0, #0x1
527	mcr	p14, 0, r0, c7, c0, 0
528	RET
529END(xscale_cpu_sleep)
530