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