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