]> git.sur5r.net Git - u-boot/blob - arch/mips/lib/cache.c
Merge branch 'master' of git://git.denx.de/u-boot-i2c
[u-boot] / arch / mips / lib / cache.c
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 }