Merge tag 'u-boot-imx-20211020' of https://source.denx.de/u-boot/custodians/u-boot-imx
[platform/kernel/u-boot.git] / arch / riscv / cpu / start.S
index a4433fb..76850ec 100644 (file)
@@ -13,7 +13,6 @@
 #include <config.h>
 #include <common.h>
 #include <elf.h>
-#include <asm/csr.h>
 #include <asm/encoding.h>
 #include <generated/asm-offsets.h>
 
@@ -40,30 +39,46 @@ secondary_harts_relocation_error:
 .section .text
 .globl _start
 _start:
-#ifdef CONFIG_RISCV_MMODE
-       csrr    a0, mhartid
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
+       csrr    a0, CSR_MHARTID
 #endif
 
-       /* save hart id and dtb pointer */
+       /*
+        * Save hart id and dtb pointer. The thread pointer register is not
+        * modified by C code. It is used by secondary_hart_loop.
+        */
        mv      tp, a0
        mv      s1, a1
 
+       /*
+        * Set the global data pointer to a known value in case we get a very
+        * early trap. The global data pointer will be set its actual value only
+        * after it has been initialized.
+        */
+       mv      gp, zero
+
+       /*
+        * Set the trap handler. This must happen after initializing gp because
+        * the handler may use it.
+        */
        la      t0, trap_entry
        csrw    MODE_PREFIX(tvec), t0
 
-       /* mask all interrupts */
+       /*
+        * Mask all interrupts. Interrupts are disabled globally (in m/sstatus)
+        * for U-Boot, but we will need to read m/sip to determine if we get an
+        * IPI
+        */
        csrw    MODE_PREFIX(ie), zero
 
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
        /* check if hart is within range */
        /* tp: hart id */
        li      t0, CONFIG_NR_CPUS
        bge     tp, t0, hart_out_of_bounds_loop
-#endif
 
-#ifdef CONFIG_SMP
        /* set xSIE bit to receive IPIs */
-#ifdef CONFIG_RISCV_MMODE
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
        li      t0, MIE_MSIE
 #else
        li      t0, SIE_SSIE
@@ -76,7 +91,11 @@ _start:
  */
 call_board_init_f:
        li      t0, -16
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
+       li      t1, CONFIG_SPL_STACK
+#else
        li      t1, CONFIG_SYS_INIT_SP_ADDR
+#endif
        and     sp, t1, t0              /* force 16 byte alignment */
 
 call_board_init_f_0:
@@ -84,13 +103,13 @@ call_board_init_f_0:
        jal     board_init_f_alloc_reserve
 
        /*
-        * Set global data pointer here for all harts, uninitialized at this
-        * point.
+        * Save global data pointer for later. We don't set it here because it
+        * is not initialized yet.
         */
-       mv      gp, a0
+       mv      s0, a0
 
        /* setup stack */
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
        /* tp: hart id */
        slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
        sub     sp, a0, t0
@@ -98,34 +117,54 @@ call_board_init_f_0:
        mv      sp, a0
 #endif
 
+       /* Configure proprietary settings and customized CSRs of harts */
+call_harts_early_init:
+       jal     harts_early_init
+
+#ifndef CONFIG_XIP
        /*
         * Pick hart to initialize global data and run U-Boot. The other harts
         * wait for initialization to complete.
         */
        la      t0, hart_lottery
-       li      s2, 1
+       li      t1, 1
        amoswap.w s2, t1, 0(t0)
        bnez    s2, wait_for_gd_init
-
-       la      t0, prior_stage_fdt_address
-       SREG    s1, 0(t0)
+#else
+       /*
+        * FIXME: gp is set before it is initialized. If an XIP U-Boot ever
+        * encounters a pending IPI on boot it is liable to jump to whatever
+        * memory happens to be in ipi_data.addr on boot. It may also run into
+        * problems if it encounters an exception too early (because printf/puts
+        * accesses gd).
+        */
+       mv      gp, s0
+       bnez    tp, secondary_hart_loop
+#endif
 
        jal     board_init_f_init_reserve
 
