1/* 2 * ti omap3530 SoC machine assist 3 * arm cortex-a8 processor 4 * 5 * loader uses R11 as scratch. 6 * R9 and R10 are used for `extern register' variables. 7 * 8 * ARM v7 arch. ref. man. §B1.3.3 that we don't need barriers 9 * around moves to CPSR. 10 */ 11 12#include "arm.s" 13 14/* 15 * MCR and MRC are counter-intuitively named. 16 * MCR coproc, opcode1, Rd, CRn, CRm[, opcode2] # arm -> coproc 17 * MRC coproc, opcode1, Rd, CRn, CRm[, opcode2] # coproc -> arm 18 */ 19 20/* 21 * Entered here from Das U-Boot or another Plan 9 kernel with MMU disabled. 22 * Until the MMU is enabled it is OK to call functions provided 23 * they are within ±32MiB relative and do not require any 24 * local variables or more than one argument (i.e. there is 25 * no stack). 26 */ 27TEXT _start(SB), 1, $-4 28 MOVW $setR12(SB), R12 /* load the SB */ 29 SUB $KZERO, R12 30 ADD $PHYSDRAM, R12 31 32 /* SVC mode, interrupts disabled */ 33 MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1 34 MOVW R1, CPSR 35 BARRIERS 36 37 DELAY(printloopret, 1) 38PUTC('\r') 39 DELAY(printloopnl, 1) 40PUTC('\n') 41 /* 42 * work around errata 43 */ 44 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl 45 ORR $(CpACissue1|CpACldstissue1), R1 /* fight omap35x errata 3.1.1.9 */ 46 ORR $CpACibe, R1 /* enable cp15 invalidate */ 47 ORR $CpACl1pe, R1 /* enable l1 parity checking */ 48 ORR $CpCalign, R1 /* catch alignment errors */ 49 BIC $CpACasa, R1 /* no speculative accesses */ 50 /* go faster with fewer restrictions */ 51 BIC $(CpACcachenopipe|CpACcp15serial|CpACcp15waitidle|CpACcp15pipeflush), R1 52 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl 53 ISB 54 55 MRC CpSC, 1, R1, C(CpCLD), C(CpCLDl2), CpCLDl2aux 56 ORR $CpCl2nowralloc, R1 /* fight cortex errata 460075 */ 57 ORR $(CpCl2ecc|CpCl2eccparity), R1 58#ifdef TEDIUM 59 /* 60 * I don't know why this clobbers the system, but I'm tired 61 * of arguing with this fussy processor. To hell with it. 62 */ 63 MCR CpSC, 1, R1, C(CpCLD), C(CpCLDl2), CpCLDl2aux 64 ISB 65#endif 66 DELAY(printloops, 1) 67PUTC('P') 68 /* 69 * disable the MMU & caches 70 */ 71 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl 72 BIC $(CpCdcache|CpCicache|CpCmmu), R1 73 ORR $CpCsbo, R1 74 BIC $CpCsbz, R1 75 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl 76 ISB 77 78 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl 79 BIC $CpACl2en, R1 /* turn l2 cache off */ 80 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl 81 ISB 82 83PUTC('l') 84 DELAY(printloop3, 1) 85 86PUTC('a') 87 /* clear Mach */ 88 MOVW $PADDR(MACHADDR), R4 /* address of Mach */ 89 MOVW $0, R0 90_machZ: 91 MOVW R0, (R4) 92 ADD $4, R4 93 CMP.S $PADDR(L1+L1X(0)), R4 /* end at top-level page table */ 94 BNE _machZ 95 96 /* 97 * set up the MMU page table 98 */ 99 100PUTC('n') 101 /* clear all PTEs first, to provide a default */ 102// MOVW $PADDR(L1+L1X(0)), R4 /* address of PTE for 0 */ 103_ptenv0: 104 ZEROPTE() 105 CMP.S $PADDR(L1+16*KiB), R4 106 BNE _ptenv0 107 108 DELAY(printloop4, 2) 109PUTC(' ') 110 /* 111 * set up double map of PHYSDRAM, KZERO to PHYSDRAM for first few MBs, 112 * but only if KZERO and PHYSDRAM differ. 113 */ 114 MOVW $PTEDRAM, R2 /* PTE bits */ 115 MOVW $PHYSDRAM, R3 /* pa */ 116 CMP $KZERO, R3 117 BEQ no2map 118 MOVW $PADDR(L1+L1X(PHYSDRAM)), R4 /* address of PTE for PHYSDRAM */ 119 MOVW $DOUBLEMAPMBS, R5 120_ptdbl: 121 FILLPTE() 122 SUB.S $1, R5 123 BNE _ptdbl 124no2map: 125 126 /* 127 * back up and fill in PTEs for memory at KZERO. 128 * beagle has 1 bank of 256MB of SDRAM at PHYSDRAM; 129 * igepv2 has 1 bank of 512MB at PHYSDRAM. 130 * Map the maximum (512MB). 131 */ 132PUTC('9') 133 MOVW $PTEDRAM, R2 /* PTE bits */ 134 MOVW $PHYSDRAM, R3 135 MOVW $PADDR(L1+L1X(KZERO)), R4 /* start with PTE for KZERO */ 136 MOVW $512, R5 /* inner loop count (MBs) */ 137_ptekrw: /* set PTEs */ 138 FILLPTE() 139 SUB.S $1, R5 /* decrement inner loop count */ 140 BNE _ptekrw 141 142 /* 143 * back up and fill in PTEs for MMIO 144 * stop somewhere after uarts 145 */ 146PUTC(' ') 147 MOVW $PTEIO, R2 /* PTE bits */ 148 MOVW $PHYSIO, R3 149 MOVW $PADDR(L1+L1X(VIRTIO)), R4 /* start with PTE for VIRTIO */ 150_ptenv2: 151 FILLPTE() 152 CMP.S $PADDR(L1+L1X(PHYSIOEND)), R4 153 BNE _ptenv2 154 155 /* mmu.c sets up the trap vectors later */ 156 157 /* 158 * set up a temporary stack; avoid data & bss segments 159 */ 160 MOVW $(PHYSDRAM | (128*1024*1024)), R13 161 162 /* invalidate caches */ 163 BL cachedinv(SB) 164 MOVW $KZERO, R0 165 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvi), CpCACHEall 166 ISB 167 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEwait 168 BARRIERS 169 170PUTC('f') 171 /* 172 * turn caches on 173 */ 174 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl 175 ORR $CpACl2en, R1 /* turn l2 cache on */ 176 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl 177 BARRIERS 178 179 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl 180 ORR $(CpCdcache|CpCicache), R1 181 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl 182 BARRIERS 183 184PUTC('r') 185 /* set the domain access control */ 186 MOVW $Client, R0 187 BL dacput(SB) 188 189 DELAY(printloop5, 2) 190PUTC('o') 191 /* set the translation table base */ 192 MOVW $PADDR(L1), R0 193 BL ttbput(SB) 194 195 MOVW $0, R0 196 BL pidput(SB) /* paranoia */ 197 198PUTC('m') 199 /* 200 * the little dance to turn the MMU on 201 */ 202 BL cacheuwbinv(SB) 203 BL mmuinvalidate(SB) 204 BL mmuenable(SB) 205 206PUTC(' ') 207 /* warp the PC into the virtual map */ 208 MOVW $KZERO, R0 209 BL _r15warp(SB) 210 211 /* 212 * now running at KZERO+something! 213 */ 214 215 MOVW $setR12(SB), R12 /* reload the SB */ 216 217 /* 218 * set up temporary stack again, in case we've just switched 219 * to a new register set. 220 */ 221 MOVW $(KZERO|(128*1024*1024)), R13 222 223 /* can now execute arbitrary C code */ 224 225 BL cacheuwbinv(SB) 226 227PUTC('B') 228 MOVW $PHYSDRAM, R3 /* pa */ 229 CMP $KZERO, R3 230 BEQ no2unmap 231 /* undo double map of PHYSDRAM, KZERO & first few MBs */ 232 MOVW $(L1+L1X(PHYSDRAM)), R4 /* addr. of PTE for PHYSDRAM */ 233 MOVW $0, R0 234 MOVW $DOUBLEMAPMBS, R5 235_ptudbl: 236 ZEROPTE() 237 SUB.S $1, R5 238 BNE _ptudbl 239no2unmap: 240 BARRIERS 241 MOVW $KZERO, R0 242 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv 243 BARRIERS 244 245#ifdef HIGH_SECURITY /* i.e., not GP omap */ 246 /* hack: set `secure monitor' vector base addr for cortex */ 247// MOVW $HVECTORS, R0 248 MOVW $PADDR(L1), R0 249 SUB $(MACHSIZE+(2*1024)), R0 250 MCR CpSC, 0, R0, C(CpVECS), C(CpVECSbase), CpVECSmon 251 ISB 252#endif 253 254 /* 255 * call main in C 256 * pass Mach to main and set up the stack in it 257 */ 258 MOVW $(MACHADDR), R0 /* Mach */ 259 MOVW R0, R13 260 ADD $(MACHSIZE), R13 /* stack pointer */ 261 SUB $4, R13 /* space for link register */ 262 MOVW R0, R10 /* m = MACHADDR */ 263PUTC('e') 264 BL main(SB) /* void main(Mach*) */ 265 /*FALLTHROUGH*/ 266 267/* 268 * reset the system 269 */ 270 271TEXT _reset(SB), 1, $-4 272 MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R0 273 MOVW R0, CPSR 274 BARRIERS 275 276 DELAY(printloopr, 2) 277PUTC('!') 278PUTC('r') 279PUTC('e') 280PUTC('s') 281PUTC('e') 282PUTC('t') 283PUTC('!') 284PUTC('\r') 285PUTC('\n') 286 287 /* turn the caches off */ 288 BL cacheuwbinv(SB) 289 290 MRC CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl 291 BIC $(CpCicache|CpCdcache|CpCalign), R0 292 ORR $CpCsw, R0 /* enable SWP */ 293 MCR CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl 294 BARRIERS 295 296 /* redo double map of PHYSDRAM, KZERO & first few MBs */ 297 MOVW $PTEDRAM, R2 /* PTE bits */ 298 MOVW $PHYSDRAM, R3 /* pa */ 299 MOVW $(L1+L1X(PHYSDRAM)), R4 /* address of PHYSDRAM's PTE */ 300 MOVW $DOUBLEMAPMBS, R5 301_ptrdbl: 302 FILLPTE() 303 SUB.S $1, R5 304 BNE _ptrdbl 305 306 MOVW $PHYSDRAM, R0 307 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv 308 BARRIERS 309 310 /* turn the MMU off */ 311 MOVW $PHYSDRAM, R0 312 BL _r15warp(SB) 313 BL mmuinvalidate(SB) 314 BL mmudisable(SB) 315 316 /* set new reset vector */ 317 MOVW $HVECTORS, R2 318 MOVW $0xe59ff018, R3 /* MOVW 0x18(R15), R15 */ 319 MOVW R3, (R2) 320 BARRIERS 321 322// MOVW $PHYSFLASH, R3 /* TODO */ 323// MOVW R3, 0x20(R2) /* where $0xe59ff018 jumps to */ 324 325 /* ...and jump to it */ 326// MOVW R2, R15 /* software reboot */ 327_limbo: /* should not get here... */ 328 BL idlehands(SB) 329 B _limbo /* ... and can't get out */ 330 BL _div(SB) /* hack to load _div, etc. */ 331 332TEXT _r15warp(SB), 1, $-4 333 BIC $KSEGM, R14 /* link reg, will become PC */ 334 ORR R0, R14 335 BIC $KSEGM, R13 /* SP too */ 336 ORR R0, R13 337 RET 338 339/* 340 * `single-element' cache operations. 341 * in arm arch v7, they operate on all cache levels, so separate 342 * l2 functions are unnecessary. 343 */ 344 345TEXT cachedwbse(SB), $-4 /* D writeback SE */ 346 MOVW R0, R2 347 348 MOVW CPSR, R3 349 CPSID /* splhi */ 350 351 BARRIERS /* force outstanding stores to cache */ 352 MOVW R2, R0 353 MOVW 4(FP), R1 354 ADD R0, R1 /* R1 is end address */ 355 BIC $(CACHELINESZ-1), R0 /* cache line start */ 356_dwbse: 357 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEse 358 /* can't have a BARRIER here since it zeroes R0 */ 359 ADD $CACHELINESZ, R0 360 CMP.S R0, R1 361 BGT _dwbse 362 B _wait 363 364TEXT cachedwbinvse(SB), $-4 /* D writeback+invalidate SE */ 365 MOVW R0, R2 366 367 MOVW CPSR, R3 368 CPSID /* splhi */ 369 370 BARRIERS /* force outstanding stores to cache */ 371 MOVW R2, R0 372 MOVW 4(FP), R1 373 ADD R0, R1 /* R1 is end address */ 374 BIC $(CACHELINESZ-1), R0 /* cache line start */ 375_dwbinvse: 376 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEse 377 /* can't have a BARRIER here since it zeroes R0 */ 378 ADD $CACHELINESZ, R0 379 CMP.S R0, R1 380 BGT _dwbinvse 381_wait: /* drain write buffer */ 382 BARRIERS 383 /* drain L1 write buffer, also drains L2 eviction buffer on sheeva */ 384 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEwait 385 ISB 386 387 MOVW R3, CPSR /* splx */ 388 RET 389 390TEXT cachedinvse(SB), $-4 /* D invalidate SE */ 391 MOVW R0, R2 392 393 MOVW CPSR, R3 394 CPSID /* splhi */ 395 396 BARRIERS /* force outstanding stores to cache */ 397 MOVW R2, R0 398 MOVW 4(FP), R1 399 ADD R0, R1 /* R1 is end address */ 400 BIC $(CACHELINESZ-1), R0 /* cache line start */ 401_dinvse: 402 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEse 403 /* can't have a BARRIER here since it zeroes R0 */ 404 ADD $CACHELINESZ, R0 405 CMP.S R0, R1 406 BGT _dinvse 407 B _wait 408 409/* 410 * enable mmu and high vectors 411 */ 412TEXT mmuenable(SB), 1, $-4 413 MRC CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl 414 ORR $(CpChv|CpCmmu), R0 415 MCR CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl 416 BARRIERS 417 RET 418 419TEXT mmudisable(SB), 1, $-4 420 MRC CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl 421 BIC $(CpChv|CpCmmu), R0 422 MCR CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl 423 BARRIERS 424 RET 425 426/* 427 * If one of these MCR instructions crashes or hangs the machine, 428 * check your Level 1 page table (at TTB) closely. 429 */ 430TEXT mmuinvalidate(SB), $-4 /* invalidate all */ 431 MOVW CPSR, R2 432 CPSID /* interrupts off */ 433 434 BARRIERS 435 MOVW PC, R0 /* some valid virtual address */ 436 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv 437 BARRIERS 438 MOVW R2, CPSR /* interrupts restored */ 439 RET 440 441TEXT mmuinvalidateaddr(SB), $-4 /* invalidate single entry */ 442 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinvse 443 BARRIERS 444 RET 445 446TEXT cpidget(SB), 1, $-4 /* main ID */ 447 MRC CpSC, 0, R0, C(CpID), C(0), CpIDid 448 RET 449 450TEXT cpctget(SB), 1, $-4 /* cache type */ 451 MRC CpSC, 0, R0, C(CpID), C(0), CpIDct 452 RET 453 454TEXT controlget(SB), 1, $-4 /* control */ 455 MRC CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl 456 RET 457 458TEXT ttbget(SB), 1, $-4 /* translation table base */ 459 MRC CpSC, 0, R0, C(CpTTB), C(0), CpTTB0 460 RET 461 462TEXT ttbput(SB), 1, $-4 /* translation table base */ 463 MCR CpSC, 0, R0, C(CpTTB), C(0), CpTTB0 464 MCR CpSC, 0, R0, C(CpTTB), C(0), CpTTB1 /* cortex has two */ 465 ISB 466 RET 467 468TEXT dacget(SB), 1, $-4 /* domain access control */ 469 MRC CpSC, 0, R0, C(CpDAC), C(0) 470 RET 471 472TEXT dacput(SB), 1, $-4 /* domain access control */ 473 MCR CpSC, 0, R0, C(CpDAC), C(0) 474 ISB 475 RET 476 477TEXT fsrget(SB), 1, $-4 /* data fault status */ 478 MRC CpSC, 0, R0, C(CpFSR), C(0), CpDFSR 479 RET 480 481TEXT ifsrget(SB), 1, $-4 /* instruction fault status */ 482 MRC CpSC, 0, R0, C(CpFSR), C(0), CpIFSR 483 RET 484 485TEXT farget(SB), 1, $-4 /* fault address */ 486 MRC CpSC, 0, R0, C(CpFAR), C(0x0) 487 RET 488 489TEXT getpsr(SB), 1, $-4 490 MOVW CPSR, R0 491 RET 492 493TEXT getscr(SB), 1, $-4 494 MRC CpSC, 0, R0, C(CpCONTROL), C(CpCONTROLscr), CpSCRscr 495 RET 496 497TEXT pidget(SB), 1, $-4 /* address translation pid */ 498 MRC CpSC, 0, R0, C(CpPID), C(0x0) 499 RET 500 501TEXT pidput(SB), 1, $-4 /* address translation pid */ 502 MCR CpSC, 0, R0, C(CpPID), C(0x0) 503 ISB 504 RET 505 506TEXT splhi(SB), 1, $-4 507 MOVW CPSR, R0 508 CPSID /* turn off interrupts */ 509 510 MOVW $(MACHADDR+4), R2 /* save caller pc in Mach */ 511 MOVW R14, 0(R2) 512 RET 513 514TEXT spllo(SB), 1, $-4 /* start marker for devkprof.c */ 515 MOVW CPSR, R0 516 CPSIE 517 RET 518 519TEXT splx(SB), 1, $-4 520 MOVW $(MACHADDR+0x04), R2 /* save caller pc in Mach */ 521 MOVW R14, 0(R2) 522 523 MOVW CPSR, R3 524 MOVW R0, CPSR /* reset interrupt level */ 525 MOVW R3, R0 /* must return old CPSR */ 526 RET 527 528TEXT spldone(SB), 1, $0 /* end marker for devkprof.c */ 529 RET 530 531TEXT islo(SB), 1, $-4 532 MOVW CPSR, R0 533 AND $(PsrDirq), R0 534 EOR $(PsrDirq), R0 535 RET 536 537TEXT tas(SB), $-4 538TEXT _tas(SB), $-4 539 MOVW R0,R1 540 MOVW $1,R0 541 SWPW R0,(R1) /* fix: deprecated in armv7 */ 542 RET 543 544TEXT clz(SB), $-4 545 CLZ(0, 0) /* 0 is R0 */ 546 RET 547 548TEXT setlabel(SB), 1, $-4 549 MOVW R13, 0(R0) /* sp */ 550 MOVW R14, 4(R0) /* pc */ 551 MOVW $0, R0 552 RET 553 554TEXT gotolabel(SB), 1, $-4 555 MOVW 0(R0), R13 /* sp */ 556 MOVW 4(R0), R14 /* pc */ 557 MOVW $1, R0 558 RET 559 560TEXT getcallerpc(SB), 1, $-4 561 MOVW 0(R13), R0 562 RET 563 564TEXT idlehands(SB), $-4 565 BARRIERS 566 WFI 567 RET 568 569TEXT coherence(SB), $-4 570 BARRIERS 571 RET 572 573#include "cache.v7.s" 574