ARC: CACHE: mark IOC helper functions as inlined_cachefunc
[oweals/u-boot.git] / arch / arc / lib / cache.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
4  */
5
6 #include <config.h>
7 #include <common.h>
8 #include <cpu_func.h>
9 #include <linux/compiler.h>
10 #include <linux/kernel.h>
11 #include <linux/log2.h>
12 #include <asm/arcregs.h>
13 #include <asm/arc-bcr.h>
14 #include <asm/cache.h>
15
16 /*
17  * [ NOTE 1 ]:
18  * Data cache (L1 D$ or SL$) entire invalidate operation or data cache disable
19  * operation may result in unexpected behavior and data loss even if we flush
20  * data cache right before invalidation. That may happens if we store any context
21  * on stack (like we store BLINK register on stack before function call).
22  * BLINK register is the register where return address is automatically saved
23  * when we do function call with instructions like 'bl'.
24  *
25  * There is the real example:
26  * We may hang in the next code as we store any BLINK register on stack in
27  * invalidate_dcache_all() function.
28  *
29  * void flush_dcache_all() {
30  *     __dc_entire_op(OP_FLUSH);
31  *     // Other code //
32  * }
33  *
34  * void invalidate_dcache_all() {
35  *     __dc_entire_op(OP_INV);
36  *     // Other code //
37  * }
38  *
39  * void foo(void) {
40  *     flush_dcache_all();
41  *     invalidate_dcache_all();
42  * }
43  *
44  * Now let's see what really happens during that code execution:
45  *
46  * foo()
47  *   |->> call flush_dcache_all
48  *     [return address is saved to BLINK register]
49  *     [push BLINK] (save to stack)              ![point 1]
50  *     |->> call __dc_entire_op(OP_FLUSH)
51  *         [return address is saved to BLINK register]
52  *         [flush L1 D$]
53  *         return [jump to BLINK]
54  *     <<------
55  *     [other flush_dcache_all code]
56  *     [pop BLINK] (get from stack)
57  *     return [jump to BLINK]
58  *   <<------
59  *   |->> call invalidate_dcache_all
60  *     [return address is saved to BLINK register]
61  *     [push BLINK] (save to stack)               ![point 2]
62  *     |->> call __dc_entire_op(OP_FLUSH)
63  *         [return address is saved to BLINK register]
64  *         [invalidate L1 D$]                 ![point 3]
65  *         // Oops!!!
66  *         // We lose return address from invalidate_dcache_all function:
67  *         // we save it to stack and invalidate L1 D$ after that!
68  *         return [jump to BLINK]
69  *     <<------
70  *     [other invalidate_dcache_all code]
71  *     [pop BLINK] (get from stack)
72  *     // we don't have this data in L1 dcache as we invalidated it in [point 3]
73  *     // so we get it from next memory level (for example DDR memory)
74  *     // but in the memory we have value which we save in [point 1], which
75  *     // is return address from flush_dcache_all function (instead of
76  *     // address from current invalidate_dcache_all function which we
77  *     // saved in [point 2] !)
78  *     return [jump to BLINK]
79  *   <<------
80  *   // As BLINK points to invalidate_dcache_all, we call it again and
81  *   // loop forever.
82  *
83  * Fortunately we may fix that by using flush & invalidation of D$ with a single
84  * one instruction (instead of flush and invalidation instructions pair) and
85  * enabling force function inline with '__attribute__((always_inline))' gcc
86  * attribute to avoid any function call (and BLINK store) between cache flush
87  * and disable.
88  *
89  *
90  * [ NOTE 2 ]:
91  * As of today we only support the following cache configurations on ARC.
92  * Other configurations may exist in HW but we don't support it in SW.
93  * Configuration 1:
94  *        ______________________
95  *       |                      |
96  *       |   ARC CPU            |
97  *       |______________________|
98  *        ___|___        ___|___
99  *       |       |      |       |
100  *       | L1 I$ |      | L1 D$ |
101  *       |_______|      |_______|
102  *        on/off         on/off
103  *        ___|______________|____
104  *       |                      |
105  *       |   main memory        |
106  *       |______________________|
107  *
108  * Configuration 2:
109  *        ______________________
110  *       |                      |
111  *       |   ARC CPU            |
112  *       |______________________|
113  *        ___|___        ___|___
114  *       |       |      |       |
115  *       | L1 I$ |      | L1 D$ |
116  *       |_______|      |_______|
117  *        on/off         on/off
118  *        ___|______________|____
119  *       |                      |
120  *       |   L2 (SL$)           |
121  *       |______________________|
122  *          always on (ARCv2, HS <  3.0)
123  *          on/off    (ARCv2, HS >= 3.0)
124  *        ___|______________|____
125  *       |                      |
126  *       |   main memory        |
127  *       |______________________|
128  *
129  * Configuration 3:
130  *        ______________________
131  *       |                      |
132  *       |   ARC CPU            |
133  *       |______________________|
134  *        ___|___        ___|___
135  *       |       |      |       |
136  *       | L1 I$ |      | L1 D$ |
137  *       |_______|      |_______|
138  *        on/off        must be on
139  *        ___|______________|____      _______
140  *       |                      |     |       |
141  *       |   L2 (SL$)           |-----|  IOC  |
142  *       |______________________|     |_______|
143  *          always must be on          on/off
144  *        ___|______________|____
145  *       |                      |
146  *       |   main memory        |
147  *       |______________________|
148  */
149
150 DECLARE_GLOBAL_DATA_PTR;
151
152 /* Bit values in IC_CTRL */
153 #define IC_CTRL_CACHE_DISABLE   BIT(0)
154
155 /* Bit values in DC_CTRL */
156 #define DC_CTRL_CACHE_DISABLE   BIT(0)
157 #define DC_CTRL_INV_MODE_FLUSH  BIT(6)
158 #define DC_CTRL_FLUSH_STATUS    BIT(8)
159
160 #define OP_INV                  BIT(0)
161 #define OP_FLUSH                BIT(1)
162 #define OP_FLUSH_N_INV          (OP_FLUSH | OP_INV)
163
164 /* Bit val in SLC_CONTROL */
165 #define SLC_CTRL_DIS            0x001
166 #define SLC_CTRL_IM             0x040
167 #define SLC_CTRL_BUSY           0x100
168 #define SLC_CTRL_RGN_OP_INV     0x200
169
170 #define CACHE_LINE_MASK         (~(gd->arch.l1_line_sz - 1))
171
172 /*
173  * We don't want to use '__always_inline' macro here as it can be redefined
174  * to simple 'inline' in some cases which breaks stuff. See [ NOTE 1 ] for more
175  * details about the reasons we need to use always_inline functions.
176  */
177 #define inlined_cachefunc        inline __attribute__((always_inline))
178
179 static inlined_cachefunc void __ic_entire_invalidate(void);
180 static inlined_cachefunc void __dc_entire_op(const int cacheop);
181 static inlined_cachefunc void __slc_entire_op(const int op);
182 static inlined_cachefunc bool ioc_enabled(void);
183
184 static inline bool pae_exists(void)
185 {
186         /* TODO: should we compare mmu version from BCR and from CONFIG? */
187 #if (CONFIG_ARC_MMU_VER >= 4)
188         union bcr_mmu_4 mmu4;
189
190         mmu4.word = read_aux_reg(ARC_AUX_MMU_BCR);
191
192         if (mmu4.fields.pae)
193                 return true;
194 #endif /* (CONFIG_ARC_MMU_VER >= 4) */
195
196         return false;
197 }
198
199 static inlined_cachefunc bool icache_exists(void)
200 {
201         union bcr_di_cache ibcr;
202
203         ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
204         return !!ibcr.fields.ver;
205 }
206
207 static inlined_cachefunc bool icache_enabled(void)
208 {
209         if (!icache_exists())
210                 return false;
211
212         return !(read_aux_reg(ARC_AUX_IC_CTRL) & IC_CTRL_CACHE_DISABLE);
213 }
214
215 static inlined_cachefunc bool dcache_exists(void)
216 {
217         union bcr_di_cache dbcr;
218
219         dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
220         return !!dbcr.fields.ver;
221 }
222
223 static inlined_cachefunc bool dcache_enabled(void)
224 {
225         if (!dcache_exists())
226                 return false;
227
228         return !(read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_CACHE_DISABLE);
229 }
230
231 static inlined_cachefunc bool slc_exists(void)
232 {
233         if (is_isa_arcv2()) {
234                 union bcr_generic sbcr;
235
236                 sbcr.word = read_aux_reg(ARC_BCR_SLC);
237                 return !!sbcr.fields.ver;
238         }
239
240         return false;
241 }
242
243 enum slc_dis_status {
244         ST_SLC_MISSING = 0,
245         ST_SLC_NO_DISABLE_CTRL,
246         ST_SLC_DISABLE_CTRL
247 };
248
249 /*
250  * ARCv1                                     -> ST_SLC_MISSING
251  * ARCv2 && SLC absent                       -> ST_SLC_MISSING
252  * ARCv2 && SLC exists && SLC version <= 2   -> ST_SLC_NO_DISABLE_CTRL
253  * ARCv2 && SLC exists && SLC version > 2    -> ST_SLC_DISABLE_CTRL
254  */
255 static inlined_cachefunc enum slc_dis_status slc_disable_supported(void)
256 {
257         if (is_isa_arcv2()) {
258                 union bcr_generic sbcr;
259
260                 sbcr.word = read_aux_reg(ARC_BCR_SLC);
261                 if (sbcr.fields.ver == 0)
262                         return ST_SLC_MISSING;
263                 else if (sbcr.fields.ver <= 2)
264                         return ST_SLC_NO_DISABLE_CTRL;
265                 else
266                         return ST_SLC_DISABLE_CTRL;
267         }
268
269         return ST_SLC_MISSING;
270 }
271
272 static inlined_cachefunc bool __slc_enabled(void)
273 {
274         return !(read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_DIS);
275 }
276
277 static inlined_cachefunc void __slc_enable(void)
278 {
279         unsigned int ctrl;
280
281         ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
282         ctrl &= ~SLC_CTRL_DIS;
283         write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
284 }
285
286 static inlined_cachefunc void __slc_disable(void)
287 {
288         unsigned int ctrl;
289
290         ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
291         ctrl |= SLC_CTRL_DIS;
292         write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
293 }
294
295 static inlined_cachefunc bool slc_enabled(void)
296 {
297         enum slc_dis_status slc_status = slc_disable_supported();
298
299         if (slc_status == ST_SLC_MISSING)
300                 return false;
301         else if (slc_status == ST_SLC_NO_DISABLE_CTRL)
302                 return true;
303         else
304                 return __slc_enabled();
305 }
306
307 static inlined_cachefunc bool slc_data_bypass(void)
308 {
309         /*
310          * If L1 data cache is disabled SL$ is bypassed and all load/store
311          * requests are sent directly to main memory.
312          */
313         return !dcache_enabled();
314 }
315
316 void slc_enable(void)
317 {
318         if (slc_disable_supported() != ST_SLC_DISABLE_CTRL)
319                 return;
320
321         if (__slc_enabled())
322                 return;
323
324         __slc_enable();
325 }
326
327 /* TODO: warn if we are not able to disable SLC */
328 void slc_disable(void)
329 {
330         if (slc_disable_supported() != ST_SLC_DISABLE_CTRL)
331                 return;
332
333         /* we don't support SLC disabling if we use IOC */
334         if (ioc_enabled())
335                 return;
336
337         if (!__slc_enabled())
338                 return;
339
340         /*
341          * We need to flush L1D$ to guarantee that we won't have any
342          * writeback operations during SLC disabling.
343          */
344         __dc_entire_op(OP_FLUSH);
345         __slc_entire_op(OP_FLUSH_N_INV);
346         __slc_disable();
347 }
348
349 static inlined_cachefunc bool ioc_exists(void)
350 {
351         if (is_isa_arcv2()) {
352                 union bcr_clust_cfg cbcr;
353
354                 cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
355                 return cbcr.fields.c;
356         }
357
358         return false;
359 }
360
361 static inlined_cachefunc bool ioc_enabled(void)
362 {
363         /*
364          * We check only CONFIG option instead of IOC HW state check as IOC
365          * must be disabled by default.
366          */
367         if (is_ioc_enabled())
368                 return ioc_exists();
369
370         return false;
371 }
372
373 static inlined_cachefunc void __slc_entire_op(const int op)
374 {
375         unsigned int ctrl;
376
377         if (!slc_enabled())
378                 return;
379
380         ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
381
382         if (!(op & OP_FLUSH))           /* i.e. OP_INV */
383                 ctrl &= ~SLC_CTRL_IM;   /* clear IM: Disable flush before Inv */
384         else
385                 ctrl |= SLC_CTRL_IM;
386
387         write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
388
389         if (op & OP_INV)        /* Inv or flush-n-inv use same cmd reg */
390                 write_aux_reg(ARC_AUX_SLC_INVALIDATE, 0x1);
391         else
392                 write_aux_reg(ARC_AUX_SLC_FLUSH, 0x1);
393
394         /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
395         read_aux_reg(ARC_AUX_SLC_CTRL);
396
397         /* Important to wait for flush to complete */
398         while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY);
399 }
400
401 static void slc_upper_region_init(void)
402 {
403         /*
404          * ARC_AUX_SLC_RGN_START1 and ARC_AUX_SLC_RGN_END1 register exist
405          * only if PAE exists in current HW. So we had to check pae_exist
406          * before using them.
407          */
408         if (!pae_exists())
409                 return;
410
411         /*
412          * ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1 are always == 0
413          * as we don't use PAE40.
414          */
415         write_aux_reg(ARC_AUX_SLC_RGN_END1, 0);
416         write_aux_reg(ARC_AUX_SLC_RGN_START1, 0);
417 }
418
419 static void __slc_rgn_op(unsigned long paddr, unsigned long sz, const int op)
420 {
421 #ifdef CONFIG_ISA_ARCV2
422
423         unsigned int ctrl;
424         unsigned long end;
425
426         if (!slc_enabled())
427                 return;
428
429         /*
430          * The Region Flush operation is specified by CTRL.RGN_OP[11..9]
431          *  - b'000 (default) is Flush,
432          *  - b'001 is Invalidate if CTRL.IM == 0
433          *  - b'001 is Flush-n-Invalidate if CTRL.IM == 1
434          */
435         ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
436
437         /* Don't rely on default value of IM bit */
438         if (!(op & OP_FLUSH))           /* i.e. OP_INV */
439                 ctrl &= ~SLC_CTRL_IM;   /* clear IM: Disable flush before Inv */
440         else
441                 ctrl |= SLC_CTRL_IM;
442
443         if (op & OP_INV)
444                 ctrl |= SLC_CTRL_RGN_OP_INV;    /* Inv or flush-n-inv */
445         else
446                 ctrl &= ~SLC_CTRL_RGN_OP_INV;
447
448         write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
449
450         /*
451          * Lower bits are ignored, no need to clip
452          * END needs to be setup before START (latter triggers the operation)
453          * END can't be same as START, so add (l2_line_sz - 1) to sz
454          */
455         end = paddr + sz + gd->arch.slc_line_sz - 1;
456
457         /*
458          * Upper addresses (ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1)
459          * are always == 0 as we don't use PAE40, so we only setup lower ones
460          * (ARC_AUX_SLC_RGN_END and ARC_AUX_SLC_RGN_START)
461          */
462         write_aux_reg(ARC_AUX_SLC_RGN_END, end);
463         write_aux_reg(ARC_AUX_SLC_RGN_START, paddr);
464
465         /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
466         read_aux_reg(ARC_AUX_SLC_CTRL);
467
468         while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY);
469
470 #endif /* CONFIG_ISA_ARCV2 */
471 }
472
473 static void arc_ioc_setup(void)
474 {
475         /* IOC Aperture start is equal to DDR start */
476         unsigned int ap_base = CONFIG_SYS_SDRAM_BASE;
477         /* IOC Aperture size is equal to DDR size */
478         long ap_size = CONFIG_SYS_SDRAM_SIZE;
479
480         /* Unsupported configuration. See [ NOTE 2 ] for more details. */
481         if (!slc_exists())
482                 panic("Try to enable IOC but SLC is not present");
483
484         if (!slc_enabled())
485                 panic("Try to enable IOC but SLC is disabled");
486
487         /* Unsupported configuration. See [ NOTE 2 ] for more details. */
488         if (!dcache_enabled())
489                 panic("Try to enable IOC but L1 D$ is disabled");
490
491         if (!is_power_of_2(ap_size) || ap_size < 4096)
492                 panic("IOC Aperture size must be power of 2 and bigger 4Kib");
493
494         /* IOC Aperture start must be aligned to the size of the aperture */
495         if (ap_base % ap_size != 0)
496                 panic("IOC Aperture start must be aligned to the size of the aperture");
497
498         flush_n_invalidate_dcache_all();
499
500         /*
501          * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB,
502          * so setting 0x11 implies 512M, 0x12 implies 1G...
503          */
504         write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE,
505                       order_base_2(ap_size / 1024) - 2);
506
507         write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12);
508         write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
509         write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
510 }
511
512 static void read_decode_cache_bcr_arcv2(void)
513 {
514 #ifdef CONFIG_ISA_ARCV2
515
516         union bcr_slc_cfg slc_cfg;
517
518         if (slc_exists()) {
519                 slc_cfg.word = read_aux_reg(ARC_AUX_SLC_CONFIG);
520                 gd->arch.slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64;
521
522                 /*
523                  * We don't support configuration where L1 I$ or L1 D$ is
524                  * absent but SL$ exists. See [ NOTE 2 ] for more details.
525                  */
526                 if (!icache_exists() || !dcache_exists())
527                         panic("Unsupported cache configuration: SLC exists but one of L1 caches is absent");
528         }
529
530 #endif /* CONFIG_ISA_ARCV2 */
531 }
532
533 void read_decode_cache_bcr(void)
534 {
535         int dc_line_sz = 0, ic_line_sz = 0;
536         union bcr_di_cache ibcr, dbcr;
537
538         /*
539          * We don't care much about I$ line length really as there're
540          * no per-line ops on I$ instead we only do full invalidation of it
541          * on occasion of relocation and right before jumping to the OS.
542          * Still we check insane config with zero-encoded line length in
543          * presense of version field in I$ BCR. Just in case.
544          */
545         ibcr.word = read_aux_reg(ARC_BCR_IC_BUILD);
546         if (ibcr.fields.ver) {
547                 ic_line_sz = 8 << ibcr.fields.line_len;
548                 if (!ic_line_sz)
549                         panic("Instruction exists but line length is 0\n");
550         }
551
552         dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD);
553         if (dbcr.fields.ver) {
554                 gd->arch.l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len;
555                 if (!dc_line_sz)
556                         panic("Data cache exists but line length is 0\n");
557         }
558 }
559
560 void cache_init(void)
561 {
562         read_decode_cache_bcr();
563
564         if (is_isa_arcv2())
565                 read_decode_cache_bcr_arcv2();
566
567         if (is_isa_arcv2() && ioc_enabled())
568                 arc_ioc_setup();
569
570         if (is_isa_arcv2() && slc_exists())
571                 slc_upper_region_init();
572 }
573
574 int icache_status(void)
575 {
576         return icache_enabled();
577 }
578
579 void icache_enable(void)
580 {
581         if (icache_exists())
582                 write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) &
583                               ~IC_CTRL_CACHE_DISABLE);
584 }
585
586 void icache_disable(void)
587 {
588         if (!icache_exists())
589                 return;
590
591         __ic_entire_invalidate();
592
593         write_aux_reg(ARC_AUX_IC_CTRL, read_aux_reg(ARC_AUX_IC_CTRL) |
594                       IC_CTRL_CACHE_DISABLE);
595 }
596
597 /* IC supports only invalidation */
598 static inlined_cachefunc void __ic_entire_invalidate(void)
599 {
600         if (!icache_enabled())
601                 return;
602
603         /* Any write to IC_IVIC register triggers invalidation of entire I$ */
604         write_aux_reg(ARC_AUX_IC_IVIC, 1);
605         /*
606          * As per ARC HS databook (see chapter 5.3.3.2)
607          * it is required to add 3 NOPs after each write to IC_IVIC.
608          */
609         __builtin_arc_nop();
610         __builtin_arc_nop();
611         __builtin_arc_nop();
612         read_aux_reg(ARC_AUX_IC_CTRL);  /* blocks */
613 }
614
615 void invalidate_icache_all(void)
616 {
617         __ic_entire_invalidate();
618
619         /*
620          * If SL$ is bypassed for data it is used only for instructions,
621          * so we need to invalidate it too.
622          */
623         if (is_isa_arcv2() && slc_data_bypass())
624                 __slc_entire_op(OP_INV);
625 }
626
627 int dcache_status(void)
628 {
629         return dcache_enabled();
630 }
631
632 void dcache_enable(void)
633 {
634         if (!dcache_exists())
635                 return;
636
637         write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) &
638                       ~(DC_CTRL_INV_MODE_FLUSH | DC_CTRL_CACHE_DISABLE));
639 }
640
641 void dcache_disable(void)
642 {
643         if (!dcache_exists())
644                 return;
645
646         __dc_entire_op(OP_FLUSH_N_INV);
647
648         /*
649          * As SLC will be bypassed for data after L1 D$ disable we need to
650          * flush it first before L1 D$ disable. Also we invalidate SLC to
651          * avoid any inconsistent data problems after enabling L1 D$ again with
652          * dcache_enable function.
653          */
654         if (is_isa_arcv2())
655                 __slc_entire_op(OP_FLUSH_N_INV);
656
657         write_aux_reg(ARC_AUX_DC_CTRL, read_aux_reg(ARC_AUX_DC_CTRL) |
658                       DC_CTRL_CACHE_DISABLE);
659 }
660
661 /* Common Helper for Line Operations on D-cache */
662 static inline void __dcache_line_loop(unsigned long paddr, unsigned long sz,
663                                       const int cacheop)
664 {
665         unsigned int aux_cmd;
666         int num_lines;
667
668         /* d$ cmd: INV (discard or wback-n-discard) OR FLUSH (wback) */
669         aux_cmd = cacheop & OP_INV ? ARC_AUX_DC_IVDL : ARC_AUX_DC_FLDL;
670
671         sz += paddr & ~CACHE_LINE_MASK;
672         paddr &= CACHE_LINE_MASK;
673
674         num_lines = DIV_ROUND_UP(sz, gd->arch.l1_line_sz);
675
676         while (num_lines-- > 0) {
677 #if (CONFIG_ARC_MMU_VER == 3)
678                 write_aux_reg(ARC_AUX_DC_PTAG, paddr);
679 #endif
680                 write_aux_reg(aux_cmd, paddr);
681                 paddr += gd->arch.l1_line_sz;
682         }
683 }
684
685 static inlined_cachefunc void __before_dc_op(const int op)
686 {
687         unsigned int ctrl;
688
689         ctrl = read_aux_reg(ARC_AUX_DC_CTRL);
690
691         /* IM bit implies flush-n-inv, instead of vanilla inv */
692         if (op == OP_INV)
693                 ctrl &= ~DC_CTRL_INV_MODE_FLUSH;
694         else
695                 ctrl |= DC_CTRL_INV_MODE_FLUSH;
696
697         write_aux_reg(ARC_AUX_DC_CTRL, ctrl);
698 }
699
700 static inlined_cachefunc void __after_dc_op(const int op)
701 {
702         if (op & OP_FLUSH)      /* flush / flush-n-inv both wait */
703                 while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS);
704 }
705
706 static inlined_cachefunc void __dc_entire_op(const int cacheop)
707 {
708         int aux;
709
710         if (!dcache_enabled())
711                 return;
712
713         __before_dc_op(cacheop);
714
715         if (cacheop & OP_INV)   /* Inv or flush-n-inv use same cmd reg */
716                 aux = ARC_AUX_DC_IVDC;
717         else
718                 aux = ARC_AUX_DC_FLSH;
719
720         write_aux_reg(aux, 0x1);
721
722         __after_dc_op(cacheop);
723 }
724
725 static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
726                                 const int cacheop)
727 {
728         if (!dcache_enabled())
729                 return;
730
731         __before_dc_op(cacheop);
732         __dcache_line_loop(paddr, sz, cacheop);
733         __after_dc_op(cacheop);
734 }
735
736 void invalidate_dcache_range(unsigned long start, unsigned long end)
737 {
738         if (start >= end)
739                 return;
740
741         /*
742          * ARCv1                                 -> call __dc_line_op
743          * ARCv2 && L1 D$ disabled               -> nothing
744          * ARCv2 && L1 D$ enabled && IOC enabled -> nothing
745          * ARCv2 && L1 D$ enabled && no IOC      -> call __dc_line_op; call __slc_rgn_op
746          */
747         if (!is_isa_arcv2() || !ioc_enabled())
748                 __dc_line_op(start, end - start, OP_INV);
749
750         if (is_isa_arcv2() && !ioc_enabled() && !slc_data_bypass())
751                 __slc_rgn_op(start, end - start, OP_INV);
752 }
753
754 void flush_dcache_range(unsigned long start, unsigned long end)
755 {
756         if (start >= end)
757                 return;
758
759         /*
760          * ARCv1                                 -> call __dc_line_op
761          * ARCv2 && L1 D$ disabled               -> nothing
762          * ARCv2 && L1 D$ enabled && IOC enabled -> nothing
763          * ARCv2 && L1 D$ enabled && no IOC      -> call __dc_line_op; call __slc_rgn_op
764          */
765         if (!is_isa_arcv2() || !ioc_enabled())
766                 __dc_line_op(start, end - start, OP_FLUSH);
767
768         if (is_isa_arcv2() && !ioc_enabled() && !slc_data_bypass())
769                 __slc_rgn_op(start, end - start, OP_FLUSH);
770 }
771
772 void flush_cache(unsigned long start, unsigned long size)
773 {
774         flush_dcache_range(start, start + size);
775 }
776
777 /*
778  * As invalidate_dcache_all() is not used in generic U-Boot code and as we
779  * don't need it in arch/arc code alone (invalidate without flush) we implement
780  * flush_n_invalidate_dcache_all (flush and invalidate in 1 operation) because
781  * it's much safer. See [ NOTE 1 ] for more details.
782  */
783 void flush_n_invalidate_dcache_all(void)
784 {
785         __dc_entire_op(OP_FLUSH_N_INV);
786
787         if (is_isa_arcv2() && !slc_data_bypass())
788                 __slc_entire_op(OP_FLUSH_N_INV);
789 }
790
791 void flush_dcache_all(void)
792 {
793         __dc_entire_op(OP_FLUSH);
794
795         if (is_isa_arcv2() && !slc_data_bypass())
796                 __slc_entire_op(OP_FLUSH);
797 }
798
799 /*
800  * This is function to cleanup all caches (and therefore sync I/D caches) which
801  * can be used for cleanup before linux launch or to sync caches during
802  * relocation.
803  */
804 void sync_n_cleanup_cache_all(void)
805 {
806         __dc_entire_op(OP_FLUSH_N_INV);
807
808         /*
809          * If SL$ is bypassed for data it is used only for instructions,
810          * and we shouldn't flush it. So invalidate it instead of flush_n_inv.
811          */
812         if (is_isa_arcv2()) {
813                 if (slc_data_bypass())
814                         __slc_entire_op(OP_INV);
815                 else
816                         __slc_entire_op(OP_FLUSH_N_INV);
817         }
818
819         __ic_entire_invalidate();
820 }