uboot/arch/arm/cpu/arm920t/start.S
<<
>>
Prefs
   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 * Subtracting _start from them lets the linker put their
  81 * relative position in the executable instead of leaving
  82 * them null.
  83 */
  84.globl _bss_start_ofs
  85_bss_start_ofs:
  86        .word __bss_start - _start
  87
  88.globl _bss_end_ofs
  89_bss_end_ofs:
  90        .word __bss_end__ - _start
  91
  92.globl _end_ofs
  93_end_ofs:
  94        .word _end - _start
  95
  96#ifdef CONFIG_USE_IRQ
  97/* IRQ stack memory (calculated at run-time) */
  98.globl IRQ_STACK_START
  99IRQ_STACK_START:
 100        .word   0x0badc0de
 101
 102/* IRQ stack memory (calculated at run-time) */
 103.globl FIQ_STACK_START
 104FIQ_STACK_START:
 105        .word 0x0badc0de
 106#endif
 107
 108/* IRQ stack memory (calculated at run-time) + 8 bytes */
 109.globl IRQ_STACK_START_IN
 110IRQ_STACK_START_IN:
 111        .word   0x0badc0de
 112
 113/*
 114 * the actual start code
 115 */
 116
 117start_code:
 118        /*
 119         * set the cpu to SVC32 mode
 120         */
 121        mrs     r0, cpsr
 122        bic     r0, r0, #0x1f
 123        orr     r0, r0, #0xd3
 124        msr     cpsr, r0
 125
 126#if     defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
 127        /*
 128         * relocate exception table
 129         */
 130        ldr     r0, =_start
 131        ldr     r1, =0x0
 132        mov     r2, #16
 133copyex:
 134        subs    r2, r2, #1
 135        ldr     r3, [r0], #4
 136        str     r3, [r1], #4
 137        bne     copyex
 138#endif
 139
 140#ifdef CONFIG_S3C24X0
 141        /* turn off the watchdog */
 142
 143# if defined(CONFIG_S3C2400)
 144#  define pWTCON        0x15300000
 145#  define INTMSK        0x14400008      /* Interrupt-Controller base addresses */
 146#  define CLKDIVN       0x14800014      /* clock divisor register */
 147#else
 148#  define pWTCON        0x53000000
 149#  define INTMSK        0x4A000008      /* Interrupt-Controller base addresses */
 150#  define INTSUBMSK     0x4A00001C
 151#  define CLKDIVN       0x4C000014      /* clock divisor register */
 152# endif
 153
 154        ldr     r0, =pWTCON
 155        mov     r1, #0x0
 156        str     r1, [r0]
 157
 158        /*
 159         * mask all IRQs by setting all bits in the INTMR - default
 160         */
 161        mov     r1, #0xffffffff
 162        ldr     r0, =INTMSK
 163        str     r1, [r0]
 164# if defined(CONFIG_S3C2410)
 165        ldr     r1, =0x3ff
 166        ldr     r0, =INTSUBMSK
 167        str     r1, [r0]
 168# endif
 169
 170        /* FCLK:HCLK:PCLK = 1:2:4 */
 171        /* default FCLK is 120 MHz ! */
 172        ldr     r0, =CLKDIVN
 173        mov     r1, #3
 174        str     r1, [r0]
 175#endif  /* CONFIG_S3C24X0 */
 176
 177        /*
 178         * we do sys-critical inits only at reboot,
 179         * not when booting from ram!
 180         */
 181#ifndef CONFIG_SKIP_LOWLEVEL_INIT
 182        bl      cpu_init_crit
 183#endif
 184
 185/* Set stackpointer in internal RAM to call board_init_f */
 186call_board_init_f:
 187        ldr     sp, =(CONFIG_SYS_INIT_SP_ADDR)
 188        bic     sp, sp, #7 /* 8-byte alignment for ABI compliance */
 189        ldr     r0,=0x00000000
 190        bl      board_init_f
 191
 192/*------------------------------------------------------------------------------*/
 193
 194/*
 195 * void relocate_code (addr_sp, gd, addr_moni)
 196 *
 197 * This "function" does not return, instead it continues in RAM
 198 * after relocating the monitor code.
 199 *
 200 */
 201        .globl  relocate_code
 202relocate_code:
 203        mov     r4, r0  /* save addr_sp */
 204        mov     r5, r1  /* save addr of gd */
 205        mov     r6, r2  /* save addr of destination */
 206
 207        /* Set up the stack                                                 */
 208stack_setup:
 209        mov     sp, r4
 210
 211        adr     r0, _start
 212        cmp     r0, r6
 213        beq     clear_bss               /* skip relocation */
 214        mov     r1, r6                  /* r1 <- scratch for copy_loop */
 215        ldr     r3, _bss_start_ofs
 216        add     r2, r0, r3              /* r2 <- source end address         */
 217
 218copy_loop:
 219        ldmia   r0!, {r9-r10}           /* copy from source address [r0]    */
 220        stmia   r1!, {r9-r10}           /* copy to   target address [r1]    */
 221        cmp     r0, r2                  /* until source end address [r2]    */
 222        blo     copy_loop
 223
 224#ifndef CONFIG_SPL_BUILD
 225        /*
 226         * fix .rel.dyn relocations
 227         */
 228        ldr     r0, _TEXT_BASE          /* r0 <- Text base */
 229        sub     r9, r6, r0              /* r9 <- relocation offset */
 230        ldr     r10, _dynsym_start_ofs  /* r10 <- sym table ofs */
 231        add     r10, r10, r0            /* r10 <- sym table in FLASH */
 232        ldr     r2, _rel_dyn_start_ofs  /* r2 <- rel dyn start ofs */
 233        add     r2, r2, r0              /* r2 <- rel dyn start in FLASH */
 234        ldr     r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
 235        add     r3, r3, r0              /* r3 <- rel dyn end in FLASH */
 236fixloop:
 237        ldr     r0, [r2]                /* r0 <- location to fix up, IN FLASH! */
 238        add     r0, r0, r9              /* r0 <- location to fix up in RAM */
 239        ldr     r1, [r2, #4]
 240        and     r7, r1, #0xff
 241        cmp     r7, #23                 /* relative fixup? */
 242        beq     fixrel
 243        cmp     r7, #2                  /* absolute fixup? */
 244        beq     fixabs
 245        /* ignore unknown type of fixup */
 246        b       fixnext
 247fixabs:
 248        /* absolute fix: set location to (offset) symbol value */
 249        mov     r1, r1, LSR #4          /* r1 <- symbol index in .dynsym */
 250        add     r1, r10, r1             /* r1 <- address of symbol in table */
 251        ldr     r1, [r1, #4]            /* r1 <- symbol value */
 252        add     r1, r1, r9              /* r1 <- relocated sym addr */
 253        b       fixnext
 254fixrel:
 255        /* relative fix: increase location by offset */
 256        ldr     r1, [r0]
 257        add     r1, r1, r9
 258fixnext:
 259        str     r1, [r0]
 260        add     r2, r2, #8              /* each rel.dyn entry is 8 bytes */
 261        cmp     r2, r3
 262        blo     fixloop
 263#endif
 264
 265clear_bss:
 266#ifndef CONFIG_SPL_BUILD
 267        ldr     r0, _bss_start_ofs
 268        ldr     r1, _bss_end_ofs
 269        mov     r4, r6                  /* reloc addr */
 270        add     r0, r0, r4
 271        add     r1, r1, r4
 272        mov     r2, #0x00000000         /* clear                            */
 273
 274clbss_l:str     r2, [r0]                /* clear loop...                    */
 275        add     r0, r0, #4
 276        cmp     r0, r1
 277        bne     clbss_l
 278
 279        bl coloured_LED_init
 280        bl red_led_on
 281#endif
 282
 283/*
 284 * We are done. Do not return, instead branch to second part of board
 285 * initialization, now running from RAM.
 286 */
 287#ifdef CONFIG_NAND_SPL
 288        ldr     r0, _nand_boot_ofs
 289        mov     pc, r0
 290
 291_nand_boot_ofs:
 292        .word nand_boot
 293#else
 294        ldr     r0, _board_init_r_ofs
 295        adr     r1, _start
 296        add     lr, r0, r1
 297        add     lr, lr, r9
 298        /* setup parameters for board_init_r */
 299        mov     r0, r5          /* gd_t */
 300        mov     r1, r6          /* dest_addr */
 301        /* jump to it ... */
 302        mov     pc, lr
 303
 304_board_init_r_ofs:
 305        .word board_init_r - _start
 306#endif
 307
 308_rel_dyn_start_ofs:
 309        .word __rel_dyn_start - _start
 310_rel_dyn_end_ofs:
 311        .word __rel_dyn_end - _start
 312_dynsym_start_ofs:
 313        .word __dynsym_start - _start
 314
 315/*
 316 *************************************************************************
 317 *
 318 * CPU_init_critical registers
 319 *
 320 * setup important registers
 321 * setup memory timing
 322 *
 323 *************************************************************************
 324 */
 325
 326
 327#ifndef CONFIG_SKIP_LOWLEVEL_INIT
 328cpu_init_crit:
 329        /*
 330         * flush v4 I/D caches
 331         */
 332        mov     r0, #0
 333        mcr     p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */
 334        mcr     p15, 0, r0, c8, c7, 0   /* flush v4 TLB */
 335
 336        /*
 337         * disable MMU stuff and caches
 338         */
 339        mrc     p15, 0, r0, c1, c0, 0
 340        bic     r0, r0, #0x00002300     @ clear bits 13, 9:8 (--V- --RS)
 341        bic     r0, r0, #0x00000087     @ clear bits 7, 2:0 (B--- -CAM)
 342        orr     r0, r0, #0x00000002     @ set bit 2 (A) Align
 343        orr     r0, r0, #0x00001000     @ set bit 12 (I) I-Cache
 344        mcr     p15, 0, r0, c1, c0, 0
 345
 346        /*
 347         * before relocating, we have to setup RAM timing
 348         * because memory timing is board-dependend, you will
 349         * find a lowlevel_init.S in your board directory.
 350         */
 351        mov     ip, lr
 352
 353        bl      lowlevel_init
 354
 355        mov     lr, ip
 356        mov     pc, lr
 357#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
 358
 359/*
 360 *************************************************************************
 361 *
 362 * Interrupt handling
 363 *
 364 *************************************************************************
 365 */
 366
 367@
 368@ IRQ stack frame.
 369@
 370#define S_FRAME_SIZE    72
 371
 372#define S_OLD_R0        68
 373#define S_PSR           64
 374#define S_PC            60
 375#define S_LR            56
 376#define S_SP            52
 377
 378#define S_IP            48
 379#define S_FP            44
 380#define S_R10           40
 381#define S_R9            36
 382#define S_R8            32
 383#define S_R7            28
 384#define S_R6            24
 385#define S_R5            20
 386#define S_R4            16
 387#define S_R3            12
 388#define S_R2            8
 389#define S_R1            4
 390#define S_R0            0
 391
 392#define MODE_SVC        0x13
 393#define I_BIT           0x80
 394
 395/*
 396 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 397 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
 398 */
 399
 400        .macro  bad_save_user_regs
 401        sub     sp, sp, #S_FRAME_SIZE
 402        stmia   sp, {r0 - r12}                  @ Calling r0-r12
 403        ldr     r2, IRQ_STACK_START_IN
 404        ldmia   r2, {r2 - r3}                   @ get pc, cpsr
 405        add     r0, sp, #S_FRAME_SIZE           @ restore sp_SVC
 406
 407        add     r5, sp, #S_SP
 408        mov     r1, lr
 409        stmia   r5, {r0 - r3}                   @ save sp_SVC, lr_SVC, pc, cpsr
 410        mov     r0, sp
 411        .endm
 412
 413        .macro  irq_save_user_regs
 414        sub     sp, sp, #S_FRAME_SIZE
 415        stmia   sp, {r0 - r12}                  @ Calling r0-r12
 416        add     r7, sp, #S_PC
 417        stmdb   r7, {sp, lr}^                   @ Calling SP, LR
 418        str     lr, [r7, #0]                    @ Save calling PC
 419        mrs     r6, spsr
 420        str     r6, [r7, #4]                    @ Save CPSR
 421        str     r0, [r7, #8]                    @ Save OLD_R0
 422        mov     r0, sp
 423        .endm
 424
 425        .macro  irq_restore_user_regs
 426        ldmia   sp, {r0 - lr}^                  @ Calling r0 - lr
 427        mov     r0, r0
 428        ldr     lr, [sp, #S_PC]                 @ Get PC
 429        add     sp, sp, #S_FRAME_SIZE
 430        /* return & move spsr_svc into cpsr */
 431        subs    pc, lr, #4
 432        .endm
 433
 434        .macro get_bad_stack
 435        ldr     r13, IRQ_STACK_START_IN         @ setup our mode stack
 436
 437        str     lr, [r13]                       @ save caller lr / spsr
 438        mrs     lr, spsr
 439        str     lr, [r13, #4]
 440
 441        mov     r13, #MODE_SVC                  @ prepare SVC-Mode
 442        @ msr   spsr_c, r13
 443        msr     spsr, r13
 444        mov     lr, pc
 445        movs    pc, lr
 446        .endm
 447
 448        .macro get_irq_stack                    @ setup IRQ stack
 449        ldr     sp, IRQ_STACK_START
 450        .endm
 451
 452        .macro get_fiq_stack                    @ setup FIQ stack
 453        ldr     sp, FIQ_STACK_START
 454        .endm
 455
 456/*
 457 * exception handlers
 458 */
 459        .align  5
 460undefined_instruction:
 461        get_bad_stack
 462        bad_save_user_regs
 463        bl      do_undefined_instruction
 464
 465        .align  5
 466software_interrupt:
 467        get_bad_stack
 468        bad_save_user_regs
 469        bl      do_software_interrupt
 470
 471        .align  5
 472prefetch_abort:
 473        get_bad_stack
 474        bad_save_user_regs
 475        bl      do_prefetch_abort
 476
 477        .align  5
 478data_abort:
 479        get_bad_stack
 480        bad_save_user_regs
 481        bl      do_data_abort
 482
 483        .align  5
 484not_used:
 485        get_bad_stack
 486        bad_save_user_regs
 487        bl      do_not_used
 488
 489#ifdef CONFIG_USE_IRQ
 490
 491        .align  5
 492irq:
 493        get_irq_stack
 494        irq_save_user_regs
 495        bl      do_irq
 496        irq_restore_user_regs
 497
 498        .align  5
 499fiq:
 500        get_fiq_stack
 501        /* someone ought to write a more effiction fiq_save_user_regs */
 502        irq_save_user_regs
 503        bl      do_fiq
 504        irq_restore_user_regs
 505
 506#else
 507
 508        .align  5
 509irq:
 510        get_bad_stack
 511        bad_save_user_regs
 512        bl      do_irq
 513
 514        .align  5
 515fiq:
 516        get_bad_stack
 517        bad_save_user_regs
 518        bl      do_fiq
 519
 520#endif
 521