+       SREG    s1, GD_FIRMWARE_FDT_ADDR(gp)
        /* save the boot hart id to global_data */
        SREG    tp, GD_BOOT_HART(gp)
 
+#ifndef CONFIG_XIP
        la      t0, available_harts_lock
-       fence   rw, w
-       amoswap.w zero, zero, 0(t0)
+       amoswap.w.rl zero, zero, 0(t0)
 
 wait_for_gd_init:
        la      t0, available_harts_lock
        li      t1, 1
-1:     amoswap.w t1, t1, 0(t0)
-       fence   r, rw
+1:     amoswap.w.aq t1, t1, 0(t0)
        bnez    t1, 1b
 
+       /*
+        * Set the global data pointer only when gd_t has been initialized.
+        * This was already set by arch_setup_gd on the boot hart, but all other
+        * harts' global data pointers gets set here.
+        */
+       mv      gp, s0
+
        /* register available harts in the available_harts mask */
        li      t1, 1
        sll     t1, t1, tp
@@ -133,14 +172,14 @@ wait_for_gd_init:
        or      t2, t2, t1
        SREG    t2, GD_AVAILABLE_HARTS(gp)
 
-       fence   rw, w
-       amoswap.w zero, zero, 0(t0)
+       amoswap.w.rl zero, zero, 0(t0)
 
        /*
         * Continue on hart lottery winner, others branch to
         * secondary_hart_loop.
         */
        bnez    s2, secondary_hart_loop
+#endif
 
        /* Enable cache */
        jal     icache_enable
@@ -152,10 +191,63 @@ wait_for_gd_init:
 
        mv      a0, zero                /* a0 <-- boot_flags = 0 */
        la      t5, board_init_f
-       jr      t5                      /* jump to board_init_f() */
+       jalr    t5                      /* jump to board_init_f() */
+
+#ifdef CONFIG_SPL_BUILD
+spl_clear_bss:
+       la      t0, __bss_start
+       la      t1, __bss_end
+       beq     t0, t1, spl_stack_gd_setup
+
+spl_clear_bss_loop:
+       SREG    zero, 0(t0)
+       addi    t0, t0, REGBYTES
+       blt     t0, t1, spl_clear_bss_loop
+
+spl_stack_gd_setup:
+       jal     spl_relocate_stack_gd
+
+       /* skip setup if we did not relocate */
+       beqz    a0, spl_call_board_init_r
+       mv      s0, a0
+
+       /* setup stack on main hart */
+#if CONFIG_IS_ENABLED(SMP)
+       /* tp: hart id */
+       slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
+       sub     sp, s0, t0
+#else
+       mv      sp, s0
+#endif
+
+#if CONFIG_IS_ENABLED(SMP)
+       /* set new stack and global data pointer on secondary harts */
+spl_secondary_hart_stack_gd_setup:
+       la      a0, secondary_hart_relocate
+       mv      a1, s0
+       mv      a2, s0
+       mv      a3, zero
+       jal     smp_call_function
+
+       /* hang if relocation of secondary harts has failed */
+       beqz    a0, 1f
+       mv      a1, a0
+       la      a0, secondary_harts_relocation_error
+       jal     printf
+       jal     hang
+#endif
+
+       /* set new global data pointer on main hart */
+1:     mv      gp, s0
+
+spl_call_board_init_r:
+       mv      a0, zero
+       mv      a1, zero
+       jal     board_init_r
+#endif
 
 /*
- * void relocate_code (addr_sp, gd, addr_moni)
+ * void relocate_code(addr_sp, gd, addr_moni)
  *
  * This "function" does not return, instead it continues in RAM
  * after relocating the monitor code.
@@ -171,7 +263,7 @@ relocate_code:
  *Set up the stack
  */
 stack_setup:
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
        /* tp: hart id */
        slli    t0, tp, CONFIG_STACK_SIZE_SHIFT
        sub     sp, s2, t0
