]> git.ipfire.org Git - people/ms/u-boot.git/blob - arch/mips/lib/cache.c
fbaafee8cdeaac121e728ea886311ad409c1f1ef
[people/ms/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 #ifndef CONFIG_SYS_CACHE_SIZE_AUTO
13
14 static inline unsigned long icache_line_size(void)
15 {
16 return CONFIG_SYS_CACHELINE_SIZE;
17 }
18
19 static inline unsigned long dcache_line_size(void)
20 {
21 return CONFIG_SYS_CACHELINE_SIZE;
22 }
23
24 #else /* !CONFIG_SYS_CACHELINE_SIZE */
25
26 static inline unsigned long icache_line_size(void)
27 {
28 unsigned long conf1, il;
29 conf1 = read_c0_config1();
30 il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
31 if (!il)
32 return 0;
33 return 2 << il;
34 }
35
36 static inline unsigned long dcache_line_size(void)
37 {
38 unsigned long conf1, dl;
39 conf1 = read_c0_config1();
40 dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
41 if (!dl)
42 return 0;
43 return 2 << dl;
44 }
45
46 #endif /* !CONFIG_SYS_CACHELINE_SIZE */
47
48 void flush_cache(ulong start_addr, ulong size)
49 {
50 unsigned long ilsize = icache_line_size();
51 unsigned long dlsize = dcache_line_size();
52 const void *addr, *aend;
53
54 /* aend will be miscalculated when size is zero, so we return here */
55 if (size == 0)
56 return;
57
58 addr = (const void *)(start_addr & ~(dlsize - 1));
59 aend = (const void *)((start_addr + size - 1) & ~(dlsize - 1));
60
61 if (ilsize == dlsize) {
62 /* flush I-cache & D-cache simultaneously */
63 while (1) {
64 mips_cache(HIT_WRITEBACK_INV_D, addr);
65 mips_cache(HIT_INVALIDATE_I, addr);
66 if (addr == aend)
67 break;
68 addr += dlsize;
69 }
70 return;
71 }
72
73 /* flush D-cache */
74 while (1) {
75 mips_cache(HIT_WRITEBACK_INV_D, addr);
76 if (addr == aend)
77 break;
78 addr += dlsize;
79 }
80
81 /* flush I-cache */
82 addr = (const void *)(start_addr & ~(ilsize - 1));
83 aend = (const void *)((start_addr + size - 1) & ~(ilsize - 1));
84 while (1) {
85 mips_cache(HIT_INVALIDATE_I, addr);
86 if (addr == aend)
87 break;
88 addr += ilsize;
89 }
90 }
91
92 void flush_dcache_range(ulong start_addr, ulong stop)
93 {
94 unsigned long lsize = dcache_line_size();
95 const void *addr = (const void *)(start_addr & ~(lsize - 1));
96 const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
97
98 /* aend will be miscalculated when size is zero, so we return here */
99 if (start_addr == stop)
100 return;
101
102 while (1) {
103 mips_cache(HIT_WRITEBACK_INV_D, addr);
104 if (addr == aend)
105 break;
106 addr += lsize;
107 }
108 }
109
110 void invalidate_dcache_range(ulong start_addr, ulong stop)
111 {
112 unsigned long lsize = dcache_line_size();
113 const void *addr = (const void *)(start_addr & ~(lsize - 1));
114 const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
115
116 /* aend will be miscalculated when size is zero, so we return here */
117 if (start_addr == stop)
118 return;
119
120 while (1) {
121 mips_cache(HIT_INVALIDATE_D, addr);
122 if (addr == aend)
123 break;
124 addr += lsize;
125 }
126 }