]> git.ipfire.org Git - people/ms/u-boot.git/blame - arch/arc/lib/cache.c
Merge branch 'master' of git://git.denx.de/u-boot
[people/ms/u-boot.git] / arch / arc / lib / cache.c
CommitLineData
2f16ac9d
AB
1/*
2 * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include <config.h>
ef639e6f
AB
8#include <linux/compiler.h>
9#include <linux/kernel.h>
2f16ac9d 10#include <asm/arcregs.h>
205e7a7b 11#include <asm/cache.h>
2f16ac9d 12
ef639e6f
AB
13#define CACHE_LINE_MASK (~(CONFIG_SYS_CACHELINE_SIZE - 1))
14
2f16ac9d
AB
15/* Bit values in IC_CTRL */
16#define IC_CTRL_CACHE_DISABLE (1 << 0)
17
18/* Bit values in DC_CTRL */
19#define DC_CTRL_CACHE_DISABLE (1 << 0)
20#define DC_CTRL_INV_MODE_FLUSH (1 << 6)
21#define DC_CTRL_FLUSH_STATUS (1 << 8)
f8cf3d1e 22#define CACHE_VER_NUM_MASK 0xF
6eb15e50 23#define SLC_CTRL_SB (1 << 2)
2f16ac9d 24
ef639e6f
AB
25#define OP_INV 0x1
26#define OP_FLUSH 0x2
27#define OP_INV_IC 0x3
28
29#ifdef CONFIG_ISA_ARCV2
30/*
31 * By default that variable will fall into .bss section.
32 * But .bss section is not relocated and so it will be initilized before
33 * relocation but will be used after being zeroed.
34 */
35int slc_line_sz __section(".data");
36int slc_exists __section(".data");
37
38static unsigned int __before_slc_op(const int op)
39{
40 unsigned int reg = reg;
41
42 if (op == OP_INV) {
43 /*
44 * IM is set by default and implies Flush-n-inv
45 * Clear it here for vanilla inv
46 */
47 reg = read_aux_reg(ARC_AUX_SLC_CTRL);
48 write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH);
49 }
50
51 return reg;
52}
53
54static void __after_slc_op(const int op, unsigned int reg)
55{
56 if (op & OP_FLUSH) /* flush / flush-n-inv both wait */
57 while (read_aux_reg(ARC_AUX_SLC_CTRL) &
58 DC_CTRL_FLUSH_STATUS)
59 ;
60
61 /* Switch back to default Invalidate mode */
62 if (op == OP_INV)
63 write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH);
64}
65
66static inline void __slc_line_loop(unsigned long paddr, unsigned long sz,
67 const int op)
68{
69 unsigned int aux_cmd;
70 int num_lines;
71
72#define SLC_LINE_MASK (~(slc_line_sz - 1))
73
74 aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL;
75
76 sz += paddr & ~SLC_LINE_MASK;
77 paddr &= SLC_LINE_MASK;
78
79 num_lines = DIV_ROUND_UP(sz, slc_line_sz);
80
81 while (num_lines-- > 0) {
82 write_aux_reg(aux_cmd, paddr);
83 paddr += slc_line_sz;
84 }
85}
86
87static inline void __slc_entire_op(const int cacheop)
88{
89 int aux;
90 unsigned int ctrl_reg = __before_slc_op(cacheop);
91
92 if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */
93 aux = ARC_AUX_SLC_INVALIDATE;
94 else
95 aux = ARC_AUX_SLC_FLUSH;
96
97 write_aux_reg(aux, 0x1);
98
99 __after_slc_op(cacheop, ctrl_reg);
100}
101
102static inline void __slc_line_op(unsigned long paddr, unsigned long sz,
103 const int cacheop)
104{
105 unsigned int ctrl_reg = __before_slc_op(cacheop);
106 __slc_line_loop(paddr, sz, cacheop);
107 __after_slc_op(cacheop, ctrl_reg);
108}
109#else
110#define __slc_entire_op(cacheop)
111#define __slc_line_op(paddr, sz, cacheop)
112#endif
113
114static inline int icache_exists(void)
115{
116 /* Check if Instruction Cache is available */
117 if (read_aux_reg(ARC_BCR_IC_BUILD) & CACHE_VER_NUM_MASK)
118 return 1;
119 else
120 return 0;
121}
122
123static inline int dcache_exists(void)
124{
125 /* Check if Data Cache is available */
126 if (read_aux_reg(ARC_BCR_DC_BUILD) & CACHE_VER_NUM_MASK)
127 return 1;
128 else
129 return 0;
130}
131
132void cache_init(void)
133{
134#ifdef CONFIG_ISA_ARCV2
135 /* Check if System-Level Cache (SLC) is available */
136 if (read_aux_reg(ARC_BCR_SLC) & CACHE_VER_NUM_MASK) {
137#define LSIZE_OFFSET 4
138#define LSIZE_MASK 3
139 if (read_aux_reg(ARC_AUX_SLC_CONFIG) &
140 (LSIZE_MASK << LSIZE_OFFSET))
141 slc_line_sz = 64;
142 else
143 slc_line_sz = 128;
144 slc_exists = 1;
145 } else {
146 slc_exists = 0;
147 }
148#endif
149}
150
2f16ac9d
AB
151int icache_status(void)
152{
ef639e6f 153 if (!icache_exists())
f8cf3d1e
IG
154 return 0;
155
ef639e6f
AB
156 if (read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE)
157 return 0;
158 else
159 return 1;
2f16ac9d
AB
160}
161
162void icache_enable(void)
163{
ef639e6f
AB
164 if (icache_exists())
165 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) &
166 ~IC_CTRL_CACHE_DISABLE);
2f16ac9d
AB
167}
168
169void icache_disable(void)
170{
ef639e6f
AB
171 if (icache_exists())
172 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) |
173 IC_CTRL_CACHE_DISABLE);
2f16ac9d
AB
174}
175
ef639e6f 176#ifndef CONFIG_SYS_DCACHE_OFF
2f16ac9d
AB
177void invalidate_icache_all(void)
178{
2f16ac9d 179 /* Any write to IC_IVIC register triggers invalidation of entire I$ */
ef639e6f
AB
180 if (icache_status()) {
181 write_aux_reg(ARC_AUX_IC_IVIC, 1);
182 read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */
183 }
2f16ac9d 184}
ef639e6f
AB
185#else
186void invalidate_icache_all(void)
187{
188}
189#endif
2f16ac9d
AB
190
191int dcache_status(void)
192{
ef639e6f 193 if (!dcache_exists())
f8cf3d1e
IG
194 return 0;
195
ef639e6f
AB
196 if (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE)
197 return 0;
198 else
199 return 1;
2f16ac9d
AB
200}
201
202void dcache_enable(void)
203{
ef639e6f 204 if (!dcache_exists())
f8cf3d1e
IG
205 return;
206
2f16ac9d
AB
207 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) &
208 ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE));
209}
210
211void dcache_disable(void)
212{
ef639e6f 213 if (!dcache_exists())
f8cf3d1e
IG
214 return;
215
2f16ac9d
AB
216 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) |
217 DC_CTRL_CACHE_DISABLE);
218}
219
2f16ac9d 220#ifndef CONFIG_SYS_DCACHE_OFF
ef639e6f
AB
221/*
222 * Common Helper for Line Operations on {I,D}-Cache
223 */
224static inline void __cache_line_loop(unsigned long paddr, unsigned long sz,
225 const int cacheop)
2f16ac9d 226{
ef639e6f 227 unsigned int aux_cmd;
5ff40f3d 228#if (CONFIG_ARC_MMU_VER == 3)
ef639e6f 229 unsigned int aux_tag;
2f16ac9d 230#endif
ef639e6f 231 int num_lines;
2f16ac9d 232
ef639e6f
AB
233 if (cacheop == OP_INV_IC) {
234 aux_cmd = ARC_AUX_IC_IVIL;
5ff40f3d 235#if (CONFIG_ARC_MMU_VER == 3)
ef639e6f 236 aux_tag = ARC_AUX_IC_PTAG;
2f16ac9d 237#endif
ef639e6f
AB
238 } else {
239 /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
240 aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL;
241#if (CONFIG_ARC_MMU_VER == 3)
242 aux_tag = ARC_AUX_DC_PTAG;
243#endif
244 }
2f16ac9d 245
ef639e6f
AB
246 sz += paddr & ~CACHE_LINE_MASK;
247 paddr &= CACHE_LINE_MASK;
2f16ac9d 248
ef639e6f 249 num_lines = DIV_ROUND_UP(sz, CONFIG_SYS_CACHELINE_SIZE);
2f16ac9d 250
ef639e6f 251 while (num_lines-- > 0) {
5ff40f3d 252#if (CONFIG_ARC_MMU_VER == 3)
ef639e6f 253 write_aux_reg(aux_tag, paddr);
2f16ac9d 254#endif
ef639e6f
AB
255 write_aux_reg(aux_cmd, paddr);
256 paddr += CONFIG_SYS_CACHELINE_SIZE;
2f16ac9d 257 }
2f16ac9d
AB
258}
259
ef639e6f 260static unsigned int __before_dc_op(const int op)
2f16ac9d 261{
ef639e6f
AB
262 unsigned int reg;
263
264 if (op == OP_INV) {
265 /*
266 * IM is set by default and implies Flush-n-inv
267 * Clear it here for vanilla inv
268 */
269 reg = read_aux_reg(ARC_AUX_DC_CTRL);
270 write_aux_reg(ARC_AUX_DC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH);
271 }
ae4a351a 272
ef639e6f 273 return reg;
2f16ac9d
AB
274}
275
ef639e6f 276static void __after_dc_op(const int op, unsigned int reg)
2f16ac9d 277{
ef639e6f
AB
278 if (op & OP_FLUSH) /* flush / flush-n-inv both wait */
279 while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS)
280 ;
281
282 /* Switch back to default Invalidate mode */
283 if (op == OP_INV)
284 write_aux_reg(ARC_AUX_DC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH);
2f16ac9d 285}
6eb15e50 286
ef639e6f 287static inline void __dc_entire_op(const int cacheop)
6eb15e50 288{
ef639e6f
AB
289 int aux;
290 unsigned int ctrl_reg = __before_dc_op(cacheop);
6eb15e50 291
ef639e6f
AB
292 if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */
293 aux = ARC_AUX_DC_IVDC;
294 else
295 aux = ARC_AUX_DC_FLSH;
6eb15e50 296
ef639e6f 297 write_aux_reg(aux, 0x1);
6eb15e50 298
ef639e6f 299 __after_dc_op(cacheop, ctrl_reg);
6eb15e50
AB
300}
301
ef639e6f
AB
302static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
303 const int cacheop)
6eb15e50 304{
ef639e6f
AB
305 unsigned int ctrl_reg = __before_dc_op(cacheop);
306 __cache_line_loop(paddr, sz, cacheop);
307 __after_dc_op(cacheop, ctrl_reg);
308}
309#else
310#define __dc_entire_op(cacheop)
311#define __dc_line_op(paddr, sz, cacheop)
312#endif /* !CONFIG_SYS_DCACHE_OFF */
6eb15e50 313
ef639e6f
AB
314void invalidate_dcache_range(unsigned long start, unsigned long end)
315{
316 __dc_line_op(start, end - start, OP_INV);
317#ifdef CONFIG_ISA_ARCV2
318 if (slc_exists)
319 __slc_line_op(start, end - start, OP_INV);
320#endif
321}
6eb15e50 322
ef639e6f
AB
323void flush_dcache_range(unsigned long start, unsigned long end)
324{
325 __dc_line_op(start, end - start, OP_FLUSH);
326#ifdef CONFIG_ISA_ARCV2
327 if (slc_exists)
328 __slc_line_op(start, end - start, OP_FLUSH);
329#endif
6eb15e50
AB
330}
331
ef639e6f 332void flush_cache(unsigned long start, unsigned long size)
6eb15e50 333{
ef639e6f
AB
334 flush_dcache_range(start, start + size);
335}
6eb15e50 336
ef639e6f
AB
337void invalidate_dcache_all(void)
338{
339 __dc_entire_op(OP_INV);
340#ifdef CONFIG_ISA_ARCV2
341 if (slc_exists)
342 __slc_entire_op(OP_INV);
343#endif
6eb15e50
AB
344}
345
ef639e6f
AB
346void flush_dcache_all(void)
347{
348 __dc_entire_op(OP_FLUSH);
349#ifdef CONFIG_ISA_ARCV2
350 if (slc_exists)
351 __slc_entire_op(OP_FLUSH);
352#endif
353}