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