1
2
3
4
5
6#include <config.h>
7#include <common.h>
8#include <linux/compiler.h>
9#include <linux/kernel.h>
10#include <linux/log2.h>
11#include <asm/arcregs.h>
12#include <asm/arc-bcr.h>
13#include <asm/cache.h>
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149DECLARE_GLOBAL_DATA_PTR;
150
151
152#define IC_CTRL_CACHE_DISABLE BIT(0)
153
154
155#define DC_CTRL_CACHE_DISABLE BIT(0)
156#define DC_CTRL_INV_MODE_FLUSH BIT(6)
157#define DC_CTRL_FLUSH_STATUS BIT(8)
158
159#define OP_INV BIT(0)
160#define OP_FLUSH BIT(1)
161#define OP_FLUSH_N_INV (OP_FLUSH | OP_INV)
162
163
164#define SLC_CTRL_DIS 0x001
165#define SLC_CTRL_IM 0x040
166#define SLC_CTRL_BUSY 0x100
167#define SLC_CTRL_RGN_OP_INV 0x200
168
169#define CACHE_LINE_MASK (~(gd->arch.l1_line_sz - 1))
170
171
172
173
174
175
176#define inlined_cachefunc inline __attribute__((always_inline))
177
178static inlined_cachefunc void __ic_entire_invalidate(void);
179static inlined_cachefunc void __dc_entire_op(const int cacheop);
180
181static inline bool pae_exists(void)
182{
183
184#if (CONFIG_ARC_MMU_VER >= 4)
185 union bcr_mmu_4 mmu4;
186
187 mmu4.word = read_aux_reg(ARC_AUX_MMU_BCR);
188
189 if (mmu4.fields.pae)
190 return true;
191#endif
192
193 return false;
194}
195
196static inlined_cachefunc bool icache_exists(void)
197{
198 union bcr_di_cache ibcr;
199
200 ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
201 return !!ibcr.fields.ver;
202}
203
204static inlined_cachefunc bool icache_enabled(void)
205{
206 if (!icache_exists())
207 return false;
208
209 return !(read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE);
210}
211
212static inlined_cachefunc bool dcache_exists(void)
213{
214 union bcr_di_cache dbcr;
215
216 dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
217 return !!dbcr.fields.ver;
218}
219
220static inlined_cachefunc bool dcache_enabled(void)
221{
222 if (!dcache_exists())
223 return false;
224
225 return !(read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE);
226}
227
228static inlined_cachefunc bool slc_exists(void)
229{
230 if (is_isa_arcv2()) {
231 union bcr_generic sbcr;
232
233 sbcr.word = read_aux_reg(ARC_BCR_SLC);
234 return !!sbcr.fields.ver;
235 }
236
237 return false;
238}
239
240static inlined_cachefunc bool slc_data_bypass(void)
241{
242
243
244
245
246 return !dcache_enabled();
247}
248
249static inline bool ioc_exists(void)
250{
251 if (is_isa_arcv2()) {
252 union bcr_clust_cfg cbcr;
253
254 cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
255 return cbcr.fields.c;
256 }
257
258 return false;
259}
260
261static inline bool ioc_enabled(void)
262{
263
264
265
266
267 if (is_ioc_enabled())
268 return ioc_exists();
269
270 return false;
271}
272
273static inlined_cachefunc void __slc_entire_op(const int op)
274{
275 unsigned int ctrl;
276
277 if (!slc_exists())
278 return;
279
280 ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
281
282 if (!(op & OP_FLUSH))
283 ctrl &= ~SLC_CTRL_IM;
284 else
285 ctrl |= SLC_CTRL_IM;
286
287 write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
288
289 if (op & OP_INV)
290 write_aux_reg(ARC_AUX_SLC_INVALIDATE, 0x1);
291 else
292 write_aux_reg(ARC_AUX_SLC_FLUSH, 0x1);
293
294
295 read_aux_reg(ARC_AUX_SLC_CTRL);
296
297
298 while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY);
299}
300
301static void slc_upper_region_init(void)
302{
303
304
305
306
307
308 if (!pae_exists())
309 return;
310
311
312
313
314
315 write_aux_reg(ARC_AUX_SLC_RGN_END1, 0);
316 write_aux_reg(ARC_AUX_SLC_RGN_START1, 0);
317}
318
319static void __slc_rgn_op(unsigned long paddr, unsigned long sz, const int op)
320{
321#ifdef CONFIG_ISA_ARCV2
322
323 unsigned int ctrl;
324 unsigned long end;
325
326 if (!slc_exists())
327 return;
328
329
330
331
332
333
334
335 ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
336
337
338 if (!(op & OP_FLUSH))
339 ctrl &= ~SLC_CTRL_IM;
340 else
341 ctrl |= SLC_CTRL_IM;
342
343 if (op & OP_INV)
344 ctrl |= SLC_CTRL_RGN_OP_INV;
345 else
346 ctrl &= ~SLC_CTRL_RGN_OP_INV;
347
348 write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
349
350
351
352
353
354
355 end = paddr + sz + gd->arch.slc_line_sz - 1;
356
357
358
359
360
361
362 write_aux_reg(ARC_AUX_SLC_RGN_END, end);
363 write_aux_reg(ARC_AUX_SLC_RGN_START, paddr);
364
365
366 read_aux_reg(ARC_AUX_SLC_CTRL);
367
368 while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY);
369
370#endif
371}
372
373static void arc_ioc_setup(void)
374{
375
376 unsigned int ap_base = CONFIG_SYS_SDRAM_BASE;
377
378 long ap_size = CONFIG_SYS_SDRAM_SIZE;
379
380
381 if (!slc_exists())
382 panic("Try to enable IOC but SLC is not present");
383
384
385 if (!dcache_enabled())
386 panic("Try to enable IOC but L1 D$ is disabled");
387
388 if (!is_power_of_2(ap_size) || ap_size < 4096)
389 panic("IOC Aperture size must be power of 2 and bigger 4Kib");
390
391
392 if (ap_base % ap_size != 0)
393 panic("IOC Aperture start must be aligned to the size of the aperture");
394
395 flush_n_invalidate_dcache_all();
396
397
398
399
400
401 write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE,
402 order_base_2(ap_size / 1024) - 2);
403
404 write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12);
405 write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
406 write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
407}
408
409static void read_decode_cache_bcr_arcv2(void)
410{
411#ifdef CONFIG_ISA_ARCV2
412
413 union bcr_slc_cfg slc_cfg;
414
415 if (slc_exists()) {
416 slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG);
417 gd->arch.slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64;
418
419
420
421
422
423 if (!icache_exists() || !dcache_exists())
424 panic("Unsupported cache configuration: SLC exists but one of L1 caches is absent");
425 }
426
427#endif
428}
429
430void read_decode_cache_bcr(void)
431{
432 int dc_line_sz = 0, ic_line_sz = 0;
433 union bcr_di_cache ibcr, dbcr;
434
435 ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
436 if (ibcr.fields.ver) {
437 gd->arch.l1_line_sz = ic_line_sz = 8 << ibcr.fields.line_len;
438 if (!ic_line_sz)
439 panic("Instruction exists but line length is 0\n");
440 }
441
442 dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
443 if (dbcr.fields.ver) {
444 gd->arch.l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len;
445 if (!dc_line_sz)
446 panic("Data cache exists but line length is 0\n");
447 }
448
449 if (ic_line_sz && dc_line_sz && (ic_line_sz != dc_line_sz))
450 panic("Instruction and data cache line lengths differ\n");
451}
452
453void cache_init(void)
454{
455 read_decode_cache_bcr();
456
457 if (is_isa_arcv2())
458 read_decode_cache_bcr_arcv2();
459
460 if (is_isa_arcv2() && ioc_enabled())
461 arc_ioc_setup();
462
463 if (is_isa_arcv2() && slc_exists())
464 slc_upper_region_init();
465}
466
467int icache_status(void)
468{
469 return icache_enabled();
470}
471
472void icache_enable(void)
473{
474 if (icache_exists())
475 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) &
476 ~IC_CTRL_CACHE_DISABLE);
477}
478
479void icache_disable(void)
480{
481 if (!icache_exists())
482 return;
483
484 __ic_entire_invalidate();
485
486 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) |
487 IC_CTRL_CACHE_DISABLE);
488}
489
490
491static inlined_cachefunc void __ic_entire_invalidate(void)
492{
493 if (!icache_enabled())
494 return;
495
496
497 write_aux_reg(ARC_AUX_IC_IVIC, 1);
498
499
500
501
502 __builtin_arc_nop();
503 __builtin_arc_nop();
504 __builtin_arc_nop();
505 read_aux_reg(ARC_AUX_IC_CTRL);
506}
507
508void invalidate_icache_all(void)
509{
510 __ic_entire_invalidate();
511
512
513
514
515
516
517
518 if (is_isa_arcv2() && slc_data_bypass())
519 __slc_entire_op(OP_INV);
520}
521
522int dcache_status(void)
523{
524 return dcache_enabled();
525}
526
527void dcache_enable(void)
528{
529 if (!dcache_exists())
530 return;
531
532 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) &
533 ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE));
534}
535
536void dcache_disable(void)
537{
538 if (!dcache_exists())
539 return;
540
541 __dc_entire_op(OP_FLUSH_N_INV);
542
543
544
545
546
547
548
549 if (is_isa_arcv2())
550 __slc_entire_op(OP_FLUSH_N_INV);
551
552 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) |
553 DC_CTRL_CACHE_DISABLE);
554}
555
556
557static inline void __dcache_line_loop(unsigned long paddr, unsigned long sz,
558 const int cacheop)
559{
560 unsigned int aux_cmd;
561 int num_lines;
562
563
564 aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL;
565
566 sz += paddr & ~CACHE_LINE_MASK;
567 paddr &= CACHE_LINE_MASK;
568
569 num_lines = DIV_ROUND_UP(sz, gd->arch.l1_line_sz);
570
571 while (num_lines-- > 0) {
572#if (CONFIG_ARC_MMU_VER == 3)
573 write_aux_reg(ARC_AUX_DC_PTAG, paddr);
574#endif
575 write_aux_reg(aux_cmd, paddr);
576 paddr += gd->arch.l1_line_sz;
577 }
578}
579
580static inlined_cachefunc void __before_dc_op(const int op)
581{
582 unsigned int ctrl;
583
584 ctrl = read_aux_reg(ARC_AUX_DC_CTRL);
585
586
587 if (op == OP_INV)
588 ctrl &= ~DC_CTRL_INV_MODE_FLUSH;
589 else
590 ctrl |= DC_CTRL_INV_MODE_FLUSH;
591
592 write_aux_reg(ARC_AUX_DC_CTRL, ctrl);
593}
594
595static inlined_cachefunc void __after_dc_op(const int op)
596{
597 if (op & OP_FLUSH)
598 while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS);
599}
600
601static inlined_cachefunc void __dc_entire_op(const int cacheop)
602{
603 int aux;
604
605 if (!dcache_enabled())
606 return;
607
608 __before_dc_op(cacheop);
609
610 if (cacheop & OP_INV)
611 aux = ARC_AUX_DC_IVDC;
612 else
613 aux = ARC_AUX_DC_FLSH;
614
615 write_aux_reg(aux, 0x1);
616
617 __after_dc_op(cacheop);
618}
619
620static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
621 const int cacheop)
622{
623 if (!dcache_enabled())
624 return;
625
626 __before_dc_op(cacheop);
627 __dcache_line_loop(paddr, sz, cacheop);
628 __after_dc_op(cacheop);
629}
630
631void invalidate_dcache_range(unsigned long start, unsigned long end)
632{
633 if (start >= end)
634 return;
635
636
637
638
639
640
641
642 if (!is_isa_arcv2() || !ioc_enabled())
643 __dc_line_op(start, end - start, OP_INV);
644
645 if (is_isa_arcv2() && !ioc_enabled() && !slc_data_bypass())
646 __slc_rgn_op(start, end - start, OP_INV);
647}
648
649void flush_dcache_range(unsigned long start, unsigned long end)
650{
651 if (start >= end)
652 return;
653
654
655
656
657
658
659
660 if (!is_isa_arcv2() || !ioc_enabled())
661 __dc_line_op(start, end - start, OP_FLUSH);
662
663 if (is_isa_arcv2() && !ioc_enabled() && !slc_data_bypass())
664 __slc_rgn_op(start, end - start, OP_FLUSH);
665}
666
667void flush_cache(unsigned long start, unsigned long size)
668{
669 flush_dcache_range(start, start + size);
670}
671
672
673
674
675
676
677
678void flush_n_invalidate_dcache_all(void)
679{
680 __dc_entire_op(OP_FLUSH_N_INV);
681
682 if (is_isa_arcv2() && !slc_data_bypass())
683 __slc_entire_op(OP_FLUSH_N_INV);
684}
685
686void flush_dcache_all(void)
687{
688 __dc_entire_op(OP_FLUSH);
689
690 if (is_isa_arcv2() && !slc_data_bypass())
691 __slc_entire_op(OP_FLUSH);
692}
693
694
695
696
697
698
699void sync_n_cleanup_cache_all(void)
700{
701 __dc_entire_op(OP_FLUSH_N_INV);
702
703
704
705
706
707 if (is_isa_arcv2()) {
708 if (slc_data_bypass())
709 __slc_entire_op(OP_INV);
710 else
711 __slc_entire_op(OP_FLUSH_N_INV);
712 }
713
714 __ic_entire_invalidate();
715}
716