1171617Scognet/*	$NetBSD: cpufunc_asm_xscale.S,v 1.16 2002/08/17 16:36:32 thorpej Exp $	*/
2171617Scognet
3171617Scognet/*-
4171617Scognet * Copyright (c) 2007 Olivier Houchard
5171617Scognet * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
6171617Scognet * All rights reserved.
7171617Scognet *
8171617Scognet * Written by Allen Briggs and Jason R. Thorpe for Wasabi Systems, Inc.
9171617Scognet *
10171617Scognet * Redistribution and use in source and binary forms, with or without
11171617Scognet * modification, are permitted provided that the following conditions
12171617Scognet * are met:
13171617Scognet * 1. Redistributions of source code must retain the above copyright
14171617Scognet *    notice, this list of conditions and the following disclaimer.
15171617Scognet * 2. Redistributions in binary form must reproduce the above copyright
16171617Scognet *    notice, this list of conditions and the following disclaimer in the
17171617Scognet *    documentation and/or other materials provided with the distribution.
18171617Scognet * 3. All advertising materials mentioning features or use of this software
19171617Scognet *    must display the following acknowledgement:
20171617Scognet *	This product includes software developed for the NetBSD Project by
21171617Scognet *	Wasabi Systems, Inc.
22171617Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23171617Scognet *    or promote products derived from this software without specific prior
24171617Scognet *    written permission.
25171617Scognet *
26171617Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27171617Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28171617Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29171617Scognet * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
30171617Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31171617Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32171617Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33171617Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34171617Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35171617Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36171617Scognet * POSSIBILITY OF SUCH DAMAGE.
37171617Scognet *
38171617Scognet */
39171617Scognet
40171617Scognet/*-
41171617Scognet * Copyright (c) 2001 Matt Thomas.
42171617Scognet * Copyright (c) 1997,1998 Mark Brinicombe.
43171617Scognet * Copyright (c) 1997 Causality Limited
44171617Scognet * All rights reserved.
45171617Scognet *
46171617Scognet * Redistribution and use in source and binary forms, with or without
47171617Scognet * modification, are permitted provided that the following conditions
48171617Scognet * are met:
49171617Scognet * 1. Redistributions of source code must retain the above copyright
50171617Scognet *    notice, this list of conditions and the following disclaimer.
51171617Scognet * 2. Redistributions in binary form must reproduce the above copyright
52171617Scognet *    notice, this list of conditions and the following disclaimer in the
53171617Scognet *    documentation and/or other materials provided with the distribution.
54171617Scognet * 3. All advertising materials mentioning features or use of this software
55171617Scognet *    must display the following acknowledgement:
56171617Scognet *	This product includes software developed by Causality Limited.
57171617Scognet * 4. The name of Causality Limited may not be used to endorse or promote
58171617Scognet *    products derived from this software without specific prior written
59171617Scognet *    permission.
60171617Scognet *
61171617Scognet * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
62171617Scognet * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63171617Scognet * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
64171617Scognet * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
65171617Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
66171617Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
67171617Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68171617Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69171617Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70171617Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71171617Scognet * SUCH DAMAGE.
72171617Scognet *
73171617Scognet * XScale core 3 assembly functions for CPU / MMU / TLB specific operations
74171617Scognet */
75236991Simp
76271398Sandrew#include <machine/armreg.h>
77171617Scognet#include <machine/asm.h>
78171617Scognet__FBSDID("$FreeBSD: stable/11/sys/arm/arm/cpufunc_asm_xscale_c3.S 331890 2018-04-02 22:02:49Z gonzo $");
79171617Scognet
80171617Scognet/*
81171617Scognet * Size of the XScale core D-cache.
82171617Scognet */
83171617Scognet#define	DCACHE_SIZE		0x00008000
84171617Scognet
85171617Scognet/*
86171617Scognet * CPWAIT -- Canonical method to wait for CP15 update.
87171617Scognet * From: Intel 80200 manual, section 2.3.3.
88171617Scognet *
89171617Scognet * NOTE: Clobbers the specified temp reg.
90171617Scognet */
91171617Scognet#define	CPWAIT_BRANCH							 \
92171617Scognet	sub	pc, pc, #4
93171617Scognet
94171617Scognet#define	CPWAIT(tmp)							 \
95171617Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
96171617Scognet	mov	tmp, tmp		/* wait for it to complete */	;\
97171617Scognet	CPWAIT_BRANCH			/* branch to next insn */
98171617Scognet
99171617Scognet#define	CPWAIT_AND_RETURN_SHIFTER	lsr #32
100171617Scognet
101171617Scognet#define	CPWAIT_AND_RETURN(tmp)						 \
102171617Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
103171617Scognet	/* Wait for it to complete and branch to the return address */	 \
104171617Scognet	sub	pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER
105171617Scognet
106171617Scognet#define ARM_USE_L2_CACHE
107171617Scognet
108171617Scognet#define L2_CACHE_SIZE		0x80000
109171617Scognet#define L2_CACHE_WAYS		8
110171617Scognet#define L2_CACHE_LINE_SIZE	32
111171617Scognet#define L2_CACHE_SETS		(L2_CACHE_SIZE / \
112171617Scognet    (L2_CACHE_WAYS * L2_CACHE_LINE_SIZE))
113171617Scognet
114171617Scognet#define L1_DCACHE_SIZE		32 * 1024
115171617Scognet#define L1_DCACHE_WAYS		4
116171617Scognet#define L1_DCACHE_LINE_SIZE	32
117171617Scognet#define L1_DCACHE_SETS		(L1_DCACHE_SIZE / \
118171617Scognet    (L1_DCACHE_WAYS * L1_DCACHE_LINE_SIZE))
119171617Scognet#ifdef CACHE_CLEAN_BLOCK_INTR
120171617Scognet#define	XSCALE_CACHE_CLEAN_BLOCK					\
121171617Scognet	stmfd	sp!, {r4}					;	\
122261393Sian	mrs	r4, cpsr					;	\
123271398Sandrew	orr	r0, r4, #(PSR_I | PSR_F)			;	\
124261393Sian	msr	cpsr_fsxc, r0
125171617Scognet
126171617Scognet#define	XSCALE_CACHE_CLEAN_UNBLOCK					\
127261393Sian	msr	cpsr_fsxc, r4					;	\
128171617Scognet	ldmfd	sp!, {r4}
129171617Scognet#else
130295267Smmel#define	XSCALE_CACHE_CLEAN_BLOCK
131295267Smmel#define	XSCALE_CACHE_CLEAN_UNBLOCK
132171617Scognet#endif /* CACHE_CLEAN_BLOCK_INTR */
133171617Scognet
134171617Scognet
135171617ScognetENTRY_NP(xscalec3_cache_syncI)
136269390SianEENTRY_NP(xscalec3_cache_purgeID)
137171617Scognet	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache (D cleaned below) */
138269390SianEENTRY_NP(xscalec3_cache_cleanID)
139269390SianEENTRY_NP(xscalec3_cache_purgeD)
140269390SianEENTRY(xscalec3_cache_cleanD)
141171617Scognet
142171617Scognet	XSCALE_CACHE_CLEAN_BLOCK
143171617Scognet	mov	r0, #0
144171617Scognet1:
145171617Scognet	mov	r1, r0, asl #30
146171617Scognet	mov	r2, #0
147171617Scognet2:
148171617Scognet	orr	r3, r1, r2, asl #5
149171617Scognet	mcr	p15, 0, r3, c7, c14, 2	/* clean and invalidate */
150171617Scognet	add	r2, r2, #1
151171617Scognet	cmp	r2, #L1_DCACHE_SETS
152171617Scognet	bne	2b
153171617Scognet	add	r0, r0, #1
154171617Scognet	cmp	r0, #4
155171617Scognet	bne	1b
156171617Scognet	CPWAIT(r0)
157171617Scognet	XSCALE_CACHE_CLEAN_UNBLOCK
158171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
159171617Scognet
160171617Scognet	RET
161269390SianEEND(xscalec3_cache_purgeID)
162269390SianEEND(xscalec3_cache_cleanID)
163269390SianEEND(xscalec3_cache_purgeD)
164269390SianEEND(xscalec3_cache_cleanD)
165248361SandrewEND(xscalec3_cache_syncI)
166171617Scognet
167171617ScognetENTRY(xscalec3_cache_purgeID_rng)
168171617Scognet
169171617Scognet	cmp	r1, #0x4000
170171617Scognet	bcs	_C_LABEL(xscalec3_cache_cleanID)
171171617Scognet	and	r2, r0, #0x1f
172171617Scognet	add	r1, r1, r2
173171617Scognet	bic	r0, r0, #0x1f
174171617Scognet
175171617Scognet1:	mcr	p15, 0, r0, c7, c14, 1	/* clean/invalidate L1 D cache entry */
176171617Scognet	nop
177171617Scognet	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
178171617Scognet	add	r0, r0, #32
179171617Scognet	subs	r1, r1, #32
180171617Scognet	bhi	1b
181171617Scognet
182171617Scognet	CPWAIT(r0)
183171617Scognet
184171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
185171617Scognet
186171617Scognet	CPWAIT_AND_RETURN(r0)
187248361SandrewEND(xscalec3_cache_purgeID_rng)
188171617Scognet
189171617ScognetENTRY(xscalec3_cache_syncI_rng)
190171617Scognet	cmp	r1, #0x4000
191171617Scognet	bcs	_C_LABEL(xscalec3_cache_syncI)
192171617Scognet
193171617Scognet	and	r2, r0, #0x1f
194171617Scognet	add	r1, r1, r2
195171617Scognet	bic	r0, r0, #0x1f
196171617Scognet
197171617Scognet1:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
198171617Scognet	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
199171617Scognet	add	r0, r0, #32
200171617Scognet	subs	r1, r1, #32
201171617Scognet	bhi	1b
202171617Scognet
203171617Scognet	CPWAIT(r0)
204171617Scognet
205171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
206171617Scognet
207171617Scognet	CPWAIT_AND_RETURN(r0)
208248361SandrewEND(xscalec3_cache_syncI_rng)
209283366Sandrew
210171617ScognetENTRY(xscalec3_cache_purgeD_rng)
211171617Scognet
212171617Scognet	cmp	r1, #0x4000
213171617Scognet	bcs	_C_LABEL(xscalec3_cache_cleanID)
214171617Scognet	and	r2, r0, #0x1f
215171617Scognet	add	r1, r1, r2
216171617Scognet	bic	r0, r0, #0x1f
217171617Scognet
218171617Scognet1:	mcr	p15, 0, r0, c7, c14, 1	/* Clean and invalidate D cache entry */
219171617Scognet	add	r0, r0, #32
220171617Scognet	subs	r1, r1, #32
221171617Scognet	bhi	1b
222171617Scognet
223171617Scognet	CPWAIT(r0)
224171617Scognet
225171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
226171617Scognet
227171617Scognet	CPWAIT_AND_RETURN(r0)
228248361SandrewEND(xscalec3_cache_purgeD_rng)
229248361Sandrew
230171617ScognetENTRY(xscalec3_cache_cleanID_rng)
231269390SianEENTRY(xscalec3_cache_cleanD_rng)
232171617Scognet
233171617Scognet	cmp	r1, #0x4000
234171617Scognet	bcs	_C_LABEL(xscalec3_cache_cleanID)
235171617Scognet	and	r2, r0, #0x1f
236171617Scognet	add	r1, r1, r2
237171617Scognet	bic	r0, r0, #0x1f
238171617Scognet
239171617Scognet1:	mcr	p15, 0, r0, c7, c10, 1	/* clean L1 D cache entry */
240171617Scognet	nop
241171617Scognet	add	r0, r0, #32
242171617Scognet	subs	r1, r1, #32
243171617Scognet	bhi	1b
244171617Scognet
245171617Scognet	CPWAIT(r0)
246171617Scognet
247171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
248171617Scognet
249171617Scognet	CPWAIT_AND_RETURN(r0)
250269390SianEEND(xscalec3_cache_cleanD_rng)
251248361SandrewEND(xscalec3_cache_cleanID_rng)
252171617Scognet
253171617ScognetENTRY(xscalec3_l2cache_purge)
254171617Scognet	/* Clean-up the L2 cache */
255171617Scognet	mcr	p15, 0, r0, c7, c10, 5	/* Data memory barrier */
256171617Scognet	mov	r0, #0
257171617Scognet1:
258171617Scognet	mov	r1, r0, asl #29
259171617Scognet	mov	r2, #0
260171617Scognet2:
261171617Scognet	orr	r3, r1, r2, asl #5
262171617Scognet	mcr	p15, 1, r3, c7, c15, 2
263171617Scognet	add	r2, r2, #1
264171617Scognet	cmp	r2, #L2_CACHE_SETS
265171617Scognet	bne	2b
266171617Scognet	add	r0, r0, #1
267171617Scognet	cmp	r0, #8
268171617Scognet	bne	1b
269171617Scognet	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
270171617Scognet
271171617Scognet	CPWAIT(r0)
272171617Scognet	mcr	p15, 0, r0, c7, c10, 5	/* Data memory barrier */
273171617Scognet	RET
274248361SandrewEND(xscalec3_l2cache_purge)
275171617Scognet
276171617ScognetENTRY(xscalec3_l2cache_clean_rng)
277171617Scognet	mcr	p15, 0, r0, c7, c10, 5	/* Data memory barrier */
278171617Scognet
279171617Scognet	and	r2, r0, #0x1f
280171617Scognet	add	r1, r1, r2
281171617Scognet	bic	r0, r0, #0x1f
282171617Scognet
283171617Scognet1:	mcr	p15, 1, r0, c7, c11, 1	/* Clean L2 D cache entry */
284171617Scognet	add	r0, r0, #32
285171617Scognet	subs	r1, r1, #32
286171617Scognet	bhi	1b
287171617Scognet
288171617Scognet
289171617Scognet	CPWAIT(r0)
290171617Scognet
291171617Scognet	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
292171617Scognet	mcr	p15, 0, r0, c7, c10, 5
293171617Scognet
294171617Scognet	CPWAIT_AND_RETURN(r0)
295248361SandrewEND(xscalec3_l2cache_clean_rng)
296171617Scognet
297171617ScognetENTRY(xscalec3_l2cache_purge_rng)
298171617Scognet
299171617Scognet	mcr	p15, 0, r0, c7, c10, 5	/* Data memory barrier */
300171617Scognet
301171617Scognet	and	r2, r0, #0x1f
302171617Scognet	add	r1, r1, r2
303171617Scognet	bic	r0, r0, #0x1f
304171617Scognet
305171617Scognet1:	mcr	p15, 1, r0, c7, c11, 1	/* Clean L2 D cache entry */
306171617Scognet	mcr	p15, 1, r0, c7, c7, 1   /* Invalidate L2 D cache entry */
307171617Scognet	add	r0, r0, #32
308171617Scognet	subs	r1, r1, #32
309171617Scognet	bhi	1b
310171617Scognet
311171617Scognet	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
312171617Scognet	mcr	p15, 0, r0, c7, c10, 5
313171617Scognet
314171617Scognet	CPWAIT_AND_RETURN(r0)
315248361SandrewEND(xscalec3_l2cache_purge_rng)
316171617Scognet
317171617ScognetENTRY(xscalec3_l2cache_flush_rng)
318171617Scognet	mcr	p15, 0, r0, c7, c10, 5	/* Data memory barrier */
319171617Scognet
320171617Scognet	and	r2, r0, #0x1f
321171617Scognet	add	r1, r1, r2
322171617Scognet	bic	r0, r0, #0x1f
323171617Scognet
324171617Scognet1:	mcr	p15, 1, r0, c7, c7, 1   /* Invalidate L2 cache line */
325171617Scognet	add	r0, r0, #32
326171617Scognet	subs	r1, r1, #32
327171617Scognet	bhi	1b
328171617Scognet	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
329171617Scognet	mcr	p15, 0, r0, c7, c10, 5
330171617Scognet	CPWAIT_AND_RETURN(r0)
331248361SandrewEND(xscalec3_l2cache_flush_rng)
332248361Sandrew
333171617Scognet/*
334171617Scognet * Functions to set the MMU Translation Table Base register
335171617Scognet *
336171617Scognet * We need to clean and flush the cache as it uses virtual
337171617Scognet * addresses that are about to change.
338171617Scognet */
339171617ScognetENTRY(xscalec3_setttb)
340171617Scognet#ifdef CACHE_CLEAN_BLOCK_INTR
341261393Sian	mrs	r3, cpsr
342271398Sandrew	orr	r1, r3, #(PSR_I | PSR_F)
343261393Sian	msr	cpsr_fsxc, r1
344171617Scognet#endif
345171617Scognet	stmfd	sp!, {r0-r3, lr}
346171617Scognet	bl	_C_LABEL(xscalec3_cache_cleanID)
347171617Scognet	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I$ and BTB */
348171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write and fill buffer */
349171617Scognet
350171617Scognet	CPWAIT(r0)
351171617Scognet
352171617Scognet	ldmfd	sp!, {r0-r3, lr}
353171617Scognet
354171617Scognet#ifdef ARM_USE_L2_CACHE
355171617Scognet	orr	r0, r0, #0x18	/* cache the page table in L2 */
356171617Scognet#endif
357236991Simp	/* Write the TTB */
358171617Scognet	mcr	p15, 0, r0, c2, c0, 0
359171617Scognet
360171617Scognet	/* If we have updated the TTB we must flush the TLB */
361171617Scognet	mcr	p15, 0, r0, c8, c7, 0	/* invalidate I+D TLB */
362171617Scognet
363171617Scognet	CPWAIT(r0)
364171617Scognet
365171617Scognet#ifdef CACHE_CLEAN_BLOCK_INTR
366261393Sian	msr	cpsr_fsxc, r3
367171617Scognet#endif
368171617Scognet	RET
369248361SandrewEND(xscalec3_setttb)
370171617Scognet
371171617Scognet/*
372171617Scognet * Context switch.
373171617Scognet *
374171617Scognet * These is the CPU-specific parts of the context switcher cpu_switch()
375171617Scognet * These functions actually perform the TTB reload.
376171617Scognet *
377171617Scognet * NOTE: Special calling convention
378171617Scognet *	r1, r4-r13 must be preserved
379171617Scognet */
380171617ScognetENTRY(xscalec3_context_switch)
381171617Scognet	/*
382171617Scognet	 * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this.
383171617Scognet	 * Thus the data cache will contain only kernel data and the
384171617Scognet	 * instruction cache will contain only kernel code, and all
385171617Scognet	 * kernel mappings are shared by all processes.
386171617Scognet	 */
387171617Scognet#ifdef ARM_USE_L2_CACHE
388171617Scognet	orr	r0, r0, #0x18	/* Cache the page table in L2 */
389171617Scognet#endif
390171617Scognet	/* Write the TTB */
391171617Scognet	mcr	p15, 0, r0, c2, c0, 0
392171617Scognet
393171617Scognet	/* If we have updated the TTB we must flush the TLB */
394171617Scognet	mcr	p15, 0, r0, c8, c7, 0	/* flush the I+D tlb */
395171617Scognet
396171617Scognet	CPWAIT_AND_RETURN(r0)
397248361SandrewEND(xscalec3_context_switch)
398248361Sandrew
399