Home | History | Annotate | Download | only in mpc85xx
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright 2008-2011 Freescale Semiconductor, Inc.
      4  *
      5  * (C) Copyright 2000
      6  * Wolfgang Denk, DENX Software Engineering, wd (at) denx.de.
      7  */
      8 
      9 #include <common.h>
     10 #include <asm/processor.h>
     11 #include <asm/mmu.h>
     12 #ifdef CONFIG_ADDR_MAP
     13 #include <addr_map.h>
     14 #endif
     15 
     16 #include <linux/log2.h>
     17 
     18 DECLARE_GLOBAL_DATA_PTR;
     19 
     20 void invalidate_tlb(u8 tlb)
     21 {
     22 	if (tlb == 0)
     23 		mtspr(MMUCSR0, 0x4);
     24 	if (tlb == 1)
     25 		mtspr(MMUCSR0, 0x2);
     26 }
     27 
     28 __weak void init_tlbs(void)
     29 {
     30 	int i;
     31 
     32 	for (i = 0; i < num_tlb_entries; i++) {
     33 		write_tlb(tlb_table[i].mas0,
     34 			  tlb_table[i].mas1,
     35 			  tlb_table[i].mas2,
     36 			  tlb_table[i].mas3,
     37 			  tlb_table[i].mas7);
     38 	}
     39 
     40 	return ;
     41 }
     42 
     43 #if !defined(CONFIG_NAND_SPL) && \
     44 	(!defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SPL_INIT_MINIMAL))
     45 void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn,
     46 		       phys_addr_t *rpn)
     47 {
     48 	u32 _mas1;
     49 
     50 	mtspr(MAS0, FSL_BOOKE_MAS0(1, idx, 0));
     51 	asm volatile("tlbre;isync");
     52 	_mas1 = mfspr(MAS1);
     53 
     54 	*valid = (_mas1 & MAS1_VALID);
     55 	*tsize = (_mas1 >> 7) & 0x1f;
     56 	*epn = mfspr(MAS2) & MAS2_EPN;
     57 	*rpn = mfspr(MAS3) & MAS3_RPN;
     58 #ifdef CONFIG_ENABLE_36BIT_PHYS
     59 	*rpn |= ((u64)mfspr(MAS7)) << 32;
     60 #endif
     61 }
     62 
     63 void print_tlbcam(void)
     64 {
     65 	int i;
     66 	unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff;
     67 
     68 	/* walk all the entries */
     69 	printf("TLBCAM entries\n");
     70 	for (i = 0; i < num_cam; i++) {
     71 		unsigned long epn;
     72 		u32 tsize, valid;
     73 		phys_addr_t rpn;
     74 
     75 		read_tlbcam_entry(i, &valid, &tsize, &epn, &rpn);
     76 		printf("entry %02d: V: %d EPN 0x%08x RPN 0x%08llx size:",
     77 			i, (valid == 0) ? 0 : 1, (unsigned int)epn,
     78 			(unsigned long long)rpn);
     79 		print_size(TSIZE_TO_BYTES(tsize), "\n");
     80 	}
     81 }
     82 
     83 static inline void use_tlb_cam(u8 idx)
     84 {
     85 	int i = idx / 32;
     86 	int bit = idx % 32;
     87 
     88 	gd->arch.used_tlb_cams[i] |= (1 << bit);
     89 }
     90 
     91 static inline void free_tlb_cam(u8 idx)
     92 {
     93 	int i = idx / 32;
     94 	int bit = idx % 32;
     95 
     96 	gd->arch.used_tlb_cams[i] &= ~(1 << bit);
     97 }
     98 
     99 void init_used_tlb_cams(void)
    100 {
    101 	int i;
    102 	unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff;
    103 
    104 	for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++)
    105 		gd->arch.used_tlb_cams[i] = 0;
    106 
    107 	/* walk all the entries */
    108 	for (i = 0; i < num_cam; i++) {
    109 		mtspr(MAS0, FSL_BOOKE_MAS0(1, i, 0));
    110 		asm volatile("tlbre;isync");
    111 		if (mfspr(MAS1) & MAS1_VALID)
    112 			use_tlb_cam(i);
    113 	}
    114 }
    115 
    116 int find_free_tlbcam(void)
    117 {
    118 	int i;
    119 	u32 idx;
    120 
    121 	for (i = 0; i < ((CONFIG_SYS_NUM_TLBCAMS+31)/32); i++) {
    122 		idx = ffz(gd->arch.used_tlb_cams[i]);
    123 
    124 		if (idx != 32)
    125 			break;
    126 	}
    127 
    128 	idx += i * 32;
    129 
    130 	if (idx >= CONFIG_SYS_NUM_TLBCAMS)
    131 		return -1;
    132 
    133 	return idx;
    134 }
    135 
    136 void set_tlb(u8 tlb, u32 epn, u64 rpn,
    137 	     u8 perms, u8 wimge,
    138 	     u8 ts, u8 esel, u8 tsize, u8 iprot)
    139 {
    140 	u32 _mas0, _mas1, _mas2, _mas3, _mas7;
    141 
    142 	if (tlb == 1)
    143 		use_tlb_cam(esel);
    144 
    145 	if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1 &&
    146 	    tsize & 1) {
    147 		printf("%s: bad tsize %d on entry %d at 0x%08x\n",
    148 			__func__, tsize, tlb, epn);
    149 		return;
    150 	}
    151 
    152 	_mas0 = FSL_BOOKE_MAS0(tlb, esel, 0);
    153 	_mas1 = FSL_BOOKE_MAS1(1, iprot, 0, ts, tsize);
    154 	_mas2 = FSL_BOOKE_MAS2(epn, wimge);
    155 	_mas3 = FSL_BOOKE_MAS3(rpn, 0, perms);
    156 	_mas7 = FSL_BOOKE_MAS7(rpn);
    157 
    158 	write_tlb(_mas0, _mas1, _mas2, _mas3, _mas7);
    159 
    160 #ifdef CONFIG_ADDR_MAP
    161 	if ((tlb == 1) && (gd->flags & GD_FLG_RELOC))
    162 		addrmap_set_entry(epn, rpn, TSIZE_TO_BYTES(tsize), esel);
    163 #endif
    164 }
    165 
    166 void disable_tlb(u8 esel)
    167 {
    168 	u32 _mas0, _mas1, _mas2, _mas3;
    169 
    170 	free_tlb_cam(esel);
    171 
    172 	_mas0 = FSL_BOOKE_MAS0(1, esel, 0);
    173 	_mas1 = 0;
    174 	_mas2 = 0;
    175 	_mas3 = 0;
    176 
    177 	mtspr(MAS0, _mas0);
    178 	mtspr(MAS1, _mas1);
    179 	mtspr(MAS2, _mas2);
    180 	mtspr(MAS3, _mas3);
    181 #ifdef CONFIG_ENABLE_36BIT_PHYS
    182 	mtspr(MAS7, 0);
    183 #endif
    184 	asm volatile("isync;msync;tlbwe;isync");
    185 
    186 #ifdef CONFIG_ADDR_MAP
    187 	if (gd->flags & GD_FLG_RELOC)
    188 		addrmap_set_entry(0, 0, 0, esel);
    189 #endif
    190 }
    191 
    192 static void tlbsx (const volatile unsigned *addr)
    193 {
    194 	__asm__ __volatile__ ("tlbsx 0,%0" : : "r" (addr), "m" (*addr));
    195 }
    196 
    197 /* return -1 if we didn't find anything */
    198 int find_tlb_idx(void *addr, u8 tlbsel)
    199 {
    200 	u32 _mas0, _mas1;
    201 
    202 	/* zero out Search PID, AS */
    203 	mtspr(MAS6, 0);
    204 
    205 	tlbsx(addr);
    206 
    207 	_mas0 = mfspr(MAS0);
    208 	_mas1 = mfspr(MAS1);
    209 
    210 	/* we found something, and its in the TLB we expect */
    211 	if ((MAS1_VALID & _mas1) &&
    212 		(MAS0_TLBSEL(tlbsel) == (_mas0 & MAS0_TLBSEL_MSK))) {
    213 		return ((_mas0 & MAS0_ESEL_MSK) >> 16);
    214 	}
    215 
    216 	return -1;
    217 }
    218 
    219 #ifdef CONFIG_ADDR_MAP
    220 void init_addr_map(void)
    221 {
    222 	int i;
    223 	unsigned int num_cam = mfspr(SPRN_TLB1CFG) & 0xfff;
    224 
    225 	/* walk all the entries */
    226 	for (i = 0; i < num_cam; i++) {
    227 		unsigned long epn;
    228 		u32 tsize, valid;
    229 		phys_addr_t rpn;
    230 
    231 		read_tlbcam_entry(i, &valid, &tsize, &epn, &rpn);
    232 		if (valid & MAS1_VALID)
    233 			addrmap_set_entry(epn, rpn, TSIZE_TO_BYTES(tsize), i);
    234 	}
    235 
    236 	return ;
    237 }
    238 #endif
    239 
    240 uint64_t tlb_map_range(ulong v_addr, phys_addr_t p_addr, uint64_t size,
    241 		       enum tlb_map_type map_type)
    242 {
    243 	int i;
    244 	unsigned int tlb_size;
    245 	unsigned int wimge;
    246 	unsigned int perm;
    247 	unsigned int max_cam, tsize_mask;
    248 
    249 	if (map_type == TLB_MAP_RAM) {
    250 		perm = MAS3_SX|MAS3_SW|MAS3_SR;
    251 		wimge = MAS2_M;
    252 #ifdef CONFIG_SYS_PPC_DDR_WIMGE
    253 		wimge = CONFIG_SYS_PPC_DDR_WIMGE;
    254 #endif
    255 	} else {
    256 		perm = MAS3_SW|MAS3_SR;
    257 		wimge = MAS2_I|MAS2_G;
    258 	}
    259 
    260 	if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) {
    261 		/* Convert (4^max) kB to (2^max) bytes */
    262 		max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10;
    263 		tsize_mask = ~1U;
    264 	} else {
    265 		/* Convert (2^max) kB to (2^max) bytes */
    266 		max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10;
    267 		tsize_mask = ~0U;
    268 	}
    269 
    270 	for (i = 0; size && i < 8; i++) {
    271 		int tlb_index = find_free_tlbcam();
    272 		u32 camsize = __ilog2_u64(size) & tsize_mask;
    273 		u32 align = __ilog2(v_addr) & tsize_mask;
    274 
    275 		if (tlb_index == -1)
    276 			break;
    277 
    278 		if (align == -2) align = max_cam;
    279 		if (camsize > align)
    280 			camsize = align;
    281 
    282 		if (camsize > max_cam)
    283 			camsize = max_cam;
    284 
    285 		tlb_size = camsize - 10;
    286 
    287 		set_tlb(1, v_addr, p_addr, perm, wimge,
    288 			0, tlb_index, tlb_size, 1);
    289 
    290 		size -= 1ULL << camsize;
    291 		v_addr += 1UL << camsize;
    292 		p_addr += 1UL << camsize;
    293 	}
    294 
    295 	return size;
    296 }
    297 
    298 unsigned int setup_ddr_tlbs_phys(phys_addr_t p_addr,
    299 				 unsigned int memsize_in_meg)
    300 {
    301 	unsigned int ram_tlb_address = (unsigned int)CONFIG_SYS_DDR_SDRAM_BASE;
    302 	u64 memsize = (u64)memsize_in_meg << 20;
    303 	u64 size;
    304 
    305 	size = min(memsize, (u64)CONFIG_MAX_MEM_MAPPED);
    306 	size = tlb_map_range(ram_tlb_address, p_addr, size, TLB_MAP_RAM);
    307 
    308 	if (size || memsize > CONFIG_MAX_MEM_MAPPED) {
    309 		print_size(memsize > CONFIG_MAX_MEM_MAPPED ?
    310 			   memsize - CONFIG_MAX_MEM_MAPPED + size : size,
    311 			   " left unmapped\n");
    312 	}
    313 
    314 	return memsize_in_meg;
    315 }
    316 
    317 unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg)
    318 {
    319 	return
    320 		setup_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg);
    321 }
    322 
    323 /* Invalidate the DDR TLBs for the requested size */
    324 void clear_ddr_tlbs_phys(phys_addr_t p_addr, unsigned int memsize_in_meg)
    325 {
    326 	u32 vstart = CONFIG_SYS_DDR_SDRAM_BASE;
    327 	unsigned long epn;
    328 	u32 tsize, valid, ptr;
    329 	phys_addr_t rpn = 0;
    330 	int ddr_esel;
    331 	u64 memsize = (u64)memsize_in_meg << 20;
    332 
    333 	ptr = vstart;
    334 
    335 	while (ptr < (vstart + memsize)) {
    336 		ddr_esel = find_tlb_idx((void *)ptr, 1);
    337 		if (ddr_esel != -1) {
    338 			read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn);
    339 			disable_tlb(ddr_esel);
    340 		}
    341 		ptr += TSIZE_TO_BYTES(tsize);
    342 	}
    343 }
    344 
    345 void clear_ddr_tlbs(unsigned int memsize_in_meg)
    346 {
    347 	clear_ddr_tlbs_phys(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg);
    348 }
    349 
    350 
    351 #endif /* not SPL */
    352