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