xref: /OK3568_Linux_fs/u-boot/arch/arc/lib/cache.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <config.h>
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <linux/compiler.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/log2.h>
12*4882a593Smuzhiyun #include <asm/arcregs.h>
13*4882a593Smuzhiyun #include <asm/cache.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun /* Bit values in IC_CTRL */
16*4882a593Smuzhiyun #define IC_CTRL_CACHE_DISABLE	(1 << 0)
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /* Bit values in DC_CTRL */
19*4882a593Smuzhiyun #define DC_CTRL_CACHE_DISABLE	(1 << 0)
20*4882a593Smuzhiyun #define DC_CTRL_INV_MODE_FLUSH	(1 << 6)
21*4882a593Smuzhiyun #define DC_CTRL_FLUSH_STATUS	(1 << 8)
22*4882a593Smuzhiyun #define CACHE_VER_NUM_MASK	0xF
23*4882a593Smuzhiyun #define SLC_CTRL_SB		(1 << 2)
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define OP_INV		0x1
26*4882a593Smuzhiyun #define OP_FLUSH	0x2
27*4882a593Smuzhiyun #define OP_INV_IC	0x3
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /*
30*4882a593Smuzhiyun  * By default that variable will fall into .bss section.
31*4882a593Smuzhiyun  * But .bss section is not relocated and so it will be initilized before
32*4882a593Smuzhiyun  * relocation but will be used after being zeroed.
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun int l1_line_sz __section(".data");
35*4882a593Smuzhiyun int dcache_exists __section(".data");
36*4882a593Smuzhiyun int icache_exists __section(".data");
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define CACHE_LINE_MASK		(~(l1_line_sz - 1))
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
41*4882a593Smuzhiyun int slc_line_sz __section(".data");
42*4882a593Smuzhiyun int slc_exists __section(".data");
43*4882a593Smuzhiyun int ioc_exists __section(".data");
44*4882a593Smuzhiyun 
__before_slc_op(const int op)45*4882a593Smuzhiyun static unsigned int __before_slc_op(const int op)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	unsigned int reg = reg;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (op == OP_INV) {
50*4882a593Smuzhiyun 		/*
51*4882a593Smuzhiyun 		 * IM is set by default and implies Flush-n-inv
52*4882a593Smuzhiyun 		 * Clear it here for vanilla inv
53*4882a593Smuzhiyun 		 */
54*4882a593Smuzhiyun 		reg = read_aux_reg(ARC_AUX_SLC_CTRL);
55*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH);
56*4882a593Smuzhiyun 	}
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	return reg;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
__after_slc_op(const int op,unsigned int reg)61*4882a593Smuzhiyun static void __after_slc_op(const int op, unsigned int reg)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	if (op & OP_FLUSH) {	/* flush / flush-n-inv both wait */
64*4882a593Smuzhiyun 		/*
65*4882a593Smuzhiyun 		 * Make sure "busy" bit reports correct status,
66*4882a593Smuzhiyun 		 * see STAR 9001165532
67*4882a593Smuzhiyun 		 */
68*4882a593Smuzhiyun 		read_aux_reg(ARC_AUX_SLC_CTRL);
69*4882a593Smuzhiyun 		while (read_aux_reg(ARC_AUX_SLC_CTRL) &
70*4882a593Smuzhiyun 		       DC_CTRL_FLUSH_STATUS)
71*4882a593Smuzhiyun 			;
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	/* Switch back to default Invalidate mode */
75*4882a593Smuzhiyun 	if (op == OP_INV)
76*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
__slc_line_loop(unsigned long paddr,unsigned long sz,const int op)79*4882a593Smuzhiyun static inline void __slc_line_loop(unsigned long paddr, unsigned long sz,
80*4882a593Smuzhiyun 				   const int op)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	unsigned int aux_cmd;
83*4882a593Smuzhiyun 	int num_lines;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #define SLC_LINE_MASK	(~(slc_line_sz - 1))
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	sz += paddr & ~SLC_LINE_MASK;
90*4882a593Smuzhiyun 	paddr &= SLC_LINE_MASK;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	num_lines = DIV_ROUND_UP(sz, slc_line_sz);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	while (num_lines-- > 0) {
95*4882a593Smuzhiyun 		write_aux_reg(aux_cmd, paddr);
96*4882a593Smuzhiyun 		paddr += slc_line_sz;
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
__slc_entire_op(const int cacheop)100*4882a593Smuzhiyun static inline void __slc_entire_op(const int cacheop)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	int aux;
103*4882a593Smuzhiyun 	unsigned int ctrl_reg = __before_slc_op(cacheop);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (cacheop & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
106*4882a593Smuzhiyun 		aux = ARC_AUX_SLC_INVALIDATE;
107*4882a593Smuzhiyun 	else
108*4882a593Smuzhiyun 		aux = ARC_AUX_SLC_FLUSH;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	write_aux_reg(aux, 0x1);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	__after_slc_op(cacheop, ctrl_reg);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
__slc_line_op(unsigned long paddr,unsigned long sz,const int cacheop)115*4882a593Smuzhiyun static inline void __slc_line_op(unsigned long paddr, unsigned long sz,
116*4882a593Smuzhiyun 				 const int cacheop)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	unsigned int ctrl_reg = __before_slc_op(cacheop);
119*4882a593Smuzhiyun 	__slc_line_loop(paddr, sz, cacheop);
120*4882a593Smuzhiyun 	__after_slc_op(cacheop, ctrl_reg);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun #else
123*4882a593Smuzhiyun #define __slc_entire_op(cacheop)
124*4882a593Smuzhiyun #define __slc_line_op(paddr, sz, cacheop)
125*4882a593Smuzhiyun #endif
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
read_decode_cache_bcr_arcv2(void)128*4882a593Smuzhiyun static void read_decode_cache_bcr_arcv2(void)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	union {
131*4882a593Smuzhiyun 		struct {
132*4882a593Smuzhiyun #ifdef CONFIG_CPU_BIG_ENDIAN
133*4882a593Smuzhiyun 			unsigned int pad:24, way:2, lsz:2, sz:4;
134*4882a593Smuzhiyun #else
135*4882a593Smuzhiyun 			unsigned int sz:4, lsz:2, way:2, pad:24;
136*4882a593Smuzhiyun #endif
137*4882a593Smuzhiyun 		} fields;
138*4882a593Smuzhiyun 		unsigned int word;
139*4882a593Smuzhiyun 	} slc_cfg;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	union {
142*4882a593Smuzhiyun 		struct {
143*4882a593Smuzhiyun #ifdef CONFIG_CPU_BIG_ENDIAN
144*4882a593Smuzhiyun 			unsigned int pad:24, ver:8;
145*4882a593Smuzhiyun #else
146*4882a593Smuzhiyun 			unsigned int ver:8, pad:24;
147*4882a593Smuzhiyun #endif
148*4882a593Smuzhiyun 		} fields;
149*4882a593Smuzhiyun 		unsigned int word;
150*4882a593Smuzhiyun 	} sbcr;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	sbcr.word = read_aux_reg(ARC_BCR_SLC);
153*4882a593Smuzhiyun 	if (sbcr.fields.ver) {
154*4882a593Smuzhiyun 		slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG);
155*4882a593Smuzhiyun 		slc_exists = 1;
156*4882a593Smuzhiyun 		slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	union {
160*4882a593Smuzhiyun 		struct bcr_clust_cfg {
161*4882a593Smuzhiyun #ifdef CONFIG_CPU_BIG_ENDIAN
162*4882a593Smuzhiyun 			unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
163*4882a593Smuzhiyun #else
164*4882a593Smuzhiyun 			unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
165*4882a593Smuzhiyun #endif
166*4882a593Smuzhiyun 		} fields;
167*4882a593Smuzhiyun 		unsigned int word;
168*4882a593Smuzhiyun 	} cbcr;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
171*4882a593Smuzhiyun 	if (cbcr.fields.c)
172*4882a593Smuzhiyun 		ioc_exists = 1;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun #endif
175*4882a593Smuzhiyun 
read_decode_cache_bcr(void)176*4882a593Smuzhiyun void read_decode_cache_bcr(void)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	int dc_line_sz = 0, ic_line_sz = 0;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	union {
181*4882a593Smuzhiyun 		struct {
182*4882a593Smuzhiyun #ifdef CONFIG_CPU_BIG_ENDIAN
183*4882a593Smuzhiyun 			unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
184*4882a593Smuzhiyun #else
185*4882a593Smuzhiyun 			unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
186*4882a593Smuzhiyun #endif
187*4882a593Smuzhiyun 		} fields;
188*4882a593Smuzhiyun 		unsigned int word;
189*4882a593Smuzhiyun 	} ibcr, dbcr;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
192*4882a593Smuzhiyun 	if (ibcr.fields.ver) {
193*4882a593Smuzhiyun 		icache_exists = 1;
194*4882a593Smuzhiyun 		l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len;
195*4882a593Smuzhiyun 		if (!ic_line_sz)
196*4882a593Smuzhiyun 			panic("Instruction exists but line length is 0\n");
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
200*4882a593Smuzhiyun 	if (dbcr.fields.ver){
201*4882a593Smuzhiyun 		dcache_exists = 1;
202*4882a593Smuzhiyun 		l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len;
203*4882a593Smuzhiyun 		if (!dc_line_sz)
204*4882a593Smuzhiyun 			panic("Data cache exists but line length is 0\n");
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz))
208*4882a593Smuzhiyun 		panic("Instruction and data cache line lengths differ\n");
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun 
cache_init(void)211*4882a593Smuzhiyun void cache_init(void)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	read_decode_cache_bcr();
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
216*4882a593Smuzhiyun 	read_decode_cache_bcr_arcv2();
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	if (ioc_exists) {
219*4882a593Smuzhiyun 		/* IOC Aperture start is equal to DDR start */
220*4882a593Smuzhiyun 		unsigned int ap_base = CONFIG_SYS_SDRAM_BASE;
221*4882a593Smuzhiyun 		/* IOC Aperture size is equal to DDR size */
222*4882a593Smuzhiyun 		long ap_size = CONFIG_SYS_SDRAM_SIZE;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 		flush_dcache_all();
225*4882a593Smuzhiyun 		invalidate_dcache_all();
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 		if (!is_power_of_2(ap_size) || ap_size < 4096)
228*4882a593Smuzhiyun 			panic("IOC Aperture size must be power of 2 and bigger 4Kib");
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 		/*
231*4882a593Smuzhiyun 		 * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB,
232*4882a593Smuzhiyun 		 * so setting 0x11 implies 512M, 0x12 implies 1G...
233*4882a593Smuzhiyun 		 */
234*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE,
235*4882a593Smuzhiyun 			      order_base_2(ap_size/1024) - 2);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 		/* IOC Aperture start must be aligned to the size of the aperture */
239*4882a593Smuzhiyun 		if (ap_base % ap_size != 0)
240*4882a593Smuzhiyun 			panic("IOC Aperture start must be aligned to the size of the aperture");
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12);
243*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
244*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun #endif
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
icache_status(void)250*4882a593Smuzhiyun int icache_status(void)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	if (!icache_exists)
253*4882a593Smuzhiyun 		return 0;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE)
256*4882a593Smuzhiyun 		return 0;
257*4882a593Smuzhiyun 	else
258*4882a593Smuzhiyun 		return 1;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
icache_enable(void)261*4882a593Smuzhiyun void icache_enable(void)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	if (icache_exists)
264*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) &
265*4882a593Smuzhiyun 			      ~IC_CTRL_CACHE_DISABLE);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
icache_disable(void)268*4882a593Smuzhiyun void icache_disable(void)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	if (icache_exists)
271*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) |
272*4882a593Smuzhiyun 			      IC_CTRL_CACHE_DISABLE);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun #ifndef CONFIG_SYS_DCACHE_OFF
invalidate_icache_all(void)276*4882a593Smuzhiyun void invalidate_icache_all(void)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	/* Any write to IC_IVIC register triggers invalidation of entire I$ */
279*4882a593Smuzhiyun 	if (icache_status()) {
280*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_IC_IVIC, 1);
281*4882a593Smuzhiyun 		read_aux_reg(ARC_AUX_IC_CTRL);	/* blocks */
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun #else
invalidate_icache_all(void)285*4882a593Smuzhiyun void invalidate_icache_all(void)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun #endif
289*4882a593Smuzhiyun 
dcache_status(void)290*4882a593Smuzhiyun int dcache_status(void)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	if (!dcache_exists)
293*4882a593Smuzhiyun 		return 0;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE)
296*4882a593Smuzhiyun 		return 0;
297*4882a593Smuzhiyun 	else
298*4882a593Smuzhiyun 		return 1;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
dcache_enable(void)301*4882a593Smuzhiyun void dcache_enable(void)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	if (!dcache_exists)
304*4882a593Smuzhiyun 		return;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) &
307*4882a593Smuzhiyun 		      ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE));
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
dcache_disable(void)310*4882a593Smuzhiyun void dcache_disable(void)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun 	if (!dcache_exists)
313*4882a593Smuzhiyun 		return;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) |
316*4882a593Smuzhiyun 		      DC_CTRL_CACHE_DISABLE);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun #ifndef CONFIG_SYS_DCACHE_OFF
320*4882a593Smuzhiyun /*
321*4882a593Smuzhiyun  * Common Helper for Line Operations on {I,D}-Cache
322*4882a593Smuzhiyun  */
__cache_line_loop(unsigned long paddr,unsigned long sz,const int cacheop)323*4882a593Smuzhiyun static inline void __cache_line_loop(unsigned long paddr, unsigned long sz,
324*4882a593Smuzhiyun 				     const int cacheop)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	unsigned int aux_cmd;
327*4882a593Smuzhiyun #if (CONFIG_ARC_MMU_VER == 3)
328*4882a593Smuzhiyun 	unsigned int aux_tag;
329*4882a593Smuzhiyun #endif
330*4882a593Smuzhiyun 	int num_lines;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	if (cacheop == OP_INV_IC) {
333*4882a593Smuzhiyun 		aux_cmd = ARC_AUX_IC_IVIL;
334*4882a593Smuzhiyun #if (CONFIG_ARC_MMU_VER == 3)
335*4882a593Smuzhiyun 		aux_tag = ARC_AUX_IC_PTAG;
336*4882a593Smuzhiyun #endif
337*4882a593Smuzhiyun 	} else {
338*4882a593Smuzhiyun 		/* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
339*4882a593Smuzhiyun 		aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL;
340*4882a593Smuzhiyun #if (CONFIG_ARC_MMU_VER == 3)
341*4882a593Smuzhiyun 		aux_tag = ARC_AUX_DC_PTAG;
342*4882a593Smuzhiyun #endif
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	sz += paddr & ~CACHE_LINE_MASK;
346*4882a593Smuzhiyun 	paddr &= CACHE_LINE_MASK;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	num_lines = DIV_ROUND_UP(sz, l1_line_sz);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	while (num_lines-- > 0) {
351*4882a593Smuzhiyun #if (CONFIG_ARC_MMU_VER == 3)
352*4882a593Smuzhiyun 		write_aux_reg(aux_tag, paddr);
353*4882a593Smuzhiyun #endif
354*4882a593Smuzhiyun 		write_aux_reg(aux_cmd, paddr);
355*4882a593Smuzhiyun 		paddr += l1_line_sz;
356*4882a593Smuzhiyun 	}
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
__before_dc_op(const int op)359*4882a593Smuzhiyun static unsigned int __before_dc_op(const int op)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	unsigned int reg;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (op == OP_INV) {
364*4882a593Smuzhiyun 		/*
365*4882a593Smuzhiyun 		 * IM is set by default and implies Flush-n-inv
366*4882a593Smuzhiyun 		 * Clear it here for vanilla inv
367*4882a593Smuzhiyun 		 */
368*4882a593Smuzhiyun 		reg = read_aux_reg(ARC_AUX_DC_CTRL);
369*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH);
370*4882a593Smuzhiyun 	}
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	return reg;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
__after_dc_op(const int op,unsigned int reg)375*4882a593Smuzhiyun static void __after_dc_op(const int op, unsigned int reg)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	if (op & OP_FLUSH)	/* flush / flush-n-inv both wait */
378*4882a593Smuzhiyun 		while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS)
379*4882a593Smuzhiyun 			;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	/* Switch back to default Invalidate mode */
382*4882a593Smuzhiyun 	if (op == OP_INV)
383*4882a593Smuzhiyun 		write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH);
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun 
__dc_entire_op(const int cacheop)386*4882a593Smuzhiyun static inline void __dc_entire_op(const int cacheop)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun 	int aux;
389*4882a593Smuzhiyun 	unsigned int ctrl_reg = __before_dc_op(cacheop);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	if (cacheop & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
392*4882a593Smuzhiyun 		aux = ARC_AUX_DC_IVDC;
393*4882a593Smuzhiyun 	else
394*4882a593Smuzhiyun 		aux = ARC_AUX_DC_FLSH;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	write_aux_reg(aux, 0x1);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	__after_dc_op(cacheop, ctrl_reg);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun 
__dc_line_op(unsigned long paddr,unsigned long sz,const int cacheop)401*4882a593Smuzhiyun static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
402*4882a593Smuzhiyun 				const int cacheop)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun 	unsigned int ctrl_reg = __before_dc_op(cacheop);
405*4882a593Smuzhiyun 	__cache_line_loop(paddr, sz, cacheop);
406*4882a593Smuzhiyun 	__after_dc_op(cacheop, ctrl_reg);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun #else
409*4882a593Smuzhiyun #define __dc_entire_op(cacheop)
410*4882a593Smuzhiyun #define __dc_line_op(paddr, sz, cacheop)
411*4882a593Smuzhiyun #endif /* !CONFIG_SYS_DCACHE_OFF */
412*4882a593Smuzhiyun 
invalidate_dcache_range(unsigned long start,unsigned long end)413*4882a593Smuzhiyun void invalidate_dcache_range(unsigned long start, unsigned long end)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
416*4882a593Smuzhiyun 	if (!ioc_exists)
417*4882a593Smuzhiyun #endif
418*4882a593Smuzhiyun 		__dc_line_op(start, end - start, OP_INV);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
421*4882a593Smuzhiyun 	if (slc_exists && !ioc_exists)
422*4882a593Smuzhiyun 		__slc_line_op(start, end - start, OP_INV);
423*4882a593Smuzhiyun #endif
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
flush_dcache_range(unsigned long start,unsigned long end)426*4882a593Smuzhiyun void flush_dcache_range(unsigned long start, unsigned long end)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
429*4882a593Smuzhiyun 	if (!ioc_exists)
430*4882a593Smuzhiyun #endif
431*4882a593Smuzhiyun 		__dc_line_op(start, end - start, OP_FLUSH);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
434*4882a593Smuzhiyun 	if (slc_exists && !ioc_exists)
435*4882a593Smuzhiyun 		__slc_line_op(start, end - start, OP_FLUSH);
436*4882a593Smuzhiyun #endif
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun 
flush_cache(unsigned long start,unsigned long size)439*4882a593Smuzhiyun void flush_cache(unsigned long start, unsigned long size)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	flush_dcache_range(start, start + size);
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun 
invalidate_dcache_all(void)444*4882a593Smuzhiyun void invalidate_dcache_all(void)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun 	__dc_entire_op(OP_INV);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
449*4882a593Smuzhiyun 	if (slc_exists)
450*4882a593Smuzhiyun 		__slc_entire_op(OP_INV);
451*4882a593Smuzhiyun #endif
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
flush_dcache_all(void)454*4882a593Smuzhiyun void flush_dcache_all(void)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	__dc_entire_op(OP_FLUSH);
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun #ifdef CONFIG_ISA_ARCV2
459*4882a593Smuzhiyun 	if (slc_exists)
460*4882a593Smuzhiyun 		__slc_entire_op(OP_FLUSH);
461*4882a593Smuzhiyun #endif
462*4882a593Smuzhiyun }
463