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, 2017 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 "cpu_op.h" 27 #include "memory.h" 28 #include "paging.h" 29 #include "sdram.h" 30 31 void flush_icache_all() 32 { 33 uint32_t addr; 34 35 flush_icache_tag(); 36 37 for (addr = KSEG0; addr < KSEG0 + CONFIG_SYS_ICACHE_SIZE; addr += CONFIG_SYS_CACHELINE_SIZE) 38 flush_icache_region(addr); 39 40 flush_icache_config(); 41 } 42 43 void flush_dcache_all() 44 { 45 uint32_t addr; 46 47 for (addr = KSEG0; addr < KSEG0 + CONFIG_SYS_DCACHE_SIZE; addr += CONFIG_SYS_CACHELINE_SIZE) 48 flush_dcache_region(addr); 49 50 asm volatile ("sync"); 51 } 52 53 void flush_cache_all() 54 { 55 flush_dcache_all(); 56 flush_icache_all(); 57 } 58 59 void init_registers(uint32_t *base, uint32_t got, void (*function)(), uint32_t args[], uint8_t nargs) 60 { 61 uint8_t i; 62 63 /* Provide arguments to the function. */ 64 65 for (i = 0; i < nargs; i++) 66 { 67 base[i+4] = args[i]; 68 } 69 70 /* Store essential data for the function environment. */ 71 72 base[25] = (uint32_t) function - 0x80000000; /* store the function address as t9 */ 73 base[26] = got - 0x80000000; /* store the global pointer */ 74 base[29] = (uint32_t) function - 0x80000000; /* store the function address as EPC (for the handler) */ 75 } 76 77 void init_tlb(uint8_t first_random) 78 { 79 uint32_t limit = configure_tlb(first_random), i; 80 81 /* Reset the mappings. The total number is bits 30..25 of Config1. */ 82 83 for (i = 0; i < ((limit >> 25) & 0x3f); i++) 84 { 85 map_page_index(0, 0, 4096, 0, 0, i); 86 } 87 } 88 89 void init_page_table(uint32_t page_table, uint32_t virtual, uint32_t physical, uint32_t pagesize, uint8_t flags, uint8_t asid) 90 { 91 uint32_t lower = ((physical & 0xfffff000) >> 6) | flags; 92 uint32_t upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags; 93 94 /* 95 With a complete address space mapping involving pairs of 4KB pages 96 described by two values for each entry, there would be... 97 98 an address space of 0x100000000 requiring... 99 100 0x100000000 / (8 * 1024) == 0x100000000 >> 13 101 == 524288 entries 102 == 0x80000 entries 103 104 Thus, each task's entries would require... 105 106 0x80000 * 8 == 0x400000 bytes 107 108 The kseg2 region thus permits 256 tasks occupying 0x40000000 bytes. 109 110 However, for more modest address spaces occupying as much as 32MB there 111 would be... 112 113 an address space of 0x02000000 requiring... 114 115 0x02000000 / (8 * 1024) == 0x02000000 >> 13 116 == 4096 entries 117 == 0x1000 entries 118 119 Thus, each task's entries would only require... 120 121 0x1000 * 8 == 0x8000 bytes 122 */ 123 124 uint32_t base = page_table + STAGE2_PAGE_TABLE_TASK * asid; 125 126 /* Each page table entry corresponds to a pair of 4KB pages and holds two values. */ 127 128 uint32_t entry = ((virtual & 0xffffe000) >> 13) * 8; 129 uint32_t *address = (uint32_t *) (base + entry); 130 131 /* The page tables should be permanently mapped to avoid hierarchical TLB miss handling. */ 132 133 *address = lower; 134 *(address + 1) = upper; 135 } 136 137 void map_page(uint32_t virtual, uint32_t physical, uint32_t pagesize, uint8_t flags, uint8_t asid) 138 { 139 uint32_t start = (virtual & 0xffffe000) | asid; /* VPN2 | ASID*/ 140 uint32_t lower = ((physical & 0xfffff000) >> 6) | flags; 141 uint32_t upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags; 142 uint32_t pagemask = ((pagesize - 1) & 0xfffff000) << 1; 143 144 map_page_op(lower, upper, start, pagemask); 145 } 146 147 void map_page_index(uint32_t virtual, uint32_t physical, uint32_t pagesize, uint8_t flags, uint8_t asid, uint32_t index) 148 { 149 uint32_t start = (virtual & 0xffffe000) | asid; /* VPN2 | ASID*/ 150 uint32_t lower = ((physical & 0xfffff000) >> 6) | flags; 151 uint32_t upper = (((physical + pagesize) & 0xfffff000) >> 6) | flags; 152 uint32_t pagemask = ((pagesize - 1) & 0xfffff000) << 1; 153 154 map_page_set_index(index); 155 map_page_index_op(lower, upper, start, pagemask); 156 }