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 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 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 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 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 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 169 void rt_hw_icache_flush_line(rt_uint32_t addr) 170 { 171 cache_op(HIT_INVALIDATE_I, addr); 172 } 173 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 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 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