18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mm/cache-v6.S 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001 Deep Blue Solutions Ltd. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This is the "shell" of the ARMv6 processor support. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/linkage.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <asm/assembler.h> 128c2ecf20Sopenharmony_ci#include <asm/errno.h> 138c2ecf20Sopenharmony_ci#include <asm/unwind.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "proc-macros.S" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define HARVARD_CACHE 188c2ecf20Sopenharmony_ci#define CACHE_LINE_SIZE 32 198c2ecf20Sopenharmony_ci#define D_CACHE_LINE_SIZE 32 208c2ecf20Sopenharmony_ci#define BTB_FLUSH_SIZE 8 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * v6_flush_icache_all() 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Flush the whole I-cache. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * ARM1136 erratum 411920 - Invalidate Instruction Cache operation can fail. 288c2ecf20Sopenharmony_ci * This erratum is present in 1136, 1156 and 1176. It does not affect the 298c2ecf20Sopenharmony_ci * MPCore. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Registers: 328c2ecf20Sopenharmony_ci * r0 - set to 0 338c2ecf20Sopenharmony_ci * r1 - corrupted 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ciENTRY(v6_flush_icache_all) 368c2ecf20Sopenharmony_ci mov r0, #0 378c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_411920 388c2ecf20Sopenharmony_ci mrs r1, cpsr 398c2ecf20Sopenharmony_ci cpsid ifa @ disable interrupts 408c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache 418c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache 428c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache 438c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c5, 0 @ invalidate entire I-cache 448c2ecf20Sopenharmony_ci msr cpsr_cx, r1 @ restore interrupts 458c2ecf20Sopenharmony_ci .rept 11 @ ARM Ltd recommends at least 468c2ecf20Sopenharmony_ci nop @ 11 NOPs 478c2ecf20Sopenharmony_ci .endr 488c2ecf20Sopenharmony_ci#else 498c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c5, 0 @ invalidate I-cache 508c2ecf20Sopenharmony_ci#endif 518c2ecf20Sopenharmony_ci ret lr 528c2ecf20Sopenharmony_ciENDPROC(v6_flush_icache_all) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * v6_flush_cache_all() 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * Flush the entire cache. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * It is assumed that: 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ciENTRY(v6_flush_kern_cache_all) 628c2ecf20Sopenharmony_ci mov r0, #0 638c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 648c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c14, 0 @ D cache clean+invalidate 658c2ecf20Sopenharmony_ci#ifndef CONFIG_ARM_ERRATA_411920 668c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate 678c2ecf20Sopenharmony_ci#else 688c2ecf20Sopenharmony_ci b v6_flush_icache_all 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_ci#else 718c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c15, 0 @ Cache clean+invalidate 728c2ecf20Sopenharmony_ci#endif 738c2ecf20Sopenharmony_ci ret lr 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * v6_flush_cache_all() 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Flush all TLB entries in a particular address space 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * - mm - mm_struct describing address space 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ciENTRY(v6_flush_user_cache_all) 838c2ecf20Sopenharmony_ci /*FALLTHROUGH*/ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * v6_flush_cache_range(start, end, flags) 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * Flush a range of TLB entries in the specified address space. 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * - start - start address (may not be aligned) 918c2ecf20Sopenharmony_ci * - end - end address (exclusive, may not be aligned) 928c2ecf20Sopenharmony_ci * - flags - vm_area_struct flags describing address space 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * It is assumed that: 958c2ecf20Sopenharmony_ci * - we have a VIPT cache. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ciENTRY(v6_flush_user_cache_range) 988c2ecf20Sopenharmony_ci ret lr 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * v6_coherent_kern_range(start,end) 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Ensure that the I and D caches are coherent within specified 1048c2ecf20Sopenharmony_ci * region. This is typically used when code has been written to 1058c2ecf20Sopenharmony_ci * a memory region, and will be executed. 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * - start - virtual start address of region 1088c2ecf20Sopenharmony_ci * - end - virtual end address of region 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * It is assumed that: 1118c2ecf20Sopenharmony_ci * - the Icache does not read data from the write buffer 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ciENTRY(v6_coherent_kern_range) 1148c2ecf20Sopenharmony_ci /* FALLTHROUGH */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* 1178c2ecf20Sopenharmony_ci * v6_coherent_user_range(start,end) 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Ensure that the I and D caches are coherent within specified 1208c2ecf20Sopenharmony_ci * region. This is typically used when code has been written to 1218c2ecf20Sopenharmony_ci * a memory region, and will be executed. 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * - start - virtual start address of region 1248c2ecf20Sopenharmony_ci * - end - virtual end address of region 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * It is assumed that: 1278c2ecf20Sopenharmony_ci * - the Icache does not read data from the write buffer 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ciENTRY(v6_coherent_user_range) 1308c2ecf20Sopenharmony_ci UNWIND(.fnstart ) 1318c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 1328c2ecf20Sopenharmony_ci bic r0, r0, #CACHE_LINE_SIZE - 1 1338c2ecf20Sopenharmony_ci1: 1348c2ecf20Sopenharmony_ci USER( mcr p15, 0, r0, c7, c10, 1 ) @ clean D line 1358c2ecf20Sopenharmony_ci add r0, r0, #CACHE_LINE_SIZE 1368c2ecf20Sopenharmony_ci cmp r0, r1 1378c2ecf20Sopenharmony_ci blo 1b 1388c2ecf20Sopenharmony_ci#endif 1398c2ecf20Sopenharmony_ci mov r0, #0 1408c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 1418c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c10, 4 @ drain write buffer 1428c2ecf20Sopenharmony_ci#ifndef CONFIG_ARM_ERRATA_411920 1438c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate 1448c2ecf20Sopenharmony_ci#else 1458c2ecf20Sopenharmony_ci b v6_flush_icache_all 1468c2ecf20Sopenharmony_ci#endif 1478c2ecf20Sopenharmony_ci#else 1488c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB 1498c2ecf20Sopenharmony_ci#endif 1508c2ecf20Sopenharmony_ci ret lr 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * Fault handling for the cache operation above. If the virtual address in r0 1548c2ecf20Sopenharmony_ci * isn't mapped, fail with -EFAULT. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci9001: 1578c2ecf20Sopenharmony_ci mov r0, #-EFAULT 1588c2ecf20Sopenharmony_ci ret lr 1598c2ecf20Sopenharmony_ci UNWIND(.fnend ) 1608c2ecf20Sopenharmony_ciENDPROC(v6_coherent_user_range) 1618c2ecf20Sopenharmony_ciENDPROC(v6_coherent_kern_range) 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* 1648c2ecf20Sopenharmony_ci * v6_flush_kern_dcache_area(void *addr, size_t size) 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci * Ensure that the data held in the page kaddr is written back 1678c2ecf20Sopenharmony_ci * to the page in question. 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * - addr - kernel address 1708c2ecf20Sopenharmony_ci * - size - region size 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ciENTRY(v6_flush_kern_dcache_area) 1738c2ecf20Sopenharmony_ci add r1, r0, r1 1748c2ecf20Sopenharmony_ci bic r0, r0, #D_CACHE_LINE_SIZE - 1 1758c2ecf20Sopenharmony_ci1: 1768c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 1778c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line 1788c2ecf20Sopenharmony_ci#else 1798c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c15, 1 @ clean & invalidate unified line 1808c2ecf20Sopenharmony_ci#endif 1818c2ecf20Sopenharmony_ci add r0, r0, #D_CACHE_LINE_SIZE 1828c2ecf20Sopenharmony_ci cmp r0, r1 1838c2ecf20Sopenharmony_ci blo 1b 1848c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 1858c2ecf20Sopenharmony_ci mov r0, #0 1868c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c10, 4 1878c2ecf20Sopenharmony_ci#endif 1888c2ecf20Sopenharmony_ci ret lr 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* 1928c2ecf20Sopenharmony_ci * v6_dma_inv_range(start,end) 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Invalidate the data cache within the specified region; we will 1958c2ecf20Sopenharmony_ci * be performing a DMA operation in this region and we want to 1968c2ecf20Sopenharmony_ci * purge old data in the cache. 1978c2ecf20Sopenharmony_ci * 1988c2ecf20Sopenharmony_ci * - start - virtual start address of region 1998c2ecf20Sopenharmony_ci * - end - virtual end address of region 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_civ6_dma_inv_range: 2028c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_CACHE_RWFO 2038c2ecf20Sopenharmony_ci ldrb r2, [r0] @ read for ownership 2048c2ecf20Sopenharmony_ci strb r2, [r0] @ write for ownership 2058c2ecf20Sopenharmony_ci#endif 2068c2ecf20Sopenharmony_ci tst r0, #D_CACHE_LINE_SIZE - 1 2078c2ecf20Sopenharmony_ci bic r0, r0, #D_CACHE_LINE_SIZE - 1 2088c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 2098c2ecf20Sopenharmony_ci mcrne p15, 0, r0, c7, c10, 1 @ clean D line 2108c2ecf20Sopenharmony_ci#else 2118c2ecf20Sopenharmony_ci mcrne p15, 0, r0, c7, c11, 1 @ clean unified line 2128c2ecf20Sopenharmony_ci#endif 2138c2ecf20Sopenharmony_ci tst r1, #D_CACHE_LINE_SIZE - 1 2148c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_CACHE_RWFO 2158c2ecf20Sopenharmony_ci ldrbne r2, [r1, #-1] @ read for ownership 2168c2ecf20Sopenharmony_ci strbne r2, [r1, #-1] @ write for ownership 2178c2ecf20Sopenharmony_ci#endif 2188c2ecf20Sopenharmony_ci bic r1, r1, #D_CACHE_LINE_SIZE - 1 2198c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 2208c2ecf20Sopenharmony_ci mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D line 2218c2ecf20Sopenharmony_ci#else 2228c2ecf20Sopenharmony_ci mcrne p15, 0, r1, c7, c15, 1 @ clean & invalidate unified line 2238c2ecf20Sopenharmony_ci#endif 2248c2ecf20Sopenharmony_ci1: 2258c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 2268c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c6, 1 @ invalidate D line 2278c2ecf20Sopenharmony_ci#else 2288c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c7, 1 @ invalidate unified line 2298c2ecf20Sopenharmony_ci#endif 2308c2ecf20Sopenharmony_ci add r0, r0, #D_CACHE_LINE_SIZE 2318c2ecf20Sopenharmony_ci cmp r0, r1 2328c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_CACHE_RWFO 2338c2ecf20Sopenharmony_ci ldrlo r2, [r0] @ read for ownership 2348c2ecf20Sopenharmony_ci strlo r2, [r0] @ write for ownership 2358c2ecf20Sopenharmony_ci#endif 2368c2ecf20Sopenharmony_ci blo 1b 2378c2ecf20Sopenharmony_ci mov r0, #0 2388c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c10, 4 @ drain write buffer 2398c2ecf20Sopenharmony_ci ret lr 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* 2428c2ecf20Sopenharmony_ci * v6_dma_clean_range(start,end) 2438c2ecf20Sopenharmony_ci * - start - virtual start address of region 2448c2ecf20Sopenharmony_ci * - end - virtual end address of region 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_civ6_dma_clean_range: 2478c2ecf20Sopenharmony_ci bic r0, r0, #D_CACHE_LINE_SIZE - 1 2488c2ecf20Sopenharmony_ci1: 2498c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_CACHE_RWFO 2508c2ecf20Sopenharmony_ci ldr r2, [r0] @ read for ownership 2518c2ecf20Sopenharmony_ci#endif 2528c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 2538c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c10, 1 @ clean D line 2548c2ecf20Sopenharmony_ci#else 2558c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c11, 1 @ clean unified line 2568c2ecf20Sopenharmony_ci#endif 2578c2ecf20Sopenharmony_ci add r0, r0, #D_CACHE_LINE_SIZE 2588c2ecf20Sopenharmony_ci cmp r0, r1 2598c2ecf20Sopenharmony_ci blo 1b 2608c2ecf20Sopenharmony_ci mov r0, #0 2618c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c10, 4 @ drain write buffer 2628c2ecf20Sopenharmony_ci ret lr 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/* 2658c2ecf20Sopenharmony_ci * v6_dma_flush_range(start,end) 2668c2ecf20Sopenharmony_ci * - start - virtual start address of region 2678c2ecf20Sopenharmony_ci * - end - virtual end address of region 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ciENTRY(v6_dma_flush_range) 2708c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_CACHE_RWFO 2718c2ecf20Sopenharmony_ci ldrb r2, [r0] @ read for ownership 2728c2ecf20Sopenharmony_ci strb r2, [r0] @ write for ownership 2738c2ecf20Sopenharmony_ci#endif 2748c2ecf20Sopenharmony_ci bic r0, r0, #D_CACHE_LINE_SIZE - 1 2758c2ecf20Sopenharmony_ci1: 2768c2ecf20Sopenharmony_ci#ifdef HARVARD_CACHE 2778c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line 2788c2ecf20Sopenharmony_ci#else 2798c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c15, 1 @ clean & invalidate line 2808c2ecf20Sopenharmony_ci#endif 2818c2ecf20Sopenharmony_ci add r0, r0, #D_CACHE_LINE_SIZE 2828c2ecf20Sopenharmony_ci cmp r0, r1 2838c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_CACHE_RWFO 2848c2ecf20Sopenharmony_ci ldrblo r2, [r0] @ read for ownership 2858c2ecf20Sopenharmony_ci strblo r2, [r0] @ write for ownership 2868c2ecf20Sopenharmony_ci#endif 2878c2ecf20Sopenharmony_ci blo 1b 2888c2ecf20Sopenharmony_ci mov r0, #0 2898c2ecf20Sopenharmony_ci mcr p15, 0, r0, c7, c10, 4 @ drain write buffer 2908c2ecf20Sopenharmony_ci ret lr 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/* 2938c2ecf20Sopenharmony_ci * dma_map_area(start, size, dir) 2948c2ecf20Sopenharmony_ci * - start - kernel virtual start address 2958c2ecf20Sopenharmony_ci * - size - size of region 2968c2ecf20Sopenharmony_ci * - dir - DMA direction 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_ciENTRY(v6_dma_map_area) 2998c2ecf20Sopenharmony_ci add r1, r1, r0 3008c2ecf20Sopenharmony_ci teq r2, #DMA_FROM_DEVICE 3018c2ecf20Sopenharmony_ci beq v6_dma_inv_range 3028c2ecf20Sopenharmony_ci#ifndef CONFIG_DMA_CACHE_RWFO 3038c2ecf20Sopenharmony_ci b v6_dma_clean_range 3048c2ecf20Sopenharmony_ci#else 3058c2ecf20Sopenharmony_ci teq r2, #DMA_TO_DEVICE 3068c2ecf20Sopenharmony_ci beq v6_dma_clean_range 3078c2ecf20Sopenharmony_ci b v6_dma_flush_range 3088c2ecf20Sopenharmony_ci#endif 3098c2ecf20Sopenharmony_ciENDPROC(v6_dma_map_area) 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* 3128c2ecf20Sopenharmony_ci * dma_unmap_area(start, size, dir) 3138c2ecf20Sopenharmony_ci * - start - kernel virtual start address 3148c2ecf20Sopenharmony_ci * - size - size of region 3158c2ecf20Sopenharmony_ci * - dir - DMA direction 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ciENTRY(v6_dma_unmap_area) 3188c2ecf20Sopenharmony_ci#ifndef CONFIG_DMA_CACHE_RWFO 3198c2ecf20Sopenharmony_ci add r1, r1, r0 3208c2ecf20Sopenharmony_ci teq r2, #DMA_TO_DEVICE 3218c2ecf20Sopenharmony_ci bne v6_dma_inv_range 3228c2ecf20Sopenharmony_ci#endif 3238c2ecf20Sopenharmony_ci ret lr 3248c2ecf20Sopenharmony_ciENDPROC(v6_dma_unmap_area) 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci .globl v6_flush_kern_cache_louis 3278c2ecf20Sopenharmony_ci .equ v6_flush_kern_cache_louis, v6_flush_kern_cache_all 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci __INITDATA 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) 3328c2ecf20Sopenharmony_ci define_cache_functions v6 333