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