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 */
75251866Sscottl
76171617Scognet#include <machine/asm.h>
77171617Scognet__FBSDID("$FreeBSD$");
78171617Scognet
79171617Scognet/*
80171617Scognet * Size of the XScale core D-cache.
81171617Scognet */
82171617Scognet#define	DCACHE_SIZE		0x00008000
83171617Scognet
84171617Scognet.Lblock_userspace_access:
85171617Scognet	.word	_C_LABEL(block_userspace_access)
86171617Scognet
87171617Scognet/*
88171617Scognet * CPWAIT -- Canonical method to wait for CP15 update.
89171617Scognet * From: Intel 80200 manual, section 2.3.3.
90171617Scognet *
91171617Scognet * NOTE: Clobbers the specified temp reg.
92171617Scognet */
93171617Scognet#define	CPWAIT_BRANCH							 \
94171617Scognet	sub	pc, pc, #4
95171617Scognet
96171617Scognet#define	CPWAIT(tmp)							 \
97171617Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
98171617Scognet	mov	tmp, tmp		/* wait for it to complete */	;\
99171617Scognet	CPWAIT_BRANCH			/* branch to next insn */
100171617Scognet
101171617Scognet#define	CPWAIT_AND_RETURN_SHIFTER	lsr #32
102171617Scognet
103171617Scognet#define	CPWAIT_AND_RETURN(tmp)						 \
104171617Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
105171617Scognet	/* Wait for it to complete and branch to the return address */	 \
106171617Scognet	sub	pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER
107171617Scognet
108171617Scognet#define ARM_USE_L2_CACHE
109171617Scognet
110171617Scognet#define L2_CACHE_SIZE		0x80000
111171617Scognet#define L2_CACHE_WAYS		8
112171617Scognet#define L2_CACHE_LINE_SIZE	32
113171617Scognet#define L2_CACHE_SETS		(L2_CACHE_SIZE / \
114171617Scognet    (L2_CACHE_WAYS * L2_CACHE_LINE_SIZE))
115171617Scognet
116171617Scognet#define L1_DCACHE_SIZE		32 * 1024
117171617Scognet#define L1_DCACHE_WAYS		4
118171617Scognet#define L1_DCACHE_LINE_SIZE	32
119171617Scognet#define L1_DCACHE_SETS		(L1_DCACHE_SIZE / \
120171617Scognet    (L1_DCACHE_WAYS * L1_DCACHE_LINE_SIZE))
121171617Scognet#ifdef CACHE_CLEAN_BLOCK_INTR
122171617Scognet#define	XSCALE_CACHE_CLEAN_BLOCK					\
123171617Scognet	stmfd	sp!, {r4}					;	\
124171617Scognet	mrs	r4, cpsr_all					;	\
125171617Scognet	orr	r0, r4, #(I32_bit | F32_bit)			;	\
126171617Scognet	msr	cpsr_all, r0
127171617Scognet
128171617Scognet#define	XSCALE_CACHE_CLEAN_UNBLOCK					\
129171617Scognet	msr	cpsr_all, r4					;	\
130171617Scognet	ldmfd	sp!, {r4}
131171617Scognet#else
132171617Scognet#define	XSCALE_CACHE_CLEAN_BLOCK					\
133171617Scognet	stmfd	sp!, {r4}					;	\
134171617Scognet	ldr	r4, .Lblock_userspace_access			;	\
135171617Scognet	ldr	ip, [r4]					;	\
136171617Scognet	orr	r0, ip, #1					;	\
137171617Scognet	str	r0, [r4]
138171617Scognet
139171617Scognet#define	XSCALE_CACHE_CLEAN_UNBLOCK					\
140171617Scognet	str	ip, [r3]					;	\
141171617Scognet	ldmfd	sp!, {r4}
142171617Scognet#endif /* CACHE_CLEAN_BLOCK_INTR */
143171617Scognet
144171617Scognet
145171617ScognetENTRY_NP(xscalec3_cache_syncI)
146171617ScognetENTRY_NP(xscalec3_cache_purgeID)
147171617Scognet	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache (D cleaned below) */
148171617ScognetENTRY_NP(xscalec3_cache_cleanID)
149171617ScognetENTRY_NP(xscalec3_cache_purgeD)
150171617ScognetENTRY(xscalec3_cache_cleanD)
151171617Scognet
152171617Scognet	XSCALE_CACHE_CLEAN_BLOCK
153171617Scognet	mov	r0, #0
154171617Scognet1:
155171617Scognet	mov	r1, r0, asl #30
156171617Scognet	mov	r2, #0
157171617Scognet2:
158171617Scognet	orr	r3, r1, r2, asl #5
159171617Scognet	mcr	p15, 0, r3, c7, c14, 2	/* clean and invalidate */
160171617Scognet	add	r2, r2, #1
161171617Scognet	cmp	r2, #L1_DCACHE_SETS
162171617Scognet	bne	2b
163171617Scognet	add	r0, r0, #1
164171617Scognet	cmp	r0, #4
165171617Scognet	bne	1b
166171617Scognet	CPWAIT(r0)
167171617Scognet	XSCALE_CACHE_CLEAN_UNBLOCK
168171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
169171617Scognet
170171617Scognet	RET
171171617Scognet
172171617ScognetENTRY(xscalec3_cache_purgeID_rng)
173171617Scognet
174171617Scognet	cmp	r1, #0x4000
175171617Scognet	bcs	_C_LABEL(xscalec3_cache_cleanID)
176171617Scognet	and	r2, r0, #0x1f
177171617Scognet	add	r1, r1, r2
178171617Scognet	bic	r0, r0, #0x1f
179171617Scognet
180171617Scognet1:	mcr	p15, 0, r0, c7, c14, 1	/* clean/invalidate L1 D cache entry */
181171617Scognet	nop
182171617Scognet	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
183171617Scognet	add	r0, r0, #32
184171617Scognet	subs	r1, r1, #32
185171617Scognet	bhi	1b
186171617Scognet
187171617Scognet	CPWAIT(r0)
188171617Scognet
189171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
190171617Scognet
191171617Scognet	CPWAIT_AND_RETURN(r0)
192171617Scognet
193171617ScognetENTRY(xscalec3_cache_syncI_rng)
194171617Scognet	cmp	r1, #0x4000
195171617Scognet	bcs	_C_LABEL(xscalec3_cache_syncI)
196171617Scognet
197171617Scognet	and	r2, r0, #0x1f
198171617Scognet	add	r1, r1, r2
199171617Scognet	bic	r0, r0, #0x1f
200171617Scognet
201171617Scognet1:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
202171617Scognet	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
203171617Scognet	add	r0, r0, #32
204171617Scognet	subs	r1, r1, #32
205171617Scognet	bhi	1b
206171617Scognet
207171617Scognet	CPWAIT(r0)
208171617Scognet
209171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
210171617Scognet
211171617Scognet	CPWAIT_AND_RETURN(r0)
212171617Scognet
213171617ScognetENTRY(xscalec3_cache_purgeD_rng)
214171617Scognet
215171617Scognet	cmp	r1, #0x4000
216171617Scognet	bcs	_C_LABEL(xscalec3_cache_cleanID)
217171617Scognet	and	r2, r0, #0x1f
218171617Scognet	add	r1, r1, r2
219171617Scognet	bic	r0, r0, #0x1f
220171617Scognet
221171617Scognet1:	mcr	p15, 0, r0, c7, c14, 1	/* Clean and invalidate D cache entry */
222171617Scognet	add	r0, r0, #32
223171617Scognet	subs	r1, r1, #32
224171617Scognet	bhi	1b
225171617Scognet
226171617Scognet	CPWAIT(r0)
227171617Scognet
228171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
229171617Scognet
230171617Scognet	CPWAIT_AND_RETURN(r0)
231171617ScognetENTRY(xscalec3_cache_cleanID_rng)
232171617ScognetENTRY(xscalec3_cache_cleanD_rng)
233171617Scognet
234171617Scognet	cmp	r1, #0x4000
235171617Scognet	bcs	_C_LABEL(xscalec3_cache_cleanID)
236171617Scognet	and	r2, r0, #0x1f
237171617Scognet	add	r1, r1, r2
238171617Scognet	bic	r0, r0, #0x1f
239171617Scognet
240171617Scognet1:	mcr	p15, 0, r0, c7, c10, 1	/* clean L1 D cache entry */
241171617Scognet	nop
242171617Scognet	add	r0, r0, #32
243171617Scognet	subs	r1, r1, #32
244171617Scognet	bhi	1b
245171617Scognet
246171617Scognet	CPWAIT(r0)
247171617Scognet
248171617Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
249171617Scognet
250171617Scognet	CPWAIT_AND_RETURN(r0)
251171617Scognet
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
274171617Scognet
275171617ScognetENTRY(xscalec3_l2cache_clean_rng)
276171617Scognet	mcr	p15, 0, r0, c7, c10, 5	/* Data memory barrier */
277171617Scognet
278171617Scognet	and	r2, r0, #0x1f
279171617Scognet	add	r1, r1, r2
280171617Scognet	bic	r0, r0, #0x1f
281171617Scognet
282171617Scognet1:	mcr	p15, 1, r0, c7, c11, 1	/* Clean L2 D cache entry */
283171617Scognet	add	r0, r0, #32
284171617Scognet	subs	r1, r1, #32
285171617Scognet	bhi	1b
286171617Scognet
287171617Scognet
288171617Scognet	CPWAIT(r0)
289171617Scognet
290171617Scognet	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
291171617Scognet	mcr	p15, 0, r0, c7, c10, 5
292171617Scognet
293171617Scognet	CPWAIT_AND_RETURN(r0)
294171617Scognet
295171617ScognetENTRY(xscalec3_l2cache_purge_rng)
296171617Scognet
297171617Scognet	mcr	p15, 0, r0, c7, c10, 5	/* Data memory barrier */
298171617Scognet
299171617Scognet	and	r2, r0, #0x1f
300171617Scognet	add	r1, r1, r2
301171617Scognet	bic	r0, r0, #0x1f
302171617Scognet
303171617Scognet1:	mcr	p15, 1, r0, c7, c11, 1	/* Clean L2 D cache entry */
304171617Scognet	mcr	p15, 1, r0, c7, c7, 1   /* Invalidate L2 D cache entry */
305171617Scognet	add	r0, r0, #32
306171617Scognet	subs	r1, r1, #32
307171617Scognet	bhi	1b
308171617Scognet
309171617Scognet	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
310171617Scognet	mcr	p15, 0, r0, c7, c10, 5
311171617Scognet
312171617Scognet	CPWAIT_AND_RETURN(r0)
313171617Scognet
314171617ScognetENTRY(xscalec3_l2cache_flush_rng)
315171617Scognet	mcr	p15, 0, r0, c7, c10, 5	/* Data memory barrier */
316171617Scognet
317171617Scognet	and	r2, r0, #0x1f
318171617Scognet	add	r1, r1, r2
319171617Scognet	bic	r0, r0, #0x1f
320171617Scognet
321171617Scognet1:	mcr	p15, 1, r0, c7, c7, 1   /* Invalidate L2 cache line */
322171617Scognet	add	r0, r0, #32
323171617Scognet	subs	r1, r1, #32
324171617Scognet	bhi	1b
325171617Scognet	mcr	p15, 0, r0, c7, c10, 4		@ data write barrier
326171617Scognet	mcr	p15, 0, r0, c7, c10, 5
327171617Scognet	CPWAIT_AND_RETURN(r0)
328171617Scognet/*
329171617Scognet * Functions to set the MMU Translation Table Base register
330171617Scognet *
331171617Scognet * We need to clean and flush the cache as it uses virtual
332171617Scognet * addresses that are about to change.
333171617Scognet */
334171617ScognetENTRY(xscalec3_setttb)
335171617Scognet#ifdef CACHE_CLEAN_BLOCK_INTR
336171617Scognet	mrs	r3, cpsr_all
337171617Scognet	orr	r1, r3, #(I32_bit | F32_bit)
338171617Scognet	msr	cpsr_all, r1
339171617Scognet#else
340171617Scognet	ldr	r3, .Lblock_userspace_access
341171617Scognet	ldr	r2, [r3]
342251866Sscottl	orr	r1, r2, #1
343171617Scognet	str	r1, [r3]
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
357251866Sscottl	/* 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
366171617Scognet	msr	cpsr_all, r3
367171617Scognet#else
368171617Scognet	str	r2, [r3]
369171617Scognet#endif
370171617Scognet	RET
371171617Scognet
372171617Scognet/*
373171617Scognet * Context switch.
374171617Scognet *
375171617Scognet * These is the CPU-specific parts of the context switcher cpu_switch()
376171617Scognet * These functions actually perform the TTB reload.
377171617Scognet *
378171617Scognet * NOTE: Special calling convention
379171617Scognet *	r1, r4-r13 must be preserved
380171617Scognet */
381171617ScognetENTRY(xscalec3_context_switch)
382171617Scognet	/*
383171617Scognet	 * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this.
384171617Scognet	 * Thus the data cache will contain only kernel data and the
385171617Scognet	 * instruction cache will contain only kernel code, and all
386171617Scognet	 * kernel mappings are shared by all processes.
387171617Scognet	 */
388171617Scognet#ifdef ARM_USE_L2_CACHE
389171617Scognet	orr	r0, r0, #0x18	/* Cache the page table in L2 */
390171617Scognet#endif
391171617Scognet	/* Write the TTB */
392171617Scognet	mcr	p15, 0, r0, c2, c0, 0
393171617Scognet
394171617Scognet	/* If we have updated the TTB we must flush the TLB */
395171617Scognet	mcr	p15, 0, r0, c8, c7, 0	/* flush the I+D tlb */
396171617Scognet
397171617Scognet	CPWAIT_AND_RETURN(r0)
398