100a9730eSGuo Ren // SPDX-License-Identifier: GPL-2.0 200a9730eSGuo Ren // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 300a9730eSGuo Ren 400a9730eSGuo Ren #include <linux/spinlock.h> 500a9730eSGuo Ren #include <asm/cache.h> 600a9730eSGuo Ren #include <abi/reg_ops.h> 700a9730eSGuo Ren 800a9730eSGuo Ren /* for L1-cache */ 900a9730eSGuo Ren #define INS_CACHE (1 << 0) 1000a9730eSGuo Ren #define DATA_CACHE (1 << 1) 1100a9730eSGuo Ren #define CACHE_INV (1 << 4) 1200a9730eSGuo Ren #define CACHE_CLR (1 << 5) 1300a9730eSGuo Ren #define CACHE_OMS (1 << 6) 1400a9730eSGuo Ren #define CACHE_ITS (1 << 7) 1500a9730eSGuo Ren #define CACHE_LICF (1 << 31) 1600a9730eSGuo Ren 1700a9730eSGuo Ren /* for L2-cache */ 1800a9730eSGuo Ren #define CR22_LEVEL_SHIFT (1) 1900a9730eSGuo Ren #define CR22_SET_SHIFT (7) 2000a9730eSGuo Ren #define CR22_WAY_SHIFT (30) 2100a9730eSGuo Ren #define CR22_WAY_SHIFT_L2 (29) 2200a9730eSGuo Ren 2300a9730eSGuo Ren static DEFINE_SPINLOCK(cache_lock); 2400a9730eSGuo Ren 2500a9730eSGuo Ren static inline void cache_op_line(unsigned long i, unsigned int val) 2600a9730eSGuo Ren { 2700a9730eSGuo Ren mtcr("cr22", i); 2800a9730eSGuo Ren mtcr("cr17", val); 2900a9730eSGuo Ren } 3000a9730eSGuo Ren 3100a9730eSGuo Ren #define CCR2_L2E (1 << 3) 3200a9730eSGuo Ren static void cache_op_all(unsigned int value, unsigned int l2) 3300a9730eSGuo Ren { 3400a9730eSGuo Ren mtcr("cr17", value | CACHE_CLR); 3500a9730eSGuo Ren mb(); 3600a9730eSGuo Ren 3700a9730eSGuo Ren if (l2 && (mfcr_ccr2() & CCR2_L2E)) { 3800a9730eSGuo Ren mtcr("cr24", value | CACHE_CLR); 3900a9730eSGuo Ren mb(); 4000a9730eSGuo Ren } 4100a9730eSGuo Ren } 4200a9730eSGuo Ren 4300a9730eSGuo Ren static void cache_op_range( 4400a9730eSGuo Ren unsigned int start, 4500a9730eSGuo Ren unsigned int end, 4600a9730eSGuo Ren unsigned int value, 4700a9730eSGuo Ren unsigned int l2) 4800a9730eSGuo Ren { 4900a9730eSGuo Ren unsigned long i, flags; 5000a9730eSGuo Ren unsigned int val = value | CACHE_CLR | CACHE_OMS; 5100a9730eSGuo Ren bool l2_sync; 5200a9730eSGuo Ren 5300a9730eSGuo Ren if (unlikely((end - start) >= PAGE_SIZE) || 5400a9730eSGuo Ren unlikely(start < PAGE_OFFSET) || 5500a9730eSGuo Ren unlikely(start >= PAGE_OFFSET + LOWMEM_LIMIT)) { 5600a9730eSGuo Ren cache_op_all(value, l2); 5700a9730eSGuo Ren return; 5800a9730eSGuo Ren } 5900a9730eSGuo Ren 6000a9730eSGuo Ren if ((mfcr_ccr2() & CCR2_L2E) && l2) 6100a9730eSGuo Ren l2_sync = 1; 6200a9730eSGuo Ren else 6300a9730eSGuo Ren l2_sync = 0; 6400a9730eSGuo Ren 6500a9730eSGuo Ren spin_lock_irqsave(&cache_lock, flags); 6600a9730eSGuo Ren 6700a9730eSGuo Ren i = start & ~(L1_CACHE_BYTES - 1); 6800a9730eSGuo Ren for (; i < end; i += L1_CACHE_BYTES) { 6900a9730eSGuo Ren cache_op_line(i, val); 7000a9730eSGuo Ren if (l2_sync) { 7100a9730eSGuo Ren mb(); 7200a9730eSGuo Ren mtcr("cr24", val); 7300a9730eSGuo Ren } 7400a9730eSGuo Ren } 7500a9730eSGuo Ren spin_unlock_irqrestore(&cache_lock, flags); 7600a9730eSGuo Ren 7700a9730eSGuo Ren mb(); 7800a9730eSGuo Ren } 7900a9730eSGuo Ren 8000a9730eSGuo Ren void dcache_wb_line(unsigned long start) 8100a9730eSGuo Ren { 8200a9730eSGuo Ren asm volatile("idly4\n":::"memory"); 8300a9730eSGuo Ren cache_op_line(start, DATA_CACHE|CACHE_CLR); 8400a9730eSGuo Ren mb(); 8500a9730eSGuo Ren } 8600a9730eSGuo Ren 8700a9730eSGuo Ren void icache_inv_range(unsigned long start, unsigned long end) 8800a9730eSGuo Ren { 8900a9730eSGuo Ren cache_op_range(start, end, INS_CACHE|CACHE_INV, 0); 9000a9730eSGuo Ren } 9100a9730eSGuo Ren 9200a9730eSGuo Ren void icache_inv_all(void) 9300a9730eSGuo Ren { 9400a9730eSGuo Ren cache_op_all(INS_CACHE|CACHE_INV, 0); 9500a9730eSGuo Ren } 9600a9730eSGuo Ren 97*761b4f69SGuo Ren void local_icache_inv_all(void *priv) 98*761b4f69SGuo Ren { 99*761b4f69SGuo Ren cache_op_all(INS_CACHE|CACHE_INV, 0); 100*761b4f69SGuo Ren } 101*761b4f69SGuo Ren 10200a9730eSGuo Ren void dcache_wb_range(unsigned long start, unsigned long end) 10300a9730eSGuo Ren { 10400a9730eSGuo Ren cache_op_range(start, end, DATA_CACHE|CACHE_CLR, 0); 10500a9730eSGuo Ren } 10600a9730eSGuo Ren 10700a9730eSGuo Ren void dcache_wbinv_all(void) 10800a9730eSGuo Ren { 10900a9730eSGuo Ren cache_op_all(DATA_CACHE|CACHE_CLR|CACHE_INV, 0); 11000a9730eSGuo Ren } 11100a9730eSGuo Ren 11200a9730eSGuo Ren void cache_wbinv_range(unsigned long start, unsigned long end) 11300a9730eSGuo Ren { 11400a9730eSGuo Ren cache_op_range(start, end, INS_CACHE|DATA_CACHE|CACHE_CLR|CACHE_INV, 0); 11500a9730eSGuo Ren } 11600a9730eSGuo Ren EXPORT_SYMBOL(cache_wbinv_range); 11700a9730eSGuo Ren 11800a9730eSGuo Ren void cache_wbinv_all(void) 11900a9730eSGuo Ren { 12000a9730eSGuo Ren cache_op_all(INS_CACHE|DATA_CACHE|CACHE_CLR|CACHE_INV, 0); 12100a9730eSGuo Ren } 12200a9730eSGuo Ren 12300a9730eSGuo Ren void dma_wbinv_range(unsigned long start, unsigned long end) 12400a9730eSGuo Ren { 12500a9730eSGuo Ren cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1); 12600a9730eSGuo Ren } 12700a9730eSGuo Ren 128ae76f635SGuo Ren void dma_inv_range(unsigned long start, unsigned long end) 129ae76f635SGuo Ren { 130ae76f635SGuo Ren cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1); 131ae76f635SGuo Ren } 132ae76f635SGuo Ren 13300a9730eSGuo Ren void dma_wb_range(unsigned long start, unsigned long end) 13400a9730eSGuo Ren { 135ae76f635SGuo Ren cache_op_range(start, end, DATA_CACHE|CACHE_CLR|CACHE_INV, 1); 13600a9730eSGuo Ren } 137