1/* 2 * BCM947XX Boot code for standalone apps. 3 * 4 * Code should be position-independent until it copies itself to SDRAM. 5 * 6 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved. 7 * 8 * Permission to use, copy, modify, and/or distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 17 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 18 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 * 20 * $Id: boot.S,v 1.35 2010-08-06 00:03:55 $ 21 */ 22 23#include "mipsinc.h" 24#include "hndsoc.h" 25#include "sbchipc.h" 26#include "bcmdevs.h" 27 28 29/* Debug macro - write a number to a pair of chipc regs - use it with caution, 30 * the registers being used only exist in chip rev >= 22, meaning NOT in 5354 31 * and previous chips. Also, it changes k0 and k1 registers. 32 * Value can be read from epidiag -j using "pci r 0x180000d0 4" 33 */ 34#define TRACEINIT(x) 35#define TRACE(x) 36#define TRACE2(x) 37 38 .text 39 LEAF(startup) 40 .set noreorder 41 42 43 TRACEINIT(0x424f00) 44 # XXX: the following code snipet sets clk frequency to 200M 45 # correct pll clk freq to real speed in the 5350 case. 46 # unless its vsim which we detect as pkg option 1 (should be 0xe) 47 # It is Ugly...but 48 li s2,KSEG1ADDR(SI_ENUM_BASE) # s2 = SI_ENUM_BASE 49 li a3,BCM5350_CHIP_ID # 5350 ChipID 50 lw s1,CC_CHIPID(s2) # s1 = ChipID register 51 li t2,CID_ID_MASK # chip id is bit 0-15 52 and t2,s1,t2 53 bne t2,a3,2f # if not 5350 then skip 54 nop 55 56 TRACE(0x424f01) 57 li t2,CID_PKG_MASK # if it is a vsim 5350, also skip 58 and t2,s1,t2 59 li a3,(HDLSIM5350_PKG_ID << CID_PKG_SHIFT) 60 beq t2,a3,initcpu # if pkg opt 1 then skip 61 nop 62 63 TRACE(0x424f02) 64 li a3,CLKC_5350_N 65 lw t3,CC_CLKC_N(s2) 66 beq a3,t3,initcpu # move ahead if clk freq set correctly 67 nop 68 sw a3,CC_CLKC_N(s2) # set control N1 to select 6 69 li t3,1 70 sw t3,CC_WATCHDOG(s2) # set WatchDog Reset 711: b 1b 72 nop 73 742: li a3,BCM5354_CHIP_ID # 5354 ChipID 75 bne t2,a3,initcpu # if not 5354 then skip 76 nop 77 78 TRACE(0x424f03) 79 li t2,CID_REV_MASK # Get chip rev 80 and t2,s1,t2 81 li t3,(3 << CID_REV_SHIFT) # Is it an a3? 82 blt t2,t3,a0a1a2 83 nop 84 85 /* Fix up for a3 (and up?) */ 86 li a0,0x01330000 # Value for regcontrol 2 87 li t2,2 88 sw t2,PMU_REG_CONTROL_ADDR(s2) 89 sw a0,PMU_REG_CONTROL_DATA(s2) 90 91a0a1a2: 92 li a0,0x00002000 # Value for regcontrol 0 93 li a1,0x06800000 # Value for regcontrol 1 94 li a3,0x02000000 # Value for regcontrol 3 95 96fixregctl: 97 li t2,0x1 # Need define 98 sw t2,PMU_REG_CONTROL_ADDR(s2) 99 sw a1,PMU_REG_CONTROL_DATA(s2) 100 101 /* 102 * Trim the output voltage of the 1.2V BB switcher and 2.5V 103 * regulator to the correct value. 104 */ 105 li t2,0x0 106 sw t2,PMU_REG_CONTROL_ADDR(s2) 107 sw a0,PMU_REG_CONTROL_DATA(s2) # BB switcher to get 1.2V 108 li t2,0x3 109 sw t2,PMU_REG_CONTROL_ADDR(s2) 110 sw a3,PMU_REG_CONTROL_DATA(s2) # of VDDP LDO to get 2.5V 111 112 lw t2,PMU_CTL(s2) # Check if PLL has been programmed 113 andi t2,t2,PCTL_XTALFREQ_MASK 114 bnez t2,3f # Yup, leave it alone 115 nop 116 117 li t2,0x7ffff # Should only turn off the PLL bit 118 sw t2,PMU_MIN_RES_MASK(s2) # Disable base band PLL 119 sw t2,PMU_MAX_RES_MASK(s2) 120 121 li t2,0x1 122 sw t2,PMU_PLL_CONTROL_ADDR(s2) 123 li t2,0x66666602 # Set the PLL Mode properly 124 sw t2,PMU_PLL_CONTROL_DATA(s2) 125 li t2,0xfffff # Enable base band PLL 126 sw t2,PMU_MIN_RES_MASK(s2) 127 sw t2,PMU_MAX_RES_MASK(s2) 128 nop 129 130 /* Init code for ff4 space without TLB, enabling RAC */ 1313: TRACE(0x424f04) 132 li t0,0x1fa0000c # Set up CBR to 0x1fax_xxxx 133 .set mips32 134 mtc0 t0,$22,6 135 li t1,0x1fa00000 136 lw t2,0x14(t1) 137 or t3,t2,0xc0000000 # enable ffxx_xxxx space # without programming TLB 138 sw t3,0x14(t1) 139 li t0,0xff40000c # change CBR to ff4x_xxxx 140 mtc0 t0,$22,6 141 .set mips0 142 143 144 /* Initialize processor state */ 145initcpu: 146 TRACE(0x424f05) 147 mfc0 t0,C0_STATUS 148 li t1,~(ST0_CU | ST0_RP | ST0_RE | ST0_TS | ST0_SR | ST0_NMI | ST0_UM | ST0_IE) 149 and t0,t1 150 li t1,ST0_IM 151 or t0,t1 152 mtc0 t0,C0_STATUS 153 154 mtc0 zero,C0_CAUSE 155 156 mtc0 zero,C0_COUNT 157 158 li t0,-1 159 mtc0 t0,C0_COMPARE 160 161initram: 162 /* Check if we booted from SDRAM */ 163 bal 1f 164 nop 165 1661: li t0,PHYSADDR_MASK 167 and t0,t0,ra 168 li t1,SI_FLASH1 169 blt t0,t1,chkcacheon 170 move s5,zero # In ram, relocate factor is 0 171 172 /* If we are in flash, compute reloc for text addresses */ 173 TRACE(0x424f06) 174 li t0,KSEG0ADDR(SI_FLASH1) 175 la t1,text_start 176 sub s5,t0,t1 # s5: Relocate factor 177 178 /* Figure out if we have an SB or AI chip */ 179chkchiptype: 180 TRACE(0x424f08) 181 li t0,CID_TYPE_MASK 182 and t0,t0,s1 183 srl s7,t0,CID_TYPE_SHIFT # s7 = ChipType (0 for SB, = 1 for AI) 184 185 bnez s7,chkcacheon # If ai chip no need to check chipc rev 186 nop 187 188 /* Is this chipc rev 11 or 12 and a serial flash? */ 189 TRACE(0x424f0a) 190 li t0,KSEG1ADDR(SI_ENUM_BASE) 191 lw t1,(SBCONFIGOFF + SBIDHIGH)(t0) 192 and t2,t1,SBIDH_CC_MASK 193 srl t2,t2,SBIDH_CC_SHIFT 194 bne t2,CC_CORE_ID,chkcacheon # Not chipc 195 nop 196 and t2,t1,SBIDH_RC_MASK 197 and t3,t1,SBIDH_RCE_MASK 198 srl t3,t3,SBIDH_RCE_SHIFT 199 or t2,t3 200 ble t2,10,chkcacheon # ccrev <= 10 201 nop 202 bge t2,13,chkcacheon # ccrev >= 13 203 nop 204 lw t0,CC_CAPABILITIES(t0) 205 and t0,t0,CC_CAP_FLASH_MASK 206 beq t0,SFLASH_AT,switchkseg0 # Atmel sflash 207 nop 208 beq t0,SFLASH_ST,switchkseg0 # ST sflash 209 nop 210 211 b chkcacheon 212 nop 213 214 /* Black hole for traps with BEV on */ 215 .org 0x380 216bevtrap: 217 TRACE2(0x424f0380) 218 nop 219 nop 220 .set mips32 221 wait 222 .set mips0 223 nop 224 nop 225 b bevtrap 226 nop 227 228 /* Record the size of the binary */ 229 .org BISZ_OFFSET 230 .word BISZ_MAGIC 231 .word text_start 232 .word text_end 233 .word data_start 234 .word data_end 235 .word bss_start 236 .word bss_end 237 .word _end 238 239 /* Embedded NVRAM */ 240 .balign 0x400 241 .globl embedded_nvram 242embedded_nvram: 243 .fill 0x400,4,~(0x48534c46) 244 .long 0x4c5a4d41 # LZMA NVRAM Supported 245 246chkcacheon: 247 TRACE(0x424f0b) 248 /* Check if the caches are already on */ 249 mfc0 t0,C0_CONFIG 250 and t0,CONF_CM_CMASK 251 bne t0,CONF_CM_UNCACHED,switchkseg0 252 nop 253 254initcaches: 255 TRACE(0x424f0c) 256 li t0,(HDLSIM_PKG_ID << CID_PKG_SHIFT) # vsim package option 257 li t2,CID_PKG_MASK # isolate chip package 258 and t2,s1,t2 259 beq t0,t2,chcach # Skip cache init if vsim 260 261 /* Figure if it is a mips32r2 CPU which we take as an indication that 262 * there is no BRCM CP0 register and the D$ tags are in select 2 263 */ 264 mfc0 s6,C0_CONFIG 265 andi s6,CONF_AR # s6 != 0 if mips32r2 266 beqz s6,1f 267 nop 268 b 2f 269 nop 270 271 /* Turn on the caches in the CP0 register */ 2721: TRACE(0x424f0d) 273 mfc0 t0,C0_DIAGNOSTIC 274 or t0,(BRCM_IC_ENABLE | BRCM_DC_ENABLE) # Enable both I$ and D$ 275 mtc0 t0,C0_DIAGNOSTIC 276 nop 277 2782: /* Get cache sizes */ 279 TRACE(0x424f0e) 280 .set mips32 281 mfc0 a0,C0_CONFIG,1 # a0 has CP0 CONFIG1 282 .set mips0 283 284 li a1,CONF1_DL_MASK 285 and a1,a0 286 beq a1,zero,initic 287 nop 288 289 srl a1,CONF1_DL_SHIFT 290 li t0,CONF1_DL_BASE 291 sll a1,t0,a1 # a1 has D$ cache line size 292 293 li a2,CONF1_DA_MASK 294 and a2,a0 295 srl a2,CONF1_DA_SHIFT 296 addiu a2,CONF1_DA_BASE # a2 now has D$ associativity 297 298 li t0,CONF1_DS_MASK 299 and t0,a0 300 srl t0,CONF1_DS_SHIFT 301 li a3,CONF1_DS_BASE 302 sll a3,a3,t0 # a3 has D$ sets per way 303 304 multu a2,a3 # sets/way * associativity 305 mflo t0 # total cache lines 306 307 multu a1,t0 # D$ linesize * lines 308 mflo a2 # a2 is now D$ size in bytes 309 310 /* Initilize the D$: */ 311 beqz s6,1f 312 nop 313 .set mips32 314 mtc0 zero,C0_TAGLO,2 # For mips32r2 the D$ Tags are in select 2 315 mtc0 zero,C0_TAGHI,2 316 .set mips0 317 b 2f 318 nop 319 3201: mtc0 zero,C0_TAGLO 321 mtc0 zero,C0_TAGHI 322 3232: li t0,KSEG0 # Just an address for the first $ line 324 addu t1,t0,a2 # + size of cache == end 325 326 .set mips32 3273: cache Index_Store_Tag_D,0(t0) 328 .set mips0 329 bne t0,t1,3b 330 addu t0,a1 331 332initic: 333 /* Now we get to do it all again for the I$ */ 334 335 TRACE(0x424f0f) 336 li a1,CONF1_IL_MASK 337 and a1,a0 338 beq a1,zero,chcach 339 nop 340 341 srl a1,CONF1_IL_SHIFT 342 li t0,CONF1_IL_BASE 343 sll a1,t0,a1 # a1 has I$ cache line size 344 345 li a2,CONF1_IA_MASK 346 and a2,a0 347 srl a2,CONF1_IA_SHIFT 348 addiu a2,CONF1_IA_BASE # a2 now has I$ associativity 349 350 li t0,CONF1_IS_MASK 351 and t0,a0 352 srl t0,CONF1_IS_SHIFT 353 li a3,CONF1_IS_BASE 354 sll a3,a3,t0 # a3 has I$ sets per way 355 356 multu a2,a3 # sets/way * associativity 357 mflo t0 # total cache lines 358 359 multu a1,t0 # I$ linesize * lines 360 mflo a2 # a2 is cache size in bytes 361 362 /* Initilize the I$: */ 363 mtc0 zero,C0_TAGLO 364 mtc0 zero,C0_TAGHI 365 366 li t0,KSEG0 # Just an address for the first $ line 367 addu t1,t0,a2 # + size of cache == end 368 369 .set mips32 3701: cache Index_Store_Tag_I,0(t0) 371 .set mips0 372 bne t0,t1,1b 373 addu t0,a1 374 375chcach: 376 TRACE(0x424f10) 377 /* Caches initialized, change cacheability */ 378 mfc0 t0,C0_CONFIG 379 and t0,~CONF_CM_CMASK 380 or t0,CONF_CM_CACHABLE_NONCOHERENT 381 mtc0 t0,C0_CONFIG 382 nop 383 384switchkseg0: 385 la t2,board_draminit 386 add t2,t2,s5 387 la ra,backfbd 388 add ra,ra,s5 389 jr t2 390 nop 391 392 /* Should return ram size in v0 */ 393backfbd: 394 bnez v0,1f 395 nop 396 397panic: TRACE2(0x424f0bad) 398 b panic 399 nop 400 401 /* Re-check if we booted from SDRAM */ 4021: TRACE(0x424f11) 403 bal 2f 404 nop 405 4062: li t0,PHYSADDR_MASK 407 and t0,t0,ra 408 li t1,SI_FLASH1 409 blt t0,t1,inram 410 nop 411 412 /* Copy self to SDRAM */ 413copy2ram: 414 TRACE(0x424f12) 415#ifdef CONFIG_XIP 416 la a0,text_end 417 la a1,data_start 418 la a2,data_end 419#else 420 li a0,KSEG0ADDR(SI_FLASH1) 421 la a1,text_start 422 li t0,PHYSADDR_MASK # Uncached writes to avoid a flush 423 and a1,a1,t0 424 li t1,KSEG1 425 or a1,a1,t1 426 la a2,data_end 427 and a2,a2,t0 428 or a2,a2,t1 429#endif 4301: lw t0,0(a0) 431 sw t0,0(a1) 432 add a0,4 433 add a1,4 434 blt a1,a2,1b 435 nop 436 437 /* Go execute from ram now */ 438 la t0,inram 439 jr t0 440 nop 441 442inram: 443clearbss: 444 TRACE(0x424f13) 445 /* Clear BSS */ 446 la a0,bss_start 447 la a1,bss_end 4481: sw zero,0(a0) 449 addi a0,a0,4 450 blt a0,a1,1b 451 nop 452 453 /* Setup trap handlers */ 454 TRACE(0x424f14) 455 la t0,trap_init 456 jalr t0 457 nop 458 459 /* Record the memory size */ 4602: TRACE(0x424f15) 461 la t0,_memsize 462 sw v0,0(t0) 463 464 /* Set up stack pointer */ 465 or v0,KSEG0 466 sub sp,v0,4 467 468/* bootloader supports nvram dl: shift stack pointer beyond nvram */ 469#ifdef DL_NVRAM 470 la t1,_dlvarsz 471 sw sp,0(t1) 472 li a0,DL_NVRAM 473 sub sp,sp,a0 474 la t1,_dlvars 475 sw sp,0(t1) 476 sub sp,sp,4 477#endif /* DL_NVRAM */ 478 479 /* Jump to C */ 480 la t0,c_main 481 jal t0 482 move a0,ra 483 484 /* In case c_main returns */ 485theend: TRACE2(0x424feedd) 486 nop 487 nop 488 .set mips32 489 wait 490 .set mips0 491 nop 492 nop 493 b theend 494 nop 495 496 .set reorder 497 END(startup) 498 499 .data 500 .globl _memsize 501_memsize: 502 .word 0 503 504#ifdef DL_NVRAM 505 .globl _dlvars 506_dlvars: 507 .word 0 508 509 .globl _dlvarsz 510_dlvarsz: 511 .word 0 512#endif /* DL_NVRAM */ 513