Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-riscv

+ riscv: Add Zbb support
+ riscv: Add preliminary RISC-V falcon mode support
+ riscv: Remove dram_init_banksize()
+ andes: rearrange PLICSW scheme
+ visionfive2: enable bootstage configs
diff --git a/Makefile b/Makefile
index b204a50..e0040a4 100644
--- a/Makefile
+++ b/Makefile
@@ -2165,7 +2165,7 @@
 	       mkimage-out.spl.mkimage mkimage.spl.mkimage imx-boot.map \
 	       itb.fit.fit itb.fit.itb itb.map spl.map mkimage-out.rom.mkimage \
 	       mkimage.rom.mkimage rom.map simple-bin.map simple-bin-spi.map \
-	       idbloader-spi.img lib/efi_loader/helloworld_efi.S
+	       idbloader-spi.img lib/efi_loader/helloworld_efi.S *.itb
 
 # Directories & files removed with 'make mrproper'
 MRPROPER_DIRS  += include/config include/generated spl tpl vpl \
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 183885e..e291456 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -187,6 +187,97 @@
 	  riscv32 ABI from ilp32 to ilp32d and the riscv64 ABI from lp64 to
 	  lp64d.
 
+config RISCV_ISA_ZBB
+	bool "Zbb extension support for bit manipulation instructions"
+	help
+	  Adds ZBB extension (basic bit manipulation) to the ISA subsets
+	  that the toolchain is allowed to emit when building U-Boot.
+	  The Zbb extension provides instructions to accelerate a number
+	  of bit-specific operations (count bit population, sign extending,
+	  bitrotation, etc) and enables optimized string routines.
+
+menu "Use assembly optimized implementation of string routines"
+
+config USE_ARCH_STRLEN
+	bool "Use an assembly optimized implementation of strlen"
+	default y
+	depends on RISCV_ISA_ZBB
+	help
+	  Enable the generation of an optimized version of strlen using
+	  Zbb extension.
+
+config SPL_USE_ARCH_STRLEN
+	bool "Use an assembly optimized implementation of strlen for SPL"
+	default y if USE_ARCH_STRLEN
+	depends on RISCV_ISA_ZBB
+	depends on SPL
+	help
+	  Enable the generation of an optimized version of strlen using
+	  Zbb extension.
+
+config TPL_USE_ARCH_STRLEN
+	bool "Use an assembly optimized implementation of strlen for TPL"
+	default y if USE_ARCH_STRLEN
+	depends on RISCV_ISA_ZBB
+	depends on TPL
+	help
+	  Enable the generation of an optimized version of strlen using
+	  Zbb extension.
+
+config USE_ARCH_STRCMP
+	bool "Use an assembly optimized implementation of strcmp"
+	default y
+	depends on RISCV_ISA_ZBB
+	help
+	  Enable the generation of an optimized version of strcmp using
+	  Zbb extension.
+
+config SPL_USE_ARCH_STRCMP
+	bool "Use an assembly optimized implementation of strcmp for SPL"
+	default y if USE_ARCH_STRCMP
+	depends on RISCV_ISA_ZBB
+	depends on SPL
+	help
+	  Enable the generation of an optimized version of strcmp using
+	  Zbb extension.
+
+config TPL_USE_ARCH_STRCMP
+	bool "Use an assembly optimized implementation of strcmp for TPL"
+	default y if USE_ARCH_STRCMP
+	depends on RISCV_ISA_ZBB
+	depends on TPL
+	help
+	  Enable the generation of an optimized version of strcmp using
+	  Zbb extension.
+
+config USE_ARCH_STRNCMP
+	bool "Use an assembly optimized implementation of strncmp"
+	default y
+	depends on RISCV_ISA_ZBB
+	help
+	  Enable the generation of an optimized version of strncmp using
+	  Zbb extension.
+
+config SPL_USE_ARCH_STRNCMP
+	bool "Use an assembly optimized implementation of strncmp for SPL"
+	default y if USE_ARCH_STRNCMP
+	depends on RISCV_ISA_ZBB
+	depends on SPL
+	help
+	  Enable the generation of an optimized version of strncmp using
+	  Zbb extension.
+
+config TPL_USE_ARCH_STRNCMP
+	bool "Use an assembly optimized implementation of strncmp for TPL"
+	default y if USE_ARCH_STRNCMP
+	depends on RISCV_ISA_ZBB
+	depends on TPL
+	help
+	  Enable the generation of an optimized version of strncmp using
+	  Zbb extension.
+
+endmenu
+
 config RISCV_ISA_A
 	def_bool y
 
@@ -424,4 +515,12 @@
 
 endmenu
 