@@ -208,7 +300,7 @@ fix_rela_dyn:
 /*
  * skip first reserved entry: address, type, addend
  */
-       bne     t1, t2, 7f
+       j       10f
 
 6:
        LREG    t5, -(REGBYTES*2)(t1)   /* t5 <-- relocation info:type */
@@ -219,9 +311,7 @@ fix_rela_dyn:
        add     t5, t5, t6              /* t5 <-- location to fix up in RAM */
        add     t3, t3, t6              /* t3 <-- location to fix up in RAM */
        SREG    t5, 0(t3)
-7:
-       addi    t1, t1, (REGBYTES*3)
-       ble     t1, t2, 6b
+       j       10f
 
 8:
        la      t4, __dyn_sym_start
@@ -238,13 +328,15 @@ fix_rela_dyn:
        li      t5, SYM_SIZE
        mul     t0, t0, t5
        add     s5, t4, t0
+       LREG    t0, -(REGBYTES)(t1)     /* t0 <-- addend */
        LREG    t5, REGBYTES(s5)
+       add     t5, t5, t0
        add     t5, t5, t6              /* t5 <-- location to fix up in RAM */
        add     t3, t3, t6              /* t3 <-- location to fix up in RAM */
        SREG    t5, 0(t3)
 10:
        addi    t1, t1, (REGBYTES*3)
-       ble     t1, t2, 9b
+       ble     t1, t2, 6b
 
 /*
  * trap update
@@ -263,10 +355,10 @@ clear_bss:
 clbss_l:
        SREG    zero, 0(t0)             /* clear loop... */
        addi    t0, t0, REGBYTES
-       bne     t0, t1, clbss_l
+       blt     t0, t1, clbss_l
 
 relocate_secondary_harts:
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
        /* send relocation IPI */
        la      t0, secondary_hart_relocate
        add     a0, t0, t6
@@ -276,6 +368,7 @@ relocate_secondary_harts:
 
        mv      a1, s2
        mv      a2, s3
+       mv      a3, zero
        jal     smp_call_function
 
        /* hang if relocation of secondary harts has failed */
@@ -296,9 +389,8 @@ relocate_secondary_harts:
 call_board_init_r:
        jal     invalidate_icache_all
        jal     flush_dcache_all
-       la      t0, board_init_r
-       mv      t4, t0                  /* offset of board_init_r() */
-       add     t4, t4, t6              /* real address of board_init_r() */
+       la      t0, board_init_r        /* offset of board_init_r() */
+       add     t4, t0, t6              /* real address of board_init_r() */
 /*
  * setup parameters for board_init_r
  */
@@ -310,14 +402,12 @@ call_board_init_r:
  */
        jr      t4                      /* jump to board_init_r() */
 
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
 hart_out_of_bounds_loop:
        /* Harts in this loop are out of bounds, increase CONFIG_NR_CPUS. */
        wfi
        j       hart_out_of_bounds_loop
-#endif
 
-#ifdef CONFIG_SMP
 /* SMP relocation entry */
 secondary_hart_relocate:
        /* a1: new sp */
@@ -332,12 +422,16 @@ secondary_hart_relocate:
        mv      gp, a2
 #endif
 
+/*
+ * Interrupts are disabled globally, but they can still be read from m/sip. The
+ * wfi function will wake us up if we get an IPI, even if we do not trap.
+ */
 secondary_hart_loop:
        wfi
 
-#ifdef CONFIG_SMP
+#if CONFIG_IS_ENABLED(SMP)
        csrr    t0, MODE_PREFIX(ip)
-#ifdef CONFIG_RISCV_MMODE
+#if CONFIG_IS_ENABLED(RISCV_MMODE)
        andi    t0, t0, MIE_MSIE
 #else
        andi    t0, t0, SIE_SSIE