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 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.global _end_vect 55_end_vect: 56 57 .balignl 16,0xdeadbeef 58/************************************************************************* 59 * 60 * Startup Code (reset vector) 61 * 62 * do important init only if we don't start from memory! 63 * setup Memory and board specific bits prior to relocation. 64 * relocate armboot to ram 65 * setup stack 66 * 67 *************************************************************************/ 68 69.globl _TEXT_BASE 70_TEXT_BASE: 71 .word CONFIG_SYS_TEXT_BASE 72 73/* 74 * These are defined in the board-specific linker script. 75 */ 76.globl _bss_start_ofs 77_bss_start_ofs: 78 .word __bss_start - _start 79 80.globl _bss_end_ofs 81_bss_end_ofs: 82 .word _end - _start 83 84#ifdef CONFIG_USE_IRQ 85/* IRQ stack memory (calculated at run-time) */ 86.globl IRQ_STACK_START 87IRQ_STACK_START: 88 .word 0x0badc0de 89 90/* IRQ stack memory (calculated at run-time) */ 91.globl FIQ_STACK_START 92FIQ_STACK_START: 93 .word 0x0badc0de 94#endif 95 96/* IRQ stack memory (calculated at run-time) + 8 bytes */ 97.globl IRQ_STACK_START_IN 98IRQ_STACK_START_IN: 99 .word 0x0badc0de 100 101/* 102 * the actual reset code 103 */ 104 105reset: 106 /* 107 * set the cpu to SVC32 mode 108 */ 109 mrs r0, cpsr 110 bic r0, r0, #0x1f 111 orr r0, r0, #0xd3 112 msr cpsr,r0 113 114#if (CONFIG_OMAP34XX) 115 /* Copy vectors to mask ROM indirect addr */ 116 adr r0, _start @ r0 <- current position of code 117 add r0, r0, #4 @ skip reset vector 118 mov r2, #64 @ r2 <- size to copy 119 add r2, r0, r2 @ r2 <- source end address 120 mov r1, #SRAM_OFFSET0 @ build vect addr 121 mov r3, #SRAM_OFFSET1 122 add r1, r1, r3 123 mov r3, #SRAM_OFFSET2 124 add r1, r1, r3 125next: 126 ldmia r0!, {r3 - r10} @ copy from source address [r0] 127 stmia r1!, {r3 - r10} @ copy to target address [r1] 128 cmp r0, r2 @ until source end address [r2] 129 bne next @ loop until equal */ 130#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT) 131 /* No need to copy/exec the clock code - DPLL adjust already done 132 * in NAND/oneNAND Boot. 133 */ 134 bl cpy_clk_code @ put dpll adjust code behind vectors 135#endif /* NAND Boot */ 136#endif 137 /* the mask ROM code should have PLL and others stable */ 138#ifndef CONFIG_SKIP_LOWLEVEL_INIT 139 bl cpu_init_crit 140#endif 141 142/* Set stackpointer in internal RAM to call board_init_f */ 143call_board_init_f: 144 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 145 ldr r0,=0x00000000 146 bl board_init_f 147 148/*------------------------------------------------------------------------------*/ 149 150/* 151 * void relocate_code (addr_sp, gd, addr_moni) 152 * 153 * This "function" does not return, instead it continues in RAM 154 * after relocating the monitor code. 155 * 156 */ 157 .globl relocate_code 158relocate_code: 159 mov r4, r0 /* save addr_sp */ 160 mov r5, r1 /* save addr of gd */ 161 mov r6, r2 /* save addr of destination */ 162 mov r7, r2 /* save addr of destination */ 163 164 /* Set up the stack */ 165stack_setup: 166 mov sp, r4 167 168 adr r0, _start 169 ldr r2, _TEXT_BASE 170 ldr r3, _bss_start_ofs 171 add r2, r0, r3 /* r2 <- source end address */ 172 cmp r0, r6 173#ifndef CONFIG_PRELOADER 174 beq jump_2_ram 175#endif 176 177copy_loop: 178 ldmia r0!, {r9-r10} /* copy from source address [r0] */ 179 stmia r6!, {r9-r10} /* copy to target address [r1] */ 180 cmp r0, r2 /* until source end address [r2] */ 181 blo copy_loop 182 183#ifndef CONFIG_PRELOADER 184 /* 185 * fix .rel.dyn relocations 186 */ 187 ldr r0, _TEXT_BASE /* r0 <- Text base */ 188 sub r9, r7, r0 /* r9 <- relocation offset */ 189 ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */ 190 add r10, r10, r0 /* r10 <- sym table in FLASH */ 191 ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */ 192 add r2, r2, r0 /* r2 <- rel dyn start in FLASH */ 193 ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */ 194 add r3, r3, r0 /* r3 <- rel dyn end in FLASH */ 195fixloop: 196 ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */ 197 add r0, r0, r9 /* r0 <- location to fix up in RAM */ 198 ldr r1, [r2, #4] 199 and r8, r1, #0xff 200 cmp r8, #23 /* relative fixup? */ 201 beq fixrel 202 cmp r8, #2 /* absolute fixup? */ 203 beq fixabs 204 /* ignore unknown type of fixup */ 205 b fixnext 206fixabs: 207 /* absolute fix: set location to (offset) symbol value */ 208 mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */ 209 add r1, r10, r1 /* r1 <- address of symbol in table */ 210 ldr r1, [r1, #4] /* r1 <- symbol value */ 211 add r1, r9 /* r1 <- relocated sym addr */ 212 b fixnext 213fixrel: 214 /* relative fix: increase location by offset */ 215 ldr r1, [r0] 216 add r1, r1, r9 217fixnext: 218 str r1, [r0] 219 add r2, r2, #8 /* each rel.dyn entry is 8 bytes */ 220 cmp r2, r3 221 blo fixloop 222 223clear_bss: 224 ldr r0, _bss_start_ofs 225 ldr r1, _bss_end_ofs 226 ldr r3, _TEXT_BASE /* Text base */ 227 mov r4, r7 /* reloc addr */ 228 add r0, r0, r4 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#endif /* #ifndef CONFIG_PRELOADER */ 237 238/* 239 * We are done. Do not return, instead branch to second part of board 240 * initialization, now running from RAM. 241 */ 242jump_2_ram: 243 ldr r0, _board_init_r_ofs 244 adr r1, _start 245 add lr, r0, r1 246 add lr, lr, r9 247 /* setup parameters for board_init_r */ 248 mov r0, r5 /* gd_t */ 249 mov r1, r7 /* dest_addr */ 250 /* jump to it ... */ 251 mov pc, lr 252 253_board_init_r_ofs: 254 .word board_init_r - _start 255 256_rel_dyn_start_ofs: 257 .word __rel_dyn_start - _start 258_rel_dyn_end_ofs: 259 .word __rel_dyn_end - _start 260_dynsym_start_ofs: 261 .word __dynsym_start - _start 262 263/************************************************************************* 264 * 265 * CPU_init_critical registers 266 * 267 * setup important registers 268 * setup memory timing 269 * 270 *************************************************************************/ 271cpu_init_crit: 272 /* 273 * Invalidate L1 I/D 274 */ 275 mov r0, #0 @ set up for MCR 276 mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs 277 mcr p15, 0, r0, c7, c5, 0 @ invalidate icache 278 279 /* 280 * disable MMU stuff and caches 281 */ 282 mrc p15, 0, r0, c1, c0, 0 283 bic r0, r0, #0x00002000 @ clear bits 13 (--V-) 284 bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) 285 orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align 286 orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB 287 mcr p15, 0, r0, c1, c0, 0 288 289 /* 290 * Jump to board specific initialization... 291 * The Mask ROM will have already initialized 292 * basic memory. Go here to bump up clock rate and handle 293 * wake up conditions. 294 */ 295 mov ip, lr @ persevere link reg across call 296 bl lowlevel_init @ go setup pll,mux,memory 297 mov lr, ip @ restore link 298 mov pc, lr @ back to my caller 299/* 300 ************************************************************************* 301 * 302 * Interrupt handling 303 * 304 ************************************************************************* 305 */ 306@ 307@ IRQ stack frame. 308@ 309#define S_FRAME_SIZE 72 310 311#define S_OLD_R0 68 312#define S_PSR 64 313#define S_PC 60 314#define S_LR 56 315#define S_SP 52 316 317#define S_IP 48 318#define S_FP 44 319#define S_R10 40 320#define S_R9 36 321#define S_R8 32 322#define S_R7 28 323#define S_R6 24 324#define S_R5 20 325#define S_R4 16 326#define S_R3 12 327#define S_R2 8 328#define S_R1 4 329#define S_R0 0 330 331#define MODE_SVC 0x13 332#define I_BIT 0x80 333 334/* 335 * use bad_save_user_regs for abort/prefetch/undef/swi ... 336 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling 337 */ 338 339 .macro bad_save_user_regs 340 sub sp, sp, #S_FRAME_SIZE @ carve out a frame on current 341 @ user stack 342 stmia sp, {r0 - r12} @ Save user registers (now in 343 @ svc mode) r0-r12 344 ldr r2, IRQ_STACK_START_IN @ set base 2 words into abort 345 @ stack 346 ldmia r2, {r2 - r3} @ get values for "aborted" pc 347 @ and cpsr (into parm regs) 348 add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack 349 350 add r5, sp, #S_SP 351 mov r1, lr 352 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr 353 mov r0, sp @ save current stack into r0 354 @ (param register) 355 .endm 356 357 .macro irq_save_user_regs 358 sub sp, sp, #S_FRAME_SIZE 359 stmia sp, {r0 - r12} @ Calling r0-r12 360 add r8, sp, #S_PC @ !! R8 NEEDS to be saved !! 361 @ a reserved stack spot would 362 @ be good. 363 stmdb r8, {sp, lr}^ @ Calling SP, LR 364 str lr, [r8, #0] @ Save calling PC 365 mrs r6, spsr 366 str r6, [r8, #4] @ Save CPSR 367 str r0, [r8, #8] @ Save OLD_R0 368 mov r0, sp 369 .endm 370 371 .macro irq_restore_user_regs 372 ldmia sp, {r0 - lr}^ @ Calling r0 - lr 373 mov r0, r0 374 ldr lr, [sp, #S_PC] @ Get PC 375 add sp, sp, #S_FRAME_SIZE 376 subs pc, lr, #4 @ return & move spsr_svc into 377 @ cpsr 378 .endm 379 380 .macro get_bad_stack 381 ldr r13, IRQ_STACK_START_IN @ setup our mode stack (enter 382 @ in banked mode) 383 384 str lr, [r13] @ save caller lr in position 0 385 @ of saved stack 386 mrs lr, spsr @ get the spsr 387 str lr, [r13, #4] @ save spsr in position 1 of 388 @ saved stack 389 390 mov r13, #MODE_SVC @ prepare SVC-Mode 391 @ msr spsr_c, r13 392 msr spsr, r13 @ switch modes, make sure 393 @ moves will execute 394 mov lr, pc @ capture return pc 395 movs pc, lr @ jump to next instruction & 396 @ switch modes. 397 .endm 398 399 .macro get_bad_stack_swi 400 sub r13, r13, #4 @ space on current stack for 401 @ scratch reg. 402 str r0, [r13] @ save R0's value. 403 ldr r0, IRQ_STACK_START_IN @ get data regions start 404 @ spots for abort stack 405 str lr, [r0] @ save caller lr in position 0 406 @ of saved stack 407 mrs r0, spsr @ get the spsr 408 str lr, [r0, #4] @ save spsr in position 1 of 409 @ saved stack 410 ldr r0, [r13] @ restore r0 411 add r13, r13, #4 @ pop stack entry 412 .endm 413 414 .macro get_irq_stack @ setup IRQ stack 415 ldr sp, IRQ_STACK_START 416 .endm 417 418 .macro get_fiq_stack @ setup FIQ stack 419 ldr sp, FIQ_STACK_START 420 .endm 421 422/* 423 * exception handlers 424 */ 425 .align 5 426undefined_instruction: 427 get_bad_stack 428 bad_save_user_regs 429 bl do_undefined_instruction 430 431 .align 5 432software_interrupt: 433 get_bad_stack_swi 434 bad_save_user_regs 435 bl do_software_interrupt 436 437 .align 5 438prefetch_abort: 439 get_bad_stack 440 bad_save_user_regs 441 bl do_prefetch_abort 442 443 .align 5 444data_abort: 445 get_bad_stack 446 bad_save_user_regs 447 bl do_data_abort 448 449 .align 5 450not_used: 451 get_bad_stack 452 bad_save_user_regs 453 bl do_not_used 454 455#ifdef CONFIG_USE_IRQ 456 457 .align 5 458irq: 459 get_irq_stack 460 irq_save_user_regs 461 bl do_irq 462 irq_restore_user_regs 463 464 .align 5 465fiq: 466 get_fiq_stack 467 /* someone ought to write a more effective fiq_save_user_regs */ 468 irq_save_user_regs 469 bl do_fiq 470 irq_restore_user_regs 471 472#else 473 474 .align 5 475irq: 476 get_bad_stack 477 bad_save_user_regs 478 bl do_irq 479 480 .align 5 481fiq: 482 get_bad_stack 483 bad_save_user_regs 484 bl do_fiq 485 486#endif 487