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 ppaact = memalign(PAMU_TABLE_ALIGNMENT, ppaact_size); 243 if (!ppaact) 244 return -1; 245 memset(ppaact, 0, ppaact_size); 246 247 /* Allocate space for Secondary PAACT Table */ 248 sec = memalign(PAMU_TABLE_ALIGNMENT, spaact_size); 249 if (!sec) 250 return -1; 251 memset(sec, 0, spaact_size); 252 253 ppaact_phys = virt_to_phys((void *)ppaact); 254 ppaact_lim = ppaact_phys + ppaact_size; 255 256 spaact_phys = (uint64_t)virt_to_phys((void *)sec); 257 spaact_lim = spaact_phys + spaact_size; 258 259 /* Configure all PAMU's */ 260 for (i = 0; i < CONFIG_NUM_PAMU; i++) { 261 regs = (struct ccsr_pamu *)base_addr; 262 263 out_be32(®s->ppbah, ppaact_phys >> 32); 264 out_be32(®s->ppbal, (uint32_t)ppaact_phys); 265 266 out_be32(®s->pplah, (ppaact_lim) >> 32); 267 out_be32(®s->pplal, (uint32_t)ppaact_lim); 268 269 if (sec != NULL) { 270 out_be32(®s->spbah, spaact_phys >> 32); 271 out_be32(®s->spbal, (uint32_t)spaact_phys); 272 out_be32(®s->splah, spaact_lim >> 32); 273 out_be32(®s->splal, (uint32_t)spaact_lim); 274 } 275 asm volatile("sync" : : : "memory"); 276 277 base_addr += PAMU_OFFSET; 278 } 279 280 return 0; 281 } 282 283 void pamu_enable(void) 284 { 285 u32 i = 0; 286 u32 base_addr = CONFIG_SYS_PAMU_ADDR; 287 for (i = 0; i < CONFIG_NUM_PAMU; i++) { 288 setbits_be32((void *)base_addr + PAMU_PCR_OFFSET, 289 PAMU_PCR_PE); 290 asm volatile("sync" : : : "memory"); 291 base_addr += PAMU_OFFSET; 292 } 293 } 294 295 void pamu_reset(void) 296 { 297 u32 i = 0; 298 u32 base_addr = CONFIG_SYS_PAMU_ADDR; 299 struct ccsr_pamu *regs; 300 301 for (i = 0; i < CONFIG_NUM_PAMU; i++) { 302 regs = (struct ccsr_pamu *)base_addr; 303 /* Clear PPAACT Base register */ 304 out_be32(®s->ppbah, 0); 305 out_be32(®s->ppbal, 0); 306 out_be32(®s->pplah, 0); 307 out_be32(®s->pplal, 0); 308 out_be32(®s->spbah, 0); 309 out_be32(®s->spbal, 0); 310 out_be32(®s->splah, 0); 311 out_be32(®s->splal, 0); 312 313 clrbits_be32((void *)regs + PAMU_PCR_OFFSET, PAMU_PCR_PE); 314 asm volatile("sync" : : : "memory"); 315 base_addr += PAMU_OFFSET; 316 } 317 } 318 319 void pamu_disable(void) 320 { 321 u32 i = 0; 322 u32 base_addr = CONFIG_SYS_PAMU_ADDR; 323 324 325 for (i = 0; i < CONFIG_NUM_PAMU; i++) { 326 clrbits_be32((void *)base_addr + PAMU_PCR_OFFSET, PAMU_PCR_PE); 327 asm volatile("sync" : : : "memory"); 328 base_addr += PAMU_OFFSET; 329 } 330 } 331 332 333 static uint64_t find_max(uint64_t arr[], int num) 334 { 335 int i = 0; 336 int max = 0; 337 for (i = 1 ; i < num; i++) 338 if (arr[max] < arr[i]) 339 max = i; 340 341 return arr[max]; 342 } 343 344 static uint64_t find_min(uint64_t arr[], int num) 345 { 346 int i = 0; 347 int min = 0; 348 for (i = 1 ; i < num; i++) 349 if (arr[min] > arr[i]) 350 min = i; 351 352 return arr[min]; 353 } 354 355 static uint32_t get_win_cnt(uint64_t size) 356 { 357 uint32_t win_cnt = DEFAULT_NUM_SUBWINDOWS; 358 359 while (win_cnt && (size/win_cnt) < PAMU_PAGE_SIZE) 360 win_cnt >>= 1; 361 362 return win_cnt; 363 } 364 365 int config_pamu(struct pamu_addr_tbl *tbl, int num_entries, uint32_t liodn) 366 { 367 int i = 0; 368 int ret = 0; 369 uint32_t num_sec_windows = 0; 370 uint32_t num_windows = 0; 371 uint64_t min_addr, max_addr; 372 uint64_t size; 373 uint64_t subwin_size; 374 int sizebit; 375 376 min_addr = find_min(tbl->start_addr, num_entries); 377 max_addr = find_max(tbl->end_addr, num_entries); 378 size = max_addr - min_addr + 1; 379 380 if (!size) 381 return -1; 382 383 sizebit = __ilog2_roundup_64(size); 384 size = 1 << sizebit; 385 debug("min start_addr is %llx\n", min_addr); 386 debug("max end_addr is %llx\n", max_addr); 387 debug("size found is %llx\n", size); 388 389 if (size < PAMU_PAGE_SIZE) 390 size = PAMU_PAGE_SIZE; 391 392 while (1) { 393 min_addr = min_addr & ~(size - 1); 394 if (min_addr + size > max_addr) 395 break; 396 size <<= 1; 397 if (!size) 398 return -1; 399 } 400 debug("PAACT :Base addr is %llx\n", min_addr); 401 debug("PAACT : Size is %llx\n", size); 402 num_windows = get_win_cnt(size); 403 /* For a single window, no spaact entries are required 404 * sec_sub_window count = 0 */ 405 if (num_windows > 1) 406 num_sec_windows = num_windows; 407 else 408 num_sec_windows = 0; 409 410 ret = pamu_config_ppaace(liodn, min_addr, 411 size , -1, -1, -1, num_sec_windows); 412 413 if (ret < 0) 414 return ret; 415 416 debug("configured ppace\n"); 417 418 if (num_sec_windows) { 419 subwin_size = size >> count_lsb_zeroes(num_sec_windows); 420 debug("subwin_size is %llx\n", subwin_size); 421 422 for (i = 0; i < num_entries; i++) { 423 ret = pamu_config_spaace(liodn, 424 subwin_size, tbl->start_addr[i] - min_addr, 425 tbl->size[i], -1, -1, -1); 426 427 if (ret < 0) 428 return ret; 429 } 430 } 431 432 return ret; 433 } 434