fsl_pamu.c 10 KB

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