162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/arch/arm/mm/cache-v4wt.S
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 1997-2002 Russell king
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  ARMv4 write through cache operations support.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  We assume that the write buffer is not enabled.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <linux/linkage.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <asm/assembler.h>
1462306a36Sopenharmony_ci#include <asm/page.h>
1562306a36Sopenharmony_ci#include "proc-macros.S"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * The size of one data cache line.
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci#define CACHE_DLINESIZE	32
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * The number of data cache segments.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ci#define CACHE_DSEGMENTS	8
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * The number of lines in a cache segment.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci#define CACHE_DENTRIES	64
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * This is the size at which it becomes more efficient to
3462306a36Sopenharmony_ci * clean the whole cache, rather than using the individual
3562306a36Sopenharmony_ci * cache line maintenance instructions.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * *** This needs benchmarking
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci#define CACHE_DLIMIT	16384
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci *	flush_icache_all()
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci *	Unconditionally clean and invalidate the entire icache.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ciENTRY(v4wt_flush_icache_all)
4762306a36Sopenharmony_ci	mov	r0, #0
4862306a36Sopenharmony_ci	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
4962306a36Sopenharmony_ci	ret	lr
5062306a36Sopenharmony_ciENDPROC(v4wt_flush_icache_all)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/*
5362306a36Sopenharmony_ci *	flush_user_cache_all()
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci *	Invalidate all cache entries in a particular address
5662306a36Sopenharmony_ci *	space.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ciENTRY(v4wt_flush_user_cache_all)
5962306a36Sopenharmony_ci	/* FALLTHROUGH */
6062306a36Sopenharmony_ci/*
6162306a36Sopenharmony_ci *	flush_kern_cache_all()
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci *	Clean and invalidate the entire cache.
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ciENTRY(v4wt_flush_kern_cache_all)
6662306a36Sopenharmony_ci	mov	r2, #VM_EXEC
6762306a36Sopenharmony_ci	mov	ip, #0
6862306a36Sopenharmony_ci__flush_whole_cache:
6962306a36Sopenharmony_ci	tst	r2, #VM_EXEC
7062306a36Sopenharmony_ci	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache
7162306a36Sopenharmony_ci	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
7262306a36Sopenharmony_ci	ret	lr
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*
7562306a36Sopenharmony_ci *	flush_user_cache_range(start, end, flags)
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci *	Clean and invalidate a range of cache entries in the specified
7862306a36Sopenharmony_ci *	address space.
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci *	- start - start address (inclusive, page aligned)
8162306a36Sopenharmony_ci *	- end	- end address (exclusive, page aligned)
8262306a36Sopenharmony_ci *	- flags	- vma_area_struct flags describing address space
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_ciENTRY(v4wt_flush_user_cache_range)
8562306a36Sopenharmony_ci	sub	r3, r1, r0			@ calculate total size
8662306a36Sopenharmony_ci	cmp	r3, #CACHE_DLIMIT
8762306a36Sopenharmony_ci	bhs	__flush_whole_cache
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
9062306a36Sopenharmony_ci	tst	r2, #VM_EXEC
9162306a36Sopenharmony_ci	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
9262306a36Sopenharmony_ci	add	r0, r0, #CACHE_DLINESIZE
9362306a36Sopenharmony_ci	cmp	r0, r1
9462306a36Sopenharmony_ci	blo	1b
9562306a36Sopenharmony_ci	ret	lr
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/*
9862306a36Sopenharmony_ci *	coherent_kern_range(start, end)
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci *	Ensure coherency between the Icache and the Dcache in the
10162306a36Sopenharmony_ci *	region described by start.  If you have non-snooping
10262306a36Sopenharmony_ci *	Harvard caches, you need to implement this function.
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci *	- start  - virtual start address
10562306a36Sopenharmony_ci *	- end	 - virtual end address
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_ciENTRY(v4wt_coherent_kern_range)
10862306a36Sopenharmony_ci	/* FALLTRHOUGH */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci *	coherent_user_range(start, end)
11262306a36Sopenharmony_ci *
11362306a36Sopenharmony_ci *	Ensure coherency between the Icache and the Dcache in the
11462306a36Sopenharmony_ci *	region described by start.  If you have non-snooping
11562306a36Sopenharmony_ci *	Harvard caches, you need to implement this function.
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci *	- start  - virtual start address
11862306a36Sopenharmony_ci *	- end	 - virtual end address
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_ciENTRY(v4wt_coherent_user_range)
12162306a36Sopenharmony_ci	bic	r0, r0, #CACHE_DLINESIZE - 1
12262306a36Sopenharmony_ci1:	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
12362306a36Sopenharmony_ci	add	r0, r0, #CACHE_DLINESIZE
12462306a36Sopenharmony_ci	cmp	r0, r1
12562306a36Sopenharmony_ci	blo	1b
12662306a36Sopenharmony_ci	mov	r0, #0
12762306a36Sopenharmony_ci	ret	lr
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/*
13062306a36Sopenharmony_ci *	flush_kern_dcache_area(void *addr, size_t size)
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci *	Ensure no D cache aliasing occurs, either with itself or
13362306a36Sopenharmony_ci *	the I cache
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci *	- addr	- kernel address
13662306a36Sopenharmony_ci *	- size	- region size
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_ciENTRY(v4wt_flush_kern_dcache_area)
13962306a36Sopenharmony_ci	mov	r2, #0
14062306a36Sopenharmony_ci	mcr	p15, 0, r2, c7, c5, 0		@ invalidate I cache
14162306a36Sopenharmony_ci	add	r1, r0, r1
14262306a36Sopenharmony_ci	/* fallthrough */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/*
14562306a36Sopenharmony_ci *	dma_inv_range(start, end)
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci *	Invalidate (discard) the specified virtual address range.
14862306a36Sopenharmony_ci *	May not write back any entries.  If 'start' or 'end'
14962306a36Sopenharmony_ci *	are not cache line aligned, those lines must be written
15062306a36Sopenharmony_ci *	back.
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci *	- start  - virtual start address
15362306a36Sopenharmony_ci *	- end	 - virtual end address
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_civ4wt_dma_inv_range:
15662306a36Sopenharmony_ci	bic	r0, r0, #CACHE_DLINESIZE - 1
15762306a36Sopenharmony_ci1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
15862306a36Sopenharmony_ci	add	r0, r0, #CACHE_DLINESIZE
15962306a36Sopenharmony_ci	cmp	r0, r1
16062306a36Sopenharmony_ci	blo	1b
16162306a36Sopenharmony_ci	ret	lr
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/*
16462306a36Sopenharmony_ci *	dma_flush_range(start, end)
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci *	Clean and invalidate the specified virtual address range.
16762306a36Sopenharmony_ci *
16862306a36Sopenharmony_ci *	- start  - virtual start address
16962306a36Sopenharmony_ci *	- end	 - virtual end address
17062306a36Sopenharmony_ci */
17162306a36Sopenharmony_ci	.globl	v4wt_dma_flush_range
17262306a36Sopenharmony_ci	.equ	v4wt_dma_flush_range, v4wt_dma_inv_range
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci *	dma_unmap_area(start, size, dir)
17662306a36Sopenharmony_ci *	- start	- kernel virtual start address
17762306a36Sopenharmony_ci *	- size	- size of region
17862306a36Sopenharmony_ci *	- dir	- DMA direction
17962306a36Sopenharmony_ci */
18062306a36Sopenharmony_ciENTRY(v4wt_dma_unmap_area)
18162306a36Sopenharmony_ci	add	r1, r1, r0
18262306a36Sopenharmony_ci	teq	r2, #DMA_TO_DEVICE
18362306a36Sopenharmony_ci	bne	v4wt_dma_inv_range
18462306a36Sopenharmony_ci	/* FALLTHROUGH */
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/*
18762306a36Sopenharmony_ci *	dma_map_area(start, size, dir)
18862306a36Sopenharmony_ci *	- start	- kernel virtual start address
18962306a36Sopenharmony_ci *	- size	- size of region
19062306a36Sopenharmony_ci *	- dir	- DMA direction
19162306a36Sopenharmony_ci */
19262306a36Sopenharmony_ciENTRY(v4wt_dma_map_area)
19362306a36Sopenharmony_ci	ret	lr
19462306a36Sopenharmony_ciENDPROC(v4wt_dma_unmap_area)
19562306a36Sopenharmony_ciENDPROC(v4wt_dma_map_area)
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	.globl	v4wt_flush_kern_cache_louis
19862306a36Sopenharmony_ci	.equ	v4wt_flush_kern_cache_louis, v4wt_flush_kern_cache_all
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	__INITDATA
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
20362306a36Sopenharmony_ci	define_cache_functions v4wt
204