1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * CPU init module File: sb1250_altcpu.S 5 * 6 * Secondary core startup routines for CFE 7 * 8 * Author: Mitch Lichtenberg 9 * 10 ********************************************************************* 11 * 12 * Copyright 2000,2001,2002,2003 13 * Broadcom Corporation. All rights reserved. 14 * 15 * This software is furnished under license and may be used and 16 * copied only in accordance with the following terms and 17 * conditions. Subject to these conditions, you may download, 18 * copy, install, use, modify and distribute modified or unmodified 19 * copies of this software in source and/or binary form. No title 20 * or ownership is transferred hereby. 21 * 22 * 1) Any source code used, modified or distributed must reproduce 23 * and retain this copyright notice and list of conditions 24 * as they appear in the source file. 25 * 26 * 2) No right is granted to use any trade name, trademark, or 27 * logo of Broadcom Corporation. The "Broadcom Corporation" 28 * name may not be used to endorse or promote products derived 29 * from this software without the prior written permission of 30 * Broadcom Corporation. 31 * 32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 44 * THE POSSIBILITY OF SUCH DAMAGE. 45 ********************************************************************* */ 46 47#include "sbmips.h" 48#include "exception.h" 49 50#include "bsp_config.h" 51 52#ifdef _CFE_ 53#include "cfe_devfuncs.h" 54#else 55#define CFE_EPTSEAL 0x43464531 56#endif 57 58#include "sb1250_defs.h" 59#include "sb1250_regs.h" 60#include "sb1250_scd.h" 61 62#include "cpu_config.h" 63 64/* ********************************************************************* 65 * Macros 66 ********************************************************************* */ 67 68#include "mipsmacros.h" 69 70#define SETLEDS1(a,b,c,d) \ 71 li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ 72 JAL_KSEG1(board_setleds) 73#define SETLEDS(a,b,c,d) \ 74 li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ 75 JAL(board_setleds) 76 77 78/* ********************************************************************* 79 * Initialized Data 80 ********************************************************************* */ 81 82 .sdata 83 84/* 85 * Initial start addresses for secondary CPUs 86 */ 87 88 .globl cpu_startvectors 89cpu_startvectors: 90 .dword 0 # cpu #0 (not used) 91 .dword 0 # cpu #1 92 93/* 94 * Initial values for SP, GP, and A1 (user argument) 95 */ 96 97cpu_start_spvals: 98 .dword 0 # cpu #0 (not used) 99 .dword 0 # cpu #1 100 101cpu_start_gpvals: 102 .dword 0 # cpu #0 (not used) 103 .dword 0 # cpu #1 104 105cpu_start_args: 106 .dword 0 # cpu #0 (not used) 107 .dword 0 # cpu #1 108 109 110 .extern mem_datareloc 111 112 113/* ********************************************************************* 114 * Linkage Tables 115 * 116 * This table contains pointers to routines in other modules. 117 * we do things this way so we can stay position-independent and 118 * also avoid problems with the limitations of relative branching. 119 ********************************************************************* */ 120 121 .text 122 123 .set mips64 124 125/* ********************************************************************* 126 * ALTCPU_KSEG1_SWITCH 127 * 128 * Hack the return address so we will come back in KSEG1 (uncached) 129 * 130 * Input parameters: 131 * nothing 132 * 133 * Return value: 134 * nothing 135 ********************************************************************* */ 136 137altcpu_kseg1_switch: 138 139 and ra,(K0SIZE-1) 140 or ra,K1BASE 141 jr ra 142 143 144/* ********************************************************************* 145 * ALTCPU_KSEG0_SWITCH 146 * 147 * Hack the return address so we will come back in KSEG0 148 * 149 * Input parameters: 150 * nothing 151 * 152 * Return value: 153 * nothing 154 ********************************************************************* */ 155 156altcpu_kseg0_switch: 157 158 and ra,(K0SIZE-1) 159 or ra,K0BASE 160 jr ra 161 162 163/* ********************************************************************* 164 * SB1250_ALTCPU_START1 165 * 166 * Start secondary processor(s). These processors will start 167 * running the code at ALTCPU_RESET (see below). We wait here 168 * for the secondary processor(s) to finish their cache 169 * initialization and then return. 170 * 171 * This routine is normally run from KSEG1 172 * 173 * Input parameters: 174 * nothing 175 * 176 * Return value: 177 * nothing 178 ********************************************************************* */ 179 180LEAF(sb1250_altcpu_start1) 181 182 /* 183 * Don't do this if we have only one CPU. This way we can 184 * support running the multiprocessor version of CFE 185 * with only one core. 186 */ 187 188sb1250_altcpu_start1a: 189 190 la t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION) 191 ld t0,(t0) # Get system revision 192 dsrl t0,S_SYS_PART # Shift part # to low bits 193 dsrl t0,8 # isolate CPU part of number 194 and t0,0x0F # T0 = number of CPUs 195 bgt t0,1,1f # Keep going if more than one CPU 196 j ra # Go back home, nothing to do 1971: 198 199 /* 200 * Clear out our mailbox registers (both CPUs) 201 */ 202 203 la a0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CLR_CPU)) 204 dli t0,-1 # clear all 64 bits 205 sd t0,(a0) 206 la a0,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_CLR_CPU)) 207 sd t0,(a0) 208 209 /* 210 * Let the secondary CPU(s) out of reset 211 * 212 * XXX This is very SB1250-specific at the moment. 213 */ 214 215 la a0,PHYS_TO_K1(A_SCD_SYSTEM_CFG) 216 ld t0,0(a0) 217 dli t1,M_SYS_CPU_RESET_1 # Reset mask 218 not t1 # clear this bit 219 and t0,t1 # New value to write 220 sd t0,0(a0) # CPU1 is now running 221 222 /* 223 * Wait for the other CPU to ring our doorbell 224 */ 225 226 2271: la a0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CPU)); 228 ld t0,(a0) # Read mailbox 229 beq t0,zero,1b # Loop till the bit is set 230 231 /* 232 * Clear the mailbox to dismiss the pending interrupts 233 */ 234 235 la a0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CLR_CPU)) 236 dli t0,-1 # clear all 64 bits 237 sd t0,(a0) 238 239 /* 240 * Okay, it's safe to return 241 */ 242 243 j ra 244 245 246END(sb1250_altcpu_start1) 247 248/* ********************************************************************* 249 * SB1250_ALTCPU_START2 250 * 251 * Finish startup of secondary processor(s) - we pass the relocation 252 * offset to the other CPUs here, and the CPUs relocate their 253 * data segments and go to the idle loop. 254 * 255 * This routine is normally run from KSEG0 256 * 257 * Input parameters: 258 * a0 - data relocation offset (0=none) 259 * 260 * Return value: 261 * nothing 262 ********************************************************************* */ 263 264LEAF(sb1250_altcpu_start2) 265 266 /* 267 * Don't do this if we have only one CPU. 268 */ 269 270 la t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION) 271 ld t0,(t0) # Get system revision 272 dsrl t0,S_SYS_PART # Shift part # to low bits 273 dsrl t0,8 # isolate CPU part of number 274 and t0,0x0F # T0 = number of CPUs 275 bgt t0,1,1f # Keep going if more than one CPU 276 j ra # Go back home, nothing to do 2771: 278 279 /* 280 * Let secondary CPU(s) run their idle loops. Set the 281 * mailbox register to our relocation factor so we can read 282 * it out of the mailbox register and relocate GP properly. 283 */ 284 285 la t1,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_SET_CPU)) 286 or t0,a0,1 # hack - make sure reloc is nonzero 287 sd t0,0(t1) # Write to mailbox register 288 289 j ra 290 291END(sb1250_altcpu_start2) 292 293/* ********************************************************************* 294 * SB1250_ALTCPU_KILL 295 * 296 * Kill a secondary CPU, causing it to return to the idle 297 * loop. We do this by switching to uncached mode, 298 * asserting RESET on the other CPU, and then re-run 299 * ALTCPU_START again. 300 * 301 * Input parameters: 302 * nothing 303 * 304 * Return value: 305 * nothing 306 ********************************************************************* */ 307 308LEAF(sb1250_altcpu_kill) 309 310 /* 311 * Don't do this if we have only one CPU. 312 */ 313 314 la t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION) 315 ld t0,(t0) # Get system revision 316 dsrl t0,S_SYS_PART # Shift part # to low bits 317 dsrl t0,8 # isolate CPU part of number 318 and t0,0x0F # T0 = number of CPUs 319 bgt t0,1,1f # Keep going if more than one CPU 320 j ra # Go back home, nothing to do 3211: 322 323 /* 324 * More than one CPU, go ahead... 325 */ 326 327 move t7,ra # save RA, we'll make calls 328 329#ifdef _SB1250_PASS1_WORKAROUNDS_ 330 # 331 # Not sure what we need to do here wrt cacheability of 332 # the genbus space, if anything. Some portion of CPU1's 333 # istream will come from L1, but the data should all be from 334 # DRAM. These references will be cacheable noncoherent, 335 # should we worry if cpu0 is coherent shared at this time? 336 # probably. 337 # 338#endif 339 340 la t1,cpu_startvectors 341 sd zero,8(t1) # Reset address of CPU1 (2nd entry in table) 342 343 # 344 # Flush the D cache to ensure that the write above made it 345 # out of our L1. 346 # 347 348 JAL(sb1250_l1cache_flush_d) # uses t0, t2, t3 349 350 # 351 # Switch to KSEG1 to quiesce our cache activity. 352 # 353 354 bal altcpu_kseg1_switch # switch to uncached mode 355 356 # 357 # Force CPU1 into reset 358 # 359 360 li a0,PHYS_TO_K1(A_SCD_SYSTEM_CFG) 361 ld t0,0(a0) 362 dli t1,M_SYS_CPU_RESET_1 # Reset mask 363 or t0,t1 # New value to write 364 sd t0,0(a0) # CPU1 is now in reset 365 366 # 367 # Not sure how long we're supposed to wait. 368 # 369 ssnop 370 ssnop 371 ssnop 372 ssnop 373 374 # 375 # Now restart CPU1 376 # 377 378 bal sb1250_altcpu_start1a 379 380 # 381 # It's safe to be cached again. 382 # 383 384 bal altcpu_kseg0_switch 385 386 # 387 # At this point, CPU1 is waiting for us to indicate that it's 388 # okay to use memory again. Ring its doorbell. 389 # 390 391 la a0,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_SET_CPU)) 392 LR t0,mem_datareloc 393 or t0,1 394 sd t0,0(a0) 395 396 # 397 # CPU1 is back in our control. 398 # 399 400 move ra,t7 401 move v0,zero 402 403 j ra 404 405 406END(sb1250_altcpu_kill) 407 408 409/* ********************************************************************* 410 * ALTCPU_RESET 411 * 412 * Start address for secondary CPU(s) - do the initialization of 413 * the local CPU and then notify CPU0 that we're done. 414 * 415 * This routine is called in KSEG1. 416 * 417 * Input parameters: 418 * t0 - CPU identifier 419 * 420 * Return value: 421 * nothing 422 ********************************************************************* */ 423 424 425LEAF(sb1250_altcpu_reset) 426 427 428 mfc0 t0,C0_PRID # get CPU PRID register 429 and t0,t0,0xe000000 # determine cpu number 430 beq t0,zero,iscpu0 # go if on CPU0 431 432 433#if CFG_RELOC 434 /* 435 * SVR4 PIC mode: get a copy of GP for use in the boot ROM. 436 */ 437 lui gp,%hi(_gp) 438 addiu gp,%lo(_gp) 439 or gp,gp,K1BASE 440#endif 441 442 /* 443 * Note: we should never get to the CPU1 code if we're 444 * with only one CPU. Theoretically, nobody got past the 445 * check in altcpu_start. But, just in case, if we 446 * get here and we're on CPU1, and we supposedly only 447 * have one CPU, reset CPU1. 448 */ 449 450 la t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION) 451 ld t0,(t0) # Get system revision 452 dsrl t0,S_SYS_PART # Shift part # to low bits 453 dsrl t0,8 # isolate CPU part of number 454 and t0,0x0F # T0 = number of CPUs 455 beq t0,1,iscpu0 # If only one CPU, kill off CPU1 456 457 458 /* 459 * Initialize CPU registers. 460 */ 461 462 JAL_KSEG1(sb1_cpu_init) 463 464#ifdef _SB1250_PASS1_WORKAROUNDS_ 465 /* 466 * See the above note about this workaround. It's important 467 * to remain noncoherent until we're done with the flash. 468 */ 469 470 SETCCAMODE(v0,K_CFG_K0COH_CACHEABLE) /* cacheable NONCOHERENT */ 471#endif 472 473 SETLEDS1('C','P','U','1') 474 475 /* 476 * Initialize the L1 cache 477 */ 478 479#if CFG_INIT_L1 480 JAL_KSEG1(sb1250_l1cache_init) 481#endif 482 483 484 /* 485 * Notify the SCD that we're done initializing. Do this by 486 * ringing CPU0's doorbell. 487 */ 488 489 la a0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_SET_CPU)); 490 491 mfc0 t0,C0_PRID # get processor number 492 srl t0,t0,25 # shift CPU bits into low 493 and t0,t0,7 # keep only low 3 bits 494 li t1,1 # make a bit mask depending on CPU 495 sll t1,t1,t0 # calculate t1 = 1 shl cpu number 496 sd t1,0(a0) # set corresponding bit in mailbox 497 498 499 /* 500 * Go to the idle loop 501 */ 502 503 b altcpu_idle # go to idle loop 504 505 506 /* 507 * We get here if we were running on CPU0. Make things 508 * pretty for the reset of CPU initialization. 509 */ 510 511 512iscpu0: 513 514 /* 515 * If we are on CPU0, then force CPU1 into reset. This is needed 516 * for the case where the firmware has crashed and we need to get 517 * control of the system again. 518 */ 519 520 li a0,PHYS_TO_K1(A_SCD_SYSTEM_CFG) 521 ld t0,0(a0) 522 dli t1,M_SYS_CPU_RESET_1 # Reset mask 523 or t0,t1 # New value to write 524 sd t0,0(a0) # CPU1 is now in reset 525 526 j ra # return (we were on CPU 0) 527 528END(sb1250_altcpu_reset) 529 530 531/* ********************************************************************* 532 * ALTCPU_CMD_START(cpu,addr) 533 * 534 * Start an alternate CPU. 535 * 536 * Input parameters: 537 * a0 - cpu number (must be 1 for the SB1250) 538 * a1 - pointer to start parameters (four 64-bit values) 539 * array[0] = start address (PC) 540 * array[1] = start stack pointer (SP) 541 * array[2] = start global pointer (GP) 542 * array[3] = start user argument (A1) 543 * 544 * Return value: 545 * v0 - 0 if ok 546 * else -1 if request could not be handled 547 ********************************************************************* */ 548 549#define R_CPUSTART_PCVAL 0 550#define R_CPUSTART_SPVAL 8 551#define R_CPUSTART_GPVAL 16 552#define R_CPUSTART_A1VAL 24 553 554LEAF(altcpu_cmd_start) 555 556 li v0,-1 /* assume failure */ 557 bne a0,1,1f /* go if not CPU 1 */ 558 559 /* 560 * Return an error if running in uniprocessor mode. 561 */ 562 563 la t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION) 564 ld t0,(t0) # Get system revision 565 dsrl t0,S_SYS_PART # Shift part # to low bits 566 dsrl t0,8 # isolate CPU part of number 567 and t0,0x0F # T0 = number of CPUs 568 beq t0,1,1f # If only one CPU, error. 569 570 /* 571 * Multiprocessor mode, start the other CPU 572 */ 573 574 move t0,a0 /* get CPU number */ 575 sll t0,3 /* multiply by 8 for table index */ 576 577 la t1,cpu_start_gpvals 578 add t1,t0 /* copy the GP value */ 579 ld t2,R_CPUSTART_GPVAL(a1) 580 sd t2,0(t1) 581 582 la t1,cpu_start_spvals 583 add t1,t0 /* copy the SP value */ 584 ld t2,R_CPUSTART_SPVAL(a1) 585 sd t2,0(t1) 586 587 la t1,cpu_start_args 588 add t1,t0 /* copy the A1 value */ 589 ld t2,R_CPUSTART_A1VAL(a1) 590 sd t2,0(t1) 591 592 la t1,cpu_startvectors 593 add t1,t0 /* copy the PC value */ 594 ld t2,R_CPUSTART_PCVAL(a1) 595 sd t2,0(t1) 596 597 move v0,zero /* success */ 598 5991: j ra 600 601END(altcpu_cmd_start) 602 603/* ********************************************************************* 604 * ALTCPU_CMD_STOP(cpu) 605 * 606 * Stop the specified CPU. 607 * 608 * We don't really support this at the moment. 609 * 610 * Input parameters: 611 * a0 - cpu number 612 * 613 * Return value: 614 * v0 - 0 if ok, else error code 615 ********************************************************************* */ 616 617LEAF(altcpu_cmd_stop) 618 619 li v0,-1 /* assume failure */ 620 bne a0,1,1f /* go if not CPU 1 */ 621 622 /* 623 * Return an error if running in uniprocessor mode. 624 */ 625 626 la t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION) 627 ld t0,(t0) # Get system revision 628 dsrl t0,S_SYS_PART # Shift part # to low bits 629 dsrl t0,8 # isolate CPU part of number 630 and t0,0x0F # T0 = number of CPUs 631 beq t0,1,1f # If only one CPU, error. 632 633 /* 634 * Multiprocessor mode, stop the other CPU 635 */ 636 637 JMP(sb1250_altcpu_kill) /* kill the CPU */ 638 6391: j ra 640 641END(altcpu_cmd_stop) 642 643/* ********************************************************************* 644 * ALTCPU_IDLE 645 * 646 * Loop forever waiting for someone to tell us where to go. 647 * 648 * Input parameters: 649 * nothing. 650 * 651 * Return value: 652 * nothing 653 ********************************************************************* */ 654 655altcpu_idle: 656 657 /* 658 * Switch to KSEG0 (cached) 659 */ 660 661 bal altcpu_kseg0_switch 662 663#if CFG_RELOC 664 lui gp,%hi(_gp) 665 addiu gp,%lo(_gp) 666#endif 667 668 SETLEDS('c','p','u','1') 669 670 671 /* 672 * Now wait for CPU0 to ring *our* doorbell. This is our signal that 673 * it's safe to go to the idle loop. Until CPU0 rings our 674 * doorbell, we can't use memory (but we can use the cache). 675 * XXX Very SB1250 specific here. 676 */ 677 6781: la a0,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_CPU)) 679 ld t0,(a0) # Read mailbox 680 beq t0,zero,1b # Loop till the bit is set 681 682 /* 683 * Clear all the bits in the mailbox register to dismiss the 684 * pending interrupt 685 */ 686 687 la a0,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_CLR_CPU)) 688 li t1,-1 689 sd t1,0(a0) 690 691 692 /* 693 * We may need GP, especially in relocated version 694 * 695 * Yucky hack: The relocation factor was passed to us in 696 * the mailbox register, which is conveniently in t0 right now. 697 * (except the lower bit is set just in case the reloc was 698 * zero, so clear that first). 699 */ 700 701 li t1,1 # 1 702 not t1 # FFFFFFFFE 703 and t0,t1 # clear lower bit. 704 705 706#if (CFG_RELOC) 707 708 /* 709 * SVR4 PIC: GP is already set to GOT, relocate 710 * it and jump to relocated code 711 */ 712__AltCpuGoRel: 713 714 la t1,1f # Get address of where to go 715 ADDU gp,t0 # Relocate GP 716 ADDU t1,t0 # Relocate address 717 jr t1 # Go there. 718 7191: # we will go "here" in the reloc world 720#else 721 /* 722 * non-PIC: Standard GP 723 */ 724 la gp,_gp 725 ADD gp,t0 # relocate GP. 726#endif 727 728 729 /* 730 * Get our processor number 731 */ 732 733 mfc0 t0,C0_PRID # Get PRID (for processor id) 734 735 srl t0,t0,25 # shift CPU bits into low 736 and t0,t0,7 # keep only low 3 bits 737 sll t0,t0,3 # multiply by 8 for table index 738 739 /* 740 * Set up registers like we were launching a program. 741 */ 742 743 la a2,cpu_apientry # A2 = firmware entry vector 744 move a0,gp # A0 = handle 745 li a3,CFE_EPTSEAL # A3 = entrypoint signature 746 747 748#ifdef _SB1250_PASS1_WORKAROUNDS_ 749 /* 750 * Okay, it's safe now to be coherent. 751 * Flush the D cache to invalidate all the lines we have, 752 * then change the config register back. 753 * 754 * Danger! It's imperative that *no stores to memory* be done 755 * prior to this point, otherwise flushing the cache 756 * will race with core 0, which will also be flushing 757 * lines at this time. 758 */ 759 move k0,t0 760 JAL(sb1250_l1cache_flush_d) 761 SETCCAMODE(v0,K_CFG_K0COH_COHERENT) /* cacheable coherent */ 762 move t0,k0 763#endif 764 765 /* 766 * Read the start address from the CPU restart table 767 * and jump to it. For an idle CPU, the address in the 768 * table below will be the zero, causing 769 * the CPU to loop forever. To start a secondary CPU, 770 * just write an address in cpu_startvectors[cpu_id] 771 * 772 * Warning: This kind of assumes that this code will 773 * live in cacheable space. If it doesn't, it will 774 * probably cause lots of unwanted bus traffic. 775 */ 776 li s4,0 777 778loop_forever: ld t1,cpu_startvectors(t0) # Load address of routine 779 beq t1,zero,loop_forever 780 ld a1,cpu_start_args(t0) # Load user argument (A1) 781 ld sp,cpu_start_spvals(t0) # Load stack pointer 782 ld t2,cpu_start_gpvals(t0) # Load global pointer 783 move gp,t2 # and put in real register 784 j t1 # jump to start address 785 786 787/* ********************************************************************* 788 * End 789 ********************************************************************* */ 790