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#ifdef CONFIG_SPL_BUILD 55_undefined_instruction: .word _undefined_instruction 56_software_interrupt: .word _software_interrupt 57_prefetch_abort: .word _prefetch_abort 58_data_abort: .word _data_abort 59_not_used: .word _not_used 60_irq: .word _irq 61_fiq: .word _fiq 62_pad: .word 0x12345678 /* now 16*4=64 */ 63#else 64_undefined_instruction: .word undefined_instruction 65_software_interrupt: .word software_interrupt 66_prefetch_abort: .word prefetch_abort 67_data_abort: .word data_abort 68_not_used: .word not_used 69_irq: .word irq 70_fiq: .word fiq 71_pad: .word 0x12345678 /* now 16*4=64 */ 72#endif /* CONFIG_SPL_BUILD */ 73 74 .balignl 16,0xdeadbeef 75 76 77/* 78 ************************************************************************* 79 * 80 * Startup Code (reset vector) 81 * 82 * do important init only if we don't start from RAM! 83 * relocate armboot to ram 84 * setup stack 85 * jump to second stage 86 * 87 ************************************************************************* 88 */ 89 90.globl _TEXT_BASE 91_TEXT_BASE: 92#ifdef CONFIG_SPL_BUILD 93 .word CONFIG_SPL_TEXT_BASE 94#else 95 .word CONFIG_SYS_TEXT_BASE 96#endif 97 98/* 99 * These are defined in the board-specific linker script. 100 * Subtracting _start from them lets the linker put their 101 * relative position in the executable instead of leaving 102 * them null. 103 */ 104.globl _bss_start_ofs 105_bss_start_ofs: 106 .word __bss_start - _start 107 108.globl _bss_end_ofs 109_bss_end_ofs: 110 .word __bss_end__ - _start 111 112.globl _end_ofs 113_end_ofs: 114 .word _end - _start 115 116#ifdef CONFIG_USE_IRQ 117/* IRQ stack memory (calculated at run-time) */ 118.globl IRQ_STACK_START 119IRQ_STACK_START: 120 .word 0x0badc0de 121 122/* IRQ stack memory (calculated at run-time) */ 123.globl FIQ_STACK_START 124FIQ_STACK_START: 125 .word 0x0badc0de 126#endif 127 128/* IRQ stack memory (calculated at run-time) + 8 bytes */ 129.globl IRQ_STACK_START_IN 130IRQ_STACK_START_IN: 131 .word 0x0badc0de 132 133/* 134 * the actual reset code 135 */ 136 137reset: 138 /* 139 * set the cpu to SVC32 mode 140 */ 141 mrs r0,cpsr 142 bic r0,r0,#0x1f 143 orr r0,r0,#0xd3 144 msr cpsr,r0 145 146 /* 147 * we do sys-critical inits only at reboot, 148 * not when booting from ram! 149 */ 150#ifndef CONFIG_SKIP_LOWLEVEL_INIT 151 bl cpu_init_crit 152#endif 153 154#ifdef CONFIG_LPC2292 155 bl lowlevel_init 156#endif 157 158/* Set stackpointer in internal RAM to call board_init_f */ 159call_board_init_f: 160 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 161 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 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 180 /* Set up the stack */ 181stack_setup: 182 mov sp, r4 183 184 adr r0, _start 185 cmp r0, r6 186 moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */ 187 beq clear_bss /* skip relocation */ 188 mov r1, r6 /* r1 <- scratch for copy_loop */ 189 ldr r3, _bss_start_ofs 190 add r2, r0, r3 /* r2 <- source end address */ 191 192copy_loop: 193 ldmia r0!, {r9-r10} /* copy from source address [r0] */ 194 stmia r1!, {r9-r10} /* copy to target address [r1] */ 195 cmp r0, r2 /* until source end address [r2] */ 196 blo copy_loop 197 198#ifndef CONFIG_SPL_BUILD 199 /* 200 * fix .rel.dyn relocations 201 */ 202 ldr r0, _TEXT_BASE /* r0 <- Text base */ 203 sub r9, r6, r0 /* r9 <- relocation offset */ 204 ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */ 205 add r10, r10, r0 /* r10 <- sym table in FLASH */ 206 ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */ 207 add r2, r2, r0 /* r2 <- rel dyn start in FLASH */ 208 ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */ 209 add r3, r3, r0 /* r3 <- rel dyn end in FLASH */ 210fixloop: 211 ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ 212 add r0, r0, r9 /* r0 <- location to fix up in RAM */ 213 ldr r1, [r2, #4] 214 and r7, r1, #0xff 215 cmp r7, #23 /* relative fixup? */ 216 beq fixrel 217 cmp r7, #2 /* absolute fixup? */ 218 beq fixabs 219 /* ignore unknown type of fixup */ 220 b fixnext 221fixabs: 222 /* absolute fix: set location to (offset) symbol value */ 223 mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */ 224 add r1, r10, r1 /* r1 <- address of symbol in table */ 225 ldr r1, [r1, #4] /* r1 <- symbol value */ 226 add r1, r1, r9 /* r1 <- relocated sym addr */ 227 b fixnext 228fixrel: 229 /* relative fix: increase location by offset */ 230 ldr r1, [r0] 231 add r1, r1, r9 232fixnext: 233 str r1, [r0] 234 add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ 235 cmp r2, r3 236 blo fixloop 237#endif 238 239clear_bss: 240#ifndef CONFIG_SPL_BUILD 241 ldr r0, _bss_start_ofs 242 ldr r1, _bss_end_ofs 243 mov r4, r6 /* reloc addr */ 244 add r0, r0, r4 245 add r1, r1, r4 246 mov r2, #0x00000000 /* clear */ 247 248clbss_l:cmp r0, r1 /* clear loop... */ 249 bhs clbss_e /* if reached end of bss, exit */ 250 str r2, [r0] 251 add r0, r0, #4 252 b clbss_l 253clbss_e: 254 255 bl coloured_LED_init 256 bl red_led_on 257#endif 258 259/* 260 * We are done. Do not return, instead branch to second part of board 261 * initialization, now running from RAM. 262 */ 263 ldr r0, _board_init_r_ofs 264 adr r1, _start 265 add lr, r0, r1 266 add lr, lr, r9 267 /* setup parameters for board_init_r */ 268 mov r0, r5 /* gd_t */ 269 mov r1, r6 /* dest_addr */ 270 /* jump to it ... */ 271 mov pc, lr 272 273_board_init_r_ofs: 274 .word board_init_r - _start 275 276_rel_dyn_start_ofs: 277 .word __rel_dyn_start - _start 278_rel_dyn_end_ofs: 279 .word __rel_dyn_end - _start 280_dynsym_start_ofs: 281 .word __dynsym_start - _start 282 283/* 284 ************************************************************************* 285 * 286 * CPU_init_critical registers 287 * 288 * setup important registers 289 * setup memory timing 290 * 291 ************************************************************************* 292 */ 293 294#if defined(CONFIG_LPC2292) 295PLLCFG_ADR: .word PLLCFG 296PLLFEED_ADR: .word PLLFEED 297PLLCON_ADR: .word PLLCON 298PLLSTAT_ADR: .word PLLSTAT 299VPBDIV_ADR: .word VPBDIV 300MEMMAP_ADR: .word MEMMAP 301 302#endif 303 304cpu_init_crit: 305#if defined(CONFIG_NETARM) 306 /* 307 * prior to software reset : need to set pin PORTC4 to be *HRESET 308 */ 309 ldr r0, =NETARM_GEN_MODULE_BASE 310 ldr r1, =(NETARM_GEN_PORT_MODE(0x10) | \ 311 NETARM_GEN_PORT_DIR(0x10)) 312 str r1, [r0, #+NETARM_GEN_PORTC] 313 /* 314 * software reset : see HW Ref. Guide 8.2.4 : Software Service register 315 * for an explanation of this process 316 */ 317 ldr r0, =NETARM_GEN_MODULE_BASE 318 ldr r1, =NETARM_GEN_SW_SVC_RESETA 319 str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] 320 ldr r1, =NETARM_GEN_SW_SVC_RESETB 321 str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] 322 ldr r1, =NETARM_GEN_SW_SVC_RESETA 323 str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] 324 ldr r1, =NETARM_GEN_SW_SVC_RESETB 325 str r1, [r0, #+NETARM_GEN_SOFTWARE_SERVICE] 326 /* 327 * setup PLL and System Config 328 */ 329 ldr r0, =NETARM_GEN_MODULE_BASE 330 331 ldr r1, =( NETARM_GEN_SYS_CFG_LENDIAN | \ 332 NETARM_GEN_SYS_CFG_BUSFULL | \ 333 NETARM_GEN_SYS_CFG_USER_EN | \ 334 NETARM_GEN_SYS_CFG_ALIGN_ABORT | \ 335 NETARM_GEN_SYS_CFG_BUSARB_INT | \ 336 NETARM_GEN_SYS_CFG_BUSMON_EN ) 337 338 str r1, [r0, #+NETARM_GEN_SYSTEM_CONTROL] 339 340#ifndef CONFIG_NETARM_PLL_BYPASS 341 ldr r1, =( NETARM_GEN_PLL_CTL_PLLCNT(NETARM_PLL_COUNT_VAL) | \ 342 NETARM_GEN_PLL_CTL_POLTST_DEF | \ 343 NETARM_GEN_PLL_CTL_INDIV(1) | \ 344 NETARM_GEN_PLL_CTL_ICP_DEF | \ 345 NETARM_GEN_PLL_CTL_OUTDIV(2) ) 346 str r1, [r0, #+NETARM_GEN_PLL_CONTROL] 347#endif 348 349 /* 350 * mask all IRQs by clearing all bits in the INTMRs 351 */ 352 mov r1, #0 353 ldr r0, =NETARM_GEN_MODULE_BASE 354 str r1, [r0, #+NETARM_GEN_INTR_ENABLE] 355 356#elif defined(CONFIG_S3C4510B) 357 358 /* 359 * Mask off all IRQ sources 360 */ 361 ldr r1, =REG_INTMASK 362 ldr r0, =0x3FFFFF 363 str r0, [r1] 364 365 /* 366 * Disable Cache 367 */ 368 ldr r0, =REG_SYSCFG 369 ldr r1, =0x83ffffa0 /* cache-disabled */ 370 str r1, [r0] 371 372#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) 373 /* No specific initialisation for IntegratorAP/CM720T as yet */ 374#elif defined(CONFIG_LPC2292) 375 /* Set-up PLL */ 376 mov r3, #0xAA 377 mov r4, #0x55 378 /* First disconnect and disable the PLL */ 379 ldr r0, PLLCON_ADR 380 mov r1, #0x00 381 str r1, [r0] 382 ldr r0, PLLFEED_ADR /* start feed sequence */ 383 str r3, [r0] 384 str r4, [r0] /* feed sequence done */ 385 /* Set new M and P values */ 386 ldr r0, PLLCFG_ADR 387 mov r1, #0x23 /* M=4 and P=2 */ 388 str r1, [r0] 389 ldr r0, PLLFEED_ADR /* start feed sequence */ 390 str r3, [r0] 391 str r4, [r0] /* feed sequence done */ 392 /* Then enable the PLL */ 393 ldr r0, PLLCON_ADR 394 mov r1, #0x01 /* PLL enable bit */ 395 str r1, [r0] 396 ldr r0, PLLFEED_ADR /* start feed sequence */ 397 str r3, [r0] 398 str r4, [r0] /* feed sequence done */ 399 /* Wait for the lock */ 400 ldr r0, PLLSTAT_ADR 401 mov r1, #0x400 /* lock bit */ 402lock_loop: 403 ldr r2, [r0] 404 and r2, r1, r2 405 cmp r2, #0 406 beq lock_loop 407 /* And finally connect the PLL */ 408 ldr r0, PLLCON_ADR 409 mov r1, #0x03 /* PLL enable bit and connect bit */ 410 str r1, [r0] 411 ldr r0, PLLFEED_ADR /* start feed sequence */ 412 str r3, [r0] 413 str r4, [r0] /* feed sequence done */ 414 /* Set-up VPBDIV register */ 415 ldr r0, VPBDIV_ADR 416 mov r1, #0x01 /* VPB clock is same as process clock */ 417 str r1, [r0] 418#elif defined(CONFIG_TEGRA) 419 /* No cpu_init_crit for tegra as yet */ 420#else 421#error No cpu_init_crit() defined for current CPU type 422#endif 423 424#ifdef CONFIG_ARM7_REVD 425 /* set clock speed */ 426 /* !!! we run @ 36 MHz due to a hardware flaw in Rev. D processors */ 427 /* !!! not doing DRAM refresh properly! */ 428 ldr r0, SYSCON3 429 ldr r1, [r0] 430 bic r1, r1, #CLKCTL 431 orr r1, r1, #CLKCTL_36 432 str r1, [r0] 433#endif 434 435#if !defined(CONFIG_LPC2292) && !defined(CONFIG_TEGRA) 436 mov ip, lr 437 /* 438 * before relocating, we have to setup RAM timing 439 * because memory timing is board-dependent, you will 440 * find a lowlevel_init.S in your board directory. 441 */ 442 bl lowlevel_init 443 mov lr, ip 444#endif 445 446 mov pc, lr 447 448 449#ifndef CONFIG_SPL_BUILD 450/* 451 ************************************************************************* 452 * 453 * Interrupt handling 454 * 455 ************************************************************************* 456 */ 457 458@ 459@ IRQ stack frame. 460@ 461#define S_FRAME_SIZE 72 462 463#define S_OLD_R0 68 464#define S_PSR 64 465#define S_PC 60 466#define S_LR 56 467#define S_SP 52 468 469#define S_IP 48 470#define S_FP 44 471#define S_R10 40 472#define S_R9 36 473#define S_R8 32 474#define S_R7 28 475#define S_R6 24 476#define S_R5 20 477#define S_R4 16 478#define S_R3 12 479#define S_R2 8 480#define S_R1 4 481#define S_R0 0 482 483#define MODE_SVC 0x13 484#define I_BIT 0x80 485 486/* 487 * use bad_save_user_regs for abort/prefetch/undef/swi ... 488 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling 489 */ 490 491 .macro bad_save_user_regs 492 sub sp, sp, #S_FRAME_SIZE 493 stmia sp, {r0 - r12} @ Calling r0-r12 494 add r8, sp, #S_PC 495 496 ldr r2, IRQ_STACK_START_IN 497 ldmia r2, {r2 - r4} @ get pc, cpsr, old_r0 498 add r0, sp, #S_FRAME_SIZE @ restore sp_SVC 499 500 add r5, sp, #S_SP 501 mov r1, lr 502 stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_r 503 mov r0, sp 504 .endm 505 506 .macro irq_save_user_regs 507 sub sp, sp, #S_FRAME_SIZE 508 stmia sp, {r0 - r12} @ Calling r0-r12 509 add r8, sp, #S_PC 510 stmdb r8, {sp, lr}^ @ Calling SP, LR 511 str lr, [r8, #0] @ Save calling PC 512 mrs r6, spsr 513 str r6, [r8, #4] @ Save CPSR 514 str r0, [r8, #8] @ Save OLD_R0 515 mov r0, sp 516 .endm 517 518 .macro irq_restore_user_regs 519 ldmia sp, {r0 - lr}^ @ Calling r0 - lr 520 mov r0, r0 521 ldr lr, [sp, #S_PC] @ Get PC 522 add sp, sp, #S_FRAME_SIZE 523 subs pc, lr, #4 @ return & move spsr_svc into cpsr 524 .endm 525 526 .macro get_bad_stack 527 ldr r13, IRQ_STACK_START_IN @ setup our mode stack 528 529 str lr, [r13] @ save caller lr / spsr 530 mrs lr, spsr 531 str lr, [r13, #4] 532 533 mov r13, #MODE_SVC @ prepare SVC-Mode 534 msr spsr_c, r13 535 mov lr, pc 536 movs pc, lr 537 .endm 538 539 .macro get_irq_stack @ setup IRQ stack 540 ldr sp, IRQ_STACK_START 541 .endm 542 543 .macro get_fiq_stack @ setup FIQ stack 544 ldr sp, FIQ_STACK_START 545 .endm 546 547/* 548 * exception handlers 549 */ 550 .align 5 551undefined_instruction: 552 get_bad_stack 553 bad_save_user_regs 554 bl do_undefined_instruction 555 556 .align 5 557software_interrupt: 558 get_bad_stack 559 bad_save_user_regs 560 bl do_software_interrupt 561 562 .align 5 563prefetch_abort: 564 get_bad_stack 565 bad_save_user_regs 566 bl do_prefetch_abort 567 568 .align 5 569data_abort: 570 get_bad_stack 571 bad_save_user_regs 572 bl do_data_abort 573 574 .align 5 575not_used: 576 get_bad_stack 577 bad_save_user_regs 578 bl do_not_used 579 580#ifdef CONFIG_USE_IRQ 581 582 .align 5 583irq: 584 get_irq_stack 585 irq_save_user_regs 586 bl do_irq 587 irq_restore_user_regs 588 589 .align 5 590fiq: 591 get_fiq_stack 592 /* someone ought to write a more effiction fiq_save_user_regs */ 593 irq_save_user_regs 594 bl do_fiq 595 irq_restore_user_regs 596 597#else 598 599 .align 5 600irq: 601 get_bad_stack 602 bad_save_user_regs 603 bl do_irq 604 605 .align 5 606fiq: 607 get_bad_stack 608 bad_save_user_regs 609 bl do_fiq 610 611#endif 612#endif /* CONFIG_SPL_BUILD */ 613 614#if defined(CONFIG_NETARM) 615 .align 5 616.globl reset_cpu 617reset_cpu: 618 ldr r1, =NETARM_MEM_MODULE_BASE 619 ldr r0, [r1, #+NETARM_MEM_CS0_BASE_ADDR] 620 ldr r1, =0xFFFFF000 621 and r0, r1, r0 622 ldr r1, =(relocate-CONFIG_SYS_TEXT_BASE) 623 add r0, r1, r0 624 ldr r4, =NETARM_GEN_MODULE_BASE 625 ldr r1, =NETARM_GEN_SW_SVC_RESETA 626 str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] 627 ldr r1, =NETARM_GEN_SW_SVC_RESETB 628 str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] 629 ldr r1, =NETARM_GEN_SW_SVC_RESETA 630 str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] 631 ldr r1, =NETARM_GEN_SW_SVC_RESETB 632 str r1, [r4, #+NETARM_GEN_SOFTWARE_SERVICE] 633 mov pc, r0 634#elif defined(CONFIG_S3C4510B) 635/* Nothing done here as reseting the CPU is board specific, depending 636 * on external peripherals such as watchdog timers, etc. */ 637#elif defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_INTEGRATOR) 638 /* No specific reset actions for IntegratorAP/CM720T as yet */ 639#elif defined(CONFIG_LPC2292) 640 .align 5 641.globl reset_cpu 642reset_cpu: 643 mov pc, r0 644#elif defined(CONFIG_TEGRA) 645 /* No specific reset actions for tegra as yet */ 646#else 647#error No reset_cpu() defined for current CPU type 648#endif 649