1/* 2 * armboot - Startup Code for ARM720 CPU-core 3 * 4 * Copyright (c) 2001 Marius Gr�ger <mag@sysgo.de> 5 * Copyright (c) 2002 Alex Z�pke <azu@sysgo.de> 6 * 7 * See file CREDITS for list of people who contributed to this 8 * project. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23 * MA 02111-1307 USA 24 */ 25 26#include <asm-offsets.h> 27#include <config.h> 28#include <version.h> 29#include <asm/hardware.h> 30 31/* 32 ************************************************************************* 33 * 34 * Jump vector table as in table 3.1 in [1] 35 * 36 ************************************************************************* 37 */ 38 39 40.globl _start 41_start: b reset 42 ldr pc, _undefined_instruction 43 ldr pc, _software_interrupt 44 ldr pc, _prefetch_abort 45 ldr pc, _data_abort 46#ifdef CONFIG_LPC2292 47 .word 0xB4405F76 /* 2's complement of the checksum of the vectors */ 48#else 49 ldr pc, _not_used 50#endif 51 ldr pc, _irq 52 ldr pc, _fiq 53 54_undefined_instruction: .word undefined_instruction 55_software_interrupt: .word software_interrupt 56_prefetch_abort: .word prefetch_abort 57_data_abort: .word data_abort 58_not_used: .word not_used 59_irq: .word irq 60_fiq: .word fiq 61 62 .balignl 16,0xdeadbeef 63 64 65/* 66 ************************************************************************* 67 * 68 * Startup Code (reset vector) 69 * 70 * do important init only if we don't start from RAM! 71 * relocate armboot to ram 72 * setup stack 73 * jump to second stage 74 * 75 ************************************************************************* 76 */ 77 78.globl _TEXT_BASE 79_TEXT_BASE: 80 .word CONFIG_SYS_TEXT_BASE 81 82/* 83 * These are defined in the board-specific linker script. 84 */ 85.globl _bss_start 86_bss_start: 87 .word __bss_start 88 89.globl _bss_end 90_bss_end: 91 .word _end 92 93#ifdef CONFIG_USE_IRQ 94/* IRQ stack memory (calculated at run-time) */ 95.globl IRQ_STACK_START 96IRQ_STACK_START: 97 .word 0x0badc0de 98 99/* IRQ stack memory (calculated at run-time) */ 100.globl FIQ_STACK_START 101FIQ_STACK_START: 102 .word 0x0badc0de 103#endif 104 105/* IRQ stack memory (calculated at run-time) + 8 bytes */ 106.globl IRQ_STACK_START_IN 107IRQ_STACK_START_IN: 108 .word 0x0badc0de 109 110.globl _datarel_start 111_datarel_start: 112 .word __datarel_start 113 114.globl _datarelrolocal_start 115_datarelrolocal_start: 116 .word __datarelrolocal_start 117 118.globl _datarellocal_start 119_datarellocal_start: 120 .word __datarellocal_start 121 122.globl _datarelro_start 123_datarelro_start: 124 .word __datarelro_start 125 126.globl _got_start 127_got_start: 128 .word __got_start 129 130.globl _got_end 131_got_end: 132 .word __got_end 133 134/* 135 * the actual reset code 136 */ 137 138reset: 139 /* 140 * set the cpu to SVC32 mode 141 */ 142 mrs r0,cpsr 143 bic r0,r0,#0x1f 144 orr r0,r0,#0xd3 145 msr cpsr,r0 146 147 /* 148 * we do sys-critical inits only at reboot, 149 * not when booting from ram! 150 */ 151#ifndef CONFIG_SKIP_LOWLEVEL_INIT 152 bl cpu_init_crit 153#endif 154 155#ifdef CONFIG_LPC2292 156 bl lowlevel_init 157#endif 158 159/* Set stackpointer in internal RAM to call board_init_f */ 160call_board_init_f: 161 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 162 ldr r0,=0x00000000 163 bl board_init_f 164 165/*------------------------------------------------------------------------------*/ 166 167/* 168 * void relocate_code (addr_sp, gd, addr_moni) 169 * 170 * This "function" does not return, instead it continues in RAM 171 * after relocating the monitor code. 172 * 173 */ 174 .globl relocate_code 175relocate_code: 176 mov r4, r0 /* save addr_sp */ 177 mov r5, r1 /* save addr of gd */ 178 mov r6, r2 /* save addr of destination */ 179 mov r7, r2 /* save addr of destination */ 180 181 /* Set up the stack */ 182stack_setup: 183 mov sp, r4 184 185 adr r0, _start 186 ldr r2, _TEXT_BASE 187 ldr r3, _bss_start 188 sub r2, r3, r2 /* r2 <- size of armboot */ 189 add r2, r0, r2 /* r2 <- source end address */ 190 cmp r0, r6 191 beq clear_bss 192 193copy_loop: 194 ldmia r0!, {r9-r10} /* copy from source address [r0] */ 195 stmia r6!, {r9-r10} /* copy to target address [r1] */ 196 cmp r0, r2 /* until source end address [r2] */ 197 blo copy_loop 198 199#ifndef CONFIG_PRELOADER 200 /* fix got entries */ 201 ldr r1, _TEXT_BASE /* Text base */ 202 mov r0, r7 /* reloc addr */ 203 ldr r2, _got_start /* addr in Flash */ 204 ldr r3, _got_end /* addr in Flash */ 205 sub r3, r3, r1 206 add r3, r3, r0 207 sub r2, r2, r1 208 add r2, r2, r0 209 210fixloop: 211 ldr r4, [r2] 212 sub r4, r4, r1 213 add r4, r4, r0 214 str r4, [r2] 215 add r2, r2, #4 216 cmp r2, r3 217 blo fixloop 218#endif 219 220clear_bss: 221#ifndef CONFIG_PRELOADER 222 ldr r0, _bss_start 223 ldr r1, _bss_end 224 ldr r3, _TEXT_BASE /* Text base */ 225 mov r4, r7 /* reloc addr */ 226 sub r0, r0, r3 227 add r0, r0, r4 228 sub r1, r1, r3 229 add r1, r1, r4 230 mov r2, #0x00000000 /* clear */ 231 232clbss_l:str r2, [r0] /* clear loop... */ 233 add r0, r0, #4 234 cmp r0, r1 235 bne clbss_l 236 237 bl coloured_LED_init 238 bl red_LED_on 239#endif 240 241/* 242 * We are done. Do not return, instead branch to second part of board 243 * initialization, now running from RAM. 244 */ 245 ldr r0, _TEXT_BASE 246 ldr r2, _board_init_r 247 sub r2, r2, r0 248 add r2, r2, r7 /* position from board_init_r in RAM */ 249 /* setup parameters for board_init_r */ 250 mov r0, r5 /* gd_t */ 251 mov r1, r7 /* dest_addr */ 252 /* jump to it ... */ 253 mov lr, r2 254 mov pc, lr 255 256_board_init_r: .word board_init_r 257 258/* 259 ************************************************************************* 260 * 261 * CPU_init_critical registers 262 * 263 * setup important registers 264 * setup memory timing 265 * 266 ************************************************************************* 267 */ 268 269#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_ARMADILLO) 270 271/* Interupt-Controller base addresses */ 272INTMR1: .word 0x80000280 @ 32 bit size 273INTMR2: .word 0x80001280 @ 16 bit size 274INTMR3: .word 0x80002280 @ 8 bit size 275 276/* SYSCONs */ 277SYSCON1: .word 0x80000100 278SYSCON2: .word 0x80001100 279SYSCON3: .word 0x80002200 280 281#define CLKCTL 0x6 /* mask */ 282#define CLKCTL_18 0x0 /* 18.432 MHz */ 283#define CLKCTL_36 0x2 /* 36.864 MHz */ 284#define CLKCTL_49 0x4 /* 49.152 MHz */ 285#define CLKCTL_73 0x6 /* 73.728 MHz */ 286 287#elif defined(CONFIG_LPC2292) 288PLLCFG_ADR: .word PLLCFG 289PLLFEED_ADR: .word PLLFEED 290PLLCON_ADR: .word PLLCON 291PLLSTAT_ADR: .word PLLSTAT 292VPBDIV_ADR: .word VPBDIV 293MEMMAP_ADR: .word MEMMAP 294 295#endif 296 297cpu_init_crit: 298#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_ARMADILLO) 299 300 /* 301 * mask all IRQs by clearing all bits in the INTMRs 302 */ 303 mov r1, #0x00 304 ldr r0, INTMR1 305 str r1, [r0] 306 ldr r0, INTMR2 307 str r1, [r0] 308 ldr r0, INTMR3 309 str r1, [r0] 310 311 /* 312 * flush v4 I/D caches 313 */ 314 mov r0, #0 315 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ 316 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ 317 318 /* 319 * disable MMU stuff and caches 320 */ 321 mrc p15,0,r0,c1,c0 322 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) 323 bic r0, r0, #0x0000008f @ clear bits 7, 3:0 (B--- WCAM) 324 orr r0, r0, #0x00000002 @ set bit 2 (A) Align 325 mcr p15,0,r0,c1,c0 326#elif defined(CONFIG_NETARM) 327 /* 328 * prior to software reset : need to set pin PORTC4 to be *HRESET 329 */ 330 ldr r0, =NETARM_GEN_MODULE_BASE 331 ldr r1, =(NETARM_GEN_PORT_MODE(0x10) | \ 332 NETARM_GEN_PORT_DIR(0x10)) 333 str r1, [r0, #+NETARM_GEN_PORTC] 334 /* 335 * software reset : see HW Ref. Guide 8.2.4 : Software Service register 336 * for an explanation of this process 337 */ 338 ldr r0, =NETARM_GEN_MODULE_BASE 339 ldr r1, =NETARM_GEN_SW_SVC_RESETA 340 str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] 341 ldr r1, =NETARM_GEN_SW_SVC_RESETB 342 str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] 343 ldr r1, =NETARM_GEN_SW_SVC_RESETA 344 str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] 345 ldr r1, =NETARM_GEN_SW_SVC_RESETB 346 str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] 347 /* 348 * setup PLL and System Config 349 */ 350 ldr r0, =NETARM_GEN_MODULE_BASE 351 352 ldr r1, =( NETARM_GEN_SYS_CFG_LENDIAN | \ 353 NETARM_GEN_SYS_CFG_BUSFULL | \ 354 NETARM_GEN_SYS_CFG_USER_EN | \ 355 NETARM_GEN_SYS_CFG_ALIGN_ABORT | \ 356 NETARM_GEN_SYS_CFG_BUSARB_INT | \ 357 NETARM_GEN_SYS_CFG_BUSMON_EN ) 358 359 str r1, [r0, #+NETARM_GEN_SYSTEM_CONTROL] 360 361#ifndef CONFIG_NETARM_PLL_BYPASS 362 ldr r1, =( NETARM_GEN_PLL_CTL_PLLCNT(NETARM_PLL_COUNT_VAL) | \ 363 NETARM_GEN_PLL_CTL_POLTST_DEF | \ 364 NETARM_GEN_PLL_CTL_INDIV(1) | \ 365 NETARM_GEN_PLL_CTL_ICP_DEF | \ 366 NETARM_GEN_PLL_CTL_OUTDIV(2) ) 367 str r1, [r0, #+NETARM_GEN_PLL_CONTROL] 368#endif 369 370 /* 371 * mask all IRQs by clearing all bits in the INTMRs 372 */ 373 mov r1, #0 374 ldr r0, =NETARM_GEN_MODULE_BASE 375 str r1, [r0, #+NETARM_GEN_INTR_ENABLE] 376 377#elif defined(CONFIG_S3C4510B) 378 379 /* 380 * Mask off all IRQ sources 381 */ 382 ldr r1, =REG_INTMASK 383 ldr r0, =0x3FFFFF 384 str r0, [r1] 385 386 /* 387 * Disable Cache 388 */ 389 ldr r0, =REG_SYSCFG 390 ldr r1, =0x83ffffa0 /* cache-disabled */ 391 str r1, [r0] 392 393#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) 394 /* No specific initialisation for IntegratorAP/CM720T as yet */ 395#elif defined(CONFIG_LPC2292) 396 /* Set-up PLL */ 397 mov r3, #0xAA 398 mov r4, #0x55 399 /* First disconnect and disable the PLL */ 400 ldr r0, PLLCON_ADR 401 mov r1, #0x00 402 str r1, [r0] 403 ldr r0, PLLFEED_ADR /* start feed sequence */ 404 str r3, [r0] 405 str r4, [r0] /* feed sequence done */ 406 /* Set new M and P values */ 407 ldr r0, PLLCFG_ADR 408 mov r1, #0x23 /* M=4 and P=2 */ 409 str r1, [r0] 410 ldr r0, PLLFEED_ADR /* start feed sequence */ 411 str r3, [r0] 412 str r4, [r0] /* feed sequence done */ 413 /* Then enable the PLL */ 414 ldr r0, PLLCON_ADR 415 mov r1, #0x01 /* PLL enable bit */ 416 str r1, [r0] 417 ldr r0, PLLFEED_ADR /* start feed sequence */ 418 str r3, [r0] 419 str r4, [r0] /* feed sequence done */ 420 /* Wait for the lock */ 421 ldr r0, PLLSTAT_ADR 422 mov r1, #0x400 /* lock bit */ 423lock_loop: 424 ldr r2, [r0] 425 and r2, r1, r2 426 cmp r2, #0 427 beq lock_loop 428 /* And finally connect the PLL */ 429 ldr r0, PLLCON_ADR 430 mov r1, #0x03 /* PLL enable bit and connect bit */ 431 str r1, [r0] 432 ldr r0, PLLFEED_ADR /* start feed sequence */ 433 str r3, [r0] 434 str r4, [r0] /* feed sequence done */ 435 /* Set-up VPBDIV register */ 436 ldr r0, VPBDIV_ADR 437 mov r1, #0x01 /* VPB clock is same as process clock */ 438 str r1, [r0] 439#else 440#error No cpu_init_crit() defined for current CPU type 441#endif 442 443#ifdef CONFIG_ARM7_REVD 444 /* set clock speed */ 445 /* !!! we run @ 36 MHz due to a hardware flaw in Rev. D processors */ 446 /* !!! not doing DRAM refresh properly! */ 447 ldr r0, SYSCON3 448 ldr r1, [r0] 449 bic r1, r1, #CLKCTL 450 orr r1, r1, #CLKCTL_36 451 str r1, [r0] 452#endif 453 454#ifndef CONFIG_LPC2292 455 mov ip, lr 456 /* 457 * before relocating, we have to setup RAM timing 458 * because memory timing is board-dependent, you will 459 * find a lowlevel_init.S in your board directory. 460 */ 461 bl lowlevel_init 462 mov lr, ip 463#endif 464 465 mov pc, lr 466 467 468/* 469 ************************************************************************* 470 * 471 * Interrupt handling 472 * 473 ************************************************************************* 474 */ 475 476@ 477@ IRQ stack frame. 478@ 479#define S_FRAME_SIZE 72 480 481#define S_OLD_R0 68 482#define S_PSR 64 483#define S_PC 60 484#define S_LR 56 485#define S_SP 52 486 487#define S_IP 48 488#define S_FP 44 489#define S_R10 40 490#define S_R9 36 491#define S_R8 32 492#define S_R7 28 493#define S_R6 24 494#define S_R5 20 495#define S_R4 16 496#define S_R3 12 497#define S_R2 8 498#define S_R1 4 499#define S_R0 0 500 501#define MODE_SVC 0x13 502#define I_BIT 0x80 503 504/* 505 * use bad_save_user_regs for abort/prefetch/undef/swi ... 506 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling 507 */ 508 509 .macro bad_save_user_regs 510 sub sp, sp, #S_FRAME_SIZE 511 stmia sp, {r0 - r12} @ Calling r0-r12 512 add r8, sp, #S_PC 513 514 ldr r2, IRQ_STACK_START_IN 515 ldmia r2, {r2 - r4} @ get pc, cpsr, old_r0 516 add r0, sp, #S_FRAME_SIZE @ restore sp_SVC 517 518 add r5, sp, #S_SP 519 mov r1, lr 520 stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_r 521 mov r0, sp 522 .endm 523 524 .macro irq_save_user_regs 525 sub sp, sp, #S_FRAME_SIZE 526 stmia sp, {r0 - r12} @ Calling r0-r12 527 add r8, sp, #S_PC 528 stmdb r8, {sp, lr}^ @ Calling SP, LR 529 str lr, [r8, #0] @ Save calling PC 530 mrs r6, spsr 531 str r6, [r8, #4] @ Save CPSR 532 str r0, [r8, #8] @ Save OLD_R0 533 mov r0, sp 534 .endm 535 536 .macro irq_restore_user_regs 537 ldmia sp, {r0 - lr}^ @ Calling r0 - lr 538 mov r0, r0 539 ldr lr, [sp, #S_PC] @ Get PC 540 add sp, sp, #S_FRAME_SIZE 541 subs pc, lr, #4 @ return & move spsr_svc into cpsr 542 .endm 543 544 .macro get_bad_stack 545 ldr r13, IRQ_STACK_START_IN @ setup our mode stack 546 547 str lr, [r13] @ save caller lr / spsr 548 mrs lr, spsr 549 str lr, [r13, #4] 550 551 mov r13, #MODE_SVC @ prepare SVC-Mode 552 msr spsr_c, r13 553 mov lr, pc 554 movs pc, lr 555 .endm 556 557 .macro get_irq_stack @ setup IRQ stack 558 ldr sp, IRQ_STACK_START 559 .endm 560 561 .macro get_fiq_stack @ setup FIQ stack 562 ldr sp, FIQ_STACK_START 563 .endm 564 565/* 566 * exception handlers 567 */ 568 .align 5 569undefined_instruction: 570 get_bad_stack 571 bad_save_user_regs 572 bl do_undefined_instruction 573 574 .align 5 575software_interrupt: 576 get_bad_stack 577 bad_save_user_regs 578 bl do_software_interrupt 579 580 .align 5 581prefetch_abort: 582 get_bad_stack 583 bad_save_user_regs 584 bl do_prefetch_abort 585 586 .align 5 587data_abort: 588 get_bad_stack 589 bad_save_user_regs 590 bl do_data_abort 591 592 .align 5 593not_used: 594 get_bad_stack 595 bad_save_user_regs 596 bl do_not_used 597 598#ifdef CONFIG_USE_IRQ 599 600 .align 5 601irq: 602 get_irq_stack 603 irq_save_user_regs 604 bl do_irq 605 irq_restore_user_regs 606 607 .align 5 608fiq: 609 get_fiq_stack 610 /* someone ought to write a more effiction fiq_save_user_regs */ 611 irq_save_user_regs 612 bl do_fiq 613 irq_restore_user_regs 614 615#else 616 617 .align 5 618irq: 619 get_bad_stack 620 bad_save_user_regs 621 bl do_irq 622 623 .align 5 624fiq: 625 get_bad_stack 626 bad_save_user_regs 627 bl do_fiq 628 629#endif 630 631#if defined(CONFIG_IMPA7) || defined(CONFIG_EP7312) || defined(CONFIG_ARMADILLO) 632 .align 5 633.globl reset_cpu 634reset_cpu: 635 mov ip, #0 636 mcr p15, 0, ip, c7, c7, 0 @ invalidate cache 637 mcr p15, 0, ip, c8, c7, 0 @ flush TLB (v4) 638 mrc p15, 0, ip, c1, c0, 0 @ get ctrl register 639 bic ip, ip, #0x000f @ ............wcam 640 bic ip, ip, #0x2100 @ ..v....s........ 641 mcr p15, 0, ip, c1, c0, 0 @ ctrl register 642 mov pc, r0 643#elif defined(CONFIG_NETARM) 644 .align 5 645.globl reset_cpu 646reset_cpu: 647 ldr r1, =NETARM_MEM_MODULE_BASE 648 ldr r0, [r1, #+NETARM_MEM_CS0_BASE_ADDR] 649 ldr r1, =0xFFFFF000 650 and r0, r1, r0 651 ldr r1, =(relocate-CONFIG_SYS_TEXT_BASE) 652 add r0, r1, r0 653 ldr r4, =NETARM_GEN_MODULE_BASE 654 ldr r1, =NETARM_GEN_SW_SVC_RESETA 655 str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] 656 ldr r1, =NETARM_GEN_SW_SVC_RESETB 657 str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] 658 ldr r1, =NETARM_GEN_SW_SVC_RESETA 659 str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] 660 ldr r1, =NETARM_GEN_SW_SVC_RESETB 661 str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] 662 mov pc, r0 663#elif defined(CONFIG_S3C4510B) 664/* Nothing done here as reseting the CPU is board specific, depending 665 * on external peripherals such as watchdog timers, etc. */ 666#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) 667 /* No specific reset actions for IntegratorAP/CM720T as yet */ 668#elif defined(CONFIG_LPC2292) 669 .align 5 670.globl reset_cpu 671reset_cpu: 672 mov pc, r0 673#else 674#error No reset_cpu() defined for current CPU type 675#endif 676