+config SPL_LOAD_FIT_OPENSBI_OS_BOOT
+	bool "Enable SPL (OpenSBI OS boot mode) applying linux from FIT"
+	depends on SPL_LOAD_FIT
+	help
+	  Use fw_dynamic from the FIT image, and u-boot SPL will invoke it directly.
+	  This is a shortcut boot flow, from u-boot SPL -> OpenSBI -> u-boot proper
+	  -> linux to u-boot SPL -> OpenSBI -> linux.
+
 endmenu
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 4963b51..b3ef870 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -24,6 +24,9 @@
 ifeq ($(CONFIG_RISCV_ISA_C),y)
 	ARCH_C = c
 endif
+ifeq ($(CONFIG_RISCV_ISA_ZBB),y)
+	ARCH_ZBB = _zbb
+endif
 ifeq ($(CONFIG_CMODEL_MEDLOW),y)
 	CMODEL = medlow
 endif
@@ -32,7 +35,7 @@
 endif
 
 
-RISCV_MARCH = $(ARCH_BASE)$(ARCH_A)$(ARCH_F)$(ARCH_D)$(ARCH_C)
+RISCV_MARCH = $(ARCH_BASE)$(ARCH_A)$(ARCH_F)$(ARCH_D)$(ARCH_C)$(ARCH_ZBB)
 ABI = $(ABI_BASE)$(ABI_D)
 
 # Newer binutils versions default to ISA spec version 20191213 which moves some
diff --git a/arch/riscv/cpu/generic/dram.c b/arch/riscv/cpu/generic/dram.c
index 94d8018..1b51bae 100644
--- a/arch/riscv/cpu/generic/dram.c
+++ b/arch/riscv/cpu/generic/dram.c
@@ -20,19 +20,3 @@
 {
 	return fdtdec_setup_memory_banksize();
 }
-
-phys_addr_t board_get_usable_ram_top(phys_size_t total_size)
-{
-	/*
-	 * Ensure that we run from first 4GB so that all
-	 * addresses used by U-Boot are 32bit addresses.
-	 *
-	 * This in-turn ensures that 32bit DMA capable
-	 * devices work fine because DMA mapping APIs will
-	 * provide 32bit DMA addresses only.
-	 */
-	if (gd->ram_top >= SZ_4G)
-		return SZ_4G - 1;
-
-	return gd->ram_top;
-}
diff --git a/arch/riscv/dts/binman.dtsi b/arch/riscv/dts/binman.dtsi
index 156cb00..6b4eb8d 100644
--- a/arch/riscv/dts/binman.dtsi
+++ b/arch/riscv/dts/binman.dtsi
@@ -5,6 +5,9 @@
 
 #include <config.h>
 
