Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / arch / mips / lib / cache.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2003
4  * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
5  */
6
7 #include <common.h>
8 #include <cpu_func.h>
9 #include <asm/cache.h>
10 #include <asm/cacheops.h>
11 #ifdef CONFIG_MIPS_L2_CACHE
12 #include <asm/cm.h>
13 #endif
14 #include <asm/io.h>
15 #include <asm/mipsregs.h>
16 #include <asm/system.h>
17 #include <linux/bug.h>
18
19 DECLARE_GLOBAL_DATA_PTR;
20
21 static void probe_l2(void)
22 {
23 #ifdef CONFIG_MIPS_L2_CACHE
24         unsigned long conf2, sl;
25         bool l2c = false;
26
27         if (!(read_c0_config1() & MIPS_CONF_M))
28                 return;
29
30         conf2 = read_c0_config2();
31
32         if (__mips_isa_rev >= 6) {
33                 l2c = conf2 & MIPS_CONF_M;
34                 if (l2c)
35                         l2c = read_c0_config3() & MIPS_CONF_M;
36                 if (l2c)
37                         l2c = read_c0_config4() & MIPS_CONF_M;
38                 if (l2c)
39                         l2c = read_c0_config5() & MIPS_CONF5_L2C;
40         }
41
42         if (l2c && config_enabled(CONFIG_MIPS_CM)) {
43                 gd->arch.l2_line_size = mips_cm_l2_line_size();
44         } else if (l2c) {
45                 /* We don't know how to retrieve L2 config on this system */
46                 BUG();
47         } else {
48                 sl = (conf2 & MIPS_CONF2_SL) >> MIPS_CONF2_SL_SHF;
49                 gd->arch.l2_line_size = sl ? (2 << sl) : 0;
50         }
51 #endif
52 }
53
54 void mips_cache_probe(void)
55 {
56 #ifdef CONFIG_SYS_CACHE_SIZE_AUTO
57         unsigned long conf1, il, dl;
58
59         conf1 = read_c0_config1();
60
61         il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
62         dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
63
64         gd->arch.l1i_line_size = il ? (2 << il) : 0;
65         gd->arch.l1d_line_size = dl ? (2 << dl) : 0;
66 #endif
67         probe_l2();
68 }
69
70 static inline unsigned long icache_line_size(void)
71 {
72 #ifdef CONFIG_SYS_CACHE_SIZE_AUTO
73         return gd->arch.l1i_line_size;
74 #else
75         return CONFIG_SYS_ICACHE_LINE_SIZE;
76 #endif
77 }
78
79 static inline unsigned long dcache_line_size(void)
80 {
81 #ifdef CONFIG_SYS_CACHE_SIZE_AUTO
82         return gd->arch.l1d_line_size;
83 #else
84         return CONFIG_SYS_DCACHE_LINE_SIZE;
85 #endif
86 }
87
88 static inline unsigned long scache_line_size(void)
89 {
90 #ifdef CONFIG_MIPS_L2_CACHE
91         return gd->arch.l2_line_size;
92 #else
93         return CONFIG_SYS_SCACHE_LINE_SIZE;
94 #endif
95 }
96
97 #define cache_loop(start, end, lsize, ops...) do {                      \
98         const void *addr = (const void *)(start & ~(lsize - 1));        \
99         const void *aend = (const void *)((end - 1) & ~(lsize - 1));    \
100         const unsigned int cache_ops[] = { ops };                       \
101         unsigned int i;                                                 \
102                                                                         \
103         if (!lsize)                                                     \
104                 break;                                                  \
105                                                                         \
106         for (; addr <= aend; addr += lsize) {                           \
107                 for (i = 0; i < ARRAY_SIZE(cache_ops); i++)             \
108                         mips_cache(cache_ops[i], addr);                 \
109         }                                                               \
110 } while (0)
111
112 void flush_cache(ulong start_addr, ulong size)
113 {
114         unsigned long ilsize = icache_line_size();
115         unsigned long dlsize = dcache_line_size();
116         unsigned long slsize = scache_line_size();
117
118         /* aend will be miscalculated when size is zero, so we return here */
119         if (size == 0)
120                 return;
121
122         if ((ilsize == dlsize) && !slsize) {
123                 /* flush I-cache & D-cache simultaneously */
124                 cache_loop(start_addr, start_addr + size, ilsize,
125                            HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I);
126                 goto ops_done;
127         }
128
129         /* flush D-cache */
130         cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D);
131
132         /* flush L2 cache */
133         cache_loop(start_addr, start_addr + size, slsize, HIT_WRITEBACK_INV_SD);
134
135         /* flush I-cache */
136         cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I);
137
138 ops_done:
139         /* ensure cache ops complete before any further memory accesses */
140         sync();
141
142         /* ensure the pipeline doesn't contain now-invalid instructions */
143         instruction_hazard_barrier();
144 }
145
146 void __weak flush_dcache_range(ulong start_addr, ulong stop)
147 {
148         unsigned long lsize = dcache_line_size();
149         unsigned long slsize = scache_line_size();
150
151         /* aend will be miscalculated when size is zero, so we return here */
152         if (start_addr == stop)
153                 return;
154
155         cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D);
156
157         /* flush L2 cache */
158         cache_loop(start_addr, stop, slsize, HIT_WRITEBACK_INV_SD);
159
160         /* ensure cache ops complete before any further memory accesses */
161         sync();
162 }
163
164 void invalidate_dcache_range(ulong start_addr, ulong stop)
165 {
166         unsigned long lsize = dcache_line_size();
167         unsigned long slsize = scache_line_size();
168
169         /* aend will be miscalculated when size is zero, so we return here */
170         if (start_addr == stop)
171                 return;
172
173         /* invalidate L2 cache */
174         cache_loop(start_addr, stop, slsize, HIT_INVALIDATE_SD);
175
176         cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D);
177
178         /* ensure cache ops complete before any further memory accesses */
179         sync();
180 }
181
182 int dcache_status(void)
183 {
184         unsigned int cca = read_c0_config() & CONF_CM_CMASK;
185         return cca != CONF_CM_UNCACHED;
186 }
187
188 void dcache_enable(void)
189 {
190         puts("Not supported!\n");
191 }
192
193 void dcache_disable(void)
194 {
195         /* change CCA to uncached */
196         change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
197
198         /* ensure the pipeline doesn't contain now-invalid instructions */
199         instruction_hazard_barrier();
200 }