u-boot/arch/nds32/cpu/n1213/start.S
Tom Rini 83d290c56f SPDX: Convert all of our single license tags to Linux Kernel style
When U-Boot started using SPDX tags we were among the early adopters and
there weren't a lot of other examples to borrow from.  So we picked the
area of the file that usually had a full license text and replaced it
with an appropriate SPDX-License-Identifier: entry.  Since then, the
Linux Kernel has adopted SPDX tags and they place it as the very first
line in a file (except where shebangs are used, then it's second line)
and with slightly different comment styles than us.

In part due to community overlap, in part due to better tag visibility
and in part for other minor reasons, switch over to that style.

This commit changes all instances where we have a single declared
license in the tag as both the before and after are identical in tag
contents.  There's also a few places where I found we did not have a tag
and have introduced one.

Signed-off-by: Tom Rini <trini@konsulko.com>
2018-05-07 09:34:12 -04:00

575 lines
13 KiB
ArmAsm

/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Andesboot - Startup Code for Whitiger core
*
* Copyright (C) 2006 Andes Technology Corporation
* Copyright (C) 2006 Shawn Lin <nobuhiro@andestech.com>
* Copyright (C) 2011 Macpaul Lin <macpaul@andestech.com>
* Greentime Hu <greentime@andestech.com>
*/
.pic
#include <asm-offsets.h>
#include <config.h>
#include <common.h>
#include <asm/macro.h>
/*
* Jump vector table for EVIC mode
*/
#define ENA_DCAC 2UL
#define DIS_DCAC ~ENA_DCAC
#define ICAC_MEM_KBF_ISET (0x07) ! I Cache sets per way
#define ICAC_MEM_KBF_IWAY (0x07<<3) ! I cache ways
#define ICAC_MEM_KBF_ISZ (0x07<<6) ! I cache line size
#define DCAC_MEM_KBF_DSET (0x07) ! D Cache sets per way
#define DCAC_MEM_KBF_DWAY (0x07<<3) ! D cache ways
#define DCAC_MEM_KBF_DSZ (0x07<<6) ! D cache line size
#define PSW $ir0
#define EIT_INTR_PSW $ir1 ! interruption $PSW
#define EIT_PREV_IPSW $ir2 ! previous $IPSW
#define EIT_IVB $ir3 ! intr vector base address
#define EIT_EVA $ir4 ! MMU related Exception VA reg
#define EIT_PREV_EVA $ir5 ! previous $eva
#define EIT_ITYPE $ir6 ! interruption type
#define EIT_PREV_ITYPE $ir7 ! prev intr type
#define EIT_MACH_ERR $ir8 ! machine error log
#define EIT_INTR_PC $ir9 ! Interruption PC
#define EIT_PREV_IPC $ir10 ! previous $IPC
#define EIT_OVL_INTR_PC $ir11 ! overflow interruption PC
#define EIT_PREV_P0 $ir12 ! prev $P0
#define EIT_PREV_P1 $ir13 ! prev $p1
#define CR_ICAC_MEM $cr1 ! I-cache/memory config reg
#define CR_DCAC_MEM $cr2 ! D-cache/memory config reg
#define MR_CAC_CTL $mr8
.globl _start
_start: j reset
j tlb_fill
j tlb_not_present
j tlb_misc
j tlb_vlpt_miss
j machine_error
j debug
j general_exception
j syscall
j internal_interrupt ! H0I
j internal_interrupt ! H1I
j internal_interrupt ! H2I
j internal_interrupt ! H3I
j internal_interrupt ! H4I
j internal_interrupt ! H5I
j software_interrupt ! S0I
.balign 16
/*
* Andesboot Startup Code (reset vector)
*
* 1. bootstrap
* 1.1 reset - start of u-boot
* 1.2 to superuser mode - as is when reset
* 1.4 Do lowlevel_init
* - (this will jump out to lowlevel_init.S in SoC)
* - (lowlevel_init)
* 1.3 Turn off watchdog timer
* - (this will jump out to watchdog.S in SoC)
* - (turnoff_watchdog)
* 2. Do critical init when reboot (not from mem)
* 3. Relocate andesboot to ram
* 4. Setup stack
* 5. Jump to second stage (board_init_r)
*/
/* Note: TEXT_BASE is defined by the (board-dependent) linker script */
.globl _TEXT_BASE
_TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE
/* IRQ stack memory (calculated at run-time) + 8 bytes */
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
.word 0x0badc0de
/*
* The bootstrap code of nds32 core
*/
reset:
/*
* gp = ~0 for burn mode
* = ~load_address for load mode
*/
reset_gp:
.relax_hint 0
sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
.relax_hint 0
ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
add5.pc $gp
set_ivb:
li $r0, 0x0
/* turn on BTB */
mtsr $r0, $misc_ctl
/* set IVIC, vector size: 4 bytes, base: 0x0 */
mtsr $r0, $ivb
/*
* MMU_CTL NTC0 Non-cacheable
*/
li $r0, ~0x6
mfsr $r1, $mr0
and $r1, $r1, $r0
mtsr $r1, $mr0
li $r0, ~0x3
mfsr $r1, $mr8
and $r1, $r1, $r0
mtsr $r1, $mr8
#if (!defined(CONFIG_SYS_ICACHE_OFF) || !defined(CONFIG_SYS_DCACHE_OFF))
/*
* MMU_CTL NTC0 Cacheable/Write-Back
*/
li $r0, 0x4
mfsr $r1, $mr0
or $r1, $r1, $r0
mtsr $r1, $mr0
#endif
#ifndef CONFIG_SYS_DCACHE_OFF
#ifdef CONFIG_ARCH_MAP_SYSMEM
/*
* MMU_CTL NTC1 Non-cacheable
*/
li $r0, ~0x18
mfsr $r1, $mr0
and $r1, $r1, $r0
mtsr $r1, $mr0
/*
* MMU_CTL NTM1 mapping for partition 0
*/
li $r0, ~0x6000
mfsr $r1, $mr0
and $r1, $r1, $r0
mtsr $r1, $mr0
#endif
#endif
#if !defined(CONFIG_SYS_ICACHE_OFF)
li $r0, 0x1
mfsr $r1, $mr8
or $r1, $r1, $r0
mtsr $r1, $mr8
#endif
#if !defined(CONFIG_SYS_DCACHE_OFF)
li $r0, 0x2
mfsr $r1, $mr8
or $r1, $r1, $r0
mtsr $r1, $mr8
#endif
jal mem_init
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
jal lowlevel_init
/*
* gp = ~VMA for burn mode
* = ~load_address for load mode
*/
update_gp:
.relax_hint 0
sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_-8)
.relax_hint 0
ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_-4)
add5.pc $gp
#endif
/*
* do critical initializations first (shall be in short time)
* do self_relocation ASAP.
*/
/*
* Set the N1213 (Whitiger) core to superuser mode
* According to spec, it is already when reset
*/
#ifndef CONFIG_SKIP_TRUNOFF_WATCHDOG
jal turnoff_watchdog
#endif
/*
* Do CPU critical regs init only at reboot,
* not when booting from ram
*/
#ifdef CONFIG_INIT_CRITICAL
jal cpu_init_crit ! Do CPU critical regs init
#endif
/*
* Set stackpointer in internal RAM to call board_init_f
* $sp must be 8-byte alignment for ABI compliance.
*/
call_board_init_f:
li $sp, CONFIG_SYS_INIT_SP_ADDR
move $r0, $sp
bal board_init_f_alloc_reserve
move $sp, $r0
bal board_init_f_init_reserve
#ifdef CONFIG_DEBUG_UART
bal debug_uart_init
#endif
li $r0, 0x00000000
#ifdef __PIC__
#ifdef __NDS32_N1213_43U1H__
/* __NDS32_N1213_43U1H__ implies NDS32 V0 ISA */
la $r15, board_init_f ! store function address into $r15
#endif
#endif
j board_init_f ! jump to board_init_f() in lib/board.c
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
/*
* gp = ~RAM_SIZE - TEXT_SIZE for burn/load mode
*/
.globl relocate_code
relocate_code:
move $r4, $r0 /* save addr_sp */
move $r5, $r1 /* save addr of gd */
move $r6, $r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
move $sp, $r4
la $r0, _start@GOTOFF
beq $r0, $r6, clear_bss /* skip relocation */
la $r1, _end@GOTOFF
move $r2, $r6 /* r2 <- scratch for copy_loop */
copy_loop:
lmw.bim $r11, [$r0], $r18
smw.bim $r11, [$r2], $r18
blt $r0, $r1, copy_loop
/*
* fix relocations related issues
*/
fix_relocations:
l.w $r0, _TEXT_BASE@GOTOFF /* r0 <- Text base */
sub $r9, $r6, $r0 /* r9 <- relocation offset */
la $r7, __rel_dyn_start@GOTOFF
add $r7, $r7, $r9 /* r2 <- rel __got_start in RAM */
la $r8, __rel_dyn_end@GOTOFF
add $r8, $r8, $r9 /* r2 <- rel __got_start in RAM */
li $r3, #0x2a /* R_NDS32_RELATIVE */
1:
lmw.bim $r0, [$r7], $r2 /* r0,r1,r2 <- adr,type,addend */
bne $r1, $r3, 2f
add $r0, $r0, $r9
add $r2, $r2, $r9
sw $r2, [$r0]
2:
blt $r7, $r8, 1b
clear_bss:
la $r0, __bss_start@GOTOFF /* r0 <- rel __bss_start in FLASH */
add $r0, $r0, $r9 /* r0 <- rel __bss_start in FLASH */
la $r1, __bss_end@GOTOFF /* r1 <- rel __bss_end in RAM */
add $r1, $r1, $r9 /* r0 <- rel __bss_end in RAM */
li $r2, 0x00000000 /* clear */
clbss_l:
sw $r2, [$r0] /* clear loop... */
addi $r0, $r0, #4
bne $r0, $r1, clbss_l
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
call_board_init_r:
bal invalidate_icache_all
bal flush_dcache_all
la $r0, board_init_r@GOTOFF
move $lp, $r0 /* offset of board_init_r() */
add $lp, $lp, $r9 /* real address of board_init_r() */
/* setup parameters for board_init_r */
move $r0, $r5 /* gd_t */
move $r1, $r6 /* dest_addr */
#ifdef __PIC__
#ifdef __NDS32_N1213_43U1H__ /* NDS32 V0 ISA */
move $r15, $lp /* store function address into $r15 */
#endif
#endif
/* jump to it ... */
jr $lp /* jump to board_init_r() */
/*
* Initialize CPU critical registers
*
* 1. Setup control registers
* 1.1 Mask all IRQs
* 1.2 Flush cache and TLB
* 1.3 Disable MMU and cache
* 2. Setup memory timing
*/
cpu_init_crit:
move $r0, $lp /* push ra */
/* Disable Interrupts by clear GIE in $PSW reg */
setgie.d
/* Flush caches and TLB */
/* Invalidate caches */
jal invalidate_icac
jal invalidate_dcac
/* Flush TLB */
mfsr $p0, $MMU_CFG
andi $p0, $p0, 0x3 ! MMPS
li $p1, 0x2 ! TLB MMU
bne $p0, $p1, 1f
tlbop flushall ! Flush TLB
1:
! Disable MMU, Dcache
! Whitiger is MMU disabled when reset
! Disable the D$
mfsr $p0, MR_CAC_CTL ! Get the $CACHE_CTL reg
li $p1, DIS_DCAC
and $p0, $p0, $p1 ! Set DC_EN bit
mtsr $p0, MR_CAC_CTL ! write back the $CACHE_CTL reg
isb
move $lp, $r0
2:
ret
/*
* Invalidate I$
*/
invalidate_icac:
! read $cr1(I CAC/MEM cfg. reg.) configuration
mfsr $t0, CR_ICAC_MEM
! Get the ISZ field
andi $p0, $t0, ICAC_MEM_KBF_ISZ
! if $p0=0, then no I CAC existed
beqz $p0, end_flush_icache
! get $p0 the index of I$ block
srli $p0, $p0, 6
! $t1= bit width of I cache line size(ISZ)
addi $t1, $p0, 2
li $t4, 1
sll $t5, $t4, $t1 ! get $t5 cache line size
andi $p1, $t0, ICAC_MEM_KBF_ISET ! get the ISET field
addi $t2, $p1, 6 ! $t2= bit width of ISET
andi $p1, $t0, ICAC_MEM_KBF_IWAY ! get bitfield of Iway
srli $p1, $p1, 3
addi $p1, $p1, 1 ! then $p1 is I way number
add $t3, $t2, $t1 ! SHIFT
sll $p1, $p1, $t3 ! GET the total cache size
ICAC_LOOP:
sub $p1, $p1, $t5
cctl $p1, L1I_IX_INVAL
bnez $p1, ICAC_LOOP
end_flush_icache:
ret
/*
* Invalidate D$
*/
invalidate_dcac:
! read $cr2(D CAC/MEM cfg. reg.) configuration
mfsr $t0, CR_DCAC_MEM
! Get the DSZ field
andi $p0, $t0, DCAC_MEM_KBF_DSZ
! if $p0=0, then no D CAC existed
beqz $p0, end_flush_dcache
! get $p0 the index of D$ block
srli $p0, $p0, 6
! $t1= bit width of D cache line size(DSZ)
addi $t1, $p0, 2
li $t4, 1
sll $t5, $t4, $t1 ! get $t5 cache line size
andi $p1, $t0, DCAC_MEM_KBF_DSET ! get the DSET field
addi $t2, $p1, 6 ! $t2= bit width of DSET
andi $p1, $t0, DCAC_MEM_KBF_DWAY ! get bitfield of D way
srli $p1, $p1, 3
addi $p1, $p1, 1 ! then $p1 is D way number
add $t3, $t2, $t1 ! SHIFT
sll $p1, $p1, $t3 ! GET the total cache size
DCAC_LOOP:
sub $p1, $p1, $t5
cctl $p1, L1D_IX_INVAL
bnez $p1, DCAC_LOOP
end_flush_dcache:
ret
/*
* Interrupt handling
*/
/*
* exception handlers
*/
.align 5
.macro SAVE_ALL
! FIXME: Other way to get PC?
! FIXME: Update according to the newest spec!!
1:
li $r28, 1
push $r28
mfsr $r28, PSW ! $PSW
push $r28
mfsr $r28, EIT_EVA ! $ir1 $EVA
push $r28
mfsr $r28, EIT_ITYPE ! $ir2 $ITYPE
push $r28
mfsr $r28, EIT_MACH_ERR ! $ir3 Mach Error
push $r28
mfsr $r28, EIT_INTR_PSW ! $ir5 $IPSW
push $r28
mfsr $r28, EIT_PREV_IPSW ! $ir6 prev $IPSW
push $r28
mfsr $r28, EIT_PREV_EVA ! $ir7 prev $EVA
push $r28
mfsr $r28, EIT_PREV_ITYPE ! $ir8 prev $ITYPE
push $r28
mfsr $r28, EIT_INTR_PC ! $ir9 Interruption PC
push $r28
mfsr $r28, EIT_PREV_IPC ! $ir10 prev INTR_PC
push $r28
mfsr $r28, EIT_OVL_INTR_PC ! $ir11 Overflowed INTR_PC
push $r28
mfusr $r28, $d1.lo
push $r28
mfusr $r28, $d1.hi
push $r28
mfusr $r28, $d0.lo
push $r28
mfusr $r28, $d0.hi
push $r28
pushm $r0, $r30 ! store $sp-$r31, ra-$r30, $gp-$r29, $r28-$fp
addi $sp, $sp, -4 ! make room for implicit pt_regs parameters
.endm
.align 5
tlb_fill:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 1 ! Determine interruption type
bal do_interruption
.align 5
tlb_not_present:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 2 ! Determine interruption type
bal do_interruption
.align 5
tlb_misc:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 3 ! Determine interruption type
bal do_interruption
.align 5
tlb_vlpt_miss:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 4 ! Determine interruption type
bal do_interruption
.align 5
machine_error:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 5 ! Determine interruption type
bal do_interruption
.align 5
debug:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 6 ! Determine interruption type
bal do_interruption
.align 5
general_exception:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 7 ! Determine interruption type
bal do_interruption
.align 5
syscall:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 8 ! Determine interruption type
bal do_interruption
.align 5
internal_interrupt:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 9 ! Determine interruption type
bal do_interruption
.align 5
software_interrupt:
SAVE_ALL
move $r0, $sp ! To get the kernel stack
li $r1, 10 ! Determine interruption type
bal do_interruption
.align 5
/*
* void reset_cpu(ulong addr);
* $r0: input address to jump to
*/
.globl reset_cpu
reset_cpu:
/* No need to disable MMU because we never enable it */
bal invalidate_icac
bal invalidate_dcac
mfsr $p0, $MMU_CFG
andi $p0, $p0, 0x3 ! MMPS
li $p1, 0x2 ! TLB MMU
bne $p0, $p1, 1f
tlbop flushall ! Flush TLB
1:
mfsr $p0, MR_CAC_CTL ! Get the $CACHE_CTL reg
li $p1, DIS_DCAC
and $p0, $p0, $p1 ! Clear the DC_EN bit
mtsr $p0, MR_CAC_CTL ! Write back the $CACHE_CTL reg
br $r0 ! Jump to the input address