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