uboot/arch/nds32/cpu/n1213/start.S
<<
>>
Prefs
   1/*
   2 *      Andesboot - Startup Code for Whitiger core
   3 *
   4 *      Copyright (C) 2006      Andes Technology Corporation
   5 *      Copyright (C) 2006      Shawn Lin <nobuhiro@andestech.com>
   6 *      Copyright (C) 2011      Macpaul Lin <macpaul@andestech.com>
   7 *                              Greentime Hu <greentime@andestech.com>
   8 *
   9 * See file CREDITS for list of people who contributed to this
  10 * project.
  11 *
  12 * This program is free software; you can redistribute it and/or
  13 * modify it under the terms of the GNU General Public License as
  14 * published by the Free Software Foundation; either version 2 of
  15 * the License, or (at your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20 * GNU General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  25 * MA 02111-1307 USA
  26 */
  27
  28#include <asm-offsets.h>
  29#include <config.h>
  30#include <common.h>
  31#include <asm/macro.h>
  32#include <version.h>
  33
  34/*
  35 * Jump vector table for EVIC mode
  36 */
  37#define ENA_DCAC                2UL
  38#define DIS_DCAC                ~ENA_DCAC
  39#define ICAC_MEM_KBF_ISET       (0x07)          ! I Cache sets per way
  40#define ICAC_MEM_KBF_IWAY       (0x07<<3)       ! I cache ways
  41#define ICAC_MEM_KBF_ISZ        (0x07<<6)       ! I cache line size
  42#define DCAC_MEM_KBF_DSET       (0x07)          ! D Cache sets per way
  43#define DCAC_MEM_KBF_DWAY       (0x07<<3)       ! D cache ways
  44#define DCAC_MEM_KBF_DSZ        (0x07<<6)       ! D cache line size
  45
  46#define PSW                     $ir0
  47#define EIT_INTR_PSW            $ir1            ! interruption $PSW
  48#define EIT_PREV_IPSW           $ir2            ! previous $IPSW
  49#define EIT_IVB                 $ir3            ! intr vector base address
  50#define EIT_EVA                 $ir4            ! MMU related Exception VA reg
  51#define EIT_PREV_EVA            $ir5            ! previous $eva
  52#define EIT_ITYPE               $ir6            ! interruption type
  53#define EIT_PREV_ITYPE          $ir7            ! prev intr type
  54#define EIT_MACH_ERR            $ir8            ! machine error log
  55#define EIT_INTR_PC             $ir9            ! Interruption PC
  56#define EIT_PREV_IPC            $ir10           ! previous $IPC
  57#define EIT_OVL_INTR_PC         $ir11           ! overflow interruption PC
  58#define EIT_PREV_P0             $ir12           ! prev $P0
  59#define EIT_PREV_P1             $ir13           ! prev $p1
  60#define CR_ICAC_MEM             $cr1            ! I-cache/memory config reg
  61#define CR_DCAC_MEM             $cr2            ! D-cache/memory config reg
  62#define MR_CAC_CTL              $mr8
  63
  64.globl _start
  65
  66_start: j       reset
  67        j       tlb_fill
  68        j       tlb_not_present
  69        j       tlb_misc
  70        j       tlb_vlpt_miss
  71        j       machine_error
  72        j       debug
  73        j       general_exception
  74        j       syscall
  75        j       internal_interrupt              ! H0I
  76        j       internal_interrupt              ! H1I
  77        j       internal_interrupt              ! H2I
  78        j       internal_interrupt              ! H3I
  79        j       internal_interrupt              ! H4I
  80        j       internal_interrupt              ! H5I
  81        j       software_interrupt              ! S0I
  82
  83        .balign 16
  84
  85/*
  86 * Andesboot Startup Code (reset vector)
  87 *
  88 *      1.      bootstrap
  89 *              1.1 reset - start of u-boot
  90 *              1.2 to superuser mode - as is when reset
  91 *              1.4 Do lowlevel_init
  92 *                      - (this will jump out to lowlevel_init.S in SoC)
  93 *                      - (lowlevel_init)
  94 *              1.3 Turn off watchdog timer
  95 *                      - (this will jump out to watchdog.S in SoC)
  96 *                      - (turnoff_watchdog)
  97 *      2.      Do critical init when reboot (not from mem)
  98 *      3.      Relocate andesboot to ram
  99 *      4.      Setup stack
 100 *      5.      Jump to second stage (board_init_r)
 101 */
 102
 103/* Note: TEXT_BASE is defined by the (board-dependent) linker script */
 104.globl _TEXT_BASE
 105_TEXT_BASE:
 106        .word   CONFIG_SYS_TEXT_BASE
 107
 108/*
 109 * These are defined in the board-specific linker script.
 110 * Subtracting _start from them lets the linker put their
 111 * relative position in the executable instead of leaving
 112 * them null.
 113 */
 114#ifdef CONFIG_USE_IRQ
 115/* IRQ stack memory (calculated at run-time) */
 116.globl IRQ_STACK_START
 117IRQ_STACK_START:
 118        .word 0x0badc0de
 119
 120/* IRQ stack memory (calculated at run-time) */
 121.globl FIQ_STACK_START
 122FIQ_STACK_START:
 123        .word 0x0badc0de
 124#endif
 125
 126/* IRQ stack memory (calculated at run-time) + 8 bytes */
 127.globl IRQ_STACK_START_IN
 128IRQ_STACK_START_IN:
 129        .word 0x0badc0de
 130
 131/*
 132 * The bootstrap code of nds32 core
 133 */
 134
 135reset:
 136set_ivb:
 137        li      $r0, 0x0
 138
 139        /* turn on BTB */
 140        mtsr    $r0, $misc_ctl
 141        /* set IVIC, vector size: 4 bytes, base: 0x0 */
 142        mtsr    $r0, $ivb
 143
 144load_lli:
 145#ifndef CONFIG_SKIP_LOWLEVEL_INIT
 146        jal     load_lowlevel_init
 147        jral    $p0
 148#endif
 149
 150/*
 151 * Set the N1213 (Whitiger) core to superuser mode
 152 * According to spec, it is already when reset
 153 */
 154turnoff_wtdog:
 155#ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
 156        jal     load_turnoff_watchdog
 157        jral    $p0
 158#endif
 159
 160/*
 161 * Do CPU critical regs init only at reboot,
 162 * not when booting from ram
 163 */
 164#ifdef CONFIG_INIT_CRITICAL
 165        bal     cpu_init_crit           ! Do CPU critical regs init
 166#endif
 167
 168/*
 169 * Set stackpointer in internal RAM to call board_init_f
 170 * $sp must be 8-byte alignment for ABI compliance.
 171 */
 172call_board_init_f:
 173        li      $sp, CONFIG_SYS_INIT_SP_ADDR
 174        li      $r0, 0x00000000
 175
 176#ifdef __PIC__
 177#ifdef __NDS32_N1213_43U1H__
 178/* __NDS32_N1213_43U1H__ implies NDS32 V0 ISA */
 179        la      $r15, board_init_f      ! store function address into $r15
 180#endif
 181#endif
 182        j       board_init_f            ! jump to board_init_f() in lib/board.c
 183
 184/*
 185 * void relocate_code (addr_sp, gd, addr_moni)
 186 *
 187 * This "function" does not return, instead it continues in RAM
 188 * after relocating the monitor code.
 189 *
 190 */
 191.globl  relocate_code
 192relocate_code:
 193        move    $r4, $r0                /* save addr_sp */
 194        move    $r5, $r1                /* save addr of gd */
 195        move    $r6, $r2                /* save addr of destination */
 196
 197/* Set up the stack */
 198stack_setup:
 199        move    $sp, $r4
 200
 201        la      $r0, _start
 202
 203        beq     $r0, $r6, clear_bss     /* skip relocation */
 204
 205        move    $r1, $r6                /* r1 <- scratch for copy_loop */
 206        la      $r3, __bss_start
 207        sub     $r3, $r3, $r0           /* r3 <- __bss_start_ofs */
 208        add     $r2, $r0, $r3           /* r2 <- source end address */
 209
 210copy_loop:
 211        lwi.p   $r7, [$r0], #4
 212        swi.p   $r7, [$r1], #4
 213        blt     $r0, $r2, copy_loop
 214
 215/*
 216 * fix relocations related issues
 217 */
 218fix_relocations:
 219        l.w     $r0, _TEXT_BASE         /* r0 <- Text base */
 220        sub     $r9, $r6, $r0           /* r9 <- relocation offset */
 221
 222fix_got:
 223/*
 224 * Now we want to update GOT.
 225 *
 226 * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
 227 * generated by GNU ld. Skip these reserved entries from relocation.
 228 */
 229        la      $r2, __got_start        /* r2 <- rel __got_start in FLASH */
 230        add     $r2, $r2, $r9           /* r2 <- rel __got_start in RAM */
 231        la      $r3, __got_end          /* r3 <- rel __got_end in FLASH */
 232        add     $r3, $r3, $r9           /* r3 <- rel __got_end in RAM */
 233        addi    $r2, $r2, #8            /* skipping first two entries */
 234fix_got_loop:
 235        lwi     $r0, [$r2]              /* r0 <- location in FLASH to fix up */
 236        add     $r0, $r0, $r9           /* r0 <- location fix up to RAM */
 237        swi.p   $r0, [$r2], #4          /* r0 <- store fix into .got in RAM */
 238        blt     $r2, $r3, fix_got_loop
 239
 240clear_bss:
 241        la      $r0, __bss_start        /* r0 <- rel __bss_start in FLASH */
 242        add     $r0, $r0, $r9           /* r0 <- rel __bss_start in FLASH */
 243        la      $r1, __bss_end          /* r1 <- rel __bss_end in RAM */
 244        add     $r1, $r1, $r9           /* r0 <- rel __bss_end in RAM */
 245        li      $r2, 0x00000000         /* clear */
 246
 247clbss_l:
 248        sw      $r2, [$r0]              /* clear loop... */
 249        addi    $r0, $r0, #4
 250        bne     $r0, $r1, clbss_l
 251
 252/*
 253 * We are done. Do not return, instead branch to second part of board
 254 * initialization, now running from RAM.
 255 */
 256call_board_init_r:
 257        la      $r0, board_init_r
 258        move    $lp, $r0                /* offset of board_init_r() */
 259        add     $lp, $lp, $r9           /* real address of board_init_r() */
 260        /* setup parameters for board_init_r */
 261        move    $r0, $r5                /* gd_t */
 262        move    $r1, $r6                /* dest_addr */
 263
 264#ifdef __PIC__
 265#ifdef __NDS32_N1213_43U1H__            /* NDS32 V0 ISA */
 266        move    $r15, $lp               /* store function address into $r15 */
 267#endif
 268#endif
 269
 270        /* jump to it ... */
 271        jr      $lp                     /* jump to board_init_r() */
 272
 273/*
 274 * Initialize CPU critical registers
 275 *
 276 *      1.      Setup control registers
 277 *              1.1 Mask all IRQs
 278 *              1.2 Flush cache and TLB
 279 *              1.3 Disable MMU and cache
 280 *      2.      Setup memory timing
 281 */
 282
 283cpu_init_crit:
 284
 285        move    $r0, $lp                /* push ra */
 286
 287        /* Disable Interrupts by clear GIE in $PSW reg */
 288        setgie.d
 289
 290        /* Flush caches and TLB */
 291        /* Invalidate caches */
 292        bal     invalidate_icac
 293        bal     invalidate_dcac
 294
 295        /* Flush TLB */
 296        mfsr    $p0, $MMU_CFG
 297        andi    $p0, $p0, 0x3                   ! MMPS
 298        li      $p1, 0x2                        ! TLB MMU
 299        bne     $p0, $p1, 1f
 300        tlbop   flushall                        ! Flush TLB
 301
 3021:
 303        ! Disable MMU, Dcache
 304        ! Whitiger is MMU disabled when reset
 305        ! Disable the D$
 306        mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
 307        li      $p1, DIS_DCAC
 308        and     $p0, $p0, $p1                   ! Set DC_EN bit
 309        mtsr    $p0, MR_CAC_CTL                 ! write back the $CACHE_CTL reg
 310        isb
 311
 312        move    $lp, $r0
 3132:
 314        ret
 315
 316#ifndef CONFIG_SKIP_LOWLEVEL_INIT
 317load_lowlevel_init:
 318        la  $r6, lowlevel_init
 319        la  $r7, load_lli + 4
 320        sub $p0, $r6, $r7
 321        add $p0, $p0, $lp
 322ret
 323#endif
 324
 325#ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
 326load_turnoff_watchdog:
 327        la  $r6, turnoff_watchdog
 328        la  $r7, turnoff_wtdog + 4
 329        sub $p0, $r6, $r7
 330        add $p0, $p0, $lp
 331ret
 332#endif
 333
 334/*
 335 * Invalidate I$
 336 */
 337invalidate_icac:
 338        ! read $cr1(I CAC/MEM cfg. reg.) configuration
 339        mfsr    $t0, CR_ICAC_MEM
 340
 341        ! Get the ISZ field
 342        andi    $p0, $t0, ICAC_MEM_KBF_ISZ
 343
 344        ! if $p0=0, then no I CAC existed
 345        beqz    $p0, end_flush_icache
 346
 347        ! get $p0 the index of I$ block
 348        srli    $p0, $p0, 6
 349
 350        ! $t1= bit width of I cache line size(ISZ)
 351        addi    $t1, $p0, 2
 352
 353        li      $t4, 1
 354        sll     $t5, $t4, $t1                   ! get $t5 cache line size
 355        andi    $p1, $t0, ICAC_MEM_KBF_ISET     ! get the ISET field
 356        addi    $t2, $p1, 6                     ! $t2= bit width of ISET
 357        andi    $p1, $t0, ICAC_MEM_KBF_IWAY     ! get bitfield of Iway
 358        srli    $p1, $p1, 3
 359        addi    $p1, $p1, 1                     ! then $p1 is I way number
 360        add     $t3, $t2, $t1                   ! SHIFT
 361        sll     $p1, $p1, $t3                   ! GET the total cache size
 362ICAC_LOOP:
 363        sub     $p1, $p1, $t5
 364        cctl    $p1, L1I_IX_INVAL
 365        bnez    $p1, ICAC_LOOP
 366end_flush_icache:
 367        ret
 368
 369/*
 370 * Invalidate D$
 371 */
 372invalidate_dcac:
 373        ! read $cr2(D CAC/MEM cfg. reg.) configuration
 374        mfsr    $t0, CR_DCAC_MEM
 375
 376        ! Get the DSZ field
 377        andi    $p0, $t0, DCAC_MEM_KBF_DSZ
 378
 379        ! if $p0=0, then no D CAC existed
 380        beqz    $p0, end_flush_dcache
 381
 382        ! get $p0 the index of D$ block
 383        srli    $p0, $p0, 6
 384
 385        ! $t1= bit width of D cache line size(DSZ)
 386        addi    $t1, $p0, 2
 387
 388        li      $t4, 1
 389        sll     $t5, $t4, $t1                   ! get $t5 cache line size
 390        andi    $p1, $t0, DCAC_MEM_KBF_DSET     ! get the DSET field
 391        addi    $t2, $p1, 6                     ! $t2= bit width of DSET
 392        andi    $p1, $t0, DCAC_MEM_KBF_DWAY     ! get bitfield of D way
 393        srli    $p1, $p1, 3
 394        addi    $p1, $p1, 1                     ! then $p1 is D way number
 395        add     $t3, $t2, $t1                   ! SHIFT
 396        sll     $p1, $p1, $t3                   ! GET the total cache size
 397DCAC_LOOP:
 398        sub     $p1, $p1, $t5
 399        cctl    $p1, L1D_IX_INVAL
 400        bnez    $p1, DCAC_LOOP
 401end_flush_dcache:
 402        ret
 403
 404/*
 405 * Interrupt handling
 406 */
 407
 408/*
 409 * exception handlers
 410 */
 411        .align  5
 412
 413.macro  SAVE_ALL
 414        ! FIXME: Other way to get PC?
 415        ! FIXME: Update according to the newest spec!!
 4161:
 417        la       $r28, 1
 418        push $r28
 419        mfsr $r28, PSW                  ! $PSW
 420        push $r28
 421        mfsr $r28, EIT_EVA              ! $ir1 $EVA
 422        push $r28
 423        mfsr $r28, EIT_ITYPE            ! $ir2 $ITYPE
 424        push $r28
 425        mfsr $r28, EIT_MACH_ERR         ! $ir3 Mach Error
 426        push $r28
 427        mfsr $r28, EIT_INTR_PSW         ! $ir5 $IPSW
 428        push $r28
 429        mfsr $r28, EIT_PREV_IPSW        ! $ir6 prev $IPSW
 430        push $r28
 431        mfsr $r28, EIT_PREV_EVA         ! $ir7 prev $EVA
 432        push $r28
 433        mfsr $r28, EIT_PREV_ITYPE       ! $ir8 prev $ITYPE
 434        push $r28
 435        mfsr $r28, EIT_INTR_PC          ! $ir9 Interruption PC
 436        push $r28
 437        mfsr $r28, EIT_PREV_IPC         ! $ir10 prev INTR_PC
 438        push $r28
 439        mfsr $r28, EIT_OVL_INTR_PC      ! $ir11 Overflowed INTR_PC
 440        push $r28
 441        mfusr $r28, $d1.lo
 442        push $r28
 443        mfusr $r28, $d1.hi
 444        push $r28
 445        mfusr $r28, $d0.lo
 446        push $r28
 447        mfusr $r28, $d0.hi
 448        push $r28
 449        pushm $r0, $r30         ! store $sp-$r31, ra-$r30, $gp-$r29, $r28-$fp
 450        addi    $sp, $sp, -4    ! make room for implicit pt_regs parameters
 451.endm
 452
 453        .align  5
 454tlb_fill:
 455        SAVE_ALL
 456        move    $r0, $sp                        ! To get the kernel stack
 457        li      $r1, 1                          ! Determine interruption type
 458        bal     do_interruption
 459
 460        .align  5
 461tlb_not_present:
 462        SAVE_ALL
 463        move    $r0, $sp                        ! To get the kernel stack
 464        li      $r1, 2                          ! Determine interruption type
 465        bal     do_interruption
 466
 467        .align  5
 468tlb_misc:
 469        SAVE_ALL
 470        move    $r0, $sp                        ! To get the kernel stack
 471        li      $r1, 3                          ! Determine interruption type
 472        bal     do_interruption
 473
 474        .align  5
 475tlb_vlpt_miss:
 476        SAVE_ALL
 477        move    $r0, $sp                        ! To get the kernel stack
 478        li      $r1, 4                          ! Determine interruption type
 479        bal     do_interruption
 480
 481        .align  5
 482machine_error:
 483        SAVE_ALL
 484        move    $r0, $sp                        ! To get the kernel stack
 485        li      $r1, 5                          ! Determine interruption type
 486        bal     do_interruption
 487
 488        .align  5
 489debug:
 490        SAVE_ALL
 491        move    $r0, $sp                        ! To get the kernel stack
 492        li      $r1, 6                          ! Determine interruption type
 493        bal     do_interruption
 494
 495        .align  5
 496general_exception:
 497        SAVE_ALL
 498        move    $r0, $sp                        ! To get the kernel stack
 499        li      $r1, 7                          ! Determine interruption type
 500        bal     do_interruption
 501
 502        .align  5
 503syscall:
 504        SAVE_ALL
 505        move    $r0, $sp                        ! To get the kernel stack
 506        li      $r1, 8                          ! Determine interruption type
 507        bal     do_interruption
 508
 509        .align  5
 510internal_interrupt:
 511        SAVE_ALL
 512        move    $r0, $sp                        ! To get the kernel stack
 513        li      $r1, 9                          ! Determine interruption type
 514        bal     do_interruption
 515
 516        .align  5
 517software_interrupt:
 518        SAVE_ALL
 519        move    $r0, $sp                        ! To get the kernel stack
 520        li      $r1, 10                         ! Determine interruption type
 521        bal     do_interruption
 522
 523        .align  5
 524
 525/*
 526 * void reset_cpu(ulong addr);
 527 * $r0: input address to jump to
 528 */
 529.globl reset_cpu
 530reset_cpu:
 531/* No need to disable MMU because we never enable it */
 532
 533        bal     invalidate_icac
 534        bal     invalidate_dcac
 535        mfsr    $p0, $MMU_CFG
 536        andi    $p0, $p0, 0x3                   ! MMPS
 537        li      $p1, 0x2                        ! TLB MMU
 538        bne     $p0, $p1, 1f
 539        tlbop   flushall                        ! Flush TLB
 5401:
 541        mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
 542        li      $p1, DIS_DCAC
 543        and     $p0, $p0, $p1                   ! Clear the DC_EN bit
 544        mtsr    $p0, MR_CAC_CTL                 ! Write back the $CACHE_CTL reg
 545        br      $r0                             ! Jump to the input address
 546