MIPS: Split I & D cache line size config
[platform/kernel/u-boot.git] / arch / mips / lib / cache.c
1 /*
2  * (C) Copyright 2003
3  * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <common.h>
9 #include <asm/cacheops.h>
10 #include <asm/mipsregs.h>
11
12 static inline unsigned long icache_line_size(void)
13 {
14         unsigned long conf1, il;
15
16         if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
17                 return CONFIG_SYS_ICACHE_LINE_SIZE;
18
19         conf1 = read_c0_config1();
20         il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
21         if (!il)
22                 return 0;
23         return 2 << il;
24 }
25
26 static inline unsigned long dcache_line_size(void)
27 {
28         unsigned long conf1, dl;
29
30         if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
31                 return CONFIG_SYS_DCACHE_LINE_SIZE;
32
33         conf1 = read_c0_config1();
34         dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
35         if (!dl)
36                 return 0;
37         return 2 << dl;
38 }
39
40 void flush_cache(ulong start_addr, ulong size)
41 {
42         unsigned long ilsize = icache_line_size();
43         unsigned long dlsize = dcache_line_size();
44         const void *addr, *aend;
45
46         /* aend will be miscalculated when size is zero, so we return here */
47         if (size == 0)
48                 return;
49
50         addr = (const void *)(start_addr & ~(dlsize - 1));
51         aend = (const void *)((start_addr + size - 1) & ~(dlsize - 1));
52
53         if (ilsize == dlsize) {
54                 /* flush I-cache & D-cache simultaneously */
55                 while (1) {
56                         mips_cache(HIT_WRITEBACK_INV_D, addr);
57                         mips_cache(HIT_INVALIDATE_I, addr);
58                         if (addr == aend)
59                                 break;
60                         addr += dlsize;
61                 }
62                 return;
63         }
64
65         /* flush D-cache */
66         while (1) {
67                 mips_cache(HIT_WRITEBACK_INV_D, addr);
68                 if (addr == aend)
69                         break;
70                 addr += dlsize;
71         }
72
73         /* flush I-cache */
74         addr = (const void *)(start_addr & ~(ilsize - 1));
75         aend = (const void *)((start_addr + size - 1) & ~(ilsize - 1));
76         while (1) {
77                 mips_cache(HIT_INVALIDATE_I, addr);
78                 if (addr == aend)
79                         break;
80                 addr += ilsize;
81         }
82 }
83
84 void flush_dcache_range(ulong start_addr, ulong stop)
85 {
86         unsigned long lsize = dcache_line_size();
87         const void *addr = (const void *)(start_addr & ~(lsize - 1));
88         const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
89
90         /* aend will be miscalculated when size is zero, so we return here */
91         if (start_addr == stop)
92                 return;
93
94         while (1) {
95                 mips_cache(HIT_WRITEBACK_INV_D, addr);
96                 if (addr == aend)
97                         break;
98                 addr += lsize;
99         }
100 }
101
102 void invalidate_dcache_range(ulong start_addr, ulong stop)
103 {
104         unsigned long lsize = dcache_line_size();
105         const void *addr = (const void *)(start_addr & ~(lsize - 1));
106         const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
107
108         /* aend will be miscalculated when size is zero, so we return here */
109         if (start_addr == stop)
110                 return;
111
112         while (1) {
113                 mips_cache(HIT_INVALIDATE_D, addr);
114                 if (addr == aend)
115                         break;
116                 addr += lsize;
117         }
118 }