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