1/* 2 * armboot - Startup Code for OMAP3530/ARM Cortex CPU-core 3 * 4 * Copyright (c) 2004 Texas Instruments <r-woodruff2@ti.com> 5 * 6 * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> 7 * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> 8 * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> 9 * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> 10 * Copyright (c) 2003 Kshitij <kshitij@ti.com> 11 * Copyright (c) 2006-2008 Syed Mohammed Khasim <x0khasim@ti.com> 12 * 13 * See file CREDITS for list of people who contributed to this 14 * project. 15 * 16 * This program is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU General Public License as 18 * published by the Free Software Foundation; either version 2 of 19 * the License, or (at your option) any later version. 20 * 21 * This program is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * GNU General Public License for more details. 25 * 26 * You should have received a copy of the GNU General Public License 27 * along with this program; if not, write to the Free Software 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 29 * MA 02111-1307 USA 30 */ 31 32#include <config.h> 33#include <version.h> 34 35.globl _start 36_start: b reset 37 ldr pc, _undefined_instruction 38 ldr pc, _software_interrupt 39 ldr pc, _prefetch_abort 40 ldr pc, _data_abort 41 ldr pc, _not_used 42 ldr pc, _irq 43 ldr pc, _fiq 44 45_undefined_instruction: .word undefined_instruction 46_software_interrupt: .word software_interrupt 47_prefetch_abort: .word prefetch_abort 48_data_abort: .word data_abort 49_not_used: .word not_used 50_irq: .word irq 51_fiq: .word fiq 52_pad: .word 0x12345678 /* now 16*4=64 */ 53.global _end_vect 54_end_vect: 55 56 .balignl 16,0xdeadbeef 57/************************************************************************* 58 * 59 * Startup Code (reset vector) 60 * 61 * do important init only if we don't start from memory! 62 * setup Memory and board specific bits prior to relocation. 63 * relocate armboot to ram 64 * setup stack 65 * 66 *************************************************************************/ 67 68.globl _TEXT_BASE 69_TEXT_BASE: 70 .word CONFIG_SYS_TEXT_BASE 71 72#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC) 73.globl _armboot_start 74_armboot_start: 75 .word _start 76#endif 77 78/* 79 * These are defined in the board-specific linker script. 80 */ 81.globl _bss_start_ofs 82_bss_start_ofs: 83 .word __bss_start - _start 84 85.globl _bss_end_ofs 86_bss_end_ofs: 87 .word _end - _start 88 89#ifdef CONFIG_USE_IRQ 90/* IRQ stack memory (calculated at run-time) */ 91.globl IRQ_STACK_START 92IRQ_STACK_START: 93 .word 0x0badc0de 94 95/* IRQ stack memory (calculated at run-time) */ 96.globl FIQ_STACK_START 97FIQ_STACK_START: 98 .word 0x0badc0de 99#endif 100 101#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) 102/* IRQ stack memory (calculated at run-time) + 8 bytes */ 103.globl IRQ_STACK_START_IN 104IRQ_STACK_START_IN: 105 .word 0x0badc0de 106 107.globl _datarel_start_ofs 108_datarel_start_ofs: 109 .word __datarel_start - _start 110 111.globl _datarelrolocal_start_ofs 112_datarelrolocal_start_ofs: 113 .word __datarelrolocal_start - _start 114 115.globl _datarellocal_start_ofs 116_datarellocal_start_ofs: 117 .word __datarellocal_start - _start 118 119.globl _datarelro_start_ofs 120_datarelro_start_ofs: 121 .word __datarelro_start - _start 122 123.globl _got_start_ofs 124_got_start_ofs: 125 .word __got_start - _start 126 127.globl _got_end_Ofs 128_got_end_ofs: 129 .word __got_end - _start 130 131/* 132 * the actual reset code 133 */ 134 135reset: 136 /* 137 * set the cpu to SVC32 mode 138 */ 139 mrs r0, cpsr 140 bic r0, r0, #0x1f 141 orr r0, r0, #0xd3 142 msr cpsr,r0 143 144#if (CONFIG_OMAP34XX) 145 /* Copy vectors to mask ROM indirect addr */ 146 adr r0, _start @ r0 <- current position of code 147 add r0, r0, #4 @ skip reset vector 148 mov r2, #64 @ r2 <- size to copy 149 add r2, r0, r2 @ r2 <- source end address 150 mov r1, #SRAM_OFFSET0 @ build vect addr 151 mov r3, #SRAM_OFFSET1 152 add r1, r1, r3 153 mov r3, #SRAM_OFFSET2 154 add r1, r1, r3 155next: 156 ldmia r0!, {r3 - r10} @ copy from source address [r0] 157 stmia r1!, {r3 - r10} @ copy to target address [r1] 158 cmp r0, r2 @ until source end address [r2] 159 bne next @ loop until equal */ 160#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT) 161 /* No need to copy/exec the clock code - DPLL adjust already done 162 * in NAND/oneNAND Boot. 163 */ 164 bl cpy_clk_code @ put dpll adjust code behind vectors 165#endif /* NAND Boot */ 166#endif 167 /* the mask ROM code should have PLL and others stable */ 168#ifndef CONFIG_SKIP_LOWLEVEL_INIT 169 bl cpu_init_crit 170#endif 171 172/* Set stackpointer in internal RAM to call board_init_f */ 173call_board_init_f: 174 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 175 ldr r0,=0x00000000 176 bl board_init_f 177 178/*------------------------------------------------------------------------------*/ 179 180/* 181 * void relocate_code (addr_sp, gd, addr_moni) 182 * 183 * This "function" does not return, instead it continues in RAM 184 * after relocating the monitor code. 185 * 186 */ 187 .globl relocate_code 188relocate_code: 189 mov r4, r0 /* save addr_sp */ 190 mov r5, r1 /* save addr of gd */ 191 mov r6, r2 /* save addr of destination */ 192 mov r7, r2 /* save addr of destination */ 193 194 /* Set up the stack */ 195stack_setup: 196 mov sp, r4 197 198#ifndef CONFIG_SKIP_RELOCATE_UBOOT 199 adr r0, _start 200 ldr r2, _TEXT_BASE 201 ldr r3, _bss_start_ofs 202 add r2, r0, r3 /* r2 <- source end address */ 203 cmp r0, r6 204#ifndef CONFIG_PRELOADER 205 beq jump_2_ram 206#endif 207 208copy_loop: 209 ldmia r0!, {r9-r10} /* copy from source address [r0] */ 210 stmia r6!, {r9-r10} /* copy to target address [r1] */ 211 cmp r0, r2 /* until source end address [r2] */ 212 blo copy_loop 213 214#ifndef CONFIG_PRELOADER 215 /* 216 * fix .rel.dyn relocations 217 */ 218 ldr r0, _TEXT_BASE /* r0 <- Text base */ 219 sub r9, r7, r0 /* r9 <- relocation offset */ 220 ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */ 221 add r10, r10, r0 /* r10 <- sym table in FLASH */ 222 ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */ 223 add r2, r2, r0 /* r2 <- rel dyn start in FLASH */ 224 ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */ 225 add r3, r3, r0 /* r3 <- rel dyn end in FLASH */ 226fixloop: 227 ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ 228 add r0, r9 /* r0 <- location to fix up in RAM */ 229 ldr r1, [r2, #4] 230 and r8, r1, #0xff 231 cmp r8, #23 /* relative fixup? */ 232 beq fixrel 233 cmp r8, #2 /* absolute fixup? */ 234 beq fixabs 235 /* ignore unknown type of fixup */ 236 b fixnext 237fixabs: 238 /* absolute fix: set location to (offset) symbol value */ 239 mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */ 240 add r1, r10, r1 /* r1 <- address of symbol in table */ 241 ldr r1, [r1, #4] /* r1 <- symbol value */ 242 add r1, r9 /* r1 <- relocated sym addr */ 243 b fixnext 244fixrel: 245 /* relative fix: increase location by offset */ 246 ldr r1, [r0] 247 add r1, r1, r9 248fixnext: 249 str r1, [r0] 250 add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ 251 cmp r2, r3 252 blo fixloop 253 254clear_bss: 255 ldr r0, _bss_start_ofs 256 ldr r1, _bss_end_ofs 257 ldr r3, _TEXT_BASE /* Text base */ 258 mov r4, r7 /* reloc addr */ 259 add r0, r0, r4 260 add r1, r1, r4 261 mov r2, #0x00000000 /* clear */ 262 263clbss_l:str r2, [r0] /* clear loop... */ 264 add r0, r0, #4 265 cmp r0, r1 266 bne clbss_l 267#endif /* #ifndef CONFIG_PRELOADER */ 268#endif /* #ifndef CONFIG_SKIP_RELOCATE_UBOOT */ 269 270/* 271 * We are done. Do not return, instead branch to second part of board 272 * initialization, now running from RAM. 273 */ 274jump_2_ram: 275 ldr r0, _board_init_r_ofs 276 adr r1, _start 277 add r0, r0, r1 278 add lr, r0, r9 279 /* setup parameters for board_init_r */ 280 mov r0, r5 /* gd_t */ 281 mov r1, r7 /* dest_addr */ 282 /* jump to it ... */ 283 mov pc, lr 284 285_board_init_r_ofs: 286 .word board_init_r - _start 287 288_rel_dyn_start_ofs: 289 .word __rel_dyn_start - _start 290_rel_dyn_end_ofs: 291 .word __rel_dyn_end - _start 292_dynsym_start_ofs: 293 .word __dynsym_start - _start 294 295#else /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */ 296/* 297 * the actual reset code 298 */ 299 300reset: 301 /* 302 * set the cpu to SVC32 mode 303 */ 304 mrs r0, cpsr 305 bic r0, r0, #0x1f 306 orr r0, r0, #0xd3 307 msr cpsr,r0 308 309#if (CONFIG_OMAP34XX) 310 /* Copy vectors to mask ROM indirect addr */ 311 adr r0, _start @ r0 <- current position of code 312 add r0, r0, #4 @ skip reset vector 313 mov r2, #64 @ r2 <- size to copy 314 add r2, r0, r2 @ r2 <- source end address 315 mov r1, #SRAM_OFFSET0 @ build vect addr 316 mov r3, #SRAM_OFFSET1 317 add r1, r1, r3 318 mov r3, #SRAM_OFFSET2 319 add r1, r1, r3 320next: 321 ldmia r0!, {r3 - r10} @ copy from source address [r0] 322 stmia r1!, {r3 - r10} @ copy to target address [r1] 323 cmp r0, r2 @ until source end address [r2] 324 bne next @ loop until equal */ 325#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT) 326 /* No need to copy/exec the clock code - DPLL adjust already done 327 * in NAND/oneNAND Boot. 328 */ 329 bl cpy_clk_code @ put dpll adjust code behind vectors 330#endif /* NAND Boot */ 331#endif 332 /* the mask ROM code should have PLL and others stable */ 333#ifndef CONFIG_SKIP_LOWLEVEL_INIT 334 bl cpu_init_crit 335#endif 336 337#ifndef CONFIG_SKIP_RELOCATE_UBOOT 338relocate: @ relocate U-Boot to RAM 339 adr r0, _start @ r0 <- current position of code 340 ldr r1, _TEXT_BASE @ test if we run from flash or RAM 341 cmp r0, r1 @ don't reloc during debug 342 beq stack_setup 343 344 ldr r2, _armboot_start 345 ldr r3, _bss_start 346 sub r2, r3, r2 @ r2 <- size of armboot 347 add r2, r0, r2 @ r2 <- source end address 348 349copy_loop: @ copy 32 bytes at a time 350 ldmia r0!, {r3 - r10} @ copy from source address [r0] 351 stmia r1!, {r3 - r10} @ copy to target address [r1] 352 cmp r0, r2 @ until source end address [r2] 353 blo copy_loop 354#endif /* CONFIG_SKIP_RELOCATE_UBOOT */ 355 356 /* Set up the stack */ 357stack_setup: 358 ldr r0, _TEXT_BASE @ upper 128 KiB: relocated uboot 359 sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area 360 sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo 361#ifdef CONFIG_USE_IRQ 362 sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ) 363#endif 364 sub sp, r0, #12 @ leave 3 words for abort-stack 365 bic sp, sp, #7 @ 8-byte alignment for ABI compliance 366 367 /* Clear BSS (if any). Is below tx (watch load addr - need space) */ 368clear_bss: 369 ldr r0, _bss_start @ find start of bss segment 370 ldr r1, _bss_end @ stop here 371 mov r2, #0x00000000 @ clear value 372clbss_l: 373 str r2, [r0] @ clear BSS location 374 cmp r0, r1 @ are we at the end yet 375 add r0, r0, #4 @ increment clear index pointer 376 bne clbss_l @ keep clearing till at end 377 378 ldr pc, _start_armboot @ jump to C code 379 380_start_armboot: .word start_armboot 381#endif /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */ 382 383/************************************************************************* 384 * 385 * CPU_init_critical registers 386 * 387 * setup important registers 388 * setup memory timing 389 * 390 *************************************************************************/ 391cpu_init_crit: 392 /* 393 * Invalidate L1 I/D 394 */ 395 mov r0, #0 @ set up for MCR 396 mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs 397 mcr p15, 0, r0, c7, c5, 0 @ invalidate icache 398 399 /* 400 * disable MMU stuff and caches 401 */ 402 mrc p15, 0, r0, c1, c0, 0 403 bic r0, r0, #0x00002000 @ clear bits 13 (--V-) 404 bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) 405 orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align 406 orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB 407 mcr p15, 0, r0, c1, c0, 0 408 409 /* 410 * Jump to board specific initialization... 411 * The Mask ROM will have already initialized 412 * basic memory. Go here to bump up clock rate and handle 413 * wake up conditions. 414 */ 415 mov ip, lr @ persevere link reg across call 416 bl lowlevel_init @ go setup pll,mux,memory 417 mov lr, ip @ restore link 418 mov pc, lr @ back to my caller 419/* 420 ************************************************************************* 421 * 422 * Interrupt handling 423 * 424 ************************************************************************* 425 */ 426@ 427@ IRQ stack frame. 428@ 429#define S_FRAME_SIZE 72 430 431#define S_OLD_R0 68 432#define S_PSR 64 433#define S_PC 60 434#define S_LR 56 435#define S_SP 52 436 437#define S_IP 48 438#define S_FP 44 439#define S_R10 40 440#define S_R9 36 441#define S_R8 32 442#define S_R7 28 443#define S_R6 24 444#define S_R5 20 445#define S_R4 16 446#define S_R3 12 447#define S_R2 8 448#define S_R1 4 449#define S_R0 0 450 451#define MODE_SVC 0x13 452#define I_BIT 0x80 453 454/* 455 * use bad_save_user_regs for abort/prefetch/undef/swi ... 456 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling 457 */ 458 459 .macro bad_save_user_regs 460 sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current 461 @ user stack 462 stmia sp, {r0 - r12} @ Save user registers (now in 463 @ svc mode) r0-r12 464#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC) 465 ldr r2, _armboot_start 466 sub r2, r2, #(CONFIG_SYS_MALLOC_LEN) 467 sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ set base 2 words into abort 468#else 469 ldr r2, IRQ_STACK_START_IN @ set base 2 words into abort 470 @ stack 471#endif 472 ldmia r2, {r2 - r3} @ get values for "aborted" pc 473 @ and cpsr (into parm regs) 474 add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack 475 476 add r5, sp, #S_SP 477 mov r1, lr 478 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr 479 mov r0, sp @ save current stack into r0 480 @ (param register) 481 .endm 482 483 .macro irq_save_user_regs 484 sub sp, sp, #S_FRAME_SIZE 485 stmia sp, {r0 - r12} @ Calling r0-r12 486 add r8, sp, #S_PC @ !! R8 NEEDS to be saved !! 487 @ a reserved stack spot would 488 @ be good. 489 stmdb r8, {sp, lr}^ @ Calling SP, LR 490 str lr, [r8, #0] @ Save calling PC 491 mrs r6, spsr 492 str r6, [r8, #4] @ Save CPSR 493 str r0, [r8, #8] @ Save OLD_R0 494 mov r0, sp 495 .endm 496 497 .macro irq_restore_user_regs 498 ldmia sp, {r0 - lr}^ @ Calling r0 - lr 499 mov r0, r0 500 ldr lr, [sp, #S_PC] @ Get PC 501 add sp, sp, #S_FRAME_SIZE 502 subs pc, lr, #4 @ return & move spsr_svc into 503 @ cpsr 504 .endm 505 506 .macro get_bad_stack 507#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC) 508 ldr r13, _armboot_start @ setup our mode stack (enter 509 sub r13, r13, #(CONFIG_SYS_MALLOC_LEN) @ move past malloc pool 510 sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ move to reserved a couple 511#else 512 ldr r13, IRQ_STACK_START_IN @ setup our mode stack (enter 513 @ in banked mode) 514#endif 515 516 str lr, [r13] @ save caller lr in position 0 517 @ of saved stack 518 mrs lr, spsr @ get the spsr 519 str lr, [r13, #4] @ save spsr in position 1 of 520 @ saved stack 521 522 mov r13, #MODE_SVC @ prepare SVC-Mode 523 @ msr spsr_c, r13 524 msr spsr, r13 @ switch modes, make sure 525 @ moves will execute 526 mov lr, pc @ capture return pc 527 movs pc, lr @ jump to next instruction & 528 @ switch modes. 529 .endm 530 531 .macro get_bad_stack_swi 532 sub r13, r13, #4 @ space on current stack for 533 @ scratch reg. 534 str r0, [r13] @ save R0's value. 535#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC) 536 ldr r0, _armboot_start @ get data regions start 537 sub r0, r0, #(CONFIG_SYS_MALLOC_LEN) @ move past malloc pool 538 sub r0, r0, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ move past gbl and a couple 539#else 540 ldr r0, IRQ_STACK_START_IN @ get data regions start 541 @ spots for abort stack 542#endif 543 str lr, [r0] @ save caller lr in position 0 544 @ of saved stack 545 mrs r0, spsr @ get the spsr 546 str lr, [r0, #4] @ save spsr in position 1 of 547 @ saved stack 548 ldr r0, [r13] @ restore r0 549 add r13, r13, #4 @ pop stack entry 550 .endm 551 552 .macro get_irq_stack @ setup IRQ stack 553 ldr sp, IRQ_STACK_START 554 .endm 555 556 .macro get_fiq_stack @ setup FIQ stack 557 ldr sp, FIQ_STACK_START 558 .endm 559 560/* 561 * exception handlers 562 */ 563 .align 5 564undefined_instruction: 565 get_bad_stack 566 bad_save_user_regs 567 bl do_undefined_instruction 568 569 .align 5 570software_interrupt: 571 get_bad_stack_swi 572 bad_save_user_regs 573 bl do_software_interrupt 574 575 .align 5 576prefetch_abort: 577 get_bad_stack 578 bad_save_user_regs 579 bl do_prefetch_abort 580 581 .align 5 582data_abort: 583 get_bad_stack 584 bad_save_user_regs 585 bl do_data_abort 586 587 .align 5 588not_used: 589 get_bad_stack 590 bad_save_user_regs 591 bl do_not_used 592 593#ifdef CONFIG_USE_IRQ 594 595 .align 5 596irq: 597 get_irq_stack 598 irq_save_user_regs 599 bl do_irq 600 irq_restore_user_regs 601 602 .align 5 603fiq: 604 get_fiq_stack 605 /* someone ought to write a more effective fiq_save_user_regs */ 606 irq_save_user_regs 607 bl do_fiq 608 irq_restore_user_regs 609 610#else 611 612 .align 5 613irq: 614 get_bad_stack 615 bad_save_user_regs 616 bl do_irq 617 618 .align 5 619fiq: 620 get_bad_stack 621 bad_save_user_regs 622 bl do_fiq 623 624#endif 625