xref: /openbmc/u-boot/arch/mips/lib/cache.c (revision 372286217f050bfd57695001d59f618c52822f40)
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 void flush_cache(ulong start_addr, ulong size)
41 {
42 	unsigned long ilsize = icache_line_size();
43 	unsigned long dlsize = dcache_line_size();
44 	const void *addr, *aend;
45 
46 	/* aend will be miscalculated when size is zero, so we return here */
47 	if (size == 0)
48 		return;
49 
50 	addr = (const void *)(start_addr & ~(dlsize - 1));
51 	aend = (const void *)((start_addr + size - 1) & ~(dlsize - 1));
52 
53 	if (ilsize == dlsize) {
54 		/* flush I-cache & D-cache simultaneously */
55 		while (1) {
56 			mips_cache(HIT_WRITEBACK_INV_D, addr);
57 			mips_cache(HIT_INVALIDATE_I, addr);
58 			if (addr == aend)
59 				break;
60 			addr += dlsize;
61 		}
62 		return;
63 	}
64 
65 	/* flush D-cache */
66 	while (1) {
67 		mips_cache(HIT_WRITEBACK_INV_D, addr);
68 		if (addr == aend)
69 			break;
70 		addr += dlsize;
71 	}
72 
73 	/* flush I-cache */
74 	addr = (const void *)(start_addr & ~(ilsize - 1));
75 	aend = (const void *)((start_addr + size - 1) & ~(ilsize - 1));
76 	while (1) {
77 		mips_cache(HIT_INVALIDATE_I, addr);
78 		if (addr == aend)
79 			break;
80 		addr += ilsize;
81 	}
82 }
83 
84 void flush_dcache_range(ulong start_addr, ulong stop)
85 {
86 	unsigned long lsize = dcache_line_size();
87 	const void *addr = (const void *)(start_addr & ~(lsize - 1));
88 	const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
89 
90 	/* aend will be miscalculated when size is zero, so we return here */
91 	if (start_addr == stop)
92 		return;
93 
94 	while (1) {
95 		mips_cache(HIT_WRITEBACK_INV_D, addr);
96 		if (addr == aend)
97 			break;
98 		addr += lsize;
99 	}
100 }
101 
102 void invalidate_dcache_range(ulong start_addr, ulong stop)
103 {
104 	unsigned long lsize = dcache_line_size();
105 	const void *addr = (const void *)(start_addr & ~(lsize - 1));
106 	const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
107 
108 	/* aend will be miscalculated when size is zero, so we return here */
109 	if (start_addr == stop)
110 		return;
111 
112 	while (1) {
113 		mips_cache(HIT_INVALIDATE_D, addr);
114 		if (addr == aend)
115 			break;
116 		addr += lsize;
117 	}
118 }
119