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