1/* ********************************************************************* 2 * SB1250 Board Support Package 3 * 4 * CPU initialization File: bcmcore_cpuinit.S 5 * 6 * This module contains code to initialize the CPU cores. 7 * 8 * Note: all the routines in this module rely on registers only, 9 * since DRAM may not be active yet. 10 * 11 * Author: Mitch Lichtenberg (mpl@broadcom.com) 12 * 13 ********************************************************************* 14 * 15 * XX Copyright 2000,2001 16 * Broadcom Corporation. All rights reserved. 17 * 18 * BROADCOM PROPRIETARY AND CONFIDENTIAL 19 * 20 * This software is furnished under license and may be used and 21 * copied only in accordance with the license. 22 ********************************************************************* */ 23 24#include "sbmips.h" 25#include "exception.h" 26#include "bsp_config.h" 27#include "mipsmacros.h" 28#include "cpu_config.h" /* for ERET and HAZARD */ 29#include "cfe_iocb.h" 30 31 32 .text 33 34 .set mips32 35 36/* ********************************************************************* 37 * Macros 38 ********************************************************************* */ 39 40#define R_CPU_CP0INIT _TBLIDX(0) 41#define R_CPU_L1CINIT _TBLIDX(1) 42#define R_CPU_SETLEDS _TBLIDX(2) 43 44#define SETLEDS1(a,b,c,d) \ 45 li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ 46 CALLINIT_KSEG1(cpuinit_table,R_CPU_SETLEDS) 47#define SETLEDS(a,b,c,d) \ 48 li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ 49 CALLINIT_KSEG0(cpuinit_table,R_CPU_SETLEDS) 50 51cpuinit_table: 52 _LONG_ bcmcore_cp0_init # [ 0 ] R_CPU_CP0INIT 53 _LONG_ bcmcore_l1cache_init # [ 1 ] R_CPU_L1CINIT 54 _LONG_ board_setleds # [ 2 ] R_CPU_SETLEDS 55 56 57/* ********************************************************************* 58 * BCMCORE_CP0_INIT() 59 * 60 * Initialize an BCMCORE CPU's CP0 registers 61 * 62 * Input parameters: 63 * nothing 64 * 65 * Return value: 66 * nothing 67 * 68 * Registers used: 69 * all 70 ********************************************************************* */ 71 72 73LEAF(bcmcore_cp0_init) 74 75 .set noreorder 76 77 mtc0 zero,C0_WATCHLO # Watch registers. 78 mtc0 zero,C0_WATCHHI 79 mtc0 zero,C0_CAUSE # must clear before writing SR 80 81 mfc0 v0,C0_SR # Get status register 82 and v0,M_SR_SR # preserve soft reset 83#ifdef DEBUG_ENV_ICE 84 and v0,~M_SR_BEV 85#else 86 or v0,M_SR_BEV # exceptions to boot vector 87#endif 88 mtc0 v0,C0_SR # set up the status register 89 90 91 mfc0 v0,C0_CONFIG # get current CONFIG register 92 srl v0,v0,3 # strip out K0 bits 93 sll v0,v0,3 # k0 bits now zero 94 or v0,v0,K_CFG_K0COH_CACHEABLE # K0 is cacheable. 95 mtc0 v0,C0_CONFIG 96 nop 97 98 mfc0 v0,C0_PRID 99 and v0,0x00fffe00 100 bne v0,0x00029000,1f # Broadcom BCM330X 101 nop 102 mfc0 v0,C0_DIAGNOSTIC 103 or v0,0x80000000 # Enable icache 104 or v0,0x40000000 # Enable dcache 105 mtc0 v0,C0_DIAGNOSTIC 106 1071: mtc0 zero,C0_WATCHLO # Watch registers. 108 mtc0 zero,C0_WATCHHI 109 110 mtc0 zero,C0_TLBHI # TLB entry (high half) 111 nop 112 113 114 # 115 # This is probably not the right init value for C0_COMPARE, 116 # but it seems to be necessary for the sim model right now. 117 # 118 119 li v0,-1 120 mtc0 v0,C0_COMPARE 121 nop 122 123 # 124 # Initialize all the TLB entries to some invalid value 125 # 126 127 mtc0 zero,C0_TLBLO0 /* tlblo0 = invalid */ 128 nop 129 mtc0 zero,C0_TLBLO1 /* tlblo1 = invalid */ 130 nop 131 mtc0 zero,C0_PGMASK /* 4K pages */ 132 nop 133 134 li t0,K1BASE /* tlbhi = impossible vpn */ 135 mfc0 v0,C0_CONFIG,1 136 li t1,M_CFG_MMUSIZE 137 and t1,v0 138 srl t1,S_CFG_MMUSIZE /* index */ 139 140 141 nop 1421: mtc0 t0,C0_TLBHI 143 nop 144 mtc0 t1,C0_INX 145 nop 146 addu t0,0x2000 /* inc vpn */ 147 tlbwi 148 bnez t1,1b 149 subu t1,1 # BDSLOT 150 .set reorder 151 152 153 154 jr ra 155 156 157END(bcmcore_cp0_init) 158 159 160/* ********************************************************************* 161 * BCMCORE_CPUINIT 162 * 163 * Do initialization of the Broadcom core 164 * 165 * Input parameters: 166 * nothing 167 * 168 * Return value: 169 * nothing 170 ********************************************************************* */ 171 172 173LEAF(bcmcore_cpuinit) 174 175 move fp,ra 176 177 SETLEDS1('C','P','U','I') 178 CALLINIT_KSEG1(cpuinit_table,R_CPU_CP0INIT) 179#if CFG_INIT_L1 > 0 180 SETLEDS1('L','1','C','I') 181 CALLINIT_KSEG1(cpuinit_table,R_CPU_L1CINIT) 182#endif 183 move ra,fp 184 j ra 185 186END(bcmcore_cpuinit) 187 188 189/* ********************************************************************* 190 * BCMCORE_NULL 191 * 192 * Dummy handler for routines we don't need to implement, like 193 * the multiprocessor stuff 194 * 195 * Input parameters: 196 * nothing 197 * 198 * Return value: 199 * nothing 200 * 201 * Registers used: 202 * none 203 ********************************************************************* */ 204 205LEAF(bcmcore_null) 206 207 j ra 208 209END(bcmcore_null) 210 211 212/* ********************************************************************* 213 * BCMCORE_CPURESTART 214 * 215 * This routine is called when someone soft-exits to CFE. We 216 * reinitialize any CP0 stuff here. 217 * 218 * Input parameters: 219 * nothing 220 * 221 * Return value: 222 * nothing 223 ********************************************************************* */ 224 225LEAF(bcmcore_cpurestart) 226 227 j ra 228 229END(bcmcore_cpurestart) 230 231 232/* ********************************************************************* 233 * BCMCORE_CACHEOPS 234 * 235 * Perform various cache operations on a BCM Core 236 * 237 * Input parameters: 238 * a0 - flag bits (CFE_CACHE_xxx) 239 * 240 * Return value: 241 * nothing 242 * 243 * Registers used: 244 * t0,t1,t2,t3,v1,s0 245 ********************************************************************* */ 246 247LEAF(bcmcore_cacheops) 248 249 move s0,ra 250 251 move v1,a0 252 253 /* 254 * With no flags, we flush L1D and invalid L1I 255 */ 256 257 bne v1,zero,1f 258 li v1,CFE_CACHE_FLUSH_D | CFE_CACHE_INVAL_I 2591: 260 261 /* 262 * Flush the D-Cache, since the program we loaded is "data". 263 */ 264 265 and a0,v1,CFE_CACHE_FLUSH_D | CFE_CACHE_INVAL_D | CFE_CACHE_FLUSH_RANGE | CFE_CACHE_INVAL_RANGE 266 beq a0,zero,1f 267 jal bcmcore_l1cache_flush_d 2681: 269 270 /* 271 * Invalidate the I-Cache, so that addresses in the program 272 * region will miss and need to be filled from the data we 273 * just flushed above. 274 */ 275 276 and a0,v1,CFE_CACHE_INVAL_I 277 beq a0,zero,1f 278 jal bcmcore_l1cache_inval_i 2791: 280 281 move ra,s0 282 j ra 283 284END(bcmcore_cacheops) 285 286 287 288/* ********************************************************************* 289 * BCMCORE_TLBHANDLER 290 * 291 * This is the TLB exception handler for the bcmcore 292 * 293 * Note: only K0 and K1 are available to us at this time. 294 * 295 * Input parameters: 296 * nothing 297 * 298 * Return value: 299 * nothing 300 ********************************************************************* */ 301 302 303LEAF(bcmcore_tlbhandler) 304 .set noreorder 305 .set noat 306 307#ifdef BCM4704 308 nop 309#endif 310 311 312/* 313 * This requires a bit of explanation: We only support 256KB 314 * of mapped space for the boot program. This space will be 315 * mapped from 0x2000_0000 to 0x2004_0000 to some physical 316 * memory allocated by the firmware. This is 64 pages 317 * of 4KB each. 318 * 319 * We know our BadVPN2 will be in the range 320 * 0x100000 to 0x1001F0, since the memory is mapped from 321 * 0x2000_0000 to 0x2004_0000. BadVPN2 plus the four bits 322 * of zeroes at the end are bits 31..9 323 * 324 * We also want to place the PTEbase on something other than 325 * a 16MB boundary. Each entry is 16 bytes, and there 326 * are 64 entries, so we need only 10 bits to address 327 * the entire table (it can therefore be aligned on a 328 * 1KB boundary). 329 * 330 * To make this work, we'll shift PTEbase to the right, leaving 331 * the bottom ten bits for the page number, as: 332 * 333 * Bits 31..10: PTEbase 334 * Bits 9..4: BadVPN 335 * Bits 3..0: 16 bytes for table entry 336 * 337 * Therefore: 338 * PTEbase gets shifted right 13 bits. 339 * BadVPN gets masked at 6 bits (mask is 0x3F0) 340 * The bottom 4 bits are zero. 341 * 342 * To range check the address, we can shift the Bad VPN 343 * right by 9 bits, and check for values of 0x1000 and 344 * 0x1001. 345 */ 346 347 348 /* 349 * This part range checks the VPN2 field in the 350 * context register. We only handle 351 * VPN2s in the range 0x100000 to 0x1001F0 352 */ 353 mfc0 k0,C0_TLBHI 354 355 mfc0 k0,C0_CTEXT # Get context 356 sra k0,8 # keep hi part 357 and k0,0x1FFF # of VPN2 358 li k1,0x1000 # 0x1000 is ok 359 beq k0,k1,1f # 360 nop # BDSLOT 361 li k1,0x1001 # 0x1001 is ok 362 beq k0,k1,1f # 363 nop # BDSLOT 364 365 li k0,XTYPE_TLBFILL # all other bits are not 366 j _exc_entry 367 nop # BDSLOT 368 3691: mfc0 k0,C0_CTEXT # Get context 370 sra k0,13 # Shift PTEbase 371 li k1,0x3FF # Generate mask to kill 372 not k1 # BadVPN2 bits 373 and k0,k1 # keep only PTEBase part. 374 375 mfc0 k1,C0_CTEXT # Get Context 376 and k1,0x3F0 # Keep only BadVPN2 bits 377 or k1,k0 # Replace PTEBase 378 379 ld k0,0(k1) # Load entrylo0 380 ld k1,8(k1) # Load entrylo1 381 mtc0 k0,C0_TLBLO0 # and write to CP0 382 mtc0 k1,C0_TLBLO1 383 tlbwr # put it in the TLB 384 ERET 385 nop 386 387 .set reorder 388 .set at 389 390END(bcmcore_tlbhandler) 391 392 393/* ********************************************************************* 394 * End 395 ********************************************************************* */ 396 397