/* * BCM947XX Boot code for standalone apps. * * Code should be position-independent until it copies itself to SDRAM. * * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: boot.S,v 1.35 2010-08-06 00:03:55 $ */ #include "mipsinc.h" #include "hndsoc.h" #include "sbchipc.h" #include "bcmdevs.h" /* Debug macro - write a number to a pair of chipc regs - use it with caution, * the registers being used only exist in chip rev >= 22, meaning NOT in 5354 * and previous chips. Also, it changes k0 and k1 registers. * Value can be read from epidiag -j using "pci r 0x180000d0 4" */ #define TRACEINIT(x) #define TRACE(x) #define TRACE2(x) .text LEAF(startup) .set noreorder TRACEINIT(0x424f00) # XXX: the following code snipet sets clk frequency to 200M # correct pll clk freq to real speed in the 5350 case. # unless its vsim which we detect as pkg option 1 (should be 0xe) # It is Ugly...but li s2,KSEG1ADDR(SI_ENUM_BASE) # s2 = SI_ENUM_BASE li a3,BCM5350_CHIP_ID # 5350 ChipID lw s1,CC_CHIPID(s2) # s1 = ChipID register li t2,CID_ID_MASK # chip id is bit 0-15 and t2,s1,t2 bne t2,a3,2f # if not 5350 then skip nop TRACE(0x424f01) li t2,CID_PKG_MASK # if it is a vsim 5350, also skip and t2,s1,t2 li a3,(HDLSIM5350_PKG_ID << CID_PKG_SHIFT) beq t2,a3,initcpu # if pkg opt 1 then skip nop TRACE(0x424f02) li a3,CLKC_5350_N lw t3,CC_CLKC_N(s2) beq a3,t3,initcpu # move ahead if clk freq set correctly nop sw a3,CC_CLKC_N(s2) # set control N1 to select 6 li t3,1 sw t3,CC_WATCHDOG(s2) # set WatchDog Reset 1: b 1b nop 2: li a3,BCM5354_CHIP_ID # 5354 ChipID bne t2,a3,initcpu # if not 5354 then skip nop TRACE(0x424f03) li t2,CID_REV_MASK # Get chip rev and t2,s1,t2 li t3,(3 << CID_REV_SHIFT) # Is it an a3? blt t2,t3,a0a1a2 nop /* Fix up for a3 (and up?) */ li a0,0x01330000 # Value for regcontrol 2 li t2,2 sw t2,PMU_REG_CONTROL_ADDR(s2) sw a0,PMU_REG_CONTROL_DATA(s2) a0a1a2: li a0,0x00002000 # Value for regcontrol 0 li a1,0x06800000 # Value for regcontrol 1 li a3,0x02000000 # Value for regcontrol 3 fixregctl: li t2,0x1 # Need define sw t2,PMU_REG_CONTROL_ADDR(s2) sw a1,PMU_REG_CONTROL_DATA(s2) /* * Trim the output voltage of the 1.2V BB switcher and 2.5V * regulator to the correct value. */ li t2,0x0 sw t2,PMU_REG_CONTROL_ADDR(s2) sw a0,PMU_REG_CONTROL_DATA(s2) # BB switcher to get 1.2V li t2,0x3 sw t2,PMU_REG_CONTROL_ADDR(s2) sw a3,PMU_REG_CONTROL_DATA(s2) # of VDDP LDO to get 2.5V lw t2,PMU_CTL(s2) # Check if PLL has been programmed andi t2,t2,PCTL_XTALFREQ_MASK bnez t2,3f # Yup, leave it alone nop li t2,0x7ffff # Should only turn off the PLL bit sw t2,PMU_MIN_RES_MASK(s2) # Disable base band PLL sw t2,PMU_MAX_RES_MASK(s2) li t2,0x1 sw t2,PMU_PLL_CONTROL_ADDR(s2) li t2,0x66666602 # Set the PLL Mode properly sw t2,PMU_PLL_CONTROL_DATA(s2) li t2,0xfffff # Enable base band PLL sw t2,PMU_MIN_RES_MASK(s2) sw t2,PMU_MAX_RES_MASK(s2) nop /* Init code for ff4 space without TLB, enabling RAC */ 3: TRACE(0x424f04) li t0,0x1fa0000c # Set up CBR to 0x1fax_xxxx .set mips32 mtc0 t0,$22,6 li t1,0x1fa00000 lw t2,0x14(t1) or t3,t2,0xc0000000 # enable ffxx_xxxx space # without programming TLB sw t3,0x14(t1) li t0,0xff40000c # change CBR to ff4x_xxxx mtc0 t0,$22,6 .set mips0 /* Initialize processor state */ initcpu: TRACE(0x424f05) mfc0 t0,C0_STATUS li t1,~(ST0_CU | ST0_RP | ST0_RE | ST0_TS | ST0_SR | ST0_NMI | ST0_UM | ST0_IE) and t0,t1 li t1,ST0_IM or t0,t1 mtc0 t0,C0_STATUS mtc0 zero,C0_CAUSE mtc0 zero,C0_COUNT li t0,-1 mtc0 t0,C0_COMPARE initram: /* Check if we booted from SDRAM */ bal 1f nop 1: li t0,PHYSADDR_MASK and t0,t0,ra li t1,SI_FLASH1 blt t0,t1,chkcacheon move s5,zero # In ram, relocate factor is 0 /* If we are in flash, compute reloc for text addresses */ TRACE(0x424f06) li t0,KSEG0ADDR(SI_FLASH1) la t1,text_start sub s5,t0,t1 # s5: Relocate factor /* Figure out if we have an SB or AI chip */ chkchiptype: TRACE(0x424f08) li t0,CID_TYPE_MASK and t0,t0,s1 srl s7,t0,CID_TYPE_SHIFT # s7 = ChipType (0 for SB, = 1 for AI) bnez s7,chkcacheon # If ai chip no need to check chipc rev nop /* Is this chipc rev 11 or 12 and a serial flash? */ TRACE(0x424f0a) li t0,KSEG1ADDR(SI_ENUM_BASE) lw t1,(SBCONFIGOFF + SBIDHIGH)(t0) and t2,t1,SBIDH_CC_MASK srl t2,t2,SBIDH_CC_SHIFT bne t2,CC_CORE_ID,chkcacheon # Not chipc nop and t2,t1,SBIDH_RC_MASK and t3,t1,SBIDH_RCE_MASK srl t3,t3,SBIDH_RCE_SHIFT or t2,t3 ble t2,10,chkcacheon # ccrev <= 10 nop bge t2,13,chkcacheon # ccrev >= 13 nop lw t0,CC_CAPABILITIES(t0) and t0,t0,CC_CAP_FLASH_MASK beq t0,SFLASH_AT,switchkseg0 # Atmel sflash nop beq t0,SFLASH_ST,switchkseg0 # ST sflash nop b chkcacheon nop /* Black hole for traps with BEV on */ .org 0x380 bevtrap: TRACE2(0x424f0380) nop nop .set mips32 wait .set mips0 nop nop b bevtrap nop /* Record the size of the binary */ .org BISZ_OFFSET .word BISZ_MAGIC .word text_start .word text_end .word data_start .word data_end .word bss_start .word bss_end .word _end /* Embedded NVRAM */ .balign 0x400 .globl embedded_nvram embedded_nvram: .fill 0x400,4,~(0x48534c46) .long 0x4c5a4d41 # LZMA NVRAM Supported chkcacheon: TRACE(0x424f0b) /* Check if the caches are already on */ mfc0 t0,C0_CONFIG and t0,CONF_CM_CMASK bne t0,CONF_CM_UNCACHED,switchkseg0 nop initcaches: TRACE(0x424f0c) li t0,(HDLSIM_PKG_ID << CID_PKG_SHIFT) # vsim package option li t2,CID_PKG_MASK # isolate chip package and t2,s1,t2 beq t0,t2,chcach # Skip cache init if vsim /* Figure if it is a mips32r2 CPU which we take as an indication that * there is no BRCM CP0 register and the D$ tags are in select 2 */ mfc0 s6,C0_CONFIG andi s6,CONF_AR # s6 != 0 if mips32r2 beqz s6,1f nop b 2f nop /* Turn on the caches in the CP0 register */ 1: TRACE(0x424f0d) mfc0 t0,C0_DIAGNOSTIC or t0,(BRCM_IC_ENABLE | BRCM_DC_ENABLE) # Enable both I$ and D$ mtc0 t0,C0_DIAGNOSTIC nop 2: /* Get cache sizes */ TRACE(0x424f0e) .set mips32 mfc0 a0,C0_CONFIG,1 # a0 has CP0 CONFIG1 .set mips0 li a1,CONF1_DL_MASK and a1,a0 beq a1,zero,initic nop srl a1,CONF1_DL_SHIFT li t0,CONF1_DL_BASE sll a1,t0,a1 # a1 has D$ cache line size li a2,CONF1_DA_MASK and a2,a0 srl a2,CONF1_DA_SHIFT addiu a2,CONF1_DA_BASE # a2 now has D$ associativity li t0,CONF1_DS_MASK and t0,a0 srl t0,CONF1_DS_SHIFT li a3,CONF1_DS_BASE sll a3,a3,t0 # a3 has D$ sets per way multu a2,a3 # sets/way * associativity mflo t0 # total cache lines multu a1,t0 # D$ linesize * lines mflo a2 # a2 is now D$ size in bytes /* Initilize the D$: */ beqz s6,1f nop .set mips32 mtc0 zero,C0_TAGLO,2 # For mips32r2 the D$ Tags are in select 2 mtc0 zero,C0_TAGHI,2 .set mips0 b 2f nop 1: mtc0 zero,C0_TAGLO mtc0 zero,C0_TAGHI 2: li t0,KSEG0 # Just an address for the first $ line addu t1,t0,a2 # + size of cache == end .set mips32 3: cache Index_Store_Tag_D,0(t0) .set mips0 bne t0,t1,3b addu t0,a1 initic: /* Now we get to do it all again for the I$ */ TRACE(0x424f0f) li a1,CONF1_IL_MASK and a1,a0 beq a1,zero,chcach nop srl a1,CONF1_IL_SHIFT li t0,CONF1_IL_BASE sll a1,t0,a1 # a1 has I$ cache line size li a2,CONF1_IA_MASK and a2,a0 srl a2,CONF1_IA_SHIFT addiu a2,CONF1_IA_BASE # a2 now has I$ associativity li t0,CONF1_IS_MASK and t0,a0 srl t0,CONF1_IS_SHIFT li a3,CONF1_IS_BASE sll a3,a3,t0 # a3 has I$ sets per way multu a2,a3 # sets/way * associativity mflo t0 # total cache lines multu a1,t0 # I$ linesize * lines mflo a2 # a2 is cache size in bytes /* Initilize the I$: */ mtc0 zero,C0_TAGLO mtc0 zero,C0_TAGHI li t0,KSEG0 # Just an address for the first $ line addu t1,t0,a2 # + size of cache == end .set mips32 1: cache Index_Store_Tag_I,0(t0) .set mips0 bne t0,t1,1b addu t0,a1 chcach: TRACE(0x424f10) /* Caches initialized, change cacheability */ mfc0 t0,C0_CONFIG and t0,~CONF_CM_CMASK or t0,CONF_CM_CACHABLE_NONCOHERENT mtc0 t0,C0_CONFIG nop switchkseg0: la t2,board_draminit add t2,t2,s5 la ra,backfbd add ra,ra,s5 jr t2 nop /* Should return ram size in v0 */ backfbd: bnez v0,1f nop panic: TRACE2(0x424f0bad) b panic nop /* Re-check if we booted from SDRAM */ 1: TRACE(0x424f11) bal 2f nop 2: li t0,PHYSADDR_MASK and t0,t0,ra li t1,SI_FLASH1 blt t0,t1,inram nop /* Copy self to SDRAM */ copy2ram: TRACE(0x424f12) #ifdef CONFIG_XIP la a0,text_end la a1,data_start la a2,data_end #else li a0,KSEG0ADDR(SI_FLASH1) la a1,text_start li t0,PHYSADDR_MASK # Uncached writes to avoid a flush and a1,a1,t0 li t1,KSEG1 or a1,a1,t1 la a2,data_end and a2,a2,t0 or a2,a2,t1 #endif 1: lw t0,0(a0) sw t0,0(a1) add a0,4 add a1,4 blt a1,a2,1b nop /* Go execute from ram now */ la t0,inram jr t0 nop inram: clearbss: TRACE(0x424f13) /* Clear BSS */ la a0,bss_start la a1,bss_end 1: sw zero,0(a0) addi a0,a0,4 blt a0,a1,1b nop /* Setup trap handlers */ TRACE(0x424f14) la t0,trap_init jalr t0 nop /* Record the memory size */ 2: TRACE(0x424f15) la t0,_memsize sw v0,0(t0) /* Set up stack pointer */ or v0,KSEG0 sub sp,v0,4 /* bootloader supports nvram dl: shift stack pointer beyond nvram */ #ifdef DL_NVRAM la t1,_dlvarsz sw sp,0(t1) li a0,DL_NVRAM sub sp,sp,a0 la t1,_dlvars sw sp,0(t1) sub sp,sp,4 #endif /* DL_NVRAM */ /* Jump to C */ la t0,c_main jal t0 move a0,ra /* In case c_main returns */ theend: TRACE2(0x424feedd) nop nop .set mips32 wait .set mips0 nop nop b theend nop .set reorder END(startup) .data .globl _memsize _memsize: .word 0 #ifdef DL_NVRAM .globl _dlvars _dlvars: .word 0 .globl _dlvarsz _dlvarsz: .word 0 #endif /* DL_NVRAM */