3 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
5 * SPDX-License-Identifier: GPL-2.0+
9 #include <asm/cacheops.h>
10 #include <asm/mipsregs.h>
12 static inline unsigned long icache_line_size(void)
14 unsigned long conf1, il;
16 if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
17 return CONFIG_SYS_ICACHE_LINE_SIZE;
19 conf1 = read_c0_config1();
20 il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
26 static inline unsigned long dcache_line_size(void)
28 unsigned long conf1, dl;
30 if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
31 return CONFIG_SYS_DCACHE_LINE_SIZE;
33 conf1 = read_c0_config1();
34 dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
40 #define cache_loop(start, end, lsize, ops...) do { \
41 const void *addr = (const void *)(start & ~(lsize - 1)); \
42 const void *aend = (const void *)((end - 1) & ~(lsize - 1)); \
43 const unsigned int cache_ops[] = { ops }; \
46 for (; addr <= aend; addr += lsize) { \
47 for (i = 0; i < ARRAY_SIZE(cache_ops); i++) \
48 mips_cache(cache_ops[i], addr); \
52 void flush_cache(ulong start_addr, ulong size)
54 unsigned long ilsize = icache_line_size();
55 unsigned long dlsize = dcache_line_size();
57 /* aend will be miscalculated when size is zero, so we return here */
61 if (ilsize == dlsize) {
62 /* flush I-cache & D-cache simultaneously */
63 cache_loop(start_addr, start_addr + size, ilsize,
64 HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I);
69 cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D);
72 cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I);
75 void flush_dcache_range(ulong start_addr, ulong stop)
77 unsigned long lsize = dcache_line_size();
79 /* aend will be miscalculated when size is zero, so we return here */
80 if (start_addr == stop)
83 cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D);
86 void invalidate_dcache_range(ulong start_addr, ulong stop)
88 unsigned long lsize = dcache_line_size();
90 /* aend will be miscalculated when size is zero, so we return here */
91 if (start_addr == stop)
94 cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D);