xref: /openbmc/u-boot/arch/mips/lib/cache.c (revision e04f9d0c)
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/mipsregs.h>
11 
12 static inline unsigned long icache_line_size(void)
13 {
14 	unsigned long conf1, il;
15 
16 	if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
17 		return CONFIG_SYS_ICACHE_LINE_SIZE;
18 
19 	conf1 = read_c0_config1();
20 	il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
21 	if (!il)
22 		return 0;
23 	return 2 << il;
24 }
25 
26 static inline unsigned long dcache_line_size(void)
27 {
28 	unsigned long conf1, dl;
29 
30 	if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
31 		return CONFIG_SYS_DCACHE_LINE_SIZE;
32 
33 	conf1 = read_c0_config1();
34 	dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
35 	if (!dl)
36 		return 0;
37 	return 2 << dl;
38 }
39 
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 };			\
44 	unsigned int i;							\
45 									\
46 	for (; addr <= aend; addr += lsize) {				\
47 		for (i = 0; i < ARRAY_SIZE(cache_ops); i++)		\
48 			mips_cache(cache_ops[i], addr);			\
49 	}								\
50 } while (0)
51 
52 void flush_cache(ulong start_addr, ulong size)
53 {
54 	unsigned long ilsize = icache_line_size();
55 	unsigned long dlsize = dcache_line_size();
56 
57 	/* aend will be miscalculated when size is zero, so we return here */
58 	if (size == 0)
59 		return;
60 
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);
65 		return;
66 	}
67 
68 	/* flush D-cache */
69 	cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D);
70 
71 	/* flush I-cache */
72 	cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I);
73 }
74 
75 void flush_dcache_range(ulong start_addr, ulong stop)
76 {
77 	unsigned long lsize = dcache_line_size();
78 
79 	/* aend will be miscalculated when size is zero, so we return here */
80 	if (start_addr == stop)
81 		return;
82 
83 	cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D);
84 }
85 
86 void invalidate_dcache_range(ulong start_addr, ulong stop)
87 {
88 	unsigned long lsize = dcache_line_size();
89 
90 	/* aend will be miscalculated when size is zero, so we return here */
91 	if (start_addr == stop)
92 		return;
93 
94 	cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_I);
95 }
96