1/* 2 * armboot - Startup Code for ARM920 CPU-core 3 * 4 * Copyright (c) 2001 Marius Gr�ger <mag@sysgo.de> 5 * Copyright (c) 2002 Alex Z�pke <azu@sysgo.de> 6 * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> 7 * 8 * See file CREDITS for list of people who contributed to this 9 * project. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation; either version 2 of 14 * the License, or (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 24 * MA 02111-1307 USA 25 */ 26 27#include <asm-offsets.h> 28#include <common.h> 29#include <config.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 start_code 42 ldr pc, _undefined_instruction 43 ldr pc, _software_interrupt 44 ldr pc, _prefetch_abort 45 ldr pc, _data_abort 46 ldr pc, _not_used 47 ldr pc, _irq 48 ldr pc, _fiq 49 50_undefined_instruction: .word undefined_instruction 51_software_interrupt: .word software_interrupt 52_prefetch_abort: .word prefetch_abort 53_data_abort: .word data_abort 54_not_used: .word not_used 55_irq: .word irq 56_fiq: .word fiq 57 58 .balignl 16,0xdeadbeef 59 60 61/* 62 ************************************************************************* 63 * 64 * Startup Code (called from the ARM reset exception vector) 65 * 66 * do important init only if we don't start from memory! 67 * relocate armboot to ram 68 * setup stack 69 * jump to second stage 70 * 71 ************************************************************************* 72 */ 73 74.globl _TEXT_BASE 75_TEXT_BASE: 76 .word CONFIG_SYS_TEXT_BASE 77 78/* 79 * These are defined in the board-specific linker script. 80 */ 81.globl _bss_start 82_bss_start: 83 .word __bss_start 84 85.globl _bss_end 86_bss_end: 87 .word _end 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/* IRQ stack memory (calculated at run-time) + 8 bytes */ 102.globl IRQ_STACK_START_IN 103IRQ_STACK_START_IN: 104 .word 0x0badc0de 105 106.globl _datarel_start 107_datarel_start: 108 .word __datarel_start 109 110.globl _datarelrolocal_start 111_datarelrolocal_start: 112 .word __datarelrolocal_start 113 114.globl _datarellocal_start 115_datarellocal_start: 116 .word __datarellocal_start 117 118.globl _datarelro_start 119_datarelro_start: 120 .word __datarelro_start 121 122.globl _got_start 123_got_start: 124 .word __got_start 125 126.globl _got_end 127_got_end: 128 .word __got_end 129 130/* 131 * the actual start code 132 */ 133 134start_code: 135 /* 136 * set the cpu to SVC32 mode 137 */ 138 mrs r0, cpsr 139 bic r0, r0, #0x1f 140 orr r0, r0, #0xd3 141 msr cpsr, r0 142 143 bl coloured_LED_init 144 bl red_LED_on 145 146#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) 147 /* 148 * relocate exception table 149 */ 150 ldr r0, =_start 151 ldr r1, =0x0 152 mov r2, #16 153copyex: 154 subs r2, r2, #1 155 ldr r3, [r0], #4 156 str r3, [r1], #4 157 bne copyex 158#endif 159 160#ifdef CONFIG_S3C24X0 161 /* turn off the watchdog */ 162 163# if defined(CONFIG_S3C2400) 164# define pWTCON 0x15300000 165# define INTMSK 0x14400008 /* Interupt-Controller base addresses */ 166# define CLKDIVN 0x14800014 /* clock divisor register */ 167#else 168# define pWTCON 0x53000000 169# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ 170# define INTSUBMSK 0x4A00001C 171# define CLKDIVN 0x4C000014 /* clock divisor register */ 172# endif 173 174 ldr r0, =pWTCON 175 mov r1, #0x0 176 str r1, [r0] 177 178 /* 179 * mask all IRQs by setting all bits in the INTMR - default 180 */ 181 mov r1, #0xffffffff 182 ldr r0, =INTMSK 183 str r1, [r0] 184# if defined(CONFIG_S3C2410) 185 ldr r1, =0x3ff 186 ldr r0, =INTSUBMSK 187 str r1, [r0] 188# endif 189 190 /* FCLK:HCLK:PCLK = 1:2:4 */ 191 /* default FCLK is 120 MHz ! */ 192 ldr r0, =CLKDIVN 193 mov r1, #3 194 str r1, [r0] 195#endif /* CONFIG_S3C24X0 */ 196 197 /* 198 * we do sys-critical inits only at reboot, 199 * not when booting from ram! 200 */ 201#ifndef CONFIG_SKIP_LOWLEVEL_INIT 202 bl cpu_init_crit 203#endif 204 205/* Set stackpointer in internal RAM to call board_init_f */ 206call_board_init_f: 207 ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) 208 ldr r0,=0x00000000 209 bl board_init_f 210 211/*------------------------------------------------------------------------------*/ 212 213/* 214 * void relocate_code (addr_sp, gd, addr_moni) 215 * 216 * This "function" does not return, instead it continues in RAM 217 * after relocating the monitor code. 218 * 219 */ 220 .globl relocate_code 221relocate_code: 222 mov r4, r0 /* save addr_sp */ 223 mov r5, r1 /* save addr of gd */ 224 mov r6, r2 /* save addr of destination */ 225 mov r7, r2 /* save addr of destination */ 226 227 /* Set up the stack */ 228stack_setup: 229 mov sp, r4 230 231 adr r0, _start 232 ldr r2, _TEXT_BASE 233 ldr r3, _bss_start 234 sub r2, r3, r2 /* r2 <- size of armboot */ 235 add r2, r0, r2 /* r2 <- source end address */ 236 cmp r0, r6 237 beq clear_bss 238 239copy_loop: 240 ldmia r0!, {r9-r10} /* copy from source address [r0] */ 241 stmia r6!, {r9-r10} /* copy to target address [r1] */ 242 cmp r0, r2 /* until source end address [r2] */ 243 blo copy_loop 244 245#ifndef CONFIG_PRELOADER 246 /* fix got entries */ 247 ldr r1, _TEXT_BASE /* Text base */ 248 mov r0, r7 /* reloc addr */ 249 ldr r2, _got_start /* addr in Flash */ 250 ldr r3, _got_end /* addr in Flash */ 251 sub r3, r3, r1 252 add r3, r3, r0 253 sub r2, r2, r1 254 add r2, r2, r0 255 256fixloop: 257 ldr r4, [r2] 258 sub r4, r4, r1 259 add r4, r4, r0 260 str r4, [r2] 261 add r2, r2, #4 262 cmp r2, r3 263 blo fixloop 264#endif 265 266clear_bss: 267#ifndef CONFIG_PRELOADER 268 ldr r0, _bss_start 269 ldr r1, _bss_end 270 ldr r3, _TEXT_BASE /* Text base */ 271 mov r4, r7 /* reloc addr */ 272 sub r0, r0, r3 273 add r0, r0, r4 274 sub r1, r1, r3 275 add r1, r1, r4 276 mov r2, #0x00000000 /* clear */ 277 278clbss_l:str r2, [r0] /* clear loop... */ 279 add r0, r0, #4 280 cmp r0, r1 281 bne clbss_l 282 283 bl coloured_LED_init 284 bl red_LED_on 285#endif 286 287/* 288 * We are done. Do not return, instead branch to second part of board 289 * initialization, now running from RAM. 290 */ 291#ifdef CONFIG_NAND_SPL 292 ldr pc, _nand_boot 293 294_nand_boot: .word nand_boot 295#else 296 ldr r0, _TEXT_BASE 297 ldr r2, _board_init_r 298 sub r2, r2, r0 299 add r2, r2, r7 /* position from board_init_r in RAM */ 300 /* setup parameters for board_init_r */ 301 mov r0, r5 /* gd_t */ 302 mov r1, r7 /* dest_addr */ 303 /* jump to it ... */ 304 mov lr, r2 305 mov pc, lr 306 307_board_init_r: .word board_init_r 308#endif 309 310/* 311 ************************************************************************* 312 * 313 * CPU_init_critical registers 314 * 315 * setup important registers 316 * setup memory timing 317 * 318 ************************************************************************* 319 */ 320 321 322#ifndef CONFIG_SKIP_LOWLEVEL_INIT 323cpu_init_crit: 324 /* 325 * flush v4 I/D caches 326 */ 327 mov r0, #0 328 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ 329 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ 330 331 /* 332 * disable MMU stuff and caches 333 */ 334 mrc p15, 0, r0, c1, c0, 0 335 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) 336 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) 337 orr r0, r0, #0x00000002 @ set bit 2 (A) Align 338 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache 339 mcr p15, 0, r0, c1, c0, 0 340 341 /* 342 * before relocating, we have to setup RAM timing 343 * because memory timing is board-dependend, you will 344 * find a lowlevel_init.S in your board directory. 345 */ 346 mov ip, lr 347 348 bl lowlevel_init 349 350 mov lr, ip 351 mov pc, lr 352#endif /* CONFIG_SKIP_LOWLEVEL_INIT */ 353 354/* 355 ************************************************************************* 356 * 357 * Interrupt handling 358 * 359 ************************************************************************* 360 */ 361 362@ 363@ IRQ stack frame. 364@ 365#define S_FRAME_SIZE 72 366 367#define S_OLD_R0 68 368#define S_PSR 64 369#define S_PC 60 370#define S_LR 56 371#define S_SP 52 372 373#define S_IP 48 374#define S_FP 44 375#define S_R10 40 376#define S_R9 36 377#define S_R8 32 378#define S_R7 28 379#define S_R6 24 380#define S_R5 20 381#define S_R4 16 382#define S_R3 12 383#define S_R2 8 384#define S_R1 4 385#define S_R0 0 386 387#define MODE_SVC 0x13 388#define I_BIT 0x80 389 390/* 391 * use bad_save_user_regs for abort/prefetch/undef/swi ... 392 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling 393 */ 394 395 .macro bad_save_user_regs 396 sub sp, sp, #S_FRAME_SIZE 397 stmia sp, {r0 - r12} @ Calling r0-r12 398 ldr r2, IRQ_STACK_START_IN 399 ldmia r2, {r2 - r3} @ get pc, cpsr 400 add r0, sp, #S_FRAME_SIZE @ restore sp_SVC 401 402 add r5, sp, #S_SP 403 mov r1, lr 404 stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr 405 mov r0, sp 406 .endm 407 408 .macro irq_save_user_regs 409 sub sp, sp, #S_FRAME_SIZE 410 stmia sp, {r0 - r12} @ Calling r0-r12 411 add r7, sp, #S_PC 412 stmdb r7, {sp, lr}^ @ Calling SP, LR 413 str lr, [r7, #0] @ Save calling PC 414 mrs r6, spsr 415 str r6, [r7, #4] @ Save CPSR 416 str r0, [r7, #8] @ Save OLD_R0 417 mov r0, sp 418 .endm 419 420 .macro irq_restore_user_regs 421 ldmia sp, {r0 - lr}^ @ Calling r0 - lr 422 mov r0, r0 423 ldr lr, [sp, #S_PC] @ Get PC 424 add sp, sp, #S_FRAME_SIZE 425 /* return & move spsr_svc into cpsr */ 426 subs pc, lr, #4 427 .endm 428 429 .macro get_bad_stack 430 ldr r13, IRQ_STACK_START_IN @ setup our mode stack 431 432 str lr, [r13] @ save caller lr / spsr 433 mrs lr, spsr 434 str lr, [r13, #4] 435 436 mov r13, #MODE_SVC @ prepare SVC-Mode 437 @ msr spsr_c, r13 438 msr spsr, r13 439 mov lr, pc 440 movs pc, lr 441 .endm 442 443 .macro get_irq_stack @ setup IRQ stack 444 ldr sp, IRQ_STACK_START 445 .endm 446 447 .macro get_fiq_stack @ setup FIQ stack 448 ldr sp, FIQ_STACK_START 449 .endm 450 451/* 452 * exception handlers 453 */ 454 .align 5 455undefined_instruction: 456 get_bad_stack 457 bad_save_user_regs 458 bl do_undefined_instruction 459 460 .align 5 461software_interrupt: 462 get_bad_stack 463 bad_save_user_regs 464 bl do_software_interrupt 465 466 .align 5 467prefetch_abort: 468 get_bad_stack 469 bad_save_user_regs 470 bl do_prefetch_abort 471 472 .align 5 473data_abort: 474 get_bad_stack 475 bad_save_user_regs 476 bl do_data_abort 477 478 .align 5 479not_used: 480 get_bad_stack 481 bad_save_user_regs 482 bl do_not_used 483 484#ifdef CONFIG_USE_IRQ 485 486 .align 5 487irq: 488 get_irq_stack 489 irq_save_user_regs 490 bl do_irq 491 irq_restore_user_regs 492 493 .align 5 494fiq: 495 get_fiq_stack 496 /* someone ought to write a more effiction fiq_save_user_regs */ 497 irq_save_user_regs 498 bl do_fiq 499 irq_restore_user_regs 500 501#else 502 503 .align 5 504irq: 505 get_bad_stack 506 bad_save_user_regs 507 bl do_irq 508 509 .align 5 510fiq: 511 get_bad_stack 512 bad_save_user_regs 513 bl do_fiq 514 515#endif 516