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