1 /*
2 * File : cache.c
3 * This file is part of RT-Thread RTOS
4 * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Change Logs:
21 * Date Author Notes
22 * 2016/11/02 Urey the first version
23 */
24
25 #include <rtthread.h>
26 #include <board.h>
27 #include <rthw.h>
28
29 #include "../common/mips.h"
30
31
32 #define CONFIG_SYS_DCACHE_SIZE 16384
33 #define CONFIG_SYS_ICACHE_SIZE 16384
34 #define CONFIG_SYS_CACHELINE_SIZE 32
35
36 #define K0_TO_K1() \
37 do { \
38 unsigned long __k0_addr; \
39 \
40 __asm__ __volatile__( \
41 "la %0, 1f\n\t" \
42 "or %0, %0, %1\n\t" \
43 "jr %0\n\t" \
44 "nop\n\t" \
45 "1: nop\n" \
46 : "=&r"(__k0_addr) \
47 : "r" (0x20000000) ); \
48 } while(0)
49
50 #define K1_TO_K0() \
51 do { \
52 unsigned long __k0_addr; \
53 __asm__ __volatile__( \
54 "nop;nop;nop;nop;nop;nop;nop\n\t" \
55 "la %0, 1f\n\t" \
56 "jr %0\n\t" \
57 "nop\n\t" \
58 "1: nop\n" \
59 : "=&r" (__k0_addr)); \
60 } while (0)
61
62 #define INVALIDATE_BTB() \
63 do { \
64 unsigned long tmp; \
65 __asm__ __volatile__( \
66 ".set mips32\n\t" \
67 "mfc0 %0, $16, 7\n\t" \
68 "nop\n\t" \
69 "ori %0, 2\n\t" \
70 "mtc0 %0, $16, 7\n\t" \
71 "nop\n\t" \
72 ".set mips2\n\t" \
73 : "=&r" (tmp)); \
74 } while (0)
75
76 #define __sync() \
77 __asm__ __volatile__( \
78 ".set push\n\t" \
79 ".set noreorder\n\t" \
80 ".set mips2\n\t" \
81 "sync\n\t" \
82 ".set pop" \
83 : /* no output */ \
84 : /* no input */ \
85 : "memory")
86
87 #if defined(JZ4775) || defined(X1000)
88 #define SYNC_WB() \
89 do { \
90 __asm__ __volatile__ ( \
91 "sync\n\t" \
92 "lw $0, %0\n\t" \
93 : \
94 :"m"(*(int *)0xa0000000) \
95 :"memory"); \
96 } while (0)
97 #else
98 #error "not define sync wb"
99 #define SYNC_WB() __asm__ __volatile__ ("sync")
100 #endif
101
102
103 #undef cache_op
104 #define cache_op(op, addr) \
105 __asm__ __volatile__( \
106 ".set push\n" \
107 ".set noreorder\n" \
108 ".set mips3\n" \
109 "cache %0, %1\n" \
110 ".set pop\n" \
111 : \
112 : "i" (op), "R" (*(unsigned char *)(addr)))
113
114
rt_hw_dcache_flush_line(rt_uint32_t addr)115 void rt_hw_dcache_flush_line(rt_uint32_t addr)
116 {
117 cache_op(HIT_WRITEBACK_INV_D, addr);
118 SYNC_WB();
119 }
120
rt_hw_dcache_flush_range(rt_uint32_t start_addr,rt_uint32_t size)121 void rt_hw_dcache_flush_range(rt_uint32_t start_addr, rt_uint32_t size)
122 {
123 rt_uint32_t lsize = CONFIG_SYS_CACHELINE_SIZE;
124 rt_uint32_t addr = start_addr & ~(lsize - 1);
125 rt_uint32_t aend = (start_addr + size - 1) & ~(lsize - 1);
126 rt_uint32_t writebuffer;
127
128 for (; addr <= aend; addr += lsize)
129 {
130 cache_op(HIT_WRITEBACK_INV_D, addr);
131 }
132 SYNC_WB();
133 }
134
rt_hw_dcache_flush_all(void)135 void rt_hw_dcache_flush_all(void)
136 {
137 rt_uint32_t addr;
138
139 for (addr = CKSEG0; addr < CKSEG0 + CONFIG_SYS_DCACHE_SIZE; addr += CONFIG_SYS_CACHELINE_SIZE)
140 {
141 cache_op(INDEX_WRITEBACK_INV_D, addr);
142 }
143
144 SYNC_WB();
145 }
146
rt_hw_dcache_invalidate_range(rt_uint32_t start_addr,rt_uint32_t size)147 void rt_hw_dcache_invalidate_range(rt_uint32_t start_addr,rt_uint32_t size)
148 {
149 rt_uint32_t lsize = CONFIG_SYS_CACHELINE_SIZE;
150 rt_uint32_t addr = start_addr & ~(lsize - 1);
151 rt_uint32_t aend = (start_addr + size - 1) & ~(lsize - 1);
152
153 for (; addr <= aend; addr += lsize)
154 cache_op(HIT_INVALIDATE_D, addr);
155 }
156
rt_hw_dcache_invalidate_all(void)157 void rt_hw_dcache_invalidate_all(void)
158 {
159 rt_uint32_t addr;
160
161 for (addr = CKSEG0; addr < CKSEG0 + CONFIG_SYS_DCACHE_SIZE; addr += CONFIG_SYS_CACHELINE_SIZE)
162 {
163 cache_op(INDEX_STORE_TAG_D, addr);
164 }
165
166 SYNC_WB();
167 }
168
rt_hw_icache_flush_line(rt_uint32_t addr)169 void rt_hw_icache_flush_line(rt_uint32_t addr)
170 {
171 cache_op(HIT_INVALIDATE_I, addr);
172 }
173
rt_hw_icache_flush_all(void)174 void rt_hw_icache_flush_all(void)
175 {
176 rt_uint32_t addr;
177
178 asm volatile ("mtc0 $0, $28"); /* Clear Taglo */
179 asm volatile ("mtc0 $0, $29"); /* Clear TagHi */
180
181 for (addr = CKSEG0; addr < CKSEG0 + CONFIG_SYS_DCACHE_SIZE; addr += CONFIG_SYS_CACHELINE_SIZE)
182 {
183 cache_op(INDEX_STORE_TAG_I, addr);
184 }
185
186 INVALIDATE_BTB();
187 }
188
rt_hw_icache_invalidate_all(void)189 void rt_hw_icache_invalidate_all(void)
190 {
191 rt_uint32_t i;
192
193 K0_TO_K1();
194
195 asm volatile (".set noreorder\n"
196 ".set mips32\n\t"
197 "mtc0\t$0,$28\n\t"
198 "mtc0\t$0,$29\n"
199 ".set mips0\n"
200 ".set reorder\n");
201 for (i = CKSEG0; i < CKSEG0 + CONFIG_SYS_ICACHE_SIZE; i += CONFIG_SYS_CACHELINE_SIZE)
202 cache_op(INDEX_STORE_TAG_I, i);
203
204 K1_TO_K0();
205
206 INVALIDATE_BTB();
207 }
208
209
rt_hw_flush_cache_all(void)210 void rt_hw_flush_cache_all(void)
211 {
212 rt_hw_dcache_flush_all();
213 rt_hw_icache_flush_all();
214 }
215
216
217
218