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 enter_user_mode(void) 91 { 92 asm volatile( 93 "mfc0 $t3, $12\n" /* CP0_STATUS */ 94 "li $t4, 0xffffffef\n" /* KSU = 2 (UM = 1) */ 95 "and $t3, $t3, $t4\n" 96 "mtc0 $t3, $12\n" 97 "nop\n"); 98 } 99 100 void enable_interrupts(void) 101 { 102 asm volatile( 103 "mfc0 $t3, $12\n" /* CP0_STATUS */ 104 "li $t4, 0x0000fc01\n" /* IE = enable interrupts */ 105 "or $t3, $t3, $t4\n" 106 "mtc0 $t3, $12\n" 107 "nop\n"); 108 } 109 110 void init_interrupts(void) 111 { 112 /* Set exception registers. */ 113 114 asm volatile( 115 "mtc0 $zero, $18\n" /* CP0_WATCHLO */ 116 "li $t3, 0x00800000\n" /* IV = 1 (use 0x80000200 for interrupts) */ 117 "mtc0 $t3, $13\n" /* CP0_CAUSE */ 118 "mfc0 $t4, $12\n" /* CP0_STATUS */ 119 "li $t3, 0xffbfffff\n" /* BEV=0 */ 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 $t0, 0x01ffe000\n" /* 16MB */ 129 "mtc0 $t0, $5\n" /* CP0_PAGEMASK */ 130 "li $t1, 1\n" /* index of first randomly-replaced entry */ 131 "mtc0 $t1, $6\n" /* CP0_WIRED */ 132 133 /* 0x80000000..0x82000000 -> 0x00000000..0x02000000 */ 134 135 "mtc0 $zero, $0\n" /* CP0_INDEX */ 136 137 /* Set physical address. */ 138 139 "li $t0, 0x0000001f\n" /* 0x00000000, C=3, dirty, global, valid */ 140 "mtc0 $t0, $2\n" /* CP0_ENTRYLO0 */ 141 "li $t1, 0x0004001f\n" /* 0x01000000, C=3, dirty, global, valid */ 142 "mtc0 $t1, $3\n" /* CP0_ENTRYLO1 */ 143 144 /* Set virtual address. */ 145 146 "li $t0, 0x80000000\n" /* 0x80000000, ASID=0 */ 147 "mtc0 $t0, $10\n" /* CP0_ENTRYHI */ 148 "nop\n" 149 150 "tlbwi\n" 151 "nop\n"); 152 } 153 154 void map_page(u32 virtual, u32 physical, u32 pagesize) 155 { 156 u32 start = virtual & 0xffffe000; /* VPN2 */ 157 u32 flags = 0x1f; /* C=3, dirty, global, valid */ 158 u32 lower = ((physical & 0xfffff000) >> 6) | flags; 159 u32 upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags; 160 u32 pagemask = ((pagesize - 1) & 0xfffff000) << 1; 161 162 asm volatile( 163 "mtc0 %3, $5\n" /* CP0_PAGEMASK */ 164 165 /* Set physical address. */ 166 167 "mtc0 %0, $2\n" /* CP0_ENTRYLO0 */ 168 "mtc0 %1, $3\n" /* CP0_ENTRYLO1 */ 169 170 /* Set virtual address. */ 171 172 "mtc0 %2, $10\n" /* CP0_ENTRYHI */ 173 "nop\n" 174 175 "tlbwr\n" 176 "nop" 177 : 178 : "r" (lower), "r" (upper), "r" (start), "r" (pagemask) 179 ); 180 } 181 182 void tlb_handle(void) 183 { 184 u32 context, virtual; 185 186 /* Obtain the bad virtual address. */ 187 188 asm volatile( 189 "mfc0 %0, $4\n" /* CP0_CONTEXT */ 190 : "=r" (context) 191 ); 192 193 /* Obtain a virtual address region with 8KB resolution. */ 194 195 virtual = (context & 0x007ffff0) << 9; 196 197 /* Request a physical region mapping two 4KB pages. */ 198 199 map_page(virtual, virtual, 4 * 1024); 200 }