18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/arch/arm/mm/cache-v4wt.S
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1997-2002 Russell king
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  ARMv4 write through cache operations support.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  We assume that the write buffer is not enabled.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/linkage.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <asm/assembler.h>
148c2ecf20Sopenharmony_ci#include <asm/page.h>
158c2ecf20Sopenharmony_ci#include "proc-macros.S"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * The size of one data cache line.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci#define CACHE_DLINESIZE	32
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * The number of data cache segments.
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci#define CACHE_DSEGMENTS	8
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * The number of lines in a cache segment.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci#define CACHE_DENTRIES	64
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * This is the size at which it becomes more efficient to
348c2ecf20Sopenharmony_ci * clean the whole cache, rather than using the individual
358c2ecf20Sopenharmony_ci * cache line maintenance instructions.
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * *** This needs benchmarking
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci#define CACHE_DLIMIT	16384
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/*
428c2ecf20Sopenharmony_ci *	flush_icache_all()
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci *	Unconditionally clean and invalidate the entire icache.
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_ciENTRY(v4wt_flush_icache_all)
478c2ecf20Sopenharmony_ci	mov	r0, #0
488c2ecf20Sopenharmony_ci	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
498c2ecf20Sopenharmony_ci	ret	lr
508c2ecf20Sopenharmony_ciENDPROC(v4wt_flush_icache_all)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/*
538c2ecf20Sopenharmony_ci *	flush_user_cache_all()
548c2ecf20Sopenharmony_ci *
558c2ecf20Sopenharmony_ci *	Invalidate all cache entries in a particular address
568c2ecf20Sopenharmony_ci *	space.
578c2ecf20Sopenharmony_ci */
588c2ecf20Sopenharmony_ciENTRY(v4wt_flush_user_cache_all)
598c2ecf20Sopenharmony_ci	/* FALLTHROUGH */
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci *	flush_kern_cache_all()
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci *	Clean and invalidate the entire cache.
648c2ecf20Sopenharmony_ci */
658c2ecf20Sopenharmony_ciENTRY(v4wt_flush_kern_cache_all)
668c2ecf20Sopenharmony_ci	mov	r2, #VM_EXEC
678c2ecf20Sopenharmony_ci	mov	ip, #0
688c2ecf20Sopenharmony_ci__flush_whole_cache:
698c2ecf20Sopenharmony_ci	tst	r2, #VM_EXEC
708c2ecf20Sopenharmony_ci	mcrne	p15, 0, ip, c7, c5, 0		@ invalidate I cache
718c2ecf20Sopenharmony_ci	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
728c2ecf20Sopenharmony_ci	ret	lr
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/*
758c2ecf20Sopenharmony_ci *	flush_user_cache_range(start, end, flags)
768c2ecf20Sopenharmony_ci *
778c2ecf20Sopenharmony_ci *	Clean and invalidate a range of cache entries in the specified
788c2ecf20Sopenharmony_ci *	address space.
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci *	- start - start address (inclusive, page aligned)
818c2ecf20Sopenharmony_ci *	- end	- end address (exclusive, page aligned)
828c2ecf20Sopenharmony_ci *	- flags	- vma_area_struct flags describing address space
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_ciENTRY(v4wt_flush_user_cache_range)
858c2ecf20Sopenharmony_ci	sub	r3, r1, r0			@ calculate total size
868c2ecf20Sopenharmony_ci	cmp	r3, #CACHE_DLIMIT
878c2ecf20Sopenharmony_ci	bhs	__flush_whole_cache
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
908c2ecf20Sopenharmony_ci	tst	r2, #VM_EXEC
918c2ecf20Sopenharmony_ci	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
928c2ecf20Sopenharmony_ci	add	r0, r0, #CACHE_DLINESIZE
938c2ecf20Sopenharmony_ci	cmp	r0, r1
948c2ecf20Sopenharmony_ci	blo	1b
958c2ecf20Sopenharmony_ci	ret	lr
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/*
988c2ecf20Sopenharmony_ci *	coherent_kern_range(start, end)
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci *	Ensure coherency between the Icache and the Dcache in the
1018c2ecf20Sopenharmony_ci *	region described by start.  If you have non-snooping
1028c2ecf20Sopenharmony_ci *	Harvard caches, you need to implement this function.
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci *	- start  - virtual start address
1058c2ecf20Sopenharmony_ci *	- end	 - virtual end address
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_ciENTRY(v4wt_coherent_kern_range)
1088c2ecf20Sopenharmony_ci	/* FALLTRHOUGH */
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci/*
1118c2ecf20Sopenharmony_ci *	coherent_user_range(start, end)
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci *	Ensure coherency between the Icache and the Dcache in the
1148c2ecf20Sopenharmony_ci *	region described by start.  If you have non-snooping
1158c2ecf20Sopenharmony_ci *	Harvard caches, you need to implement this function.
1168c2ecf20Sopenharmony_ci *
1178c2ecf20Sopenharmony_ci *	- start  - virtual start address
1188c2ecf20Sopenharmony_ci *	- end	 - virtual end address
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_ciENTRY(v4wt_coherent_user_range)
1218c2ecf20Sopenharmony_ci	bic	r0, r0, #CACHE_DLINESIZE - 1
1228c2ecf20Sopenharmony_ci1:	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
1238c2ecf20Sopenharmony_ci	add	r0, r0, #CACHE_DLINESIZE
1248c2ecf20Sopenharmony_ci	cmp	r0, r1
1258c2ecf20Sopenharmony_ci	blo	1b
1268c2ecf20Sopenharmony_ci	mov	r0, #0
1278c2ecf20Sopenharmony_ci	ret	lr
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/*
1308c2ecf20Sopenharmony_ci *	flush_kern_dcache_area(void *addr, size_t size)
1318c2ecf20Sopenharmony_ci *
1328c2ecf20Sopenharmony_ci *	Ensure no D cache aliasing occurs, either with itself or
1338c2ecf20Sopenharmony_ci *	the I cache
1348c2ecf20Sopenharmony_ci *
1358c2ecf20Sopenharmony_ci *	- addr	- kernel address
1368c2ecf20Sopenharmony_ci *	- size	- region size
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_ciENTRY(v4wt_flush_kern_dcache_area)
1398c2ecf20Sopenharmony_ci	mov	r2, #0
1408c2ecf20Sopenharmony_ci	mcr	p15, 0, r2, c7, c5, 0		@ invalidate I cache
1418c2ecf20Sopenharmony_ci	add	r1, r0, r1
1428c2ecf20Sopenharmony_ci	/* fallthrough */
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/*
1458c2ecf20Sopenharmony_ci *	dma_inv_range(start, end)
1468c2ecf20Sopenharmony_ci *
1478c2ecf20Sopenharmony_ci *	Invalidate (discard) the specified virtual address range.
1488c2ecf20Sopenharmony_ci *	May not write back any entries.  If 'start' or 'end'
1498c2ecf20Sopenharmony_ci *	are not cache line aligned, those lines must be written
1508c2ecf20Sopenharmony_ci *	back.
1518c2ecf20Sopenharmony_ci *
1528c2ecf20Sopenharmony_ci *	- start  - virtual start address
1538c2ecf20Sopenharmony_ci *	- end	 - virtual end address
1548c2ecf20Sopenharmony_ci */
1558c2ecf20Sopenharmony_civ4wt_dma_inv_range:
1568c2ecf20Sopenharmony_ci	bic	r0, r0, #CACHE_DLINESIZE - 1
1578c2ecf20Sopenharmony_ci1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
1588c2ecf20Sopenharmony_ci	add	r0, r0, #CACHE_DLINESIZE
1598c2ecf20Sopenharmony_ci	cmp	r0, r1
1608c2ecf20Sopenharmony_ci	blo	1b
1618c2ecf20Sopenharmony_ci	ret	lr
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci/*
1648c2ecf20Sopenharmony_ci *	dma_flush_range(start, end)
1658c2ecf20Sopenharmony_ci *
1668c2ecf20Sopenharmony_ci *	Clean and invalidate the specified virtual address range.
1678c2ecf20Sopenharmony_ci *
1688c2ecf20Sopenharmony_ci *	- start  - virtual start address
1698c2ecf20Sopenharmony_ci *	- end	 - virtual end address
1708c2ecf20Sopenharmony_ci */
1718c2ecf20Sopenharmony_ci	.globl	v4wt_dma_flush_range
1728c2ecf20Sopenharmony_ci	.equ	v4wt_dma_flush_range, v4wt_dma_inv_range
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/*
1758c2ecf20Sopenharmony_ci *	dma_unmap_area(start, size, dir)
1768c2ecf20Sopenharmony_ci *	- start	- kernel virtual start address
1778c2ecf20Sopenharmony_ci *	- size	- size of region
1788c2ecf20Sopenharmony_ci *	- dir	- DMA direction
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_ciENTRY(v4wt_dma_unmap_area)
1818c2ecf20Sopenharmony_ci	add	r1, r1, r0
1828c2ecf20Sopenharmony_ci	teq	r2, #DMA_TO_DEVICE
1838c2ecf20Sopenharmony_ci	bne	v4wt_dma_inv_range
1848c2ecf20Sopenharmony_ci	/* FALLTHROUGH */
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci/*
1878c2ecf20Sopenharmony_ci *	dma_map_area(start, size, dir)
1888c2ecf20Sopenharmony_ci *	- start	- kernel virtual start address
1898c2ecf20Sopenharmony_ci *	- size	- size of region
1908c2ecf20Sopenharmony_ci *	- dir	- DMA direction
1918c2ecf20Sopenharmony_ci */
1928c2ecf20Sopenharmony_ciENTRY(v4wt_dma_map_area)
1938c2ecf20Sopenharmony_ci	ret	lr
1948c2ecf20Sopenharmony_ciENDPROC(v4wt_dma_unmap_area)
1958c2ecf20Sopenharmony_ciENDPROC(v4wt_dma_map_area)
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	.globl	v4wt_flush_kern_cache_louis
1988c2ecf20Sopenharmony_ci	.equ	v4wt_flush_kern_cache_louis, v4wt_flush_kern_cache_all
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	__INITDATA
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
2038c2ecf20Sopenharmony_ci	define_cache_functions v4wt
204