1a47a12beSStefan Roese /* 2ebc73943SKumar Gala * Copyright 2008-2011 Freescale Semiconductor, Inc. 3a47a12beSStefan Roese * 4a47a12beSStefan Roese * (C) Copyright 2000 5a47a12beSStefan Roese * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 6a47a12beSStefan Roese * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8a47a12beSStefan Roese */ 9a47a12beSStefan Roese 10a47a12beSStefan Roese #include <common.h> 11a47a12beSStefan Roese #include <asm/processor.h> 12a47a12beSStefan Roese #include <asm/mmu.h> 13a47a12beSStefan Roese #ifdef CONFIG_ADDR_MAP 14a47a12beSStefan Roese #include <addr_map.h> 15a47a12beSStefan Roese #endif 16a47a12beSStefan Roese 17a47a12beSStefan Roese DECLARE_GLOBAL_DATA_PTR; 18a47a12beSStefan Roese 19a47a12beSStefan Roese void invalidate_tlb(u8 tlb) 20a47a12beSStefan Roese { 21a47a12beSStefan Roese if (tlb == 0) 22a47a12beSStefan Roese mtspr(MMUCSR0, 0x4); 23a47a12beSStefan Roese if (tlb == 1) 24a47a12beSStefan Roese mtspr(MMUCSR0, 0x2); 25a47a12beSStefan Roese } 26a47a12beSStefan Roese 27a47a12beSStefan Roese void init_tlbs(void) 28a47a12beSStefan Roese { 29a47a12beSStefan Roese int i; 30a47a12beSStefan Roese 31a47a12beSStefan Roese for (i = 0; i < num_tlb_entries; i++) { 32a47a12beSStefan Roese write_tlb(tlb_table[i].mas0, 33a47a12beSStefan Roese tlb_table[i].mas1, 34a47a12beSStefan Roese tlb_table[i].mas2, 35a47a12beSStefan Roese tlb_table[i].mas3, 36a47a12beSStefan Roese tlb_table[i].mas7); 37a47a12beSStefan Roese } 38a47a12beSStefan Roese 39a47a12beSStefan Roese return ; 40a47a12beSStefan Roese } 41a47a12beSStefan Roese 42*0151d99dSYing Zhang #if !defined(CONFIG_NAND_SPL) && \ 43*0151d99dSYing Zhang (!defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SPL_INIT_MINIMAL)) 444e63df30SBecky Bruce void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn, 454e63df30SBecky Bruce phys_addr_t *rpn) 464e63df30SBecky Bruce { 474e63df30SBecky Bruce u32 _mas1; 484e63df30SBecky Bruce 494e63df30SBecky Bruce mtspr(MAS0, FSL_BOOKE_MAS0(1, idx, 0)); 504e63df30SBecky Bruce asm volatile("tlbre;isync"); 514e63df30SBecky Bruce _mas1 = mfspr(MAS1); 524e63df30SBecky Bruce 534e63df30SBecky Bruce *valid = (_mas1 & MAS1_VALID); 5431d084ddSScott Wood *tsize = (_mas1 >> 7) & 0x1f; 554e63df30SBecky Bruce *epn = mfspr(MAS2) & MAS2_EPN; 564e63df30SBecky Bruce *rpn = mfspr(MAS3) & MAS3_RPN; 574e63df30SBecky Bruce #ifdef CONFIG_ENABLE_36BIT_PHYS 584e63df30SBecky Bruce *rpn |= ((u64)mfspr(MAS7)) << 32; 594e63df30SBecky Bruce #endif 604e63df30SBecky Bruce } 614e63df30SBecky Bruce 6270e02bcaSBecky Bruce void print_tlbcam(void) 6370e02bcaSBecky Bruce { 6470e02bcaSBecky Bruce int i; 6570e02bcaSBecky Bruce unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff; 6670e02bcaSBecky Bruce 6770e02bcaSBecky Bruce /* walk all the entries */ 6870e02bcaSBecky Bruce printf("TLBCAM entries\n"); 6970e02bcaSBecky Bruce for (i = 0; i < num_cam; i++) { 7070e02bcaSBecky Bruce unsigned long epn; 7170e02bcaSBecky Bruce u32 tsize, valid; 7270e02bcaSBecky Bruce phys_addr_t rpn; 7370e02bcaSBecky Bruce 7470e02bcaSBecky Bruce read_tlbcam_entry(i, &valid, &tsize, &epn, &rpn); 7570e02bcaSBecky Bruce printf("entry %02d: V: %d EPN 0x%08x RPN 0x%08llx size:", 7670e02bcaSBecky Bruce i, (valid == 0) ? 0 : 1, (unsigned int)epn, 7770e02bcaSBecky Bruce (unsigned long long)rpn); 7870e02bcaSBecky Bruce print_size(TSIZE_TO_BYTES(tsize), "\n"); 7970e02bcaSBecky Bruce } 8070e02bcaSBecky Bruce } 8170e02bcaSBecky Bruce 82a47a12beSStefan Roese static inline void use_tlb_cam(u8 idx) 83a47a12beSStefan Roese { 84a47a12beSStefan Roese int i = idx / 32; 85a47a12beSStefan Roese int bit = idx % 32; 86a47a12beSStefan Roese 877c80c6c5SSimon Glass gd->arch.used_tlb_cams[i] |= (1 << bit); 88a47a12beSStefan Roese } 89a47a12beSStefan Roese 90a47a12beSStefan Roese static inline void free_tlb_cam(u8 idx) 91a47a12beSStefan Roese { 92a47a12beSStefan Roese int i = idx / 32; 93a47a12beSStefan Roese int bit = idx % 32; 94a47a12beSStefan Roese 957c80c6c5SSimon Glass gd->arch.used_tlb_cams[i] &= ~(1 << bit); 96a47a12beSStefan Roese } 97a47a12beSStefan Roese 98a47a12beSStefan Roese void init_used_tlb_cams(void) 99a47a12beSStefan Roese { 100a47a12beSStefan Roese int i; 101a47a12beSStefan Roese unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff; 102a47a12beSStefan Roese 103a47a12beSStefan Roese for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) 1047c80c6c5SSimon Glass gd->arch.used_tlb_cams[i] = 0; 105a47a12beSStefan Roese 106a47a12beSStefan Roese /* walk all the entries */ 107a47a12beSStefan Roese for (i = 0; i < num_cam; i++) { 108a47a12beSStefan Roese mtspr(MAS0, FSL_BOOKE_MAS0(1, i, 0)); 109a47a12beSStefan Roese asm volatile("tlbre;isync"); 1104e63df30SBecky Bruce if (mfspr(MAS1) & MAS1_VALID) 111a47a12beSStefan Roese use_tlb_cam(i); 112a47a12beSStefan Roese } 113a47a12beSStefan Roese } 114a47a12beSStefan Roese 115a47a12beSStefan Roese int find_free_tlbcam(void) 116a47a12beSStefan Roese { 117a47a12beSStefan Roese int i; 118a47a12beSStefan Roese u32 idx; 119a47a12beSStefan Roese 120a47a12beSStefan Roese for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) { 1217c80c6c5SSimon Glass idx = ffz(gd->arch.used_tlb_cams[i]); 122a47a12beSStefan Roese 123a47a12beSStefan Roese if (idx != 32) 124a47a12beSStefan Roese break; 125a47a12beSStefan Roese } 126a47a12beSStefan Roese 127a47a12beSStefan Roese idx += i * 32; 128a47a12beSStefan Roese 129a47a12beSStefan Roese if (idx >= CONFIG_SYS_NUM_TLBCAMS) 130a47a12beSStefan Roese return -1; 131a47a12beSStefan Roese 132a47a12beSStefan Roese return idx; 133a47a12beSStefan Roese } 134a47a12beSStefan Roese 135a47a12beSStefan Roese void set_tlb(u8 tlb, u32 epn, u64 rpn, 136a47a12beSStefan Roese u8 perms, u8 wimge, 137a47a12beSStefan Roese u8 ts, u8 esel, u8 tsize, u8 iprot) 138a47a12beSStefan Roese { 139a47a12beSStefan Roese u32 _mas0, _mas1, _mas2, _mas3, _mas7; 140a47a12beSStefan Roese 141a47a12beSStefan Roese if (tlb == 1) 142a47a12beSStefan Roese use_tlb_cam(esel); 143a47a12beSStefan Roese 14431d084ddSScott Wood if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1 && 14531d084ddSScott Wood tsize & 1) { 14631d084ddSScott Wood printf("%s: bad tsize %d on entry %d at 0x%08x\n", 14731d084ddSScott Wood __func__, tsize, tlb, epn); 14831d084ddSScott Wood return; 14931d084ddSScott Wood } 15031d084ddSScott Wood 151a47a12beSStefan Roese _mas0 = FSL_BOOKE_MAS0(tlb, esel, 0); 152a47a12beSStefan Roese _mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize); 153a47a12beSStefan Roese _mas2 = FSL_BOOKE_MAS2(epn, wimge); 154a47a12beSStefan Roese _mas3 = FSL_BOOKE_MAS3(rpn, 0, perms); 155a47a12beSStefan Roese _mas7 = FSL_BOOKE_MAS7(rpn); 156a47a12beSStefan Roese 157a47a12beSStefan Roese write_tlb(_mas0, _mas1, _mas2, _mas3, _mas7); 158a47a12beSStefan Roese 159a47a12beSStefan Roese #ifdef CONFIG_ADDR_MAP 160a47a12beSStefan Roese if ((tlb == 1) && (gd->flags & GD_FLG_RELOC)) 1614e63df30SBecky Bruce addrmap_set_entry(epn, rpn, TSIZE_TO_BYTES(tsize), esel); 162a47a12beSStefan Roese #endif 163a47a12beSStefan Roese } 164a47a12beSStefan Roese 165a47a12beSStefan Roese void disable_tlb(u8 esel) 166a47a12beSStefan Roese { 1673d6d9c31SKumar Gala u32 _mas0, _mas1, _mas2, _mas3; 168a47a12beSStefan Roese 169a47a12beSStefan Roese free_tlb_cam(esel); 170a47a12beSStefan Roese 171a47a12beSStefan Roese _mas0 = FSL_BOOKE_MAS0(1, esel, 0); 172a47a12beSStefan Roese _mas1 = 0; 173a47a12beSStefan Roese _mas2 = 0; 174a47a12beSStefan Roese _mas3 = 0; 175a47a12beSStefan Roese 176a47a12beSStefan Roese mtspr(MAS0, _mas0); 177a47a12beSStefan Roese mtspr(MAS1, _mas1); 178a47a12beSStefan Roese mtspr(MAS2, _mas2); 179a47a12beSStefan Roese mtspr(MAS3, _mas3); 180a47a12beSStefan Roese #ifdef CONFIG_ENABLE_36BIT_PHYS 1813d6d9c31SKumar Gala mtspr(MAS7, 0); 182a47a12beSStefan Roese #endif 183a47a12beSStefan Roese asm volatile("isync;msync;tlbwe;isync"); 184a47a12beSStefan Roese 185a47a12beSStefan Roese #ifdef CONFIG_ADDR_MAP 186a47a12beSStefan Roese if (gd->flags & GD_FLG_RELOC) 187a47a12beSStefan Roese addrmap_set_entry(0, 0, 0, esel); 188a47a12beSStefan Roese #endif 189a47a12beSStefan Roese } 190a47a12beSStefan Roese 191a47a12beSStefan Roese static void tlbsx (const volatile unsigned *addr) 192a47a12beSStefan Roese { 193a47a12beSStefan Roese __asm__ __volatile__ ("tlbsx 0,%0" : : "r" (addr), "m" (*addr)); 194a47a12beSStefan Roese } 195a47a12beSStefan Roese 196a47a12beSStefan Roese /* return -1 if we didn't find anything */ 197a47a12beSStefan Roese int find_tlb_idx(void *addr, u8 tlbsel) 198a47a12beSStefan Roese { 199a47a12beSStefan Roese u32 _mas0, _mas1; 200a47a12beSStefan Roese 201a47a12beSStefan Roese /* zero out Search PID, AS */ 202a47a12beSStefan Roese mtspr(MAS6, 0); 203a47a12beSStefan Roese 204a47a12beSStefan Roese tlbsx(addr); 205a47a12beSStefan Roese 206a47a12beSStefan Roese _mas0 = mfspr(MAS0); 207a47a12beSStefan Roese _mas1 = mfspr(MAS1); 208a47a12beSStefan Roese 209a47a12beSStefan Roese /* we found something, and its in the TLB we expect */ 210a47a12beSStefan Roese if ((MAS1_VALID & _mas1) && 211a47a12beSStefan Roese (MAS0_TLBSEL(tlbsel) == (_mas0 & MAS0_TLBSEL_MSK))) { 212a47a12beSStefan Roese return ((_mas0 & MAS0_ESEL_MSK) >> 16); 213a47a12beSStefan Roese } 214a47a12beSStefan Roese 215a47a12beSStefan Roese return -1; 216a47a12beSStefan Roese } 217a47a12beSStefan Roese 218a47a12beSStefan Roese #ifdef CONFIG_ADDR_MAP 219a47a12beSStefan Roese void init_addr_map(void) 220a47a12beSStefan Roese { 221a47a12beSStefan Roese int i; 222a47a12beSStefan Roese unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff; 223a47a12beSStefan Roese 224a47a12beSStefan Roese /* walk all the entries */ 225a47a12beSStefan Roese for (i = 0; i < num_cam; i++) { 226a47a12beSStefan Roese unsigned long epn; 2274e63df30SBecky Bruce u32 tsize, valid; 228a47a12beSStefan Roese phys_addr_t rpn; 229a47a12beSStefan Roese 2304e63df30SBecky Bruce read_tlbcam_entry(i, &valid, &tsize, &epn, &rpn); 2314e63df30SBecky Bruce if (valid & MAS1_VALID) 2324e63df30SBecky Bruce addrmap_set_entry(epn, rpn, TSIZE_TO_BYTES(tsize), i); 233a47a12beSStefan Roese } 234a47a12beSStefan Roese 235a47a12beSStefan Roese return ; 236a47a12beSStefan Roese } 237a47a12beSStefan Roese #endif 238a47a12beSStefan Roese 239c02ce6e5SYork Sun unsigned int 240c02ce6e5SYork Sun setup_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg) 241a47a12beSStefan Roese { 242a47a12beSStefan Roese int i; 243a47a12beSStefan Roese unsigned int tlb_size; 244ffd06e02SYork Sun unsigned int wimge = MAS2_M; 245a47a12beSStefan Roese unsigned int ram_tlb_address = (unsigned int)CONFIG_SYS_DDR_SDRAM_BASE; 24631d084ddSScott Wood unsigned int max_cam, tsize_mask; 247a47a12beSStefan Roese u64 size, memsize = (u64)memsize_in_meg << 20; 248a47a12beSStefan Roese 2496b1ef2a6SBecky Bruce #ifdef CONFIG_SYS_PPC_DDR_WIMGE 2506b1ef2a6SBecky Bruce wimge = CONFIG_SYS_PPC_DDR_WIMGE; 2516b1ef2a6SBecky Bruce #endif 252a47a12beSStefan Roese size = min(memsize, CONFIG_MAX_MEM_MAPPED); 25350cf3d17SKumar Gala if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) { 254a47a12beSStefan Roese /* Convert (4^max) kB to (2^max) bytes */ 25550cf3d17SKumar Gala max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10; 25631d084ddSScott Wood tsize_mask = ~1U; 25750cf3d17SKumar Gala } else { 25850cf3d17SKumar Gala /* Convert (2^max) kB to (2^max) bytes */ 25950cf3d17SKumar Gala max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10; 26031d084ddSScott Wood tsize_mask = ~0U; 26150cf3d17SKumar Gala } 262a47a12beSStefan Roese 263a47a12beSStefan Roese for (i = 0; size && i < 8; i++) { 264a47a12beSStefan Roese int ram_tlb_index = find_free_tlbcam(); 26531d084ddSScott Wood u32 camsize = __ilog2_u64(size) & tsize_mask; 26631d084ddSScott Wood u32 align = __ilog2(ram_tlb_address) & tsize_mask; 267a47a12beSStefan Roese 268a47a12beSStefan Roese if (ram_tlb_index == -1) 269a47a12beSStefan Roese break; 270a47a12beSStefan Roese 271a47a12beSStefan Roese if (align == -2) align = max_cam; 272a47a12beSStefan Roese if (camsize > align) 273a47a12beSStefan Roese camsize = align; 274a47a12beSStefan Roese 275a47a12beSStefan Roese if (camsize > max_cam) 276a47a12beSStefan Roese camsize = max_cam; 277a47a12beSStefan Roese 27831d084ddSScott Wood tlb_size = camsize - 10; 279a47a12beSStefan Roese 280c02ce6e5SYork Sun set_tlb(1, ram_tlb_address, p_addr, 2816b1ef2a6SBecky Bruce MAS3_SX|MAS3_SW|MAS3_SR, wimge, 282a47a12beSStefan Roese 0, ram_tlb_index, tlb_size, 1); 283a47a12beSStefan Roese 284a47a12beSStefan Roese size -= 1ULL << camsize; 285a47a12beSStefan Roese memsize -= 1ULL << camsize; 286a47a12beSStefan Roese ram_tlb_address += 1UL << camsize; 287c02ce6e5SYork Sun p_addr += 1UL << camsize; 288a47a12beSStefan Roese } 289a47a12beSStefan Roese 290a47a12beSStefan Roese if (memsize) 291a47a12beSStefan Roese print_size(memsize, " left unmapped\n"); 292a47a12beSStefan Roese return memsize_in_meg; 293a47a12beSStefan Roese } 294c02ce6e5SYork Sun 295c02ce6e5SYork Sun unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) 296c02ce6e5SYork Sun { 297c02ce6e5SYork Sun return 298c02ce6e5SYork Sun setup_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg); 299c02ce6e5SYork Sun } 3009cdfe281SBecky Bruce 3019cdfe281SBecky Bruce /* Invalidate the DDR TLBs for the requested size */ 3029cdfe281SBecky Bruce void clear_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg) 3039cdfe281SBecky Bruce { 3049cdfe281SBecky Bruce u32 vstart = CONFIG_SYS_DDR_SDRAM_BASE; 3059cdfe281SBecky Bruce unsigned long epn; 3069cdfe281SBecky Bruce u32 tsize, valid, ptr; 3079cdfe281SBecky Bruce phys_addr_t rpn = 0; 3089cdfe281SBecky Bruce int ddr_esel; 3099cdfe281SBecky Bruce u64 memsize = (u64)memsize_in_meg << 20; 3109cdfe281SBecky Bruce 3119cdfe281SBecky Bruce ptr = vstart; 3129cdfe281SBecky Bruce 3139cdfe281SBecky Bruce while (ptr < (vstart + memsize)) { 3149cdfe281SBecky Bruce ddr_esel = find_tlb_idx((void *)ptr, 1); 3159cdfe281SBecky Bruce if (ddr_esel != -1) { 3169cdfe281SBecky Bruce read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); 3179cdfe281SBecky Bruce disable_tlb(ddr_esel); 3189cdfe281SBecky Bruce } 3199cdfe281SBecky Bruce ptr += TSIZE_TO_BYTES(tsize); 3209cdfe281SBecky Bruce } 3219cdfe281SBecky Bruce } 3229cdfe281SBecky Bruce 3239cdfe281SBecky Bruce void clear_ddr_tlbs(unsigned int memsize_in_meg) 3249cdfe281SBecky Bruce { 3259cdfe281SBecky Bruce clear_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg); 3269cdfe281SBecky Bruce } 3279cdfe281SBecky Bruce 3289cdfe281SBecky Bruce 329c97cd1baSScott Wood #endif /* not SPL */ 330