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