+#define U64_TO_U32_H(addr)		(((addr) >> 32) & 0xffffffff)
+#define U64_TO_U32_L(addr)		((addr) & 0xffffffff)
+
 / {
 	binman: binman {
 		multiple-images;
@@ -13,26 +16,47 @@
 
 &binman {
 	itb {
+
+#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT
 		filename = "u-boot.itb";
+#else
+		filename = "linux.itb";
+#endif
 
 		fit {
 			description = "Configuration to load OpenSBI before U-Boot";
-			#address-cells = <1>;
+			#address-cells = <2>;
 			fit,fdt-list = "of-list";
 
 			images {
+#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT
 				uboot {
 					description = "U-Boot";
 					type = "standalone";
 					os = "U-Boot";
 					arch = "riscv";
 					compression = "none";
-					load = <CONFIG_TEXT_BASE>;
+					load = <U64_TO_U32_H(CONFIG_TEXT_BASE)
+						U64_TO_U32_L(CONFIG_TEXT_BASE)>;
 
 					uboot_blob: blob-ext {
 						filename = "u-boot-nodtb.bin";
 					};
 				};
+#else
+				linux {
+					description = "Linux";
+					type = "standalone";
+					os = "Linux";
+					arch = "riscv";
+					compression = "none";
+					load = <CONFIG_TEXT_BASE>;
+
+					linux_blob: blob-ext {
+						filename = "Image";
+					};
+				};
+#endif
 
 				opensbi {
 					description = "OpenSBI fw_dynamic Firmware";
@@ -40,8 +64,10 @@
 					os = "opensbi";
 					arch = "riscv";
 					compression = "none";
-					load = <CONFIG_SPL_OPENSBI_LOAD_ADDR>;
-					entry = <CONFIG_SPL_OPENSBI_LOAD_ADDR>;
+					load = <U64_TO_U32_H(CONFIG_SPL_OPENSBI_LOAD_ADDR)
+						U64_TO_U32_L(CONFIG_SPL_OPENSBI_LOAD_ADDR)>;
+					entry = <U64_TO_U32_H(CONFIG_SPL_OPENSBI_LOAD_ADDR)
+						U64_TO_U32_L(CONFIG_SPL_OPENSBI_LOAD_ADDR)>;
 
 					opensbi_blob: opensbi {
 						filename = "fw_dynamic.bin";
@@ -68,7 +94,11 @@
 #endif
 					description = "NAME";
 					firmware = "opensbi";
+#ifndef CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT
 					loadables = "uboot";
+#else
+					loadables = "linux";
+#endif
 #ifndef CONFIG_OF_BOARD
 					fdt = "fdt-SEQ";
 #endif
diff --git a/arch/riscv/include/asm/string.h b/arch/riscv/include/asm/string.h
index 7dee3e4..38ad85f 100644
--- a/arch/riscv/include/asm/string.h
+++ b/arch/riscv/include/asm/string.h
@@ -40,4 +40,22 @@
 #endif
 extern void *memset(void *, int, __kernel_size_t);
 
+#undef __HAVE_ARCH_STRLEN
+#if CONFIG_IS_ENABLED(USE_ARCH_STRLEN)
+#define __HAVE_ARCH_STRLEN
+#endif
+extern __kernel_size_t strlen(const char *);
+
+#undef __HAVE_ARCH_STRCMP
+#if CONFIG_IS_ENABLED(USE_ARCH_STRCMP)
+#define __HAVE_ARCH_STRCMP
+#endif
+extern int strcmp(const char *, const char *);
+
+#undef __HAVE_ARCH_STRNCMP
+#if CONFIG_IS_ENABLED(USE_ARCH_STRNCMP)
+#define __HAVE_ARCH_STRNCMP
+#endif
+extern int strncmp(const char *, const char *, size_t __kernel_size_t);
+
 #endif /* __ASM_RISCV_STRING_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 02c4d8f..9a05b66 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -42,5 +42,8 @@
 obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMSET) += memset.o
 obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMMOVE) += memmove.o
 obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_MEMCPY) += memcpy.o
+obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRLEN) += strlen_zbb.o
+obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRCMP) += strcmp_zbb.o
+obj-$(CONFIG_$(SPL_TPL_)USE_ARCH_STRNCMP) += strncmp_zbb.o
 
 obj-$(CONFIG_$(SPL_TPL_)SEMIHOSTING) += semihosting.o
diff --git a/arch/riscv/lib/andes_plicsw.c b/arch/riscv/lib/andes_plicsw.c
index 7518408..6fd49e8 100644
--- a/arch/riscv/lib/andes_plicsw.c
+++ b/arch/riscv/lib/andes_plicsw.c
@@ -22,7 +22,7 @@
 #include <linux/err.h>
 
 /* pending register */
-#define PENDING_REG(base, hart)	((ulong)(base) + 0x1000 + ((hart) / 4) * 4)
+#define PENDING_REG(base)	((ulong)(base) + 0x1000)
 /* enable register */
 #define ENABLE_REG(base, hart)	((ulong)(base) + 0x2000 + (hart) * 0x80)
 /* claim register */
@@ -30,10 +30,11 @@
 /* priority register */
 #define PRIORITY_REG(base)	((ulong)(base) + PLICSW_PRIORITY_BASE)
 
-#define ENABLE_HART_IPI         (0x01010101)
-#define SEND_IPI_TO_HART(hart)  (0x1 << (hart))
+/* Bit 0 of PLIC-SW pending array is hardwired to zero, so we start from bit 1 */
+#define FIRST_AVAILABLE_BIT	0x2
+#define SEND_IPI_TO_HART(hart)	(FIRST_AVAILABLE_BIT << (hart))
 #define PLICSW_PRIORITY_BASE        0x4
-#define PLICSW_INTERRUPT_PER_HART   0x8
+#define PLICSW_INTERRUPT_PER_HART   0x1
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -41,9 +42,8 @@
 {
 	unsigned int en;
 
-	en = ENABLE_HART_IPI << hart;
+	en = FIRST_AVAILABLE_BIT << hart;
 	writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw, hart));
-	writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw + 0x4, hart));
 
 	return 0;
 }
@@ -75,7 +75,7 @@
 	ret = uclass_find_first_device(UCLASS_CPU, &dev);
 	if (ret)
 		return ret;
-	else if (!dev)
+	if (!dev)
 		return -ENODEV;
 
 	ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
@@ -105,10 +105,9 @@
 
 int riscv_send_ipi(int hart)
 {
-	unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart));
+	unsigned int ipi = SEND_IPI_TO_HART(hart);
 
-	writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw,
-				gd->arch.boot_hart));
+	writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw));
 
 	return 0;
 }
