📄 bcm1480_altcpu.s
字号:
/* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * CPU init module File: bcm1480_altcpu.S * * Secondary core startup routines for CFE * * Author: Mitch Lichtenberg * ********************************************************************* * * Copyright 2000,2001,2002,2003 * Broadcom Corporation. All rights reserved. * * This software is furnished under license and may be used and * copied only in accordance with the following terms and * conditions. Subject to these conditions, you may download, * copy, install, use, modify and distribute modified or unmodified * copies of this software in source and/or binary form. No title * or ownership is transferred hereby. * * 1) Any source code used, modified or distributed must reproduce * and retain this copyright notice and list of conditions * as they appear in the source file. * * 2) No right is granted to use any trade name, trademark, or * logo of Broadcom Corporation. The "Broadcom Corporation" * name may not be used to endorse or promote products derived * from this software without the prior written permission of * Broadcom Corporation. * * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************* */#include "sbmips.h"#include "exception.h"#include "bsp_config.h"#ifdef _CFE_#include "cfe_devfuncs.h"#else#define CFE_EPTSEAL 0x43464531#endif#include "bcm1480_regs.h"#include "bcm1480_scd.h"#include "cpu_config.h"/* ********************************************************************* * Macros ********************************************************************* */#include "mipsmacros.h"#define SETLEDS1(a,b,c,d) \ li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ JAL_KSEG1(board_setleds)#define SETLEDS(a,b,c,d) \ li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ JAL(board_setleds)#define SETLEDS1_ADD(a,b,c,d,add) \ li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ addu a0, a0, add ; \ JAL_KSEG1(board_setleds)#define SETLEDS_ADD(a,b,c,d,add) \ li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ addu a0, a0, add ; \ JAL(board_setleds)/* * Read system revision register to get # of CPUs on this part * Do this by reading CPU disables from system_cfg, * and using that to index a bit array to get the number of * cpus enabled (minus 1). */ #define GET_NUM_CPUS(reg, tmp) \ la reg,PHYS_TO_K1(A_SCD_SYSTEM_CFG) ; \ ld reg,(reg) ; \ dsrl reg,(S_BCM1480_SYS_DISABLECPU0) ; \ and reg,0x0f ; \ li tmp, 0x0116166b ; \ srl tmp, tmp, reg ; \ srl tmp, tmp, reg /* really, twice */ ; \ andi tmp, tmp, 0x3 ; \ addiu reg, tmp, 1#define GET_CUR_CPU(reg) \ mfc0 reg,C0_PRID ; \ srl reg,reg,25 ; \ and reg,reg,7 /* ********************************************************************* * Initialized Data ********************************************************************* */ .sdata#define R_CPU_STARTVECT _TBLIDX(0)#define R_CPU_SPVAL _TBLIDX(1)#define R_CPU_GPVAL _TBLIDX(2)#define R_CPU_ARG _TBLIDX(3)#define R_CPU_RECSIZE 32 /* One cache line per record *//* * Initial start addresses for secondary CPUs. Each record below * is on its own cache line. That cache line will be held exclusive * by the owning CPU and only the snoop traffic should show up * on the bus. */ .align 5 .globl cpu_idledatacpu_idledata: .dword 0,0,0,0 # cpu #0 (not used) .dword 0,0,0,0 # cpu #1 .dword 0,0,0,0 # cpu #2 .dword 0,0,0,0 # cpu #3 .extern mem_datareloc .text .set mips64/* ********************************************************************* * ALTCPU_KSEG1_SWITCH * * Hack the return address so we will come back in KSEG1 (uncached) * * Input parameters: * nothing * * Return value: * nothing ********************************************************************* */LEAF(altcpu_kseg1_switch)_altcpu_kseg1_switch: and ra,(K0SIZE-1) or ra,K1BASE jr raEND(altcpu_kseg1_switch)/* ********************************************************************* * ALTCPU_KSEG0_SWITCH * * Hack the return address so we will come back in KSEG0 * * Input parameters: * nothing * * Return value: * nothing ********************************************************************* */LEAF(altcpu_kseg0_switch)_altcpu_kseg0_switch: and ra,(K0SIZE-1) or ra,K0BASE jr raEND(altcpu_kseg0_switch)/* ********************************************************************* * BCM1480_ALTCPU_START1 * * Start secondary processor(s). These processors will start * running the code at ALTCPU_RESET (see below). We wait here * for the secondary processor(s) to finish their cache * initialization and then return. * * For simplicity, we serialize starting the secondary processors * and waiting until done for now. * * This routine is normally run from KSEG1 * * Input parameters: * nothing * * Return value: * nothing ********************************************************************* */LEAF(bcm1480_altcpu_start1) /* * Do this only for CPUs with non-zero processor IDs, possibly * none if we have only one CPU. This way we can * support running the multiprocessor version of CFE * with only one core. */ GET_NUM_CPUS(v0, t0) b 3f # loop test /* * Main loop, CPU number is in v0. */1: /* * Clear out our mailbox registers (both CPUs) * XXX - need to do all CPUs and both mailboxes */ la a0,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_CLR_CPU)) dli t0,-1 # clear all 64 bits dli t1,BCM1480_IMR_REGISTER_SPACING sd t0,(a0) multu v0,t1 mflo t1 daddu a0,a0,t1 sd t0,(a0) /* * Let the secondary CPU(s) out of reset * * XXX This is very BCM1480-specific at the moment. */ la a0,PHYS_TO_K1(A_SCD_SYSTEM_CFG) ld t0,0(a0) dli t1,M_BCM1480_SYS_CPU_RESET_0 # Base reset mask dsll t1,t1,v0 not t1 # clear this bit and t0,t1 # New value to write sd t0,0(a0) # CPU[v0] is now running /* * Wait for the other CPU to ring our doorbell */2: la a0,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_CPU)); ld t0,(a0) # Read mailbox beq t0,zero,2b # Loop till the bit is set /* * Clear the mailbox to dismiss the pending interrupts */ la a0,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_CLR_CPU)) dli t0,-1 # clear all 64 bits sd t0,(a0)3: daddiu v0,v0,-1 bne v0,zero,1b # Keep going if more secondary CPUs /* * Okay, it's safe to return */ j raEND(bcm1480_altcpu_start1)/* ********************************************************************* * BCM1480_ALTCPU_START2 * * Finish startup of secondary processor(s) - we pass the relocation * offset to the other CPUs here, and the CPUs relocate their * data segments and go to the idle loop. * * This routine is normally run from KSEG0 * * Input parameters: * a0 - data relocation offset (0=none) * * Return value: * nothing ********************************************************************* */LEAF(bcm1480_altcpu_start2) /* * Do this for all secondary CPUs (if any) */ GET_NUM_CPUS(v0, t0) b 2f /* * Main loop, CPU number is in v0. */1: /* * Let secondary CPU(s) run their idle loops. Set the * mailbox register to our relocation factor so we can read * it out of the mailbox register and relocate GP properly. */ la t1,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_SET_CPU)) dli t2,BCM1480_IMR_REGISTER_SPACING or t0,a0,1 # hack - make sure reloc is nonzero multu v0,t2 mflo t2 daddu t1,t1,t2 sd t0,0(t1) # Write to mailbox register2: daddiu v0,v0,-1 bne v0,zero,1b # Keep going if more secondary CPUs j ra END(bcm1480_altcpu_start2)/* ********************************************************************* * BCM1480_ALTCPU_KILL * * Kill a secondary CPU, causing it to return to the idle * loop. We do this by switching to uncached mode, * asserting RESET on the other CPU, and then re-run * ALTCPU_START again. * * Input parameters: * a0 - cpu number to stop * * Return value: * nothing ********************************************************************* */LEAF(bcm1480_altcpu_kill)_bcm1480_altcpu_kill: /* * Don't do this if we have only one CPU. */ GET_NUM_CPUS(t0, t1) bgt t0,1,1f # Keep going if more than one CPU j ra # Go back home, nothing to do1: /* * More than one CPU, go ahead... */ move t7,ra # save RA, we'll make calls # # Stop CPU[a0], where a0 is the cpu number. # move t0,a0 # t0 = cpu # sll t0,t0,5 # index by cache lines la t1,cpu_idledata # add t1,t0 # point at cpu[a0]'s data SR zero,R_CPU_STARTVECT(t1) # Reset address of CPU1 # # Flush the D cache to ensure that the write above made it # out of our L1. # JAL(bcm1480_l1cache_flush_d) # uses t0, t2, t3 # # Switch to KSEG1 to quiesce our cache activity. # bal _altcpu_kseg1_switch # switch to uncached mode # # Force CPU into reset (cpu number should still be in a0) # li t2,PHYS_TO_K1(A_SCD_SYSTEM_CFG) ld t0,0(t2) dli t1,M_BCM1480_SYS_CPU_RESET_0 # Base Reset mask dsll t1,t1,a0 # Shift by processor number or t0,t1 # New value to write sd t0,0(t2) # CPUn is now in reset # # Not sure how long we're supposed to wait. # ssnop ssnop ssnop ssnop # # Now restart CPUn. We can't use "altcpu_start1" here because # we're probably restarting only one of 'n' cpus. # /* * Clear out our mailbox registers (both CPUs we're interested in) */ la t2,PHYS_TO_K1(A_BCM1480_IMR_REGISTER(0,R_BCM1480_IMR_MAILBOX_0_CLR_CPU)) dli t0,-1 # clear all 64 bits dli t1,BCM1480_IMR_REGISTER_SPACING sd t0,(t2) # do CPU0 multu a0,t1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -