1 /* 2 * Copyright 2008-2011 Freescale Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <asm/processor.h> 9 #include <ioports.h> 10 #include <lmb.h> 11 #include <asm/io.h> 12 #include <asm/mmu.h> 13 #include <asm/fsl_law.h> 14 #include <asm/fsl_ddr_sdram.h> 15 #include "mp.h" 16 17 DECLARE_GLOBAL_DATA_PTR; 18 u32 fsl_ddr_get_intl3r(void); 19 20 extern u32 __spin_table[]; 21 22 u32 get_my_id() 23 { 24 return mfspr(SPRN_PIR); 25 } 26 27 /* 28 * Determine if U-Boot should keep secondary cores in reset, or let them out 29 * of reset and hold them in a spinloop 30 */ 31 int hold_cores_in_reset(int verbose) 32 { 33 /* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */ 34 if (getenv_yesno("mp_holdoff") == 1) { 35 if (verbose) { 36 puts("Secondary cores are being held in reset.\n"); 37 puts("See 'mp_holdoff' environment variable\n"); 38 } 39 40 return 1; 41 } 42 43 return 0; 44 } 45 46 int cpu_reset(int nr) 47 { 48 volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR); 49 out_be32(&pic->pir, 1 << nr); 50 /* the dummy read works around an errata on early 85xx MP PICs */ 51 (void)in_be32(&pic->pir); 52 out_be32(&pic->pir, 0x0); 53 54 return 0; 55 } 56 57 int cpu_status(int nr) 58 { 59 u32 *table, id = get_my_id(); 60 61 if (hold_cores_in_reset(1)) 62 return 0; 63 64 if (nr == id) { 65 table = (u32 *)&__spin_table; 66 printf("table base @ 0x%p\n", table); 67 } else if (is_core_disabled(nr)) { 68 puts("Disabled\n"); 69 } else { 70 table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY; 71 printf("Running on cpu %d\n", id); 72 printf("\n"); 73 printf("table @ 0x%p\n", table); 74 printf(" addr - 0x%08x\n", table[BOOT_ENTRY_ADDR_LOWER]); 75 printf(" r3 - 0x%08x\n", table[BOOT_ENTRY_R3_LOWER]); 76 printf(" pir - 0x%08x\n", table[BOOT_ENTRY_PIR]); 77 } 78 79 return 0; 80 } 81 82 #ifdef CONFIG_FSL_CORENET 83 int cpu_disable(int nr) 84 { 85 volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 86 87 setbits_be32(&gur->coredisrl, 1 << nr); 88 89 return 0; 90 } 91 92 int is_core_disabled(int nr) { 93 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 94 u32 coredisrl = in_be32(&gur->coredisrl); 95 96 return (coredisrl & (1 << nr)); 97 } 98 #else 99 int cpu_disable(int nr) 100 { 101 volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 102 103 switch (nr) { 104 case 0: 105 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU0); 106 break; 107 case 1: 108 setbits_be32(&gur->devdisr, MPC85xx_DEVDISR_CPU1); 109 break; 110 default: 111 printf("Invalid cpu number for disable %d\n", nr); 112 return 1; 113 } 114 115 return 0; 116 } 117 118 int is_core_disabled(int nr) { 119 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 120 u32 devdisr = in_be32(&gur->devdisr); 121 122 switch (nr) { 123 case 0: 124 return (devdisr & MPC85xx_DEVDISR_CPU0); 125 case 1: 126 return (devdisr & MPC85xx_DEVDISR_CPU1); 127 default: 128 printf("Invalid cpu number for disable %d\n", nr); 129 } 130 131 return 0; 132 } 133 #endif 134 135 static u8 boot_entry_map[4] = { 136 0, 137 BOOT_ENTRY_PIR, 138 BOOT_ENTRY_R3_LOWER, 139 }; 140 141 int cpu_release(int nr, int argc, char * const argv[]) 142 { 143 u32 i, val, *table = (u32 *)&__spin_table + nr * NUM_BOOT_ENTRY; 144 u64 boot_addr; 145 146 if (hold_cores_in_reset(1)) 147 return 0; 148 149 if (nr == get_my_id()) { 150 printf("Invalid to release the boot core.\n\n"); 151 return 1; 152 } 153 154 if (argc != 4) { 155 printf("Invalid number of arguments to release.\n\n"); 156 return 1; 157 } 158 159 boot_addr = simple_strtoull(argv[0], NULL, 16); 160 161 /* handle pir, r3 */ 162 for (i = 1; i < 3; i++) { 163 if (argv[i][0] != '-') { 164 u8 entry = boot_entry_map[i]; 165 val = simple_strtoul(argv[i], NULL, 16); 166 table[entry] = val; 167 } 168 } 169 170 table[BOOT_ENTRY_ADDR_UPPER] = (u32)(boot_addr >> 32); 171 172 /* ensure all table updates complete before final address write */ 173 eieio(); 174 175 table[BOOT_ENTRY_ADDR_LOWER] = (u32)(boot_addr & 0xffffffff); 176 177 return 0; 178 } 179 180 u32 determine_mp_bootpg(unsigned int *pagesize) 181 { 182 u32 bootpg; 183 #ifdef CONFIG_SYS_FSL_ERRATUM_A004468 184 u32 svr = get_svr(); 185 u32 granule_size, check; 186 struct law_entry e; 187 #endif 188 189 190 /* use last 4K of mapped memory */ 191 bootpg = ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ? 192 CONFIG_MAX_MEM_MAPPED : gd->ram_size) + 193 CONFIG_SYS_SDRAM_BASE - 4096; 194 if (pagesize) 195 *pagesize = 4096; 196 197 #ifdef CONFIG_SYS_FSL_ERRATUM_A004468 198 /* 199 * Erratum A004468 has two parts. The 3-way interleaving applies to T4240, 200 * to be fixed in rev 2.0. The 2-way interleaving applies to many SoCs. But 201 * the way boot page chosen in u-boot avoids hitting this erratum. So only 202 * thw workaround for 3-way interleaving is needed. 203 * 204 * To make sure boot page translation works with 3-Way DDR interleaving 205 * enforce a check for the following constrains 206 * 8K granule size requires BRSIZE=8K and 207 * bootpg >> log2(BRSIZE) %3 == 1 208 * 4K and 1K granule size requires BRSIZE=4K and 209 * bootpg >> log2(BRSIZE) %3 == 0 210 */ 211 if (SVR_SOC_VER(svr) == SVR_T4240 && SVR_MAJ(svr) < 2) { 212 e = find_law(bootpg); 213 switch (e.trgt_id) { 214 case LAW_TRGT_IF_DDR_INTLV_123: 215 granule_size = fsl_ddr_get_intl3r() & 0x1f; 216 if (granule_size == FSL_DDR_3WAY_8KB_INTERLEAVING) { 217 if (pagesize) 218 *pagesize = 8192; 219 bootpg &= 0xffffe000; /* align to 8KB */ 220 check = bootpg >> 13; 221 while ((check % 3) != 1) 222 check--; 223 bootpg = check << 13; 224 debug("Boot page (8K) at 0x%08x\n", bootpg); 225 break; 226 } else { 227 bootpg &= 0xfffff000; /* align to 4KB */ 228 check = bootpg >> 12; 229 while ((check % 3) != 0) 230 check--; 231 bootpg = check << 12; 232 debug("Boot page (4K) at 0x%08x\n", bootpg); 233 } 234 break; 235 default: 236 break; 237 } 238 } 239 #endif /* CONFIG_SYS_FSL_ERRATUM_A004468 */ 240 241 return bootpg; 242 } 243 244 phys_addr_t get_spin_phys_addr(void) 245 { 246 return virt_to_phys(&__spin_table); 247 } 248 249 #ifdef CONFIG_FSL_CORENET 250 static void plat_mp_up(unsigned long bootpg, unsigned int pagesize) 251 { 252 u32 cpu_up_mask, whoami, brsize = LAW_SIZE_4K; 253 u32 *table = (u32 *)&__spin_table; 254 volatile ccsr_gur_t *gur; 255 volatile ccsr_local_t *ccm; 256 volatile ccsr_rcpm_t *rcpm; 257 volatile ccsr_pic_t *pic; 258 int timeout = 10; 259 u32 mask = cpu_mask(); 260 struct law_entry e; 261 262 gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 263 ccm = (void *)(CONFIG_SYS_FSL_CORENET_CCM_ADDR); 264 rcpm = (void *)(CONFIG_SYS_FSL_CORENET_RCPM_ADDR); 265 pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR); 266 267 whoami = in_be32(&pic->whoami); 268 cpu_up_mask = 1 << whoami; 269 out_be32(&ccm->bstrl, bootpg); 270 271 e = find_law(bootpg); 272 /* pagesize is only 4K or 8K */ 273 if (pagesize == 8192) 274 brsize = LAW_SIZE_8K; 275 out_be32(&ccm->bstrar, LAW_EN | e.trgt_id << 20 | brsize); 276 debug("BRSIZE is 0x%x\n", brsize); 277 278 /* readback to sync write */ 279 in_be32(&ccm->bstrar); 280 281 /* disable time base at the platform */ 282 out_be32(&rcpm->ctbenrl, cpu_up_mask); 283 284 out_be32(&gur->brrl, mask); 285 286 /* wait for everyone */ 287 while (timeout) { 288 unsigned int i, cpu, nr_cpus = cpu_numcores(); 289 290 for_each_cpu(i, cpu, nr_cpus, mask) { 291 if (table[cpu * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER]) 292 cpu_up_mask |= (1 << cpu); 293 } 294 295 if ((cpu_up_mask & mask) == mask) 296 break; 297 298 udelay(100); 299 timeout--; 300 } 301 302 if (timeout == 0) 303 printf("CPU up timeout. CPU up mask is %x should be %x\n", 304 cpu_up_mask, mask); 305 306 /* enable time base at the platform */ 307 out_be32(&rcpm->ctbenrl, 0); 308 309 /* readback to sync write */ 310 in_be32(&rcpm->ctbenrl); 311 312 mtspr(SPRN_TBWU, 0); 313 mtspr(SPRN_TBWL, 0); 314 315 out_be32(&rcpm->ctbenrl, mask); 316 317 #ifdef CONFIG_MPC8xxx_DISABLE_BPTR 318 /* 319 * Disabling Boot Page Translation allows the memory region 0xfffff000 320 * to 0xffffffff to be used normally. Leaving Boot Page Translation 321 * enabled remaps 0xfffff000 to SDRAM which makes that memory region 322 * unusable for normal operation but it does allow OSes to easily 323 * reset a processor core to put it back into U-Boot's spinloop. 324 */ 325 clrbits_be32(&ccm->bstrar, LAW_EN); 326 #endif 327 } 328 #else 329 static void plat_mp_up(unsigned long bootpg, unsigned int pagesize) 330 { 331 u32 up, cpu_up_mask, whoami; 332 u32 *table = (u32 *)&__spin_table; 333 volatile u32 bpcr; 334 volatile ccsr_local_ecm_t *ecm = (void *)(CONFIG_SYS_MPC85xx_ECM_ADDR); 335 volatile ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 336 volatile ccsr_pic_t *pic = (void *)(CONFIG_SYS_MPC8xxx_PIC_ADDR); 337 u32 devdisr; 338 int timeout = 10; 339 340 whoami = in_be32(&pic->whoami); 341 out_be32(&ecm->bptr, 0x80000000 | (bootpg >> 12)); 342 343 /* disable time base at the platform */ 344 devdisr = in_be32(&gur->devdisr); 345 if (whoami) 346 devdisr |= MPC85xx_DEVDISR_TB0; 347 else 348 devdisr |= MPC85xx_DEVDISR_TB1; 349 out_be32(&gur->devdisr, devdisr); 350 351 /* release the hounds */ 352 up = ((1 << cpu_numcores()) - 1); 353 bpcr = in_be32(&ecm->eebpcr); 354 bpcr |= (up << 24); 355 out_be32(&ecm->eebpcr, bpcr); 356 asm("sync; isync; msync"); 357 358 cpu_up_mask = 1 << whoami; 359 /* wait for everyone */ 360 while (timeout) { 361 int i; 362 for (i = 0; i < cpu_numcores(); i++) { 363 if (table[i * NUM_BOOT_ENTRY + BOOT_ENTRY_ADDR_LOWER]) 364 cpu_up_mask |= (1 << i); 365 }; 366 367 if ((cpu_up_mask & up) == up) 368 break; 369 370 udelay(100); 371 timeout--; 372 } 373 374 if (timeout == 0) 375 printf("CPU up timeout. CPU up mask is %x should be %x\n", 376 cpu_up_mask, up); 377 378 /* enable time base at the platform */ 379 if (whoami) 380 devdisr |= MPC85xx_DEVDISR_TB1; 381 else 382 devdisr |= MPC85xx_DEVDISR_TB0; 383 out_be32(&gur->devdisr, devdisr); 384 385 /* readback to sync write */ 386 in_be32(&gur->devdisr); 387 388 mtspr(SPRN_TBWU, 0); 389 mtspr(SPRN_TBWL, 0); 390 391 devdisr &= ~(MPC85xx_DEVDISR_TB0 | MPC85xx_DEVDISR_TB1); 392 out_be32(&gur->devdisr, devdisr); 393 394 #ifdef CONFIG_MPC8xxx_DISABLE_BPTR 395 /* 396 * Disabling Boot Page Translation allows the memory region 0xfffff000 397 * to 0xffffffff to be used normally. Leaving Boot Page Translation 398 * enabled remaps 0xfffff000 to SDRAM which makes that memory region 399 * unusable for normal operation but it does allow OSes to easily 400 * reset a processor core to put it back into U-Boot's spinloop. 401 */ 402 clrbits_be32(&ecm->bptr, 0x80000000); 403 #endif 404 } 405 #endif 406 407 void cpu_mp_lmb_reserve(struct lmb *lmb) 408 { 409 u32 bootpg = determine_mp_bootpg(NULL); 410 411 lmb_reserve(lmb, bootpg, 4096); 412 } 413 414 void setup_mp(void) 415 { 416 extern u32 __secondary_start_page; 417 extern u32 __bootpg_addr, __spin_table_addr, __second_half_boot_page; 418 419 int i; 420 ulong fixup = (u32)&__secondary_start_page; 421 u32 bootpg, bootpg_map, pagesize; 422 423 bootpg = determine_mp_bootpg(&pagesize); 424 425 /* 426 * pagesize is only 4K or 8K 427 * we only use the last 4K of boot page 428 * bootpg_map saves the address for the boot page 429 * 8K is used for the workaround of 3-way DDR interleaving 430 */ 431 432 bootpg_map = bootpg; 433 434 if (pagesize == 8192) 435 bootpg += 4096; /* use 2nd half */ 436 437 /* Some OSes expect secondary cores to be held in reset */ 438 if (hold_cores_in_reset(0)) 439 return; 440 441 /* 442 * Store the bootpg's cache-able half address for use by secondary 443 * CPU cores to continue to boot 444 */ 445 __bootpg_addr = (u32)virt_to_phys(&__second_half_boot_page); 446 447 /* Store spin table's physical address for use by secondary cores */ 448 __spin_table_addr = (u32)get_spin_phys_addr(); 449 450 /* flush bootpg it before copying invalidate any staled cacheline */ 451 flush_cache(bootpg, 4096); 452 453 /* look for the tlb covering the reset page, there better be one */ 454 i = find_tlb_idx((void *)CONFIG_BPTR_VIRT_ADDR, 1); 455 456 /* we found a match */ 457 if (i != -1) { 458 /* map reset page to bootpg so we can copy code there */ 459 disable_tlb(i); 460 461 set_tlb(1, CONFIG_BPTR_VIRT_ADDR, bootpg, /* tlb, epn, rpn */ 462 MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, /* perms, wimge */ 463 0, i, BOOKE_PAGESZ_4K, 1); /* ts, esel, tsize, iprot */ 464 465 memcpy((void *)CONFIG_BPTR_VIRT_ADDR, (void *)fixup, 4096); 466 467 plat_mp_up(bootpg_map, pagesize); 468 } else { 469 puts("WARNING: No reset page TLB. " 470 "Skipping secondary core setup\n"); 471 } 472 } 473