@@ -125,10 +124,9 @@
 
 int riscv_get_ipi(int hart, int *pending)
 {
-	unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart));
+	unsigned int ipi = SEND_IPI_TO_HART(hart);
 
-	*pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw,
-						     gd->arch.boot_hart));
+	*pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw));
 	*pending = !!(*pending & ipi);
 
 	return 0;
diff --git a/arch/riscv/lib/strcmp_zbb.S b/arch/riscv/lib/strcmp_zbb.S
new file mode 100644
index 0000000..e5a367c
--- /dev/null
+++ b/arch/riscv/lib/strcmp_zbb.S
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Taken from Linux arch/riscv/lib/strcmp.S
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+
+ENTRY(__strcmp)
+WEAK(strcmp)
+.option push
+.option arch,+zbb
+	/*
+	 * Returns
+	 *   a0 - comparison result, value like strcmp
+	 *
+	 * Parameters
+	 *   a0 - string1
+	 *   a1 - string2
+	 *
+	 * Clobbers
+	 *   t0, t1, t2, t3, t4
+	 */
+
+	or	t2, a0, a1
+	li	t4, -1
+	and	t2, t2, SZREG-1
+	bnez	t2, 3f
+
+	/* Main loop for aligned string.  */
+	.p2align 3
+1:
+	REG_L	t0, 0(a0)
+	REG_L	t1, 0(a1)
+	orc.b	t3, t0
+	bne	t3, t4, 2f
+	addi	a0, a0, SZREG
+	addi	a1, a1, SZREG
+	beq	t0, t1, 1b
+
+	/*
+	 * Words don't match, and no null byte in the first
+	 * word. Get bytes in big-endian order and compare.
+	 */
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+	rev8	t0, t0
+	rev8	t1, t1
+#endif
+
+	/* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence. */
+	sltu	a0, t0, t1
+	neg	a0, a0
+	ori	a0, a0, 1
+	ret
+
+2:
+	/*
+	 * Found a null byte.
+	 * If words don't match, fall back to simple loop.
+	 */
+	bne	t0, t1, 3f
+
+	/* Otherwise, strings are equal. */
+	li	a0, 0
+	ret
+
+	/* Simple loop for misaligned strings. */
+	.p2align 3
+3:
+	lbu	t0, 0(a0)
+	lbu	t1, 0(a1)
+	addi	a0, a0, 1
+	addi	a1, a1, 1
+	bne	t0, t1, 4f
+	bnez	t0, 3b
+
+4:
+	sub	a0, t0, t1
+	ret
+.option pop
+END(__strcmp)
diff --git a/arch/riscv/lib/strlen_zbb.S b/arch/riscv/lib/strlen_zbb.S
new file mode 100644
index 0000000..bd8fa4c
--- /dev/null
+++ b/arch/riscv/lib/strlen_zbb.S
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Taken from Linux arch/riscv/lib/strlen.S
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define CZ	ctz
+# define SHIFT	srl
+#else
+# define CZ	clz
+# define SHIFT	sll
+#endif
+
+ENTRY(__strlen)
+WEAK(strlen)
+.option push
+.option arch,+zbb
+	/*
+	 * Returns
+	 *   a0 - string length
+	 *
+	 * Parameters
+	 *   a0 - String to measure
+	 *
+	 * Clobbers
+	 *   t0, t1, t2, t3
+	 */
+
+	/* Number of irrelevant bytes in the first word. */
+	andi	t2, a0, SZREG-1
+
+	/* Align pointer. */
+	andi	t0, a0, -SZREG
+
+	li	t3, SZREG
+	sub	t3, t3, t2
+	slli	t2, t2, 3
+
+	/* Get the first word.  */
+	REG_L	t1, 0(t0)
+
+	/*
+	 * Shift away the partial data we loaded to remove the irrelevant bytes
+	 * preceding the string with the effect of adding NUL bytes at the
+	 * end of the string's first word.
+	 */
+	SHIFT	t1, t1, t2
+
+	/* Convert non-NUL into 0xff and NUL into 0x00. */
+	orc.b	t1, t1
+
+	/* Convert non-NUL into 0x00 and NUL into 0xff. */
+	not	t1, t1
+
+	/*
+	 * Search for the first set bit (corresponding to a NUL byte in the
+	 * original chunk).
+	 */
+	CZ	t1, t1
+
+	/*
+	 * The first chunk is special: compare against the number
+	 * of valid bytes in this chunk.
+	 */
+	srli	a0, t1, 3
+	bgtu	t3, a0, 2f
+
+	/* Prepare for the word comparison loop. */
+	addi	t2, t0, SZREG
+	li	t3, -1
+
+	/*
+	 * Our critical loop is 4 instructions and processes data in
+	 * 4 byte or 8 byte chunks.
+	 */
+	.p2align 3
+1:
+	REG_L	t1, SZREG(t0)
+	addi	t0, t0, SZREG
+	orc.b	t1, t1
+	beq	t1, t3, 1b
+
+	not	t1, t1
+	CZ	t1, t1
+	srli	t1, t1, 3
+
+	/* Get number of processed bytes. */
+	sub	t2, t0, t2
+
+	/* Add number of characters in the first word.  */
+	add	a0, a0, t2
+
+	/* Add number of characters in the last word.  */
+	add	a0, a0, t1
+2:
+	ret
+.option pop
+END(__strlen)
diff --git a/arch/riscv/lib/strncmp_zbb.S b/arch/riscv/lib/strncmp_zbb.S
new file mode 100644
index 0000000..00e0fec
--- /dev/null
+++ b/arch/riscv/lib/strncmp_zbb.S
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Taken from Linux arch/riscv/lib/strncmp.S
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+
+ENTRY(__strncmp)
+WEAK(strncmp)
+.option push
+.option arch,+zbb
+	/*
+	 * Returns
+	 *   a0 - comparison result, like strncmp
+	 *
+	 * Parameters
+	 *   a0 - string1
+	 *   a1 - string2
+	 *   a2 - number of characters to compare
+	 *
+	 * Clobbers
+	 *   t0, t1, t2, t3, t4, t5, t6
+	 */
+
+	or	t2, a0, a1
+	li	t5, -1
+	and	t2, t2, SZREG-1
+	add	t4, a0, a2
+	bnez	t2, 3f
+
+	/* Adjust limit for fast-path.  */
+	andi	t6, t4, -SZREG
+
+	/* Main loop for aligned string.  */
+	.p2align 3
+1:
+	bge	a0, t6, 3f
+	REG_L	t0, 0(a0)
+	REG_L	t1, 0(a1)
+	orc.b	t3, t0
+	bne	t3, t5, 2f
+	orc.b	t3, t1
+	bne	t3, t5, 2f
+	addi	a0, a0, SZREG
+	addi	a1, a1, SZREG
+	beq	t0, t1, 1b
+
+	/*
+	 * Words don't match, and no null byte in the first
+	 * word. Get bytes in big-endian order and compare.
+	 */
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+	rev8	t0, t0
+	rev8	t1, t1
+#endif
+
+	/* Synthesize (t0 >= t1) ? 1 : -1 in a branchless sequence.  */
+	sltu	a0, t0, t1
+	neg	a0, a0
+	ori	a0, a0, 1
+	ret
+
+2:
+	/*
+	 * Found a null byte.
+	 * If words don't match, fall back to simple loop.
+	 */
+	bne	t0, t1, 3f
+
+	/* Otherwise, strings are equal.  */
+	li	a0, 0
+	ret
+
+	/* Simple loop for misaligned strings.  */
+	.p2align 3
+3:
+	bge	a0, t4, 5f
+	lbu	t0, 0(a0)
+	lbu	t1, 0(a1)
+	addi	a0, a0, 1
+	addi	a1, a1, 1
+	bne	t0, t1, 4f
+	bnez	t0, 3b
+
+4:
+	sub	a0, t0, t1
+	ret
+
+5:
+	li	a0, 0
+	ret
+.option pop
+END(__strncmp)
diff --git a/board/AndesTech/ae350/ae350.c b/board/AndesTech/ae350/ae350.c
index 1c2288b..d78ee40 100644
--- a/board/AndesTech/ae350/ae350.c
+++ b/board/AndesTech/ae350/ae350.c
@@ -19,6 +19,8 @@
 #include <fdtdec.h>
 #include <dm.h>
 #include <spl.h>
+#include <mapmem.h>
+#include <hang.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -26,6 +28,29 @@
  * Miscellaneous platform dependent initializations
  */
 
+#if CONFIG_IS_ENABLED(LOAD_FIT) || CONFIG_IS_ENABLED(LOAD_FIT_FULL)
+#define ANDES_SPL_FDT_ADDR	(CONFIG_TEXT_BASE - 0x100000)
+void spl_perform_fixups(struct spl_image_info *spl_image)
+{
+	/*
+	 * Originally, u-boot-spl will place DTB directly after the kernel,
+	 * but the size of the kernel did not include the BSS section, which
+	 * means u-boot-spl will place the DTB in the kernel BSS section
+	 * causing the DTB to be cleared by kernel BSS initializtion.
+	 * Moving DTB in front of the kernel can avoid the error.
+	 */
+	if (ANDES_SPL_FDT_ADDR < 0) {
+		printf("%s: CONFIG_TEXT_BASE needs to be larger than 0x100000\n",
+		       __func__);
+		hang();
+	}
+
+	memcpy((void *)ANDES_SPL_FDT_ADDR, spl_image->fdt_addr,
+	       fdt_totalsize(spl_image->fdt_addr));
+	spl_image->fdt_addr = map_sysmem(ANDES_SPL_FDT_ADDR, 0);
+}
+#endif
+
 int board_init(void)
 {
 	gd->bd->bi_boot_params = PHYS_SDRAM_0 + 0x400;
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index c026e1a..70d8d59 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -367,7 +367,8 @@
 	case IH_OS_U_BOOT:
 		return true;
 	case IH_OS_LINUX:
-		return IS_ENABLED(CONFIG_SPL_OS_BOOT);
+		return IS_ENABLED(CONFIG_SPL_OS_BOOT) ||
+		       IS_ENABLED(CONFIG_SPL_OPENSBI);
 	default:
 		return false;
 	}
diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c
index 0df6116..9801d38 100644
--- a/common/spl/spl_opensbi.c
+++ b/common/spl/spl_opensbi.c
@@ -21,7 +21,7 @@
 
 struct fw_dynamic_info opensbi_info;
 
-static int spl_opensbi_find_uboot_node(void *blob, int *uboot_node)
+static int spl_opensbi_find_os_node(void *blob, int *uboot_node, int os_type)
 {
 	int fit_images_node, node;
 	const char *fit_os;
@@ -35,7 +35,7 @@
 		if (!fit_os)
 			continue;
 
-		if (genimg_get_os_id(fit_os) == IH_OS_U_BOOT) {
+		if (genimg_get_os_id(fit_os) == os_type) {
 			*uboot_node = node;
 			return 0;
 		}
@@ -46,8 +46,9 @@
 
 void __noreturn spl_invoke_opensbi(struct spl_image_info *spl_image)
 {
-	int ret, uboot_node;
-	ulong uboot_entry;
+	int ret, os_node;
+	ulong os_entry;
+	int os_type;
 	typedef void __noreturn (*opensbi_entry_t)(ulong hartid, ulong dtb, ulong info);
 	opensbi_entry_t opensbi_entry;
 
@@ -56,22 +57,32 @@
 		hang();
 	}
 
-	/* Find U-Boot image in /fit-images */
-	ret = spl_opensbi_find_uboot_node(spl_image->fdt_addr, &uboot_node);
+	/*
+	 * Find next os image in /fit-images
+	 * The next os image default is u-boot proper, once enable
+	 * OpenSBI OS boot mode, the OS image should be linux.
+	 */
+	if (CONFIG_IS_ENABLED(LOAD_FIT_OPENSBI_OS_BOOT))
+		os_type = IH_OS_LINUX;
+	else
+		os_type = IH_OS_U_BOOT;
+
+	ret = spl_opensbi_find_os_node(spl_image->fdt_addr, &os_node, os_type);
 	if (ret) {
-		pr_err("Can't find U-Boot node, %d\n", ret);
+		pr_err("Can't find %s node for opensbi, %d\n",
+		       genimg_get_os_name(os_type), ret);
 		hang();
 	}
 
 	/* Get U-Boot entry point */
-	ret = fit_image_get_entry(spl_image->fdt_addr, uboot_node, &uboot_entry);
+	ret = fit_image_get_entry(spl_image->fdt_addr, os_node, &os_entry);
 	if (ret)
-		ret = fit_image_get_load(spl_image->fdt_addr, uboot_node, &uboot_entry);
+		ret = fit_image_get_load(spl_image->fdt_addr, os_node, &os_entry);
 
 	/* Prepare opensbi_info object */
 	opensbi_info.magic = FW_DYNAMIC_INFO_MAGIC_VALUE;
 	opensbi_info.version = FW_DYNAMIC_INFO_VERSION;
-	opensbi_info.next_addr = uboot_entry;
+	opensbi_info.next_addr = os_entry;
 	opensbi_info.next_mode = FW_DYNAMIC_INFO_NEXT_MODE_S;
 	opensbi_info.options = CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS;
 	opensbi_info.boot_hart = gd->arch.boot_hart;
diff --git a/configs/ae350_rv32_falcon_defconfig b/configs/ae350_rv32_falcon_defconfig
new file mode 100644
index 0000000..8f796d8
--- /dev/null
+++ b/configs/ae350_rv32_falcon_defconfig
@@ -0,0 +1,60 @@
+CONFIG_RISCV=y
+CONFIG_TEXT_BASE=0x01800000
+CONFIG_SYS_MALLOC_LEN=0x80000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x10000000
+CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_DEFAULT_DEVICE_TREE="ae350_32"
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_SYS_MONITOR_LEN=786432
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000000
+CONFIG_SPL=y
+CONFIG_SYS_LOAD_ADDR=0x100000
+CONFIG_TARGET_ANDES_AE350=y
+CONFIG_RISCV_SMODE=y
+# CONFIG_AVAILABLE_HARTS is not set
+CONFIG_FIT=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000
+CONFIG_SYS_MONITOR_BASE=0x88000000
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTDELAY=3
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SPL_MAX_SIZE=0x100000
+CONFIG_SPL_BSS_START_ADDR=0x400000
+CONFIG_SPL_BOARD_INIT=y
+CONFIG_SPL_CACHE=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_SYS_PBSIZE=1050
+CONFIG_SYS_BOOTM_LEN=0x4000000
+CONFIG_CMD_IMLS=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_BOOTP_PREFER_SERVERIP=y
+CONFIG_CMD_CACHE=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_NET_RETRY_COUNT=50
+CONFIG_BOOTP_SEND_HOSTNAME=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_MMC=y
+CONFIG_FTSDC010=y
+CONFIG_FTSDC010_SDIO=y
+CONFIG_MTD_NOR_FLASH=y
+CONFIG_FLASH_CFI_DRIVER=y
+CONFIG_SYS_FLASH_CFI_WIDTH_16BIT=y
+CONFIG_FLASH_SHOW_PROGRESS=0
+CONFIG_SYS_CFI_FLASH_STATUS_POLL=y
+CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
+CONFIG_SYS_FLASH_CFI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_ATCSPI200_SPI=y
+# CONFIG_BINMAN_FDT is not set
+CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y
\ No newline at end of file
diff --git a/configs/ae350_rv32_falcon_xip_defconfig b/configs/ae350_rv32_falcon_xip_defconfig
new file mode 100644
index 0000000..e01dd6f
--- /dev/null
+++ b/configs/ae350_rv32_falcon_xip_defconfig
@@ -0,0 +1,61 @@
+CONFIG_RISCV=y
+CONFIG_TEXT_BASE=0x01800000
+CONFIG_SYS_MALLOC_LEN=0x80000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x10000000
+CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_DEFAULT_DEVICE_TREE="ae350_32"
+CONFIG_SPL_TEXT_BASE=0x80000000
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_SYS_MONITOR_LEN=786432
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000000
+CONFIG_SPL=y
+CONFIG_SYS_LOAD_ADDR=0x100000
+CONFIG_TARGET_ANDES_AE350=y
+CONFIG_RISCV_SMODE=y
+CONFIG_SPL_XIP=y
+CONFIG_FIT=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x80010000
+CONFIG_SYS_MONITOR_BASE=0x88000000
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTDELAY=3
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SPL_MAX_SIZE=0x100000
+CONFIG_SPL_BSS_START_ADDR=0x400000
+CONFIG_SPL_BOARD_INIT=y
+CONFIG_SPL_CACHE=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_SYS_PBSIZE=1050
+CONFIG_SYS_BOOTM_LEN=0x4000000
+CONFIG_CMD_IMLS=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_BOOTP_PREFER_SERVERIP=y
+CONFIG_CMD_CACHE=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_NET_RETRY_COUNT=50
+CONFIG_BOOTP_SEND_HOSTNAME=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_MMC=y
+CONFIG_FTSDC010=y
+CONFIG_FTSDC010_SDIO=y
+CONFIG_MTD_NOR_FLASH=y
+CONFIG_FLASH_CFI_DRIVER=y
+CONFIG_SYS_FLASH_CFI_WIDTH_16BIT=y
+CONFIG_FLASH_SHOW_PROGRESS=0
+CONFIG_SYS_CFI_FLASH_STATUS_POLL=y
+CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
+CONFIG_SYS_FLASH_CFI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_ATCSPI200_SPI=y
+# CONFIG_BINMAN_FDT is not set
+CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y
\ No newline at end of file
diff --git a/configs/ae350_rv64_falcon_defconfig b/configs/ae350_rv64_falcon_defconfig
new file mode 100644
index 0000000..d11be97
--- /dev/null
+++ b/configs/ae350_rv64_falcon_defconfig
@@ -0,0 +1,60 @@
+CONFIG_RISCV=y
+CONFIG_TEXT_BASE=0x01800000
+CONFIG_SYS_MALLOC_LEN=0x80000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x10000000
+CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_DEFAULT_DEVICE_TREE="ae350_64"
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000000
+CONFIG_SPL=y
+CONFIG_SYS_LOAD_ADDR=0x100000
+CONFIG_TARGET_ANDES_AE350=y
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+# CONFIG_AVAILABLE_HARTS is not set
+CONFIG_FIT=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x10000000
+CONFIG_SYS_MONITOR_BASE=0x88000000
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTDELAY=3
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SPL_MAX_SIZE=0x100000
+CONFIG_SPL_BSS_START_ADDR=0x400000
+CONFIG_SPL_BOARD_INIT=y
+CONFIG_SPL_CACHE=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_SYS_PBSIZE=1050
+CONFIG_SYS_BOOTM_LEN=0x4000000
+CONFIG_CMD_IMLS=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_BOOTP_PREFER_SERVERIP=y
+CONFIG_CMD_CACHE=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_NET_RETRY_COUNT=50
+CONFIG_BOOTP_SEND_HOSTNAME=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_MMC=y
+CONFIG_FTSDC010=y
+CONFIG_FTSDC010_SDIO=y
+CONFIG_MTD_NOR_FLASH=y
+CONFIG_FLASH_CFI_DRIVER=y
+CONFIG_SYS_FLASH_CFI_WIDTH_16BIT=y
+CONFIG_FLASH_SHOW_PROGRESS=0
+CONFIG_SYS_CFI_FLASH_STATUS_POLL=y
+CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
+CONFIG_SYS_FLASH_CFI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_ATCSPI200_SPI=y
+# CONFIG_BINMAN_FDT is not set
+CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y
\ No newline at end of file
diff --git a/configs/ae350_rv64_falcon_xip_defconfig b/configs/ae350_rv64_falcon_xip_defconfig
new file mode 100644
index 0000000..492451e
--- /dev/null
+++ b/configs/ae350_rv64_falcon_xip_defconfig
@@ -0,0 +1,61 @@
+CONFIG_RISCV=y
+CONFIG_TEXT_BASE=0x01800000
+CONFIG_SYS_MALLOC_LEN=0x80000
+CONFIG_NR_DRAM_BANKS=2
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x10000000
+CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_DEFAULT_DEVICE_TREE="ae350_64"
+CONFIG_SPL_TEXT_BASE=0x80000000
+CONFIG_SYS_PROMPT="RISC-V # "
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000000
+CONFIG_SPL=y
+CONFIG_SYS_LOAD_ADDR=0x100000
+CONFIG_TARGET_ANDES_AE350=y
+CONFIG_ARCH_RV64I=y
+CONFIG_RISCV_SMODE=y
+CONFIG_SPL_XIP=y
+CONFIG_FIT=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x80010000
+CONFIG_SYS_MONITOR_BASE=0x88000000
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTDELAY=3
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SPL_MAX_SIZE=0x100000
+CONFIG_SPL_BSS_START_ADDR=0x400000
+CONFIG_SPL_BOARD_INIT=y
+CONFIG_SPL_CACHE=y
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x0
+CONFIG_SYS_PBSIZE=1050
+CONFIG_SYS_BOOTM_LEN=0x4000000
+CONFIG_CMD_IMLS=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_BOOTP_PREFER_SERVERIP=y
+CONFIG_CMD_CACHE=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_NET_RETRY_COUNT=50
+CONFIG_BOOTP_SEND_HOSTNAME=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_MMC=y
+CONFIG_FTSDC010=y
+CONFIG_FTSDC010_SDIO=y
+CONFIG_MTD_NOR_FLASH=y
+CONFIG_FLASH_CFI_DRIVER=y
+CONFIG_SYS_FLASH_CFI_WIDTH_16BIT=y
+CONFIG_FLASH_SHOW_PROGRESS=0
+CONFIG_SYS_CFI_FLASH_STATUS_POLL=y
+CONFIG_SYS_FLASH_USE_BUFFER_WRITE=y
+CONFIG_SYS_FLASH_CFI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_FTMAC100=y
+CONFIG_BAUDRATE=38400
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_ATCSPI200_SPI=y
+# CONFIG_BINMAN_FDT is not set
+CONFIG_SPL_LOAD_FIT_OPENSBI_OS_BOOT=y
\ No newline at end of file
diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig
index 6590727..b21754f 100644
--- a/configs/starfive_visionfive2_defconfig
+++ b/configs/starfive_visionfive2_defconfig
@@ -31,6 +31,7 @@
 # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
 CONFIG_FIT=y
 CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTSTAGE=y
 CONFIG_QSPI_BOOT=y
 CONFIG_SD_BOOT=y
 CONFIG_OF_BOARD_SETUP=y
@@ -72,6 +73,7 @@
 CONFIG_CMD_PCI=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_TFTPPUT=y
+CONFIG_CMD_BOOTSTAGE=y
 CONFIG_OF_BOARD=y
 CONFIG_ENV_OVERWRITE=y
 CONFIG_ENV_IS_NOWHERE=y