1 /* 2 * (C) Copyright 2003 3 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <asm/cacheops.h> 10 #ifdef CONFIG_MIPS_L2_CACHE 11 #include <asm/cm.h> 12 #endif 13 #include <asm/mipsregs.h> 14 15 DECLARE_GLOBAL_DATA_PTR; 16 17 static void probe_l2(void) 18 { 19 #ifdef CONFIG_MIPS_L2_CACHE 20 unsigned long conf2, sl; 21 bool l2c = false; 22 23 if (!(read_c0_config1() & MIPS_CONF_M)) 24 return; 25 26 conf2 = read_c0_config2(); 27 28 if (__mips_isa_rev >= 6) { 29 l2c = conf2 & MIPS_CONF_M; 30 if (l2c) 31 l2c = read_c0_config3() & MIPS_CONF_M; 32 if (l2c) 33 l2c = read_c0_config4() & MIPS_CONF_M; 34 if (l2c) 35 l2c = read_c0_config5() & MIPS_CONF5_L2C; 36 } 37 38 if (l2c && config_enabled(CONFIG_MIPS_CM)) { 39 gd->arch.l2_line_size = mips_cm_l2_line_size(); 40 } else if (l2c) { 41 /* We don't know how to retrieve L2 config on this system */ 42 BUG(); 43 } else { 44 sl = (conf2 & MIPS_CONF2_SL) >> MIPS_CONF2_SL_SHF; 45 gd->arch.l2_line_size = sl ? (2 << sl) : 0; 46 } 47 #endif 48 } 49 50 void mips_cache_probe(void) 51 { 52 #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 53 unsigned long conf1, il, dl; 54 55 conf1 = read_c0_config1(); 56 57 il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF; 58 dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF; 59 60 gd->arch.l1i_line_size = il ? (2 << il) : 0; 61 gd->arch.l1d_line_size = dl ? (2 << dl) : 0; 62 #endif 63 probe_l2(); 64 } 65 66 static inline unsigned long icache_line_size(void) 67 { 68 #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 69 return gd->arch.l1i_line_size; 70 #else 71 return CONFIG_SYS_ICACHE_LINE_SIZE; 72 #endif 73 } 74 75 static inline unsigned long dcache_line_size(void) 76 { 77 #ifdef CONFIG_SYS_CACHE_SIZE_AUTO 78 return gd->arch.l1d_line_size; 79 #else 80 return CONFIG_SYS_DCACHE_LINE_SIZE; 81 #endif 82 } 83 84 static inline unsigned long scache_line_size(void) 85 { 86 #ifdef CONFIG_MIPS_L2_CACHE 87 return gd->arch.l2_line_size; 88 #else 89 return 0; 90 #endif 91 } 92 93 #define cache_loop(start, end, lsize, ops...) do { \ 94 const void *addr = (const void *)(start & ~(lsize - 1)); \ 95 const void *aend = (const void *)((end - 1) & ~(lsize - 1)); \ 96 const unsigned int cache_ops[] = { ops }; \ 97 unsigned int i; \ 98 \ 99 for (; addr <= aend; addr += lsize) { \ 100 for (i = 0; i < ARRAY_SIZE(cache_ops); i++) \ 101 mips_cache(cache_ops[i], addr); \ 102 } \ 103 } while (0) 104 105 void flush_cache(ulong start_addr, ulong size) 106 { 107 unsigned long ilsize = icache_line_size(); 108 unsigned long dlsize = dcache_line_size(); 109 unsigned long slsize = scache_line_size(); 110 111 /* aend will be miscalculated when size is zero, so we return here */ 112 if (size == 0) 113 return; 114 115 if ((ilsize == dlsize) && !slsize) { 116 /* flush I-cache & D-cache simultaneously */ 117 cache_loop(start_addr, start_addr + size, ilsize, 118 HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I); 119 return; 120 } 121 122 /* flush D-cache */ 123 cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D); 124 125 /* flush L2 cache */ 126 if (slsize) 127 cache_loop(start_addr, start_addr + size, slsize, 128 HIT_WRITEBACK_INV_SD); 129 130 /* flush I-cache */ 131 cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I); 132 } 133 134 void flush_dcache_range(ulong start_addr, ulong stop) 135 { 136 unsigned long lsize = dcache_line_size(); 137 unsigned long slsize = scache_line_size(); 138 139 /* aend will be miscalculated when size is zero, so we return here */ 140 if (start_addr == stop) 141 return; 142 143 cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D); 144 145 /* flush L2 cache */ 146 if (slsize) 147 cache_loop(start_addr, stop, slsize, HIT_WRITEBACK_INV_SD); 148 } 149 150 void invalidate_dcache_range(ulong start_addr, ulong stop) 151 { 152 unsigned long lsize = dcache_line_size(); 153 unsigned long slsize = scache_line_size(); 154 155 /* aend will be miscalculated when size is zero, so we return here */ 156 if (start_addr == stop) 157 return; 158 159 /* invalidate L2 cache */ 160 if (slsize) 161 cache_loop(start_addr, stop, slsize, HIT_INVALIDATE_SD); 162 163 cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D); 164 } 165