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 <asm-offsets.h> 33#include <config.h> 34#include <version.h> 35 36.globl _start 37_start: b reset 38 ldr pc, _undefined_instruction 39 ldr pc, _software_interrupt 40 ldr pc, _prefetch_abort 41 ldr pc, _data_abort 42 ldr pc, _not_used 43 ldr pc, _irq 44 ldr pc, _fiq 45#ifdef CONFIG_SPL_BUILD 46_undefined_instruction: .word _undefined_instruction 47_software_interrupt: .word _software_interrupt 48_prefetch_abort: .word _prefetch_abort 49_data_abort: .word _data_abort 50_not_used: .word _not_used 51_irq: .word _irq 52_fiq: .word _fiq 53_pad: .word 0x12345678 /* now 16*4=64 */ 54#else 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#endif /* CONFIG_SPL_BUILD */ 64 65.global _end_vect 66_end_vect: 67 68 .balignl 16,0xdeadbeef 69/************************************************************************* 70 * 71 * Startup Code (reset vector) 72 * 73 * do important init only if we don't start from memory! 74 * setup Memory and board specific bits prior to relocation. 75 * relocate armboot to ram 76 * setup stack 77 * 78 *************************************************************************/ 79 80.globl _TEXT_BASE 81_TEXT_BASE: 82 .word CONFIG_SYS_TEXT_BASE 83 84#ifdef CONFIG_TEGRA2 85/* 86 * Tegra2 uses 2 separate CPUs - the AVP (ARM7TDMI) and the CPU (dual A9s). 87 * U-Boot runs on the AVP first, setting things up for the CPU (PLLs, 88 * muxes, clocks, clamps, etc.). Then the AVP halts, and expects the CPU 89 * to pick up its reset vector, which points here. 90 */ 91.globl _armboot_start 92_armboot_start: 93 .word _start 94#endif 95 96/* 97 * These are defined in the board-specific linker script. 98 */ 99.globl _bss_start_ofs 100_bss_start_ofs: 101 .word __bss_start - _start 102 103.global _image_copy_end_ofs 104_image_copy_end_ofs: 105 .word __image_copy_end - _start 106 107.globl _bss_end_ofs 108_bss_end_ofs: 109 .word __bss_end__ - _start 110 111.globl _end_ofs 112_end_ofs: 113 .word _end - _start 114 115#ifdef CONFIG_USE_IRQ 116/* IRQ stack memory (calculated at run-time) */ 117.globl IRQ_STACK_START 118IRQ_STACK_START: 119 .word 0x0badc0de 120 121/* IRQ stack memory (calculated at run-time) */ 122.globl FIQ_STACK_START 123FIQ_STACK_START: 124 .word 0x0badc0de 125#endif 126 127/* IRQ stack memory (calculated at run-time) + 8 bytes */ 128.globl IRQ_STACK_START_IN 129IRQ_STACK_START_IN: 130 .word 0x0badc0de 131 132/* 133 * the actual reset code 134 */ 135 136reset: 137 bl save_boot_params 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#if defined(CONFIG_OMAP34XX) 147 /* Copy vectors to mask ROM indirect addr */ 148 adr r0, _start @ r0 <- current position of code 149 add r0, r0, #4 @ skip reset vector 150 mov r2, #64 @ r2 <- size to copy 151 add r2, r0, r2 @ r2 <- source end address 152 mov r1, #SRAM_OFFSET0 @ build vect addr 153 mov r3, #SRAM_OFFSET1 154 add r1, r1, r3 155 mov r3, #SRAM_OFFSET2 156 add r1, r1, r3 157next: 158 ldmia r0!, {r3 - r10} @ copy from source address [r0] 159 stmia r1!, {r3 - r10} @ copy to target address [r1] 160 cmp r0, r2 @ until source end address [r2] 161 bne next @ loop until equal */ 162#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT) 163 /* No need to copy/exec the clock code - DPLL adjust already done 164 * in NAND/oneNAND Boot. 165 */ 166 bl cpy_clk_code @ put dpll adjust code behind vectors 167#endif /* NAND Boot */ 168#endif 169 /* the mask ROM code should have PLL and others stable */ 170#ifndef CONFIG_SKIP_LOWLEVEL_INIT 171 bl cpu_init_crit 172#endif 173 174/* Set stackpointer in internal RAM to call board_init_f */ 175call_board_init_f: 176 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 177 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ 178 ldr r0,=0x00000000 179 bl board_init_f 180 181/*------------------------------------------------------------------------------*/ 182 183/* 184 * void relocate_code (addr_sp, gd, addr_moni) 185 * 186 * This "function" does not return, instead it continues in RAM 187 * after relocating the monitor code. 188 * 189 */ 190 .globl relocate_code 191relocate_code: 192 mov r4, r0 /* save addr_sp */ 193 mov r5, r1 /* save addr of gd */ 194 mov r6, r2 /* save addr of destination */ 195 196 /* Set up the stack */ 197stack_setup: 198 mov sp, r4 199 200 adr r0, _start 201 cmp r0, r6 202 moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */ 203 beq clear_bss /* skip relocation */ 204 mov r1, r6 /* r1 <- scratch for copy_loop */ 205 ldr r3, _image_copy_end_ofs 206 add r2, r0, r3 /* r2 <- source end address */ 207 208copy_loop: 209 ldmia r0!, {r9-r10} /* copy from source address [r0] */ 210 stmia r1!, {r9-r10} /* copy to target address [r1] */ 211 cmp r0, r2 /* until source end address [r2] */ 212 blo copy_loop 213 214#ifndef CONFIG_SPL_BUILD 215 /* 216 * fix .rel.dyn relocations 217 */ 218 ldr r0, _TEXT_BASE /* r0 <- Text base */ 219 sub r9, r6, 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, r0, r9 /* r0 <- location to fix up in RAM */ 229 ldr r1, [r2, #4] 230 and r7, r1, #0xff 231 cmp r7, #23 /* relative fixup? */ 232 beq fixrel 233 cmp r7, #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, 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 b clear_bss 254_rel_dyn_start_ofs: 255 .word __rel_dyn_start - _start 256_rel_dyn_end_ofs: 257 .word __rel_dyn_end - _start 258_dynsym_start_ofs: 259 .word __dynsym_start - _start 260 261#endif /* #ifndef CONFIG_SPL_BUILD */ 262 263clear_bss: 264#ifdef CONFIG_SPL_BUILD 265 /* No relocation for SPL */ 266 ldr r0, =__bss_start 267 ldr r1, =__bss_end__ 268#else 269 ldr r0, _bss_start_ofs 270 ldr r1, _bss_end_ofs 271 mov r4, r6 /* reloc addr */ 272 add r0, r0, r4 273 add r1, r1, r4 274#endif 275 mov r2, #0x00000000 /* clear */ 276 277clbss_l:str r2, [r0] /* clear loop... */ 278 add r0, r0, #4 279 cmp r0, r1 280 bne clbss_l 281 282/* 283 * We are done. Do not return, instead branch to second part of board 284 * initialization, now running from RAM. 285 */ 286jump_2_ram: 287/* 288 * If I-cache is enabled invalidate it 289 */ 290#ifndef CONFIG_SYS_ICACHE_OFF 291 mcr p15, 0, r0, c7, c5, 0 @ invalidate icache 292 mcr p15, 0, r0, c7, c10, 4 @ DSB 293 mcr p15, 0, r0, c7, c5, 4 @ ISB 294#endif 295 ldr r0, _board_init_r_ofs 296 adr r1, _start 297 add lr, r0, r1 298 add lr, lr, r9 299 /* setup parameters for board_init_r */ 300 mov r0, r5 /* gd_t */ 301 mov r1, r6 /* dest_addr */ 302 /* jump to it ... */ 303 mov pc, lr 304 305_board_init_r_ofs: 306 .word board_init_r - _start 307 308 309#ifndef CONFIG_SKIP_LOWLEVEL_INIT 310/************************************************************************* 311 * 312 * CPU_init_critical registers 313 * 314 * setup important registers 315 * setup memory timing 316 * 317 *************************************************************************/ 318cpu_init_crit: 319 /* 320 * Invalidate L1 I/D 321 */ 322 mov r0, #0 @ set up for MCR 323 mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs 324 mcr p15, 0, r0, c7, c5, 0 @ invalidate icache 325 mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array 326 mcr p15, 0, r0, c7, c10, 4 @ DSB 327 mcr p15, 0, r0, c7, c5, 4 @ ISB 328 329 /* 330 * disable MMU stuff and caches 331 */ 332 mrc p15, 0, r0, c1, c0, 0 333 bic r0, r0, #0x00002000 @ clear bits 13 (--V-) 334 bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) 335 orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align 336 orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB 337#ifdef CONFIG_SYS_ICACHE_OFF 338 bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache 339#else 340 orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache 341#endif 342 mcr p15, 0, r0, c1, c0, 0 343 344 /* 345 * Jump to board specific initialization... 346 * The Mask ROM will have already initialized 347 * basic memory. Go here to bump up clock rate and handle 348 * wake up conditions. 349 */ 350 mov ip, lr @ persevere link reg across call 351 bl lowlevel_init @ go setup pll,mux,memory 352 mov lr, ip @ restore link 353 mov pc, lr @ back to my caller 354#endif 355 356#ifndef CONFIG_SPL_BUILD 357/* 358 ************************************************************************* 359 * 360 * Interrupt handling 361 * 362 ************************************************************************* 363 */ 364@ 365@ IRQ stack frame. 366@ 367#define S_FRAME_SIZE 72 368 369#define S_OLD_R0 68 370#define S_PSR 64 371#define S_PC 60 372#define S_LR 56 373#define S_SP 52 374 375#define S_IP 48 376#define S_FP 44 377#define S_R10 40 378#define S_R9 36 379#define S_R8 32 380#define S_R7 28 381#define S_R6 24 382#define S_R5 20 383#define S_R4 16 384#define S_R3 12 385#define S_R2 8 386#define S_R1 4 387#define S_R0 0 388 389#define MODE_SVC 0x13 390#define I_BIT 0x80 391 392/* 393 * use bad_save_user_regs for abort/prefetch/undef/swi ... 394 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling 395 */ 396 397 .macro bad_save_user_regs 398 sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current 399 @ user stack 400 stmia sp, {r0 - r12} @ Save user registers (now in 401 @ svc mode) r0-r12 402 ldr r2, IRQ_STACK_START_IN @ set base 2 words into abort 403 @ stack 404 ldmia r2, {r2 - r3} @ get values for "aborted" pc 405 @ and cpsr (into parm regs) 406 add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack 407 408 add r5, sp, #S_SP 409 mov r1, lr 410 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr 411 mov r0, sp @ save current stack into r0 412 @ (param register) 413 .endm 414 415 .macro irq_save_user_regs 416 sub sp, sp, #S_FRAME_SIZE 417 stmia sp, {r0 - r12} @ Calling r0-r12 418 add r8, sp, #S_PC @ !! R8 NEEDS to be saved !! 419 @ a reserved stack spot would 420 @ be good. 421 stmdb r8, {sp, lr}^ @ Calling SP, LR 422 str lr, [r8, #0] @ Save calling PC 423 mrs r6, spsr 424 str r6, [r8, #4] @ Save CPSR 425 str r0, [r8, #8] @ Save OLD_R0 426 mov r0, sp 427 .endm 428 429 .macro irq_restore_user_regs 430 ldmia sp, {r0 - lr}^ @ Calling r0 - lr 431 mov r0, r0 432 ldr lr, [sp, #S_PC] @ Get PC 433 add sp, sp, #S_FRAME_SIZE 434 subs pc, lr, #4 @ return & move spsr_svc into 435 @ cpsr 436 .endm 437 438 .macro get_bad_stack 439 ldr r13, IRQ_STACK_START_IN @ setup our mode stack (enter 440 @ in banked mode) 441 442 str lr, [r13] @ save caller lr in position 0 443 @ of saved stack 444 mrs lr, spsr @ get the spsr 445 str lr, [r13, #4] @ save spsr in position 1 of 446 @ saved stack 447 448 mov r13, #MODE_SVC @ prepare SVC-Mode 449 @ msr spsr_c, r13 450 msr spsr, r13 @ switch modes, make sure 451 @ moves will execute 452 mov lr, pc @ capture return pc 453 movs pc, lr @ jump to next instruction & 454 @ switch modes. 455 .endm 456 457 .macro get_bad_stack_swi 458 sub r13, r13, #4 @ space on current stack for 459 @ scratch reg. 460 str r0, [r13] @ save R0's value. 461 ldr r0, IRQ_STACK_START_IN @ get data regions start 462 @ spots for abort stack 463 str lr, [r0] @ save caller lr in position 0 464 @ of saved stack 465 mrs r0, spsr @ get the spsr 466 str lr, [r0, #4] @ save spsr in position 1 of 467 @ saved stack 468 ldr r0, [r13] @ restore r0 469 add r13, r13, #4 @ pop stack entry 470 .endm 471 472 .macro get_irq_stack @ setup IRQ stack 473 ldr sp, IRQ_STACK_START 474 .endm 475 476 .macro get_fiq_stack @ setup FIQ stack 477 ldr sp, FIQ_STACK_START 478 .endm 479 480/* 481 * exception handlers 482 */ 483 .align 5 484undefined_instruction: 485 get_bad_stack 486 bad_save_user_regs 487 bl do_undefined_instruction 488 489 .align 5 490software_interrupt: 491 get_bad_stack_swi 492 bad_save_user_regs 493 bl do_software_interrupt 494 495 .align 5 496prefetch_abort: 497 get_bad_stack 498 bad_save_user_regs 499 bl do_prefetch_abort 500 501 .align 5 502data_abort: 503 get_bad_stack 504 bad_save_user_regs 505 bl do_data_abort 506 507 .align 5 508not_used: 509 get_bad_stack 510 bad_save_user_regs 511 bl do_not_used 512 513#ifdef CONFIG_USE_IRQ 514 515 .align 5 516irq: 517 get_irq_stack 518 irq_save_user_regs 519 bl do_irq 520 irq_restore_user_regs 521 522 .align 5 523fiq: 524 get_fiq_stack 525 /* someone ought to write a more effective fiq_save_user_regs */ 526 irq_save_user_regs 527 bl do_fiq 528 irq_restore_user_regs 529 530#else 531 532 .align 5 533irq: 534 get_bad_stack 535 bad_save_user_regs 536 bl do_irq 537 538 .align 5 539fiq: 540 get_bad_stack 541 bad_save_user_regs 542 bl do_fiq 543 544#endif /* CONFIG_USE_IRQ */ 545#endif /* CONFIG_SPL_BUILD */ 546