1 /* 2 * Copyright 2008-2009 Freescale Semiconductor, Inc. 3 * 4 * (C) Copyright 2000 5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 6 * 7 * See file CREDITS for list of people who contributed to this 8 * project. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23 * MA 02111-1307 USA 24 */ 25 26 #include <common.h> 27 #include <asm/processor.h> 28 #include <asm/mmu.h> 29 #ifdef CONFIG_ADDR_MAP 30 #include <addr_map.h> 31 #endif 32 33 DECLARE_GLOBAL_DATA_PTR; 34 35 void invalidate_tlb(u8 tlb) 36 { 37 if (tlb == 0) 38 mtspr(MMUCSR0, 0x4); 39 if (tlb == 1) 40 mtspr(MMUCSR0, 0x2); 41 } 42 43 void init_tlbs(void) 44 { 45 int i; 46 47 for (i = 0; i < num_tlb_entries; i++) { 48 write_tlb(tlb_table[i].mas0, 49 tlb_table[i].mas1, 50 tlb_table[i].mas2, 51 tlb_table[i].mas3, 52 tlb_table[i].mas7); 53 } 54 55 return ; 56 } 57 58 void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn, 59 phys_addr_t *rpn) 60 { 61 u32 _mas1; 62 63 mtspr(MAS0, FSL_BOOKE_MAS0(1, idx, 0)); 64 asm volatile("tlbre;isync"); 65 _mas1 = mfspr(MAS1); 66 67 *valid = (_mas1 & MAS1_VALID); 68 *tsize = (_mas1 >> 8) & 0xf; 69 *epn = mfspr(MAS2) & MAS2_EPN; 70 *rpn = mfspr(MAS3) & MAS3_RPN; 71 #ifdef CONFIG_ENABLE_36BIT_PHYS 72 *rpn |= ((u64)mfspr(MAS7)) << 32; 73 #endif 74 } 75 76 #ifndef CONFIG_NAND_SPL 77 static inline void use_tlb_cam(u8 idx) 78 { 79 int i = idx / 32; 80 int bit = idx % 32; 81 82 gd->used_tlb_cams[i] |= (1 << bit); 83 } 84 85 static inline void free_tlb_cam(u8 idx) 86 { 87 int i = idx / 32; 88 int bit = idx % 32; 89 90 gd->used_tlb_cams[i] &= ~(1 << bit); 91 } 92 93 void init_used_tlb_cams(void) 94 { 95 int i; 96 unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff; 97 98 for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) 99 gd->used_tlb_cams[i] = 0; 100 101 /* walk all the entries */ 102 for (i = 0; i < num_cam; i++) { 103 mtspr(MAS0, FSL_BOOKE_MAS0(1, i, 0)); 104 asm volatile("tlbre;isync"); 105 if (mfspr(MAS1) & MAS1_VALID) 106 use_tlb_cam(i); 107 } 108 } 109 110 int find_free_tlbcam(void) 111 { 112 int i; 113 u32 idx; 114 115 for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) { 116 idx = ffz(gd->used_tlb_cams[i]); 117 118 if (idx != 32) 119 break; 120 } 121 122 idx += i * 32; 123 124 if (idx >= CONFIG_SYS_NUM_TLBCAMS) 125 return -1; 126 127 return idx; 128 } 129 130 void set_tlb(u8 tlb, u32 epn, u64 rpn, 131 u8 perms, u8 wimge, 132 u8 ts, u8 esel, u8 tsize, u8 iprot) 133 { 134 u32 _mas0, _mas1, _mas2, _mas3, _mas7; 135 136 if (tlb == 1) 137 use_tlb_cam(esel); 138 139 _mas0 = FSL_BOOKE_MAS0(tlb, esel, 0); 140 _mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize); 141 _mas2 = FSL_BOOKE_MAS2(epn, wimge); 142 _mas3 = FSL_BOOKE_MAS3(rpn, 0, perms); 143 _mas7 = FSL_BOOKE_MAS7(rpn); 144 145 write_tlb(_mas0, _mas1, _mas2, _mas3, _mas7); 146 147 #ifdef CONFIG_ADDR_MAP 148 if ((tlb == 1) && (gd->flags & GD_FLG_RELOC)) 149 addrmap_set_entry(epn, rpn, TSIZE_TO_BYTES(tsize), esel); 150 #endif 151 } 152 153 void disable_tlb(u8 esel) 154 { 155 u32 _mas0, _mas1, _mas2, _mas3, _mas7; 156 157 free_tlb_cam(esel); 158 159 _mas0 = FSL_BOOKE_MAS0(1, esel, 0); 160 _mas1 = 0; 161 _mas2 = 0; 162 _mas3 = 0; 163 _mas7 = 0; 164 165 mtspr(MAS0, _mas0); 166 mtspr(MAS1, _mas1); 167 mtspr(MAS2, _mas2); 168 mtspr(MAS3, _mas3); 169 #ifdef CONFIG_ENABLE_36BIT_PHYS 170 mtspr(MAS7, _mas7); 171 #endif 172 asm volatile("isync;msync;tlbwe;isync"); 173 174 #ifdef CONFIG_ADDR_MAP 175 if (gd->flags & GD_FLG_RELOC) 176 addrmap_set_entry(0, 0, 0, esel); 177 #endif 178 } 179 180 static void tlbsx (const volatile unsigned *addr) 181 { 182 __asm__ __volatile__ ("tlbsx 0,%0" : : "r" (addr), "m" (*addr)); 183 } 184 185 /* return -1 if we didn't find anything */ 186 int find_tlb_idx(void *addr, u8 tlbsel) 187 { 188 u32 _mas0, _mas1; 189 190 /* zero out Search PID, AS */ 191 mtspr(MAS6, 0); 192 193 tlbsx(addr); 194 195 _mas0 = mfspr(MAS0); 196 _mas1 = mfspr(MAS1); 197 198 /* we found something, and its in the TLB we expect */ 199 if ((MAS1_VALID & _mas1) && 200 (MAS0_TLBSEL(tlbsel) == (_mas0 & MAS0_TLBSEL_MSK))) { 201 return ((_mas0 & MAS0_ESEL_MSK) >> 16); 202 } 203 204 return -1; 205 } 206 207 #ifdef CONFIG_ADDR_MAP 208 void init_addr_map(void) 209 { 210 int i; 211 unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff; 212 213 /* walk all the entries */ 214 for (i = 0; i < num_cam; i++) { 215 unsigned long epn; 216 u32 tsize, valid; 217 phys_addr_t rpn; 218 219 read_tlbcam_entry(i, &valid, &tsize, &epn, &rpn); 220 if (valid & MAS1_VALID) 221 addrmap_set_entry(epn, rpn, TSIZE_TO_BYTES(tsize), i); 222 } 223 224 return ; 225 } 226 #endif 227 228 unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) 229 { 230 int i; 231 unsigned int tlb_size; 232 unsigned int ram_tlb_address = (unsigned int)CONFIG_SYS_DDR_SDRAM_BASE; 233 unsigned int max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf; 234 u64 size, memsize = (u64)memsize_in_meg << 20; 235 236 size = min(memsize, CONFIG_MAX_MEM_MAPPED); 237 238 /* Convert (4^max) kB to (2^max) bytes */ 239 max_cam = max_cam * 2 + 10; 240 241 for (i = 0; size && i < 8; i++) { 242 int ram_tlb_index = find_free_tlbcam(); 243 u32 camsize = __ilog2_u64(size) & ~1U; 244 u32 align = __ilog2(ram_tlb_address) & ~1U; 245 246 if (ram_tlb_index == -1) 247 break; 248 249 if (align == -2) align = max_cam; 250 if (camsize > align) 251 camsize = align; 252 253 if (camsize > max_cam) 254 camsize = max_cam; 255 256 tlb_size = (camsize - 10) / 2; 257 258 set_tlb(1, ram_tlb_address, ram_tlb_address, 259 MAS3_SX|MAS3_SW|MAS3_SR, 0, 260 0, ram_tlb_index, tlb_size, 1); 261 262 size -= 1ULL << camsize; 263 memsize -= 1ULL << camsize; 264 ram_tlb_address += 1UL << camsize; 265 } 266 267 if (memsize) 268 print_size(memsize, " left unmapped\n"); 269 270 /* 271 * Confirm that the requested amount of memory was mapped. 272 */ 273 return memsize_in_meg; 274 } 275 #endif /* !CONFIG_NAND_SPL */ 276