Merge https://source.denx.de/u-boot/custodians/u-boot-riscv
diff --git a/Makefile b/Makefile
index 3a6cd15..9615f8b 100644
--- a/Makefile
+++ b/Makefile
@@ -918,6 +918,7 @@
 endif
 INPUTS-$(CONFIG_TPL) += tpl/u-boot-tpl.bin
 INPUTS-$(CONFIG_OF_SEPARATE) += u-boot.dtb
+INPUTS-$(CONFIG_BINMAN_STANDALONE_FDT) += u-boot.dtb
 ifeq ($(CONFIG_SPL_FRAMEWORK),y)
 INPUTS-$(CONFIG_OF_SEPARATE) += u-boot-dtb.img
 endif
@@ -1285,6 +1286,7 @@
 		-I . -I $(srctree) -I $(srctree)/board/$(BOARDDIR) \
 		-I arch/$(ARCH)/dts -a of-list=$(CONFIG_OF_LIST) \
 		-a atf-bl31-path=${BL31} \
+		-a opensbi-path=${OPENSBI} \
 		-a default-dt=$(default_dt) \
 		-a scp-path=$(SCP) \
 		-a spl-bss-pad=$(if $(CONFIG_SPL_SEPARATE_BSS),,1) \
@@ -1389,7 +1391,7 @@
 
 u-boot-dtb.img u-boot.img u-boot.kwb u-boot.pbl u-boot-ivt.img: \
 		$(if $(CONFIG_SPL_LOAD_FIT),u-boot-nodtb.bin \
-			$(if $(CONFIG_OF_SEPARATE)$(CONFIG_OF_EMBED)$(CONFIG_OF_HOSTFILE),dts/dt.dtb) \
+			$(if $(CONFIG_OF_SEPARATE)$(CONFIG_OF_EMBED)$(CONFIG_OF_HOSTFILE)$(CONFIG_BINMAN_STANDALONE_FDT),dts/dt.dtb) \
 		,$(UBOOT_BIN)) FORCE
 	$(call if_changed,mkimage)
 	$(BOARD_SIZE_CHECK)
diff --git a/arch/riscv/cpu/generic/Kconfig b/arch/riscv/cpu/generic/Kconfig
index 6f73bdd..e025134 100644
--- a/arch/riscv/cpu/generic/Kconfig
+++ b/arch/riscv/cpu/generic/Kconfig
@@ -4,6 +4,7 @@
 
 config GENERIC_RISCV
 	bool
+	select BINMAN if SPL
 	select ARCH_EARLY_INIT_R
 	imply CPU
 	imply CPU_RISCV
diff --git a/arch/riscv/dts/Makefile b/arch/riscv/dts/Makefile
index 8138d89..26ef853 100644
--- a/arch/riscv/dts/Makefile
+++ b/arch/riscv/dts/Makefile
@@ -1,9 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0+
 
 dtb-$(CONFIG_TARGET_AX25_AE350) += ae350_32.dtb ae350_64.dtb
+dtb-$(CONFIG_TARGET_MICROCHIP_ICICLE) += microchip-mpfs-icicle-kit.dtb
+dtb-$(CONFIG_TARGET_QEMU_VIRT) += qemu-virt.dtb
 dtb-$(CONFIG_TARGET_SIFIVE_UNLEASHED) += hifive-unleashed-a00.dtb
 dtb-$(CONFIG_TARGET_SIPEED_MAIX) += k210-maix-bit.dtb
-dtb-$(CONFIG_TARGET_MICROCHIP_ICICLE) += microchip-mpfs-icicle-kit.dtb
 
 targets += $(dtb-y)
 
diff --git a/arch/riscv/dts/ae350_32.dts b/arch/riscv/dts/ae350_32.dts
index 3f8525f..a0ab5e9 100644
--- a/arch/riscv/dts/ae350_32.dts
+++ b/arch/riscv/dts/ae350_32.dts
@@ -1,5 +1,7 @@
 /dts-v1/;
 
