xref: /openbmc/u-boot/arch/arc/lib/cache.c (revision db6ce231)
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>
11660d5f0dSAlexey Brodkin #include <asm/arcregs.h>
12205e7a7bSAlexey Brodkin #include <asm/cache.h>
13660d5f0dSAlexey Brodkin 
14660d5f0dSAlexey Brodkin /* Bit values in IC_CTRL */
15660d5f0dSAlexey Brodkin #define IC_CTRL_CACHE_DISABLE	(1 << 0)
16660d5f0dSAlexey Brodkin 
17660d5f0dSAlexey Brodkin /* Bit values in DC_CTRL */
18660d5f0dSAlexey Brodkin #define DC_CTRL_CACHE_DISABLE	(1 << 0)
19660d5f0dSAlexey Brodkin #define DC_CTRL_INV_MODE_FLUSH	(1 << 6)
20660d5f0dSAlexey Brodkin #define DC_CTRL_FLUSH_STATUS	(1 << 8)
21660d5f0dSAlexey Brodkin #define CACHE_VER_NUM_MASK	0xF
226eb15e50SAlexey Brodkin #define SLC_CTRL_SB		(1 << 2)
23660d5f0dSAlexey Brodkin 
24ef639e6fSAlexey Brodkin #define OP_INV		0x1
25ef639e6fSAlexey Brodkin #define OP_FLUSH	0x2
26ef639e6fSAlexey Brodkin #define OP_INV_IC	0x3
27ef639e6fSAlexey Brodkin 
28ef639e6fSAlexey Brodkin /*
29ef639e6fSAlexey Brodkin  * By default that variable will fall into .bss section.
30ef639e6fSAlexey Brodkin  * But .bss section is not relocated and so it will be initilized before
31ef639e6fSAlexey Brodkin  * relocation but will be used after being zeroed.
32ef639e6fSAlexey Brodkin  */
33379b3280SAlexey Brodkin int l1_line_sz __section(".data");
34379b3280SAlexey Brodkin int dcache_exists __section(".data");
35379b3280SAlexey Brodkin int icache_exists __section(".data");
36379b3280SAlexey Brodkin 
37379b3280SAlexey Brodkin #define CACHE_LINE_MASK		(~(l1_line_sz - 1))
38379b3280SAlexey Brodkin 
39379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
40ef639e6fSAlexey Brodkin int slc_line_sz __section(".data");
41ef639e6fSAlexey Brodkin int slc_exists __section(".data");
42*db6ce231SAlexey Brodkin int ioc_exists __section(".data");
43ef639e6fSAlexey Brodkin 
44ef639e6fSAlexey Brodkin static unsigned int __before_slc_op(const int op)
45ef639e6fSAlexey Brodkin {
46ef639e6fSAlexey Brodkin 	unsigned int reg = reg;
47ef639e6fSAlexey Brodkin 
48ef639e6fSAlexey Brodkin 	if (op == OP_INV) {
49ef639e6fSAlexey Brodkin 		/*
50ef639e6fSAlexey Brodkin 		 * IM is set by default and implies Flush-n-inv
51ef639e6fSAlexey Brodkin 		 * Clear it here for vanilla inv
52ef639e6fSAlexey Brodkin 		 */
53ef639e6fSAlexey Brodkin 		reg = read_aux_reg(ARC_AUX_SLC_CTRL);
54ef639e6fSAlexey Brodkin 		write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH);
55ef639e6fSAlexey Brodkin 	}
56ef639e6fSAlexey Brodkin 
57ef639e6fSAlexey Brodkin 	return reg;
58ef639e6fSAlexey Brodkin }
59ef639e6fSAlexey Brodkin 
60ef639e6fSAlexey Brodkin static void __after_slc_op(const int op, unsigned int reg)
61ef639e6fSAlexey Brodkin {
62ef639e6fSAlexey Brodkin 	if (op & OP_FLUSH)	/* flush / flush-n-inv both wait */
63ef639e6fSAlexey Brodkin 		while (read_aux_reg(ARC_AUX_SLC_CTRL) &
64ef639e6fSAlexey Brodkin 		       DC_CTRL_FLUSH_STATUS)
65ef639e6fSAlexey Brodkin 			;
66ef639e6fSAlexey Brodkin 
67ef639e6fSAlexey Brodkin 	/* Switch back to default Invalidate mode */
68ef639e6fSAlexey Brodkin 	if (op == OP_INV)
69ef639e6fSAlexey Brodkin 		write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH);
70ef639e6fSAlexey Brodkin }
71ef639e6fSAlexey Brodkin 
72ef639e6fSAlexey Brodkin static inline void __slc_line_loop(unsigned long paddr, unsigned long sz,
73ef639e6fSAlexey Brodkin 				   const int op)
74ef639e6fSAlexey Brodkin {
75ef639e6fSAlexey Brodkin 	unsigned int aux_cmd;
76ef639e6fSAlexey Brodkin 	int num_lines;
77ef639e6fSAlexey Brodkin 
78ef639e6fSAlexey Brodkin #define SLC_LINE_MASK	(~(slc_line_sz - 1))
79ef639e6fSAlexey Brodkin 
80ef639e6fSAlexey Brodkin 	aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL;
81ef639e6fSAlexey Brodkin 
82ef639e6fSAlexey Brodkin 	sz += paddr & ~SLC_LINE_MASK;
83ef639e6fSAlexey Brodkin 	paddr &= SLC_LINE_MASK;
84ef639e6fSAlexey Brodkin 
85ef639e6fSAlexey Brodkin 	num_lines = DIV_ROUND_UP(sz, slc_line_sz);
86ef639e6fSAlexey Brodkin 
87ef639e6fSAlexey Brodkin 	while (num_lines-- > 0) {
88ef639e6fSAlexey Brodkin 		write_aux_reg(aux_cmd, paddr);
89ef639e6fSAlexey Brodkin 		paddr += slc_line_sz;
90ef639e6fSAlexey Brodkin 	}
91ef639e6fSAlexey Brodkin }
92ef639e6fSAlexey Brodkin 
93ef639e6fSAlexey Brodkin static inline void __slc_entire_op(const int cacheop)
94ef639e6fSAlexey Brodkin {
95ef639e6fSAlexey Brodkin 	int aux;
96ef639e6fSAlexey Brodkin 	unsigned int ctrl_reg = __before_slc_op(cacheop);
97ef639e6fSAlexey Brodkin 
98ef639e6fSAlexey Brodkin 	if (cacheop & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
99ef639e6fSAlexey Brodkin 		aux = ARC_AUX_SLC_INVALIDATE;
100ef639e6fSAlexey Brodkin 	else
101ef639e6fSAlexey Brodkin 		aux = ARC_AUX_SLC_FLUSH;
102ef639e6fSAlexey Brodkin 
103ef639e6fSAlexey Brodkin 	write_aux_reg(aux, 0x1);
104ef639e6fSAlexey Brodkin 
105ef639e6fSAlexey Brodkin 	__after_slc_op(cacheop, ctrl_reg);
106ef639e6fSAlexey Brodkin }
107ef639e6fSAlexey Brodkin 
108ef639e6fSAlexey Brodkin static inline void __slc_line_op(unsigned long paddr, unsigned long sz,
109ef639e6fSAlexey Brodkin 				 const int cacheop)
110ef639e6fSAlexey Brodkin {
111ef639e6fSAlexey Brodkin 	unsigned int ctrl_reg = __before_slc_op(cacheop);
112ef639e6fSAlexey Brodkin 	__slc_line_loop(paddr, sz, cacheop);
113ef639e6fSAlexey Brodkin 	__after_slc_op(cacheop, ctrl_reg);
114ef639e6fSAlexey Brodkin }
115ef639e6fSAlexey Brodkin #else
116ef639e6fSAlexey Brodkin #define __slc_entire_op(cacheop)
117ef639e6fSAlexey Brodkin #define __slc_line_op(paddr, sz, cacheop)
118ef639e6fSAlexey Brodkin #endif
119ef639e6fSAlexey Brodkin 
120379b3280SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
121379b3280SAlexey Brodkin static void read_decode_cache_bcr_arcv2(void)
122ef639e6fSAlexey Brodkin {
123379b3280SAlexey Brodkin 	union {
124379b3280SAlexey Brodkin 		struct {
125379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
126379b3280SAlexey Brodkin 			unsigned int pad:24, way:2, lsz:2, sz:4;
127379b3280SAlexey Brodkin #else
128379b3280SAlexey Brodkin 			unsigned int sz:4, lsz:2, way:2, pad:24;
129379b3280SAlexey Brodkin #endif
130379b3280SAlexey Brodkin 		} fields;
131379b3280SAlexey Brodkin 		unsigned int word;
132379b3280SAlexey Brodkin 	} slc_cfg;
133379b3280SAlexey Brodkin 
134379b3280SAlexey Brodkin 	union {
135379b3280SAlexey Brodkin 		struct {
136379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
137379b3280SAlexey Brodkin 			unsigned int pad:24, ver:8;
138379b3280SAlexey Brodkin #else
139379b3280SAlexey Brodkin 			unsigned int ver:8, pad:24;
140379b3280SAlexey Brodkin #endif
141379b3280SAlexey Brodkin 		} fields;
142379b3280SAlexey Brodkin 		unsigned int word;
143379b3280SAlexey Brodkin 	} sbcr;
144379b3280SAlexey Brodkin 
145379b3280SAlexey Brodkin 	sbcr.word = read_aux_reg(ARC_BCR_SLC);
146379b3280SAlexey Brodkin 	if (sbcr.fields.ver) {
147379b3280SAlexey Brodkin 		slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG);
148379b3280SAlexey Brodkin 		slc_exists = 1;
149379b3280SAlexey Brodkin 		slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64;
150379b3280SAlexey Brodkin 	}
151*db6ce231SAlexey Brodkin 
152*db6ce231SAlexey Brodkin 	union {
153*db6ce231SAlexey Brodkin 		struct bcr_clust_cfg {
154*db6ce231SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
155*db6ce231SAlexey Brodkin 			unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
156*db6ce231SAlexey Brodkin #else
157*db6ce231SAlexey Brodkin 			unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
158*db6ce231SAlexey Brodkin #endif
159*db6ce231SAlexey Brodkin 		} fields;
160*db6ce231SAlexey Brodkin 		unsigned int word;
161*db6ce231SAlexey Brodkin 	} cbcr;
162*db6ce231SAlexey Brodkin 
163*db6ce231SAlexey Brodkin 	cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
164*db6ce231SAlexey Brodkin 	if (cbcr.fields.c)
165*db6ce231SAlexey Brodkin 		ioc_exists = 1;
166379b3280SAlexey Brodkin }
167379b3280SAlexey Brodkin #endif
168379b3280SAlexey Brodkin 
169379b3280SAlexey Brodkin void read_decode_cache_bcr(void)
170379b3280SAlexey Brodkin {
171379b3280SAlexey Brodkin 	int dc_line_sz = 0, ic_line_sz = 0;
172379b3280SAlexey Brodkin 
173379b3280SAlexey Brodkin 	union {
174379b3280SAlexey Brodkin 		struct {
175379b3280SAlexey Brodkin #ifdef CONFIG_CPU_BIG_ENDIAN
176379b3280SAlexey Brodkin 			unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
177379b3280SAlexey Brodkin #else
178379b3280SAlexey Brodkin 			unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
179379b3280SAlexey Brodkin #endif
180379b3280SAlexey Brodkin 		} fields;
181379b3280SAlexey Brodkin 		unsigned int word;
182379b3280SAlexey Brodkin 	} ibcr, dbcr;
183379b3280SAlexey Brodkin 
184379b3280SAlexey Brodkin 	ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
185379b3280SAlexey Brodkin 	if (ibcr.fields.ver) {
186379b3280SAlexey Brodkin 		icache_exists = 1;
187379b3280SAlexey Brodkin 		l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len;
188379b3280SAlexey Brodkin 		if (!ic_line_sz)
189379b3280SAlexey Brodkin 			panic("Instruction exists but line length is 0\n");
190ef639e6fSAlexey Brodkin 	}
191ef639e6fSAlexey Brodkin 
192379b3280SAlexey Brodkin 	dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
193379b3280SAlexey Brodkin 	if (dbcr.fields.ver){
194379b3280SAlexey Brodkin 		dcache_exists = 1;
195379b3280SAlexey Brodkin 		l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len;
196379b3280SAlexey Brodkin 		if (!dc_line_sz)
197379b3280SAlexey Brodkin 			panic("Data cache exists but line length is 0\n");
198379b3280SAlexey Brodkin 	}
199379b3280SAlexey Brodkin 
200379b3280SAlexey Brodkin 	if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz))
201379b3280SAlexey Brodkin 		panic("Instruction and data cache line lengths differ\n");
202ef639e6fSAlexey Brodkin }
203ef639e6fSAlexey Brodkin 
204ef639e6fSAlexey Brodkin void cache_init(void)
205ef639e6fSAlexey Brodkin {
206379b3280SAlexey Brodkin 	read_decode_cache_bcr();
207379b3280SAlexey Brodkin 
208ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
209379b3280SAlexey Brodkin 	read_decode_cache_bcr_arcv2();
210*db6ce231SAlexey Brodkin 
211*db6ce231SAlexey Brodkin 	if (ioc_exists) {
212*db6ce231SAlexey Brodkin 		/* IO coherency base - 0x8z */
213*db6ce231SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, 0x80000);
214*db6ce231SAlexey Brodkin 		/* IO coherency aperture size - 512Mb: 0x8z-0xAz */
215*db6ce231SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, 0x11);
216*db6ce231SAlexey Brodkin 		/* Enable partial writes */
217*db6ce231SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
218*db6ce231SAlexey Brodkin 		/* Enable IO coherency */
219*db6ce231SAlexey Brodkin 		write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
220*db6ce231SAlexey Brodkin 	}
221ef639e6fSAlexey Brodkin #endif
222ef639e6fSAlexey Brodkin }
223ef639e6fSAlexey Brodkin 
224660d5f0dSAlexey Brodkin int icache_status(void)
225660d5f0dSAlexey Brodkin {
226379b3280SAlexey Brodkin 	if (!icache_exists)
227660d5f0dSAlexey Brodkin 		return 0;
228660d5f0dSAlexey Brodkin 
229ef639e6fSAlexey Brodkin 	if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE)
230ef639e6fSAlexey Brodkin 		return 0;
231ef639e6fSAlexey Brodkin 	else
232ef639e6fSAlexey Brodkin 		return 1;
233660d5f0dSAlexey Brodkin }
234660d5f0dSAlexey Brodkin 
235660d5f0dSAlexey Brodkin void icache_enable(void)
236660d5f0dSAlexey Brodkin {
237379b3280SAlexey Brodkin 	if (icache_exists)
238660d5f0dSAlexey Brodkin 		write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) &
239660d5f0dSAlexey Brodkin 			      ~IC_CTRL_CACHE_DISABLE);
240660d5f0dSAlexey Brodkin }
241660d5f0dSAlexey Brodkin 
242660d5f0dSAlexey Brodkin void icache_disable(void)
243660d5f0dSAlexey Brodkin {
244379b3280SAlexey Brodkin 	if (icache_exists)
245660d5f0dSAlexey Brodkin 		write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) |
246660d5f0dSAlexey Brodkin 			      IC_CTRL_CACHE_DISABLE);
247660d5f0dSAlexey Brodkin }
248660d5f0dSAlexey Brodkin 
249ef639e6fSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF
250660d5f0dSAlexey Brodkin void invalidate_icache_all(void)
251660d5f0dSAlexey Brodkin {
252660d5f0dSAlexey Brodkin 	/* Any write to IC_IVIC register triggers invalidation of entire I$ */
253ef639e6fSAlexey Brodkin 	if (icache_status()) {
254660d5f0dSAlexey Brodkin 		write_aux_reg(ARC_AUX_IC_IVIC, 1);
255ef639e6fSAlexey Brodkin 		read_aux_reg(ARC_AUX_IC_CTRL);	/* blocks */
256660d5f0dSAlexey Brodkin 	}
257ef639e6fSAlexey Brodkin }
258ef639e6fSAlexey Brodkin #else
259ef639e6fSAlexey Brodkin void invalidate_icache_all(void)
260ef639e6fSAlexey Brodkin {
261ef639e6fSAlexey Brodkin }
262ef639e6fSAlexey Brodkin #endif
263660d5f0dSAlexey Brodkin 
264660d5f0dSAlexey Brodkin int dcache_status(void)
265660d5f0dSAlexey Brodkin {
266379b3280SAlexey Brodkin 	if (!dcache_exists)
267660d5f0dSAlexey Brodkin 		return 0;
268660d5f0dSAlexey Brodkin 
269ef639e6fSAlexey Brodkin 	if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE)
270ef639e6fSAlexey Brodkin 		return 0;
271ef639e6fSAlexey Brodkin 	else
272ef639e6fSAlexey Brodkin 		return 1;
273660d5f0dSAlexey Brodkin }
274660d5f0dSAlexey Brodkin 
275660d5f0dSAlexey Brodkin void dcache_enable(void)
276660d5f0dSAlexey Brodkin {
277379b3280SAlexey Brodkin 	if (!dcache_exists)
278660d5f0dSAlexey Brodkin 		return;
279660d5f0dSAlexey Brodkin 
280660d5f0dSAlexey Brodkin 	write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) &
281660d5f0dSAlexey Brodkin 		      ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE));
282660d5f0dSAlexey Brodkin }
283660d5f0dSAlexey Brodkin 
284660d5f0dSAlexey Brodkin void dcache_disable(void)
285660d5f0dSAlexey Brodkin {
286379b3280SAlexey Brodkin 	if (!dcache_exists)
287660d5f0dSAlexey Brodkin 		return;
288660d5f0dSAlexey Brodkin 
289660d5f0dSAlexey Brodkin 	write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) |
290660d5f0dSAlexey Brodkin 		      DC_CTRL_CACHE_DISABLE);
291660d5f0dSAlexey Brodkin }
292660d5f0dSAlexey Brodkin 
293660d5f0dSAlexey Brodkin #ifndef CONFIG_SYS_DCACHE_OFF
294660d5f0dSAlexey Brodkin /*
295ef639e6fSAlexey Brodkin  * Common Helper for Line Operations on {I,D}-Cache
296660d5f0dSAlexey Brodkin  */
297ef639e6fSAlexey Brodkin static inline void __cache_line_loop(unsigned long paddr, unsigned long sz,
298ef639e6fSAlexey Brodkin 				     const int cacheop)
299660d5f0dSAlexey Brodkin {
300ef639e6fSAlexey Brodkin 	unsigned int aux_cmd;
301ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
302ef639e6fSAlexey Brodkin 	unsigned int aux_tag;
303ef639e6fSAlexey Brodkin #endif
304ef639e6fSAlexey Brodkin 	int num_lines;
305660d5f0dSAlexey Brodkin 
306ef639e6fSAlexey Brodkin 	if (cacheop == OP_INV_IC) {
307ef639e6fSAlexey Brodkin 		aux_cmd = ARC_AUX_IC_IVIL;
308ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
309ef639e6fSAlexey Brodkin 		aux_tag = ARC_AUX_IC_PTAG;
310ef639e6fSAlexey Brodkin #endif
311ef639e6fSAlexey Brodkin 	} else {
312ef639e6fSAlexey Brodkin 		/* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
313ef639e6fSAlexey Brodkin 		aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL;
314ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
315ef639e6fSAlexey Brodkin 		aux_tag = ARC_AUX_DC_PTAG;
316ef639e6fSAlexey Brodkin #endif
317660d5f0dSAlexey Brodkin 	}
318660d5f0dSAlexey Brodkin 
319ef639e6fSAlexey Brodkin 	sz += paddr & ~CACHE_LINE_MASK;
320ef639e6fSAlexey Brodkin 	paddr &= CACHE_LINE_MASK;
321ef639e6fSAlexey Brodkin 
322379b3280SAlexey Brodkin 	num_lines = DIV_ROUND_UP(sz, l1_line_sz);
323ef639e6fSAlexey Brodkin 
324ef639e6fSAlexey Brodkin 	while (num_lines-- > 0) {
325ef639e6fSAlexey Brodkin #if (CONFIG_ARC_MMU_VER == 3)
326ef639e6fSAlexey Brodkin 		write_aux_reg(aux_tag, paddr);
327ef639e6fSAlexey Brodkin #endif
328ef639e6fSAlexey Brodkin 		write_aux_reg(aux_cmd, paddr);
329379b3280SAlexey Brodkin 		paddr += l1_line_sz;
330ef639e6fSAlexey Brodkin 	}
331ef639e6fSAlexey Brodkin }
332ef639e6fSAlexey Brodkin 
333ef639e6fSAlexey Brodkin static unsigned int __before_dc_op(const int op)
334ef639e6fSAlexey Brodkin {
335ef639e6fSAlexey Brodkin 	unsigned int reg;
336ef639e6fSAlexey Brodkin 
337ef639e6fSAlexey Brodkin 	if (op == OP_INV) {
338ef639e6fSAlexey Brodkin 		/*
339ef639e6fSAlexey Brodkin 		 * IM is set by default and implies Flush-n-inv
340ef639e6fSAlexey Brodkin 		 * Clear it here for vanilla inv
341ef639e6fSAlexey Brodkin 		 */
342ef639e6fSAlexey Brodkin 		reg = read_aux_reg(ARC_AUX_DC_CTRL);
343ef639e6fSAlexey Brodkin 		write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH);
344ef639e6fSAlexey Brodkin 	}
345ef639e6fSAlexey Brodkin 
346ef639e6fSAlexey Brodkin 	return reg;
347ef639e6fSAlexey Brodkin }
348ef639e6fSAlexey Brodkin 
349ef639e6fSAlexey Brodkin static void __after_dc_op(const int op, unsigned int reg)
350ef639e6fSAlexey Brodkin {
351ef639e6fSAlexey Brodkin 	if (op & OP_FLUSH)	/* flush / flush-n-inv both wait */
352ef639e6fSAlexey Brodkin 		while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS)
353ef639e6fSAlexey Brodkin 			;
354ef639e6fSAlexey Brodkin 
355ef639e6fSAlexey Brodkin 	/* Switch back to default Invalidate mode */
356ef639e6fSAlexey Brodkin 	if (op == OP_INV)
357ef639e6fSAlexey Brodkin 		write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH);
358ef639e6fSAlexey Brodkin }
359ef639e6fSAlexey Brodkin 
360ef639e6fSAlexey Brodkin static inline void __dc_entire_op(const int cacheop)
361ef639e6fSAlexey Brodkin {
362ef639e6fSAlexey Brodkin 	int aux;
363ef639e6fSAlexey Brodkin 	unsigned int ctrl_reg = __before_dc_op(cacheop);
364ef639e6fSAlexey Brodkin 
365ef639e6fSAlexey Brodkin 	if (cacheop & OP_INV)	/* Inv or flush-n-inv use same cmd reg */
366ef639e6fSAlexey Brodkin 		aux = ARC_AUX_DC_IVDC;
367ef639e6fSAlexey Brodkin 	else
368ef639e6fSAlexey Brodkin 		aux = ARC_AUX_DC_FLSH;
369ef639e6fSAlexey Brodkin 
370ef639e6fSAlexey Brodkin 	write_aux_reg(aux, 0x1);
371ef639e6fSAlexey Brodkin 
372ef639e6fSAlexey Brodkin 	__after_dc_op(cacheop, ctrl_reg);
373ef639e6fSAlexey Brodkin }
374ef639e6fSAlexey Brodkin 
375ef639e6fSAlexey Brodkin static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
376ef639e6fSAlexey Brodkin 				const int cacheop)
377ef639e6fSAlexey Brodkin {
378ef639e6fSAlexey Brodkin 	unsigned int ctrl_reg = __before_dc_op(cacheop);
379ef639e6fSAlexey Brodkin 	__cache_line_loop(paddr, sz, cacheop);
380ef639e6fSAlexey Brodkin 	__after_dc_op(cacheop, ctrl_reg);
381ef639e6fSAlexey Brodkin }
382ef639e6fSAlexey Brodkin #else
383ef639e6fSAlexey Brodkin #define __dc_entire_op(cacheop)
384ef639e6fSAlexey Brodkin #define __dc_line_op(paddr, sz, cacheop)
385ef639e6fSAlexey Brodkin #endif /* !CONFIG_SYS_DCACHE_OFF */
386ef639e6fSAlexey Brodkin 
387660d5f0dSAlexey Brodkin void invalidate_dcache_range(unsigned long start, unsigned long end)
388660d5f0dSAlexey Brodkin {
389ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
390*db6ce231SAlexey Brodkin 	if (!ioc_exists)
391*db6ce231SAlexey Brodkin #endif
392*db6ce231SAlexey Brodkin 		__dc_line_op(start, end - start, OP_INV);
393*db6ce231SAlexey Brodkin 
394*db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
395*db6ce231SAlexey Brodkin 	if (slc_exists && !ioc_exists)
396ef639e6fSAlexey Brodkin 		__slc_line_op(start, end - start, OP_INV);
397660d5f0dSAlexey Brodkin #endif
398660d5f0dSAlexey Brodkin }
399660d5f0dSAlexey Brodkin 
400ef639e6fSAlexey Brodkin void flush_dcache_range(unsigned long start, unsigned long end)
401660d5f0dSAlexey Brodkin {
402ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
403*db6ce231SAlexey Brodkin 	if (!ioc_exists)
404*db6ce231SAlexey Brodkin #endif
405*db6ce231SAlexey Brodkin 		__dc_line_op(start, end - start, OP_FLUSH);
406*db6ce231SAlexey Brodkin 
407*db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
408*db6ce231SAlexey Brodkin 	if (slc_exists && !ioc_exists)
409ef639e6fSAlexey Brodkin 		__slc_line_op(start, end - start, OP_FLUSH);
410ef639e6fSAlexey Brodkin #endif
411660d5f0dSAlexey Brodkin }
412660d5f0dSAlexey Brodkin 
413660d5f0dSAlexey Brodkin void flush_cache(unsigned long start, unsigned long size)
414660d5f0dSAlexey Brodkin {
415660d5f0dSAlexey Brodkin 	flush_dcache_range(start, start + size);
416660d5f0dSAlexey Brodkin }
4176eb15e50SAlexey Brodkin 
418ef639e6fSAlexey Brodkin void invalidate_dcache_all(void)
419ef639e6fSAlexey Brodkin {
4206eb15e50SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
421*db6ce231SAlexey Brodkin 	if (!ioc_exists)
422*db6ce231SAlexey Brodkin #endif
423*db6ce231SAlexey Brodkin 		__dc_entire_op(OP_INV);
424*db6ce231SAlexey Brodkin 
425*db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
426*db6ce231SAlexey Brodkin 	if (slc_exists && !ioc_exists)
427ef639e6fSAlexey Brodkin 		__slc_entire_op(OP_INV);
428ef639e6fSAlexey Brodkin #endif
4296eb15e50SAlexey Brodkin }
4306eb15e50SAlexey Brodkin 
431ef639e6fSAlexey Brodkin void flush_dcache_all(void)
4326eb15e50SAlexey Brodkin {
433ef639e6fSAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
434*db6ce231SAlexey Brodkin 	if (!ioc_exists)
435*db6ce231SAlexey Brodkin #endif
436*db6ce231SAlexey Brodkin 		__dc_entire_op(OP_FLUSH);
437*db6ce231SAlexey Brodkin 
438*db6ce231SAlexey Brodkin #ifdef CONFIG_ISA_ARCV2
439*db6ce231SAlexey Brodkin 	if (slc_exists && !ioc_exists)
440ef639e6fSAlexey Brodkin 		__slc_entire_op(OP_FLUSH);
441ef639e6fSAlexey Brodkin #endif
4426eb15e50SAlexey Brodkin }
443