Merge tag 'dm-pull-18jan23' of https://source.denx.de/u-boot/custodians/u-boot-dm

convert rockchip to use binman
patman fix for checkpatch
binman optional entries, improved support for ELF symbols
trace improvements
minor fdt refactoring
diff --git a/.gitignore b/.gitignore
index eb769f1..3adf1fa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 # Normal rules (sorted alphabetically)
 #
 .*
+!.checkpatch.conf
 *.a
 *.asn1.[ch]
 *.bin
diff --git a/Makefile b/Makefile
index a4a14d5..eb354c0 100644
--- a/Makefile
+++ b/Makefile
@@ -1006,14 +1006,9 @@
 INPUTS-y += init_sp_bss_offset_check
 endif
 
-ifeq ($(CONFIG_ARCH_ROCKCHIP)$(CONFIG_SPL),yy)
-# Binman image dependencies
-ifeq ($(CONFIG_ARM64),y)
-INPUTS-y += u-boot.itb
-else
+ifeq ($(CONFIG_ARCH_ROCKCHIP)_$(CONFIG_SPL_FRAMEWORK),y_)
 INPUTS-y += u-boot.img
 endif
-endif
 
 INPUTS-$(CONFIG_X86) += u-boot-x86-start16.bin u-boot-x86-reset16.bin \
 	$(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \
@@ -1370,9 +1365,6 @@
 else
 ifneq ($(CONFIG_USE_SPL_FIT_GENERATOR),)
 U_BOOT_ITS := u-boot.its
-ifeq ($(CONFIG_SPL_FIT_GENERATOR),"arch/arm/mach-rockchip/make_fit_atf.py")
-U_BOOT_ITS_DEPS += u-boot
-endif
 $(U_BOOT_ITS): $(U_BOOT_ITS_DEPS) FORCE
 	$(srctree)/$(CONFIG_SPL_FIT_GENERATOR) \
 	$(patsubst %,arch/$(ARCH)/dts/%.dtb,$(subst ",,$(CONFIG_OF_LIST))) > $@
@@ -1477,7 +1469,6 @@
 u-boot-with-spl.bin: $(SPL_IMAGE) $(SPL_PAYLOAD) FORCE
 	$(call if_changed,pad_cat)
 
-
 ifeq ($(CONFIG_ARCH_LPC32XX)$(CONFIG_SPL),yy)
 MKIMAGEFLAGS_lpc32xx-spl.img = -T lpc32xximage -a $(CONFIG_SPL_TEXT_BASE)
 
diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c
index f4a045e..9d981cc 100644
--- a/arch/arm/cpu/armv7/s5p-common/timer.c
+++ b/arch/arm/cpu/armv7/s5p-common/timer.c
@@ -82,7 +82,7 @@
 	return time_ms - base;
 }
 
-unsigned long __attribute__((no_instrument_function)) timer_get_us(void)
+unsigned long notrace timer_get_us(void)
 {
 	static unsigned long base_time_us;
 
diff --git a/arch/arm/cpu/armv8/generic_timer.c b/arch/arm/cpu/armv8/generic_timer.c
index f27a74b..8f83372 100644
--- a/arch/arm/cpu/armv8/generic_timer.c
+++ b/arch/arm/cpu/armv8/generic_timer.c
@@ -17,7 +17,7 @@
 /*
  * Generic timer implementation of get_tbclk()
  */
-unsigned long get_tbclk(void)
+unsigned long notrace get_tbclk(void)
 {
 	unsigned long cntfrq;
 	asm volatile("mrs %0, cntfrq_el0" : "=r" (cntfrq));
@@ -78,7 +78,7 @@
 /*
  * timer_read_counter() using the Arm Generic Timer (aka arch timer).
  */
-unsigned long timer_read_counter(void)
+unsigned long notrace timer_read_counter(void)
 {
 	unsigned long cntpct;
 
@@ -89,7 +89,7 @@
 }
 #endif
 
-uint64_t get_ticks(void)
+uint64_t notrace get_ticks(void)
 {
 	unsigned long ticks = timer_read_counter();
 
diff --git a/arch/arm/dts/px30-ringneck-haikou-u-boot.dtsi b/arch/arm/dts/px30-ringneck-haikou-u-boot.dtsi
index e8a34c7..1325e0c 100644
--- a/arch/arm/dts/px30-ringneck-haikou-u-boot.dtsi
+++ b/arch/arm/dts/px30-ringneck-haikou-u-boot.dtsi
@@ -17,7 +17,7 @@
 
 &binman {
 	simple-bin {
-		blob {
+		fit {
 			offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
 		};
 	};
diff --git a/arch/arm/dts/rk3399-puma-haikou-u-boot.dtsi b/arch/arm/dts/rk3399-puma-haikou-u-boot.dtsi
index d2349ae..088861d 100644
--- a/arch/arm/dts/rk3399-puma-haikou-u-boot.dtsi
+++ b/arch/arm/dts/rk3399-puma-haikou-u-boot.dtsi
@@ -46,14 +46,14 @@
 
 &binman {
 	simple-bin {
-		blob {
+		fit {
 			offset = <((CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR - 64) * 512)>;
 		};
 	};
 
 #ifdef CONFIG_ROCKCHIP_SPI_IMAGE
 	simple-bin-spi {
-		blob {
+		fit {
 			/* same as u-boot,spl-payload-offset */
 			offset = <0x80000>;
 		};
diff --git a/arch/arm/dts/rk3399-u-boot.dtsi b/arch/arm/dts/rk3399-u-boot.dtsi
index 3c1a15f..8a0b180 100644
--- a/arch/arm/dts/rk3399-u-boot.dtsi
+++ b/arch/arm/dts/rk3399-u-boot.dtsi
@@ -62,6 +62,7 @@
 
 #if defined(CONFIG_ROCKCHIP_SPI_IMAGE) && defined(CONFIG_HAS_ROM)
 &binman {
+	multiple-images;
 	rom {
 		filename = "u-boot.rom";
 		size = <0x400000>;
@@ -82,7 +83,7 @@
 		};
 	};
 };
-#endif
+#endif /* CONFIG_ROCKCHIP_SPI_IMAGE && CONFIG_HAS_ROM */
 
 &cru {
 	u-boot,dm-pre-reloc;
diff --git a/arch/arm/dts/rockchip-u-boot.dtsi b/arch/arm/dts/rockchip-u-boot.dtsi
index fa094b0..234fc5d 100644
--- a/arch/arm/dts/rockchip-u-boot.dtsi
+++ b/arch/arm/dts/rockchip-u-boot.dtsi
@@ -30,14 +30,79 @@
 			};
 		};
 
-#ifdef CONFIG_ARM64
-		blob {
+#if defined(CONFIG_SPL_FIT) && defined(CONFIG_ARM64)
+		fit: fit {
+			description = "FIT image for U-Boot with bl31 (TF-A)";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
 			filename = "u-boot.itb";
+			fit,external-offset = <CONFIG_FIT_EXTERNAL_OFFSET>;
+			offset = <CONFIG_SPL_PAD_TO>;
+			images {
+				u-boot {
+					description = "U-Boot (64-bit)";
+					type = "standalone";
+					os = "U-Boot";
+					arch = "arm64";
+					compression = "none";
+					load = <CONFIG_TEXT_BASE>;
+					entry = <CONFIG_TEXT_BASE>;
+					u-boot-nodtb {
+					};
+				};
+
+				@atf-SEQ {
+					fit,operation = "split-elf";
+					description = "ARM Trusted Firmware";
+					type = "firmware";
+					arch = "arm64";
+					os = "arm-trusted-firmware";
+					compression = "none";
+					fit,load;
+					fit,entry;
+					fit,data;
+
+					atf-bl31 {
+					};
+				};
+				@tee-SEQ {
+					fit,operation = "split-elf";
+					description = "TEE";
+					type = "tee";
+					arch = "arm64";
+					os = "tee";
+					compression = "none";
+					fit,load;
+					fit,entry;
+					fit,data;
+
+					tee-os {
+						optional;
+					};
+				};
+
+				@fdt-SEQ {
+					description = "fdt-NAME";
+					compression = "none";
+					type = "flat_dt";
+				};
+			};
+
+			configurations {
+				default = "@config-DEFAULT-SEQ";
+				@config-SEQ {
+					description = "NAME.dtb";
+					fdt = "fdt-SEQ";
+					firmware = "u-boot";
+					fit,loadables;
+				};
+			};
+		};
 #else
 		u-boot-img {
-#endif
 			offset = <CONFIG_SPL_PAD_TO>;
 		};
+#endif
 	};
 
 #ifdef CONFIG_ROCKCHIP_SPI_IMAGE
@@ -59,7 +124,8 @@
 		};
 
 #ifdef CONFIG_ARM64
-		blob {
+		fit {
+			type = "blob";
 			filename = "u-boot.itb";
 #else
 		u-boot-img {
@@ -68,6 +134,6 @@
 			offset = <CONFIG_SYS_SPI_U_BOOT_OFFS>;
 		};
 	};
-#endif
+#endif /* CONFIG_ROCKCHIP_SPI_IMAGE */
 };
-#endif
+#endif /* CONFIG_SPL */
diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h
index fb5fdaf..dab148e 100644
--- a/arch/arm/mach-exynos/include/mach/cpu.h
+++ b/arch/arm/mach-exynos/include/mach/cpu.h
@@ -248,7 +248,7 @@
 }
 
 #define IS_SAMSUNG_TYPE(type, id)			\
-static inline int __attribute__((no_instrument_function)) cpu_is_##type(void) \
+static inline int notrace cpu_is_##type(void)		\
 {							\
 	return (s5p_cpu_id >> 12) == id;		\
 }
@@ -257,7 +257,7 @@
 IS_SAMSUNG_TYPE(exynos5, 0x5)
 
 #define IS_EXYNOS_TYPE(type, id)			\
-static inline int __attribute__((no_instrument_function)) \
+static inline int notrace				\
 	proid_is_##type(void)				\
 {							\
 	return s5p_cpu_id == id;			\
@@ -272,7 +272,7 @@
 #define proid_is_exynos542x() (proid_is_exynos5420() || proid_is_exynos5422())
 
 #define SAMSUNG_BASE(device, base)				\
-static inline unsigned long __attribute__((no_instrument_function)) \
+static inline unsigned long notrace				\
 	samsung_get_base_##device(void) \
 {								\
 	if (cpu_is_exynos4()) {				\
diff --git a/arch/arm/mach-rockchip/make_fit_atf.py b/arch/arm/mach-rockchip/make_fit_atf.py
deleted file mode 100755
index 08cfe9f..0000000
--- a/arch/arm/mach-rockchip/make_fit_atf.py
+++ /dev/null
@@ -1,267 +0,0 @@
-#!/usr/bin/env python3
-"""
-# SPDX-License-Identifier: GPL-2.0+
-#
-# A script to generate FIT image source for rockchip boards
-# with ARM Trusted Firmware
-# and multiple device trees (given on the command line)
-#
-# usage: $0 <dt_name> [<dt_name> [<dt_name] ...]
-"""
-
-import os
-import sys
-import getopt
-import logging
-import struct
-
-DT_HEADER = """
-/*
- * This is a generated file.
- */
-/dts-v1/;
-
-/ {
-	description = "FIT image for U-Boot with bl31 (TF-A)";
-	#address-cells = <1>;
-
-	images {
-"""
-
-DT_UBOOT = """
-		uboot {
-			description = "U-Boot (64-bit)";
-			data = /incbin/("u-boot-nodtb.bin");
-			type = "standalone";
-			os = "U-Boot";
-			arch = "arm64";
-			compression = "none";
-			load = <0x%08x>;
-		};
-
-"""
-
-DT_IMAGES_NODE_END = """	};
-
-"""
-
-DT_END = "};"
-
-def append_bl31_node(file, atf_index, phy_addr, elf_entry):
-    # Append BL31 DT node to input FIT dts file.
-    data = 'bl31_0x%08x.bin' % phy_addr
-    file.write('\t\tatf_%d {\n' % atf_index)
-    file.write('\t\t\tdescription = \"ARM Trusted Firmware\";\n')
-    file.write('\t\t\tdata = /incbin/("%s");\n' % data)
-    file.write('\t\t\ttype = "firmware";\n')
-    file.write('\t\t\tarch = "arm64";\n')
-    file.write('\t\t\tos = "arm-trusted-firmware";\n')
-    file.write('\t\t\tcompression = "none";\n')
-    file.write('\t\t\tload = <0x%08x>;\n' % phy_addr)
-    if atf_index == 1:
-        file.write('\t\t\tentry = <0x%08x>;\n' % elf_entry)
-    file.write('\t\t};\n')
-    file.write('\n')
-
-def append_tee_node(file, atf_index, phy_addr, elf_entry):
-    # Append TEE DT node to input FIT dts file.
-    data = 'tee_0x%08x.bin' % phy_addr
-    file.write('\t\tatf_%d {\n' % atf_index)
-    file.write('\t\t\tdescription = \"TEE\";\n')
-    file.write('\t\t\tdata = /incbin/("%s");\n' % data)
-    file.write('\t\t\ttype = "tee";\n')
-    file.write('\t\t\tarch = "arm64";\n')
-    file.write('\t\t\tos = "tee";\n')
-    file.write('\t\t\tcompression = "none";\n')
-    file.write('\t\t\tload = <0x%08x>;\n' % phy_addr)
-    file.write('\t\t\tentry = <0x%08x>;\n' % elf_entry)
-    file.write('\t\t};\n')
-    file.write('\n')
-
-def append_fdt_node(file, dtbs):
-    # Append FDT nodes.
-    cnt = 1
-    for dtb in dtbs:
-        dtname = os.path.basename(dtb)
-        file.write('\t\tfdt_%d {\n' % cnt)
-        file.write('\t\t\tdescription = "%s";\n' % dtname)
-        file.write('\t\t\tdata = /incbin/("%s");\n' % dtb)
-        file.write('\t\t\ttype = "flat_dt";\n')
-        file.write('\t\t\tcompression = "none";\n')
-        file.write('\t\t};\n')
-        file.write('\n')
-        cnt = cnt + 1
-
-def append_conf_section(file, cnt, dtname, segments):
-    file.write('\t\tconfig_%d {\n' % cnt)
-    file.write('\t\t\tdescription = "%s";\n' % dtname)
-    file.write('\t\t\tfirmware = "atf_1";\n')
-    file.write('\t\t\tloadables = "uboot"')
-    if segments > 1:
-        file.write(',')
-    for i in range(1, segments):
-        file.write('"atf_%d"' % (i + 1))
-        if i != (segments - 1):
-            file.write(',')
-        else:
-            file.write(';\n')
-    if segments <= 1:
-        file.write(';\n')
-    file.write('\t\t\tfdt = "fdt_%d";\n' % cnt)
-    file.write('\t\t};\n')
-    file.write('\n')
-
-def append_conf_node(file, dtbs, segments):
-    # Append configeration nodes.
-    cnt = 1
-    file.write('\tconfigurations {\n')
-    file.write('\t\tdefault = "config_1";\n')
-    for dtb in dtbs:
-        dtname = os.path.basename(dtb)
-        append_conf_section(file, cnt, dtname, segments)
-        cnt = cnt + 1
-    file.write('\t};\n')
-    file.write('\n')
-
-def generate_atf_fit_dts_uboot(fit_file, uboot_file_name):
-    segments = unpack_elf(uboot_file_name)
-    if len(segments) != 1:
-        raise ValueError("Invalid u-boot ELF image '%s'" % uboot_file_name)
-    index, entry, p_paddr, data = segments[0]
-    fit_file.write(DT_UBOOT % p_paddr)
-
-def generate_atf_fit_dts_bl31(fit_file, bl31_file_name, tee_file_name, dtbs_file_name):
-    segments = unpack_elf(bl31_file_name)
-    for index, entry, paddr, data in segments:
-        append_bl31_node(fit_file, index + 1, paddr, entry)
-    num_segments = len(segments)
-
-    if tee_file_name:
-        tee_segments = unpack_tee_file(tee_file_name)
-        for index, entry, paddr, data in tee_segments:
-            append_tee_node(fit_file, num_segments + index + 1, paddr, entry)
-        num_segments = num_segments + len(tee_segments)
-
-    append_fdt_node(fit_file, dtbs_file_name)
-    fit_file.write(DT_IMAGES_NODE_END)
-    append_conf_node(fit_file, dtbs_file_name, num_segments)
-
-def generate_atf_fit_dts(fit_file_name, bl31_file_name, tee_file_name, uboot_file_name, dtbs_file_name):
-    # Generate FIT script for ATF image.
-    if fit_file_name != sys.stdout:
-        fit_file = open(fit_file_name, "wb")
-    else:
-        fit_file = sys.stdout
-
-    fit_file.write(DT_HEADER)
-    generate_atf_fit_dts_uboot(fit_file, uboot_file_name)
-    generate_atf_fit_dts_bl31(fit_file, bl31_file_name, tee_file_name, dtbs_file_name)
-    fit_file.write(DT_END)
-
-    if fit_file_name != sys.stdout:
-        fit_file.close()
-
-def generate_atf_binary(bl31_file_name):
-    for index, entry, paddr, data in unpack_elf(bl31_file_name):
-        file_name = 'bl31_0x%08x.bin' % paddr
-        with open(file_name, "wb") as atf:
-            atf.write(data)
-
-def generate_tee_binary(tee_file_name):
-    if tee_file_name:
-        for index, entry, paddr, data in unpack_tee_file(tee_file_name):
-            file_name = 'tee_0x%08x.bin' % paddr
-            with open(file_name, "wb") as atf:
-                atf.write(data)
-
-def unpack_elf(filename):
-    with open(filename, 'rb') as file:
-        elf = file.read()
-    if elf[0:7] != b'\x7fELF\x02\x01\x01' or elf[18:20] != b'\xb7\x00':
-        raise ValueError("Invalid arm64 ELF file '%s'" % filename)
-
-    e_entry, e_phoff = struct.unpack_from('<2Q', elf, 0x18)
-    e_phentsize, e_phnum = struct.unpack_from('<2H', elf, 0x36)
-    segments = []
-
-    for index in range(e_phnum):
-        offset = e_phoff + e_phentsize * index
-        p_type, p_flags, p_offset = struct.unpack_from('<LLQ', elf, offset)
-        if p_type == 1: # PT_LOAD
-            p_paddr, p_filesz = struct.unpack_from('<2Q', elf, offset + 0x18)
-            if p_filesz > 0:
-                p_data = elf[p_offset:p_offset + p_filesz]
-                segments.append((index, e_entry, p_paddr, p_data))
-    return segments
-
-def unpack_tee_file(filename):
-    if filename.endswith('.elf'):
-        return unpack_elf(filename)
-    with open(filename, 'rb') as file:
-        bin = file.read()
-    segments = []
-    if bin[0:5] == b'OPTE\x01':
-        # OP-TEE v1 format (tee.bin)
-        init_sz, start_hi, start_lo, _, paged_sz = struct.unpack_from('<5I',
-                                                                      bin,
-                                                                      0x8)
-        if paged_sz != 0:
-            raise ValueError("OP-TEE paged mode not supported")
-        e_entry = (start_hi << 32) + start_lo
-        p_addr = e_entry
-        p_data = bin[0x1c:]
-        if len(p_data) != init_sz:
-            raise ValueError("Invalid file '%s': size mismatch "
-                             "(expected %d, have %d)" % (filename, init_sz,
-                                                         len(p_data)))
-        segments.append((0, e_entry, p_addr, p_data))
-    else:
-        raise ValueError("Unknown format for TEE file '%s'" % filename)
-    return segments
-
-def main():
-    uboot_elf = "./u-boot"
-    fit_its = sys.stdout
-    if "BL31" in os.environ:
-        bl31_elf=os.getenv("BL31");
-    elif os.path.isfile("./bl31.elf"):
-        bl31_elf = "./bl31.elf"
-    else:
-        os.system("echo 'int main(){}' > bl31.c")
-        os.system("${CROSS_COMPILE}gcc -c bl31.c -o bl31.elf")
-        bl31_elf = "./bl31.elf"
-        logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
-        logging.warning(' BL31 file bl31.elf NOT found, resulting binary is non-functional')
-        logging.warning(' Please read Building section in doc/README.rockchip')
-
-    if "TEE" in os.environ:
-        tee_file = os.getenv("TEE")
-    elif os.path.isfile("./tee.bin"):
-        tee_file = "./tee.bin"
-    elif os.path.isfile("./tee.elf"):
-        tee_file = "./tee.elf"
-    else:
-        tee_file = ""
-
-    opts, args = getopt.getopt(sys.argv[1:], "o:u:b:t:h")
-    for opt, val in opts:
-        if opt == "-o":
-            fit_its = val
-        elif opt == "-u":
-            uboot_elf = val
-        elif opt == "-b":
-            bl31_elf = val
-        elif opt == "-t":
-            tee_file = val
-        elif opt == "-h":
-            print(__doc__)
-            sys.exit(2)
-
-    dtbs = args
-
-    generate_atf_fit_dts(fit_its, bl31_elf, tee_file, uboot_elf, dtbs)
-    generate_atf_binary(bl31_elf)
-    generate_tee_binary(tee_file)
-
-if __name__ == "__main__":
-    main()
diff --git a/arch/arm/mach-rockchip/tpl.c b/arch/arm/mach-rockchip/tpl.c
index ed46a9a..fdd0c59 100644
--- a/arch/arm/mach-rockchip/tpl.c
+++ b/arch/arm/mach-rockchip/tpl.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <bootstage.h>
 #include <debug_uart.h>
 #include <dm.h>
 #include <hang.h>
@@ -70,15 +71,15 @@
 				U_BOOT_TIME ")\n");
 #endif
 #endif
+	/* Init secure timer */
+	rockchip_stimer_init();
+
 	ret = spl_early_init();
 	if (ret) {
 		debug("spl_early_init() failed: %d\n", ret);
 		hang();
 	}
 
-	/* Init secure timer */
-	rockchip_stimer_init();
-
 	/* Init ARM arch timer */
 	if (IS_ENABLED(CONFIG_SYS_ARCH_TIMER))
 		timer_init();
@@ -93,6 +94,15 @@
 int board_return_to_bootrom(struct spl_image_info *spl_image,
 			    struct spl_boot_device *bootdev)
 {
+#ifdef CONFIG_BOOTSTAGE_STASH
+	int ret;
+
+	bootstage_mark_name(BOOTSTAGE_ID_END_TPL, "end tpl");
+	ret = bootstage_stash((void *)CONFIG_BOOTSTAGE_STASH_ADDR,
+			      CONFIG_BOOTSTAGE_STASH_SIZE);
+	if (ret)
+		debug("Failed to stash bootstage: err=%d\n", ret);
+#endif
 	back_to_bootrom(BROM_BOOT_NEXTSTAGE);
 
 	return 0;
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 23693f8..22d103d 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -137,7 +137,7 @@
 
 #define DECLARE_GLOBAL_DATA_PTR   extern struct global_data *global_data_ptr
 # else
-static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void)
+static inline notrace gd_t *get_fs_gd_ptr(void)
 {
 	gd_t *gd_ptr;
 
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 3e613de..27764fc 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -71,7 +71,7 @@
 #define EAX_EDX_RET(val, low, high)	"=A" (val)
 #endif
 
-static inline __attribute__((no_instrument_function))
+static inline notrace
 	unsigned long long native_read_msr(unsigned int msr)
 {
 	DECLARE_ARGS(val, low, high);
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index 4cf41e9..8f38c2d 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -108,7 +108,7 @@
 int arch_misc_init(void);
 
 /* Read the time stamp counter */
-static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void)
+static inline notrace uint64_t rdtsc(void)
 {
 	uint32_t high, low;
 	__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
diff --git a/boot/Kconfig b/boot/Kconfig
index 48fa15e..fdcfbae 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -282,12 +282,11 @@
 config USE_SPL_FIT_GENERATOR
 	bool "Use a script to generate the .its script"
 	depends on SPL_FIT
-	default y if !ARCH_SUNXI && !RISCV
+	default y if SPL_FIT && ARCH_ZYNQMP
 
 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
 	help
 	  Specifies a (platform specific) script file to generate the FIT
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 08da7fe..0e026bb 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -599,6 +599,7 @@
 			debug("Ignoring compatible = %s property\n",
 			      compatible);
 	}
+	return 0;
 
 	ret = fpga_load(devnum, (void *)fpga_image->load_addr,
 			fpga_image->size, BIT_FULL, flags);
diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig
index fe3346f..ad46a74 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -179,3 +179,4 @@
 CONFIG_USB_GADGET_PRODUCT_NUM=0x6162
 CONFIG_USB_GADGET_DOWNLOAD=y
 CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_PHANDLE_CHECK_SEQ=y
diff --git a/configs/evb-ast2600_defconfig b/configs/evb-ast2600_defconfig
index 2fac79b..3440062 100644
--- a/configs/evb-ast2600_defconfig
+++ b/configs/evb-ast2600_defconfig
@@ -120,3 +120,4 @@
 CONFIG_SHA384=y
 CONFIG_HEXDUMP=y
 # CONFIG_EFI_LOADER is not set
+CONFIG_PHANDLE_CHECK_SEQ=y
diff --git a/configs/evb-rk3288_defconfig b/configs/evb-rk3288_defconfig
index fcfb6aa..5c6b1d5 100644
--- a/configs/evb-rk3288_defconfig
+++ b/configs/evb-rk3288_defconfig
@@ -29,6 +29,7 @@
 CONFIG_DISPLAY_BOARDINFO_LATE=y
 CONFIG_SPL_PAD_TO=0x7f8000
 CONFIG_SPL_NO_BSS_LIMIT=y
+# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
 # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
 CONFIG_SPL_STACK=0xff718000
 CONFIG_SPL_STACK_R=y
diff --git a/configs/rockpro64-rk3399_defconfig b/configs/rockpro64-rk3399_defconfig
index 6422b9f..3b4820c 100644
--- a/configs/rockpro64-rk3399_defconfig
+++ b/configs/rockpro64-rk3399_defconfig
@@ -9,6 +9,7 @@
 CONFIG_DEFAULT_DEVICE_TREE="rk3399-rockpro64"
 CONFIG_ROCKCHIP_RK3399=y
 CONFIG_TARGET_ROCKPRO64_RK3399=y
+CONFIG_BOOTSTAGE_STASH_ADDR=0xff8e0000
 CONFIG_DEBUG_UART_BASE=0xFF1A0000
 CONFIG_DEBUG_UART_CLOCK=24000000
 CONFIG_SPL_SPI_FLASH_SUPPORT=y
@@ -17,6 +18,12 @@
 CONFIG_DEBUG_UART=y
 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
 CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x300000
+CONFIG_BOOTSTAGE=y
+CONFIG_SPL_BOOTSTAGE=y
+CONFIG_TPL_BOOTSTAGE=y
+CONFIG_BOOTSTAGE_REPORT=y
+CONFIG_SPL_BOOTSTAGE_RECORD_COUNT=10
+CONFIG_BOOTSTAGE_STASH=y
 CONFIG_USE_PREBOOT=y
 CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-rockpro64.dtb"
 CONFIG_DISPLAY_BOARDINFO_LATE=y
@@ -40,6 +47,7 @@
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
+CONFIG_CMD_BOOTSTAGE=y
 CONFIG_SPL_OF_CONTROL=y
 CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
diff --git a/configs/sama7g5ek_mmc1_defconfig b/configs/sama7g5ek_mmc1_defconfig
index f004e44..ecb4dfc 100644
--- a/configs/sama7g5ek_mmc1_defconfig
+++ b/configs/sama7g5ek_mmc1_defconfig
@@ -79,3 +79,4 @@
 CONFIG_MCHP_PIT64B_TIMER=y
 CONFIG_OF_LIBFDT_OVERLAY=y
 # CONFIG_EFI_LOADER_HII is not set
+CONFIG_PHANDLE_CHECK_SEQ=y
diff --git a/configs/sama7g5ek_mmc_defconfig b/configs/sama7g5ek_mmc_defconfig
index 5b42fc6..1d5bccd 100644
--- a/configs/sama7g5ek_mmc_defconfig
+++ b/configs/sama7g5ek_mmc_defconfig
@@ -79,3 +79,4 @@
 CONFIG_MCHP_PIT64B_TIMER=y
 CONFIG_OF_LIBFDT_OVERLAY=y
 # CONFIG_EFI_LOADER_HII is not set
+CONFIG_PHANDLE_CHECK_SEQ=y
diff --git a/doc/develop/trace.rst b/doc/develop/trace.rst
index b22e068..5c7802d 100644
--- a/doc/develop/trace.rst
+++ b/doc/develop/trace.rst
@@ -185,7 +185,7 @@
 this timer include high resolution timers, PWMs or profile timers if
 available. Most modern SOCs have a suitable timer for this. Make sure
 that you mark this timer (and anything it calls) with
-__attribute__((no_instrument_function)) so that the trace library can
+notrace so that the trace library can
 use it without causing an infinite loop.
 
 
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index ce2d5dd..a1b85ca 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -403,13 +403,6 @@
 {
 	const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
 
-	/*
-	 * Make sure that the pinctrl driver gets probed after binding
-	 * as some pinctrl drivers also register the GPIO driver during
-	 * probe, and if they are not probed GPIO-s are not registered.
-	 */
-	dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
-
 	if (!ops) {
 		dev_dbg(dev, "ops is not set.  Do not bind.\n");
 		return -EINVAL;
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 12355af..aa61a0f 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -555,15 +555,6 @@
 int fdtdec_get_is_enabled(const void *blob, int node);
 
 /**
- * Make sure we have a valid fdt available to control U-Boot.
- *
- * If not, a message is printed to the console if the console is ready.
- *
- * Return: 0 if all ok, -1 if not
- */
-int fdtdec_prepare_fdt(void);
-
-/**
  * Checks that we have a valid fdt available to control U-Boot.
 
  * However, if not then for the moment nothing is done, since this function
diff --git a/lib/Kconfig b/lib/Kconfig
index 980bbc4..549bd35 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -316,7 +316,7 @@
 config TRACE
 	bool "Support for tracing of function calls and timing"
 	imply CMD_TRACE
-	select TIMER_EARLY
+	imply TIMER_EARLY
 	help
 	  Enables function tracing within U-Boot. This allows recording of call
 	  traces including timing information. The command can write data to
@@ -422,6 +422,7 @@
 config SPL_TPM
 	bool "Trusted Platform Module (TPM) Support in SPL"
 	depends on SPL_DM
+	imply SPL_CRC8
 	help
 	  This enables support for TPMs which can be used to provide security
 	  features for your board. The TPM can be connected via LPC or I2C
@@ -617,6 +618,23 @@
 	  security applications, but it can be useful for providing a quick
 	  checksum of a block of data.
 
+config CRC8
+	def_bool y
+	help
+	  Enables CRC8 support in U-Boot. This is normally required. CRC8 is
+	  a simple and fast checksumming algorithm which does a bytewise
+	  checksum with feedback to produce an 8-bit result. The code is small
+	  and it does not require a lookup table (unlike CRC32).
+
+config SPL_CRC8
+	bool "Support CRC8 in SPL"
+	depends on SPL
+	help
+	  Enables CRC8 support in SPL. This is not normally required. CRC8 is
+	  a simple and fast checksumming algorithm which does a bytewise
+	  checksum with feedback to produce an 8-bit result. The code is small
+	  and it does not require a lookup table (unlike CRC32).
+
 config CRC32
 	def_bool y
 	help
@@ -1042,6 +1060,13 @@
 	  Define the number of supported reserved regions in the library logical
 	  memory blocks.
 
+config PHANDLE_CHECK_SEQ
+	bool "Enable phandle check while getting sequence number"
+	help
+	  When there are multiple device tree nodes with same name,
+          enable this config option to distinguish them using
+	  phandles in fdtdec_get_alias_seq() function.
+
 endmenu
 
 menu "FWU Multi Bank Updates"
diff --git a/lib/Makefile b/lib/Makefile
index d77b33e..a282e40 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -57,12 +57,13 @@
 
 obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm-common.o
 ifeq ($(CONFIG_$(SPL_TPL_)TPM),y)
-obj-y += crc8.o
 obj-$(CONFIG_TPM) += tpm_api.o
 obj-$(CONFIG_TPM_V1) += tpm-v1.o
 obj-$(CONFIG_TPM_V2) += tpm-v2.o
 endif
 
+obj-$(CONFIG_$(SPL_TPL_)CRC8) += crc8.o
+
 obj-y += crypto/
 
 obj-$(CONFIG_$(SPL_TPL_)GENERATE_ACPI_TABLE) += acpi/
diff --git a/lib/efi_loader/efi_freestanding.c b/lib/efi_loader/efi_freestanding.c
index c85df02..4b65fc6 100644
--- a/lib/efi_loader/efi_freestanding.c
+++ b/lib/efi_loader/efi_freestanding.c
@@ -100,7 +100,7 @@
  * func_ptr:	Pointer to function being entered
  * caller:	Pointer to function which called this function
  */
-void __attribute__((no_instrument_function))
+void notrace
 __cyg_profile_func_enter(void *func_ptr, void *caller)
 {
 }
@@ -116,7 +116,7 @@
  * func_ptr:	Pointer to function being entered
  * caller:	Pointer to function which called this function
  */
-void __attribute__((no_instrument_function))
+void notrace
 __cyg_profile_func_exit(void *func_ptr, void *caller)
 {
 }
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 64c5b3d..0827e16 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -13,6 +13,7 @@
 #include <log.h>
 #include <malloc.h>
 #include <net.h>
+#include <spl.h>
 #include <env.h>
 #include <errno.h>
 #include <fdtdec.h>
@@ -518,8 +519,11 @@
 		 * Adding an extra check to distinguish DT nodes with
 		 * same name
 		 */
-		if (offset != fdt_path_offset(blob, prop))
-			continue;
+		if (IS_ENABLED(CONFIG_PHANDLE_CHECK_SEQ)) {
+			if (fdt_get_phandle(blob, offset) !=
+			    fdt_get_phandle(blob, fdt_path_offset(blob, prop)))
+				continue;
+		}
 
 		val = trailing_strtol(name);
 		if (val != -1) {
@@ -586,6 +590,34 @@
 	return fdt_path_offset(blob, prop);
 }
 
+/**
+ * fdtdec_prepare_fdt() - Check we have a valid fdt available to control U-Boot
+ *
+ * @blob: Blob to check
+ *
+ * If not, a message is printed to the console if the console is ready.
+ *
+ * Return: 0 if all ok, -ENOENT if not
+ */
+static int fdtdec_prepare_fdt(const void *blob)
+{
+	if (!blob || ((uintptr_t)blob & 3) || fdt_check_header(blob)) {
+		if (spl_phase() <= PHASE_SPL) {
+			puts("Missing DTB\n");
+		} else {
+			printf("No valid device tree binary found at %p\n",
+			       blob);
+			if (_DEBUG && blob) {
+				printf("fdt_blob=%p\n", blob);
+				print_buffer((ulong)blob, blob, 4, 32, 0);
+			}
+		}
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
 int fdtdec_check_fdt(void)
 {
 	/*
@@ -594,37 +626,10 @@
 	 * FDT (prior to console ready) will need to make their own
 	 * arrangements and do their own checks.
 	 */
-	assert(!fdtdec_prepare_fdt());
+	assert(!fdtdec_prepare_fdt(gd->fdt_blob));
 	return 0;
 }
 
-/*
- * This function is a little odd in that it accesses global data. At some
- * point if the architecture board.c files merge this will make more sense.
- * Even now, it is common code.
- */
-int fdtdec_prepare_fdt(void)
-{
-	if (!gd->fdt_blob || ((uintptr_t)gd->fdt_blob & 3) ||
-	    fdt_check_header(gd->fdt_blob)) {
-#ifdef CONFIG_SPL_BUILD
-		puts("Missing DTB\n");
-#else
-		printf("No valid device tree binary found at %p\n",
-		       gd->fdt_blob);
-# ifdef DEBUG
-		if (gd->fdt_blob) {
-			printf("fdt_blob=%p\n", gd->fdt_blob);
-			print_buffer((ulong)gd->fdt_blob, gd->fdt_blob, 4,
-				     32, 0);
-		}
-# endif
-#endif
-		return -1;
-	}
-	return 0;
-}
-
 int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name)
 {
 	const u32 *phandle;
@@ -1229,6 +1234,29 @@
 #else
 	/* FDT is at end of image */
 	fdt_blob = (ulong *)&_end;
+
+	if (_DEBUG && !fdtdec_prepare_fdt(fdt_blob)) {
+		int stack_ptr;
+		const void *top = fdt_blob + fdt_totalsize(fdt_blob);
+
+		/*
+		 * Perform a sanity check on the memory layout. If this fails,
+		 * it indicates that the device tree is positioned above the
+		 * global data pointer or the stack pointer. This should not
+		 * happen.
+		 *
+		 * If this fails, check that SYS_INIT_SP_ADDR has enough space
+		 * below it for SYS_MALLOC_F_LEN and global_data, as well as the
+		 * stack, without overwriting the device tree or U-Boot itself.
+		 * Since the device tree is sitting at _end (the start of the
+		 * BSS region), we need the top of the device tree to be below
+		 * any memory allocated by board_init_f_alloc_reserve().
+		 */
+		if (top > (void *)gd || top > (void *)&stack_ptr) {
+			printf("FDT %p gd %p\n", fdt_blob, gd);
+			panic("FDT overlap");
+		}
+	}
 #endif
 
 	return fdt_blob;
@@ -1666,7 +1694,7 @@
 	if (CONFIG_IS_ENABLED(MULTI_DTB_FIT))
 		setup_multi_dtb_fit();
 
-	ret = fdtdec_prepare_fdt();
+	ret = fdtdec_prepare_fdt(gd->fdt_blob);
 	if (!ret)
 		ret = fdtdec_board_setup(gd->fdt_blob);
 	oftree_reset();
@@ -1698,7 +1726,7 @@
 
 		*rescan = 1;
 		gd->fdt_blob = fdt_blob;
-		return fdtdec_prepare_fdt();
+		return fdtdec_prepare_fdt(fdt_blob);
 	}
 
 	/*
diff --git a/lib/trace.c b/lib/trace.c
index 54f0bf2..b9dc6d2 100644
--- a/lib/trace.c
+++ b/lib/trace.c
@@ -40,7 +40,8 @@
 	int max_depth;
 };
 
-static struct trace_hdr *hdr;	/* Pointer to start of trace buffer */
+/* Pointer to start of trace buffer */
+static struct trace_hdr *hdr __section(".data");
 
 static inline uintptr_t __attribute__((no_instrument_function))
 		func_ptr_to_num(void *func_ptr)
@@ -68,7 +69,7 @@
 /**
  * trace_save_gd() - save the value of the gd register
  */
-static void __attribute__((no_instrument_function)) trace_save_gd(void)
+static void notrace trace_save_gd(void)
 {
 	trace_gd = gd;
 }
@@ -81,7 +82,7 @@
  * have to set the gd register to the U-Boot value when entering a trace
  * point and set it back to the application value when exiting the trace point.
  */
-static void __attribute__((no_instrument_function)) trace_swap_gd(void)
+static void notrace trace_swap_gd(void)
 {
 	volatile gd_t *temp_gd = trace_gd;
 
@@ -91,18 +92,17 @@
 
 #else
 
-static void __attribute__((no_instrument_function)) trace_save_gd(void)
+static void notrace trace_save_gd(void)
 {
 }
 
-static void __attribute__((no_instrument_function)) trace_swap_gd(void)
+static void notrace trace_swap_gd(void)
 {
 }
 
 #endif
 
-static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr,
-				void *caller, ulong flags)
+static void notrace add_ftrace(void *func_ptr, void *caller, ulong flags)
 {
 	if (hdr->depth > hdr->depth_limit) {
 		hdr->ftrace_too_deep_count++;
@@ -118,7 +118,7 @@
 	hdr->ftrace_count++;
 }
 
-static void __attribute__((no_instrument_function)) add_textbase(void)
+static void notrace add_textbase(void)
 {
 	if (hdr->ftrace_count < hdr->ftrace_size) {
 		struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count];
@@ -139,8 +139,7 @@
  * @func_ptr:	pointer to function being entered
  * @caller:	pointer to function which called this function
  */
-void __attribute__((no_instrument_function)) __cyg_profile_func_enter(
-		void *func_ptr, void *caller)
+void notrace __cyg_profile_func_enter(void *func_ptr, void *caller)
 {
 	if (trace_enabled) {
 		int func;
@@ -167,8 +166,7 @@
  * @func_ptr:	pointer to function being entered
  * @caller:	pointer to function which called this function
  */
-void __attribute__((no_instrument_function)) __cyg_profile_func_exit(
-		void *func_ptr, void *caller)
+void notrace __cyg_profile_func_exit(void *func_ptr, void *caller)
 {
 	if (trace_enabled) {
 		trace_swap_gd();
@@ -327,7 +325,7 @@
 	puts(" calls not traced due to depth\n");
 }
 
-void __attribute__((no_instrument_function)) trace_set_enabled(int enabled)
+void notrace trace_set_enabled(int enabled)
 {
 	trace_enabled = enabled != 0;
 }
@@ -339,8 +337,7 @@
  * @buff_size:	Size of trace buffer
  * Return:	0 if ok
  */
-int __attribute__((no_instrument_function)) trace_init(void *buff,
-		size_t buff_size)
+int notrace trace_init(void *buff, size_t buff_size)
 {
 	ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
 	size_t needed;
@@ -404,7 +401,7 @@
  *
  * Return:	0 if ok, -ENOSPC if not enough memory is available
  */
-int __attribute__((no_instrument_function)) trace_early_init(void)
+int notrace trace_early_init(void)
 {
 	ulong func_count = gd->mon_len / FUNC_SITE_SIZE;
 	size_t buff_size = CONFIG_TRACE_EARLY_SIZE;
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 69e4b00..fa8abdc 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -487,6 +487,14 @@
 since it is assumed that images are XIP and the offsets already include the
 address.
 
+While U-Boot's symbol updating is handled automatically by the u-boot-spl
+entry type (and others), it is possible to use this feature with any blob. To
+do this, add a `write-symbols` (boolean) property to the node, set the ELF
+filename using `elf-filename` and set 'elf-base-sym' to the base symbol for the
+start of the binary image (this defaults to `__image_copy_start` which is what
+U-Boot uses). See `testBlobSymbol()` for an example.
+
+.. _binman_fdt:
 
 Access to binman entry offsets at run time (fdt)
 ------------------------------------------------
@@ -689,6 +697,15 @@
     `no-expanded` property disables this just for a single entry. Put the
     `no-expanded` boolean property in the node to select this behaviour.
 
+optional:
+    External blobs are normally required to be present for the image to be
+    built (but see `External blobs`_). This properly allows an entry to be
+    optional, so that when it is cannot be found, this problem is ignored and
+    an empty file is used for this blob. This should be used only when the blob
+    is entirely optional and is not needed for correct operation of the image.
+    Note that missing, optional blobs do not produce a non-zero exit code from
+    binman, although it does show a warning about the missing external blob.
+
 The attributes supported for images and sections are described below. Several
 are similar to those for entries.
 
@@ -782,6 +799,37 @@
 symlink:
     Adds a symlink to the image with string given in the symlink property.
 
+overlap:
+    Indicates that this entry overlaps with others in the same section. These
+    entries should appear at the end of the section. Overlapping entries are not
+    packed with other entries, but their contents are written over other entries
+    in the section. Overlapping entries must have an explicit offset and size.
+
+write-symbols:
+    Indicates that the blob should be updated with symbol values calculated by
+    binman. This is automatic for certain entry types, e.g. `u-boot-spl`. See
+    binman_syms_ for more information.
+
+elf-filename:
+    Sets the file name of a blob's associated ELF file. For example, if the
+    blob is `zephyr.bin` then the ELF file may be `zephyr.elf`. This allows
+    binman to locate symbols and understand the structure of the blob. See
+    binman_syms_ for more information.
+
+elf-base-sym:
+    Sets the name of the ELF symbol that points to the start of a blob. For
+    U-Boot this is `__image_copy_start` and that is the default used by binman
+    if this property is missing. For other projects, a difference symbol may be
+    needed. Add this symbol to the properties for the blob so that symbols can
+    be read correctly. See binman_syms_ for more information.
+
+offset-from-elf:
+    Sets the offset of an entry based on a symbol value in an another entry.
+    The format is <&phandle>, "sym_name", <offset> where phandle is the entry
+    containing the blob (with associated ELF file providing symbols), <sym_name>
+    is the symbol to lookup (relative to elf-base-sym) and <offset> is an offset
+    to add to that value.
+
 Examples of the above options can be found in the tests. See the
 tools/binman/test directory.
 
@@ -836,6 +884,11 @@
     renamed to 'ro-u-boot' and 'rw-u-boot'. This can be useful to
     distinguish binaries with otherwise identical names.
 
+filename:
+    This allows the contents of the section to be written to a file in the
+    output directory. This can sometimes be useful to use the data in one
+    section in different image, since there is currently no way to share data
+    beteen images other than through files.
 
 Image Properties
 ----------------
@@ -1007,6 +1060,28 @@
 entry args are provided by the U-Boot Makefile.
 
 
+Optional entries
+----------------
+
+Some entries need to exist only if certain conditions are met. For example, an
+entry may want to appear in the image only if a file has a particular format.
+Obviously the entry must exist in the image description for it to be processed
+at all, so a way needs to be found to have the entry remove itself.
+
+To handle this, when entry.ObtainContents() is called, the entry can call
+entry.mark_absent() to mark itself as absent, passing a suitable message as the
+reason.
+
+Any absent entries are dropped immediately after ObtainContents() has been
+called on all entries.
+
+It is not possible for an entry to mark itself absent at any other point in the
+processing. It must happen in the ObtainContents() method.
+
+The effect is as if the entry had never been present at all, since the image
+is packed without it and it disappears from the list of entries.
+
+
 Compression
 -----------
 
@@ -1683,7 +1758,8 @@
 
 Note: for sections, this also checks that the entries do not overlap, nor extend
 outside the section. If the section does not have a defined size, the size is
-set large enough to hold all the entries.
+set large enough to hold all the entries. For entries that are explicitly marked
+as overlapping, this check is skipped.
 
 6. SetImagePos() - sets the image position of every entry. This is the absolute
 position 'image-pos', as opposed to 'offset' which is relative to the containing
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 964c698..e647400 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -552,6 +552,7 @@
         image.SetAllowMissing(allow_missing)
         image.SetAllowFakeBlob(allow_fake_blobs)
         image.GetEntryContents()
+        image.drop_absent()
     image.GetEntryOffsets()
 
     # We need to pack the entries to figure out where everything
@@ -593,12 +594,14 @@
     image.BuildImage()
     if write_map:
         image.WriteMap()
+
     missing_list = []
     image.CheckMissing(missing_list)
     if missing_list:
         tout.warning("Image '%s' is missing external blobs and is non-functional: %s" %
                      (image.name, ' '.join([e.name for e in missing_list])))
         _ShowHelpForMissingBlobs(missing_list)
+
     faked_list = []
     image.CheckFakedBlobs(faked_list)
     if faked_list:
@@ -606,6 +609,15 @@
             "Image '%s' has faked external blobs and is non-functional: %s" %
             (image.name, ' '.join([os.path.basename(e.GetDefaultFilename())
                                    for e in faked_list])))
+
+    optional_list = []
+    image.CheckOptional(optional_list)
+    if optional_list:
+        tout.warning(
+            "Image '%s' is missing external blobs but is still functional: %s" %
+            (image.name, ' '.join([e.name for e in optional_list])))
+        _ShowHelpForMissingBlobs(optional_list)
+
     missing_bintool_list = []
     image.check_missing_bintools(missing_bintool_list)
     if missing_bintool_list:
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index fe50bf5..3cc8a38 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -210,7 +210,31 @@
         raise ValueError('%s has size %d: only 4 and 8 are supported' %
                          (msg, sym.size))
 
-def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
+def GetSymbolOffset(elf_fname, sym_name, base_sym=None):
+    """Read the offset of a symbol compared to base symbol
+
+    This is useful for obtaining the value of a single symbol relative to the
+    base of a binary blob.
+
+    Args:
+        elf_fname: Filename of the ELF file to read
+        sym_name (str): Name of symbol to read
+        base_sym (str): Base symbol to sue to calculate the offset (or None to
+            use '__image_copy_start'
+
+    Returns:
+        int: Offset of the symbol relative to the base symbol
+    """
+    if not base_sym:
+        base_sym = '__image_copy_start'
+    fname = tools.get_input_filename(elf_fname)
+    syms = GetSymbols(fname, [base_sym, sym_name])
+    base = syms[base_sym].address
+    val = syms[sym_name].address
+    return val - base
+
+def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
+                          base_sym=None):
     """Replace all symbols in an entry with their correct values
 
     The entry contents is updated so that values for referenced symbols will be
@@ -223,7 +247,10 @@
             entry
         entry: Entry to process
         section: Section which can be used to lookup symbol values
+        base_sym: Base symbol marking the start of the image
     """
+    if not base_sym:
+        base_sym = '__image_copy_start'
     fname = tools.get_input_filename(elf_fname)
     syms = GetSymbols(fname, ['image', 'binman'])
     if is_elf:
@@ -243,7 +270,7 @@
     if not syms:
         tout.debug('LookupAndWriteSymbols: no syms')
         return
-    base = syms.get('__image_copy_start')
+    base = syms.get(base_sym)
     if not base and not is_elf:
         tout.debug('LookupAndWriteSymbols: no base')
         return
@@ -518,3 +545,18 @@
             rend = start + segment['p_filesz']
             segments.append((i, segment['p_paddr'], data[start:rend]))
     return segments, entry
+
+def is_valid(data):
+    """Check if some binary data is a valid ELF file
+
+    Args:
+        data (bytes): Bytes to check
+
+    Returns:
+        bool: True if a valid Elf file, False if not
+    """
+    try:
+        DecodeElf(data, 0)
+        return True
+    except ELFError:
+        return False
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py
index 75b867c..082a3e1 100644
--- a/tools/binman/elf_test.py
+++ b/tools/binman/elf_test.py
@@ -348,6 +348,16 @@
         finally:
             elf.ELF_TOOLS = old_val
 
+    def test_is_valid(self):
+        """Test is_valid()"""
+        self.assertEqual(False, elf.is_valid(b''))
+        self.assertEqual(False, elf.is_valid(b'1234'))
+
+        fname = self.ElfTestFile('elf_sections')
+        data = tools.read_file(fname)
+        self.assertEqual(True, elf.is_valid(data))
+        self.assertEqual(False, elf.is_valid(data[4:]))
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index 3dc32db..2b32c13 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -216,11 +216,11 @@
 obtained from the list of available device-tree files, managed by the
 'state' module.
 
-Additional Properties / Entry arguments:
-    - prepend: Header type to use:
-        length: 32-bit length header
+Additional attributes:
+    prepend: Header used (e.g. 'length')
 
 
+
 .. _etype_blob_ext:
 
 Entry: blob-ext: Externally built binary blob
@@ -1178,11 +1178,13 @@
     - multiple-data-files: boolean to tell binman to pass all files as
       datafiles to mkimage instead of creating a temporary file the result
       of datafiles concatenation
+    - filename: filename of output binary generated by mkimage
 
 The data passed to mkimage via the -d flag is collected from subnodes of the
 mkimage node, e.g.::
 
     mkimage {
+        filename = "imximage.bin";
         args = "-n test -T imximage";
 
         u-boot-spl {
@@ -1190,13 +1192,14 @@
     };
 
 This calls mkimage to create an imximage with `u-boot-spl.bin` as the data
-file, which mkimage being called like this::
+file, with mkimage being called like this::
 
     mkimage -d <data_file> -n test -T imximage <output_file>
 
 The output from mkimage then becomes part of the image produced by
-binman. If you need to put mulitple things in the data file, you can use
-a section, or just multiple subnodes like this::
+binman but also is written into `imximage.bin` file. If you need to put
+multiple things in the data file, you can use a section, or just multiple
+subnodes like this::
 
     mkimage {
         args = "-n test -T imximage";
@@ -1208,17 +1211,20 @@
         };
     };
 
+Note that binman places the contents (here SPL and TPL) into a single file
+and passes that to mkimage using the -d option.
+
 To pass all datafiles untouched to mkimage::
 
     mkimage {
-        args = "-n rk3399 -T rkspi";
-        multiple-data-files;
+            args = "-n rk3399 -T rkspi";
+            multiple-data-files;
 
-        u-boot-tpl {
-        };
+            u-boot-tpl {
+            };
 
-        u-boot-spl {
-        };
+            u-boot-spl {
+            };
     };
 
 This calls mkimage to create a Rockchip RK3399-specific first stage
@@ -1242,17 +1248,17 @@
 
     mkimage {
         args = "-T imximage";
-        data-to-imagename';
+        data-to-imagename;
 
         u-boot-spl {
         };
     };
 
 That will pass the data to mkimage both as the data file (with -d) and as
-the image name (with -n).
+the image name (with -n). In both cases, a filename is passed as the
+argument, with the actual data being in that file.
 
-
-If need to pass different data in with -n, then use an imagename subnode::
+If need to pass different data in with -n, then use an `imagename` subnode::
 
     mkimage {
         args = "-T imximage";
@@ -1270,6 +1276,20 @@
 This will pass in u-boot-spl as the input data and the .cfgout file as the
 -n data.
 
+
+
+.. _etype_null:
+
+Entry: null: An entry which has no contents of its own
+------------------------------------------------------
+
+Note that the size property must be set since otherwise this entry does not
+know how large it should be.
+
+The contents are set by the containing section, e.g. the section's pad
+byte.
+
+
 
 .. _etype_opensbi:
 
@@ -1478,6 +1498,10 @@
     be written at offset 4 in the image file, since the first 16 bytes are
     skipped when writing.
 
+filename
+    filename to write the unpadded section contents to within the output
+    directory (None to skip this).
+
 Since a section is also an entry, it inherits all the properies of entries
 too.
 
@@ -1497,13 +1521,48 @@
 
 Properties / Entry arguments:
     - tee-os-path: Filename of file to read into entry. This is typically
-        called tee-pager.bin
+        called tee.bin or tee.elf
 
 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/OP-TEE/optee_os for more information about OP-TEE.
 
+Note that if the file is in ELF format, it must go in a FIT. In that case,
+this entry will mark itself as absent, providing the data only through the
+read_elf_segments() method.
+
+Marking this entry as absent means that it if is used in the wrong context
+it can be automatically dropped. Thus it is possible to add an OP-TEE entry
+like this::
+
+    binman {
+        tee-os {
+        };
+    };
+
+and pass either an ELF or plain binary in with -a tee-os-path <filename>
+and have binman do the right thing:
+
+   - include the entry if tee.bin is provided and it does NOT have the v1
+     header
+   - drop it otherwise
 
+When used within a FIT, we can do::
+
+    binman {
+        fit {
+            tee-os {
+            };
+        };
+    };
+
+which will split the ELF into separate nodes for each segment, if an ELF
+file is provided (see :ref:`etype_fit`), or produce a single node if the
+OP-TEE binary v1 format is provided (see optee_doc_) .
+
+.. _optee_doc: https://optee.readthedocs.io/en/latest/architecture/core.html#partitioning-of-the-binary
+
+
 
 .. _etype_text:
 
@@ -1567,11 +1626,7 @@
 to relocate itself at runtime. The binary typically includes a device tree
 blob at the end of it.
 
-U-Boot can access binman symbols at runtime. See:
-
-    'Access to binman entry offsets at run time (fdt)'
-
-in the binman README for more information.
+U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`.
 
 Note that this entry is automatically replaced with u-boot-expanded unless
 --no-expanded is used or the node has a 'no-expanded' property.
@@ -1701,9 +1756,7 @@
 to run from the correct address if direct flash execution is possible (e.g.
 on x86 devices).
 
-SPL can access binman symbols at runtime. See:
-
-    'Access to binman entry offsets at run time (symbols)'
+SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
 in the binman README for more information.
 
@@ -1806,9 +1859,7 @@
 expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
 u-boot-spl-dtb
 
-SPL can access binman symbols at runtime. See:
-
-    'Access to binman entry offsets at run time (symbols)'
+SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
 in the binman README for more information.
 
@@ -1844,9 +1895,7 @@
 address in SRAM, or written to run from the correct address if direct
 flash execution is possible (e.g. on x86 devices).
 
-SPL can access binman symbols at runtime. See:
-
-    'Access to binman entry offsets at run time (symbols)'
+SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
 in the binman README for more information.
 
@@ -1961,9 +2010,7 @@
 expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
 u-boot-tpl-dtb
 
-TPL can access binman symbols at runtime. See:
-
-    'Access to binman entry offsets at run time (symbols)'
+TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
 in the binman README for more information.
 
@@ -2034,6 +2081,128 @@
 
 
 
+.. _etype_u_boot_vpl:
+
+Entry: u-boot-vpl: U-Boot VPL binary
+------------------------------------
+
+Properties / Entry arguments:
+    - filename: Filename of u-boot-vpl.bin (default 'vpl/u-boot-vpl.bin')
+
+This is the U-Boot VPL (Verifying Program Loader) binary. This is a small
+binary which loads before SPL, typically into on-chip SRAM. It is
+responsible for locating, loading and jumping to SPL, the next-stage
+loader. Note that VPL is not relocatable so must be loaded to the correct
+address in SRAM, or written to run from the correct address if direct
+flash execution is possible (e.g. on x86 devices).
+
+SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
+
+in the binman README for more information.
+
+The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
+binman uses that to look up symbols to write into the VPL binary.
+
+
+
+.. _etype_u_boot_vpl_bss_pad:
+
+Entry: u-boot-vpl-bss-pad: U-Boot VPL binary padded with a BSS region
+---------------------------------------------------------------------
+
+Properties / Entry arguments:
+    None
+
+This holds the padding added after the VPL binary to cover the BSS (Block
+Started by Symbol) region. This region holds the various variables used by
+VPL. It is set to 0 by VPL when it starts up. If you want to append data to
+the VPL image (such as a device tree file), you must pad out the BSS region
+to avoid the data overlapping with U-Boot variables. This entry is useful in
+that case. It automatically pads out the entry size to cover both the code,
+data and BSS.
+
+The contents of this entry will a certain number of zero bytes, determined
+by __bss_size
+
+The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
+binman uses that to look up the BSS address.
+
+
+
+.. _etype_u_boot_vpl_dtb:
+
+Entry: u-boot-vpl-dtb: U-Boot VPL device tree
+---------------------------------------------
+
+Properties / Entry arguments:
+    - filename: Filename of u-boot.dtb (default 'vpl/u-boot-vpl.dtb')
+
+This is the VPL device tree, containing configuration information for
+VPL. VPL needs this to know what devices are present and which drivers
+to activate.
+
+
+
+.. _etype_u_boot_vpl_elf:
+
+Entry: u-boot-vpl-elf: U-Boot VPL ELF image
+-------------------------------------------
+
+Properties / Entry arguments:
+    - filename: Filename of VPL u-boot (default 'vpl/u-boot-vpl')
+
+This is the U-Boot VPL ELF image. It does not include a device tree but can
+be relocated to any address for execution.
+
+
+
+.. _etype_u_boot_vpl_expanded:
+
+Entry: u-boot-vpl-expanded: U-Boot VPL flat binary broken out into its component parts
+--------------------------------------------------------------------------------------
+
+Properties / Entry arguments:
+    - vpl-dtb: Controls whether this entry is selected (set to 'y' or '1' to
+        select)
+
+This is a section containing the U-Boot binary, BSS padding if needed and a
+devicetree. Using this entry type automatically creates this section, with
+the following entries in it:
+
+   u-boot-vpl-nodtb
+   u-boot-vpl-bss-pad
+   u-boot-dtb
+
+Having the devicetree separate allows binman to update it in the final
+image, so that the entries positions are provided to the running U-Boot.
+
+This entry is selected based on the value of the 'vpl-dtb' entryarg. If
+this is non-empty (and not 'n' or '0') then this expanded entry is selected.
+
+
+
+.. _etype_u_boot_vpl_nodtb:
+
+Entry: u-boot-vpl-nodtb: VPL binary without device tree appended
+----------------------------------------------------------------
+
+Properties / Entry arguments:
+    - filename: Filename to include (default 'vpl/u-boot-vpl-nodtb.bin')
+
+This is the U-Boot VPL binary, It does not include a device tree blob at
+the end of it so may not be able to work without it, assuming VPL needs
+a device tree to operate on your platform. You can add a u_boot_vpl_dtb
+entry after this one, or use a u_boot_vpl entry instead, which normally
+expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
+u-boot-vpl-dtb
+
+VPL can access binman symbols at runtime. See :ref:`binman_fdt`.
+
+The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
+binman uses that to look up symbols to write into the VPL binary.
+
+
+
 .. _etype_u_boot_with_ucode_ptr:
 
 Entry: u-boot-with-ucode-ptr: U-Boot with embedded microcode pointer
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 1be31a0..5d8696e 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -73,7 +73,9 @@
         compress: Compression algoithm used (e.g. 'lz4'), 'none' if none
         orig_offset: Original offset value read from node
         orig_size: Original size value read from node
-        missing: True if this entry is missing its contents
+        missing: True if this entry is missing its contents. Note that if it is
+            optional, this entry will not appear in the list generated by
+            entry.CheckMissing() since it is considered OK for it to be missing.
         allow_missing: Allow children of this entry to be missing (used by
             subclasses such as Entry_section)
         allow_fake: Allow creating a dummy fake file if the blob file is not
@@ -91,6 +93,12 @@
             file, or is a binary file produced from an ELF file
         auto_write_symbols (bool): True to write ELF symbols into this entry's
             contents
+        absent (bool): True if this entry is absent. This can be controlled by
+            the entry itself, allowing it to vanish in certain circumstances.
+            An absent entry is removed during processing so that it does not
+            appear in the map
+        optional (bool): True if this entry contains an optional external blob
+        overlap (bool): True if this entry overlaps with others
     """
     fake_dir = None
 
@@ -133,6 +141,11 @@
         self.comp_bintool = None
         self.elf_fname = None
         self.auto_write_symbols = auto_write_symbols
+        self.absent = False
+        self.optional = False
+        self.overlap = False
+        self.elf_base_sym = None
+        self.offset_from_elf = None
 
     @staticmethod
     def FindEntryClass(etype, expanded):
@@ -284,9 +297,15 @@
         self.offset_unset = fdt_util.GetBool(self._node, 'offset-unset')
         self.extend_size = fdt_util.GetBool(self._node, 'extend-size')
         self.missing_msg = fdt_util.GetString(self._node, 'missing-msg')
+        self.optional = fdt_util.GetBool(self._node, 'optional')
+        self.overlap = fdt_util.GetBool(self._node, 'overlap')
+        if self.overlap:
+            self.required_props += ['offset', 'size']
 
         # This is only supported by blobs and sections at present
         self.compress = fdt_util.GetString(self._node, 'compress', 'none')
+        self.offset_from_elf = fdt_util.GetPhandleNameOffset(self._node,
+                                                             'offset-from-elf')
 
     def GetDefaultFilename(self):
         return None
@@ -444,7 +463,7 @@
 
         Returns:
             True if the contents were found, False if another call is needed
-            after the other entries are processed.
+            after the other entries are processed, None if there is no contents
         """
         # No contents by default: subclasses can implement this
         return True
@@ -483,7 +502,10 @@
             if self.offset_unset:
                 self.Raise('No offset set with offset-unset: should another '
                            'entry provide this correct offset?')
-            self.offset = tools.align(offset, self.align)
+            elif self.offset_from_elf:
+                self.offset = self.lookup_offset()
+            else:
+                self.offset = tools.align(offset, self.align)
         needed = self.pad_before + self.contents_size + self.pad_after
         needed = tools.align(needed, self.align_size)
         size = self.size
@@ -572,7 +594,9 @@
 
         Returns:
             bytes content of the entry, excluding any padding. If the entry is
-                compressed, the compressed data is returned
+                compressed, the compressed data is returned. If the entry data
+                is not yet available, False can be returned. If the entry data
+                is null, then None is returned.
         """
         self.Detail('GetData: size %s' % to_hex_size(self.data))
         return self.data
@@ -659,7 +683,7 @@
             # Check if we are writing symbols into an ELF file
             is_elf = self.GetDefaultFilename() == self.elf_fname
             elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(),
-                                      is_elf)
+                                      is_elf, self.elf_base_sym)
 
     def CheckEntries(self):
         """Check that the entry offsets are correct
@@ -1034,14 +1058,15 @@
         self.allow_fake = allow_fake
 
     def CheckMissing(self, missing_list):
-        """Check if any entries in this section have missing external blobs
+        """Check if the entry has missing external blobs
 
-        If there are missing blobs, the entries are added to the list
+        If there are missing (non-optional) blobs, the entries are added to the
+        list
 
         Args:
             missing_list: List of Entry objects to be added to
         """
-        if self.missing:
+        if self.missing and not self.optional:
             missing_list.append(self)
 
     def check_fake_fname(self, fname, size=0):
@@ -1080,6 +1105,17 @@
         # This is meaningless for anything other than blobs
         pass
 
+    def CheckOptional(self, optional_list):
+        """Check if the entry has missing but optional external blobs
+
+        If there are missing (optional) blobs, the entries are added to the list
+
+        Args:
+            optional_list (list): List of Entry objects to be added to
+        """
+        if self.missing and self.optional:
+            optional_list.append(self)
+
     def GetAllowMissing(self):
         """Get whether a section allows missing external blobs
 
@@ -1281,3 +1317,31 @@
                 not_present.append(prop)
         if not_present:
             self.Raise(f"'{self.etype}' entry is missing properties: {' '.join(not_present)}")
+
+    def mark_absent(self, msg):
+        tout.info("Entry '%s' marked absent: %s" % (self._node.path, msg))
+        self.absent = True
+
+    def read_elf_segments(self):
+        """Read segments from an entry that can generate an ELF file
+
+        Returns:
+            tuple:
+                list of segments, each:
+                    int: Segment number (0 = first)
+                    int: Start address of segment in memory
+                    bytes: Contents of segment
+                int: entry address of ELF file
+        """
+        return None
+
+    def lookup_offset(self):
+        node, sym_name, offset = self.offset_from_elf
+        entry = self.section.FindEntryByNode(node)
+        if not entry:
+            self.Raise("Cannot find entry for node '%s'" % node.name)
+        if not entry.elf_fname:
+            entry.Raise("Need elf-fname property '%s'" % node.name)
+        val = elf.GetSymbolOffset(entry.elf_fname, sym_name,
+                                  entry.elf_base_sym)
+        return val + offset
diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py
index 6960048..1c1efb2 100644
--- a/tools/binman/etype/_testing.py
+++ b/tools/binman/etype/_testing.py
@@ -63,6 +63,7 @@
                                                     'bad-update-contents-twice')
         self.return_contents_later = fdt_util.GetBool(self._node,
                                                      'return-contents-later')
+        self.set_to_absent = fdt_util.GetBool(self._node, 'set-to-absent')
 
         # Set to True when the entry is ready to process the FDT.
         self.process_fdt_ready = False
@@ -119,6 +120,8 @@
         if self.require_bintool_for_contents:
             if self.bintool_for_contents is None:
                 self.Raise("Required bintool unusable in ObtainContents()")
+        if self.set_to_absent:
+            self.mark_absent('for testing purposes')
         return True
 
     def GetOffsets(self):
diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py
index a50a806..c7ddced 100644
--- a/tools/binman/etype/blob.py
+++ b/tools/binman/etype/blob.py
@@ -35,11 +35,17 @@
         super().__init__(section, etype, node,
                          auto_write_symbols=auto_write_symbols)
         self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
+        self.elf_fname = fdt_util.GetString(self._node, 'elf-filename',
+                                            self.elf_fname)
+        self.elf_base_sym = fdt_util.GetString(self._node, 'elf-base-sym')
+        if not self.auto_write_symbols:
+            if fdt_util.GetBool(self._node, 'write-symbols'):
+                self.auto_write_symbols = True
 
     def ObtainContents(self, fake_size=0):
         self._filename = self.GetDefaultFilename()
         self._pathname = tools.get_input_filename(self._filename,
-            self.external and self.section.GetAllowMissing())
+            self.external and (self.optional or self.section.GetAllowMissing()))
         # Allow the file to be missing
         if not self._pathname:
             self._pathname, faked = self.check_fake_fname(self._filename,
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index 7860e2a..0e9d81b 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -392,8 +392,8 @@
 
         _add_entries(self._node, 0, self._node)
 
-        # Keep a copy of all entries, including generator entries, since these
-        # removed from self._entries later.
+        # Keep a copy of all entries, including generator entries, since those
+        # are removed from self._entries later.
         self._priv_entries = dict(self._entries)
 
     def BuildSectionData(self, required):
@@ -540,50 +540,50 @@
                     else:
                         self.Raise("Generator node requires 'fit,fdt-list' property")
 
-        def _gen_split_elf(base_node, node, elf_data, missing):
+        def _gen_split_elf(base_node, node, segments, entry_addr):
             """Add nodes for the ELF file, one per group of contiguous segments
 
             Args:
                 base_node (Node): Template node from the binman definition
                 node (Node): Node to replace (in the FIT being built)
-                data (bytes): ELF-format data to process (may be empty)
-                missing (bool): True if any of the data is missing
-
+                segments (list): list of segments, each:
+                    int: Segment number (0 = first)
+                    int: Start address of segment in memory
+                    bytes: Contents of segment
+                entry_addr (int): entry address of ELF file
             """
-            # If any pieces are missing, skip this. The missing entries will
-            # show an error
-            if not missing:
-                try:
-                    segments, entry = elf.read_loadable_segments(elf_data)
-                except ValueError as exc:
-                    self._raise_subnode(node,
-                                        f'Failed to read ELF file: {str(exc)}')
-                for (seq, start, data) in segments:
-                    node_name = node.name[1:].replace('SEQ', str(seq + 1))
-                    with fsw.add_node(node_name):
-                        loadables.append(node_name)
-                        for pname, prop in node.props.items():
-                            if not pname.startswith('fit,'):
-                                fsw.property(pname, prop.bytes)
-                            elif pname == 'fit,load':
-                                fsw.property_u32('load', start)
-                            elif pname == 'fit,entry':
-                                if seq == 0:
-                                    fsw.property_u32('entry', entry)
-                            elif pname == 'fit,data':
-                                fsw.property('data', bytes(data))
-                            elif pname != 'fit,operation':
-                                self._raise_subnode(
-                                    node, f"Unknown directive '{pname}'")
+            for (seq, start, data) in segments:
+                node_name = node.name[1:].replace('SEQ', str(seq + 1))
+                with fsw.add_node(node_name):
+                    loadables.append(node_name)
+                    for pname, prop in node.props.items():
+                        if not pname.startswith('fit,'):
+                            fsw.property(pname, prop.bytes)
+                        elif pname == 'fit,load':
+                            fsw.property_u32('load', start)
+                        elif pname == 'fit,entry':
+                            if seq == 0:
+                                fsw.property_u32('entry', entry_addr)
+                        elif pname == 'fit,data':
+                            fsw.property('data', bytes(data))
+                        elif pname != 'fit,operation':
+                            self._raise_subnode(
+                                node, f"Unknown directive '{pname}'")
 
         def _gen_node(base_node, node, depth, in_images, entry):
             """Generate nodes from a template
 
-            This creates one node for each member of self._fdts using the
-            provided template. If a property value contains 'NAME' it is
-            replaced with the filename of the FDT. If a property value contains
-            SEQ it is replaced with the node sequence number, where 1 is the
-            first.
+            This creates one or more nodes depending on the fit,operation being
+            used.
+
+            For OP_GEN_FDT_NODES it creates one node for each member of
+            self._fdts using the provided template. If a property value contains
+            'NAME' it is replaced with the filename of the FDT. If a property
+            value contains SEQ it is replaced with the node sequence number,
+            where 1 is the first.
+
+            For OP_SPLIT_ELF it emits one node for each section in the ELF file.
+            If the file is missing, nothing is generated.
 
             Args:
                 base_node (Node): Base Node of the FIT (with 'description'
@@ -592,6 +592,8 @@
                 depth (int): Current node depth (0 is the base 'fit' node)
                 in_images (bool): True if this is inside the 'images' node, so
                     that 'data' properties should be generated
+                entry (entry_Section): Entry for the section containing the
+                    contents of this node
             """
             oper = self._get_operation(base_node, node)
             if oper == OP_GEN_FDT_NODES:
@@ -600,13 +602,28 @@
                 # Entry_section.ObtainContents() either returns True or
                 # raises an exception.
                 data = None
-                missing_list = []
+                missing_opt_list = []
                 entry.ObtainContents()
                 entry.Pack(0)
-                data = entry.GetData()
-                entry.CheckMissing(missing_list)
+                entry.CheckMissing(missing_opt_list)
+                entry.CheckOptional(missing_opt_list)
 
-                _gen_split_elf(base_node, node, data, bool(missing_list))
+                # If any pieces are missing, skip this. The missing entries will
+                # show an error
+                if not missing_opt_list:
+                    segs = entry.read_elf_segments()
+                    if segs:
+                        segments, entry_addr = segs
+                    else:
+                        elf_data = entry.GetData()
+                        try:
+                            segments, entry_addr = (
+                                    elf.read_loadable_segments(elf_data))
+                        except ValueError as exc:
+                            self._raise_subnode(
+                                node, f'Failed to read ELF file: {str(exc)}')
+
+                    _gen_split_elf(base_node, node, segments, entry_addr)
 
         def _add_node(base_node, depth, node):
             """Add nodes to the output FIT
@@ -638,8 +655,7 @@
 
             for subnode in node.subnodes:
                 subnode_path = f'{rel_path}/{subnode.name}'
-                if has_images and not (subnode.name.startswith('hash') or
-                                       subnode.name.startswith('signature')):
+                if has_images and not self.IsSpecialSubnode(subnode):
                     # This subnode is a content node not meant to appear in
                     # the FIT (e.g. "/images/kernel/u-boot"), so don't call
                     # fsw.add_node() or _add_node() for it.
diff --git a/tools/binman/etype/mkimage.py b/tools/binman/etype/mkimage.py
index c2288c4..cb264c3c 100644
--- a/tools/binman/etype/mkimage.py
+++ b/tools/binman/etype/mkimage.py
@@ -57,24 +57,24 @@
     Note that binman places the contents (here SPL and TPL) into a single file
     and passes that to mkimage using the -d option.
 
-	To pass all datafiles untouched to mkimage::
+    To pass all datafiles untouched to mkimage::
 
-		mkimage {
-			args = "-n rk3399 -T rkspi";
-			multiple-data-files;
+        mkimage {
+                args = "-n rk3399 -T rkspi";
+                multiple-data-files;
 
-			u-boot-tpl {
-			};
+                u-boot-tpl {
+                };
 
-			u-boot-spl {
-			};
-		};
+                u-boot-spl {
+                };
+        };
 
-	This calls mkimage to create a Rockchip RK3399-specific first stage
-	bootloader, made of TPL+SPL. Since this first stage bootloader requires to
-	align the TPL and SPL but also some weird hacks that is handled by mkimage
-	directly, binman is told to not perform the concatenation of datafiles prior
-	to passing the data to mkimage.
+    This calls mkimage to create a Rockchip RK3399-specific first stage
+    bootloader, made of TPL+SPL. Since this first stage bootloader requires to
+    align the TPL and SPL but also some weird hacks that is handled by mkimage
+    directly, binman is told to not perform the concatenation of datafiles prior
+    to passing the data to mkimage.
 
     To use CONFIG options in the arguments, use a string list instead, as in
     this example which also produces four arguments::
diff --git a/tools/binman/etype/null.py b/tools/binman/etype/null.py
new file mode 100644
index 0000000..c10d482
--- /dev/null
+++ b/tools/binman/etype/null.py
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2023 Google LLC
+# Written by Simon Glass <sjg@chromium.org>
+#
+
+from binman.entry import Entry
+from dtoc import fdt_util
+from patman import tools
+
+class Entry_null(Entry):
+    """An entry which has no contents of its own
+
+    Note that the size property must be set since otherwise this entry does not
+    know how large it should be.
+
+    The contents are set by the containing section, e.g. the section's pad
+    byte.
+    """
+    def __init__(self, section, etype, node):
+        super().__init__(section, etype, node)
+        self.required_props = ['size']
+
+    def ObtainContents(self):
+        # null contents
+        return None
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index da561e2..57b91ff 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -144,6 +144,10 @@
         be written at offset 4 in the image file, since the first 16 bytes are
         skipped when writing.
 
+    filename
+        filename to write the unpadded section contents to within the output
+        directory (None to skip this).
+
     Since a section is also an entry, it inherits all the properies of entries
     too.
 
@@ -163,6 +167,18 @@
         self._skip_at_start = None
         self._end_4gb = False
         self._ignore_missing = False
+        self._filename = None
+
+    def IsSpecialSubnode(self, node):
+        """Check if a node is a special one used by the section itself
+
+        Some notes are used for hashing / signatures and do not add entries to
+        the actual section.
+
+        Returns:
+            bool: True if the node is a special one, else False
+        """
+        return node.name.startswith('hash') or node.name.startswith('signature')
 
     def ReadNode(self):
         """Read properties from the section node"""
@@ -183,12 +199,14 @@
                 self._skip_at_start = 0
         self._name_prefix = fdt_util.GetString(self._node, 'name-prefix')
         self.align_default = fdt_util.GetInt(self._node, 'align-default', 0)
+        self._filename = fdt_util.GetString(self._node, 'filename',
+                                            self._filename)
 
         self.ReadEntries()
 
     def ReadEntries(self):
         for node in self._node.subnodes:
-            if node.name.startswith('hash') or node.name.startswith('signature'):
+            if self.IsSpecialSubnode(node):
                 continue
             entry = Entry.Create(self, node,
                                  expanded=self.GetImage().use_expanded,
@@ -258,6 +276,7 @@
 
         Args:
             entry: Entry to check
+            entry_data: Data for the entry, False if is null
 
         Returns:
             Contents of the entry along with any pad bytes before and
@@ -312,14 +331,32 @@
             # earlier in the image description. See testCollectionSection().
             if not required and entry_data is None:
                 return None
-            data = self.GetPaddedDataForEntry(entry, entry_data)
+
+            entry_data_final = entry_data
+            if entry_data is None:
+                pad_byte = (entry._pad_byte if isinstance(entry, Entry_section)
+                            else self._pad_byte)
+                entry_data_final = tools.get_bytes(self._pad_byte, entry.size)
+
+            data = self.GetPaddedDataForEntry(entry, entry_data_final)
             # Handle empty space before the entry
             pad = (entry.offset or 0) - self._skip_at_start - len(section_data)
             if pad > 0:
                 section_data += tools.get_bytes(self._pad_byte, pad)
 
             # Add in the actual entry data
-            section_data += data
+            if entry.overlap:
+                end_offset = entry.offset + entry.size
+                if end_offset > len(section_data):
+                    entry.Raise("Offset %#x (%d) ending at %#x (%d) must overlap with existing entries" %
+                                (entry.offset, entry.offset, end_offset,
+                                 end_offset))
+                # Don't write anything for null entries'
+                if entry_data is not None:
+                    section_data = (section_data[:entry.offset] + data +
+                                    section_data[entry.offset + entry.size:])
+            else:
+                section_data += data
 
         self.Detail('GetData: %d entries, total size %#x' %
                     (len(self._entries), len(section_data)))
@@ -348,7 +385,8 @@
         """Get the contents of an entry
 
         This builds the contents of the section, stores this as the contents of
-        the section and returns it
+        the section and returns it. If the section has a filename, the data is
+        written there also.
 
         Args:
             required: True if the data must be present, False if it is OK to
@@ -363,6 +401,8 @@
         if data is None:
             return None
         self.SetContents(data)
+        if self._filename:
+            tools.write_file(tools.get_output_filename(self._filename), data)
         return data
 
     def GetOffsets(self):
@@ -439,12 +479,13 @@
                             (entry.offset, entry.offset, entry.size, entry.size,
                              self._node.path, self._skip_at_start,
                              self._skip_at_start, max_size, max_size))
-            if entry.offset < offset and entry.size:
-                entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' "
-                            "ending at %#x (%d)" %
-                            (entry.offset, entry.offset, prev_name, offset, offset))
-            offset = entry.offset + entry.size
-            prev_name = entry.GetPath()
+            if not entry.overlap:
+                if entry.offset < offset and entry.size:
+                    entry.Raise("Offset %#x (%d) overlaps with previous entry '%s' ending at %#x (%d)" %
+                                (entry.offset, entry.offset, prev_name, offset,
+                                 offset))
+                offset = entry.offset + entry.size
+                prev_name = entry.GetPath()
 
     def WriteSymbols(self, section):
         """Write symbol values into binary files for access at run time"""
@@ -662,10 +703,13 @@
 
     def GetEntryContents(self, skip_entry=None):
         """Call ObtainContents() for each entry in the section
+
+        Note that this may set entry.absent to True if the entry is not
+        actually needed
         """
         def _CheckDone(entry):
             if entry != skip_entry:
-                if not entry.ObtainContents():
+                if entry.ObtainContents() is False:
                     next_todo.append(entry)
             return entry
 
@@ -706,6 +750,10 @@
                        todo)
         return True
 
+    def drop_absent(self):
+        """Drop entries which are absent"""
+        self._entries = {n: e for n, e in self._entries.items() if not e.absent}
+
     def _SetEntryOffsetSize(self, name, offset, size):
         """Set the offset and size of an entry
 
@@ -846,7 +894,8 @@
     def CheckMissing(self, missing_list):
         """Check if any entries in this section have missing external blobs
 
-        If there are missing blobs, the entries are added to the list
+        If there are missing (non-optional) blobs, the entries are added to the
+        list
 
         Args:
             missing_list: List of Entry objects to be added to
@@ -865,6 +914,17 @@
         for entry in self._entries.values():
             entry.CheckFakedBlobs(faked_blobs_list)
 
+    def CheckOptional(self, optional_list):
+        """Check the section for missing but optional external blobs
+
+        If there are missing (optional) blobs, the entries are added to the list
+
+        Args:
+            optional_list (list): List of Entry objects to be added to
+        """
+        for entry in self._entries.values():
+            entry.CheckOptional(optional_list)
+
     def check_missing_bintools(self, missing_list):
         """Check if any entries in this section have missing bintools
 
@@ -931,3 +991,12 @@
         super().AddBintools(btools)
         for entry in self._entries.values():
             entry.AddBintools(btools)
+
+    def read_elf_segments(self):
+        entries = self.GetEntries()
+
+        # If the section only has one entry, see if it can provide ELF segments
+        if len(entries) == 1:
+            for entry in entries.values():
+                return entry.read_elf_segments()
+        return None
diff --git a/tools/binman/etype/tee_os.py b/tools/binman/etype/tee_os.py
index 6ce4b67..5529727 100644
--- a/tools/binman/etype/tee_os.py
+++ b/tools/binman/etype/tee_os.py
@@ -4,19 +4,93 @@
 # Entry-type module for OP-TEE Trusted OS firmware blob
 #
 
+import struct
+
 from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg
+from binman import elf
 
 class Entry_tee_os(Entry_blob_named_by_arg):
     """Entry containing an OP-TEE Trusted OS (TEE) blob
 
     Properties / Entry arguments:
         - tee-os-path: Filename of file to read into entry. This is typically
-            called tee-pager.bin
+            called tee.bin or tee.elf
 
     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/OP-TEE/optee_os for more information about OP-TEE.
+
+    Note that if the file is in ELF format, it must go in a FIT. In that case,
+    this entry will mark itself as absent, providing the data only through the
+    read_elf_segments() method.
+
+    Marking this entry as absent means that it if is used in the wrong context
+    it can be automatically dropped. Thus it is possible to add an OP-TEE entry
+    like this::
+
+        binman {
+            tee-os {
+            };
+        };
+
+    and pass either an ELF or plain binary in with -a tee-os-path <filename>
+    and have binman do the right thing:
+
+       - include the entry if tee.bin is provided and it does NOT have the v1
+         header
+       - drop it otherwise
+
+    When used within a FIT, we can do::
+
+        binman {
+            fit {
+                tee-os {
+                };
+            };
+        };
+
+    which will split the ELF into separate nodes for each segment, if an ELF
+    file is provided (see :ref:`etype_fit`), or produce a single node if the
+    OP-TEE binary v1 format is provided (see optee_doc_) .
+
+    .. _optee_doc: https://optee.readthedocs.io/en/latest/architecture/core.html#partitioning-of-the-binary
     """
     def __init__(self, section, etype, node):
         super().__init__(section, etype, node, 'tee-os')
         self.external = True
+
+    @staticmethod
+    def is_optee_bin_v1(data):
+        return len(data) >= 8 and data[0:5] == b'OPTE\x01'
+
+    def ObtainContents(self, fake_size=0):
+        result = super().ObtainContents(fake_size)
+        if not self.missing:
+            # If using the flat binary (without the OP-TEE header), then it is
+            # just included as a blob. But if it is an ELF or usees the v1
+            # binary header, then the FIT implementation will call
+            # read_elf_segments() to get the segment information
+            if elf.is_valid(self.data):
+                self.mark_absent('uses Elf format which must be in a FIT')
+            elif self.is_optee_bin_v1(self.data):
+                # The FIT implementation will call read_elf_segments() to get
+                # the segment information
+                self.mark_absent('uses v1 format which must be in a FIT')
+        return result
+
+    def read_elf_segments(self):
+        data = self.GetData()
+        if self.is_optee_bin_v1(data):
+            # OP-TEE v1 format (tee.bin)
+            init_sz, start_hi, start_lo, _, paged_sz = (
+                struct.unpack_from('<5I', data, 0x8))
+            if paged_sz != 0:
+                self.Raise("OP-TEE paged mode not supported")
+            e_entry = (start_hi << 32) + start_lo
+            p_addr = e_entry
+            p_data = data[0x1c:]
+            if len(p_data) != init_sz:
+                self.Raise("Invalid OP-TEE file: size mismatch (expected %#x, have %#x)" %
+                           (init_sz, len(p_data)))
+            return [[0, p_addr, p_data]], e_entry
+        return None
diff --git a/tools/binman/etype/u_boot.py b/tools/binman/etype/u_boot.py
index e8d180a..d5639ee 100644
--- a/tools/binman/etype/u_boot.py
+++ b/tools/binman/etype/u_boot.py
@@ -18,11 +18,7 @@
     to relocate itself at runtime. The binary typically includes a device tree
     blob at the end of it.
 
-    U-Boot can access binman symbols at runtime. See:
-
-        'Access to binman entry offsets at run time (fdt)'
-
-    in the binman README for more information.
+    U-Boot can access binman symbols at runtime. See :ref:`binman_fdt`.
 
     Note that this entry is automatically replaced with u-boot-expanded unless
     --no-expanded is used or the node has a 'no-expanded' property.
diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py
index d1aa3b4..7f710c8 100644
--- a/tools/binman/etype/u_boot_spl.py
+++ b/tools/binman/etype/u_boot_spl.py
@@ -21,9 +21,7 @@
     to run from the correct address if direct flash execution is possible (e.g.
     on x86 devices).
 
-    SPL can access binman symbols at runtime. See:
-
-        'Access to binman entry offsets at run time (symbols)'
+    SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
     in the binman README for more information.
 
@@ -36,7 +34,6 @@
     def __init__(self, section, etype, node):
         super().__init__(section, etype, node, auto_write_symbols=True)
         self.elf_fname = 'spl/u-boot-spl'
-        self.auto_write_symbols = True
 
     def GetDefaultFilename(self):
         return 'spl/u-boot-spl.bin'
diff --git a/tools/binman/etype/u_boot_spl_nodtb.py b/tools/binman/etype/u_boot_spl_nodtb.py
index 50a126d..e7ec329 100644
--- a/tools/binman/etype/u_boot_spl_nodtb.py
+++ b/tools/binman/etype/u_boot_spl_nodtb.py
@@ -21,9 +21,7 @@
     expands to a section containing u-boot-spl-dtb, u-boot-spl-bss-pad and
     u-boot-spl-dtb
 
-    SPL can access binman symbols at runtime. See:
-
-        'Access to binman entry offsets at run time (symbols)'
+    SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
     in the binman README for more information.
 
diff --git a/tools/binman/etype/u_boot_tpl.py b/tools/binman/etype/u_boot_tpl.py
index 1883a2b..397b9f8 100644
--- a/tools/binman/etype/u_boot_tpl.py
+++ b/tools/binman/etype/u_boot_tpl.py
@@ -21,9 +21,7 @@
     address in SRAM, or written to run from the correct address if direct
     flash execution is possible (e.g. on x86 devices).
 
-    SPL can access binman symbols at runtime. See:
-
-        'Access to binman entry offsets at run time (symbols)'
+    SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
     in the binman README for more information.
 
diff --git a/tools/binman/etype/u_boot_tpl_nodtb.py b/tools/binman/etype/u_boot_tpl_nodtb.py
index 7e08e58..9bb2b5d 100644
--- a/tools/binman/etype/u_boot_tpl_nodtb.py
+++ b/tools/binman/etype/u_boot_tpl_nodtb.py
@@ -21,9 +21,7 @@
     expands to a section containing u-boot-tpl-dtb, u-boot-tpl-bss-pad and
     u-boot-tpl-dtb
 
-    TPL can access binman symbols at runtime. See:
-
-        'Access to binman entry offsets at run time (symbols)'
+    TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
     in the binman README for more information.
 
diff --git a/tools/binman/etype/u_boot_vpl.py b/tools/binman/etype/u_boot_vpl.py
index 62e5969..31d7e83 100644
--- a/tools/binman/etype/u_boot_vpl.py
+++ b/tools/binman/etype/u_boot_vpl.py
@@ -21,9 +21,7 @@
     address in SRAM, or written to run from the correct address if direct
     flash execution is possible (e.g. on x86 devices).
 
-    SPL can access binman symbols at runtime. See:
-
-        'Access to binman entry offsets at run time (symbols)'
+    SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
     in the binman README for more information.
 
diff --git a/tools/binman/etype/u_boot_vpl_nodtb.py b/tools/binman/etype/u_boot_vpl_nodtb.py
index db3d8a9..64c2767 100644
--- a/tools/binman/etype/u_boot_vpl_nodtb.py
+++ b/tools/binman/etype/u_boot_vpl_nodtb.py
@@ -21,11 +21,7 @@
     expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
     u-boot-vpl-dtb
 
-    VPL can access binman symbols at runtime. See:
-
-        'Access to binman entry offsets at run time (symbols)'
-
-    in the binman README for more information.
+    VPL can access binman symbols at runtime. See :ref:`binman_fdt`.
 
     The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
     binman uses that to look up symbols to write into the VPL binary.
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 62ee86b..be0aea4 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -112,6 +112,8 @@
 # Supported compression bintools
 COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
 
+TEE_ADDR = 0x5678
+
 class TestFunctional(unittest.TestCase):
     """Functional tests for binman
 
@@ -219,6 +221,9 @@
         TestFunctional._MakeInputFile('tee.elf',
             tools.read_file(cls.ElfTestFile('elf_sections')))
 
+        # Newer OP_TEE file in v1 binary format
+        cls.make_tee_bin('tee.bin')
+
         cls.comp_bintools = {}
         for name in COMP_BINTOOLS:
             cls.comp_bintools[name] = bintool.Bintool.create(name)
@@ -644,6 +649,14 @@
     def ElfTestFile(cls, fname):
         return os.path.join(cls._elf_testdir, fname)
 
+    @classmethod
+    def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
+        init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
+        data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
+                                            dummy, paged_sz) + U_BOOT_DATA
+        data += extra_data
+        TestFunctional._MakeInputFile(fname, data)
+
     def AssertInList(self, grep_list, target):
         """Assert that at least one of a list of things is in a target
 
@@ -6077,5 +6090,225 @@
             'Cannot write symbols to an ELF file without Python elftools',
             str(exc.exception))
 
+    def testSectionFilename(self):
+        """Check writing of section contents to a file"""
+        data = self._DoReadFile('261_section_fname.dts')
+        expected = (b'&&' + U_BOOT_DATA + b'&&&' +
+                    tools.get_bytes(ord('!'), 7) +
+                    U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
+        self.assertEqual(expected, data)
+
+        sect_fname = tools.get_output_filename('outfile.bin')
+        self.assertTrue(os.path.exists(sect_fname))
+        sect_data = tools.read_file(sect_fname)
+        self.assertEqual(U_BOOT_DATA, sect_data)
+
+    def testAbsent(self):
+        """Check handling of absent entries"""
+        data = self._DoReadFile('262_absent.dts')
+        self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
+
+    def testPackTeeOsOptional(self):
+        """Test that an image with an optional TEE binary can be created"""
+        entry_args = {
+            'tee-os-path': 'tee.elf',
+        }
+        data = self._DoReadFileDtb('263_tee_os_opt.dts',
+                                   entry_args=entry_args)[0]
+        self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
+
+    def checkFitTee(self, dts, tee_fname):
+        """Check that a tee-os entry works and returns data
+
+        Args:
+            dts (str): Device tree filename to use
+            tee_fname (str): filename containing tee-os
+
+        Returns:
+            bytes: Image contents
+        """
+        if not elf.ELF_TOOLS:
+            self.skipTest('Python elftools not available')
+        entry_args = {
+            'of-list': 'test-fdt1 test-fdt2',
+            'default-dt': 'test-fdt2',
+            'tee-os-path': tee_fname,
+        }
+        test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
+        data = self._DoReadFileDtb(dts, entry_args=entry_args,
+                                   extra_indirs=[test_subdir])[0]
+        return data
+
+    def testFitTeeOsOptionalFit(self):
+        """Test an image with a FIT with an optional OP-TEE binary"""
+        data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
+
+        # There should be only one node, holding the data set up in SetUpClass()
+        # for tee.bin
+        dtb = fdt.Fdt.FromData(data)
+        dtb.Scan()
+        node = dtb.GetNode('/images/tee-1')
+        self.assertEqual(TEE_ADDR,
+                         fdt_util.fdt32_to_cpu(node.props['load'].value))
+        self.assertEqual(TEE_ADDR,
+                         fdt_util.fdt32_to_cpu(node.props['entry'].value))
+        self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
+
+    def testFitTeeOsOptionalFitBad(self):
+        """Test an image with a FIT with an optional OP-TEE binary"""
+        with self.assertRaises(ValueError) as exc:
+            self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
+        self.assertIn(
+            "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
+            str(exc.exception))
+
+    def testFitTeeOsBad(self):
+        """Test an OP-TEE binary with wrong formats"""
+        self.make_tee_bin('tee.bad1', 123)
+        with self.assertRaises(ValueError) as exc:
+            self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
+        self.assertIn(
+            "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
+            str(exc.exception))
+
+        self.make_tee_bin('tee.bad2', 0, b'extra data')
+        with self.assertRaises(ValueError) as exc:
+            self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
+        self.assertIn(
+            "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
+            str(exc.exception))
+
+    def testExtblobOptional(self):
+        """Test an image with an external blob that is optional"""
+        with test_util.capture_sys_output() as (stdout, stderr):
+            data = self._DoReadFile('266_blob_ext_opt.dts')
+        self.assertEqual(REFCODE_DATA, data)
+        err = stderr.getvalue()
+        self.assertRegex(
+            err,
+            "Image '.*' is missing external blobs but is still functional: missing")
+
+    def testSectionInner(self):
+        """Test an inner section with a size"""
+        data = self._DoReadFile('267_section_inner.dts')
+        expected = U_BOOT_DATA + tools.get_bytes(0, 12)
+        self.assertEqual(expected, data)
+
+    def testNull(self):
+        """Test an image with a null entry"""
+        data = self._DoReadFile('268_null.dts')
+        self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
+
+    def testOverlap(self):
+        """Test an image with a overlapping entry"""
+        data = self._DoReadFile('269_overlap.dts')
+        self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
+
+        image = control.images['image']
+        entries = image.GetEntries()
+
+        self.assertIn('inset', entries)
+        inset = entries['inset']
+        self.assertEqual(1, inset.offset);
+        self.assertEqual(1, inset.image_pos);
+        self.assertEqual(2, inset.size);
+
+    def testOverlapNull(self):
+        """Test an image with a null overlap"""
+        data = self._DoReadFile('270_overlap_null.dts')
+        self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
+
+        # Check the FMAP
+        fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
+        self.assertEqual(4, fhdr.nareas)
+        fiter = iter(fentries)
+
+        fentry = next(fiter)
+        self.assertEqual(b'SECTION', fentry.name)
+        self.assertEqual(0, fentry.offset)
+        self.assertEqual(len(U_BOOT_DATA), fentry.size)
+        self.assertEqual(0, fentry.flags)
+
+        fentry = next(fiter)
+        self.assertEqual(b'U_BOOT', fentry.name)
+        self.assertEqual(0, fentry.offset)
+        self.assertEqual(len(U_BOOT_DATA), fentry.size)
+        self.assertEqual(0, fentry.flags)
+
+        # Make sure that the NULL entry appears in the FMAP
+        fentry = next(fiter)
+        self.assertEqual(b'NULL', fentry.name)
+        self.assertEqual(1, fentry.offset)
+        self.assertEqual(2, fentry.size)
+        self.assertEqual(0, fentry.flags)
+
+        fentry = next(fiter)
+        self.assertEqual(b'FMAP', fentry.name)
+        self.assertEqual(len(U_BOOT_DATA), fentry.offset)
+
+    def testOverlapBad(self):
+        """Test an image with a bad overlapping entry"""
+        with self.assertRaises(ValueError) as exc:
+            self._DoReadFile('271_overlap_bad.dts')
+        self.assertIn(
+            "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
+            str(exc.exception))
+
+    def testOverlapNoOffset(self):
+        """Test an image with a bad overlapping entry"""
+        with self.assertRaises(ValueError) as exc:
+            self._DoReadFile('272_overlap_no_size.dts')
+        self.assertIn(
+            "Node '/binman/inset': 'fill' entry is missing properties: size",
+            str(exc.exception))
+
+    def testBlobSymbol(self):
+        """Test a blob with symbols read from an ELF file"""
+        elf_fname = self.ElfTestFile('blob_syms')
+        TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
+        TestFunctional._MakeInputFile('blob_syms.bin',
+            tools.read_file(self.ElfTestFile('blob_syms.bin')))
+
+        data = self._DoReadFile('273_blob_symbol.dts')
+
+        syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
+        addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
+        self.assertEqual(syms['_binman_sym_magic'].address, addr)
+        self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
+        self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
+
+        sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
+        expected = sym_values
+        self.assertEqual(expected, data[:len(expected)])
+
+    def testOffsetFromElf(self):
+        """Test a blob with symbols read from an ELF file"""
+        elf_fname = self.ElfTestFile('blob_syms')
+        TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
+        TestFunctional._MakeInputFile('blob_syms.bin',
+            tools.read_file(self.ElfTestFile('blob_syms.bin')))
+
+        data = self._DoReadFile('274_offset_from_elf.dts')
+
+        syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
+        base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
+
+        image = control.images['image']
+        entries = image.GetEntries()
+
+        self.assertIn('inset', entries)
+        inset = entries['inset']
+
+        self.assertEqual(base + 4, inset.offset);
+        self.assertEqual(base + 4, inset.image_pos);
+        self.assertEqual(4, inset.size);
+
+        self.assertIn('inset2', entries)
+        inset = entries['inset2']
+        self.assertEqual(base + 8, inset.offset);
+        self.assertEqual(base + 8, inset.image_pos);
+        self.assertEqual(4, inset.size);
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/image.py b/tools/binman/image.py
index 6d4bff5..b84dd21 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -94,9 +94,6 @@
 
     def ReadNode(self):
         super().ReadNode()
-        filename = fdt_util.GetString(self._node, 'filename')
-        if filename:
-            self._filename = filename
         self.allow_repack = fdt_util.GetBool(self._node, 'allow-repack')
         self._symlink = fdt_util.GetString(self._node, 'symlink')
 
diff --git a/tools/binman/test/261_section_fname.dts b/tools/binman/test/261_section_fname.dts
new file mode 100644
index 0000000..790381e
--- /dev/null
+++ b/tools/binman/test/261_section_fname.dts
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		pad-byte = <0x26>;
+		size = <0x20>;
+		section@0 {
+			size = <0x10>;
+			pad-byte = <0x21>;
+			pad-before = <2>;
+			pad-after = <3>;
+
+			section {
+				filename = "outfile.bin";
+				u-boot {
+				};
+			};
+		};
+		section@1 {
+			u-boot {
+			};
+		};
+	};
+};
diff --git a/tools/binman/test/262_absent.dts b/tools/binman/test/262_absent.dts
new file mode 100644
index 0000000..2ab8766
--- /dev/null
+++ b/tools/binman/test/262_absent.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+
+		_testing {
+			set-to-absent;
+		};
+
+		u-boot-img {
+		};
+	};
+};
diff --git a/tools/binman/test/263_tee_os_opt.dts b/tools/binman/test/263_tee_os_opt.dts
new file mode 100644
index 0000000..2e4ec24
--- /dev/null
+++ b/tools/binman/test/263_tee_os_opt.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+		tee-os {
+			/*
+			 * this results in nothing being added since only the
+			 * .bin format is supported by this etype, unless it is
+			 * part of a FIT
+			 */
+		};
+		u-boot-img {
+		};
+	};
+};
diff --git a/tools/binman/test/264_tee_os_opt_fit.dts b/tools/binman/test/264_tee_os_opt_fit.dts
new file mode 100644
index 0000000..ae44b43
--- /dev/null
+++ b/tools/binman/test/264_tee_os_opt_fit.dts
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		fit {
+			description = "test-desc";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				@tee-SEQ {
+					fit,operation = "split-elf";
+					description = "TEE";
+					type = "tee";
+					arch = "arm64";
+					os = "tee";
+					compression = "none";
+					fit,load;
+					fit,entry;
+					fit,data;
+
+					tee-os {
+					};
+				};
+			};
+		};
+	};
+};
diff --git a/tools/binman/test/265_tee_os_opt_fit_bad.dts b/tools/binman/test/265_tee_os_opt_fit_bad.dts
new file mode 100644
index 0000000..7fa363c
--- /dev/null
+++ b/tools/binman/test/265_tee_os_opt_fit_bad.dts
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		fit {
+			description = "test-desc";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				@tee-SEQ {
+					fit,operation = "split-elf";
+					description = "TEE";
+					type = "tee";
+					arch = "arm64";
+					os = "tee";
+					compression = "none";
+					fit,load;
+					fit,entry;
+					fit,data;
+
+					tee-os {
+					};
+
+					/*
+					 * mess up the ELF data by adding
+					 * another bit of data at the end
+					 */
+					u-boot {
+					};
+				};
+			};
+		};
+	};
+};
diff --git a/tools/binman/test/266_blob_ext_opt.dts b/tools/binman/test/266_blob_ext_opt.dts
new file mode 100644
index 0000000..7171531
--- /dev/null
+++ b/tools/binman/test/266_blob_ext_opt.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		ok {
+			type = "blob-ext";
+			filename = "refcode.bin";
+		};
+
+		missing {
+			type = "blob-ext";
+			filename = "missing.bin";
+			optional;
+		};
+	};
+};
diff --git a/tools/binman/test/267_section_inner.dts b/tools/binman/test/267_section_inner.dts
new file mode 100644
index 0000000..f6faab3
--- /dev/null
+++ b/tools/binman/test/267_section_inner.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		section {
+			size = <0x10>;
+			u-boot {
+			};
+		};
+	};
+};
diff --git a/tools/binman/test/268_null.dts b/tools/binman/test/268_null.dts
new file mode 100644
index 0000000..3824ba8
--- /dev/null
+++ b/tools/binman/test/268_null.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		pad-byte = <0xff>;
+		u-boot {
+		};
+		null {
+			size = <4>;
+		};
+		u-boot-img {
+		};
+	};
+};
diff --git a/tools/binman/test/269_overlap.dts b/tools/binman/test/269_overlap.dts
new file mode 100644
index 0000000..f949b8b
--- /dev/null
+++ b/tools/binman/test/269_overlap.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+
+		inset {
+			type = "fill";
+			fill-byte = [61];
+			offset = <1>;
+			size = <2>;
+			overlap;
+		};
+	};
+};
diff --git a/tools/binman/test/270_overlap_null.dts b/tools/binman/test/270_overlap_null.dts
new file mode 100644
index 0000000..feed9ec
--- /dev/null
+++ b/tools/binman/test/270_overlap_null.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		section {
+			u-boot {
+			};
+
+			null {
+				offset = <1>;
+				size = <2>;
+				overlap;
+			};
+		};
+
+		fmap {
+		};
+	};
+};
diff --git a/tools/binman/test/271_overlap_bad.dts b/tools/binman/test/271_overlap_bad.dts
new file mode 100644
index 0000000..f281802
--- /dev/null
+++ b/tools/binman/test/271_overlap_bad.dts
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+
+		inset {
+			type = "fill";
+			fill-byte = [61];
+			offset = <0x10>;
+			size = <2>;
+			overlap;
+		};
+	};
+};
diff --git a/tools/binman/test/272_overlap_no_size.dts b/tools/binman/test/272_overlap_no_size.dts
new file mode 100644
index 0000000..4517536
--- /dev/null
+++ b/tools/binman/test/272_overlap_no_size.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+
+		inset {
+			type = "fill";
+			fill-byte = [61];
+			overlap;
+		};
+	};
+};
diff --git a/tools/binman/test/273_blob_symbol.dts b/tools/binman/test/273_blob_symbol.dts
new file mode 100644
index 0000000..87b0aba
--- /dev/null
+++ b/tools/binman/test/273_blob_symbol.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		blob {
+			filename = "blob_syms.bin";
+			write-symbols;
+			elf-filename = "blob_syms";
+			elf-base-sym = "__my_start_sym";
+		};
+
+		inset {
+			type = "null";
+			offset = <4>;
+			size = <8>;
+			overlap;
+		};
+	};
+};
diff --git a/tools/binman/test/274_offset_from_elf.dts b/tools/binman/test/274_offset_from_elf.dts
new file mode 100644
index 0000000..e3372fc
--- /dev/null
+++ b/tools/binman/test/274_offset_from_elf.dts
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		blob: blob {
+			filename = "blob_syms.bin";
+			elf-filename = "blob_syms";
+			elf-base-sym = "__my_start_sym";
+		};
+
+		inset {
+			type = "null";
+			offset-from-elf = <&blob>, "val3", <0>;
+			size = <4>;
+			overlap;
+		};
+
+		inset2 {
+			type = "null";
+			offset-from-elf = <&blob>, "val3", <4>;
+			size = <4>;
+			overlap;
+		};
+	};
+};
diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile
index bea8567..cd66a30 100644
--- a/tools/binman/test/Makefile
+++ b/tools/binman/test/Makefile
@@ -30,11 +30,12 @@
 LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds
 LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
 LDS_EFL_SECTIONS := -T $(SRC)elf_sections.lds
+LDS_BLOB := -T $(SRC)blob_syms.lds
 
 TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \
 	u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \
 	u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \
-	u_boot_binman_embed u_boot_binman_embed_sm elf_sections
+	u_boot_binman_embed u_boot_binman_embed_sm elf_sections blob_syms.bin
 
 all: $(TARGETS)
 
@@ -71,6 +72,12 @@
 u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED)
 u_boot_binman_embed_sm: u_boot_binman_embed_sm.c
 
+blob_syms.bin: blob_syms
+	$(OBJCOPY) -O binary $< -R .note.gnu.build-id $@
+
+blob_syms: CFLAGS += $(LDS_BLOB)
+blob_syms: blob_syms.c
+
 elf_sections: CFLAGS += $(LDS_EFL_SECTIONS)
 elf_sections: elf_sections.c
 
diff --git a/tools/binman/test/blob_syms.c b/tools/binman/test/blob_syms.c
new file mode 100644
index 0000000..d652c79
--- /dev/null
+++ b/tools/binman/test/blob_syms.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Google, Inc
+ *
+ * Simple program to create some binman symbols. This is used by binman tests.
+ */
+
+typedef unsigned long ulong;
+
+#include <linux/kconfig.h>
+#include <binman_sym.h>
+
+DECLARE_BINMAN_MAGIC_SYM;
+
+unsigned long val1 = 123;
+unsigned long val2 = 456;
+binman_sym_declare(unsigned long, inset, offset);
+unsigned long val3 = 789;
+unsigned long val4 = 999;
+binman_sym_declare(unsigned long, inset, size);
diff --git a/tools/binman/test/blob_syms.lds b/tools/binman/test/blob_syms.lds
new file mode 100644
index 0000000..787e38d
--- /dev/null
+++ b/tools/binman/test/blob_syms.lds
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2016 Google, Inc
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0x00000010;
+	_start = .;
+
+	. = ALIGN(4);
+	.text :
+	{
+		__my_start_sym = .;
+		*(.text*)
+	}
+
+	. = ALIGN(4);
+	.binman_sym_table : {
+		__binman_sym_start = .;
+		KEEP(*(SORT(.binman_sym*)));
+		__binman_sym_end = .;
+	}
+	.interp : { *(.interp*) }
+
+}
diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py
index d7c38ad..f343166 100644
--- a/tools/dtoc/fdt_util.py
+++ b/tools/dtoc/fdt_util.py
@@ -281,6 +281,34 @@
         value = [value]
     return [fdt32_to_cpu(v) for v in value]
 
+def GetPhandleNameOffset(node, propname):
+    """Get a <&phandle>, "string", <offset> value from a property
+
+    Args:
+        node: Node object to read from
+        propname: property name to read
+
+    Returns:
+        tuple:
+            Node object
+            str
+            int
+        or None if the property does not exist
+    """
+    prop = node.props.get(propname)
+    if not prop:
+        return None
+    value = prop.bytes
+    phandle = fdt32_to_cpu(value[:4])
+    node = node.GetFdt().LookupPhandle(phandle)
+    name = ''
+    for byte in value[4:]:
+        if not byte:
+            break
+        name += chr(byte)
+    val = fdt32_to_cpu(value[4 + len(name) + 1:])
+    return node, name, val
+
 def GetDatatype(node, propname, datatype):
     """Get a value of a given type from a property
 
diff --git a/tools/dtoc/test/dtoc_test_phandle.dts b/tools/dtoc/test/dtoc_test_phandle.dts
index a71acff..d9aa433 100644
--- a/tools/dtoc/test/dtoc_test_phandle.dts
+++ b/tools/dtoc/test/dtoc_test_phandle.dts
@@ -32,6 +32,7 @@
 		u-boot,dm-pre-reloc;
 		compatible = "source";
 		clocks = <&phandle &phandle_1 11 &phandle_2 12 13 &phandle>;
+		phandle-name-offset = <&phandle_2>, "fred", <123>;
 	};
 
 	phandle-source2 {
diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py
index 879ca2a..c62fcba 100755
--- a/tools/dtoc/test_dtoc.py
+++ b/tools/dtoc/test_dtoc.py
@@ -929,6 +929,7 @@
         self._check_strings(HEADER + '''
 struct dtd_source {
 \tstruct phandle_2_arg clocks[4];
+\tunsigned char	phandle_name_offset[13];
 };
 struct dtd_target {
 \tfdt32_t\t\tintval;
@@ -981,6 +982,8 @@
 \t\t\t{0, {11}},
 \t\t\t{1, {12, 13}},
 \t\t\t{4, {}},},
+\t.phandle_name_offset	= {0x0, 0x0, 0x0, 0x3, 0x66, 0x72, 0x65, 0x64,
+\t\t0x0, 0x0, 0x0, 0x0, 0x7b},
 };
 U_BOOT_DRVINFO(phandle_source) = {
 \t.name\t\t= "source",
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index a3e36ea..3b8ee00 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -795,6 +795,17 @@
         finally:
             tools.outdir= old_outdir
 
+    def test_get_phandle_name_offset(self):
+        val = fdt_util.GetPhandleNameOffset(self.node, 'missing')
+        self.assertIsNone(val)
+
+        dtb = fdt.FdtScan(find_dtb_file('dtoc_test_phandle.dts'))
+        node = dtb.GetNode('/phandle-source')
+        node, name, offset = fdt_util.GetPhandleNameOffset(node,
+                                                           'phandle-name-offset')
+        self.assertEqual('phandle3-target', node.name)
+        self.assertEqual('fred', name)
+        self.assertEqual(123, offset)
 
 def run_test_coverage(build_dir):
     """Run the tests and check that we get 100% coverage
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 923a975..8a18b1b 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -36,8 +36,10 @@
 
 	tfd = mmap_fdt(params->cmdname, tmpfile, size_inc, &ptr, &sbuf, true,
 		       false);
-	if (tfd < 0)
+	if (tfd < 0) {
+		fprintf(stderr, "Cannot map FDT file '%s'\n", tmpfile);
 		return -EIO;
+	}
 
 	if (params->keydest) {
 		struct stat dest_sbuf;
diff --git a/tools/image-host.c b/tools/image-host.c
index 4e0512b..4a24dee 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -1292,8 +1292,12 @@
 		ret = fit_image_add_verification_data(keydir, keyfile, keydest,
 				fit, noffset, comment, require_keys, engine_id,
 				cmdname, algo_name);
-		if (ret)
+		if (ret) {
+			printf("Can't add verification data for node '%s' (%s)\n",
+			       fdt_get_name(fit, noffset, NULL),
+			       fdt_strerror(ret));
 			return ret;
+		}
 	}
 
 	/* If there are no keys, we can't sign configurations */
diff --git a/tools/patman/.checkpatch.conf b/tools/patman/.checkpatch.conf
new file mode 120000
index 0000000..c0e2020
--- /dev/null
+++ b/tools/patman/.checkpatch.conf
@@ -0,0 +1 @@
+../../.checkpatch.conf
\ No newline at end of file
diff --git a/tools/patman/checkpatch.py b/tools/patman/checkpatch.py
index 012c0d8..d1b902d 100644
--- a/tools/patman/checkpatch.py
+++ b/tools/patman/checkpatch.py
@@ -211,7 +211,7 @@
             stdout: Full output of checkpatch
     """
     chk = find_check_patch()
-    args = [chk, '--u-boot', '--strict']
+    args = [chk]
     if not use_tree:
         args.append('--no-tree')
     if show_types:
diff --git a/tools/proftool.c b/tools/proftool.c
index ea7d07a..b66ea55 100644
--- a/tools/proftool.c
+++ b/tools/proftool.c
@@ -81,14 +81,15 @@
 static void usage(void)
 {
 	fprintf(stderr,
-		"Usage: proftool -cds -v3 <cmd> <profdata>\n"
+		"Usage: proftool [-cmtv] <cmd> <profdata>\n"
 		"\n"
 		"Commands\n"
 		"   dump-ftrace\t\tDump out textual data in ftrace format\n"
 		"\n"
 		"Options:\n"
+		"   -c <cfg>\tSpecific config file\n"
 		"   -m <map>\tSpecify Systen.map file\n"
-		"   -t <trace>\tSpecific trace data file (from U-Boot)\n"
+		"   -t <fname>\tSpecify trace data file (from U-Boot 'trace calls')\n"
 		"   -v <0-4>\tSpecify verbosity\n");
 	exit(EXIT_FAILURE);
 }
@@ -162,7 +163,7 @@
 	if (!err)
 		return 1;
 	if (err != size) {
-		error("Cannot read profile file at pos %ld\n", ftell(fin));
+		error("Cannot read profile file at pos %lx\n", ftell(fin));
 		return -1;
 	}
 	return 0;
@@ -495,10 +496,17 @@
 	int missing_count = 0, skip_count = 0;
 	int i;
 
-	printf("# tracer: ftrace\n"
-		"#\n"
-		"#           TASK-PID   CPU#    TIMESTAMP  FUNCTION\n"
-		"#              | |      |          |         |\n");
+	printf("# tracer: function\n"
+	      "#\n"
+	      "# entries-in-buffer/entries-written: 140080/250280   #P:4\n"
+	      "#\n"
+	      "#                              _-----=> irqs-off\n"
+	      "#                             / _----=> need-resched\n"
+	      "#                            | / _---=> hardirq/softirq\n"
+	      "#                            || / _--=> preempt-depth\n"
+	      "#                            ||| /     delay\n"
+	      "#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION\n"
+	      "#              | |       |   ||||       |         |\n");
 	for (i = 0, call = call_list; i < call_count; i++, call++) {
 		struct func_info *func = find_func_by_offset(call->func);
 		ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
@@ -520,7 +528,7 @@
 			continue;
 		}
 
-		printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1,
+		printf("%16s-%-5d [000] ....  %lu.%06lu: ", "uboot", 1,
 		       time / 1000000, time % 1000000);
 
 		out_func(call->func, 0, " <- ");
@@ -562,23 +570,23 @@
 int main(int argc, char *argv[])
 {
 	const char *map_fname = "System.map";
-	const char *prof_fname = NULL;
-	const char *trace_config_fname = NULL;
+	const char *trace_fname = NULL;
+	const char *config_fname = NULL;
 	int opt;
 
 	verbose = 2;
-	while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) {
+	while ((opt = getopt(argc, argv, "c:m:t:v:")) != -1) {
 		switch (opt) {
-		case 'm':
-			map_fname = optarg;
+		case 'c':
+			config_fname = optarg;
 			break;
 
-		case 'p':
-			prof_fname = optarg;
+		case 'm':
+			map_fname = optarg;
 			break;
 
 		case 't':
-			trace_config_fname = optarg;
+			trace_fname = optarg;
 			break;
 
 		case 'v':
@@ -594,6 +602,5 @@
 		usage();
 
 	debug("Debug enabled\n");
-	return prof_tool(argc, argv, prof_fname, map_fname,
-			 trace_config_fname);
+	return prof_tool(argc, argv, trace_fname, map_fname, config_fname);
 }