+#include "binman.dtsi"
+
 / {
 	#address-cells = <1>;
 	#size-cells = <1>;
diff --git a/arch/riscv/dts/ae350_64.dts b/arch/riscv/dts/ae350_64.dts
index 482c707..f654f48 100644
--- a/arch/riscv/dts/ae350_64.dts
+++ b/arch/riscv/dts/ae350_64.dts
@@ -1,5 +1,7 @@
 /dts-v1/;
 
+#include "binman.dtsi"
+
 / {
 	#address-cells = <2>;
 	#size-cells = <2>;
diff --git a/arch/riscv/dts/binman.dtsi b/arch/riscv/dts/binman.dtsi
new file mode 100644
index 0000000..d26cfdb
--- /dev/null
+++ b/arch/riscv/dts/binman.dtsi
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <config.h>
+
+/ {
+	binman: binman {
+		multiple-images;
+	};
+};
+
+&binman {
+	itb {
+		filename = "u-boot.itb";
+
+		fit {
+			description = "Configuration to load OpenSBI before U-Boot";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				uboot {
+					description = "U-Boot";
+					type = "standalone";
+					os = "U-Boot";
+					arch = "riscv";
+					compression = "none";
+					load = <CONFIG_SYS_TEXT_BASE>;
+
+					uboot_blob: blob-ext {
+						filename = "u-boot-nodtb.bin";
+					};
+				};
+
+				opensbi {
+					description = "OpenSBI fw_dynamic Firmware";
+					type = "firmware";
+					os = "opensbi";
+					arch = "riscv";
+					compression = "none";
+					load = <CONFIG_SPL_OPENSBI_LOAD_ADDR>;
+					entry = <CONFIG_SPL_OPENSBI_LOAD_ADDR>;
+
+					opensbi_blob: opensbi {
+						filename = "fw_dynamic.bin";
+					};
+				};
+
+#ifndef CONFIG_OF_PRIOR_STAGE
+				@fdt-SEQ {
+					description = "NAME";
+					type = "flat_dt";
+					compression = "none";
+				};
+#endif
+			};
+
+			configurations {
+				default = "conf-1";
+
+#ifndef CONFIG_OF_PRIOR_STAGE
+				@conf-SEQ {
+#else
+				conf-1 {
+#endif
+					description = "NAME";
+					firmware = "opensbi";
+					loadables = "uboot";
+#ifndef CONFIG_OF_PRIOR_STAGE
+					fdt = "fdt-SEQ";
+#endif
+				};
+			};
+		};
+	};
+};
diff --git a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
index 1996149..51b5661 100644
--- a/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
+++ b/arch/riscv/dts/hifive-unleashed-a00-u-boot.dtsi
@@ -3,6 +3,7 @@
  * Copyright (C) 2019 Jagan Teki <jagan@amarulasolutions.com>
  */
 
+#include "binman.dtsi"
 #include "fu540-c000-u-boot.dtsi"
 #include "fu540-hifive-unleashed-a00-ddr.dtsi"
 
diff --git a/arch/riscv/dts/qemu-virt.dts b/arch/riscv/dts/qemu-virt.dts
new file mode 100644
index 0000000..fecff54
--- /dev/null
+++ b/arch/riscv/dts/qemu-virt.dts
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+/dts-v1/;
+
+#include "binman.dtsi"
diff --git a/arch/riscv/lib/mkimage_fit_opensbi.sh b/arch/riscv/lib/mkimage_fit_opensbi.sh
deleted file mode 100755
index d6f95e5..0000000
--- a/arch/riscv/lib/mkimage_fit_opensbi.sh
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0+
-#
-# script to generate FIT image source for RISC-V boards with OpenSBI
-# and, optionally, multiple device trees (given on the command line).
-#
-# usage: $0 [<dt_name> [<dt_name] ...]
-
-[ -z "$OPENSBI" ] && OPENSBI="fw_dynamic.bin"
-
-if [ -z "$UBOOT_LOAD_ADDR" ]; then
-	UBOOT_LOAD_ADDR="$(grep "^CONFIG_SYS_TEXT_BASE=" .config | awk 'BEGIN{FS="="} {print $2}')"
-fi
-
-if [ -z "$OPENSBI_LOAD_ADDR" ]; then
-	OPENSBI_LOAD_ADDR="$(grep "^CONFIG_SPL_OPENSBI_LOAD_ADDR=" .config | awk 'BEGIN{FS="="} {print $2}')"
-fi
-
-if [ ! -f $OPENSBI ]; then
-	echo "WARNING: OpenSBI binary \"$OPENSBI\" not found, resulting binary is not functional." >&2
-	OPENSBI=/dev/null
-fi
-
-cat << __HEADER_EOF
-/dts-v1/;
-
-/ {
-	description = "Configuration to load OpenSBI before U-Boot";
-
-	images {
-		uboot {
-			description = "U-Boot";
-			data = /incbin/("u-boot-nodtb.bin");
-			type = "standalone";
-			os = "U-Boot";
-			arch = "riscv";
-			compression = "none";
-			load = <$UBOOT_LOAD_ADDR>;
-		};
-		opensbi {
-			description = "RISC-V OpenSBI";
-			data = /incbin/("$OPENSBI");
-			type = "firmware";
-			os = "opensbi";
-			arch = "riscv";
-			compression = "none";
-			load = <$OPENSBI_LOAD_ADDR>;
-			entry = <$OPENSBI_LOAD_ADDR>;
-		};
-__HEADER_EOF
-
-cnt=1
-for dtname in $*
-do
-	cat << __FDT_IMAGE_EOF
-		fdt_$cnt {
-			description = "$(basename $dtname .dtb)";
-			data = /incbin/("$dtname");
-			type = "flat_dt";
-			compression = "none";
-		};
-__FDT_IMAGE_EOF
-cnt=$((cnt+1))
-done
-
-cat << __CONF_HEADER_EOF
-	};
-	configurations {
-		default = "config_1";
-
-__CONF_HEADER_EOF
-
-if [ $# -eq 0 ]; then
-cat << __CONF_SECTION_EOF
-		config_1 {
-			description = "U-Boot FIT";
-			firmware = "opensbi";
-			loadables = "uboot";
-		};
-__CONF_SECTION_EOF
-else
-cnt=1
-for dtname in $*
-do
-cat << __CONF_SECTION_EOF
-		config_$cnt {
-			description = "$(basename $dtname .dtb)";
-			firmware = "opensbi";
-			loadables = "uboot";
-			fdt = "fdt_$cnt";
-		};
-__CONF_SECTION_EOF
-cnt=$((cnt+1))
-done
-fi
-
-cat << __ITS_EOF
-	};
-};
-__ITS_EOF
diff --git a/board/AndesTech/ax25-ae350/Kconfig b/board/AndesTech/ax25-ae350/Kconfig
index 321dd0c..e50f505 100644
--- a/board/AndesTech/ax25-ae350/Kconfig
+++ b/board/AndesTech/ax25-ae350/Kconfig
@@ -31,6 +31,7 @@
 	def_bool y
 	select RISCV_NDS
 	select SUPPORT_SPL
+	select BINMAN if SPL
 	imply SMP
 	imply SPL_RAM_SUPPORT
 	imply SPL_RAM_DEVICE
diff --git a/board/sifive/unleashed/Kconfig b/board/sifive/unleashed/Kconfig
index dbffd59..502916e 100644
--- a/board/sifive/unleashed/Kconfig
+++ b/board/sifive/unleashed/Kconfig
@@ -27,6 +27,7 @@
 	def_bool y
 	select SIFIVE_FU540
 	select ENV_IS_IN_SPI_FLASH
+	select BINMAN
 	imply CMD_DHCP
 	imply CMD_EXT2
 	imply CMD_EXT4
diff --git a/common/Kconfig.boot b/common/Kconfig.boot
index 5660822..3c6e77d 100644
--- a/common/Kconfig.boot
+++ b/common/Kconfig.boot
@@ -205,7 +205,7 @@
 
 	  This path has the following limitations:
 
-	  1. "loadables" images, other than FTDs, which do not have a "load"
+	  1. "loadables" images, other than FDTs, which do not have a "load"
 	     property will not be loaded. This limitation also applies to FPGA
 	     images with the correct "compatible" string.
 	  2. For FPGA images, only the "compatible" = "u-boot,fpga-legacy"
@@ -274,14 +274,13 @@
 
 config USE_SPL_FIT_GENERATOR
 	bool "Use a script to generate the .its script"
-	default y if SPL_FIT && !ARCH_SUNXI
+	default y if SPL_FIT && (!ARCH_SUNXI && !RISCV)
 
 config SPL_FIT_GENERATOR
 	string ".its file generator script for U-Boot FIT image"
 	depends on USE_SPL_FIT_GENERATOR
 	default "arch/arm/mach-rockchip/make_fit_atf.py" if SPL_LOAD_FIT && ARCH_ROCKCHIP
 	default "arch/arm/mach-zynqmp/mkimage_fit_atf.sh" if SPL_LOAD_FIT && ARCH_ZYNQMP
-	default "arch/riscv/lib/mkimage_fit_opensbi.sh" if SPL_LOAD_FIT && RISCV
 	help
 	  Specifies a (platform specific) script file to generate the FIT
 	  source file used to build the U-Boot FIT image file. This gets
diff --git a/configs/ae350_rv32_spl_defconfig b/configs/ae350_rv32_spl_defconfig
index 153266f..e8dc816 100644
--- a/configs/ae350_rv32_spl_defconfig
+++ b/configs/ae350_rv32_spl_defconfig
@@ -2,7 +2,9 @@
 CONFIG_SYS_TEXT_BASE=0x01200000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x100000
 CONFIG_SPL=y
+CONFIG_DEFAULT_DEVICE_TREE="ae350_32"
 CONFIG_TARGET_AX25_AE350=y
 CONFIG_RISCV_SMODE=y
 CONFIG_DISTRO_DEFAULTS=y
diff --git a/configs/ae350_rv32_spl_xip_defconfig b/configs/ae350_rv32_spl_xip_defconfig
index 651b1eb..418170c 100644
--- a/configs/ae350_rv32_spl_xip_defconfig
+++ b/configs/ae350_rv32_spl_xip_defconfig
@@ -2,8 +2,10 @@
 CONFIG_SYS_TEXT_BASE=0x01200000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x100000
 CONFIG_SPL_TEXT_BASE=0x80000000
 CONFIG_SPL=y
+CONFIG_DEFAULT_DEVICE_TREE="ae350_32"
 CONFIG_TARGET_AX25_AE350=y
 CONFIG_RISCV_SMODE=y
 CONFIG_XIP=y
diff --git a/configs/ae350_rv64_spl_defconfig b/configs/ae350_rv64_spl_defconfig
index f434091..d23b56c 100644
--- a/configs/ae350_rv64_spl_defconfig
+++ b/configs/ae350_rv64_spl_defconfig
@@ -2,7 +2,9 @@
 CONFIG_SYS_TEXT_BASE=0x01200000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x100000
 CONFIG_SPL=y
+CONFIG_DEFAULT_DEVICE_TREE="ae350_64"
 CONFIG_TARGET_AX25_AE350=y
 CONFIG_ARCH_RV64I=y
 CONFIG_RISCV_SMODE=y
diff --git a/configs/ae350_rv64_spl_xip_defconfig b/configs/ae350_rv64_spl_xip_defconfig
index b0afdb4..7826ae4 100644
--- a/configs/ae350_rv64_spl_xip_defconfig
+++ b/configs/ae350_rv64_spl_xip_defconfig
@@ -2,8 +2,10 @@
 CONFIG_SYS_TEXT_BASE=0x01200000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_ENV_SECT_SIZE=0x1000
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x100000
 CONFIG_SPL_TEXT_BASE=0x80000000
 CONFIG_SPL=y
+CONFIG_DEFAULT_DEVICE_TREE="ae350_64"
 CONFIG_TARGET_AX25_AE350=y
 CONFIG_ARCH_RV64I=y
 CONFIG_RISCV_SMODE=y
diff --git a/configs/qemu-riscv32_spl_defconfig b/configs/qemu-riscv32_spl_defconfig
index 18dfe33..f30bd5f 100644
--- a/configs/qemu-riscv32_spl_defconfig
+++ b/configs/qemu-riscv32_spl_defconfig
@@ -2,6 +2,7 @@
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x20000
 CONFIG_SPL=y
+CONFIG_DEFAULT_DEVICE_TREE="qemu-virt"
 CONFIG_TARGET_QEMU_VIRT=y
 CONFIG_RISCV_SMODE=y
 CONFIG_DISTRO_DEFAULTS=y
diff --git a/configs/qemu-riscv64_spl_defconfig b/configs/qemu-riscv64_spl_defconfig
index 897adf6..ee91ece 100644
--- a/configs/qemu-riscv64_spl_defconfig
+++ b/configs/qemu-riscv64_spl_defconfig
@@ -2,6 +2,7 @@
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SIZE=0x20000
 CONFIG_SPL=y
+CONFIG_DEFAULT_DEVICE_TREE="qemu-virt"
 CONFIG_TARGET_QEMU_VIRT=y
 CONFIG_ARCH_RV64I=y
 CONFIG_RISCV_SMODE=y
diff --git a/dts/Kconfig b/dts/Kconfig
index 99ce75e..dabe008 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -19,6 +19,24 @@
 	bool
 	select DTOC
 
+config BINMAN_STANDALONE_FDT
+	bool
+	depends on BINMAN
+	default y if OF_BOARD || OF_PRIOR_STAGE
+	help
+	  This option tells U-Boot build system that a standalone device tree
+	  source is explicitly required when using binman to package U-Boot.
+
+	  This is not necessary in a common scenario where a device tree source
+	  that contains the binman node is provided in the arch/<arch>/dts
+	  directory for a specific board. Such device tree sources are built for
+	  OF_SEPARATE or OF_EMBED. However for a scenario like the board device
+	  tree blob is not provided in the U-Boot build tree, but fed to U-Boot
+	  in the runtime, e.g.: in the OF_PRIOR_STAGE case that it is passed by
+	  a prior stage bootloader. For such scenario, a standalone device tree
+	  blob containing binman node to describe how to package U-Boot should
+	  be provided explicitly.
+
 menu "Device Tree Control"
 	depends on SUPPORT_OF_CONTROL
 
diff --git a/lib/Kconfig b/lib/Kconfig
index b057b9d..d675ab1 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -25,7 +25,7 @@
 config BINMAN_FDT
 	bool "Allow access to binman information in the device tree"
 	depends on BINMAN && DM && OF_CONTROL
-	default y
+	default y if OF_SEPARATE || OF_EMBED
 	help
 	  This enables U-Boot to access information about binman entries,
 	  stored in the device tree in a binman node. Typical uses are to
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 1aa2459..bc635aa 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -232,6 +232,30 @@
 inclusion' below.
 
 
+Using binman with OF_BOARD or OF_PRIOR_STAGE
+--------------------------------------------
+
+Normally binman is used with a board configured with OF_SEPARATE or OF_EMBED.
+This is a typical scenario where a device tree source that contains the binman
+node is provided in the arch/<arch>/dts directory for a specific board.
+
+However for a board configured with OF_BOARD or OF_PRIOR_STAGE, no device tree
+blob is provided in the U-Boot build phase hence the binman node information
+is not available. In order to support such use case, a new Kconfig option
+BINMAN_STANDALONE_FDT is introduced, to tell the build system that a standalone
+device tree blob containing binman node is explicitly required.
+
+Note there is a Kconfig option BINMAN_FDT which enables U-Boot run time to
+access information about binman entries, stored in the device tree in a binman
+node. Generally speaking, this option makes sense for OF_SEPARATE or OF_EMBED.
+For the other OF_CONTROL methods, it's quite possible binman node is not
+available as binman is invoked during the build phase, thus this option is not
+turned on by default for these OF_CONTROL methods.
+
+See qemu-riscv64_spl_defconfig for an example of how binman is used with
+OF_PRIOR_STAGE to generate u-boot.itb image.
+
+
 Access to binman entry offsets at run time (symbols)
 ----------------------------------------------------
 
@@ -322,9 +346,9 @@
 command line. For example some entries need access to files and it is not
 always convenient to put these filenames in the image definition (device tree).
 
-The-a option supports this::
+The -a option supports this::
 
-    -a<prop>=<value>
+    -a <prop>=<value>
 
 where::
 
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index f1c3b7d..dcac700 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -761,6 +761,19 @@
 
 
 
+Entry: opensbi: RISC-V OpenSBI fw_dynamic blob
+----------------------------------------------
+
+Properties / Entry arguments:
+    - opensbi-path: Filename of file to read into entry. This is typically
+        called fw_dynamic.bin
+
+This entry holds the run-time firmware, typically started by U-Boot SPL.
+See the U-Boot README for your architecture or board for how to use it. See
+https://github.com/riscv/opensbi for more information about OpenSBI.
+
+
+
 Entry: powerpc-mpc85xx-bootpg-resetvec: PowerPC mpc85xx bootpg + resetvec code for U-Boot
 -----------------------------------------------------------------------------------------
 
diff --git a/tools/binman/etype/atf_bl31.py b/tools/binman/etype/atf_bl31.py
index 163d714..2041da4 100644
--- a/tools/binman/etype/atf_bl31.py
+++ b/tools/binman/etype/atf_bl31.py
@@ -2,7 +2,7 @@
 # Copyright 2020 Google LLC
 # Written by Simon Glass <sjg@chromium.org>
 #
-# Entry-type module for Intel Management Engine binary blob
+# Entry-type module for ARM Trusted Firmware binary blob
 #
 
 from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg
diff --git a/tools/binman/etype/opensbi.py b/tools/binman/etype/opensbi.py
new file mode 100644
index 0000000..74d473d
--- /dev/null
+++ b/tools/binman/etype/opensbi.py
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2021, Bin Meng <bmeng.cn@gmail.com>
+#
+# Entry-type module for RISC-V OpenSBI binary blob
+#
+
+from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg
+
+class Entry_opensbi(Entry_blob_named_by_arg):
+    """RISC-V OpenSBI fw_dynamic blob
+
+    Properties / Entry arguments:
+        - opensbi-path: Filename of file to read into entry. This is typically
+            called fw_dynamic.bin
+
+    This entry holds the run-time firmware, typically started by U-Boot SPL.
+    See the U-Boot README for your architecture or board for how to use it. See
+    https://github.com/riscv/opensbi for more information about OpenSBI.
+    """
+    def __init__(self, section, etype, node):
+        super().__init__(section, etype, node, 'opensbi')
+        self.external = True
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index f36823f..5383eec 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -76,6 +76,7 @@
 FSP_S_DATA            = b'fsp_s'
 FSP_T_DATA            = b'fsp_t'
 ATF_BL31_DATA         = b'bl31'
+OPENSBI_DATA          = b'opensbi'
 SCP_DATA              = b'scp'
 TEST_FDT1_DATA        = b'fdt1'
 TEST_FDT2_DATA        = b'test-fdt2'
@@ -178,6 +179,7 @@
         TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
         TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
         TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
+        TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
         TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
 
         # Add a few .dtb files for testing
@@ -3826,7 +3828,7 @@
             'default-dt': 'test-fdt2',
         }
         data = self._DoReadFileDtb(
-            '172_fit_fdt.dts',
+            '170_fit_fdt.dts',
             entry_args=entry_args,
             extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
         self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
@@ -3848,7 +3850,7 @@
     def testFitFdtMissingList(self):
         """Test handling of a missing 'of-list' entry arg"""
         with self.assertRaises(ValueError) as e:
-            self._DoReadFile('172_fit_fdt.dts')
+            self._DoReadFile('170_fit_fdt.dts')
         self.assertIn("Generator node requires 'of-list' entry argument",
                       str(e.exception))
 
@@ -3871,7 +3873,7 @@
         entry_args = {
             'of-list': '',
         }
-        data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
+        data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
 
     def testFitFdtMissing(self):
         """Test handling of a missing 'default-dt' entry arg"""
@@ -3880,7 +3882,7 @@
         }
         with self.assertRaises(ValueError) as e:
             self._DoReadFileDtb(
-                '172_fit_fdt.dts',
+                '170_fit_fdt.dts',
                 entry_args=entry_args,
                 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
         self.assertIn("Generated 'default' node requires default-dt entry argument",
@@ -3894,7 +3896,7 @@
         }
         with self.assertRaises(ValueError) as e:
             self._DoReadFileDtb(
-                '172_fit_fdt.dts',
+                '170_fit_fdt.dts',
                 entry_args=entry_args,
                 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
         self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
@@ -4535,5 +4537,10 @@
         expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
         self.assertEqual(expected, data)
 
+    def testPackOpenSBI(self):
+        """Test that an image with an OpenSBI binary can be created"""
+        data = self._DoReadFile('201_opensbi.dts')
+        self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/172_fit_fdt.dts b/tools/binman/test/170_fit_fdt.dts
similarity index 100%
rename from tools/binman/test/172_fit_fdt.dts
rename to tools/binman/test/170_fit_fdt.dts
diff --git a/tools/binman/test/201_opensbi.dts b/tools/binman/test/201_opensbi.dts
new file mode 100644
index 0000000..942183f
--- /dev/null
+++ b/tools/binman/test/201_opensbi.dts
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		opensbi {
+			filename = "fw_dynamic.bin";
+		};
+	};
+};