fsl_pamu.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * FSL PAMU driver
  4. *
  5. * Copyright 2012-2016 Freescale Semiconductor, Inc.
  6. */
  7. #include <common.h>
  8. #include <log.h>
  9. #include <linux/bitops.h>
  10. #include <linux/log2.h>
  11. #include <malloc.h>
  12. #include <asm/fsl_pamu.h>
  13. struct paace *ppaact;
  14. struct paace *sec;
  15. unsigned long fspi;
  16. static inline int __ilog2_roundup_64(uint64_t val)
  17. {
  18. if ((val & (val - 1)) == 0)
  19. return __ilog2_u64(val);
  20. else
  21. return __ilog2_u64(val) + 1;
  22. }
  23. static inline int count_lsb_zeroes(unsigned long val)
  24. {
  25. return ffs(val) - 1;
  26. }
  27. static unsigned int map_addrspace_size_to_wse(uint64_t addrspace_size)
  28. {
  29. /* window size is 2^(WSE+1) bytes */
  30. return count_lsb_zeroes(addrspace_size >> PAMU_PAGE_SHIFT) +
  31. PAMU_PAGE_SHIFT - 1;
  32. }
  33. static unsigned int map_subwindow_cnt_to_wce(uint32_t subwindow_cnt)
  34. {
  35. /* window count is 2^(WCE+1) bytes */
  36. return count_lsb_zeroes(subwindow_cnt) - 1;
  37. }
  38. static void pamu_setup_default_xfer_to_host_ppaace(struct paace *ppaace)
  39. {
  40. set_bf(ppaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_PRIMARY);
  41. set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
  42. PAACE_M_COHERENCE_REQ);
  43. }
  44. static void pamu_setup_default_xfer_to_host_spaace(struct paace *spaace)
  45. {
  46. set_bf(spaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_SECONDARY);
  47. set_bf(spaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
  48. PAACE_M_COHERENCE_REQ);
  49. }
  50. /** Sets up PPAACE entry for specified liodn
  51. *
  52. * @param[in] liodn Logical IO device number
  53. * @param[in] win_addr starting address of DSA window
  54. * @param[in] win-size size of DSA window
  55. * @param[in] omi Operation mapping index -- if ~omi == 0 then omi
  56. not defined
  57. * @param[in] stashid cache stash id for associated cpu -- if ~stashid == 0
  58. then stashid not defined
  59. * @param[in] snoopid snoop id for hardware coherency -- if ~snoopid == 0
  60. then snoopid not defined
  61. * @param[in] subwin_cnt number of sub-windows
  62. *
  63. * @return Returns 0 upon success else error code < 0 returned
  64. */
  65. static int pamu_config_ppaace(uint32_t liodn, uint64_t win_addr,
  66. uint64_t win_size, uint32_t omi,
  67. uint32_t snoopid, uint32_t stashid,
  68. uint32_t subwin_cnt)
  69. {
  70. struct paace *ppaace;
  71. if ((win_size & (win_size - 1)) || win_size < PAMU_PAGE_SIZE)
  72. return -1;
  73. if (win_addr & (win_size - 1))
  74. return -2;
  75. if (liodn > NUM_PPAACT_ENTRIES) {
  76. printf("Entries in PPACT not sufficient\n");
  77. return -3;
  78. }
  79. ppaace = &ppaact[liodn];
  80. /* window size is 2^(WSE+1) bytes */
  81. set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE,
  82. map_addrspace_size_to_wse(win_size));
  83. pamu_setup_default_xfer_to_host_ppaace(ppaace);
  84. if (sizeof(phys_addr_t) > 4)
  85. ppaace->wbah = (u64)win_addr >> (PAMU_PAGE_SHIFT + 20);
  86. else
  87. ppaace->wbah = 0;
  88. set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL,
  89. (win_addr >> PAMU_PAGE_SHIFT));
  90. /* set up operation mapping if it's configured */
  91. if (omi < OME_NUMBER_ENTRIES) {
  92. set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
  93. ppaace->op_encode.index_ot.omi = omi;
  94. } else if (~omi != 0) {
  95. return -3;
  96. }
  97. /* configure stash id */
  98. if (~stashid != 0)
  99. set_bf(ppaace->impl_attr, PAACE_IA_CID, stashid);
  100. /* configure snoop id */
  101. if (~snoopid != 0)
  102. ppaace->domain_attr.to_host.snpid = snoopid;
  103. if (subwin_cnt) {
  104. /* window count is 2^(WCE+1) bytes */
  105. set_bf(ppaace->impl_attr, PAACE_IA_WCE,
  106. map_subwindow_cnt_to_wce(subwin_cnt));
  107. set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0x1);
  108. ppaace->fspi = fspi;
  109. fspi = fspi + DEFAULT_NUM_SUBWINDOWS - 1;
  110. } else {
  111. set_bf(ppaace->addr_bitfields, PAACE_AF_AP, PAACE_AP_PERMS_ALL);
  112. }
  113. sync();
  114. /* Mark the ppace entry valid */
  115. ppaace->addr_bitfields |= PAACE_V_VALID;
  116. sync();
  117. return 0;
  118. }
  119. static int pamu_config_spaace(uint32_t liodn,
  120. uint64_t subwin_size, uint64_t subwin_addr, uint64_t size,
  121. uint32_t omi, uint32_t snoopid, uint32_t stashid)
  122. {
  123. struct paace *paace;
  124. /* Align start addr of subwin to subwindoe size */
  125. uint64_t sec_addr = subwin_addr & ~(subwin_size - 1);
  126. uint64_t end_addr = subwin_addr + size;
  127. int size_shift = __ilog2_u64(subwin_size);
  128. uint64_t win_size = 0;
  129. uint32_t index, swse;
  130. unsigned long fspi_idx;
  131. /* Recalculate the size */
  132. size = end_addr - sec_addr;
  133. if (!subwin_size)
  134. return -1;
  135. if (liodn > NUM_PPAACT_ENTRIES) {
  136. printf("LIODN No programmed %d > no. of PPAACT entries %d\n",
  137. liodn, NUM_PPAACT_ENTRIES);
  138. return -1;
  139. }
  140. while (sec_addr < end_addr) {
  141. debug("sec_addr < end_addr is %llx < %llx\n", sec_addr,
  142. end_addr);
  143. paace = &ppaact[liodn];
  144. if (!paace)
  145. return -1;
  146. fspi_idx = paace->fspi;
  147. /* Calculating the win_size here as if we map in index 0,
  148. paace entry woudl need to be programmed for SWSE */
  149. win_size = end_addr - sec_addr;
  150. win_size = 1 << __ilog2_roundup_64(win_size);
  151. if (win_size > subwin_size)
  152. win_size = subwin_size;
  153. else if (win_size < PAMU_PAGE_SIZE)
  154. win_size = PAMU_PAGE_SIZE;
  155. debug("win_size is %llx\n", win_size);
  156. swse = map_addrspace_size_to_wse(win_size);
  157. index = sec_addr >> size_shift;
  158. if (index == 0) {
  159. set_bf(paace->win_bitfields, PAACE_WIN_SWSE, swse);
  160. set_bf(paace->addr_bitfields, PAACE_AF_AP,
  161. PAACE_AP_PERMS_ALL);
  162. sec_addr += subwin_size;
  163. continue;
  164. }
  165. paace = sec + fspi_idx + index - 1;
  166. debug("SPAACT:Writing at location %p, index %d\n", paace,
  167. index);
  168. pamu_setup_default_xfer_to_host_spaace(paace);
  169. set_bf(paace->addr_bitfields, SPAACE_AF_LIODN, liodn);
  170. set_bf(paace->addr_bitfields, PAACE_AF_AP, PAACE_AP_PERMS_ALL);
  171. /* configure snoop id */
  172. if (~snoopid != 0)
  173. paace->domain_attr.to_host.snpid = snoopid;
  174. if (paace->addr_bitfields & PAACE_V_VALID) {
  175. debug("Reached overlap condition\n");
  176. debug("%d < %d\n", get_bf(paace->win_bitfields,
  177. PAACE_WIN_SWSE), swse);
  178. if (get_bf(paace->win_bitfields, PAACE_WIN_SWSE) < swse)
  179. set_bf(paace->win_bitfields, PAACE_WIN_SWSE,
  180. swse);
  181. } else {
  182. set_bf(paace->win_bitfields, PAACE_WIN_SWSE, swse);
  183. }
  184. paace->addr_bitfields |= PAACE_V_VALID;
  185. sec_addr += subwin_size;
  186. }
  187. return 0;
  188. }
  189. int pamu_init(void)
  190. {
  191. u32 base_addr = CONFIG_SYS_PAMU_ADDR;
  192. struct ccsr_pamu *regs;
  193. u32 i = 0;
  194. u64 ppaact_phys, ppaact_lim, ppaact_size;
  195. u64 spaact_phys, spaact_lim, spaact_size;
  196. ppaact_size = sizeof(struct paace) * NUM_PPAACT_ENTRIES;
  197. spaact_size = sizeof(struct paace) * NUM_SPAACT_ENTRIES;
  198. /* Allocate space for Primary PAACT Table */
  199. #if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_PPAACT_ADDR))
  200. ppaact = (void *)CONFIG_SPL_PPAACT_ADDR;
  201. #else
  202. ppaact = memalign(PAMU_TABLE_ALIGNMENT, ppaact_size);
  203. if (!ppaact)
  204. return -1;
  205. #endif
  206. memset(ppaact, 0, ppaact_size);
  207. /* Allocate space for Secondary PAACT Table */
  208. #if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SPAACT_ADDR))
  209. sec = (void *)CONFIG_SPL_SPAACT_ADDR;
  210. #else
  211. sec = memalign(PAMU_TABLE_ALIGNMENT, spaact_size);
  212. if (!sec)
  213. return -1;
  214. #endif
  215. memset(sec, 0, spaact_size);
  216. ppaact_phys = virt_to_phys((void *)ppaact);
  217. ppaact_lim = ppaact_phys + ppaact_size;
  218. spaact_phys = (uint64_t)virt_to_phys((void *)sec);
  219. spaact_lim = spaact_phys + spaact_size;
  220. /* Configure all PAMU's */
  221. for (i = 0; i < CONFIG_NUM_PAMU; i++) {
  222. regs = (struct ccsr_pamu *)base_addr;
  223. out_be32(&regs->ppbah, ppaact_phys >> 32);
  224. out_be32(&regs->ppbal, (uint32_t)ppaact_phys);
  225. out_be32(&regs->pplah, (ppaact_lim) >> 32);
  226. out_be32(&regs->pplal, (uint32_t)ppaact_lim);
  227. if (sec != NULL) {
  228. out_be32(&regs->spbah, spaact_phys >> 32);
  229. out_be32(&regs->spbal, (uint32_t)spaact_phys);
  230. out_be32(&regs->splah, spaact_lim >> 32);
  231. out_be32(&regs->splal, (uint32_t)spaact_lim);
  232. }
  233. sync();
  234. base_addr += PAMU_OFFSET;
  235. }
  236. return 0;
  237. }
  238. void pamu_enable(void)
  239. {
  240. u32 i = 0;
  241. u32 base_addr = CONFIG_SYS_PAMU_ADDR;
  242. for (i = 0; i < CONFIG_NUM_PAMU; i++) {
  243. setbits_be32((void *)base_addr + PAMU_PCR_OFFSET,
  244. PAMU_PCR_PE);
  245. sync();
  246. base_addr += PAMU_OFFSET;
  247. }
  248. }
  249. void pamu_reset(void)
  250. {
  251. u32 i = 0;
  252. u32 base_addr = CONFIG_SYS_PAMU_ADDR;
  253. struct ccsr_pamu *regs;
  254. for (i = 0; i < CONFIG_NUM_PAMU; i++) {
  255. regs = (struct ccsr_pamu *)base_addr;
  256. /* Clear PPAACT Base register */
  257. out_be32(&regs->ppbah, 0);
  258. out_be32(&regs->ppbal, 0);
  259. out_be32(&regs->pplah, 0);
  260. out_be32(&regs->pplal, 0);
  261. out_be32(&regs->spbah, 0);
  262. out_be32(&regs->spbal, 0);
  263. out_be32(&regs->splah, 0);
  264. out_be32(&regs->splal, 0);
  265. clrbits_be32((void *)regs + PAMU_PCR_OFFSET, PAMU_PCR_PE);
  266. sync();
  267. base_addr += PAMU_OFFSET;
  268. }
  269. }
  270. void pamu_disable(void)
  271. {
  272. u32 i = 0;
  273. u32 base_addr = CONFIG_SYS_PAMU_ADDR;
  274. for (i = 0; i < CONFIG_NUM_PAMU; i++) {
  275. clrbits_be32((void *)base_addr + PAMU_PCR_OFFSET, PAMU_PCR_PE);
  276. sync();
  277. base_addr += PAMU_OFFSET;
  278. }
  279. }
  280. static uint64_t find_max(uint64_t arr[], int num)
  281. {
  282. int i = 0;
  283. int max = 0;
  284. for (i = 1 ; i < num; i++)
  285. if (arr[max] < arr[i])
  286. max = i;
  287. return arr[max];
  288. }
  289. static uint64_t find_min(uint64_t arr[], int num)
  290. {
  291. int i = 0;
  292. int min = 0;
  293. for (i = 1 ; i < num; i++)
  294. if (arr[min] > arr[i])
  295. min = i;
  296. return arr[min];
  297. }
  298. static uint32_t get_win_cnt(uint64_t size)
  299. {
  300. uint32_t win_cnt = DEFAULT_NUM_SUBWINDOWS;
  301. while (win_cnt && (size/win_cnt) < PAMU_PAGE_SIZE)
  302. win_cnt >>= 1;
  303. return win_cnt;
  304. }
  305. int config_pamu(struct pamu_addr_tbl *tbl, int num_entries, uint32_t liodn)
  306. {
  307. int i = 0;
  308. int ret = 0;
  309. uint32_t num_sec_windows = 0;
  310. uint32_t num_windows = 0;
  311. uint64_t min_addr, max_addr;
  312. uint64_t size;
  313. uint64_t subwin_size;
  314. int sizebit;
  315. min_addr = find_min(tbl->start_addr, num_entries);
  316. max_addr = find_max(tbl->end_addr, num_entries);
  317. size = max_addr - min_addr + 1;
  318. if (!size)
  319. return -1;
  320. sizebit = __ilog2_roundup_64(size);
  321. size = 1 << sizebit;
  322. debug("min start_addr is %llx\n", min_addr);
  323. debug("max end_addr is %llx\n", max_addr);
  324. debug("size found is %llx\n", size);
  325. if (size < PAMU_PAGE_SIZE)
  326. size = PAMU_PAGE_SIZE;
  327. while (1) {
  328. min_addr = min_addr & ~(size - 1);
  329. if (min_addr + size > max_addr)
  330. break;
  331. size <<= 1;
  332. if (!size)
  333. return -1;
  334. }
  335. debug("PAACT :Base addr is %llx\n", min_addr);
  336. debug("PAACT : Size is %llx\n", size);
  337. num_windows = get_win_cnt(size);
  338. /* For a single window, no spaact entries are required
  339. * sec_sub_window count = 0 */
  340. if (num_windows > 1)
  341. num_sec_windows = num_windows;
  342. else
  343. num_sec_windows = 0;
  344. ret = pamu_config_ppaace(liodn, min_addr,
  345. size , -1, -1, -1, num_sec_windows);
  346. if (ret < 0)
  347. return ret;
  348. debug("configured ppace\n");
  349. if (num_sec_windows) {
  350. subwin_size = size >> count_lsb_zeroes(num_sec_windows);
  351. debug("subwin_size is %llx\n", subwin_size);
  352. for (i = 0; i < num_entries; i++) {
  353. ret = pamu_config_spaace(liodn,
  354. subwin_size, tbl->start_addr[i] - min_addr,
  355. tbl->size[i], -1, -1, -1);
  356. if (ret < 0)
  357. return ret;
  358. }
  359. }
  360. return ret;
  361. }