1
2
3
4
5
6#include <config.h>
7#include <common.h>
8#include <cpu_func.h>
9#include <linux/bitops.h>
10#include <linux/compiler.h>
11#include <linux/kernel.h>
12#include <linux/log2.h>
13#include <asm/arcregs.h>
14#include <asm/arc-bcr.h>
15#include <asm/cache.h>
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
149
150
151DECLARE_GLOBAL_DATA_PTR;
152
153
154#define IC_CTRL_CACHE_DISABLE BIT(0)
155
156
157#define DC_CTRL_CACHE_DISABLE BIT(0)
158#define DC_CTRL_INV_MODE_FLUSH BIT(6)
159#define DC_CTRL_FLUSH_STATUS BIT(8)
160
161#define OP_INV BIT(0)
162#define OP_FLUSH BIT(1)
163#define OP_FLUSH_N_INV (OP_FLUSH | OP_INV)
164
165
166#define SLC_CTRL_DIS 0x001
167#define SLC_CTRL_IM 0x040
168#define SLC_CTRL_BUSY 0x100
169#define SLC_CTRL_RGN_OP_INV 0x200
170
171#define CACHE_LINE_MASK (~(gd->arch.l1_line_sz - 1))
172
173
174
175
176
177
178#define inlined_cachefunc inline __attribute__((always_inline))
179
180static inlined_cachefunc void __ic_entire_invalidate(void);
181static inlined_cachefunc void __dc_entire_op(const int cacheop);
182static inlined_cachefunc void __slc_entire_op(const int op);
183static inlined_cachefunc bool ioc_enabled(void);
184
185static inline bool pae_exists(void)
186{
187
188#if (CONFIG_ARC_MMU_VER >= 4)
189 union bcr_mmu_4 mmu4;
190
191 mmu4.word = read_aux_reg(ARC_AUX_MMU_BCR);
192
193 if (mmu4.fields.pae)
194 return true;
195#endif
196
197 return false;
198}
199
200static inlined_cachefunc bool icache_exists(void)
201{
202 union bcr_di_cache ibcr;
203
204 ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
205 return !!ibcr.fields.ver;
206}
207
208static inlined_cachefunc bool icache_enabled(void)
209{
210 if (!icache_exists())
211 return false;
212
213 return !(read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE);
214}
215
216static inlined_cachefunc bool dcache_exists(void)
217{
218 union bcr_di_cache dbcr;
219
220 dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
221 return !!dbcr.fields.ver;
222}
223
224static inlined_cachefunc bool dcache_enabled(void)
225{
226 if (!dcache_exists())
227 return false;
228
229 return !(read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE);
230}
231
232static inlined_cachefunc bool slc_exists(void)
233{
234 if (is_isa_arcv2()) {
235 union bcr_generic sbcr;
236
237 sbcr.word = read_aux_reg(ARC_BCR_SLC);
238 return !!sbcr.fields.ver;
239 }
240
241 return false;
242}
243
244enum slc_dis_status {
245 ST_SLC_MISSING = 0,
246 ST_SLC_NO_DISABLE_CTRL,
247 ST_SLC_DISABLE_CTRL
248};
249
250
251
252
253
254
255
256static inlined_cachefunc enum slc_dis_status slc_disable_supported(void)
257{
258 if (is_isa_arcv2()) {
259 union bcr_generic sbcr;
260
261 sbcr.word = read_aux_reg(ARC_BCR_SLC);
262 if (sbcr.fields.ver == 0)
263 return ST_SLC_MISSING;
264 else if (sbcr.fields.ver <= 2)
265 return ST_SLC_NO_DISABLE_CTRL;
266 else
267 return ST_SLC_DISABLE_CTRL;
268 }
269
270 return ST_SLC_MISSING;
271}
272
273static inlined_cachefunc bool __slc_enabled(void)
274{
275 return !(read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_DIS);
276}
277
278static inlined_cachefunc void __slc_enable(void)
279{
280 unsigned int ctrl;
281
282 ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
283 ctrl &= ~SLC_CTRL_DIS;
284 write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
285}
286
287static inlined_cachefunc void __slc_disable(void)
288{
289 unsigned int ctrl;
290
291 ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
292 ctrl |= SLC_CTRL_DIS;
293 write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
294}
295
296static inlined_cachefunc bool slc_enabled(void)
297{
298 enum slc_dis_status slc_status = slc_disable_supported();
299
300 if (slc_status == ST_SLC_MISSING)
301 return false;
302 else if (slc_status == ST_SLC_NO_DISABLE_CTRL)
303 return true;
304 else
305 return __slc_enabled();
306}
307
308static inlined_cachefunc bool slc_data_bypass(void)
309{
310
311
312
313
314 return !dcache_enabled();
315}
316
317void slc_enable(void)
318{
319 if (slc_disable_supported() != ST_SLC_DISABLE_CTRL)
320 return;
321
322 if (__slc_enabled())
323 return;
324
325 __slc_enable();
326}
327
328
329void slc_disable(void)
330{
331 if (slc_disable_supported() != ST_SLC_DISABLE_CTRL)
332 return;
333
334
335 if (ioc_enabled())
336 return;
337
338 if (!__slc_enabled())
339 return;
340
341
342
343
344
345 __dc_entire_op(OP_FLUSH);
346 __slc_entire_op(OP_FLUSH_N_INV);
347 __slc_disable();
348}
349
350static inlined_cachefunc bool ioc_exists(void)
351{
352 if (is_isa_arcv2()) {
353 union bcr_clust_cfg cbcr;
354
355 cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
356 return cbcr.fields.c;
357 }
358
359 return false;
360}
361
362static inlined_cachefunc bool ioc_enabled(void)
363{
364
365
366
367
368 if (is_ioc_enabled())
369 return ioc_exists();
370
371 return false;
372}
373
374static inlined_cachefunc void __slc_entire_op(const int op)
375{
376 unsigned int ctrl;
377
378 if (!slc_enabled())
379 return;
380
381 ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
382
383 if (!(op & OP_FLUSH))
384 ctrl &= ~SLC_CTRL_IM;
385 else
386 ctrl |= SLC_CTRL_IM;
387
388 write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
389
390 if (op & OP_INV)
391 write_aux_reg(ARC_AUX_SLC_INVALIDATE, 0x1);
392 else
393 write_aux_reg(ARC_AUX_SLC_FLUSH, 0x1);
394
395
396 read_aux_reg(ARC_AUX_SLC_CTRL);
397
398
399 while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY);
400}
401
402static void slc_upper_region_init(void)
403{
404
405
406
407
408
409 if (!pae_exists())
410 return;
411
412
413
414
415
416 write_aux_reg(ARC_AUX_SLC_RGN_END1, 0);
417 write_aux_reg(ARC_AUX_SLC_RGN_START1, 0);
418}
419
420static void __slc_rgn_op(unsigned long paddr, unsigned long sz, const int op)
421{
422#ifdef CONFIG_ISA_ARCV2
423
424 unsigned int ctrl;
425 unsigned long end;
426
427 if (!slc_enabled())
428 return;
429
430
431
432
433
434
435
436 ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
437
438
439 if (!(op & OP_FLUSH))
440 ctrl &= ~SLC_CTRL_IM;
441 else
442 ctrl |= SLC_CTRL_IM;
443
444 if (op & OP_INV)
445 ctrl |= SLC_CTRL_RGN_OP_INV;
446 else
447 ctrl &= ~SLC_CTRL_RGN_OP_INV;
448
449 write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
450
451
452
453
454
455
456 end = paddr + sz + gd->arch.slc_line_sz - 1;
457
458
459
460
461
462
463 write_aux_reg(ARC_AUX_SLC_RGN_END, end);
464 write_aux_reg(ARC_AUX_SLC_RGN_START, paddr);
465
466
467 read_aux_reg(ARC_AUX_SLC_CTRL);
468
469 while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY);
470
471#endif
472}
473
474static void arc_ioc_setup(void)
475{
476
477 unsigned int ap_base = CONFIG_SYS_SDRAM_BASE;
478
479 long ap_size = CONFIG_SYS_SDRAM_SIZE;
480
481
482 if (!slc_exists())
483 panic("Try to enable IOC but SLC is not present");
484
485 if (!slc_enabled())
486 panic("Try to enable IOC but SLC is disabled");
487
488
489 if (!dcache_enabled())
490 panic("Try to enable IOC but L1 D$ is disabled");
491
492 if (!is_power_of_2(ap_size) || ap_size < 4096)
493 panic("IOC Aperture size must be power of 2 and bigger 4Kib");
494
495
496 if (ap_base % ap_size != 0)
497 panic("IOC Aperture start must be aligned to the size of the aperture");
498
499 flush_n_invalidate_dcache_all();
500
501
502
503
504
505 write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE,
506 order_base_2(ap_size / 1024) - 2);
507
508 write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12);
509 write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
510 write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
511}
512
513static void read_decode_cache_bcr_arcv2(void)
514{
515#ifdef CONFIG_ISA_ARCV2
516
517 union bcr_slc_cfg slc_cfg;
518
519 if (slc_exists()) {
520 slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG);
521 gd->arch.slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64;
522
523
524
525
526
527 if (!icache_exists() || !dcache_exists())
528 panic("Unsupported cache configuration: SLC exists but one of L1 caches is absent");
529 }
530
531#endif
532}
533
534void read_decode_cache_bcr(void)
535{
536 int dc_line_sz = 0, ic_line_sz = 0;
537 union bcr_di_cache ibcr, dbcr;
538
539
540
541
542
543
544
545
546 ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
547 if (ibcr.fields.ver) {
548 ic_line_sz = 8 << ibcr.fields.line_len;
549 if (!ic_line_sz)
550 panic("Instruction exists but line length is 0\n");
551 }
552
553 dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
554 if (dbcr.fields.ver) {
555 gd->arch.l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len;
556 if (!dc_line_sz)
557 panic("Data cache exists but line length is 0\n");
558 }
559}
560
561void cache_init(void)
562{
563 read_decode_cache_bcr();
564
565 if (is_isa_arcv2())
566 read_decode_cache_bcr_arcv2();
567
568 if (is_isa_arcv2() && ioc_enabled())
569 arc_ioc_setup();
570
571 if (is_isa_arcv2() && slc_exists())
572 slc_upper_region_init();
573}
574
575int icache_status(void)
576{
577 return icache_enabled();
578}
579
580void icache_enable(void)
581{
582 if (icache_exists())
583 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) &
584 ~IC_CTRL_CACHE_DISABLE);
585}
586
587void icache_disable(void)
588{
589 if (!icache_exists())
590 return;
591
592 __ic_entire_invalidate();
593
594 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) |
595 IC_CTRL_CACHE_DISABLE);
596}
597
598
599static inlined_cachefunc void __ic_entire_invalidate(void)
600{
601 if (!icache_enabled())
602 return;
603
604
605 write_aux_reg(ARC_AUX_IC_IVIC, 1);
606
607
608
609
610 __builtin_arc_nop();
611 __builtin_arc_nop();
612 __builtin_arc_nop();
613 read_aux_reg(ARC_AUX_IC_CTRL);
614}
615
616void invalidate_icache_all(void)
617{
618 __ic_entire_invalidate();
619
620
621
622
623
624 if (is_isa_arcv2() && slc_data_bypass())
625 __slc_entire_op(OP_INV);
626}
627
628int dcache_status(void)
629{
630 return dcache_enabled();
631}
632
633void dcache_enable(void)
634{
635 if (!dcache_exists())
636 return;
637
638 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) &
639 ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE));
640}
641
642void dcache_disable(void)
643{
644 if (!dcache_exists())
645 return;
646
647 __dc_entire_op(OP_FLUSH_N_INV);
648
649
650
651
652
653
654
655 if (is_isa_arcv2())
656 __slc_entire_op(OP_FLUSH_N_INV);
657
658 write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) |
659 DC_CTRL_CACHE_DISABLE);
660}
661
662
663static inline void __dcache_line_loop(unsigned long paddr, unsigned long sz,
664 const int cacheop)
665{
666 unsigned int aux_cmd;
667 int num_lines;
668
669
670 aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL;
671
672 sz += paddr & ~CACHE_LINE_MASK;
673 paddr &= CACHE_LINE_MASK;
674
675 num_lines = DIV_ROUND_UP(sz, gd->arch.l1_line_sz);
676
677 while (num_lines-- > 0) {
678#if (CONFIG_ARC_MMU_VER == 3)
679 write_aux_reg(ARC_AUX_DC_PTAG, paddr);
680#endif
681 write_aux_reg(aux_cmd, paddr);
682 paddr += gd->arch.l1_line_sz;
683 }
684}
685
686static inlined_cachefunc void __before_dc_op(const int op)
687{
688 unsigned int ctrl;
689
690 ctrl = read_aux_reg(ARC_AUX_DC_CTRL);
691
692
693 if (op == OP_INV)
694 ctrl &= ~DC_CTRL_INV_MODE_FLUSH;
695 else
696 ctrl |= DC_CTRL_INV_MODE_FLUSH;
697
698 write_aux_reg(ARC_AUX_DC_CTRL, ctrl);
699}
700
701static inlined_cachefunc void __after_dc_op(const int op)
702{
703 if (op & OP_FLUSH)
704 while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS);
705}
706
707static inlined_cachefunc void __dc_entire_op(const int cacheop)
708{
709 int aux;
710
711 if (!dcache_enabled())
712 return;
713
714 __before_dc_op(cacheop);
715
716 if (cacheop & OP_INV)
717 aux = ARC_AUX_DC_IVDC;
718 else
719 aux = ARC_AUX_DC_FLSH;
720
721 write_aux_reg(aux, 0x1);
722
723 __after_dc_op(cacheop);
724}
725
726static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
727 const int cacheop)
728{
729 if (!dcache_enabled())
730 return;
731
732 __before_dc_op(cacheop);
733 __dcache_line_loop(paddr, sz, cacheop);
734 __after_dc_op(cacheop);
735}
736
737void invalidate_dcache_range(unsigned long start, unsigned long end)
738{
739 if (start >= end)
740 return;
741
742
743
744
745
746
747
748 if (!is_isa_arcv2() || !ioc_enabled())
749 __dc_line_op(start, end - start, OP_INV);
750
751 if (is_isa_arcv2() && !ioc_enabled() && !slc_data_bypass())
752 __slc_rgn_op(start, end - start, OP_INV);
753}
754
755void flush_dcache_range(unsigned long start, unsigned long end)
756{
757 if (start >= end)
758 return;
759
760
761
762
763
764
765
766 if (!is_isa_arcv2() || !ioc_enabled())
767 __dc_line_op(start, end - start, OP_FLUSH);
768
769 if (is_isa_arcv2() && !ioc_enabled() && !slc_data_bypass())
770 __slc_rgn_op(start, end - start, OP_FLUSH);
771}
772
773void flush_cache(unsigned long start, unsigned long size)
774{
775 flush_dcache_range(start, start + size);
776}
777
778
779
780
781
782
783
784void flush_n_invalidate_dcache_all(void)
785{
786 __dc_entire_op(OP_FLUSH_N_INV);
787
788 if (is_isa_arcv2() && !slc_data_bypass())
789 __slc_entire_op(OP_FLUSH_N_INV);
790}
791
792void flush_dcache_all(void)
793{
794 __dc_entire_op(OP_FLUSH);
795
796 if (is_isa_arcv2() && !slc_data_bypass())
797 __slc_entire_op(OP_FLUSH);
798}
799
800
801
802
803
804
805void sync_n_cleanup_cache_all(void)
806{
807 __dc_entire_op(OP_FLUSH_N_INV);
808
809
810
811
812
813 if (is_isa_arcv2()) {
814 if (slc_data_bypass())
815 __slc_entire_op(OP_INV);
816 else
817 __slc_entire_op(OP_FLUSH_N_INV);
818 }
819
820 __ic_entire_invalidate();
821}
822