xref: /OK3568_Linux_fs/kernel/arch/arm/mm/cache-v7.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun *  linux/arch/arm/mm/cache-v7.S
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun *  Copyright (C) 2001 Deep Blue Solutions Ltd.
6*4882a593Smuzhiyun *  Copyright (C) 2005 ARM Ltd.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun *  This is the "shell" of the ARMv7 processor support.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun#include <linux/linkage.h>
11*4882a593Smuzhiyun#include <linux/init.h>
12*4882a593Smuzhiyun#include <asm/assembler.h>
13*4882a593Smuzhiyun#include <asm/errno.h>
14*4882a593Smuzhiyun#include <asm/unwind.h>
15*4882a593Smuzhiyun#include <asm/hardware/cache-b15-rac.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun#include "proc-macros.S"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun#ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND
20*4882a593Smuzhiyun.globl icache_size
21*4882a593Smuzhiyun	.data
22*4882a593Smuzhiyun	.align	2
23*4882a593Smuzhiyunicache_size:
24*4882a593Smuzhiyun	.long	64
25*4882a593Smuzhiyun	.text
26*4882a593Smuzhiyun#endif
27*4882a593Smuzhiyun/*
28*4882a593Smuzhiyun * The secondary kernel init calls v7_flush_dcache_all before it enables
29*4882a593Smuzhiyun * the L1; however, the L1 comes out of reset in an undefined state, so
30*4882a593Smuzhiyun * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
31*4882a593Smuzhiyun * of cache lines with uninitialized data and uninitialized tags to get
32*4882a593Smuzhiyun * written out to memory, which does really unpleasant things to the main
33*4882a593Smuzhiyun * processor.  We fix this by performing an invalidate, rather than a
34*4882a593Smuzhiyun * clean + invalidate, before jumping into the kernel.
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * This function is cloned from arch/arm/mach-tegra/headsmp.S, and needs
37*4882a593Smuzhiyun * to be called for both secondary cores startup and primary core resume
38*4882a593Smuzhiyun * procedures.
39*4882a593Smuzhiyun */
40*4882a593SmuzhiyunENTRY(v7_invalidate_l1)
41*4882a593Smuzhiyun       mov     r0, #0
42*4882a593Smuzhiyun       mcr     p15, 2, r0, c0, c0, 0
43*4882a593Smuzhiyun       mrc     p15, 1, r0, c0, c0, 0
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun       movw    r1, #0x7fff
46*4882a593Smuzhiyun       and     r2, r1, r0, lsr #13
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun       movw    r1, #0x3ff
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun       and     r3, r1, r0, lsr #3      @ NumWays - 1
51*4882a593Smuzhiyun       add     r2, r2, #1              @ NumSets
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun       and     r0, r0, #0x7
54*4882a593Smuzhiyun       add     r0, r0, #4      @ SetShift
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun       clz     r1, r3          @ WayShift
57*4882a593Smuzhiyun       add     r4, r3, #1      @ NumWays
58*4882a593Smuzhiyun1:     sub     r2, r2, #1      @ NumSets--
59*4882a593Smuzhiyun       mov     r3, r4          @ Temp = NumWays
60*4882a593Smuzhiyun2:     subs    r3, r3, #1      @ Temp--
61*4882a593Smuzhiyun       mov     r5, r3, lsl r1
62*4882a593Smuzhiyun       mov     r6, r2, lsl r0
63*4882a593Smuzhiyun       orr     r5, r5, r6      @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
64*4882a593Smuzhiyun       mcr     p15, 0, r5, c7, c6, 2
65*4882a593Smuzhiyun       bgt     2b
66*4882a593Smuzhiyun       cmp     r2, #0
67*4882a593Smuzhiyun       bgt     1b
68*4882a593Smuzhiyun       dsb     st
69*4882a593Smuzhiyun       isb
70*4882a593Smuzhiyun       ret     lr
71*4882a593SmuzhiyunENDPROC(v7_invalidate_l1)
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun/*
74*4882a593Smuzhiyun *	v7_flush_icache_all()
75*4882a593Smuzhiyun *
76*4882a593Smuzhiyun *	Flush the whole I-cache.
77*4882a593Smuzhiyun *
78*4882a593Smuzhiyun *	Registers:
79*4882a593Smuzhiyun *	r0 - set to 0
80*4882a593Smuzhiyun */
81*4882a593SmuzhiyunENTRY(v7_flush_icache_all)
82*4882a593Smuzhiyun	mov	r0, #0
83*4882a593Smuzhiyun	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)		@ invalidate I-cache inner shareable
84*4882a593Smuzhiyun	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)		@ I+BTB cache invalidate
85*4882a593Smuzhiyun	ret	lr
86*4882a593SmuzhiyunENDPROC(v7_flush_icache_all)
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun *     v7_flush_dcache_louis()
90*4882a593Smuzhiyun *
91*4882a593Smuzhiyun *     Flush the D-cache up to the Level of Unification Inner Shareable
92*4882a593Smuzhiyun *
93*4882a593Smuzhiyun *     Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
94*4882a593Smuzhiyun */
95*4882a593Smuzhiyun
96*4882a593SmuzhiyunENTRY(v7_flush_dcache_louis)
97*4882a593Smuzhiyun	dmb					@ ensure ordering with previous memory accesses
98*4882a593Smuzhiyun	mrc	p15, 1, r0, c0, c0, 1		@ read clidr, r0 = clidr
99*4882a593SmuzhiyunALT_SMP(mov	r3, r0, lsr #20)		@ move LoUIS into position
100*4882a593SmuzhiyunALT_UP(	mov	r3, r0, lsr #26)		@ move LoUU into position
101*4882a593Smuzhiyun	ands	r3, r3, #7 << 1 		@ extract LoU*2 field from clidr
102*4882a593Smuzhiyun	bne	start_flush_levels		@ LoU != 0, start flushing
103*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_643719
104*4882a593SmuzhiyunALT_SMP(mrc	p15, 0, r2, c0, c0, 0)		@ read main ID register
105*4882a593SmuzhiyunALT_UP(	ret	lr)				@ LoUU is zero, so nothing to do
106*4882a593Smuzhiyun	movw	r1, #:lower16:(0x410fc090 >> 4)	@ ID of ARM Cortex A9 r0p?
107*4882a593Smuzhiyun	movt	r1, #:upper16:(0x410fc090 >> 4)
108*4882a593Smuzhiyun	teq	r1, r2, lsr #4			@ test for errata affected core and if so...
109*4882a593Smuzhiyun	moveq	r3, #1 << 1			@   fix LoUIS value
110*4882a593Smuzhiyun	beq	start_flush_levels		@   start flushing cache levels
111*4882a593Smuzhiyun#endif
112*4882a593Smuzhiyun	ret	lr
113*4882a593SmuzhiyunENDPROC(v7_flush_dcache_louis)
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun/*
116*4882a593Smuzhiyun *	v7_flush_dcache_all()
117*4882a593Smuzhiyun *
118*4882a593Smuzhiyun *	Flush the whole D-cache.
119*4882a593Smuzhiyun *
120*4882a593Smuzhiyun *	Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
121*4882a593Smuzhiyun *
122*4882a593Smuzhiyun *	- mm    - mm_struct describing address space
123*4882a593Smuzhiyun */
124*4882a593SmuzhiyunENTRY(v7_flush_dcache_all)
125*4882a593Smuzhiyun	dmb					@ ensure ordering with previous memory accesses
126*4882a593Smuzhiyun	mrc	p15, 1, r0, c0, c0, 1		@ read clidr
127*4882a593Smuzhiyun	mov	r3, r0, lsr #23			@ move LoC into position
128*4882a593Smuzhiyun	ands	r3, r3, #7 << 1			@ extract LoC*2 from clidr
129*4882a593Smuzhiyun	beq	finished			@ if loc is 0, then no need to clean
130*4882a593Smuzhiyunstart_flush_levels:
131*4882a593Smuzhiyun	mov	r10, #0				@ start clean at cache level 0
132*4882a593Smuzhiyunflush_levels:
133*4882a593Smuzhiyun	add	r2, r10, r10, lsr #1		@ work out 3x current cache level
134*4882a593Smuzhiyun	mov	r1, r0, lsr r2			@ extract cache type bits from clidr
135*4882a593Smuzhiyun	and	r1, r1, #7			@ mask of the bits for current cache only
136*4882a593Smuzhiyun	cmp	r1, #2				@ see what cache we have at this level
137*4882a593Smuzhiyun	blt	skip				@ skip if no cache, or just i-cache
138*4882a593Smuzhiyun#ifdef CONFIG_PREEMPTION
139*4882a593Smuzhiyun	save_and_disable_irqs_notrace r9	@ make cssr&csidr read atomic
140*4882a593Smuzhiyun#endif
141*4882a593Smuzhiyun	mcr	p15, 2, r10, c0, c0, 0		@ select current cache level in cssr
142*4882a593Smuzhiyun	isb					@ isb to sych the new cssr&csidr
143*4882a593Smuzhiyun	mrc	p15, 1, r1, c0, c0, 0		@ read the new csidr
144*4882a593Smuzhiyun#ifdef CONFIG_PREEMPTION
145*4882a593Smuzhiyun	restore_irqs_notrace r9
146*4882a593Smuzhiyun#endif
147*4882a593Smuzhiyun	and	r2, r1, #7			@ extract the length of the cache lines
148*4882a593Smuzhiyun	add	r2, r2, #4			@ add 4 (line length offset)
149*4882a593Smuzhiyun	movw	r4, #0x3ff
150*4882a593Smuzhiyun	ands	r4, r4, r1, lsr #3		@ find maximum number on the way size
151*4882a593Smuzhiyun	clz	r5, r4				@ find bit position of way size increment
152*4882a593Smuzhiyun	movw	r7, #0x7fff
153*4882a593Smuzhiyun	ands	r7, r7, r1, lsr #13		@ extract max number of the index size
154*4882a593Smuzhiyunloop1:
155*4882a593Smuzhiyun	mov	r9, r7				@ create working copy of max index
156*4882a593Smuzhiyunloop2:
157*4882a593Smuzhiyun ARM(	orr	r11, r10, r4, lsl r5	)	@ factor way and cache number into r11
158*4882a593Smuzhiyun THUMB(	lsl	r6, r4, r5		)
159*4882a593Smuzhiyun THUMB(	orr	r11, r10, r6		)	@ factor way and cache number into r11
160*4882a593Smuzhiyun ARM(	orr	r11, r11, r9, lsl r2	)	@ factor index number into r11
161*4882a593Smuzhiyun THUMB(	lsl	r6, r9, r2		)
162*4882a593Smuzhiyun THUMB(	orr	r11, r11, r6		)	@ factor index number into r11
163*4882a593Smuzhiyun	mcr	p15, 0, r11, c7, c14, 2		@ clean & invalidate by set/way
164*4882a593Smuzhiyun	subs	r9, r9, #1			@ decrement the index
165*4882a593Smuzhiyun	bge	loop2
166*4882a593Smuzhiyun	subs	r4, r4, #1			@ decrement the way
167*4882a593Smuzhiyun	bge	loop1
168*4882a593Smuzhiyunskip:
169*4882a593Smuzhiyun	add	r10, r10, #2			@ increment cache number
170*4882a593Smuzhiyun	cmp	r3, r10
171*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_814220
172*4882a593Smuzhiyun	dsb
173*4882a593Smuzhiyun#endif
174*4882a593Smuzhiyun	bgt	flush_levels
175*4882a593Smuzhiyunfinished:
176*4882a593Smuzhiyun	mov	r10, #0				@ switch back to cache level 0
177*4882a593Smuzhiyun	mcr	p15, 2, r10, c0, c0, 0		@ select current cache level in cssr
178*4882a593Smuzhiyun	dsb	st
179*4882a593Smuzhiyun	isb
180*4882a593Smuzhiyun	ret	lr
181*4882a593SmuzhiyunENDPROC(v7_flush_dcache_all)
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun/*
184*4882a593Smuzhiyun *	v7_flush_cache_all()
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun *	Flush the entire cache system.
187*4882a593Smuzhiyun *  The data cache flush is now achieved using atomic clean / invalidates
188*4882a593Smuzhiyun *  working outwards from L1 cache. This is done using Set/Way based cache
189*4882a593Smuzhiyun *  maintenance instructions.
190*4882a593Smuzhiyun *  The instruction cache can still be invalidated back to the point of
191*4882a593Smuzhiyun *  unification in a single instruction.
192*4882a593Smuzhiyun *
193*4882a593Smuzhiyun */
194*4882a593SmuzhiyunENTRY(v7_flush_kern_cache_all)
195*4882a593Smuzhiyun ARM(	stmfd	sp!, {r4-r5, r7, r9-r11, lr}	)
196*4882a593Smuzhiyun THUMB(	stmfd	sp!, {r4-r7, r9-r11, lr}	)
197*4882a593Smuzhiyun	bl	v7_flush_dcache_all
198*4882a593Smuzhiyun	mov	r0, #0
199*4882a593Smuzhiyun	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)	@ invalidate I-cache inner shareable
200*4882a593Smuzhiyun	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)	@ I+BTB cache invalidate
201*4882a593Smuzhiyun ARM(	ldmfd	sp!, {r4-r5, r7, r9-r11, lr}	)
202*4882a593Smuzhiyun THUMB(	ldmfd	sp!, {r4-r7, r9-r11, lr}	)
203*4882a593Smuzhiyun	ret	lr
204*4882a593SmuzhiyunENDPROC(v7_flush_kern_cache_all)
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /*
207*4882a593Smuzhiyun *     v7_flush_kern_cache_louis(void)
208*4882a593Smuzhiyun *
209*4882a593Smuzhiyun *     Flush the data cache up to Level of Unification Inner Shareable.
210*4882a593Smuzhiyun *     Invalidate the I-cache to the point of unification.
211*4882a593Smuzhiyun */
212*4882a593SmuzhiyunENTRY(v7_flush_kern_cache_louis)
213*4882a593Smuzhiyun ARM(	stmfd	sp!, {r4-r5, r7, r9-r11, lr}	)
214*4882a593Smuzhiyun THUMB(	stmfd	sp!, {r4-r7, r9-r11, lr}	)
215*4882a593Smuzhiyun	bl	v7_flush_dcache_louis
216*4882a593Smuzhiyun	mov	r0, #0
217*4882a593Smuzhiyun	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)	@ invalidate I-cache inner shareable
218*4882a593Smuzhiyun	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)	@ I+BTB cache invalidate
219*4882a593Smuzhiyun ARM(	ldmfd	sp!, {r4-r5, r7, r9-r11, lr}	)
220*4882a593Smuzhiyun THUMB(	ldmfd	sp!, {r4-r7, r9-r11, lr}	)
221*4882a593Smuzhiyun	ret	lr
222*4882a593SmuzhiyunENDPROC(v7_flush_kern_cache_louis)
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun/*
225*4882a593Smuzhiyun *	v7_flush_cache_all()
226*4882a593Smuzhiyun *
227*4882a593Smuzhiyun *	Flush all TLB entries in a particular address space
228*4882a593Smuzhiyun *
229*4882a593Smuzhiyun *	- mm    - mm_struct describing address space
230*4882a593Smuzhiyun */
231*4882a593SmuzhiyunENTRY(v7_flush_user_cache_all)
232*4882a593Smuzhiyun	/*FALLTHROUGH*/
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun/*
235*4882a593Smuzhiyun *	v7_flush_cache_range(start, end, flags)
236*4882a593Smuzhiyun *
237*4882a593Smuzhiyun *	Flush a range of TLB entries in the specified address space.
238*4882a593Smuzhiyun *
239*4882a593Smuzhiyun *	- start - start address (may not be aligned)
240*4882a593Smuzhiyun *	- end   - end address (exclusive, may not be aligned)
241*4882a593Smuzhiyun *	- flags	- vm_area_struct flags describing address space
242*4882a593Smuzhiyun *
243*4882a593Smuzhiyun *	It is assumed that:
244*4882a593Smuzhiyun *	- we have a VIPT cache.
245*4882a593Smuzhiyun */
246*4882a593SmuzhiyunENTRY(v7_flush_user_cache_range)
247*4882a593Smuzhiyun	ret	lr
248*4882a593SmuzhiyunENDPROC(v7_flush_user_cache_all)
249*4882a593SmuzhiyunENDPROC(v7_flush_user_cache_range)
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun/*
252*4882a593Smuzhiyun *	v7_coherent_kern_range(start,end)
253*4882a593Smuzhiyun *
254*4882a593Smuzhiyun *	Ensure that the I and D caches are coherent within specified
255*4882a593Smuzhiyun *	region.  This is typically used when code has been written to
256*4882a593Smuzhiyun *	a memory region, and will be executed.
257*4882a593Smuzhiyun *
258*4882a593Smuzhiyun *	- start   - virtual start address of region
259*4882a593Smuzhiyun *	- end     - virtual end address of region
260*4882a593Smuzhiyun *
261*4882a593Smuzhiyun *	It is assumed that:
262*4882a593Smuzhiyun *	- the Icache does not read data from the write buffer
263*4882a593Smuzhiyun */
264*4882a593SmuzhiyunENTRY(v7_coherent_kern_range)
265*4882a593Smuzhiyun	/* FALLTHROUGH */
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun/*
268*4882a593Smuzhiyun *	v7_coherent_user_range(start,end)
269*4882a593Smuzhiyun *
270*4882a593Smuzhiyun *	Ensure that the I and D caches are coherent within specified
271*4882a593Smuzhiyun *	region.  This is typically used when code has been written to
272*4882a593Smuzhiyun *	a memory region, and will be executed.
273*4882a593Smuzhiyun *
274*4882a593Smuzhiyun *	- start   - virtual start address of region
275*4882a593Smuzhiyun *	- end     - virtual end address of region
276*4882a593Smuzhiyun *
277*4882a593Smuzhiyun *	It is assumed that:
278*4882a593Smuzhiyun *	- the Icache does not read data from the write buffer
279*4882a593Smuzhiyun */
280*4882a593SmuzhiyunENTRY(v7_coherent_user_range)
281*4882a593Smuzhiyun UNWIND(.fnstart		)
282*4882a593Smuzhiyun	dcache_line_size r2, r3
283*4882a593Smuzhiyun	sub	r3, r2, #1
284*4882a593Smuzhiyun	bic	r12, r0, r3
285*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_764369
286*4882a593Smuzhiyun	ALT_SMP(W(dsb))
287*4882a593Smuzhiyun	ALT_UP(W(nop))
288*4882a593Smuzhiyun#endif
289*4882a593Smuzhiyun1:
290*4882a593Smuzhiyun USER(	mcr	p15, 0, r12, c7, c11, 1	)	@ clean D line to the point of unification
291*4882a593Smuzhiyun	add	r12, r12, r2
292*4882a593Smuzhiyun	cmp	r12, r1
293*4882a593Smuzhiyun	blo	1b
294*4882a593Smuzhiyun	dsb	ishst
295*4882a593Smuzhiyun#ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND
296*4882a593Smuzhiyun	ldr	r3, =icache_size
297*4882a593Smuzhiyun	ldr	r2, [r3, #0]
298*4882a593Smuzhiyun#else
299*4882a593Smuzhiyun	icache_line_size r2, r3
300*4882a593Smuzhiyun#endif
301*4882a593Smuzhiyun	sub	r3, r2, #1
302*4882a593Smuzhiyun	bic	r12, r0, r3
303*4882a593Smuzhiyun2:
304*4882a593Smuzhiyun USER(	mcr	p15, 0, r12, c7, c5, 1	)	@ invalidate I line
305*4882a593Smuzhiyun	add	r12, r12, r2
306*4882a593Smuzhiyun	cmp	r12, r1
307*4882a593Smuzhiyun	blo	2b
308*4882a593Smuzhiyun	mov	r0, #0
309*4882a593Smuzhiyun	ALT_SMP(mcr	p15, 0, r0, c7, c1, 6)	@ invalidate BTB Inner Shareable
310*4882a593Smuzhiyun	ALT_UP(mcr	p15, 0, r0, c7, c5, 6)	@ invalidate BTB
311*4882a593Smuzhiyun	dsb	ishst
312*4882a593Smuzhiyun	isb
313*4882a593Smuzhiyun	ret	lr
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun/*
316*4882a593Smuzhiyun * Fault handling for the cache operation above. If the virtual address in r0
317*4882a593Smuzhiyun * isn't mapped, fail with -EFAULT.
318*4882a593Smuzhiyun */
319*4882a593Smuzhiyun9001:
320*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_775420
321*4882a593Smuzhiyun	dsb
322*4882a593Smuzhiyun#endif
323*4882a593Smuzhiyun	mov	r0, #-EFAULT
324*4882a593Smuzhiyun	ret	lr
325*4882a593Smuzhiyun UNWIND(.fnend		)
326*4882a593SmuzhiyunENDPROC(v7_coherent_kern_range)
327*4882a593SmuzhiyunENDPROC(v7_coherent_user_range)
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun/*
330*4882a593Smuzhiyun *	v7_flush_kern_dcache_area(void *addr, size_t size)
331*4882a593Smuzhiyun *
332*4882a593Smuzhiyun *	Ensure that the data held in the page kaddr is written back
333*4882a593Smuzhiyun *	to the page in question.
334*4882a593Smuzhiyun *
335*4882a593Smuzhiyun *	- addr	- kernel address
336*4882a593Smuzhiyun *	- size	- region size
337*4882a593Smuzhiyun */
338*4882a593SmuzhiyunENTRY(v7_flush_kern_dcache_area)
339*4882a593Smuzhiyun	dcache_line_size r2, r3
340*4882a593Smuzhiyun	add	r1, r0, r1
341*4882a593Smuzhiyun	sub	r3, r2, #1
342*4882a593Smuzhiyun	bic	r0, r0, r3
343*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_764369
344*4882a593Smuzhiyun	ALT_SMP(W(dsb))
345*4882a593Smuzhiyun	ALT_UP(W(nop))
346*4882a593Smuzhiyun#endif
347*4882a593Smuzhiyun1:
348*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D line / unified line
349*4882a593Smuzhiyun	add	r0, r0, r2
350*4882a593Smuzhiyun	cmp	r0, r1
351*4882a593Smuzhiyun	blo	1b
352*4882a593Smuzhiyun	dsb	st
353*4882a593Smuzhiyun	ret	lr
354*4882a593SmuzhiyunENDPROC(v7_flush_kern_dcache_area)
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun/*
357*4882a593Smuzhiyun *	v7_dma_inv_range(start,end)
358*4882a593Smuzhiyun *
359*4882a593Smuzhiyun *	Invalidate the data cache within the specified region; we will
360*4882a593Smuzhiyun *	be performing a DMA operation in this region and we want to
361*4882a593Smuzhiyun *	purge old data in the cache.
362*4882a593Smuzhiyun *
363*4882a593Smuzhiyun *	- start   - virtual start address of region
364*4882a593Smuzhiyun *	- end     - virtual end address of region
365*4882a593Smuzhiyun */
366*4882a593Smuzhiyunv7_dma_inv_range:
367*4882a593Smuzhiyun	dcache_line_size r2, r3
368*4882a593Smuzhiyun	sub	r3, r2, #1
369*4882a593Smuzhiyun	tst	r0, r3
370*4882a593Smuzhiyun	bic	r0, r0, r3
371*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_764369
372*4882a593Smuzhiyun	ALT_SMP(W(dsb))
373*4882a593Smuzhiyun	ALT_UP(W(nop))
374*4882a593Smuzhiyun#endif
375*4882a593Smuzhiyun	mcrne	p15, 0, r0, c7, c14, 1		@ clean & invalidate D / U line
376*4882a593Smuzhiyun	addne	r0, r0, r2
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun	tst	r1, r3
379*4882a593Smuzhiyun	bic	r1, r1, r3
380*4882a593Smuzhiyun	mcrne	p15, 0, r1, c7, c14, 1		@ clean & invalidate D / U line
381*4882a593Smuzhiyun	cmp	r0, r1
382*4882a593Smuzhiyun1:
383*4882a593Smuzhiyun	mcrlo	p15, 0, r0, c7, c6, 1		@ invalidate D / U line
384*4882a593Smuzhiyun	addlo	r0, r0, r2
385*4882a593Smuzhiyun	cmplo	r0, r1
386*4882a593Smuzhiyun	blo	1b
387*4882a593Smuzhiyun	dsb	st
388*4882a593Smuzhiyun	ret	lr
389*4882a593SmuzhiyunENDPROC(v7_dma_inv_range)
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun/*
392*4882a593Smuzhiyun *	v7_dma_clean_range(start,end)
393*4882a593Smuzhiyun *	- start   - virtual start address of region
394*4882a593Smuzhiyun *	- end     - virtual end address of region
395*4882a593Smuzhiyun */
396*4882a593Smuzhiyunv7_dma_clean_range:
397*4882a593Smuzhiyun	dcache_line_size r2, r3
398*4882a593Smuzhiyun	sub	r3, r2, #1
399*4882a593Smuzhiyun	bic	r0, r0, r3
400*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_764369
401*4882a593Smuzhiyun	ALT_SMP(W(dsb))
402*4882a593Smuzhiyun	ALT_UP(W(nop))
403*4882a593Smuzhiyun#endif
404*4882a593Smuzhiyun1:
405*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c10, 1		@ clean D / U line
406*4882a593Smuzhiyun	add	r0, r0, r2
407*4882a593Smuzhiyun	cmp	r0, r1
408*4882a593Smuzhiyun	blo	1b
409*4882a593Smuzhiyun	dsb	st
410*4882a593Smuzhiyun	ret	lr
411*4882a593SmuzhiyunENDPROC(v7_dma_clean_range)
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun/*
414*4882a593Smuzhiyun *	v7_dma_flush_range(start,end)
415*4882a593Smuzhiyun *	- start   - virtual start address of region
416*4882a593Smuzhiyun *	- end     - virtual end address of region
417*4882a593Smuzhiyun */
418*4882a593SmuzhiyunENTRY(v7_dma_flush_range)
419*4882a593Smuzhiyun	dcache_line_size r2, r3
420*4882a593Smuzhiyun	sub	r3, r2, #1
421*4882a593Smuzhiyun	bic	r0, r0, r3
422*4882a593Smuzhiyun#ifdef CONFIG_ARM_ERRATA_764369
423*4882a593Smuzhiyun	ALT_SMP(W(dsb))
424*4882a593Smuzhiyun	ALT_UP(W(nop))
425*4882a593Smuzhiyun#endif
426*4882a593Smuzhiyun1:
427*4882a593Smuzhiyun	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D / U line
428*4882a593Smuzhiyun	add	r0, r0, r2
429*4882a593Smuzhiyun	cmp	r0, r1
430*4882a593Smuzhiyun	blo	1b
431*4882a593Smuzhiyun	dsb	st
432*4882a593Smuzhiyun	ret	lr
433*4882a593SmuzhiyunENDPROC(v7_dma_flush_range)
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun/*
436*4882a593Smuzhiyun *	dma_map_area(start, size, dir)
437*4882a593Smuzhiyun *	- start	- kernel virtual start address
438*4882a593Smuzhiyun *	- size	- size of region
439*4882a593Smuzhiyun *	- dir	- DMA direction
440*4882a593Smuzhiyun */
441*4882a593SmuzhiyunENTRY(v7_dma_map_area)
442*4882a593Smuzhiyun	add	r1, r1, r0
443*4882a593Smuzhiyun	teq	r2, #DMA_FROM_DEVICE
444*4882a593Smuzhiyun	beq	v7_dma_inv_range
445*4882a593Smuzhiyun	b	v7_dma_clean_range
446*4882a593SmuzhiyunENDPROC(v7_dma_map_area)
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun/*
449*4882a593Smuzhiyun *	dma_unmap_area(start, size, dir)
450*4882a593Smuzhiyun *	- start	- kernel virtual start address
451*4882a593Smuzhiyun *	- size	- size of region
452*4882a593Smuzhiyun *	- dir	- DMA direction
453*4882a593Smuzhiyun */
454*4882a593SmuzhiyunENTRY(v7_dma_unmap_area)
455*4882a593Smuzhiyun	add	r1, r1, r0
456*4882a593Smuzhiyun	teq	r2, #DMA_TO_DEVICE
457*4882a593Smuzhiyun	bne	v7_dma_inv_range
458*4882a593Smuzhiyun	ret	lr
459*4882a593SmuzhiyunENDPROC(v7_dma_unmap_area)
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun	__INITDATA
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
464*4882a593Smuzhiyun	define_cache_functions v7
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun	/* The Broadcom Brahma-B15 read-ahead cache requires some modifications
467*4882a593Smuzhiyun	 * to the v7_cache_fns, we only override the ones we need
468*4882a593Smuzhiyun	 */
469*4882a593Smuzhiyun#ifndef CONFIG_CACHE_B15_RAC
470*4882a593Smuzhiyun	globl_equ	b15_flush_kern_cache_all,	v7_flush_kern_cache_all
471*4882a593Smuzhiyun#endif
472*4882a593Smuzhiyun	globl_equ	b15_flush_icache_all,		v7_flush_icache_all
473*4882a593Smuzhiyun	globl_equ	b15_flush_kern_cache_louis,	v7_flush_kern_cache_louis
474*4882a593Smuzhiyun	globl_equ	b15_flush_user_cache_all,	v7_flush_user_cache_all
475*4882a593Smuzhiyun	globl_equ	b15_flush_user_cache_range,	v7_flush_user_cache_range
476*4882a593Smuzhiyun	globl_equ	b15_coherent_kern_range,	v7_coherent_kern_range
477*4882a593Smuzhiyun	globl_equ	b15_coherent_user_range,	v7_coherent_user_range
478*4882a593Smuzhiyun	globl_equ	b15_flush_kern_dcache_area,	v7_flush_kern_dcache_area
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun	globl_equ	b15_dma_map_area,		v7_dma_map_area
481*4882a593Smuzhiyun	globl_equ	b15_dma_unmap_area,		v7_dma_unmap_area
482*4882a593Smuzhiyun	globl_equ	b15_dma_flush_range,		v7_dma_flush_range
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun	define_cache_functions b15
485