162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/arch/arm/mm/cache-v7.S
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2001 Deep Blue Solutions Ltd.
662306a36Sopenharmony_ci *  Copyright (C) 2005 ARM Ltd.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  This is the "shell" of the ARMv7 processor support.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci#include <linux/linkage.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <asm/assembler.h>
1362306a36Sopenharmony_ci#include <asm/errno.h>
1462306a36Sopenharmony_ci#include <asm/unwind.h>
1562306a36Sopenharmony_ci#include <asm/hardware/cache-b15-rac.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "proc-macros.S"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci.arch armv7-a
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND
2262306a36Sopenharmony_ci.globl icache_size
2362306a36Sopenharmony_ci	.data
2462306a36Sopenharmony_ci	.align	2
2562306a36Sopenharmony_ciicache_size:
2662306a36Sopenharmony_ci	.long	64
2762306a36Sopenharmony_ci	.text
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci/*
3062306a36Sopenharmony_ci * The secondary kernel init calls v7_flush_dcache_all before it enables
3162306a36Sopenharmony_ci * the L1; however, the L1 comes out of reset in an undefined state, so
3262306a36Sopenharmony_ci * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
3362306a36Sopenharmony_ci * of cache lines with uninitialized data and uninitialized tags to get
3462306a36Sopenharmony_ci * written out to memory, which does really unpleasant things to the main
3562306a36Sopenharmony_ci * processor.  We fix this by performing an invalidate, rather than a
3662306a36Sopenharmony_ci * clean + invalidate, before jumping into the kernel.
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * This function needs to be called for both secondary cores startup and
3962306a36Sopenharmony_ci * primary core resume procedures.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ciENTRY(v7_invalidate_l1)
4262306a36Sopenharmony_ci	mov	r0, #0
4362306a36Sopenharmony_ci	mcr	p15, 2, r0, c0, c0, 0	@ select L1 data cache in CSSELR
4462306a36Sopenharmony_ci	isb
4562306a36Sopenharmony_ci	mrc	p15, 1, r0, c0, c0, 0	@ read cache geometry from CCSIDR
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	movw	r3, #0x3ff
4862306a36Sopenharmony_ci	and	r3, r3, r0, lsr #3	@ 'Associativity' in CCSIDR[12:3]
4962306a36Sopenharmony_ci	clz	r1, r3			@ WayShift
5062306a36Sopenharmony_ci	mov	r2, #1
5162306a36Sopenharmony_ci	mov	r3, r3, lsl r1		@ NumWays-1 shifted into bits [31:...]
5262306a36Sopenharmony_ci	movs	r1, r2, lsl r1		@ #1 shifted left by same amount
5362306a36Sopenharmony_ci	moveq	r1, #1			@ r1 needs value > 0 even if only 1 way
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	and	r2, r0, #0x7
5662306a36Sopenharmony_ci	add	r2, r2, #4		@ SetShift
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci1:	movw	ip, #0x7fff
5962306a36Sopenharmony_ci	and	r0, ip, r0, lsr #13	@ 'NumSets' in CCSIDR[27:13]
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci2:	mov	ip, r0, lsl r2		@ NumSet << SetShift
6262306a36Sopenharmony_ci	orr	ip, ip, r3		@ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
6362306a36Sopenharmony_ci	mcr	p15, 0, ip, c7, c6, 2
6462306a36Sopenharmony_ci	subs	r0, r0, #1		@ Set--
6562306a36Sopenharmony_ci	bpl	2b
6662306a36Sopenharmony_ci	subs	r3, r3, r1		@ Way--
6762306a36Sopenharmony_ci	bcc	3f
6862306a36Sopenharmony_ci	mrc	p15, 1, r0, c0, c0, 0	@ re-read cache geometry from CCSIDR
6962306a36Sopenharmony_ci	b	1b
7062306a36Sopenharmony_ci3:	dsb	st
7162306a36Sopenharmony_ci	isb
7262306a36Sopenharmony_ci	ret	lr
7362306a36Sopenharmony_ciENDPROC(v7_invalidate_l1)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/*
7662306a36Sopenharmony_ci *	v7_flush_icache_all()
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci *	Flush the whole I-cache.
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci *	Registers:
8162306a36Sopenharmony_ci *	r0 - set to 0
8262306a36Sopenharmony_ci */
8362306a36Sopenharmony_ciENTRY(v7_flush_icache_all)
8462306a36Sopenharmony_ci	mov	r0, #0
8562306a36Sopenharmony_ci	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)		@ invalidate I-cache inner shareable
8662306a36Sopenharmony_ci	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)		@ I+BTB cache invalidate
8762306a36Sopenharmony_ci	ret	lr
8862306a36Sopenharmony_ciENDPROC(v7_flush_icache_all)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci /*
9162306a36Sopenharmony_ci *     v7_flush_dcache_louis()
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci *     Flush the D-cache up to the Level of Unification Inner Shareable
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci *     Corrupted registers: r0-r6, r9-r10
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ciENTRY(v7_flush_dcache_louis)
9962306a36Sopenharmony_ci	dmb					@ ensure ordering with previous memory accesses
10062306a36Sopenharmony_ci	mrc	p15, 1, r0, c0, c0, 1		@ read clidr, r0 = clidr
10162306a36Sopenharmony_ciALT_SMP(mov	r3, r0, lsr #20)		@ move LoUIS into position
10262306a36Sopenharmony_ciALT_UP(	mov	r3, r0, lsr #26)		@ move LoUU into position
10362306a36Sopenharmony_ci	ands	r3, r3, #7 << 1 		@ extract LoU*2 field from clidr
10462306a36Sopenharmony_ci	bne	start_flush_levels		@ LoU != 0, start flushing
10562306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_643719
10662306a36Sopenharmony_ciALT_SMP(mrc	p15, 0, r2, c0, c0, 0)		@ read main ID register
10762306a36Sopenharmony_ciALT_UP(	ret	lr)				@ LoUU is zero, so nothing to do
10862306a36Sopenharmony_ci	movw	r1, #:lower16:(0x410fc090 >> 4)	@ ID of ARM Cortex A9 r0p?
10962306a36Sopenharmony_ci	movt	r1, #:upper16:(0x410fc090 >> 4)
11062306a36Sopenharmony_ci	teq	r1, r2, lsr #4			@ test for errata affected core and if so...
11162306a36Sopenharmony_ci	moveq	r3, #1 << 1			@   fix LoUIS value
11262306a36Sopenharmony_ci	beq	start_flush_levels		@   start flushing cache levels
11362306a36Sopenharmony_ci#endif
11462306a36Sopenharmony_ci	ret	lr
11562306a36Sopenharmony_ciENDPROC(v7_flush_dcache_louis)
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/*
11862306a36Sopenharmony_ci *	v7_flush_dcache_all()
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci *	Flush the whole D-cache.
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci *	Corrupted registers: r0-r6, r9-r10
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci *	- mm    - mm_struct describing address space
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_ciENTRY(v7_flush_dcache_all)
12762306a36Sopenharmony_ci	dmb					@ ensure ordering with previous memory accesses
12862306a36Sopenharmony_ci	mrc	p15, 1, r0, c0, c0, 1		@ read clidr
12962306a36Sopenharmony_ci	mov	r3, r0, lsr #23			@ move LoC into position
13062306a36Sopenharmony_ci	ands	r3, r3, #7 << 1			@ extract LoC*2 from clidr
13162306a36Sopenharmony_ci	beq	finished			@ if loc is 0, then no need to clean
13262306a36Sopenharmony_cistart_flush_levels:
13362306a36Sopenharmony_ci	mov	r10, #0				@ start clean at cache level 0
13462306a36Sopenharmony_ciflush_levels:
13562306a36Sopenharmony_ci	add	r2, r10, r10, lsr #1		@ work out 3x current cache level
13662306a36Sopenharmony_ci	mov	r1, r0, lsr r2			@ extract cache type bits from clidr
13762306a36Sopenharmony_ci	and	r1, r1, #7			@ mask of the bits for current cache only
13862306a36Sopenharmony_ci	cmp	r1, #2				@ see what cache we have at this level
13962306a36Sopenharmony_ci	blt	skip				@ skip if no cache, or just i-cache
14062306a36Sopenharmony_ci#ifdef CONFIG_PREEMPTION
14162306a36Sopenharmony_ci	save_and_disable_irqs_notrace r9	@ make cssr&csidr read atomic
14262306a36Sopenharmony_ci#endif
14362306a36Sopenharmony_ci	mcr	p15, 2, r10, c0, c0, 0		@ select current cache level in cssr
14462306a36Sopenharmony_ci	isb					@ isb to sych the new cssr&csidr
14562306a36Sopenharmony_ci	mrc	p15, 1, r1, c0, c0, 0		@ read the new csidr
14662306a36Sopenharmony_ci#ifdef CONFIG_PREEMPTION
14762306a36Sopenharmony_ci	restore_irqs_notrace r9
14862306a36Sopenharmony_ci#endif
14962306a36Sopenharmony_ci	and	r2, r1, #7			@ extract the length of the cache lines
15062306a36Sopenharmony_ci	add	r2, r2, #4			@ add 4 (line length offset)
15162306a36Sopenharmony_ci	movw	r4, #0x3ff
15262306a36Sopenharmony_ci	ands	r4, r4, r1, lsr #3		@ find maximum number on the way size
15362306a36Sopenharmony_ci	clz	r5, r4				@ find bit position of way size increment
15462306a36Sopenharmony_ci	movw	r6, #0x7fff
15562306a36Sopenharmony_ci	and	r1, r6, r1, lsr #13		@ extract max number of the index size
15662306a36Sopenharmony_ci	mov	r6, #1
15762306a36Sopenharmony_ci	movne	r4, r4, lsl r5			@ # of ways shifted into bits [31:...]
15862306a36Sopenharmony_ci	movne	r6, r6, lsl r5			@ 1 shifted left by same amount
15962306a36Sopenharmony_ciloop1:
16062306a36Sopenharmony_ci	mov	r9, r1				@ create working copy of max index
16162306a36Sopenharmony_ciloop2:
16262306a36Sopenharmony_ci	mov	r5, r9, lsl r2			@ factor set number into r5
16362306a36Sopenharmony_ci	orr	r5, r5, r4			@ factor way number into r5
16462306a36Sopenharmony_ci	orr	r5, r5, r10			@ factor cache level into r5
16562306a36Sopenharmony_ci	mcr	p15, 0, r5, c7, c14, 2		@ clean & invalidate by set/way
16662306a36Sopenharmony_ci	subs	r9, r9, #1			@ decrement the index
16762306a36Sopenharmony_ci	bge	loop2
16862306a36Sopenharmony_ci	subs	r4, r4, r6			@ decrement the way
16962306a36Sopenharmony_ci	bcs	loop1
17062306a36Sopenharmony_ciskip:
17162306a36Sopenharmony_ci	add	r10, r10, #2			@ increment cache number
17262306a36Sopenharmony_ci	cmp	r3, r10
17362306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_814220
17462306a36Sopenharmony_ci	dsb
17562306a36Sopenharmony_ci#endif
17662306a36Sopenharmony_ci	bgt	flush_levels
17762306a36Sopenharmony_cifinished:
17862306a36Sopenharmony_ci	mov	r10, #0				@ switch back to cache level 0
17962306a36Sopenharmony_ci	mcr	p15, 2, r10, c0, c0, 0		@ select current cache level in cssr
18062306a36Sopenharmony_ci	dsb	st
18162306a36Sopenharmony_ci	isb
18262306a36Sopenharmony_ci	ret	lr
18362306a36Sopenharmony_ciENDPROC(v7_flush_dcache_all)
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci *	v7_flush_cache_all()
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci *	Flush the entire cache system.
18962306a36Sopenharmony_ci *  The data cache flush is now achieved using atomic clean / invalidates
19062306a36Sopenharmony_ci *  working outwards from L1 cache. This is done using Set/Way based cache
19162306a36Sopenharmony_ci *  maintenance instructions.
19262306a36Sopenharmony_ci *  The instruction cache can still be invalidated back to the point of
19362306a36Sopenharmony_ci *  unification in a single instruction.
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_ciENTRY(v7_flush_kern_cache_all)
19762306a36Sopenharmony_ci	stmfd	sp!, {r4-r6, r9-r10, lr}
19862306a36Sopenharmony_ci	bl	v7_flush_dcache_all
19962306a36Sopenharmony_ci	mov	r0, #0
20062306a36Sopenharmony_ci	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)	@ invalidate I-cache inner shareable
20162306a36Sopenharmony_ci	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)	@ I+BTB cache invalidate
20262306a36Sopenharmony_ci	ldmfd	sp!, {r4-r6, r9-r10, lr}
20362306a36Sopenharmony_ci	ret	lr
20462306a36Sopenharmony_ciENDPROC(v7_flush_kern_cache_all)
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci /*
20762306a36Sopenharmony_ci *     v7_flush_kern_cache_louis(void)
20862306a36Sopenharmony_ci *
20962306a36Sopenharmony_ci *     Flush the data cache up to Level of Unification Inner Shareable.
21062306a36Sopenharmony_ci *     Invalidate the I-cache to the point of unification.
21162306a36Sopenharmony_ci */
21262306a36Sopenharmony_ciENTRY(v7_flush_kern_cache_louis)
21362306a36Sopenharmony_ci	stmfd	sp!, {r4-r6, r9-r10, lr}
21462306a36Sopenharmony_ci	bl	v7_flush_dcache_louis
21562306a36Sopenharmony_ci	mov	r0, #0
21662306a36Sopenharmony_ci	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)	@ invalidate I-cache inner shareable
21762306a36Sopenharmony_ci	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)	@ I+BTB cache invalidate
21862306a36Sopenharmony_ci	ldmfd	sp!, {r4-r6, r9-r10, lr}
21962306a36Sopenharmony_ci	ret	lr
22062306a36Sopenharmony_ciENDPROC(v7_flush_kern_cache_louis)
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/*
22362306a36Sopenharmony_ci *	v7_flush_cache_all()
22462306a36Sopenharmony_ci *
22562306a36Sopenharmony_ci *	Flush all TLB entries in a particular address space
22662306a36Sopenharmony_ci *
22762306a36Sopenharmony_ci *	- mm    - mm_struct describing address space
22862306a36Sopenharmony_ci */
22962306a36Sopenharmony_ciENTRY(v7_flush_user_cache_all)
23062306a36Sopenharmony_ci	/*FALLTHROUGH*/
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/*
23362306a36Sopenharmony_ci *	v7_flush_cache_range(start, end, flags)
23462306a36Sopenharmony_ci *
23562306a36Sopenharmony_ci *	Flush a range of TLB entries in the specified address space.
23662306a36Sopenharmony_ci *
23762306a36Sopenharmony_ci *	- start - start address (may not be aligned)
23862306a36Sopenharmony_ci *	- end   - end address (exclusive, may not be aligned)
23962306a36Sopenharmony_ci *	- flags	- vm_area_struct flags describing address space
24062306a36Sopenharmony_ci *
24162306a36Sopenharmony_ci *	It is assumed that:
24262306a36Sopenharmony_ci *	- we have a VIPT cache.
24362306a36Sopenharmony_ci */
24462306a36Sopenharmony_ciENTRY(v7_flush_user_cache_range)
24562306a36Sopenharmony_ci	ret	lr
24662306a36Sopenharmony_ciENDPROC(v7_flush_user_cache_all)
24762306a36Sopenharmony_ciENDPROC(v7_flush_user_cache_range)
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/*
25062306a36Sopenharmony_ci *	v7_coherent_kern_range(start,end)
25162306a36Sopenharmony_ci *
25262306a36Sopenharmony_ci *	Ensure that the I and D caches are coherent within specified
25362306a36Sopenharmony_ci *	region.  This is typically used when code has been written to
25462306a36Sopenharmony_ci *	a memory region, and will be executed.
25562306a36Sopenharmony_ci *
25662306a36Sopenharmony_ci *	- start   - virtual start address of region
25762306a36Sopenharmony_ci *	- end     - virtual end address of region
25862306a36Sopenharmony_ci *
25962306a36Sopenharmony_ci *	It is assumed that:
26062306a36Sopenharmony_ci *	- the Icache does not read data from the write buffer
26162306a36Sopenharmony_ci */
26262306a36Sopenharmony_ciENTRY(v7_coherent_kern_range)
26362306a36Sopenharmony_ci	/* FALLTHROUGH */
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci/*
26662306a36Sopenharmony_ci *	v7_coherent_user_range(start,end)
26762306a36Sopenharmony_ci *
26862306a36Sopenharmony_ci *	Ensure that the I and D caches are coherent within specified
26962306a36Sopenharmony_ci *	region.  This is typically used when code has been written to
27062306a36Sopenharmony_ci *	a memory region, and will be executed.
27162306a36Sopenharmony_ci *
27262306a36Sopenharmony_ci *	- start   - virtual start address of region
27362306a36Sopenharmony_ci *	- end     - virtual end address of region
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci *	It is assumed that:
27662306a36Sopenharmony_ci *	- the Icache does not read data from the write buffer
27762306a36Sopenharmony_ci */
27862306a36Sopenharmony_ciENTRY(v7_coherent_user_range)
27962306a36Sopenharmony_ci UNWIND(.fnstart		)
28062306a36Sopenharmony_ci	dcache_line_size r2, r3
28162306a36Sopenharmony_ci	sub	r3, r2, #1
28262306a36Sopenharmony_ci	bic	r12, r0, r3
28362306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_764369
28462306a36Sopenharmony_ci	ALT_SMP(W(dsb))
28562306a36Sopenharmony_ci	ALT_UP(W(nop))
28662306a36Sopenharmony_ci#endif
28762306a36Sopenharmony_ci1:
28862306a36Sopenharmony_ci USER(	mcr	p15, 0, r12, c7, c11, 1	)	@ clean D line to the point of unification
28962306a36Sopenharmony_ci	add	r12, r12, r2
29062306a36Sopenharmony_ci	cmp	r12, r1
29162306a36Sopenharmony_ci	blo	1b
29262306a36Sopenharmony_ci	dsb	ishst
29362306a36Sopenharmony_ci#ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND
29462306a36Sopenharmony_ci	ldr	r3, =icache_size
29562306a36Sopenharmony_ci	ldr	r2, [r3, #0]
29662306a36Sopenharmony_ci#else
29762306a36Sopenharmony_ci	icache_line_size r2, r3
29862306a36Sopenharmony_ci#endif
29962306a36Sopenharmony_ci	sub	r3, r2, #1
30062306a36Sopenharmony_ci	bic	r12, r0, r3
30162306a36Sopenharmony_ci2:
30262306a36Sopenharmony_ci USER(	mcr	p15, 0, r12, c7, c5, 1	)	@ invalidate I line
30362306a36Sopenharmony_ci	add	r12, r12, r2
30462306a36Sopenharmony_ci	cmp	r12, r1
30562306a36Sopenharmony_ci	blo	2b
30662306a36Sopenharmony_ci	mov	r0, #0
30762306a36Sopenharmony_ci	ALT_SMP(mcr	p15, 0, r0, c7, c1, 6)	@ invalidate BTB Inner Shareable
30862306a36Sopenharmony_ci	ALT_UP(mcr	p15, 0, r0, c7, c5, 6)	@ invalidate BTB
30962306a36Sopenharmony_ci	dsb	ishst
31062306a36Sopenharmony_ci	isb
31162306a36Sopenharmony_ci	ret	lr
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci/*
31462306a36Sopenharmony_ci * Fault handling for the cache operation above. If the virtual address in r0
31562306a36Sopenharmony_ci * isn't mapped, fail with -EFAULT.
31662306a36Sopenharmony_ci */
31762306a36Sopenharmony_ci9001:
31862306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_775420
31962306a36Sopenharmony_ci	dsb
32062306a36Sopenharmony_ci#endif
32162306a36Sopenharmony_ci	mov	r0, #-EFAULT
32262306a36Sopenharmony_ci	ret	lr
32362306a36Sopenharmony_ci UNWIND(.fnend		)
32462306a36Sopenharmony_ciENDPROC(v7_coherent_kern_range)
32562306a36Sopenharmony_ciENDPROC(v7_coherent_user_range)
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci/*
32862306a36Sopenharmony_ci *	v7_flush_kern_dcache_area(void *addr, size_t size)
32962306a36Sopenharmony_ci *
33062306a36Sopenharmony_ci *	Ensure that the data held in the page kaddr is written back
33162306a36Sopenharmony_ci *	to the page in question.
33262306a36Sopenharmony_ci *
33362306a36Sopenharmony_ci *	- addr	- kernel address
33462306a36Sopenharmony_ci *	- size	- region size
33562306a36Sopenharmony_ci */
33662306a36Sopenharmony_ciENTRY(v7_flush_kern_dcache_area)
33762306a36Sopenharmony_ci	dcache_line_size r2, r3
33862306a36Sopenharmony_ci	add	r1, r0, r1
33962306a36Sopenharmony_ci	sub	r3, r2, #1
34062306a36Sopenharmony_ci	bic	r0, r0, r3
34162306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_764369
34262306a36Sopenharmony_ci	ALT_SMP(W(dsb))
34362306a36Sopenharmony_ci	ALT_UP(W(nop))
34462306a36Sopenharmony_ci#endif
34562306a36Sopenharmony_ci1:
34662306a36Sopenharmony_ci	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D line / unified line
34762306a36Sopenharmony_ci	add	r0, r0, r2
34862306a36Sopenharmony_ci	cmp	r0, r1
34962306a36Sopenharmony_ci	blo	1b
35062306a36Sopenharmony_ci	dsb	st
35162306a36Sopenharmony_ci	ret	lr
35262306a36Sopenharmony_ciENDPROC(v7_flush_kern_dcache_area)
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/*
35562306a36Sopenharmony_ci *	v7_dma_inv_range(start,end)
35662306a36Sopenharmony_ci *
35762306a36Sopenharmony_ci *	Invalidate the data cache within the specified region; we will
35862306a36Sopenharmony_ci *	be performing a DMA operation in this region and we want to
35962306a36Sopenharmony_ci *	purge old data in the cache.
36062306a36Sopenharmony_ci *
36162306a36Sopenharmony_ci *	- start   - virtual start address of region
36262306a36Sopenharmony_ci *	- end     - virtual end address of region
36362306a36Sopenharmony_ci */
36462306a36Sopenharmony_civ7_dma_inv_range:
36562306a36Sopenharmony_ci	dcache_line_size r2, r3
36662306a36Sopenharmony_ci	sub	r3, r2, #1
36762306a36Sopenharmony_ci	tst	r0, r3
36862306a36Sopenharmony_ci	bic	r0, r0, r3
36962306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_764369
37062306a36Sopenharmony_ci	ALT_SMP(W(dsb))
37162306a36Sopenharmony_ci	ALT_UP(W(nop))
37262306a36Sopenharmony_ci#endif
37362306a36Sopenharmony_ci	mcrne	p15, 0, r0, c7, c14, 1		@ clean & invalidate D / U line
37462306a36Sopenharmony_ci	addne	r0, r0, r2
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	tst	r1, r3
37762306a36Sopenharmony_ci	bic	r1, r1, r3
37862306a36Sopenharmony_ci	mcrne	p15, 0, r1, c7, c14, 1		@ clean & invalidate D / U line
37962306a36Sopenharmony_ci	cmp	r0, r1
38062306a36Sopenharmony_ci1:
38162306a36Sopenharmony_ci	mcrlo	p15, 0, r0, c7, c6, 1		@ invalidate D / U line
38262306a36Sopenharmony_ci	addlo	r0, r0, r2
38362306a36Sopenharmony_ci	cmplo	r0, r1
38462306a36Sopenharmony_ci	blo	1b
38562306a36Sopenharmony_ci	dsb	st
38662306a36Sopenharmony_ci	ret	lr
38762306a36Sopenharmony_ciENDPROC(v7_dma_inv_range)
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/*
39062306a36Sopenharmony_ci *	v7_dma_clean_range(start,end)
39162306a36Sopenharmony_ci *	- start   - virtual start address of region
39262306a36Sopenharmony_ci *	- end     - virtual end address of region
39362306a36Sopenharmony_ci */
39462306a36Sopenharmony_civ7_dma_clean_range:
39562306a36Sopenharmony_ci	dcache_line_size r2, r3
39662306a36Sopenharmony_ci	sub	r3, r2, #1
39762306a36Sopenharmony_ci	bic	r0, r0, r3
39862306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_764369
39962306a36Sopenharmony_ci	ALT_SMP(W(dsb))
40062306a36Sopenharmony_ci	ALT_UP(W(nop))
40162306a36Sopenharmony_ci#endif
40262306a36Sopenharmony_ci1:
40362306a36Sopenharmony_ci	mcr	p15, 0, r0, c7, c10, 1		@ clean D / U line
40462306a36Sopenharmony_ci	add	r0, r0, r2
40562306a36Sopenharmony_ci	cmp	r0, r1
40662306a36Sopenharmony_ci	blo	1b
40762306a36Sopenharmony_ci	dsb	st
40862306a36Sopenharmony_ci	ret	lr
40962306a36Sopenharmony_ciENDPROC(v7_dma_clean_range)
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/*
41262306a36Sopenharmony_ci *	v7_dma_flush_range(start,end)
41362306a36Sopenharmony_ci *	- start   - virtual start address of region
41462306a36Sopenharmony_ci *	- end     - virtual end address of region
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_ciENTRY(v7_dma_flush_range)
41762306a36Sopenharmony_ci	dcache_line_size r2, r3
41862306a36Sopenharmony_ci	sub	r3, r2, #1
41962306a36Sopenharmony_ci	bic	r0, r0, r3
42062306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_764369
42162306a36Sopenharmony_ci	ALT_SMP(W(dsb))
42262306a36Sopenharmony_ci	ALT_UP(W(nop))
42362306a36Sopenharmony_ci#endif
42462306a36Sopenharmony_ci1:
42562306a36Sopenharmony_ci	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D / U line
42662306a36Sopenharmony_ci	add	r0, r0, r2
42762306a36Sopenharmony_ci	cmp	r0, r1
42862306a36Sopenharmony_ci	blo	1b
42962306a36Sopenharmony_ci	dsb	st
43062306a36Sopenharmony_ci	ret	lr
43162306a36Sopenharmony_ciENDPROC(v7_dma_flush_range)
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci/*
43462306a36Sopenharmony_ci *	dma_map_area(start, size, dir)
43562306a36Sopenharmony_ci *	- start	- kernel virtual start address
43662306a36Sopenharmony_ci *	- size	- size of region
43762306a36Sopenharmony_ci *	- dir	- DMA direction
43862306a36Sopenharmony_ci */
43962306a36Sopenharmony_ciENTRY(v7_dma_map_area)
44062306a36Sopenharmony_ci	add	r1, r1, r0
44162306a36Sopenharmony_ci	teq	r2, #DMA_FROM_DEVICE
44262306a36Sopenharmony_ci	beq	v7_dma_inv_range
44362306a36Sopenharmony_ci	b	v7_dma_clean_range
44462306a36Sopenharmony_ciENDPROC(v7_dma_map_area)
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/*
44762306a36Sopenharmony_ci *	dma_unmap_area(start, size, dir)
44862306a36Sopenharmony_ci *	- start	- kernel virtual start address
44962306a36Sopenharmony_ci *	- size	- size of region
45062306a36Sopenharmony_ci *	- dir	- DMA direction
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_ciENTRY(v7_dma_unmap_area)
45362306a36Sopenharmony_ci	add	r1, r1, r0
45462306a36Sopenharmony_ci	teq	r2, #DMA_TO_DEVICE
45562306a36Sopenharmony_ci	bne	v7_dma_inv_range
45662306a36Sopenharmony_ci	ret	lr
45762306a36Sopenharmony_ciENDPROC(v7_dma_unmap_area)
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	__INITDATA
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
46262306a36Sopenharmony_ci	define_cache_functions v7
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* The Broadcom Brahma-B15 read-ahead cache requires some modifications
46562306a36Sopenharmony_ci	 * to the v7_cache_fns, we only override the ones we need
46662306a36Sopenharmony_ci	 */
46762306a36Sopenharmony_ci#ifndef CONFIG_CACHE_B15_RAC
46862306a36Sopenharmony_ci	globl_equ	b15_flush_kern_cache_all,	v7_flush_kern_cache_all
46962306a36Sopenharmony_ci#endif
47062306a36Sopenharmony_ci	globl_equ	b15_flush_icache_all,		v7_flush_icache_all
47162306a36Sopenharmony_ci	globl_equ	b15_flush_kern_cache_louis,	v7_flush_kern_cache_louis
47262306a36Sopenharmony_ci	globl_equ	b15_flush_user_cache_all,	v7_flush_user_cache_all
47362306a36Sopenharmony_ci	globl_equ	b15_flush_user_cache_range,	v7_flush_user_cache_range
47462306a36Sopenharmony_ci	globl_equ	b15_coherent_kern_range,	v7_coherent_kern_range
47562306a36Sopenharmony_ci	globl_equ	b15_coherent_user_range,	v7_coherent_user_range
47662306a36Sopenharmony_ci	globl_equ	b15_flush_kern_dcache_area,	v7_flush_kern_dcache_area
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	globl_equ	b15_dma_map_area,		v7_dma_map_area
47962306a36Sopenharmony_ci	globl_equ	b15_dma_unmap_area,		v7_dma_unmap_area
48062306a36Sopenharmony_ci	globl_equ	b15_dma_flush_range,		v7_dma_flush_range
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	define_cache_functions b15
483