1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2003
3*4882a593Smuzhiyun * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <asm/cacheops.h>
10*4882a593Smuzhiyun #ifdef CONFIG_MIPS_L2_CACHE
11*4882a593Smuzhiyun #include <asm/cm.h>
12*4882a593Smuzhiyun #endif
13*4882a593Smuzhiyun #include <asm/mipsregs.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
16*4882a593Smuzhiyun
probe_l2(void)17*4882a593Smuzhiyun static void probe_l2(void)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun #ifdef CONFIG_MIPS_L2_CACHE
20*4882a593Smuzhiyun unsigned long conf2, sl;
21*4882a593Smuzhiyun bool l2c = false;
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun if (!(read_c0_config1() & MIPS_CONF_M))
24*4882a593Smuzhiyun return;
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun conf2 = read_c0_config2();
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun if (__mips_isa_rev >= 6) {
29*4882a593Smuzhiyun l2c = conf2 & MIPS_CONF_M;
30*4882a593Smuzhiyun if (l2c)
31*4882a593Smuzhiyun l2c = read_c0_config3() & MIPS_CONF_M;
32*4882a593Smuzhiyun if (l2c)
33*4882a593Smuzhiyun l2c = read_c0_config4() & MIPS_CONF_M;
34*4882a593Smuzhiyun if (l2c)
35*4882a593Smuzhiyun l2c = read_c0_config5() & MIPS_CONF5_L2C;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun if (l2c && config_enabled(CONFIG_MIPS_CM)) {
39*4882a593Smuzhiyun gd->arch.l2_line_size = mips_cm_l2_line_size();
40*4882a593Smuzhiyun } else if (l2c) {
41*4882a593Smuzhiyun /* We don't know how to retrieve L2 config on this system */
42*4882a593Smuzhiyun BUG();
43*4882a593Smuzhiyun } else {
44*4882a593Smuzhiyun sl = (conf2 & MIPS_CONF2_SL) >> MIPS_CONF2_SL_SHF;
45*4882a593Smuzhiyun gd->arch.l2_line_size = sl ? (2 << sl) : 0;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun #endif
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
mips_cache_probe(void)50*4882a593Smuzhiyun void mips_cache_probe(void)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun #ifdef CONFIG_SYS_CACHE_SIZE_AUTO
53*4882a593Smuzhiyun unsigned long conf1, il, dl;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun conf1 = read_c0_config1();
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
58*4882a593Smuzhiyun dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun gd->arch.l1i_line_size = il ? (2 << il) : 0;
61*4882a593Smuzhiyun gd->arch.l1d_line_size = dl ? (2 << dl) : 0;
62*4882a593Smuzhiyun #endif
63*4882a593Smuzhiyun probe_l2();
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
icache_line_size(void)66*4882a593Smuzhiyun static inline unsigned long icache_line_size(void)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun #ifdef CONFIG_SYS_CACHE_SIZE_AUTO
69*4882a593Smuzhiyun return gd->arch.l1i_line_size;
70*4882a593Smuzhiyun #else
71*4882a593Smuzhiyun return CONFIG_SYS_ICACHE_LINE_SIZE;
72*4882a593Smuzhiyun #endif
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
dcache_line_size(void)75*4882a593Smuzhiyun static inline unsigned long dcache_line_size(void)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun #ifdef CONFIG_SYS_CACHE_SIZE_AUTO
78*4882a593Smuzhiyun return gd->arch.l1d_line_size;
79*4882a593Smuzhiyun #else
80*4882a593Smuzhiyun return CONFIG_SYS_DCACHE_LINE_SIZE;
81*4882a593Smuzhiyun #endif
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
scache_line_size(void)84*4882a593Smuzhiyun static inline unsigned long scache_line_size(void)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun #ifdef CONFIG_MIPS_L2_CACHE
87*4882a593Smuzhiyun return gd->arch.l2_line_size;
88*4882a593Smuzhiyun #else
89*4882a593Smuzhiyun return 0;
90*4882a593Smuzhiyun #endif
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #define cache_loop(start, end, lsize, ops...) do { \
94*4882a593Smuzhiyun const void *addr = (const void *)(start & ~(lsize - 1)); \
95*4882a593Smuzhiyun const void *aend = (const void *)((end - 1) & ~(lsize - 1)); \
96*4882a593Smuzhiyun const unsigned int cache_ops[] = { ops }; \
97*4882a593Smuzhiyun unsigned int i; \
98*4882a593Smuzhiyun \
99*4882a593Smuzhiyun for (; addr <= aend; addr += lsize) { \
100*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(cache_ops); i++) \
101*4882a593Smuzhiyun mips_cache(cache_ops[i], addr); \
102*4882a593Smuzhiyun } \
103*4882a593Smuzhiyun } while (0)
104*4882a593Smuzhiyun
flush_cache(ulong start_addr,ulong size)105*4882a593Smuzhiyun void flush_cache(ulong start_addr, ulong size)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun unsigned long ilsize = icache_line_size();
108*4882a593Smuzhiyun unsigned long dlsize = dcache_line_size();
109*4882a593Smuzhiyun unsigned long slsize = scache_line_size();
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* aend will be miscalculated when size is zero, so we return here */
112*4882a593Smuzhiyun if (size == 0)
113*4882a593Smuzhiyun return;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun if ((ilsize == dlsize) && !slsize) {
116*4882a593Smuzhiyun /* flush I-cache & D-cache simultaneously */
117*4882a593Smuzhiyun cache_loop(start_addr, start_addr + size, ilsize,
118*4882a593Smuzhiyun HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I);
119*4882a593Smuzhiyun return;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* flush D-cache */
123*4882a593Smuzhiyun cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D);
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* flush L2 cache */
126*4882a593Smuzhiyun if (slsize)
127*4882a593Smuzhiyun cache_loop(start_addr, start_addr + size, slsize,
128*4882a593Smuzhiyun HIT_WRITEBACK_INV_SD);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* flush I-cache */
131*4882a593Smuzhiyun cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
flush_dcache_range(ulong start_addr,ulong stop)134*4882a593Smuzhiyun void flush_dcache_range(ulong start_addr, ulong stop)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun unsigned long lsize = dcache_line_size();
137*4882a593Smuzhiyun unsigned long slsize = scache_line_size();
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* aend will be miscalculated when size is zero, so we return here */
140*4882a593Smuzhiyun if (start_addr == stop)
141*4882a593Smuzhiyun return;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun /* flush L2 cache */
146*4882a593Smuzhiyun if (slsize)
147*4882a593Smuzhiyun cache_loop(start_addr, stop, slsize, HIT_WRITEBACK_INV_SD);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
invalidate_dcache_range(ulong start_addr,ulong stop)150*4882a593Smuzhiyun void invalidate_dcache_range(ulong start_addr, ulong stop)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun unsigned long lsize = dcache_line_size();
153*4882a593Smuzhiyun unsigned long slsize = scache_line_size();
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /* aend will be miscalculated when size is zero, so we return here */
156*4882a593Smuzhiyun if (start_addr == stop)
157*4882a593Smuzhiyun return;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun /* invalidate L2 cache */
160*4882a593Smuzhiyun if (slsize)
161*4882a593Smuzhiyun cache_loop(start_addr, stop, slsize, HIT_INVALIDATE_SD);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D);
164*4882a593Smuzhiyun }
165