tlb.c 7.2 KB

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