uboot/arch/nds32/cpu/n1213/start.S
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0+ */
   2/*
   3 *      Andesboot - Startup Code for Whitiger core
   4 *
   5 *      Copyright (C) 2006      Andes Technology Corporation
   6 *      Copyright (C) 2006      Shawn Lin <nobuhiro@andestech.com>
   7 *      Copyright (C) 2011      Macpaul Lin <macpaul@andestech.com>
   8 *                              Greentime Hu <greentime@andestech.com>
   9 */
  10
  11.pic
  12
  13#include <asm-offsets.h>
  14#include <config.h>
  15#include <common.h>
  16#include <asm/macro.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/* IRQ stack memory (calculated at run-time) + 8 bytes */
  93.globl IRQ_STACK_START_IN
  94IRQ_STACK_START_IN:
  95        .word 0x0badc0de
  96
  97/*
  98 * The bootstrap code of nds32 core
  99 */
 100
 101reset:
 102
 103/*
 104 *  gp = ~0            for burn mode
 105 *     = ~load_address for load mode
 106 */
 107reset_gp:
 108        .relax_hint 0
 109        sethi   $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
 110        .relax_hint 0
 111        ori     $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
 112        add5.pc $gp
 113
 114set_ivb:
 115        li      $r0, 0x0
 116        /* turn on BTB */
 117        mtsr    $r0, $misc_ctl
 118        /* set IVIC, vector size: 4 bytes, base: 0x0 */
 119        mtsr    $r0, $ivb
 120/*
 121 * MMU_CTL NTC0 Non-cacheable
 122 */
 123        li      $r0, ~0x6
 124        mfsr    $r1, $mr0
 125        and     $r1, $r1, $r0
 126        mtsr    $r1, $mr0
 127
 128        li      $r0, ~0x3
 129        mfsr    $r1, $mr8
 130        and     $r1, $r1, $r0
 131        mtsr    $r1, $mr8
 132#if (!defined(CONFIG_SYS_ICACHE_OFF) || !defined(CONFIG_SYS_DCACHE_OFF))
 133/*
 134 * MMU_CTL NTC0 Cacheable/Write-Back
 135 */
 136        li      $r0, 0x4
 137        mfsr    $r1, $mr0
 138        or      $r1, $r1, $r0
 139        mtsr    $r1, $mr0
 140#endif
 141
 142#ifndef CONFIG_SYS_DCACHE_OFF
 143#ifdef CONFIG_ARCH_MAP_SYSMEM
 144/*
 145 * MMU_CTL NTC1 Non-cacheable
 146 */
 147        li      $r0, ~0x18
 148        mfsr    $r1, $mr0
 149        and     $r1, $r1, $r0
 150        mtsr    $r1, $mr0
 151/*
 152 * MMU_CTL NTM1 mapping for partition 0
 153 */
 154        li      $r0, ~0x6000
 155        mfsr    $r1, $mr0
 156        and     $r1, $r1, $r0
 157        mtsr    $r1, $mr0
 158#endif
 159#endif
 160
 161#if !defined(CONFIG_SYS_ICACHE_OFF)
 162        li      $r0, 0x1
 163        mfsr    $r1, $mr8
 164        or      $r1, $r1, $r0
 165        mtsr    $r1, $mr8
 166#endif
 167
 168#if !defined(CONFIG_SYS_DCACHE_OFF)
 169        li      $r0, 0x2
 170        mfsr    $r1, $mr8
 171        or      $r1, $r1, $r0
 172        mtsr    $r1, $mr8
 173#endif
 174
 175        jal mem_init
 176
 177#ifndef CONFIG_SKIP_LOWLEVEL_INIT
 178        jal     lowlevel_init
 179/*
 180 *  gp = ~VMA          for burn mode
 181 *     = ~load_address for load mode
 182 */
 183update_gp:
 184        .relax_hint 0
 185        sethi   $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
 186        .relax_hint 0
 187        ori     $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
 188        add5.pc $gp
 189#endif
 190/*
 191 *  do critical initializations first (shall be in short time)
 192 *  do self_relocation ASAP.
 193 */
 194
 195/*
 196 * Set the N1213 (Whitiger) core to superuser mode
 197 * According to spec, it is already when reset
 198 */
 199#ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
 200        jal     turnoff_watchdog
 201#endif
 202
 203/*
 204 * Set stackpointer in internal RAM to call board_init_f
 205 * $sp must be 8-byte alignment for ABI compliance.
 206 */
 207call_board_init_f:
 208        li              $sp, CONFIG_SYS_INIT_SP_ADDR
 209        move    $r0, $sp
 210        bal     board_init_f_alloc_reserve
 211        move    $sp, $r0
 212        bal     board_init_f_init_reserve
 213#ifdef CONFIG_DEBUG_UART
 214        bal     debug_uart_init
 215#endif
 216        li              $r0, 0x00000000
 217#ifdef __PIC__
 218#ifdef __NDS32_N1213_43U1H__
 219/* __NDS32_N1213_43U1H__ implies NDS32 V0 ISA */
 220        la      $r15, board_init_f      ! store function address into $r15
 221#endif
 222#endif
 223        j       board_init_f            ! jump to board_init_f() in lib/board.c
 224
 225/*
 226 * void relocate_code (addr_sp, gd, addr_moni)
 227 *
 228 * This "function" does not return, instead it continues in RAM
 229 * after relocating the monitor code.
 230 *
 231 */
 232
 233/*
 234 *  gp = ~RAM_SIZE - TEXT_SIZE for burn/load mode
 235 */
 236
 237.globl  relocate_code
 238relocate_code:
 239        move    $r4, $r0                /* save addr_sp */
 240        move    $r5, $r1                /* save addr of gd */
 241        move    $r6, $r2                /* save addr of destination */
 242
 243/* Set up the stack */
 244stack_setup:
 245        move    $sp, $r4
 246
 247        la      $r0, _start@GOTOFF
 248        beq     $r0, $r6, clear_bss     /* skip relocation */
 249
 250        la       $r1, _end@GOTOFF
 251        move $r2, $r6                   /* r2 <- scratch for copy_loop */
 252copy_loop:
 253        lmw.bim $r11, [$r0], $r18
 254        smw.bim $r11, [$r2], $r18
 255        blt     $r0, $r1, copy_loop
 256/*
 257 * fix relocations related issues
 258 */
 259fix_relocations:
 260        l.w     $r0, _TEXT_BASE@GOTOFF  /* r0 <- Text base */
 261        sub     $r9, $r6, $r0                   /* r9 <- relocation offset */
 262
 263        la  $r7, __rel_dyn_start@GOTOFF
 264        add     $r7, $r7, $r9           /* r2 <- rel __got_start in RAM */
 265        la  $r8, __rel_dyn_end@GOTOFF
 266        add     $r8, $r8, $r9           /* r2 <- rel __got_start in RAM */
 267        li  $r3, #0x2a /* R_NDS32_RELATIVE */
 2681:
 269        lmw.bim $r0, [$r7], $r2 /* r0,r1,r2 <- adr,type,addend */
 270        bne $r1, $r3, 2f
 271
 272        add $r0, $r0, $r9
 273        add $r2, $r2, $r9
 274        sw  $r2, [$r0]
 2752:
 276        blt $r7, $r8, 1b
 277
 278clear_bss:
 279        la      $r0, __bss_start@GOTOFF /* r0 <- rel __bss_start in FLASH */
 280        add     $r0, $r0, $r9           /* r0 <- rel __bss_start in FLASH */
 281        la      $r1, __bss_end@GOTOFF           /* r1 <- rel __bss_end in RAM */
 282        add     $r1, $r1, $r9           /* r0 <- rel __bss_end in RAM */
 283        li      $r2, 0x00000000         /* clear */
 284
 285clbss_l:
 286        sw      $r2, [$r0]              /* clear loop... */
 287        addi    $r0, $r0, #4
 288        bne     $r0, $r1, clbss_l
 289
 290/*
 291 * We are done. Do not return, instead branch to second part of board
 292 * initialization, now running from RAM.
 293 */
 294call_board_init_r:
 295        bal invalidate_icache_all
 296        bal flush_dcache_all
 297        la      $r0, board_init_r@GOTOFF
 298        move    $lp, $r0                /* offset of board_init_r() */
 299        add     $lp, $lp, $r9           /* real address of board_init_r() */
 300        /* setup parameters for board_init_r */
 301        move    $r0, $r5                /* gd_t */
 302        move    $r1, $r6                /* dest_addr */
 303
 304#ifdef __PIC__
 305#ifdef __NDS32_N1213_43U1H__            /* NDS32 V0 ISA */
 306        move    $r15, $lp               /* store function address into $r15 */
 307#endif
 308#endif
 309
 310        /* jump to it ... */
 311        jr      $lp                     /* jump to board_init_r() */
 312
 313/*
 314 * Invalidate I$
 315 */
 316invalidate_icac:
 317        ! read $cr1(I CAC/MEM cfg. reg.) configuration
 318        mfsr    $t0, CR_ICAC_MEM
 319
 320        ! Get the ISZ field
 321        andi    $p0, $t0, ICAC_MEM_KBF_ISZ
 322
 323        ! if $p0=0, then no I CAC existed
 324        beqz    $p0, end_flush_icache
 325
 326        ! get $p0 the index of I$ block
 327        srli    $p0, $p0, 6
 328
 329        ! $t1= bit width of I cache line size(ISZ)
 330        addi    $t1, $p0, 2
 331
 332        li      $t4, 1
 333        sll     $t5, $t4, $t1                   ! get $t5 cache line size
 334        andi    $p1, $t0, ICAC_MEM_KBF_ISET     ! get the ISET field
 335        addi    $t2, $p1, 6                     ! $t2= bit width of ISET
 336        andi    $p1, $t0, ICAC_MEM_KBF_IWAY     ! get bitfield of Iway
 337        srli    $p1, $p1, 3
 338        addi    $p1, $p1, 1                     ! then $p1 is I way number
 339        add     $t3, $t2, $t1                   ! SHIFT
 340        sll     $p1, $p1, $t3                   ! GET the total cache size
 341ICAC_LOOP:
 342        sub     $p1, $p1, $t5
 343        cctl    $p1, L1I_IX_INVAL
 344        bnez    $p1, ICAC_LOOP
 345end_flush_icache:
 346        ret
 347
 348/*
 349 * Invalidate D$
 350 */
 351invalidate_dcac:
 352        ! read $cr2(D CAC/MEM cfg. reg.) configuration
 353        mfsr    $t0, CR_DCAC_MEM
 354
 355        ! Get the DSZ field
 356        andi    $p0, $t0, DCAC_MEM_KBF_DSZ
 357
 358        ! if $p0=0, then no D CAC existed
 359        beqz    $p0, end_flush_dcache
 360
 361        ! get $p0 the index of D$ block
 362        srli    $p0, $p0, 6
 363
 364        ! $t1= bit width of D cache line size(DSZ)
 365        addi    $t1, $p0, 2
 366
 367        li      $t4, 1
 368        sll     $t5, $t4, $t1                   ! get $t5 cache line size
 369        andi    $p1, $t0, DCAC_MEM_KBF_DSET     ! get the DSET field
 370        addi    $t2, $p1, 6                     ! $t2= bit width of DSET
 371        andi    $p1, $t0, DCAC_MEM_KBF_DWAY     ! get bitfield of D way
 372        srli    $p1, $p1, 3
 373        addi    $p1, $p1, 1                     ! then $p1 is D way number
 374        add     $t3, $t2, $t1                   ! SHIFT
 375        sll     $p1, $p1, $t3                   ! GET the total cache size
 376DCAC_LOOP:
 377        sub     $p1, $p1, $t5
 378        cctl    $p1, L1D_IX_INVAL
 379        bnez    $p1, DCAC_LOOP
 380end_flush_dcache:
 381        ret
 382
 383/*
 384 * Interrupt handling
 385 */
 386
 387/*
 388 * exception handlers
 389 */
 390        .align  5
 391
 392.macro  SAVE_ALL
 393        ! FIXME: Other way to get PC?
 394        ! FIXME: Update according to the newest spec!!
 3951:
 396        li       $r28, 1
 397        push $r28
 398        mfsr $r28, PSW                  ! $PSW
 399        push $r28
 400        mfsr $r28, EIT_EVA              ! $ir1 $EVA
 401        push $r28
 402        mfsr $r28, EIT_ITYPE            ! $ir2 $ITYPE
 403        push $r28
 404        mfsr $r28, EIT_MACH_ERR         ! $ir3 Mach Error
 405        push $r28
 406        mfsr $r28, EIT_INTR_PSW         ! $ir5 $IPSW
 407        push $r28
 408        mfsr $r28, EIT_PREV_IPSW        ! $ir6 prev $IPSW
 409        push $r28
 410        mfsr $r28, EIT_PREV_EVA         ! $ir7 prev $EVA
 411        push $r28
 412        mfsr $r28, EIT_PREV_ITYPE       ! $ir8 prev $ITYPE
 413        push $r28
 414        mfsr $r28, EIT_INTR_PC          ! $ir9 Interruption PC
 415        push $r28
 416        mfsr $r28, EIT_PREV_IPC         ! $ir10 prev INTR_PC
 417        push $r28
 418        mfsr $r28, EIT_OVL_INTR_PC      ! $ir11 Overflowed INTR_PC
 419        push $r28
 420        mfusr $r28, $d1.lo
 421        push $r28
 422        mfusr $r28, $d1.hi
 423        push $r28
 424        mfusr $r28, $d0.lo
 425        push $r28
 426        mfusr $r28, $d0.hi
 427        push $r28
 428        pushm $r0, $r30         ! store $sp-$r31, ra-$r30, $gp-$r29, $r28-$fp
 429        addi    $sp, $sp, -4    ! make room for implicit pt_regs parameters
 430.endm
 431
 432        .align  5
 433tlb_fill:
 434        SAVE_ALL
 435        move    $r0, $sp                        ! To get the kernel stack
 436        li      $r1, 1                          ! Determine interruption type
 437        bal     do_interruption
 438
 439        .align  5
 440tlb_not_present:
 441        SAVE_ALL
 442        move    $r0, $sp                        ! To get the kernel stack
 443        li      $r1, 2                          ! Determine interruption type
 444        bal     do_interruption
 445
 446        .align  5
 447tlb_misc:
 448        SAVE_ALL
 449        move    $r0, $sp                        ! To get the kernel stack
 450        li      $r1, 3                          ! Determine interruption type
 451        bal     do_interruption
 452
 453        .align  5
 454tlb_vlpt_miss:
 455        SAVE_ALL
 456        move    $r0, $sp                        ! To get the kernel stack
 457        li      $r1, 4                          ! Determine interruption type
 458        bal     do_interruption
 459
 460        .align  5
 461machine_error:
 462        SAVE_ALL
 463        move    $r0, $sp                        ! To get the kernel stack
 464        li      $r1, 5                          ! Determine interruption type
 465        bal     do_interruption
 466
 467        .align  5
 468debug:
 469        SAVE_ALL
 470        move    $r0, $sp                        ! To get the kernel stack
 471        li      $r1, 6                          ! Determine interruption type
 472        bal     do_interruption
 473
 474        .align  5
 475general_exception:
 476        SAVE_ALL
 477        move    $r0, $sp                        ! To get the kernel stack
 478        li      $r1, 7                          ! Determine interruption type
 479        bal     do_interruption
 480
 481        .align  5
 482syscall:
 483        SAVE_ALL
 484        move    $r0, $sp                        ! To get the kernel stack
 485        li      $r1, 8                          ! Determine interruption type
 486        bal     do_interruption
 487
 488        .align  5
 489internal_interrupt:
 490        SAVE_ALL
 491        move    $r0, $sp                        ! To get the kernel stack
 492        li      $r1, 9                          ! Determine interruption type
 493        bal     do_interruption
 494
 495        .align  5
 496software_interrupt:
 497        SAVE_ALL
 498        move    $r0, $sp                        ! To get the kernel stack
 499        li      $r1, 10                         ! Determine interruption type
 500        bal     do_interruption
 501
 502        .align  5
 503
 504/*
 505 * void reset_cpu(ulong addr);
 506 * $r0: input address to jump to
 507 */
 508.globl reset_cpu
 509reset_cpu:
 510/* No need to disable MMU because we never enable it */
 511
 512        bal     invalidate_icac
 513        bal     invalidate_dcac
 514        mfsr    $p0, $MMU_CFG
 515        andi    $p0, $p0, 0x3                   ! MMPS
 516        li      $p1, 0x2                        ! TLB MMU
 517        bne     $p0, $p1, 1f
 518        tlbop   flushall                        ! Flush TLB
 5191:
 520        mfsr    $p0, MR_CAC_CTL                 ! Get the $CACHE_CTL reg
 521        li      $p1, DIS_DCAC
 522        and     $p0, $p0, $p1                   ! Clear the DC_EN bit
 523        mtsr    $p0, MR_CAC_CTL                 ! Write back the $CACHE_CTL reg
 524        br      $r0                             ! Jump to the input address
 525