riscv: add SPL support

U-Boot SPL on the generic RISC-V CPU supports two boot flows, directly
jumping to the image and via OpenSBI firmware. In the first case, both
U-Boot SPL and proper must be compiled to run in the same privilege
mode. Using OpenSBI firmware, U-Boot SPL must be compiled for machine
mode and U-Boot proper for supervisor mode.

To be able to use SPL, boards have to provide a supported SPL boot
device.

Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
diff --git a/arch/riscv/cpu/generic/Kconfig b/arch/riscv/cpu/generic/Kconfig
index b7552f5..b2cb155 100644
--- a/arch/riscv/cpu/generic/Kconfig
+++ b/arch/riscv/cpu/generic/Kconfig
@@ -10,3 +10,6 @@
 	imply RISCV_TIMER
 	imply SIFIVE_CLINT if (RISCV_MMODE || SPL_RISCV_MMODE)
 	imply CMD_CPU
+	imply SPL_CPU_SUPPORT
+	imply SPL_OPENSBI
+	imply SPL_LOAD_FIT
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index e82ee9e..66c6039 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -75,7 +75,11 @@
  */
 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:
@@ -159,7 +163,24 @@
 
 	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_call_board_init_r
+
+spl_clear_bss_loop:
+	SREG	zero, 0(t0)
+	addi	t0, t0, REGBYTES
+	bne	t0, t1, spl_clear_bss_loop
+
+spl_call_board_init_r:
+	mv	a0, zero
+	mv	a1, zero
+	jal	board_init_r
+#endif
 
 /*
  * void relocate_code (addr_sp, gd, addr_moni)
diff --git a/arch/riscv/cpu/u-boot-spl.lds b/arch/riscv/cpu/u-boot-spl.lds
new file mode 100644
index 0000000..32255d5
--- /dev/null
+++ b/arch/riscv/cpu/u-boot-spl.lds
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Based on arch/riscv/cpu/u-boot.lds, which is
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * and arch/mips/cpu/u-boot-spl.lds.
+ */
+MEMORY { .spl_mem : ORIGIN = IMAGE_TEXT_BASE, LENGTH = IMAGE_MAX_SIZE }
+MEMORY { .bss_mem : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+		    LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_ARCH("riscv")
+ENTRY(_start)
+
+SECTIONS
+{
+	. = ALIGN(4);
+	.text : {
+		arch/riscv/cpu/start.o	(.text)
+		*(.text*)
+	} > .spl_mem
+
+	. = ALIGN(4);
+	.rodata : {
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
+	} > .spl_mem
+
+	. = ALIGN(4);
+	.data : {
+		*(.data*)
+	} > .spl_mem
+	. = ALIGN(4);
+
+	.got : {
+		__got_start = .;
+		*(.got.plt) *(.got)
+		__got_end = .;
+	} > .spl_mem
+
+	. = ALIGN(4);
+
+	.u_boot_list : {
+		KEEP(*(SORT(.u_boot_list*)));
+	} > .spl_mem
+
+	. = ALIGN(4);
+
+	.binman_sym_table : {
+		__binman_sym_start = .;
+		KEEP(*(SORT(.binman_sym*)));
+		__binman_sym_end = .;
+	} > .spl_mem
+
+	. = ALIGN(4);
+
+	/DISCARD/ : { *(.rela.plt*) }
+	.rela.dyn : {
+		__rel_dyn_start = .;
+		*(.rela*)
+		__rel_dyn_end = .;
+	} > .spl_mem
+
+	. = ALIGN(4);
+
+	.dynsym : {
+		__dyn_sym_start = .;
+		*(.dynsym)
+		__dyn_sym_end = .;
+	} > .spl_mem
+
+	. = ALIGN(4);
+
+	_end = .;
+
+	.bss : {
+		__bss_start = .;
+		*(.bss*)
+		. = ALIGN(4);
+		__bss_end = .;
+	} > .bss_mem
+}