xref: /openbmc/u-boot/arch/arc/lib/cache.c (revision f2a22678)
1660d5f0dSAlexey Brodkin /*
2660d5f0dSAlexey Brodkin  * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
3660d5f0dSAlexey Brodkin  *
4660d5f0dSAlexey Brodkin  * SPDX-License-Identifier:	GPL-2.0+
5660d5f0dSAlexey Brodkin  */
6660d5f0dSAlexey Brodkin 
7660d5f0dSAlexey Brodkin #include <config.h>
8379b3280SAlexey Brodkin #include <common.h>
9ef639e6fSAlexey Brodkin #include <linux/compiler.h>
10ef639e6fSAlexey Brodkin #include <linux/kernel.h>
1197a63144SAlexey Brodkin #include <linux/log2.h>
12660d5f0dSAlexey Brodkin #include <asm/arcregs.h>
13205e7a7bSAlexey Brodkin #include <asm/cache.h>
14660d5f0dSAlexey Brodkin 
15660d5f0dSAlexey Brodkin /* Bit values in IC_CTRL */
16660d5f0dSAlexey Brodkin #define IC_CTRL_CACHE_DISABLE	(1 << 0)
17660d5f0dSAlexey Brodkin 
18660d5f0dSAlexey Brodkin /* Bit values in DC_CTRL */
19660d5f0dSAlexey Brodkin #define DC_CTRL_CACHE_DISABLE	(1 << 0)
20660d5f0dSAlexey Brodkin #define DC_CTRL_INV_MODE_FLUSH	(1 << 6)
21660d5f0dSAlexey Brodkin #define DC_CTRL_FLUSH_STATUS	(1 << 8)
22660d5f0dSAlexey Brodkin #define CACHE_VER_NUM_MASK	0xF
236eb15e50SAlexey Brodkin #define SLC_CTRL_SB		(1 << 2)
24660d5f0dSAlexey Brodkin 
25ef639e6fSAlexey Brodkin #define OP_INV		0x1
26ef639e6fSAlexey Brodkin #define OP_FLUSH	0x2
27ef639e6fSAlexey Brodkin #define OP_INV_IC	0x3
28ef639e6fSAlexey Brodkin 
29ef639e6fSAlexey Brodkin /*
30ef639e6fSAlexey Brodkin  * By default that variable will fall into .bss section.
31ef639e6fSAlexey Brodkin  * But .bss section is not relocated and so it will be initilized before
32ef639e6fSAlexey Brodkin  * relocation but will be used after being zeroed.
33ef639e6fSAlexey Brodkin  */
34379b3280SAlexey Brodkin int l1_line_sz __section(".data");
35379b3280SAlexey Brodkin int dcache_exists __section(".data");
36379b3280SAlexey Brodkin int icache_exists __section(".data");
37379b3280SAlexey Brodkin 
38379b3280SAlexey Brodkin #define CACHE_LINE_MASK		(~(l1_line_sz - 1))
39379b3280SAlexey Brodkin 
40379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
41ef639e6fSAlexey Brodkin int slc_line_sz __section(".data");
42ef639e6fSAlexey Brodkin int slc_exists __section(".data");
43db6ce231SAlexey Brodkin int ioc_exists __section(".data");
44ef639e6fSAlexey Brodkin 
45ef639e6fSAlexey Brodkin static unsigned int __before_slc_op(const int op)
46ef639e6fSAlexey Brodkin {
47ef639e6fSAlexey Brodkin 	unsigned int reg = reg;
48ef639e6fSAlexey Brodkin 
49ef639e6fSAlexey Brodkin 	if (op == OP_INV) {
50ef639e6fSAlexey Brodkin 		/*
51ef639e6fSAlexey Brodkin 		 * IM is set by default and implies Flush-n-inv
52ef639e6fSAlexey Brodkin 		 * Clear it here for vanilla inv
53ef639e6fSAlexey Brodkin 		 */
54ef639e6fSAlexey Brodkin 		reg = read_aux_reg(ARC_AUX_SLC_CTRL);
55ef639e6fSAlexey Brodkin 		write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH);
56ef639e6fSAlexey Brodkin 	}
57ef639e6fSAlexey Brodkin 
58ef639e6fSAlexey Brodkin 	return reg;
59ef639e6fSAlexey Brodkin }
60ef639e6fSAlexey Brodkin 
61ef639e6fSAlexey Brodkin static void __after_slc_op(const int op, unsigned int reg)
62ef639e6fSAlexey Brodkin {
6340a808f1SAlexey Brodkin 	if (op & OP_FLUSH) {	/* flush / flush-n-inv both wait */
6440a808f1SAlexey Brodkin 		/*
6540a808f1SAlexey Brodkin 		 * Make sure "busy" bit reports correct status,
6640a808f1SAlexey Brodkin 		 * see STAR 9001165532
6740a808f1SAlexey Brodkin 		 */
6840a808f1SAlexey Brodkin 		read_aux_reg(ARC_AUX_SLC_CTRL);
69ef639e6fSAlexey Brodkin 		while (read_aux_reg(ARC_AUX_SLC_CTRL) &
70ef639e6fSAlexey Brodkin 		       DC_CTRL_FLUSH_STATUS)
71ef639e6fSAlexey Brodkin 			;
7240a808f1SAlexey Brodkin 	}
73ef639e6fSAlexey Brodkin 
74ef639e6fSAlexey Brodkin 	/* Switch back to default Invalidate mode */
75ef639e6fSAlexey Brodkin 	if (op == OP_INV)
76ef639e6fSAlexey Brodkin 		write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH);
77ef639e6fSAlexey Brodkin }
78ef639e6fSAlexey Brodkin 
79ef639e6fSAlexey Brodkin static inline void __slc_line_loop(unsigned long paddr, unsigned long sz,
80ef639e6fSAlexey Brodkin 				   const int op)
81ef639e6fSAlexey Brodkin {
82ef639e6fSAlexey Brodkin 	unsigned int aux_cmd;
83ef639e6fSAlexey Brodkin 	int num_lines;
84ef639e6fSAlexey Brodkin 
85ef639e6fSAlexey Brodkin #define SLC_LINE_MASK	(~(slc_line_sz - 1))
86ef639e6fSAlexey Brodkin 
87ef639e6fSAlexey Brodkin 	aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL;
88ef639e6fSAlexey Brodkin 
89ef639e6fSAlexey Brodkin 	sz += paddr & ~SLC_LINE_MASK;
90ef639e6fSAlexey Brodkin 	paddr &= SLC_LINE_MASK;
91ef639e6fSAlexey Brodkin 
92ef639e6fSAlexey Brodkin 	num_lines = DIV_ROUND_UP(sz, slc_line_sz);
93ef639e6fSAlexey Brodkin 
94ef639e6fSAlexey Brodkin 	while (num_lines-- > 0) {
95ef639e6fSAlexey Brodkin 		write_aux_reg(aux_cmd, paddr);
96ef639e6fSAlexey Brodkin 		paddr += slc_line_sz;
97ef639e6fSAlexey Brodkin 	}
98ef639e6fSAlexey Brodkin }
99ef639e6fSAlexey Brodkin 
100ef639e6fSAlexey Brodkin static inline void __slc_entire_op(const int cacheop)
101ef639e6fSAlexey Brodkin {
102ef639e6fSAlexey Brodkin 	int aux;
103ef639e6fSAlexey Brodkin 	unsigned int ctrl_reg = __before_slc_op(cacheop);
104ef639e6fSAlexey Brodkin 
105ef639e6fSAlexey Brodkin 	if (cacheop & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
106ef639e6fSAlexey Brodkin 		aux = ARC_AUX_SLC_INVALIDATE;
107ef639e6fSAlexey Brodkin 	else
108ef639e6fSAlexey Brodkin 		aux = ARC_AUX_SLC_FLUSH;
109ef639e6fSAlexey Brodkin 
110ef639e6fSAlexey Brodkin 	write_aux_reg(aux, 0x1);
111ef639e6fSAlexey Brodkin 
112ef639e6fSAlexey Brodkin 	__after_slc_op(cacheop, ctrl_reg);
113ef639e6fSAlexey Brodkin }
114ef639e6fSAlexey Brodkin 
115ef639e6fSAlexey Brodkin static inline void __slc_line_op(unsigned long paddr, unsigned long sz,
116ef639e6fSAlexey Brodkin 				 const int cacheop)
117ef639e6fSAlexey Brodkin {
118ef639e6fSAlexey Brodkin 	unsigned int ctrl_reg = __before_slc_op(cacheop);
119ef639e6fSAlexey Brodkin 	__slc_line_loop(paddr, sz, cacheop);
120ef639e6fSAlexey Brodkin 	__after_slc_op(cacheop, ctrl_reg);
121ef639e6fSAlexey Brodkin }
122ef639e6fSAlexey Brodkin #else
123ef639e6fSAlexey Brodkin #define __slc_entire_op(cacheop)
124ef639e6fSAlexey Brodkin #define __slc_line_op(paddr, sz, cacheop)
125ef639e6fSAlexey Brodkin #endif
126ef639e6fSAlexey Brodkin 
127379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
128379b3280SAlexey Brodkin static void read_decode_cache_bcr_arcv2(void)
129ef639e6fSAlexey Brodkin {
130379b3280SAlexey Brodkin 	union {
131379b3280SAlexey Brodkin 		struct {
132379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
133379b3280SAlexey Brodkin 			unsigned int pad:24, way:2, lsz:2, sz:4;
134379b3280SAlexey Brodkin #else
135379b3280SAlexey Brodkin 			unsigned int sz:4, lsz:2, way:2, pad:24;
136379b3280SAlexey Brodkin #endif
137379b3280SAlexey Brodkin 		} fields;
138379b3280SAlexey Brodkin 		unsigned int word;
139379b3280SAlexey Brodkin 	} slc_cfg;
140379b3280SAlexey Brodkin 
141379b3280SAlexey Brodkin 	union {
142379b3280SAlexey Brodkin 		struct {
143379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
144379b3280SAlexey Brodkin 			unsigned int pad:24, ver:8;
145379b3280SAlexey Brodkin #else
146379b3280SAlexey Brodkin 			unsigned int ver:8, pad:24;
147379b3280SAlexey Brodkin #endif
148379b3280SAlexey Brodkin 		} fields;
149379b3280SAlexey Brodkin 		unsigned int word;
150379b3280SAlexey Brodkin 	} sbcr;
151379b3280SAlexey Brodkin 
152379b3280SAlexey Brodkin 	sbcr.word = read_aux_reg(ARC_BCR_SLC);
153379b3280SAlexey Brodkin 	if (sbcr.fields.ver) {
154379b3280SAlexey Brodkin 		slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG);
155379b3280SAlexey Brodkin 		slc_exists = 1;
156379b3280SAlexey Brodkin 		slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64;
157379b3280SAlexey Brodkin 	}
158db6ce231SAlexey Brodkin 
159db6ce231SAlexey Brodkin 	union {
160db6ce231SAlexey Brodkin 		struct bcr_clust_cfg {
161db6ce231SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
162db6ce231SAlexey Brodkin 			unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
163db6ce231SAlexey Brodkin #else
164db6ce231SAlexey Brodkin 			unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
165db6ce231SAlexey Brodkin #endif
166db6ce231SAlexey Brodkin 		} fields;
167db6ce231SAlexey Brodkin 		unsigned int word;
168db6ce231SAlexey Brodkin 	} cbcr;
169db6ce231SAlexey Brodkin 
170db6ce231SAlexey Brodkin 	cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
171db6ce231SAlexey Brodkin 	if (cbcr.fields.c)
172db6ce231SAlexey Brodkin 		ioc_exists = 1;
173379b3280SAlexey Brodkin }
174379b3280SAlexey Brodkin #endif
175379b3280SAlexey Brodkin 
176379b3280SAlexey Brodkin void read_decode_cache_bcr(void)
177379b3280SAlexey Brodkin {
178379b3280SAlexey Brodkin 	int dc_line_sz = 0, ic_line_sz = 0;
179379b3280SAlexey Brodkin 
180379b3280SAlexey Brodkin 	union {
181379b3280SAlexey Brodkin 		struct {
182379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
183379b3280SAlexey Brodkin 			unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
184379b3280SAlexey Brodkin #else
185379b3280SAlexey Brodkin 			unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
186379b3280SAlexey Brodkin #endif
187379b3280SAlexey Brodkin 		} fields;
188379b3280SAlexey Brodkin 		unsigned int word;
189379b3280SAlexey Brodkin 	} ibcr, dbcr;
190379b3280SAlexey Brodkin 
191379b3280SAlexey Brodkin 	ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
192379b3280SAlexey Brodkin 	if (ibcr.fields.ver) {
193379b3280SAlexey Brodkin 		icache_exists = 1;
194379b3280SAlexey Brodkin 		l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len;
195379b3280SAlexey Brodkin 		if (!ic_line_sz)
196379b3280SAlexey Brodkin 			panic("Instruction exists but line length is 0\n");
197ef639e6fSAlexey Brodkin 	}
198ef639e6fSAlexey Brodkin 
199379b3280SAlexey Brodkin 	dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
200379b3280SAlexey Brodkin 	if (dbcr.fields.ver){
201379b3280SAlexey Brodkin 		dcache_exists = 1;
202379b3280SAlexey Brodkin 		l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len;
203379b3280SAlexey Brodkin 		if (!dc_line_sz)
204379b3280SAlexey Brodkin 			panic("Data cache exists but line length is 0\n");
205379b3280SAlexey Brodkin 	}
206379b3280SAlexey Brodkin 
207379b3280SAlexey Brodkin 	if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz))
208379b3280SAlexey Brodkin 		panic("Instruction and data cache line lengths differ\n");
209ef639e6fSAlexey Brodkin }
210ef639e6fSAlexey Brodkin 
211ef639e6fSAlexey Brodkin void cache_init(void)
212ef639e6fSAlexey Brodkin {
213379b3280SAlexey Brodkin 	read_decode_cache_bcr();
214379b3280SAlexey Brodkin 
215ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
216379b3280SAlexey Brodkin 	read_decode_cache_bcr_arcv2();
217db6ce231SAlexey Brodkin 
218db6ce231SAlexey Brodkin 	if (ioc_exists) {
21997a63144SAlexey Brodkin 		/* IOC Aperture start is equal to DDR start */
22097a63144SAlexey Brodkin 		unsigned int ap_base = CONFIG_SYS_SDRAM_BASE;
22197a63144SAlexey Brodkin 		/* IOC Aperture size is equal to DDR size */
22297a63144SAlexey Brodkin 		long ap_size = CONFIG_SYS_SDRAM_SIZE;
22397a63144SAlexey Brodkin 
224a4a43fcfSAlexey Brodkin 		flush_dcache_all();
225a4a43fcfSAlexey Brodkin 		invalidate_dcache_all();
226a4a43fcfSAlexey Brodkin 
22797a63144SAlexey Brodkin 		if (!is_power_of_2(ap_size) || ap_size < 4096)
22897a63144SAlexey Brodkin 			panic("IOC Aperture size must be power of 2 and bigger 4Kib");
22997a63144SAlexey Brodkin 
23097a63144SAlexey Brodkin 		/*
23197a63144SAlexey Brodkin 		 * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB,
23297a63144SAlexey Brodkin 		 * so setting 0x11 implies 512M, 0x12 implies 1G...
23397a63144SAlexey Brodkin 		 */
23497a63144SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE,
23597a63144SAlexey Brodkin 			      order_base_2(ap_size/1024) - 2);
23697a63144SAlexey Brodkin 
23797a63144SAlexey Brodkin 
23897a63144SAlexey Brodkin 		/* IOC Aperture start must be aligned to the size of the aperture */
23997a63144SAlexey Brodkin 		if (ap_base % ap_size != 0)
24097a63144SAlexey Brodkin 			panic("IOC Aperture start must be aligned to the size of the aperture");
24197a63144SAlexey Brodkin 
24297a63144SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12);
243db6ce231SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
244db6ce231SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
24597a63144SAlexey Brodkin 
246db6ce231SAlexey Brodkin 	}
247ef639e6fSAlexey Brodkin #endif
248ef639e6fSAlexey Brodkin }
249ef639e6fSAlexey Brodkin 
250660d5f0dSAlexey Brodkin int icache_status(void)
251660d5f0dSAlexey Brodkin {
252379b3280SAlexey Brodkin 	if (!icache_exists)
253660d5f0dSAlexey Brodkin 		return 0;
254660d5f0dSAlexey Brodkin 
255ef639e6fSAlexey Brodkin 	if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE)
256ef639e6fSAlexey Brodkin 		return 0;
257ef639e6fSAlexey Brodkin 	else
258ef639e6fSAlexey Brodkin 		return 1;
259660d5f0dSAlexey Brodkin }
260660d5f0dSAlexey Brodkin 
261660d5f0dSAlexey Brodkin void icache_enable(void)
262660d5f0dSAlexey Brodkin {
263379b3280SAlexey Brodkin 	if (icache_exists)
264660d5f0dSAlexey Brodkin 		write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) &
265660d5f0dSAlexey Brodkin 			      ~IC_CTRL_CACHE_DISABLE);
266660d5f0dSAlexey Brodkin }
267660d5f0dSAlexey Brodkin 
268660d5f0dSAlexey Brodkin void icache_disable(void)
269660d5f0dSAlexey Brodkin {
270379b3280SAlexey Brodkin 	if (icache_exists)
271660d5f0dSAlexey Brodkin 		write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) |
272660d5f0dSAlexey Brodkin 			      IC_CTRL_CACHE_DISABLE);
273660d5f0dSAlexey Brodkin }
274660d5f0dSAlexey Brodkin 
275ef639e6fSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF
276660d5f0dSAlexey Brodkin void invalidate_icache_all(void)
277660d5f0dSAlexey Brodkin {
278660d5f0dSAlexey Brodkin 	/* Any write to IC_IVIC register triggers invalidation of entire I$ */
279ef639e6fSAlexey Brodkin 	if (icache_status()) {
280660d5f0dSAlexey Brodkin 		write_aux_reg(ARC_AUX_IC_IVIC, 1);
281*f2a22678SAlexey Brodkin 		/*
282*f2a22678SAlexey Brodkin 		 * As per ARC HS databook (see chapter 5.3.3.2)
283*f2a22678SAlexey Brodkin 		 * it is required to add 3 NOPs after each write to IC_IVIC.
284*f2a22678SAlexey Brodkin 		 */
285*f2a22678SAlexey Brodkin 		__builtin_arc_nop();
286*f2a22678SAlexey Brodkin 		__builtin_arc_nop();
287*f2a22678SAlexey Brodkin 		__builtin_arc_nop();
288ef639e6fSAlexey Brodkin 		read_aux_reg(ARC_AUX_IC_CTRL);	/* blocks */
289660d5f0dSAlexey Brodkin 	}
290ef639e6fSAlexey Brodkin }
291ef639e6fSAlexey Brodkin #else
292ef639e6fSAlexey Brodkin void invalidate_icache_all(void)
293ef639e6fSAlexey Brodkin {
294ef639e6fSAlexey Brodkin }
295ef639e6fSAlexey Brodkin #endif
296660d5f0dSAlexey Brodkin 
297660d5f0dSAlexey Brodkin int dcache_status(void)
298660d5f0dSAlexey Brodkin {
299379b3280SAlexey Brodkin 	if (!dcache_exists)
300660d5f0dSAlexey Brodkin 		return 0;
301660d5f0dSAlexey Brodkin 
302ef639e6fSAlexey Brodkin 	if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE)
303ef639e6fSAlexey Brodkin 		return 0;
304ef639e6fSAlexey Brodkin 	else
305ef639e6fSAlexey Brodkin 		return 1;
306660d5f0dSAlexey Brodkin }
307660d5f0dSAlexey Brodkin 
308660d5f0dSAlexey Brodkin void dcache_enable(void)
309660d5f0dSAlexey Brodkin {
310379b3280SAlexey Brodkin 	if (!dcache_exists)
311660d5f0dSAlexey Brodkin 		return;
312660d5f0dSAlexey Brodkin 
313660d5f0dSAlexey Brodkin 	write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) &
314660d5f0dSAlexey Brodkin 		      ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE));
315660d5f0dSAlexey Brodkin }
316660d5f0dSAlexey Brodkin 
317660d5f0dSAlexey Brodkin void dcache_disable(void)
318660d5f0dSAlexey Brodkin {
319379b3280SAlexey Brodkin 	if (!dcache_exists)
320660d5f0dSAlexey Brodkin 		return;
321660d5f0dSAlexey Brodkin 
322660d5f0dSAlexey Brodkin 	write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) |
323660d5f0dSAlexey Brodkin 		      DC_CTRL_CACHE_DISABLE);
324660d5f0dSAlexey Brodkin }
325660d5f0dSAlexey Brodkin 
326660d5f0dSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF
327660d5f0dSAlexey Brodkin /*
328ef639e6fSAlexey Brodkin  * Common Helper for Line Operations on {I,D}-Cache
329660d5f0dSAlexey Brodkin  */
330ef639e6fSAlexey Brodkin static inline void __cache_line_loop(unsigned long paddr, unsigned long sz,
331ef639e6fSAlexey Brodkin 				     const int cacheop)
332660d5f0dSAlexey Brodkin {
333ef639e6fSAlexey Brodkin 	unsigned int aux_cmd;
334ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
335ef639e6fSAlexey Brodkin 	unsigned int aux_tag;
336ef639e6fSAlexey Brodkin #endif
337ef639e6fSAlexey Brodkin 	int num_lines;
338660d5f0dSAlexey Brodkin 
339ef639e6fSAlexey Brodkin 	if (cacheop == OP_INV_IC) {
340ef639e6fSAlexey Brodkin 		aux_cmd = ARC_AUX_IC_IVIL;
341ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
342ef639e6fSAlexey Brodkin 		aux_tag = ARC_AUX_IC_PTAG;
343ef639e6fSAlexey Brodkin #endif
344ef639e6fSAlexey Brodkin 	} else {
345ef639e6fSAlexey Brodkin 		/* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
346ef639e6fSAlexey Brodkin 		aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL;
347ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
348ef639e6fSAlexey Brodkin 		aux_tag = ARC_AUX_DC_PTAG;
349ef639e6fSAlexey Brodkin #endif
350660d5f0dSAlexey Brodkin 	}
351660d5f0dSAlexey Brodkin 
352ef639e6fSAlexey Brodkin 	sz += paddr & ~CACHE_LINE_MASK;
353ef639e6fSAlexey Brodkin 	paddr &= CACHE_LINE_MASK;
354ef639e6fSAlexey Brodkin 
355379b3280SAlexey Brodkin 	num_lines = DIV_ROUND_UP(sz, l1_line_sz);
356ef639e6fSAlexey Brodkin 
357ef639e6fSAlexey Brodkin 	while (num_lines-- > 0) {
358ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
359ef639e6fSAlexey Brodkin 		write_aux_reg(aux_tag, paddr);
360ef639e6fSAlexey Brodkin #endif
361ef639e6fSAlexey Brodkin 		write_aux_reg(aux_cmd, paddr);
362379b3280SAlexey Brodkin 		paddr += l1_line_sz;
363ef639e6fSAlexey Brodkin 	}
364ef639e6fSAlexey Brodkin }
365ef639e6fSAlexey Brodkin 
366ef639e6fSAlexey Brodkin static unsigned int __before_dc_op(const int op)
367ef639e6fSAlexey Brodkin {
368ef639e6fSAlexey Brodkin 	unsigned int reg;
369ef639e6fSAlexey Brodkin 
370ef639e6fSAlexey Brodkin 	if (op == OP_INV) {
371ef639e6fSAlexey Brodkin 		/*
372ef639e6fSAlexey Brodkin 		 * IM is set by default and implies Flush-n-inv
373ef639e6fSAlexey Brodkin 		 * Clear it here for vanilla inv
374ef639e6fSAlexey Brodkin 		 */
375ef639e6fSAlexey Brodkin 		reg = read_aux_reg(ARC_AUX_DC_CTRL);
376ef639e6fSAlexey Brodkin 		write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH);
377ef639e6fSAlexey Brodkin 	}
378ef639e6fSAlexey Brodkin 
379ef639e6fSAlexey Brodkin 	return reg;
380ef639e6fSAlexey Brodkin }
381ef639e6fSAlexey Brodkin 
382ef639e6fSAlexey Brodkin static void __after_dc_op(const int op, unsigned int reg)
383ef639e6fSAlexey Brodkin {
384ef639e6fSAlexey Brodkin 	if (op & OP_FLUSH)	/* flush / flush-n-inv both wait */
385ef639e6fSAlexey Brodkin 		while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS)
386ef639e6fSAlexey Brodkin 			;
387ef639e6fSAlexey Brodkin 
388ef639e6fSAlexey Brodkin 	/* Switch back to default Invalidate mode */
389ef639e6fSAlexey Brodkin 	if (op == OP_INV)
390ef639e6fSAlexey Brodkin 		write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH);
391ef639e6fSAlexey Brodkin }
392ef639e6fSAlexey Brodkin 
393ef639e6fSAlexey Brodkin static inline void __dc_entire_op(const int cacheop)
394ef639e6fSAlexey Brodkin {
395ef639e6fSAlexey Brodkin 	int aux;
396ef639e6fSAlexey Brodkin 	unsigned int ctrl_reg = __before_dc_op(cacheop);
397ef639e6fSAlexey Brodkin 
398ef639e6fSAlexey Brodkin 	if (cacheop & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
399ef639e6fSAlexey Brodkin 		aux = ARC_AUX_DC_IVDC;
400ef639e6fSAlexey Brodkin 	else
401ef639e6fSAlexey Brodkin 		aux = ARC_AUX_DC_FLSH;
402ef639e6fSAlexey Brodkin 
403ef639e6fSAlexey Brodkin 	write_aux_reg(aux, 0x1);
404ef639e6fSAlexey Brodkin 
405ef639e6fSAlexey Brodkin 	__after_dc_op(cacheop, ctrl_reg);
406ef639e6fSAlexey Brodkin }
407ef639e6fSAlexey Brodkin 
408ef639e6fSAlexey Brodkin static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
409ef639e6fSAlexey Brodkin 				const int cacheop)
410ef639e6fSAlexey Brodkin {
411ef639e6fSAlexey Brodkin 	unsigned int ctrl_reg = __before_dc_op(cacheop);
412ef639e6fSAlexey Brodkin 	__cache_line_loop(paddr, sz, cacheop);
413ef639e6fSAlexey Brodkin 	__after_dc_op(cacheop, ctrl_reg);
414ef639e6fSAlexey Brodkin }
415ef639e6fSAlexey Brodkin #else
416ef639e6fSAlexey Brodkin #define __dc_entire_op(cacheop)
417ef639e6fSAlexey Brodkin #define __dc_line_op(paddr, sz, cacheop)
418ef639e6fSAlexey Brodkin #endif /* !CONFIG_SYS_DCACHE_OFF */
419ef639e6fSAlexey Brodkin 
420660d5f0dSAlexey Brodkin void invalidate_dcache_range(unsigned long start, unsigned long end)
421660d5f0dSAlexey Brodkin {
422ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
423db6ce231SAlexey Brodkin 	if (!ioc_exists)
424db6ce231SAlexey Brodkin #endif
425db6ce231SAlexey Brodkin 		__dc_line_op(start, end - start, OP_INV);
426db6ce231SAlexey Brodkin 
427db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
428db6ce231SAlexey Brodkin 	if (slc_exists && !ioc_exists)
429ef639e6fSAlexey Brodkin 		__slc_line_op(start, end - start, OP_INV);
430660d5f0dSAlexey Brodkin #endif
431660d5f0dSAlexey Brodkin }
432660d5f0dSAlexey Brodkin 
433ef639e6fSAlexey Brodkin void flush_dcache_range(unsigned long start, unsigned long end)
434660d5f0dSAlexey Brodkin {
435ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
436db6ce231SAlexey Brodkin 	if (!ioc_exists)
437db6ce231SAlexey Brodkin #endif
438db6ce231SAlexey Brodkin 		__dc_line_op(start, end - start, OP_FLUSH);
439db6ce231SAlexey Brodkin 
440db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
441db6ce231SAlexey Brodkin 	if (slc_exists && !ioc_exists)
442ef639e6fSAlexey Brodkin 		__slc_line_op(start, end - start, OP_FLUSH);
443ef639e6fSAlexey Brodkin #endif
444660d5f0dSAlexey Brodkin }
445660d5f0dSAlexey Brodkin 
446660d5f0dSAlexey Brodkin void flush_cache(unsigned long start, unsigned long size)
447660d5f0dSAlexey Brodkin {
448660d5f0dSAlexey Brodkin 	flush_dcache_range(start, start + size);
449660d5f0dSAlexey Brodkin }
4506eb15e50SAlexey Brodkin 
451ef639e6fSAlexey Brodkin void invalidate_dcache_all(void)
452ef639e6fSAlexey Brodkin {
453db6ce231SAlexey Brodkin 	__dc_entire_op(OP_INV);
454db6ce231SAlexey Brodkin 
455db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
456bd91508bSAlexey Brodkin 	if (slc_exists)
457ef639e6fSAlexey Brodkin 		__slc_entire_op(OP_INV);
458ef639e6fSAlexey Brodkin #endif
4596eb15e50SAlexey Brodkin }
4606eb15e50SAlexey Brodkin 
461ef639e6fSAlexey Brodkin void flush_dcache_all(void)
4626eb15e50SAlexey Brodkin {
463db6ce231SAlexey Brodkin 	__dc_entire_op(OP_FLUSH);
464db6ce231SAlexey Brodkin 
465db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
4662a8382c6SAlexey Brodkin 	if (slc_exists)
467ef639e6fSAlexey Brodkin 		__slc_entire_op(OP_FLUSH);
468ef639e6fSAlexey Brodkin #endif
4696eb15e50SAlexey Brodkin }
470