1 /* 2 * CPU-specific routines originally from U-Boot. 3 * See: uboot-xburst/files/arch/mips/cpu/xburst/cpu.c 4 * See: u-boot/arch/mips/include/asm/cacheops.h 5 * 6 * Copyright (C) 2000-2009 Wolfgang Denk, DENX Software Engineering, <wd@denx.de> 7 * Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of 12 * the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301, USA 23 */ 24 25 #include "cpu.h" 26 #include "sdram.h" 27 28 void flush_icache_all(void) 29 { 30 u32 addr, t = 0; 31 32 asm volatile ("mtc0 $0, $28"); /* Clear Taglo */ 33 asm volatile ("mtc0 $0, $29"); /* Clear TagHi */ 34 35 for (addr = KSEG0; addr < KSEG0 + CONFIG_SYS_ICACHE_SIZE; 36 addr += CONFIG_SYS_CACHELINE_SIZE) { 37 asm volatile ( 38 ".set mips3\n\t" 39 " cache %0, 0(%1)\n\t" 40 ".set mips2\n\t" 41 : 42 : "I" (Index_Store_Tag_I), "r"(addr)); 43 } 44 45 /* invalicate btb */ 46 asm volatile ( 47 ".set mips32\n\t" 48 "mfc0 %0, $16, 7\n\t" 49 "nop\n\t" 50 "ori %0,2\n\t" 51 "mtc0 %0, $16, 7\n\t" 52 ".set mips2\n\t" 53 : 54 : "r" (t)); 55 } 56 57 void flush_dcache_all(void) 58 { 59 u32 addr; 60 61 for (addr = KSEG0; addr < KSEG0 + CONFIG_SYS_DCACHE_SIZE; 62 addr += CONFIG_SYS_CACHELINE_SIZE) { 63 asm volatile ( 64 ".set mips3\n\t" 65 " cache %0, 0(%1)\n\t" 66 ".set mips2\n\t" 67 : 68 : "I" (Index_Writeback_Inv_D), "r"(addr)); 69 } 70 71 asm volatile ("sync"); 72 } 73 74 void flush_cache_all(void) 75 { 76 flush_dcache_all(); 77 flush_icache_all(); 78 } 79 80 void handle_error_level(void) 81 { 82 asm volatile( 83 "mfc0 $t3, $12\n" /* CP0_STATUS */ 84 "li $t4, 0xfffffffb\n" /* ERL = 0 */ 85 "and $t3, $t3, $t4\n" 86 "mtc0 $t3, $12\n" 87 "nop\n"); 88 } 89 90 void enable_interrupts(void) 91 { 92 asm volatile( 93 "mfc0 $t3, $12\n" /* CP0_STATUS */ 94 "li $t4, 0x0000fc01\n" /* IE = enable interrupts */ 95 "or $t3, $t3, $t4\n" 96 "mtc0 $t3, $12\n" 97 "nop\n"); 98 } 99 100 void init_interrupts(void) 101 { 102 /* Set exception registers. */ 103 104 asm volatile( 105 "mtc0 $zero, $18\n" /* CP0_WATCHLO */ 106 "li $t3, 0x00800000\n" /* IV = 1 (use 0x80000200 for interrupts) */ 107 "mtc0 $t3, $13\n" /* CP0_CAUSE */ 108 "mfc0 $t4, $12\n" /* CP0_STATUS */ 109 "li $t3, 0xffbfffff\n" /* BEV=0 */ 110 "and $t3, $t3, $t4\n" 111 "mtc0 $t3, $12\n" 112 "nop\n"); 113 } 114 115 void enter_user_mode(void) 116 { 117 asm volatile( 118 "mfc0 $t3, $12\n" /* CP0_STATUS */ 119 "li $t4, 0xffffffef\n" /* KSU = 2 (UM = 1) */ 120 "and $t3, $t3, $t4\n" 121 "mtc0 $t3, $12\n" 122 "nop\n"); 123 } 124 125 void init_tlb(void) 126 { 127 asm volatile( 128 "li $t1, 1\n" /* index of first randomly-replaced entry */ 129 "mtc0 $t1, $6\n" /* CP0_WIRED */ 130 "nop\n"); 131 132 map_page_index(0x80000000, 0x00000000, 16 * 1024 * 1024, 0x1f, 0, 0); 133 } 134 135 void map_page_index(u32 virtual, u32 physical, u32 pagesize, u8 flags, u8 asid, u32 index) 136 { 137 u32 start = virtual & 0xffffe000; /* VPN2 */ 138 u32 lower = ((physical & 0xfffff000) >> 6) | flags; 139 u32 upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags; 140 u32 pagemask = ((pagesize - 1) & 0xfffff000) << 1; 141 142 asm volatile( 143 "mtc0 %3, $5\n" /* CP0_PAGEMASK */ 144 145 /* Set the index. */ 146 147 "mtc0 %4, $0\n" /* CP0_INDEX */ 148 149 /* Set physical address. */ 150 151 "mtc0 %0, $2\n" /* CP0_ENTRYLO0 */ 152 "mtc0 %1, $3\n" /* CP0_ENTRYLO1 */ 153 154 /* Set virtual address. */ 155 156 "mtc0 %2, $10\n" /* CP0_ENTRYHI */ 157 "nop\n" 158 159 "tlbwi\n" 160 "nop" 161 : 162 : "r" (lower), "r" (upper), "r" (start), "r" (pagemask), "r" (index) 163 ); 164 } 165 166 void map_page(u32 virtual, u32 physical, u32 pagesize, u8 flags, u8 asid) 167 { 168 u32 start = virtual & 0xffffe000; /* VPN2 */ 169 u32 lower = ((physical & 0xfffff000) >> 6) | flags; 170 u32 upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags; 171 u32 pagemask = ((pagesize - 1) & 0xfffff000) << 1; 172 173 asm volatile( 174 "mtc0 %3, $5\n" /* CP0_PAGEMASK */ 175 176 /* Set physical address. */ 177 178 "mtc0 %0, $2\n" /* CP0_ENTRYLO0 */ 179 "mtc0 %1, $3\n" /* CP0_ENTRYLO1 */ 180 181 /* Set virtual address. */ 182 183 "mtc0 %2, $10\n" /* CP0_ENTRYHI */ 184 "nop\n" 185 186 "tlbwr\n" 187 "nop" 188 : 189 : "r" (lower), "r" (upper), "r" (start), "r" (pagemask) 190 ); 191 } 192 193 void unmap_page(u32 virtual, u32 physical, u32 pagesize, u8 flags, u8 asid) 194 { 195 u32 start = virtual & 0xffffe000; /* VPN2 */ 196 u32 lower = ((physical & 0xfffff000) >> 6) | flags; 197 u32 upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags; 198 u32 pagemask = ((pagesize - 1) & 0xfffff000) << 1; 199 u32 index = 0; 200 201 asm volatile( 202 "mtc0 %4, $5\n" /* CP0_PAGEMASK */ 203 204 /* Set physical address. */ 205 206 "mtc0 %1, $2\n" /* CP0_ENTRYLO0 */ 207 "mtc0 %2, $3\n" /* CP0_ENTRYLO1 */ 208 209 /* Set virtual address. */ 210 211 "mtc0 %3, $10\n" /* CP0_ENTRYHI */ 212 "nop\n" 213 214 /* Find an existing mapping. */ 215 216 "tlbp\n" 217 "nop\n" 218 219 /* Read the index register to see if a match was found. */ 220 221 "mfc0 %0, $0\n" /* CP0_INDEX */ 222 "nop" 223 : "=r" (index) 224 : "r" (lower), "r" (upper), "r" (start), "r" (pagemask) 225 ); 226 227 /* Return if the page is not mapped. */ 228 229 if (index & 0x80000000) 230 return; 231 232 /* Otherwise, invalidate the mapping. */ 233 234 map_page_index(virtual, physical, pagesize, flags & 0xfd, asid, index); 235 }