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