1129198Scognet/*	$NetBSD: cpufunc_asm_xscale.S,v 1.16 2002/08/17 16:36:32 thorpej Exp $	*/
2129198Scognet
3139735Simp/*-
4129198Scognet * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
5129198Scognet * All rights reserved.
6129198Scognet *
7129198Scognet * Written by Allen Briggs and Jason R. Thorpe for Wasabi Systems, Inc.
8129198Scognet *
9129198Scognet * Redistribution and use in source and binary forms, with or without
10129198Scognet * modification, are permitted provided that the following conditions
11129198Scognet * are met:
12129198Scognet * 1. Redistributions of source code must retain the above copyright
13129198Scognet *    notice, this list of conditions and the following disclaimer.
14129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
15129198Scognet *    notice, this list of conditions and the following disclaimer in the
16129198Scognet *    documentation and/or other materials provided with the distribution.
17129198Scognet * 3. All advertising materials mentioning features or use of this software
18129198Scognet *    must display the following acknowledgement:
19129198Scognet *	This product includes software developed for the NetBSD Project by
20129198Scognet *	Wasabi Systems, Inc.
21129198Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22129198Scognet *    or promote products derived from this software without specific prior
23129198Scognet *    written permission.
24129198Scognet *
25129198Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27129198Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28129198Scognet * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29129198Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30129198Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31129198Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32129198Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33129198Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34129198Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35129198Scognet * POSSIBILITY OF SUCH DAMAGE.
36129198Scognet *
37129198Scognet */
38129198Scognet
39139735Simp/*-
40129198Scognet * Copyright (c) 2001 Matt Thomas.
41129198Scognet * Copyright (c) 1997,1998 Mark Brinicombe.
42129198Scognet * Copyright (c) 1997 Causality Limited
43129198Scognet * All rights reserved.
44129198Scognet *
45129198Scognet * Redistribution and use in source and binary forms, with or without
46129198Scognet * modification, are permitted provided that the following conditions
47129198Scognet * are met:
48129198Scognet * 1. Redistributions of source code must retain the above copyright
49129198Scognet *    notice, this list of conditions and the following disclaimer.
50129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
51129198Scognet *    notice, this list of conditions and the following disclaimer in the
52129198Scognet *    documentation and/or other materials provided with the distribution.
53129198Scognet * 3. All advertising materials mentioning features or use of this software
54129198Scognet *    must display the following acknowledgement:
55129198Scognet *	This product includes software developed by Causality Limited.
56129198Scognet * 4. The name of Causality Limited may not be used to endorse or promote
57129198Scognet *    products derived from this software without specific prior written
58129198Scognet *    permission.
59129198Scognet *
60129198Scognet * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
61129198Scognet * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
62129198Scognet * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
63129198Scognet * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
64129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
65129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
66129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70129198Scognet * SUCH DAMAGE.
71129198Scognet *
72129198Scognet * XScale assembly functions for CPU / MMU / TLB specific operations
73129198Scognet */
74271398Sandrew#include <machine/armreg.h>
75129198Scognet#include <machine/asm.h>
76129198Scognet__FBSDID("$FreeBSD$");
77129198Scognet
78129198Scognet/*
79129198Scognet * Size of the XScale core D-cache.
80129198Scognet */
81129198Scognet#define	DCACHE_SIZE		0x00008000
82129198Scognet
83129198Scognet/*
84129198Scognet * CPWAIT -- Canonical method to wait for CP15 update.
85129198Scognet * From: Intel 80200 manual, section 2.3.3.
86129198Scognet *
87129198Scognet * NOTE: Clobbers the specified temp reg.
88129198Scognet */
89129198Scognet#define	CPWAIT_BRANCH							 \
90129198Scognet	sub	pc, pc, #4
91129198Scognet
92129198Scognet#define	CPWAIT(tmp)							 \
93129198Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
94129198Scognet	mov	tmp, tmp		/* wait for it to complete */	;\
95129198Scognet	CPWAIT_BRANCH			/* branch to next insn */
96129198Scognet
97129198Scognet#define	CPWAIT_AND_RETURN_SHIFTER	lsr #32
98129198Scognet
99129198Scognet#define	CPWAIT_AND_RETURN(tmp)						 \
100129198Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
101129198Scognet	/* Wait for it to complete and branch to the return address */	 \
102129198Scognet	sub	pc, lr, tmp, CPWAIT_AND_RETURN_SHIFTER
103129198Scognet
104129198ScognetENTRY(xscale_cpwait)
105129198Scognet	CPWAIT_AND_RETURN(r0)
106248361SandrewEND(xscale_cpwait)
107129198Scognet
108129198Scognet/*
109129198Scognet * We need a separate cpu_control() entry point, since we have to
110129198Scognet * invalidate the Branch Target Buffer in the event the BPRD bit
111129198Scognet * changes in the control register.
112129198Scognet */
113129198ScognetENTRY(xscale_control)
114300533Sian	mrc	CP15_SCTLR(r3)		/* Read the control register */
115129198Scognet	bic	r2, r3, r0		/* Clear bits */
116129198Scognet	eor	r2, r2, r1		/* XOR bits */
117129198Scognet
118129198Scognet	teq	r2, r3			/* Only write if there was a change */
119129198Scognet	mcrne	p15, 0, r0, c7, c5, 6	/* Invalidate the BTB */
120300534Sian	mcrne	CP15_SCTLR(r2)		/* Write new control register */
121129198Scognet	mov	r0, r3			/* Return old value */
122129198Scognet
123129198Scognet	CPWAIT_AND_RETURN(r1)
124248361SandrewEND(xscale_control)
125129198Scognet
126129198Scognet/*
127129198Scognet * Functions to set the MMU Translation Table Base register
128129198Scognet *
129129198Scognet * We need to clean and flush the cache as it uses virtual
130129198Scognet * addresses that are about to change.
131129198Scognet */
132129198ScognetENTRY(xscale_setttb)
133129198Scognet#ifdef CACHE_CLEAN_BLOCK_INTR
134261393Sian	mrs	r3, cpsr
135271398Sandrew	orr	r1, r3, #(PSR_I | PSR_F)
136261393Sian	msr	cpsr_fsxc, r1
137129198Scognet#endif
138129198Scognet	stmfd	sp!, {r0-r3, lr}
139129198Scognet	bl	_C_LABEL(xscale_cache_cleanID)
140129198Scognet	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I$ and BTB */
141129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write and fill buffer */
142129198Scognet
143129198Scognet	CPWAIT(r0)
144129198Scognet
145129198Scognet	ldmfd	sp!, {r0-r3, lr}
146129198Scognet
147236991Simp	/* Write the TTB */
148129198Scognet	mcr	p15, 0, r0, c2, c0, 0
149129198Scognet
150129198Scognet	/* If we have updated the TTB we must flush the TLB */
151129198Scognet	mcr	p15, 0, r0, c8, c7, 0	/* invalidate I+D TLB */
152129198Scognet
153129198Scognet	/* The cleanID above means we only need to flush the I cache here */
154129198Scognet	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I$ and BTB */
155129198Scognet
156129198Scognet	CPWAIT(r0)
157129198Scognet
158129198Scognet#ifdef CACHE_CLEAN_BLOCK_INTR
159261393Sian	msr	cpsr_fsxc, r3
160129198Scognet#endif
161137463Scognet	RET
162248361SandrewEND(xscale_setttb)
163129198Scognet
164129198Scognet/*
165129198Scognet * TLB functions
166129198Scognet *
167129198Scognet */
168129198ScognetENTRY(xscale_tlb_flushID_SE)
169129198Scognet	mcr	p15, 0, r0, c8, c6, 1	/* flush D tlb single entry */
170129198Scognet	mcr	p15, 0, r0, c8, c5, 1	/* flush I tlb single entry */
171140000Scognet	CPWAIT_AND_RETURN(r0)
172248361SandrewEND(xscale_tlb_flushID_SE)
173129198Scognet
174129198Scognet/*
175129198Scognet * Cache functions
176129198Scognet */
177129198ScognetENTRY(xscale_cache_flushID)
178129198Scognet	mcr	p15, 0, r0, c7, c7, 0	/* flush I+D cache */
179129198Scognet	CPWAIT_AND_RETURN(r0)
180248361SandrewEND(xscale_cache_flushID)
181129198Scognet
182129198ScognetENTRY(xscale_cache_flushI)
183129198Scognet	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache */
184129198Scognet	CPWAIT_AND_RETURN(r0)
185248361SandrewEND(xscale_cache_flushI)
186129198Scognet
187129198ScognetENTRY(xscale_cache_flushD)
188129198Scognet	mcr	p15, 0, r0, c7, c6, 0	/* flush D cache */
189129198Scognet	CPWAIT_AND_RETURN(r0)
190248361SandrewEND(xscale_cache_flushD)
191129198Scognet
192129198ScognetENTRY(xscale_cache_flushI_SE)
193129198Scognet	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
194129198Scognet	CPWAIT_AND_RETURN(r0)
195248361SandrewEND(xscale_cache_flushI_SE)
196129198Scognet
197129198ScognetENTRY(xscale_cache_flushD_SE)
198129198Scognet	/*
199129198Scognet	 * Errata (rev < 2): Must clean-dcache-line to an address
200129198Scognet	 * before invalidate-dcache-line to an address, or dirty
201129198Scognet	 * bits will not be cleared in the dcache array.
202129198Scognet	 */
203129198Scognet	mcr	p15, 0, r0, c7, c10, 1
204129198Scognet	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
205129198Scognet	CPWAIT_AND_RETURN(r0)
206248361SandrewEND(xscale_cache_flushD_SE)
207129198Scognet
208129198ScognetENTRY(xscale_cache_cleanD_E)
209129198Scognet	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
210129198Scognet	CPWAIT_AND_RETURN(r0)
211248361SandrewEND(xscale_cache_cleanD_E)
212129198Scognet
213129198Scognet/*
214129198Scognet * Information for the XScale cache clean/purge functions:
215129198Scognet *
216129198Scognet *	* Virtual address of the memory region to use
217129198Scognet *	* Size of memory region
218129198Scognet *
219129198Scognet * Note the virtual address for the Data cache clean operation
220129198Scognet * does not need to be backed by physical memory, since no loads
221129198Scognet * will actually be performed by the allocate-line operation.
222129198Scognet *
223129198Scognet * Note that the Mini-Data cache MUST be cleaned by executing
224129198Scognet * loads from memory mapped into a region reserved exclusively
225129198Scognet * for cleaning of the Mini-Data cache.
226129198Scognet */
227129198Scognet	.data
228129198Scognet
229129198Scognet	.global	_C_LABEL(xscale_cache_clean_addr)
230129198Scognet_C_LABEL(xscale_cache_clean_addr):
231129198Scognet	.word	0x00000000
232129198Scognet
233129198Scognet	.global	_C_LABEL(xscale_cache_clean_size)
234129198Scognet_C_LABEL(xscale_cache_clean_size):
235129198Scognet	.word	DCACHE_SIZE
236129198Scognet
237129198Scognet	.global	_C_LABEL(xscale_minidata_clean_addr)
238129198Scognet_C_LABEL(xscale_minidata_clean_addr):
239129198Scognet	.word	0x00000000
240129198Scognet
241129198Scognet	.global	_C_LABEL(xscale_minidata_clean_size)
242129198Scognet_C_LABEL(xscale_minidata_clean_size):
243129198Scognet	.word	0x00000800
244129198Scognet
245129198Scognet	.text
246129198Scognet
247129198Scognet.Lxscale_cache_clean_addr:
248129198Scognet	.word	_C_LABEL(xscale_cache_clean_addr)
249129198Scognet.Lxscale_cache_clean_size:
250129198Scognet	.word	_C_LABEL(xscale_cache_clean_size)
251129198Scognet
252129198Scognet.Lxscale_minidata_clean_addr:
253129198Scognet	.word	_C_LABEL(xscale_minidata_clean_addr)
254129198Scognet.Lxscale_minidata_clean_size:
255129198Scognet	.word	_C_LABEL(xscale_minidata_clean_size)
256129198Scognet
257129198Scognet#ifdef CACHE_CLEAN_BLOCK_INTR
258129198Scognet#define	XSCALE_CACHE_CLEAN_BLOCK					\
259261393Sian	mrs	r3, cpsr					;	\
260271398Sandrew	orr	r0, r3, #(PSR_I | PSR_F)			;	\
261261393Sian	msr	cpsr_fsxc, r0
262129198Scognet
263129198Scognet#define	XSCALE_CACHE_CLEAN_UNBLOCK					\
264261393Sian	msr	cpsr_fsxc, r3
265129198Scognet#else
266295267Smmel#define	XSCALE_CACHE_CLEAN_BLOCK
267129198Scognet
268295267Smmel#define	XSCALE_CACHE_CLEAN_UNBLOCK
269129198Scognet#endif /* CACHE_CLEAN_BLOCK_INTR */
270129198Scognet
271129198Scognet#define	XSCALE_CACHE_CLEAN_PROLOGUE					\
272129198Scognet	XSCALE_CACHE_CLEAN_BLOCK				;	\
273129198Scognet	ldr	r2, .Lxscale_cache_clean_addr			;	\
274129198Scognet	ldmia	r2, {r0, r1}					;	\
275129198Scognet	/*								\
276129198Scognet	 * BUG ALERT!							\
277129198Scognet	 *								\
278129198Scognet	 * The XScale core has a strange cache eviction bug, which	\
279129198Scognet	 * requires us to use 2x the cache size for the cache clean	\
280129198Scognet	 * and for that area to be aligned to 2 * cache size.		\
281129198Scognet	 *								\
282129198Scognet	 * The work-around is to use 2 areas for cache clean, and to	\
283129198Scognet	 * alternate between them whenever this is done.  No one knows	\
284129198Scognet	 * why the work-around works (mmm!).				\
285129198Scognet	 */								\
286129198Scognet	eor	r0, r0, #(DCACHE_SIZE)				;	\
287129198Scognet	str	r0, [r2]					;	\
288129198Scognet	add	r0, r0, r1
289129198Scognet
290129198Scognet#define	XSCALE_CACHE_CLEAN_EPILOGUE					\
291129198Scognet	XSCALE_CACHE_CLEAN_UNBLOCK
292129198Scognet
293129198ScognetENTRY_NP(xscale_cache_syncI)
294269390Sian
295269390SianEENTRY_NP(xscale_cache_purgeID)
296129198Scognet	mcr	p15, 0, r0, c7, c5, 0	/* flush I cache (D cleaned below) */
297269390SianEENTRY_NP(xscale_cache_cleanID)
298269390SianEENTRY_NP(xscale_cache_purgeD)
299269390SianEENTRY(xscale_cache_cleanD)
300129198Scognet	XSCALE_CACHE_CLEAN_PROLOGUE
301129198Scognet
302129198Scognet1:	subs	r0, r0, #32
303129198Scognet	mcr	p15, 0, r0, c7, c2, 5	/* allocate cache line */
304129198Scognet	subs	r1, r1, #32
305129198Scognet	bne	1b
306129198Scognet
307129198Scognet	CPWAIT(r0)
308129198Scognet
309129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
310129198Scognet
311129198Scognet	CPWAIT(r0)
312129198Scognet
313129198Scognet	XSCALE_CACHE_CLEAN_EPILOGUE
314137463Scognet	RET
315269390SianEEND(xscale_cache_cleanD)
316269390SianEEND(xscale_cache_purgeD)
317269390SianEEND(xscale_cache_cleanID)
318269390SianEEND(xscale_cache_purgeID)
319248361SandrewEND(xscale_cache_syncI)
320129198Scognet
321129198Scognet/*
322129198Scognet * Clean the mini-data cache.
323129198Scognet *
324129198Scognet * It's expected that we only use the mini-data cache for
325129198Scognet * kernel addresses, so there is no need to purge it on
326129198Scognet * context switch, and no need to prevent userspace access
327129198Scognet * while we clean it.
328129198Scognet */
329129198ScognetENTRY(xscale_cache_clean_minidata)
330129198Scognet	ldr	r2, .Lxscale_minidata_clean_addr
331129198Scognet	ldmia	r2, {r0, r1}
332129198Scognet1:	ldr	r3, [r0], #32
333129198Scognet	subs	r1, r1, #32
334129198Scognet	bne	1b
335129198Scognet
336129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
337129198Scognet
338129198Scognet	CPWAIT_AND_RETURN(r1)
339248361SandrewEND(xscale_cache_clean_minidata)
340129198Scognet
341129198ScognetENTRY(xscale_cache_purgeID_E)
342129198Scognet	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
343129198Scognet	CPWAIT(r1)
344129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
345129198Scognet	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
346129198Scognet	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
347129198Scognet	CPWAIT_AND_RETURN(r1)
348248361SandrewEND(xscale_cache_purgeID_E)
349129198Scognet
350129198ScognetENTRY(xscale_cache_purgeD_E)
351129198Scognet	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
352129198Scognet	CPWAIT(r1)
353129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
354129198Scognet	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
355129198Scognet	CPWAIT_AND_RETURN(r1)
356248361SandrewEND(xscale_cache_purgeD_E)
357129198Scognet
358129198Scognet/*
359129198Scognet * Soft functions
360129198Scognet */
361129198Scognet/* xscale_cache_syncI is identical to xscale_cache_purgeID */
362129198Scognet
363269390SianEENTRY(xscale_cache_cleanID_rng)
364129198ScognetENTRY(xscale_cache_cleanD_rng)
365129198Scognet	cmp	r1, #0x4000
366129198Scognet	bcs	_C_LABEL(xscale_cache_cleanID)
367129198Scognet
368129198Scognet	and	r2, r0, #0x1f
369129198Scognet	add	r1, r1, r2
370129198Scognet	bic	r0, r0, #0x1f
371129198Scognet
372129198Scognet1:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
373129198Scognet	add	r0, r0, #32
374129198Scognet	subs	r1, r1, #32
375129198Scognet	bhi	1b
376129198Scognet
377129198Scognet	CPWAIT(r0)
378129198Scognet
379129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
380129198Scognet
381129198Scognet	CPWAIT_AND_RETURN(r0)
382269390Sian/*END(xscale_cache_cleanID_rng)*/
383248361SandrewEND(xscale_cache_cleanD_rng)
384129198Scognet
385129198ScognetENTRY(xscale_cache_purgeID_rng)
386129198Scognet	cmp	r1, #0x4000
387129198Scognet	bcs	_C_LABEL(xscale_cache_purgeID)
388129198Scognet
389129198Scognet	and	r2, r0, #0x1f
390129198Scognet	add	r1, r1, r2
391129198Scognet	bic	r0, r0, #0x1f
392129198Scognet
393129198Scognet1:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
394129198Scognet	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
395129198Scognet	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
396129198Scognet	add	r0, r0, #32
397129198Scognet	subs	r1, r1, #32
398129198Scognet	bhi	1b
399129198Scognet
400129198Scognet	CPWAIT(r0)
401129198Scognet
402129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
403129198Scognet
404129198Scognet	CPWAIT_AND_RETURN(r0)
405248361SandrewEND(xscale_cache_purgeID_rng)
406129198Scognet
407129198ScognetENTRY(xscale_cache_purgeD_rng)
408129198Scognet	cmp	r1, #0x4000
409129198Scognet	bcs	_C_LABEL(xscale_cache_purgeD)
410129198Scognet
411129198Scognet	and	r2, r0, #0x1f
412129198Scognet	add	r1, r1, r2
413129198Scognet	bic	r0, r0, #0x1f
414129198Scognet
415129198Scognet1:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
416129198Scognet	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
417129198Scognet	add	r0, r0, #32
418129198Scognet	subs	r1, r1, #32
419129198Scognet	bhi	1b
420129198Scognet
421129198Scognet	CPWAIT(r0)
422129198Scognet
423129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
424129198Scognet
425129198Scognet	CPWAIT_AND_RETURN(r0)
426248361SandrewEND(xscale_cache_purgeD_rng)
427129198Scognet
428129198ScognetENTRY(xscale_cache_syncI_rng)
429129198Scognet	cmp	r1, #0x4000
430129198Scognet	bcs	_C_LABEL(xscale_cache_syncI)
431129198Scognet
432129198Scognet	and	r2, r0, #0x1f
433129198Scognet	add	r1, r1, r2
434129198Scognet	bic	r0, r0, #0x1f
435129198Scognet
436129198Scognet1:	mcr	p15, 0, r0, c7, c10, 1	/* clean D cache entry */
437129198Scognet	mcr	p15, 0, r0, c7, c5, 1	/* flush I cache single entry */
438129198Scognet	add	r0, r0, #32
439129198Scognet	subs	r1, r1, #32
440129198Scognet	bhi	1b
441129198Scognet
442129198Scognet	CPWAIT(r0)
443129198Scognet
444129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
445129198Scognet
446129198Scognet	CPWAIT_AND_RETURN(r0)
447248361SandrewEND(xscale_cache_syncI_rng)
448129198Scognet
449129198ScognetENTRY(xscale_cache_flushD_rng)
450129198Scognet	and	r2, r0, #0x1f
451129198Scognet	add	r1, r1, r2
452129198Scognet	bic	r0, r0, #0x1f
453129198Scognet
454129198Scognet1:	mcr	p15, 0, r0, c7, c6, 1	/* flush D cache single entry */
455129198Scognet	add	r0, r0, #32
456129198Scognet	subs	r1, r1, #32
457129198Scognet	bhi	1b
458129198Scognet
459129198Scognet	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
460129198Scognet
461129198Scognet	CPWAIT_AND_RETURN(r0)
462248361SandrewEND(xscale_cache_flushD_rng)
463129198Scognet
464129198Scognet/*
465129198Scognet * Context switch.
466129198Scognet *
467129198Scognet * These is the CPU-specific parts of the context switcher cpu_switch()
468129198Scognet * These functions actually perform the TTB reload.
469129198Scognet *
470129198Scognet * NOTE: Special calling convention
471129198Scognet *	r1, r4-r13 must be preserved
472129198Scognet */
473129198ScognetENTRY(xscale_context_switch)
474129198Scognet	/*
475129198Scognet	 * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this.
476129198Scognet	 * Thus the data cache will contain only kernel data and the
477129198Scognet	 * instruction cache will contain only kernel code, and all
478129198Scognet	 * kernel mappings are shared by all processes.
479129198Scognet	 */
480129198Scognet
481129198Scognet	/* Write the TTB */
482129198Scognet	mcr	p15, 0, r0, c2, c0, 0
483129198Scognet
484129198Scognet	/* If we have updated the TTB we must flush the TLB */
485129198Scognet	mcr	p15, 0, r0, c8, c7, 0	/* flush the I+D tlb */
486129198Scognet
487129198Scognet	CPWAIT_AND_RETURN(r0)
488248361SandrewEND(xscale_context_switch)
489129198Scognet
490129198Scognet/*
491129198Scognet * xscale_cpu_sleep
492129198Scognet *
493129198Scognet * This is called when there is nothing on any of the run queues.
494129198Scognet * We go into IDLE mode so that any IRQ or FIQ will awaken us.
495129198Scognet *
496129198Scognet * If this is called with anything other than ARM_SLEEP_MODE_IDLE,
497129198Scognet * ignore it.
498129198Scognet */
499129198ScognetENTRY(xscale_cpu_sleep)
500129198Scognet	tst	r0, #0x00000000
501129198Scognet	bne	1f
502129198Scognet	mov	r0, #0x1
503129198Scognet	mcr	p14, 0, r0, c7, c0, 0
504129198Scognet
505129198Scognet1:
506137463Scognet	RET
507248361SandrewEND(xscale_cpu_sleep)
508248361Sandrew
509