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