xref: /OK3568_Linux_fs/kernel/arch/arm/mm/proc-xscale.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun *  linux/arch/arm/mm/proc-xscale.S
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun *  Author:	Nicolas Pitre
6*4882a593Smuzhiyun *  Created:	November 2000
7*4882a593Smuzhiyun *  Copyright:	(C) 2000, 2001 MontaVista Software Inc.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * MMU functions for the Intel XScale CPUs
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * 2001 Aug 21:
12*4882a593Smuzhiyun *	some contributions by Brett Gaines <brett.w.gaines@intel.com>
13*4882a593Smuzhiyun *	Copyright 2001 by Intel Corp.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * 2001 Sep 08:
16*4882a593Smuzhiyun *	Completely revisited, many important fixes
17*4882a593Smuzhiyun *	Nicolas Pitre <nico@fluxnic.net>
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun#include <linux/linkage.h>
21*4882a593Smuzhiyun#include <linux/init.h>
22*4882a593Smuzhiyun#include <linux/pgtable.h>
23*4882a593Smuzhiyun#include <asm/assembler.h>
24*4882a593Smuzhiyun#include <asm/hwcap.h>
25*4882a593Smuzhiyun#include <asm/pgtable-hwdef.h>
26*4882a593Smuzhiyun#include <asm/page.h>
27*4882a593Smuzhiyun#include <asm/ptrace.h>
28*4882a593Smuzhiyun#include "proc-macros.S"
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun/*
31*4882a593Smuzhiyun * This is the maximum size of an area which will be flushed.  If the area
32*4882a593Smuzhiyun * is larger than this, then we flush the whole cache
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun#define MAX_AREA_SIZE	32768
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun/*
37*4882a593Smuzhiyun * the cache line size of the I and D cache
38*4882a593Smuzhiyun */
39*4882a593Smuzhiyun#define CACHELINESIZE	32
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun/*
42*4882a593Smuzhiyun * the size of the data cache
43*4882a593Smuzhiyun */
44*4882a593Smuzhiyun#define CACHESIZE	32768
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun/*
47*4882a593Smuzhiyun * Virtual address used to allocate the cache when flushed
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun * This must be an address range which is _never_ used.  It should
50*4882a593Smuzhiyun * apparently have a mapping in the corresponding page table for
51*4882a593Smuzhiyun * compatibility with future CPUs that _could_ require it.  For instance we
52*4882a593Smuzhiyun * don't care.
53*4882a593Smuzhiyun *
54*4882a593Smuzhiyun * This must be aligned on a 2*CACHESIZE boundary.  The code selects one of
55*4882a593Smuzhiyun * the 2 areas in alternance each time the clean_d_cache macro is used.
56*4882a593Smuzhiyun * Without this the XScale core exhibits cache eviction problems and no one
57*4882a593Smuzhiyun * knows why.
58*4882a593Smuzhiyun *
59*4882a593Smuzhiyun * Reminder: the vector table is located at 0xffff0000-0xffff0fff.
60*4882a593Smuzhiyun */
61*4882a593Smuzhiyun#define CLEAN_ADDR	0xfffe0000
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun/*
64*4882a593Smuzhiyun * This macro is used to wait for a CP15 write and is needed
65*4882a593Smuzhiyun * when we have to ensure that the last operation to the co-pro
66*4882a593Smuzhiyun * was completed before continuing with operation.
67*4882a593Smuzhiyun */
68*4882a593Smuzhiyun	.macro	cpwait, rd
69*4882a593Smuzhiyun	mrc	p15, 0, \rd, c2, c0, 0		@ arbitrary read of cp15
70*4882a593Smuzhiyun	mov	\rd, \rd			@ wait for completion
71*4882a593Smuzhiyun	sub 	pc, pc, #4			@ flush instruction pipeline
72*4882a593Smuzhiyun	.endm
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun	.macro	cpwait_ret, lr, rd
75*4882a593Smuzhiyun	mrc	p15, 0, \rd, c2, c0, 0		@ arbitrary read of cp15
76*4882a593Smuzhiyun	sub	pc, \lr, \rd, LSR #32		@ wait for completion and
77*4882a593Smuzhiyun						@ flush instruction pipeline
78*4882a593Smuzhiyun	.endm
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun/*
81*4882a593Smuzhiyun * This macro cleans the entire dcache using line allocate.
82*4882a593Smuzhiyun * The main loop has been unrolled to reduce loop overhead.
83*4882a593Smuzhiyun * rd and rs are two scratch registers.
84*4882a593Smuzhiyun */
85*4882a593Smuzhiyun	.macro  clean_d_cache, rd, rs
86*4882a593Smuzhiyun	ldr	\rs, =clean_addr
87*4882a593Smuzhiyun	ldr	\rd, [\rs]
88*4882a593Smuzhiyun	eor	\rd, \rd, #CACHESIZE
89*4882a593Smuzhiyun	str	\rd, [\rs]
90*4882a593Smuzhiyun	add	\rs, \rd, #CACHESIZE
91*4882a593Smuzhiyun1:	mcr	p15, 0, \rd, c7, c2, 5		@ allocate D cache line
92*4882a593Smuzhiyun	add	\rd, \rd, #CACHELINESIZE
93*4882a593Smuzhiyun	mcr	p15, 0, \rd, c7, c2, 5		@ allocate D cache line
94*4882a593Smuzhiyun	add	\rd, \rd, #CACHELINESIZE
95*4882a593Smuzhiyun	mcr	p15, 0, \rd, c7, c2, 5		@ allocate D cache line
96*4882a593Smuzhiyun	add	\rd, \rd, #CACHELINESIZE
97*4882a593Smuzhiyun	mcr	p15, 0, \rd, c7, c2, 5		@ allocate D cache line
98*4882a593Smuzhiyun	add	\rd, \rd, #CACHELINESIZE
99*4882a593Smuzhiyun	teq	\rd, \rs
100*4882a593Smuzhiyun	bne	1b
101*4882a593Smuzhiyun	.endm
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun	.data
104*4882a593Smuzhiyun	.align	2
105*4882a593Smuzhiyunclean_addr:	.word	CLEAN_ADDR
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun	.text
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun/*
110*4882a593Smuzhiyun * cpu_xscale_proc_init()
111*4882a593Smuzhiyun *
112*4882a593Smuzhiyun * Nothing too exciting at the moment
113*4882a593Smuzhiyun */
114*4882a593SmuzhiyunENTRY(cpu_xscale_proc_init)
115*4882a593Smuzhiyun	@ enable write buffer coalescing. Some bootloader disable it
116*4882a593Smuzhiyun	mrc	p15, 0, r1, c1, c0, 1
117*4882a593Smuzhiyun	bic	r1, r1, #1
118*4882a593Smuzhiyun	mcr	p15, 0, r1, c1, c0, 1
119*4882a593Smuzhiyun	ret	lr
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun/*
122*4882a593Smuzhiyun * cpu_xscale_proc_fin()
123*4882a593Smuzhiyun */
124*4882a593SmuzhiyunENTRY(cpu_xscale_proc_fin)
125*4882a593Smuzhiyun	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
126*4882a593Smuzhiyun	bic	r0, r0, #0x1800			@ ...IZ...........
127*4882a593Smuzhiyun	bic	r0, r0, #0x0006			@ .............CA.
128*4882a593Smuzhiyun	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
129*4882a593Smuzhiyun	ret	lr
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun/*
132*4882a593Smuzhiyun * cpu_xscale_reset(loc)
133*4882a593Smuzhiyun *
134*4882a593Smuzhiyun * Perform a soft reset of the system.  Put the CPU into the
135*4882a593Smuzhiyun * same state as it would be if it had been reset, and branch
136*4882a593Smuzhiyun * to what would be the reset vector.
137*4882a593Smuzhiyun *
138*4882a593Smuzhiyun * loc: location to jump to for soft reset
139*4882a593Smuzhiyun *
140*4882a593Smuzhiyun * Beware PXA270 erratum E7.
141*4882a593Smuzhiyun */
142*4882a593Smuzhiyun	.align	5
143*4882a593Smuzhiyun	.pushsection	.idmap.text, "ax"
144*4882a593SmuzhiyunENTRY(cpu_xscale_reset)
145*4882a593Smuzhiyun	mov	r1, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
146*4882a593Smuzhiyun	msr	cpsr_c, r1			@ reset CPSR
147*4882a593Smuzhiyun	mcr	p15, 0, r1, c10, c4, 1		@ unlock I-TLB
148*4882a593Smuzhiyun	mcr	p15, 0, r1, c8, c5, 0		@ invalidate I-TLB
149*4882a593Smuzhiyun	mrc	p15, 0, r1, c1, c0, 0		@ ctrl register
150*4882a593Smuzhiyun	bic	r1, r1, #0x0086			@ ........B....CA.
151*4882a593Smuzhiyun	bic	r1, r1, #0x3900			@ ..VIZ..S........
152*4882a593Smuzhiyun	sub	pc, pc, #4			@ flush pipeline
153*4882a593Smuzhiyun	@ *** cache line aligned ***
154*4882a593Smuzhiyun	mcr	p15, 0, r1, c1, c0, 0		@ ctrl register
155*4882a593Smuzhiyun	bic	r1, r1, #0x0001			@ ...............M
156*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches & BTB
157*4882a593Smuzhiyun	mcr	p15, 0, r1, c1, c0, 0		@ ctrl register
158*4882a593Smuzhiyun	@ CAUTION: MMU turned off from this point. We count on the pipeline
159*4882a593Smuzhiyun	@ already containing those two last instructions to survive.
160*4882a593Smuzhiyun	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
161*4882a593Smuzhiyun	ret	r0
162*4882a593SmuzhiyunENDPROC(cpu_xscale_reset)
163*4882a593Smuzhiyun	.popsection
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun/*
166*4882a593Smuzhiyun * cpu_xscale_do_idle()
167*4882a593Smuzhiyun *
168*4882a593Smuzhiyun * Cause the processor to idle
169*4882a593Smuzhiyun *
170*4882a593Smuzhiyun * For now we do nothing but go to idle mode for every case
171*4882a593Smuzhiyun *
172*4882a593Smuzhiyun * XScale supports clock switching, but using idle mode support
173*4882a593Smuzhiyun * allows external hardware to react to system state changes.
174*4882a593Smuzhiyun */
175*4882a593Smuzhiyun	.align	5
176*4882a593Smuzhiyun
177*4882a593SmuzhiyunENTRY(cpu_xscale_do_idle)
178*4882a593Smuzhiyun	mov	r0, #1
179*4882a593Smuzhiyun	mcr	p14, 0, r0, c7, c0, 0		@ Go to IDLE
180*4882a593Smuzhiyun	ret	lr
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun/* ================================= CACHE ================================ */
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun/*
185*4882a593Smuzhiyun *	flush_icache_all()
186*4882a593Smuzhiyun *
187*4882a593Smuzhiyun *	Unconditionally clean and invalidate the entire icache.
188*4882a593Smuzhiyun */
189*4882a593SmuzhiyunENTRY(xscale_flush_icache_all)
190*4882a593Smuzhiyun	mov	r0, #0
191*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
192*4882a593Smuzhiyun	ret	lr
193*4882a593SmuzhiyunENDPROC(xscale_flush_icache_all)
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun/*
196*4882a593Smuzhiyun *	flush_user_cache_all()
197*4882a593Smuzhiyun *
198*4882a593Smuzhiyun *	Invalidate all cache entries in a particular address
199*4882a593Smuzhiyun *	space.
200*4882a593Smuzhiyun */
201*4882a593SmuzhiyunENTRY(xscale_flush_user_cache_all)
202*4882a593Smuzhiyun	/* FALLTHROUGH */
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun/*
205*4882a593Smuzhiyun *	flush_kern_cache_all()
206*4882a593Smuzhiyun *
207*4882a593Smuzhiyun *	Clean and invalidate the entire cache.
208*4882a593Smuzhiyun */
209*4882a593SmuzhiyunENTRY(xscale_flush_kern_cache_all)
210*4882a593Smuzhiyun	mov	r2, #VM_EXEC
211*4882a593Smuzhiyun	mov	ip, #0
212*4882a593Smuzhiyun__flush_whole_cache:
213*4882a593Smuzhiyun	clean_d_cache r0, r1
214*4882a593Smuzhiyun	tst	r2, #VM_EXEC
215*4882a593Smuzhiyun	mcrne	p15, 0, ip, c7, c5, 0		@ Invalidate I cache & BTB
216*4882a593Smuzhiyun	mcrne	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
217*4882a593Smuzhiyun	ret	lr
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun/*
220*4882a593Smuzhiyun *	flush_user_cache_range(start, end, vm_flags)
221*4882a593Smuzhiyun *
222*4882a593Smuzhiyun *	Invalidate a range of cache entries in the specified
223*4882a593Smuzhiyun *	address space.
224*4882a593Smuzhiyun *
225*4882a593Smuzhiyun *	- start - start address (may not be aligned)
226*4882a593Smuzhiyun *	- end	- end address (exclusive, may not be aligned)
227*4882a593Smuzhiyun *	- vma	- vma_area_struct describing address space
228*4882a593Smuzhiyun */
229*4882a593Smuzhiyun	.align	5
230*4882a593SmuzhiyunENTRY(xscale_flush_user_cache_range)
231*4882a593Smuzhiyun	mov	ip, #0
232*4882a593Smuzhiyun	sub	r3, r1, r0			@ calculate total size
233*4882a593Smuzhiyun	cmp	r3, #MAX_AREA_SIZE
234*4882a593Smuzhiyun	bhs	__flush_whole_cache
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun1:	tst	r2, #VM_EXEC
237*4882a593Smuzhiyun	mcrne	p15, 0, r0, c7, c5, 1		@ Invalidate I cache line
238*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
239*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c6, 1		@ Invalidate D cache line
240*4882a593Smuzhiyun	add	r0, r0, #CACHELINESIZE
241*4882a593Smuzhiyun	cmp	r0, r1
242*4882a593Smuzhiyun	blo	1b
243*4882a593Smuzhiyun	tst	r2, #VM_EXEC
244*4882a593Smuzhiyun	mcrne	p15, 0, ip, c7, c5, 6		@ Invalidate BTB
245*4882a593Smuzhiyun	mcrne	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
246*4882a593Smuzhiyun	ret	lr
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun/*
249*4882a593Smuzhiyun *	coherent_kern_range(start, end)
250*4882a593Smuzhiyun *
251*4882a593Smuzhiyun *	Ensure coherency between the Icache and the Dcache in the
252*4882a593Smuzhiyun *	region described by start.  If you have non-snooping
253*4882a593Smuzhiyun *	Harvard caches, you need to implement this function.
254*4882a593Smuzhiyun *
255*4882a593Smuzhiyun *	- start  - virtual start address
256*4882a593Smuzhiyun *	- end	 - virtual end address
257*4882a593Smuzhiyun *
258*4882a593Smuzhiyun *	Note: single I-cache line invalidation isn't used here since
259*4882a593Smuzhiyun *	it also trashes the mini I-cache used by JTAG debuggers.
260*4882a593Smuzhiyun */
261*4882a593SmuzhiyunENTRY(xscale_coherent_kern_range)
262*4882a593Smuzhiyun	bic	r0, r0, #CACHELINESIZE - 1
263*4882a593Smuzhiyun1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
264*4882a593Smuzhiyun	add	r0, r0, #CACHELINESIZE
265*4882a593Smuzhiyun	cmp	r0, r1
266*4882a593Smuzhiyun	blo	1b
267*4882a593Smuzhiyun	mov	r0, #0
268*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c5, 0		@ Invalidate I cache & BTB
269*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 4		@ Drain Write (& Fill) Buffer
270*4882a593Smuzhiyun	ret	lr
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun/*
273*4882a593Smuzhiyun *	coherent_user_range(start, end)
274*4882a593Smuzhiyun *
275*4882a593Smuzhiyun *	Ensure coherency between the Icache and the Dcache in the
276*4882a593Smuzhiyun *	region described by start.  If you have non-snooping
277*4882a593Smuzhiyun *	Harvard caches, you need to implement this function.
278*4882a593Smuzhiyun *
279*4882a593Smuzhiyun *	- start  - virtual start address
280*4882a593Smuzhiyun *	- end	 - virtual end address
281*4882a593Smuzhiyun */
282*4882a593SmuzhiyunENTRY(xscale_coherent_user_range)
283*4882a593Smuzhiyun	bic	r0, r0, #CACHELINESIZE - 1
284*4882a593Smuzhiyun1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
285*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I cache entry
286*4882a593Smuzhiyun	add	r0, r0, #CACHELINESIZE
287*4882a593Smuzhiyun	cmp	r0, r1
288*4882a593Smuzhiyun	blo	1b
289*4882a593Smuzhiyun	mov	r0, #0
290*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c5, 6		@ Invalidate BTB
291*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 4		@ Drain Write (& Fill) Buffer
292*4882a593Smuzhiyun	ret	lr
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun/*
295*4882a593Smuzhiyun *	flush_kern_dcache_area(void *addr, size_t size)
296*4882a593Smuzhiyun *
297*4882a593Smuzhiyun *	Ensure no D cache aliasing occurs, either with itself or
298*4882a593Smuzhiyun *	the I cache
299*4882a593Smuzhiyun *
300*4882a593Smuzhiyun *	- addr	- kernel address
301*4882a593Smuzhiyun *	- size	- region size
302*4882a593Smuzhiyun */
303*4882a593SmuzhiyunENTRY(xscale_flush_kern_dcache_area)
304*4882a593Smuzhiyun	add	r1, r0, r1
305*4882a593Smuzhiyun1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
306*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
307*4882a593Smuzhiyun	add	r0, r0, #CACHELINESIZE
308*4882a593Smuzhiyun	cmp	r0, r1
309*4882a593Smuzhiyun	blo	1b
310*4882a593Smuzhiyun	mov	r0, #0
311*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c5, 0		@ Invalidate I cache & BTB
312*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 4		@ Drain Write (& Fill) Buffer
313*4882a593Smuzhiyun	ret	lr
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun/*
316*4882a593Smuzhiyun *	dma_inv_range(start, end)
317*4882a593Smuzhiyun *
318*4882a593Smuzhiyun *	Invalidate (discard) the specified virtual address range.
319*4882a593Smuzhiyun *	May not write back any entries.  If 'start' or 'end'
320*4882a593Smuzhiyun *	are not cache line aligned, those lines must be written
321*4882a593Smuzhiyun *	back.
322*4882a593Smuzhiyun *
323*4882a593Smuzhiyun *	- start  - virtual start address
324*4882a593Smuzhiyun *	- end	 - virtual end address
325*4882a593Smuzhiyun */
326*4882a593Smuzhiyunxscale_dma_inv_range:
327*4882a593Smuzhiyun	tst	r0, #CACHELINESIZE - 1
328*4882a593Smuzhiyun	bic	r0, r0, #CACHELINESIZE - 1
329*4882a593Smuzhiyun	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
330*4882a593Smuzhiyun	tst	r1, #CACHELINESIZE - 1
331*4882a593Smuzhiyun	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
332*4882a593Smuzhiyun1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
333*4882a593Smuzhiyun	add	r0, r0, #CACHELINESIZE
334*4882a593Smuzhiyun	cmp	r0, r1
335*4882a593Smuzhiyun	blo	1b
336*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 4		@ Drain Write (& Fill) Buffer
337*4882a593Smuzhiyun	ret	lr
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun/*
340*4882a593Smuzhiyun *	dma_clean_range(start, end)
341*4882a593Smuzhiyun *
342*4882a593Smuzhiyun *	Clean the specified virtual address range.
343*4882a593Smuzhiyun *
344*4882a593Smuzhiyun *	- start  - virtual start address
345*4882a593Smuzhiyun *	- end	 - virtual end address
346*4882a593Smuzhiyun */
347*4882a593Smuzhiyunxscale_dma_clean_range:
348*4882a593Smuzhiyun	bic	r0, r0, #CACHELINESIZE - 1
349*4882a593Smuzhiyun1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
350*4882a593Smuzhiyun	add	r0, r0, #CACHELINESIZE
351*4882a593Smuzhiyun	cmp	r0, r1
352*4882a593Smuzhiyun	blo	1b
353*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 4		@ Drain Write (& Fill) Buffer
354*4882a593Smuzhiyun	ret	lr
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun/*
357*4882a593Smuzhiyun *	dma_flush_range(start, end)
358*4882a593Smuzhiyun *
359*4882a593Smuzhiyun *	Clean and invalidate the specified virtual address range.
360*4882a593Smuzhiyun *
361*4882a593Smuzhiyun *	- start  - virtual start address
362*4882a593Smuzhiyun *	- end	 - virtual end address
363*4882a593Smuzhiyun */
364*4882a593SmuzhiyunENTRY(xscale_dma_flush_range)
365*4882a593Smuzhiyun	bic	r0, r0, #CACHELINESIZE - 1
366*4882a593Smuzhiyun1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
367*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
368*4882a593Smuzhiyun	add	r0, r0, #CACHELINESIZE
369*4882a593Smuzhiyun	cmp	r0, r1
370*4882a593Smuzhiyun	blo	1b
371*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 4		@ Drain Write (& Fill) Buffer
372*4882a593Smuzhiyun	ret	lr
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun/*
375*4882a593Smuzhiyun *	dma_map_area(start, size, dir)
376*4882a593Smuzhiyun *	- start	- kernel virtual start address
377*4882a593Smuzhiyun *	- size	- size of region
378*4882a593Smuzhiyun *	- dir	- DMA direction
379*4882a593Smuzhiyun */
380*4882a593SmuzhiyunENTRY(xscale_dma_map_area)
381*4882a593Smuzhiyun	add	r1, r1, r0
382*4882a593Smuzhiyun	cmp	r2, #DMA_TO_DEVICE
383*4882a593Smuzhiyun	beq	xscale_dma_clean_range
384*4882a593Smuzhiyun	bcs	xscale_dma_inv_range
385*4882a593Smuzhiyun	b	xscale_dma_flush_range
386*4882a593SmuzhiyunENDPROC(xscale_dma_map_area)
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun/*
389*4882a593Smuzhiyun *	dma_map_area(start, size, dir)
390*4882a593Smuzhiyun *	- start	- kernel virtual start address
391*4882a593Smuzhiyun *	- size	- size of region
392*4882a593Smuzhiyun *	- dir	- DMA direction
393*4882a593Smuzhiyun */
394*4882a593SmuzhiyunENTRY(xscale_80200_A0_A1_dma_map_area)
395*4882a593Smuzhiyun	add	r1, r1, r0
396*4882a593Smuzhiyun	teq	r2, #DMA_TO_DEVICE
397*4882a593Smuzhiyun	beq	xscale_dma_clean_range
398*4882a593Smuzhiyun	b	xscale_dma_flush_range
399*4882a593SmuzhiyunENDPROC(xscale_80200_A0_A1_dma_map_area)
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun/*
402*4882a593Smuzhiyun *	dma_unmap_area(start, size, dir)
403*4882a593Smuzhiyun *	- start	- kernel virtual start address
404*4882a593Smuzhiyun *	- size	- size of region
405*4882a593Smuzhiyun *	- dir	- DMA direction
406*4882a593Smuzhiyun */
407*4882a593SmuzhiyunENTRY(xscale_dma_unmap_area)
408*4882a593Smuzhiyun	ret	lr
409*4882a593SmuzhiyunENDPROC(xscale_dma_unmap_area)
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun	.globl	xscale_flush_kern_cache_louis
412*4882a593Smuzhiyun	.equ	xscale_flush_kern_cache_louis, xscale_flush_kern_cache_all
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
415*4882a593Smuzhiyun	define_cache_functions xscale
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun/*
418*4882a593Smuzhiyun * On stepping A0/A1 of the 80200, invalidating D-cache by line doesn't
419*4882a593Smuzhiyun * clear the dirty bits, which means that if we invalidate a dirty line,
420*4882a593Smuzhiyun * the dirty data can still be written back to external memory later on.
421*4882a593Smuzhiyun *
422*4882a593Smuzhiyun * The recommended workaround is to always do a clean D-cache line before
423*4882a593Smuzhiyun * doing an invalidate D-cache line, so on the affected processors,
424*4882a593Smuzhiyun * dma_inv_range() is implemented as dma_flush_range().
425*4882a593Smuzhiyun *
426*4882a593Smuzhiyun * See erratum #25 of "Intel 80200 Processor Specification Update",
427*4882a593Smuzhiyun * revision January 22, 2003, available at:
428*4882a593Smuzhiyun *     http://www.intel.com/design/iio/specupdt/273415.htm
429*4882a593Smuzhiyun */
430*4882a593Smuzhiyun.macro a0_alias basename
431*4882a593Smuzhiyun	.globl xscale_80200_A0_A1_\basename
432*4882a593Smuzhiyun	.type xscale_80200_A0_A1_\basename , %function
433*4882a593Smuzhiyun	.equ xscale_80200_A0_A1_\basename , xscale_\basename
434*4882a593Smuzhiyun.endm
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun/*
437*4882a593Smuzhiyun * Most of the cache functions are unchanged for these processor revisions.
438*4882a593Smuzhiyun * Export suitable alias symbols for the unchanged functions:
439*4882a593Smuzhiyun */
440*4882a593Smuzhiyun	a0_alias flush_icache_all
441*4882a593Smuzhiyun	a0_alias flush_user_cache_all
442*4882a593Smuzhiyun	a0_alias flush_kern_cache_all
443*4882a593Smuzhiyun	a0_alias flush_kern_cache_louis
444*4882a593Smuzhiyun	a0_alias flush_user_cache_range
445*4882a593Smuzhiyun	a0_alias coherent_kern_range
446*4882a593Smuzhiyun	a0_alias coherent_user_range
447*4882a593Smuzhiyun	a0_alias flush_kern_dcache_area
448*4882a593Smuzhiyun	a0_alias dma_flush_range
449*4882a593Smuzhiyun	a0_alias dma_unmap_area
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
452*4882a593Smuzhiyun	define_cache_functions xscale_80200_A0_A1
453*4882a593Smuzhiyun
454*4882a593SmuzhiyunENTRY(cpu_xscale_dcache_clean_area)
455*4882a593Smuzhiyun1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
456*4882a593Smuzhiyun	add	r0, r0, #CACHELINESIZE
457*4882a593Smuzhiyun	subs	r1, r1, #CACHELINESIZE
458*4882a593Smuzhiyun	bhi	1b
459*4882a593Smuzhiyun	ret	lr
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun/* =============================== PageTable ============================== */
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun/*
464*4882a593Smuzhiyun * cpu_xscale_switch_mm(pgd)
465*4882a593Smuzhiyun *
466*4882a593Smuzhiyun * Set the translation base pointer to be as described by pgd.
467*4882a593Smuzhiyun *
468*4882a593Smuzhiyun * pgd: new page tables
469*4882a593Smuzhiyun */
470*4882a593Smuzhiyun	.align	5
471*4882a593SmuzhiyunENTRY(cpu_xscale_switch_mm)
472*4882a593Smuzhiyun	clean_d_cache r1, r2
473*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c5, 0		@ Invalidate I cache & BTB
474*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
475*4882a593Smuzhiyun	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
476*4882a593Smuzhiyun	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
477*4882a593Smuzhiyun	cpwait_ret lr, ip
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun/*
480*4882a593Smuzhiyun * cpu_xscale_set_pte_ext(ptep, pte, ext)
481*4882a593Smuzhiyun *
482*4882a593Smuzhiyun * Set a PTE and flush it out
483*4882a593Smuzhiyun *
484*4882a593Smuzhiyun * Errata 40: must set memory to write-through for user read-only pages.
485*4882a593Smuzhiyun */
486*4882a593Smuzhiyuncpu_xscale_mt_table:
487*4882a593Smuzhiyun	.long	0x00						@ L_PTE_MT_UNCACHED
488*4882a593Smuzhiyun	.long	PTE_BUFFERABLE					@ L_PTE_MT_BUFFERABLE
489*4882a593Smuzhiyun	.long	PTE_CACHEABLE					@ L_PTE_MT_WRITETHROUGH
490*4882a593Smuzhiyun	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_WRITEBACK
491*4882a593Smuzhiyun	.long	PTE_EXT_TEX(1) | PTE_BUFFERABLE			@ L_PTE_MT_DEV_SHARED
492*4882a593Smuzhiyun	.long	0x00						@ unused
493*4882a593Smuzhiyun	.long	PTE_EXT_TEX(1) | PTE_CACHEABLE			@ L_PTE_MT_MINICACHE
494*4882a593Smuzhiyun	.long	PTE_EXT_TEX(1) | PTE_CACHEABLE | PTE_BUFFERABLE	@ L_PTE_MT_WRITEALLOC
495*4882a593Smuzhiyun	.long	0x00						@ unused
496*4882a593Smuzhiyun	.long	PTE_BUFFERABLE					@ L_PTE_MT_DEV_WC
497*4882a593Smuzhiyun	.long	0x00						@ unused
498*4882a593Smuzhiyun	.long	PTE_CACHEABLE | PTE_BUFFERABLE			@ L_PTE_MT_DEV_CACHED
499*4882a593Smuzhiyun	.long	0x00						@ L_PTE_MT_DEV_NONSHARED
500*4882a593Smuzhiyun	.long	0x00						@ unused
501*4882a593Smuzhiyun	.long	0x00						@ unused
502*4882a593Smuzhiyun	.long	0x00						@ unused
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun	.align	5
505*4882a593SmuzhiyunENTRY(cpu_xscale_set_pte_ext)
506*4882a593Smuzhiyun	xscale_set_pte_ext_prologue
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun	@
509*4882a593Smuzhiyun	@ Erratum 40: must set memory to write-through for user read-only pages
510*4882a593Smuzhiyun	@
511*4882a593Smuzhiyun	and	ip, r1, #(L_PTE_MT_MASK | L_PTE_USER | L_PTE_RDONLY) & ~(4 << 2)
512*4882a593Smuzhiyun	teq	ip, #L_PTE_MT_WRITEBACK | L_PTE_USER | L_PTE_RDONLY
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun	moveq	r1, #L_PTE_MT_WRITETHROUGH
515*4882a593Smuzhiyun	and	r1, r1, #L_PTE_MT_MASK
516*4882a593Smuzhiyun	adr	ip, cpu_xscale_mt_table
517*4882a593Smuzhiyun	ldr	ip, [ip, r1]
518*4882a593Smuzhiyun	bic	r2, r2, #0x0c
519*4882a593Smuzhiyun	orr	r2, r2, ip
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun	xscale_set_pte_ext_epilogue
522*4882a593Smuzhiyun	ret	lr
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun	.ltorg
525*4882a593Smuzhiyun	.align
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun.globl	cpu_xscale_suspend_size
528*4882a593Smuzhiyun.equ	cpu_xscale_suspend_size, 4 * 6
529*4882a593Smuzhiyun#ifdef CONFIG_ARM_CPU_SUSPEND
530*4882a593SmuzhiyunENTRY(cpu_xscale_do_suspend)
531*4882a593Smuzhiyun	stmfd	sp!, {r4 - r9, lr}
532*4882a593Smuzhiyun	mrc	p14, 0, r4, c6, c0, 0	@ clock configuration, for turbo mode
533*4882a593Smuzhiyun	mrc	p15, 0, r5, c15, c1, 0	@ CP access reg
534*4882a593Smuzhiyun	mrc	p15, 0, r6, c13, c0, 0	@ PID
535*4882a593Smuzhiyun	mrc	p15, 0, r7, c3, c0, 0	@ domain ID
536*4882a593Smuzhiyun	mrc	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
537*4882a593Smuzhiyun	mrc	p15, 0, r9, c1, c0, 0	@ control reg
538*4882a593Smuzhiyun	bic	r4, r4, #2		@ clear frequency change bit
539*4882a593Smuzhiyun	stmia	r0, {r4 - r9}		@ store cp regs
540*4882a593Smuzhiyun	ldmfd	sp!, {r4 - r9, pc}
541*4882a593SmuzhiyunENDPROC(cpu_xscale_do_suspend)
542*4882a593Smuzhiyun
543*4882a593SmuzhiyunENTRY(cpu_xscale_do_resume)
544*4882a593Smuzhiyun	ldmia	r0, {r4 - r9}		@ load cp regs
545*4882a593Smuzhiyun	mov	ip, #0
546*4882a593Smuzhiyun	mcr	p15, 0, ip, c8, c7, 0	@ invalidate I & D TLBs
547*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c7, 0	@ invalidate I & D caches, BTB
548*4882a593Smuzhiyun	mcr	p14, 0, r4, c6, c0, 0	@ clock configuration, turbo mode.
549*4882a593Smuzhiyun	mcr	p15, 0, r5, c15, c1, 0	@ CP access reg
550*4882a593Smuzhiyun	mcr	p15, 0, r6, c13, c0, 0	@ PID
551*4882a593Smuzhiyun	mcr	p15, 0, r7, c3, c0, 0	@ domain ID
552*4882a593Smuzhiyun	mcr	p15, 0, r1, c2, c0, 0	@ translation table base addr
553*4882a593Smuzhiyun	mcr	p15, 0, r8, c1, c0, 1	@ auxiliary control reg
554*4882a593Smuzhiyun	mov	r0, r9			@ control register
555*4882a593Smuzhiyun	b	cpu_resume_mmu
556*4882a593SmuzhiyunENDPROC(cpu_xscale_do_resume)
557*4882a593Smuzhiyun#endif
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun	.type	__xscale_setup, #function
560*4882a593Smuzhiyun__xscale_setup:
561*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I, D caches & BTB
562*4882a593Smuzhiyun	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
563*4882a593Smuzhiyun	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I, D TLBs
564*4882a593Smuzhiyun	mov	r0, #1 << 6			@ cp6 for IOP3xx and Bulverde
565*4882a593Smuzhiyun	orr	r0, r0, #1 << 13		@ Its undefined whether this
566*4882a593Smuzhiyun	mcr	p15, 0, r0, c15, c1, 0		@ affects USR or SVC modes
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun	adr	r5, xscale_crval
569*4882a593Smuzhiyun	ldmia	r5, {r5, r6}
570*4882a593Smuzhiyun	mrc	p15, 0, r0, c1, c0, 0		@ get control register
571*4882a593Smuzhiyun	bic	r0, r0, r5
572*4882a593Smuzhiyun	orr	r0, r0, r6
573*4882a593Smuzhiyun	ret	lr
574*4882a593Smuzhiyun	.size	__xscale_setup, . - __xscale_setup
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun	/*
577*4882a593Smuzhiyun	 *  R
578*4882a593Smuzhiyun	 * .RVI ZFRS BLDP WCAM
579*4882a593Smuzhiyun	 * ..11 1.01 .... .101
580*4882a593Smuzhiyun	 *
581*4882a593Smuzhiyun	 */
582*4882a593Smuzhiyun	.type	xscale_crval, #object
583*4882a593Smuzhiyunxscale_crval:
584*4882a593Smuzhiyun	crval	clear=0x00003b07, mmuset=0x00003905, ucset=0x00001900
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun	__INITDATA
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
589*4882a593Smuzhiyun	define_processor_functions xscale, dabort=v5t_early_abort, pabort=legacy_pabort, suspend=1
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun	.section ".rodata"
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun	string	cpu_arch_name, "armv5te"
594*4882a593Smuzhiyun	string	cpu_elf_name, "v5"
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun	string	cpu_80200_A0_A1_name, "XScale-80200 A0/A1"
597*4882a593Smuzhiyun	string	cpu_80200_name, "XScale-80200"
598*4882a593Smuzhiyun	string	cpu_80219_name, "XScale-80219"
599*4882a593Smuzhiyun	string	cpu_8032x_name, "XScale-IOP8032x Family"
600*4882a593Smuzhiyun	string	cpu_8033x_name, "XScale-IOP8033x Family"
601*4882a593Smuzhiyun	string	cpu_pxa250_name, "XScale-PXA250"
602*4882a593Smuzhiyun	string	cpu_pxa210_name, "XScale-PXA210"
603*4882a593Smuzhiyun	string	cpu_ixp42x_name, "XScale-IXP42x Family"
604*4882a593Smuzhiyun	string	cpu_ixp43x_name, "XScale-IXP43x Family"
605*4882a593Smuzhiyun	string	cpu_ixp46x_name, "XScale-IXP46x Family"
606*4882a593Smuzhiyun	string	cpu_ixp2400_name, "XScale-IXP2400"
607*4882a593Smuzhiyun	string	cpu_ixp2800_name, "XScale-IXP2800"
608*4882a593Smuzhiyun	string	cpu_pxa255_name, "XScale-PXA255"
609*4882a593Smuzhiyun	string	cpu_pxa270_name, "XScale-PXA270"
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun	.align
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun	.section ".proc.info.init", "a"
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun.macro xscale_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache
616*4882a593Smuzhiyun	.type	__\name\()_proc_info,#object
617*4882a593Smuzhiyun__\name\()_proc_info:
618*4882a593Smuzhiyun	.long	\cpu_val
619*4882a593Smuzhiyun	.long	\cpu_mask
620*4882a593Smuzhiyun	.long	PMD_TYPE_SECT | \
621*4882a593Smuzhiyun		PMD_SECT_BUFFERABLE | \
622*4882a593Smuzhiyun		PMD_SECT_CACHEABLE | \
623*4882a593Smuzhiyun		PMD_SECT_AP_WRITE | \
624*4882a593Smuzhiyun		PMD_SECT_AP_READ
625*4882a593Smuzhiyun	.long	PMD_TYPE_SECT | \
626*4882a593Smuzhiyun		PMD_SECT_AP_WRITE | \
627*4882a593Smuzhiyun		PMD_SECT_AP_READ
628*4882a593Smuzhiyun	initfn	__xscale_setup, __\name\()_proc_info
629*4882a593Smuzhiyun	.long	cpu_arch_name
630*4882a593Smuzhiyun	.long	cpu_elf_name
631*4882a593Smuzhiyun	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
632*4882a593Smuzhiyun	.long	\cpu_name
633*4882a593Smuzhiyun	.long	xscale_processor_functions
634*4882a593Smuzhiyun	.long	v4wbi_tlb_fns
635*4882a593Smuzhiyun	.long	xscale_mc_user_fns
636*4882a593Smuzhiyun	.ifb \cache
637*4882a593Smuzhiyun		.long	xscale_cache_fns
638*4882a593Smuzhiyun	.else
639*4882a593Smuzhiyun		.long	\cache
640*4882a593Smuzhiyun	.endif
641*4882a593Smuzhiyun	.size	__\name\()_proc_info, . - __\name\()_proc_info
642*4882a593Smuzhiyun.endm
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun	xscale_proc_info 80200_A0_A1, 0x69052000, 0xfffffffe, cpu_80200_name, \
645*4882a593Smuzhiyun		cache=xscale_80200_A0_A1_cache_fns
646*4882a593Smuzhiyun	xscale_proc_info 80200, 0x69052000, 0xfffffff0, cpu_80200_name
647*4882a593Smuzhiyun	xscale_proc_info 80219, 0x69052e20, 0xffffffe0, cpu_80219_name
648*4882a593Smuzhiyun	xscale_proc_info 8032x, 0x69052420, 0xfffff7e0, cpu_8032x_name
649*4882a593Smuzhiyun	xscale_proc_info 8033x, 0x69054010, 0xfffffd30, cpu_8033x_name
650*4882a593Smuzhiyun	xscale_proc_info pxa250, 0x69052100, 0xfffff7f0, cpu_pxa250_name
651*4882a593Smuzhiyun	xscale_proc_info pxa210, 0x69052120, 0xfffff3f0, cpu_pxa210_name
652*4882a593Smuzhiyun	xscale_proc_info ixp2400, 0x69054190, 0xfffffff0, cpu_ixp2400_name
653*4882a593Smuzhiyun	xscale_proc_info ixp2800, 0x690541a0, 0xfffffff0, cpu_ixp2800_name
654*4882a593Smuzhiyun	xscale_proc_info ixp42x, 0x690541c0, 0xffffffc0, cpu_ixp42x_name
655*4882a593Smuzhiyun	xscale_proc_info ixp43x, 0x69054040, 0xfffffff0, cpu_ixp43x_name
656*4882a593Smuzhiyun	xscale_proc_info ixp46x, 0x69054200, 0xffffff00, cpu_ixp46x_name
657*4882a593Smuzhiyun	xscale_proc_info pxa255, 0x69052d00, 0xfffffff0, cpu_pxa255_name
658*4882a593Smuzhiyun	xscale_proc_info pxa270, 0x69054110, 0xfffffff0, cpu_pxa270_name
659