xref: /OK3568_Linux_fs/u-boot/arch/mips/lib/cache.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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