Merge tag 'u-boot-at91-2025.07-a' of https://source.denx.de/u-boot/custodians/u-boot-at91 into next

First set of u-boot-at91 features for the 2025.07 cycle:

This feature set includes improvements on the atmel-quadspi driver, a
fix for the nand driver, and improvements on the pinctrl driver to be
able to use the Linux DT (also sync on the DT side as well).
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
index bd197cd..1f2766e 100644
--- a/.azure-pipelines.yml
+++ b/.azure-pipelines.yml
@@ -134,8 +134,11 @@
           export USER=azure
           virtualenv -p /usr/bin/python3 /tmp/venv
           . /tmp/venv/bin/activate
-          pip install -r test/py/requirements.txt
-          pip install -r tools/buildman/requirements.txt
+          pip install -r test/py/requirements.txt \
+            -r tools/binman/requirements.txt \
+            -r tools/buildman/requirements.txt \
+            -r tools/patman/requirements.txt \
+            -r tools/u_boot_pylib/requirements.txt
           export UBOOT_TRAVIS_BUILD_DIR=/tmp/tools-only
           export PYTHONPATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt
           export PATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}
@@ -163,9 +166,14 @@
       - script: |
           git config --global --add safe.directory $(work_dir)
           export USER=azure
-          pip install -r test/py/requirements.txt
-          pip install -r tools/buildman/requirements.txt
-          pip install asteval pylint==2.12.2 pyopenssl
+          virtualenv -p /usr/bin/python3 /tmp/venv
+          . /tmp/venv/bin/activate
+          pip install -r test/py/requirements.txt \
+            -r tools/binman/requirements.txt \
+            -r tools/buildman/requirements.txt \
+            -r tools/patman/requirements.txt \
+            -r tools/u_boot_pylib/requirements.txt \
+            asteval pylint==2.12.2 pyopenssl
           export PATH=${PATH}:~/.local/bin
           echo "[MASTER]" >> .pylintrc
           echo "load-plugins=pylint.extensions.docparams" >> .pylintrc
@@ -265,7 +273,13 @@
           if [ -n "\${BUILD_ENV}" ]; then
               export \${BUILD_ENV};
           fi
-          pip install -r tools/buildman/requirements.txt
+          virtualenv -p /usr/bin/python3 /tmp/venv
+          . /tmp/venv/bin/activate
+          pip install -r tools/binman/requirements.txt \
+            -r tools/buildman/requirements.txt \
+            -r test/py/requirements.txt \
+            -r tools/u_boot_pylib/requirements.txt \
+            pytest-azurepipelines
           tools/buildman/buildman -o \${UBOOT_TRAVIS_BUILD_DIR} -w -E -W -e --board \${TEST_PY_BD} \${OVERRIDE}
           cp /opt/grub/grub_x86.efi \${UBOOT_TRAVIS_BUILD_DIR}/
           cp /opt/grub/grub_x64.efi \${UBOOT_TRAVIS_BUILD_DIR}/
@@ -289,10 +303,6 @@
               /opt/coreboot/cbfstool \${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom remove -n fallback/payload;
               /opt/coreboot/cbfstool \${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom add-flat-binary -f \${UBOOT_TRAVIS_BUILD_DIR}/u-boot.bin -n fallback/payload -c LZMA -l 0x1110000 -e 0x1110000;
           fi
-          virtualenv -p /usr/bin/python3 /tmp/venv
-          . /tmp/venv/bin/activate
-          pip install -r test/py/requirements.txt
-          pip install pytest-azurepipelines
           export PATH=/opt/qemu/bin:/tmp/uboot-test-hooks/bin:\${PATH}
           export PYTHONPATH=/tmp/uboot-test-hooks/py/travis-ci
           # "\${var:+"-k \$var"}" expands to "" if \$var is empty, "-k \$var" if not
@@ -582,7 +592,10 @@
           # make environment variables available as tests are running inside a container
           export BUILDMAN="${BUILDMAN}"
           git config --global --add safe.directory ${WORK_DIR}
-          pip install -r tools/buildman/requirements.txt
+          virtualenv -p /usr/bin/python3 /tmp/venv
+          . /tmp/venv/bin/activate
+          pip install -r tools/binman/requirements.txt \
+            -r tools/buildman/requirements.txt
           EOF
           cat << "EOF" >> build.sh
           if [[ "${BUILDMAN}" != "" ]]; then
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 920f61e..e339c25 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -55,6 +55,11 @@
         wget -O /tmp/fip.bin https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/latest/tf-a/fip.bin;
         export BINMAN_INDIRS=/tmp;
       fi
+    # Prepare python environment
+    - virtualenv -p /usr/bin/python3 /tmp/venv;
+      . /tmp/venv/bin/activate;
+      pip install -r test/py/requirements.txt -r tools/binman/requirements.txt
+        -r tools/buildman/requirements.txt -r tools/u_boot_pylib/requirements.txt
 
   after_script:
     - cp -v /tmp/${TEST_PY_BD}/*.{html,css,xml} .
@@ -90,9 +95,6 @@
         /opt/coreboot/cbfstool ${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom remove -n fallback/payload;
         /opt/coreboot/cbfstool ${UBOOT_TRAVIS_BUILD_DIR}/coreboot.rom add-flat-binary -f ${UBOOT_TRAVIS_BUILD_DIR}/u-boot.bin -n fallback/payload -c LZMA -l 0x1110000 -e 0x1110000;
       fi
-    - virtualenv -p /usr/bin/python3 /tmp/venv
-    - . /tmp/venv/bin/activate
-    - pip install -r test/py/requirements.txt
     # "${var:+"-k $var"}" expands to "" if $var is empty, "-k $var" if not
     - export PATH=/opt/qemu/bin:/tmp/uboot-test-hooks/bin:${PATH};
       export PYTHONPATH=/tmp/uboot-test-hooks/py/travis-ci;
@@ -120,9 +122,13 @@
   tags:
     - ${HOST}
   script:
+    # Prepare python environment
+    - virtualenv -p /usr/bin/python3 /tmp/venv;
+      . /tmp/venv/bin/activate;
+      pip install -r tools/binman/requirements.txt
+        -r tools/buildman/requirements.txt
     - ret=0;
       git config --global --add safe.directory "${CI_PROJECT_DIR}";
-      pip install -r tools/buildman/requirements.txt;
       ./tools/buildman/buildman -o /tmp -PEWM -x xtensa || ret=$?;
       if [[ $ret -ne 0 ]]; then
         ./tools/buildman/buildman -o /tmp -seP;
@@ -179,8 +185,9 @@
       export USER=gitlab;
       virtualenv -p /usr/bin/python3 /tmp/venv;
       . /tmp/venv/bin/activate;
-      pip install -r test/py/requirements.txt;
-      pip install -r tools/buildman/requirements.txt;
+      pip install -r test/py/requirements.txt -r tools/binman/requirements.txt
+        -r tools/buildman/requirements.txt -r tools/patman/requirements.txt
+        -r tools/u_boot_pylib/requirements.txt;
       export UBOOT_TRAVIS_BUILD_DIR=/tmp/tools-only;
       export PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt";
       export PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}";
@@ -199,9 +206,11 @@
   extends: .testsuites
   script:
     - git config --global --add safe.directory "${CI_PROJECT_DIR}"
-    - pip install -r test/py/requirements.txt
-    - pip install -r tools/buildman/requirements.txt
-    - pip install asteval pylint==2.12.2 pyopenssl
+    - virtualenv -p /usr/bin/python3 /tmp/venv
+    - . /tmp/venv/bin/activate
+    - pip install -r test/py/requirements.txt -r tools/binman/requirements.txt
+        -r tools/buildman/requirements.txt -r tools/patman/requirements.txt
+        -r tools/u_boot_pylib/requirements.txt asteval pylint==2.12.2 pyopenssl
     - export PATH=${PATH}:~/.local/bin
     - echo "[MASTER]" >> .pylintrc
     - echo "load-plugins=pylint.extensions.docparams" >> .pylintrc
diff --git a/Makefile b/Makefile
index b32606b..d4fedd8 100644
--- a/Makefile
+++ b/Makefile
@@ -893,9 +893,6 @@
 libs-y += post/
 endif
 libs-$(CONFIG_$(PHASE_)UNIT_TEST) += test/
-libs-$(CONFIG_UT_ENV) += test/env/
-libs-$(CONFIG_UT_OPTEE) += test/optee/
-libs-$(CONFIG_UT_OVERLAY) += test/overlay/
 
 libs-y += $(if $(wildcard $(srctree)/board/$(BOARDDIR)/Makefile),board/$(BOARDDIR)/)
 
diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig
index a3ac490..1f8cb8e 100644
--- a/arch/arm/mach-k3/Kconfig
+++ b/arch/arm/mach-k3/Kconfig
@@ -159,6 +159,30 @@
 config NR_DRAM_BANKS
 	default 2
 
+config K3_REMOTEPROC_R5F
+	bool "Enable K3 Remoteproc driver for R5F"
+	depends on ARM64
+	imply REMOTEPROC_TI_K3_R5F
+	default y if (SOC_K3_AM62A7 || SOC_K3_AM654 || SOC_K3_J721E || SOC_K3_J784S4 || SOC_K3_J721S2 || SOC_K3_J722S || SOC_K3_AM62P5 || SOC_K3_AM642)
+
+config K3_REMOTEPROC_DSP
+	bool "Enable K3 Remoteproc driver for DSP"
+	depends on ARM64
+	imply REMOTEPROC_TI_K3_DSP
+	default y if (SOC_K3_AM62A7 || SOC_K3_J721E || SOC_K3_J784S4 || SOC_K3_J721S2 || SOC_K3_J722S)
+
+config K3_REMOTEPROC_M4F
+	bool "Enable K3 Remoteproc driver for M4F"
+	depends on ARM64
+	imply REMOTEPROC_TI_K3_M4F
+	default y if (SOC_K3_AM625 || SOC_K3_AM642)
+
+config K3_REMOTEPROC_PRU
+	bool "Enable K3 Remoteproc driver for PRU"
+	depends on ARM64
+	imply REMOTEPROC_TI_PRU
+	default y if (SOC_K3_AM642 || SOC_K3_AM654)
+
 if CPU_V7R
 source "arch/arm/mach-k3/r5/Kconfig"
 endif
diff --git a/board/comvetia/lxr2/lxr2.env b/board/comvetia/lxr2/lxr2.env
index ec21380..26ad4f1 100644
--- a/board/comvetia/lxr2/lxr2.env
+++ b/board/comvetia/lxr2/lxr2.env
@@ -2,7 +2,6 @@
 addip=setenv bootargs ${bootargs} ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}:${netdev}:off
 addmisc=setenv bootargs ${bootargs} ${miscargs}
 addmtd=run mtdnand;run mtdspi;setenv bootargs ${bootargs} ${mtdparts}
-altbootcmd=run swupdate
 bootcmd=run nandboot;run swupdate
 bootcount=2
 bootlimit=3
diff --git a/board/keymile/scripts/develop-common.txt b/board/keymile/scripts/develop-common.txt
index 1bdff2f..cfc6935 100644
--- a/board/keymile/scripts/develop-common.txt
+++ b/board/keymile/scripts/develop-common.txt
@@ -1,4 +1,3 @@
-altbootcmd=run ${subbootcmds}
 bootcmd=run ${subbootcmds}
 configure=run set_uimage; run set_tftppath; km_setboardid && run try_import_nfs_path && saveenv && reset
 subbootcmds=tftpfdt tftpkernel nfsargs add_default boot
diff --git a/board/keymile/scripts/ramfs-common.txt b/board/keymile/scripts/ramfs-common.txt
index 0a4a9c8..c86e626 100644
--- a/board/keymile/scripts/ramfs-common.txt
+++ b/board/keymile/scripts/ramfs-common.txt
@@ -1,6 +1,5 @@
 addramfs=setenv bootargs "${bootargs} phram.phram=rootfs${boot_bank},${rootfsaddr},${rootfssize}"
 boot_bank=-1
-altbootcmd=run ${subbootcmds}
 bootcmd=run ${subbootcmds}
 subbootcmds=save_and_reset_once tftpfdt tftpkernel setrootfsaddr tftpramfs flashargs add_default addpanic addramfs boot
 save_and_reset_once=setenv save_and_reset_once true && saveenv && reset
diff --git a/board/keymile/secu1/socfpga_secu.env b/board/keymile/secu1/socfpga_secu.env
index 147c417..6099988 100644
--- a/board/keymile/secu1/socfpga_secu.env
+++ b/board/keymile/secu1/socfpga_secu.env
@@ -1,4 +1,3 @@
-altbootcmd=run bootcmd;
 bootlimit=6
 bootnum=1
 bootretry=CONFIG_BOOT_RETRY_TIME
diff --git a/board/storopack/smegw01/smegw01.env b/board/storopack/smegw01/smegw01.env
index 93de866..c0d408e 100644
--- a/board/storopack/smegw01/smegw01.env
+++ b/board/storopack/smegw01/smegw01.env
@@ -12,21 +12,6 @@
 			setenv bootmenu_${emmc_priority} eMMC=run boot_emmc; \
 			setenv bootmenu_${sd_priority} SD=run boot_sd;
 #endif
-
-altbootcmd=
-	echo Performing rollback...;
-	if test "${mmcpart_committed}" = 1; then
-		setenv mmcpart 2;
-		setenv mmcpart_committed 2;
-	else
-		setenv mmcpart 1;
-		setenv mmcpart_committed 1;
-	fi;
-	setenv bootcount 0;
-	setenv upgrade_available;
-	setenv ustate 3;
-	saveenv;
-	run bootcmd;
 boot_emmc=setenv mmcdev_wanted 1; run persist_mmcdev; run bootcmd;
 boot_sd=setenv mmcdev_wanted 0; run persist_mmcdev; run bootcmd;
 bootcmd=
diff --git a/board/ti/am62px/am62px.env b/board/ti/am62px/am62px.env
index 7ef5407..2b2c938 100644
--- a/board/ti/am62px/am62px.env
+++ b/board/ti/am62px/am62px.env
@@ -1,6 +1,12 @@
 #include <env/ti/ti_common.env>
 #include <env/ti/mmc.env>
 
+#if CONFIG_CMD_REMOTEPROC
+#include <env/ti/k3_rproc.env>
+#endif
+
+rproc_fw_binaries= 0 /lib/firmware/am62p-mcu-r5f0_0-fw
+
 name_kern=Image
 console=ttyS2,115200n8
 args_all=setenv optargs ${optargs} earlycon=ns16550a,mmio32,0x02800000
diff --git a/board/ti/am62px/rm-cfg.yaml b/board/ti/am62px/rm-cfg.yaml
index caa2f7a..dc445a4 100644
--- a/board/ti/am62px/rm-cfg.yaml
+++ b/board/ti/am62px/rm-cfg.yaml
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0+
-# Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
+# Copyright (C) 2022-2025 Texas Instruments Incorporated - https://www.ti.com/
 #
 # Resource management configuration for AM62P
 #
@@ -244,7 +244,7 @@
             subhdr:
                 magic: 0x7B25
                 size: 8
-            resasg_entries_size: 984
+            resasg_entries_size: 1048
             reserved: 0
     resasg_entries:
         -
@@ -476,13 +476,13 @@
             host_id: 12
             reserved: 0
         -
-            start_resource: 45
+            start_resource: 44
             num_resource: 35
             type: 1802
             host_id: 35
             reserved: 0
         -
-            start_resource: 45
+            start_resource: 44
             num_resource: 35
             type: 1802
             host_id: 36
@@ -494,31 +494,31 @@
             host_id: 30
             reserved: 0
         -
-            start_resource: 14
+            start_resource: 13
             num_resource: 512
             type: 1805
             host_id: 12
             reserved: 0
         -
-            start_resource: 526
+            start_resource: 525
             num_resource: 256
             type: 1805
             host_id: 35
             reserved: 0
         -
-            start_resource: 526
+            start_resource: 525
             num_resource: 256
             type: 1805
             host_id: 36
             reserved: 0
         -
-            start_resource: 782
+            start_resource: 781
             num_resource: 128
             type: 1805
             host_id: 30
             reserved: 0
         -
-            start_resource: 910
+            start_resource: 909
             num_resource: 626
             type: 1805
             host_id: 128
@@ -645,17 +645,29 @@
             reserved: 0
         -
             start_resource: 19
-            num_resource: 64
+            num_resource: 32
             type: 1937
             host_id: 12
             reserved: 0
         -
             start_resource: 19
-            num_resource: 64
+            num_resource: 32
             type: 1937
             host_id: 36
             reserved: 0
         -
+            start_resource: 51
+            num_resource: 32
+            type: 1937
+            host_id: 12
+            reserved: 0
+        -
+            start_resource: 51
+            num_resource: 32
+            type: 1937
+            host_id: 30
+            reserved: 0
+        -
             start_resource: 83
             num_resource: 8
             type: 1938
@@ -699,17 +711,29 @@
             reserved: 0
         -
             start_resource: 118
-            num_resource: 16
+            num_resource: 6
             type: 1943
             host_id: 12
             reserved: 0
         -
             start_resource: 118
-            num_resource: 16
+            num_resource: 6
             type: 1943
             host_id: 36
             reserved: 0
         -
+            start_resource: 124
+            num_resource: 10
+            type: 1943
+            host_id: 12
+            reserved: 0
+        -
+            start_resource: 124
+            num_resource: 10
+            type: 1943
+            host_id: 30
+            reserved: 0
+        -
             start_resource: 134
             num_resource: 8
             type: 1944
@@ -765,17 +789,29 @@
             reserved: 0
         -
             start_resource: 19
-            num_resource: 8
+            num_resource: 4
             type: 1956
             host_id: 12
             reserved: 0
         -
             start_resource: 19
-            num_resource: 8
+            num_resource: 4
             type: 1956
             host_id: 36
             reserved: 0
         -
+            start_resource: 23
+            num_resource: 4
+            type: 1956
+            host_id: 12
+            reserved: 0
+        -
+            start_resource: 23
+            num_resource: 4
+            type: 1956
+            host_id: 30
+            reserved: 0
+        -
             start_resource: 27
             num_resource: 1
             type: 1957
@@ -861,17 +897,29 @@
             reserved: 0
         -
             start_resource: 19
-            num_resource: 16
+            num_resource: 6
             type: 1964
             host_id: 12
             reserved: 0
         -
             start_resource: 19
-            num_resource: 16
+            num_resource: 6
             type: 1964
             host_id: 36
             reserved: 0
         -
+            start_resource: 25
+            num_resource: 10
+            type: 1964
+            host_id: 12
+            reserved: 0
+        -
+            start_resource: 25
+            num_resource: 10
+            type: 1964
+            host_id: 30
+            reserved: 0
+        -
             start_resource: 20
             num_resource: 1
             type: 1965
diff --git a/board/ti/am62px/tifs-rm-cfg.yaml b/board/ti/am62px/tifs-rm-cfg.yaml
index a80a275..8026974 100644
--- a/board/ti/am62px/tifs-rm-cfg.yaml
+++ b/board/ti/am62px/tifs-rm-cfg.yaml
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0+
-# Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
+# Copyright (C) 2022-2025 Texas Instruments Incorporated - https://www.ti.com/
 #
 # Resource management configuration for AM62P
 #
@@ -244,7 +244,7 @@
             subhdr:
                 magic: 0x7B25
                 size: 8
-            resasg_entries_size: 840
+            resasg_entries_size: 904
             reserved: 0
     resasg_entries:
         -
@@ -423,13 +423,13 @@
                 reserved: 0
         -
                 start_resource: 44
-                num_resource: 36
+                num_resource: 35
                 type: 1802
                 host_id: 35
                 reserved: 0
         -
                 start_resource: 44
-                num_resource: 36
+                num_resource: 35
                 type: 1802
                 host_id: 36
                 reserved: 0
@@ -555,17 +555,29 @@
                 reserved: 0
         -
                 start_resource: 19
-                num_resource: 64
+                num_resource: 32
                 type: 1937
                 host_id: 12
                 reserved: 0
         -
                 start_resource: 19
-                num_resource: 64
+                num_resource: 32
                 type: 1937
                 host_id: 36
                 reserved: 0
         -
+                start_resource: 51
+                num_resource: 32
+                type: 1937
+                host_id: 12
+                reserved: 0
+        -
+                start_resource: 51
+                num_resource: 32
+                type: 1937
+                host_id: 30
+                reserved: 0
+        -
                 start_resource: 83
                 num_resource: 8
                 type: 1938
@@ -609,17 +621,29 @@
                 reserved: 0
         -
                 start_resource: 118
-                num_resource: 16
+                num_resource: 6
                 type: 1943
                 host_id: 12
                 reserved: 0
         -
                 start_resource: 118
-                num_resource: 16
+                num_resource: 6
                 type: 1943
                 host_id: 36
                 reserved: 0
         -
+                start_resource: 124
+                num_resource: 10
+                type: 1943
+                host_id: 12
+                reserved: 0
+        -
+                start_resource: 124
+                num_resource: 10
+                type: 1943
+                host_id: 30
+                reserved: 0
+        -
                 start_resource: 134
                 num_resource: 8
                 type: 1944
@@ -675,17 +699,29 @@
                 reserved: 0
         -
                 start_resource: 19
-                num_resource: 8
+                num_resource: 4
                 type: 1956
                 host_id: 12
                 reserved: 0
         -
                 start_resource: 19
-                num_resource: 8
+                num_resource: 4
                 type: 1956
                 host_id: 36
                 reserved: 0
         -
+                start_resource: 23
+                num_resource: 4
+                type: 1956
+                host_id: 12
+                reserved: 0
+        -
+                start_resource: 23
+                num_resource: 4
+                type: 1956
+                host_id: 30
+                reserved: 0
+        -
                 start_resource: 27
                 num_resource: 1
                 type: 1957
@@ -771,17 +807,29 @@
                 reserved: 0
         -
                 start_resource: 19
-                num_resource: 16
+                num_resource: 6
                 type: 1964
                 host_id: 12
                 reserved: 0
         -
                 start_resource: 19
-                num_resource: 16
+                num_resource: 6
                 type: 1964
                 host_id: 36
                 reserved: 0
         -
+                start_resource: 25
+                num_resource: 10
+                type: 1964
+                host_id: 12
+                reserved: 0
+        -
+                start_resource: 25
+                num_resource: 10
+                type: 1964
+                host_id: 30
+                reserved: 0
+        -
                 start_resource: 20
                 num_resource: 1
                 type: 1965
diff --git a/board/ti/am62x/am62x.env b/board/ti/am62x/am62x.env
index 078cc4b..60b5fd5 100644
--- a/board/ti/am62x/am62x.env
+++ b/board/ti/am62x/am62x.env
@@ -2,6 +2,12 @@
 #include <env/ti/mmc.env>
 #include <env/ti/k3_dfu.env>
 
+#if CONFIG_CMD_REMOTEPROC
+#include <env/ti/k3_rproc.env>
+#endif
+
+rproc_fw_binaries= 0 /lib/firmware/am62-mcu-m4f0_0-fw
+
 name_kern=Image
 console=ttyS2,115200n8
 args_all=setenv optargs ${optargs} earlycon=ns16550a,mmio32,0x02800000
diff --git a/board/ti/am64x/am64x.env b/board/ti/am64x/am64x.env
index 8ad805a..c8ab57b 100644
--- a/board/ti/am64x/am64x.env
+++ b/board/ti/am64x/am64x.env
@@ -2,6 +2,12 @@
 #include <env/ti/mmc.env>
 #include <env/ti/k3_dfu.env>
 
+#if CONFIG_CMD_REMOTEPROC
+#include <env/ti/k3_rproc.env>
+#endif
+
+rproc_fw_binaries= 0 /lib/firmware/am64-mcu-m4f0_0-fw 1 /lib/firmware/am64-main-r5f0_0-fw 2 /lib/firmware/am64-main-r5f0_1-fw 3 /lib/firmware/am64-main-r5f1_0-fw 4 /lib/firmware/am64-main-r5f1_1-fw
+
 name_kern=Image
 console=ttyS2,115200n8
 args_all=setenv optargs earlycon=ns16550a,mmio32,0x02800000 ${mtdparts}
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 1f9b269..2f275bd 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1602,6 +1602,7 @@
 config CMD_REMOTEPROC
 	bool "remoteproc"
 	depends on REMOTEPROC
+	default y if ARCH_K3
 	help
 	  Support for Remote Processor control
 
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 94e118f..7d67809 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -1287,6 +1287,7 @@
 
 config SPL_REMOTEPROC
 	bool "Support REMOTEPROCS"
+	default y if (CPU_V7R && ARCH_K3)
 	help
 	  Enable support for REMOTEPROCs in SPL. This permits to load
 	  a remote processor firmware in SPL.
diff --git a/configs/am335x_guardian_defconfig b/configs/am335x_guardian_defconfig
index 4059d07..c550e5e 100644
--- a/configs/am335x_guardian_defconfig
+++ b/configs/am335x_guardian_defconfig
@@ -77,6 +77,7 @@
 CONFIG_REGMAP=y
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_BOOTCOUNT_AM33XX_NVMEM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="setenv boot_syslinux_conf \"extlinux/extlinux-rollback.conf\"; run distro_bootcmd; setenv boot_syslinux_conf \"extlinux/extlinux.conf\"; run bootcmd_ubifs0;"
 CONFIG_CLK=y
 CONFIG_CLK_CCF=y
 CONFIG_CLK_TI_AM3_DPLL=y
diff --git a/configs/am62ax_evm_a53_defconfig b/configs/am62ax_evm_a53_defconfig
index bf6e963..315d660 100644
--- a/configs/am62ax_evm_a53_defconfig
+++ b/configs/am62ax_evm_a53_defconfig
@@ -41,7 +41,6 @@
 CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_CMD_MMC=y
 CONFIG_MMC_SPEED_MODE_SET=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
 CONFIG_OF_UPSTREAM=y
@@ -95,9 +94,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_SPL_DM_REGULATOR_GPIO=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
-CONFIG_REMOTEPROC_TI_K3_DSP=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/am62ax_evm_r5_defconfig b/configs/am62ax_evm_r5_defconfig
index 58cad17..3948ba22 100644
--- a/configs/am62ax_evm_r5_defconfig
+++ b/configs/am62ax_evm_r5_defconfig
@@ -48,7 +48,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 CONFIG_SPL_THERMAL=y
 CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_HUSH_PARSER=y
@@ -56,7 +55,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -98,7 +96,6 @@
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/am62px_evm_a53_defconfig b/configs/am62px_evm_a53_defconfig
index 30b4a24..a17b306 100644
--- a/configs/am62px_evm_a53_defconfig
+++ b/configs/am62px_evm_a53_defconfig
@@ -63,7 +63,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_CMD_EFIDEBUG=y
@@ -146,9 +145,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_SPL_DM_REGULATOR_GPIO=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
-CONFIG_REMOTEPROC_TI_K3_DSP=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_EMULATION=y
diff --git a/configs/am62px_evm_r5_defconfig b/configs/am62px_evm_r5_defconfig
index 54ea4bf..2438d2b 100644
--- a/configs/am62px_evm_r5_defconfig
+++ b/configs/am62px_evm_r5_defconfig
@@ -49,7 +49,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -61,7 +60,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -112,7 +110,6 @@
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/am62x_beagleplay_a53_defconfig b/configs/am62x_beagleplay_a53_defconfig
index a8a7316..cedd0f7 100644
--- a/configs/am62x_beagleplay_a53_defconfig
+++ b/configs/am62x_beagleplay_a53_defconfig
@@ -110,7 +110,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_DM_REGULATOR_TPS65219=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_EMULATION=y
diff --git a/configs/am62x_beagleplay_r5_defconfig b/configs/am62x_beagleplay_r5_defconfig
index bbc5541..5a465bf 100644
--- a/configs/am62x_beagleplay_r5_defconfig
+++ b/configs/am62x_beagleplay_r5_defconfig
@@ -50,14 +50,12 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_ASKENV=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -95,7 +93,6 @@
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/am62x_evm_a53_defconfig b/configs/am62x_evm_a53_defconfig
index 6527200..d9596cb 100644
--- a/configs/am62x_evm_a53_defconfig
+++ b/configs/am62x_evm_a53_defconfig
@@ -119,7 +119,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_SPL_DM_REGULATOR_GPIO=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_EMULATION=y
diff --git a/configs/am62x_evm_r5_defconfig b/configs/am62x_evm_r5_defconfig
index b47f2f2..8eb5940 100644
--- a/configs/am62x_evm_r5_defconfig
+++ b/configs/am62x_evm_r5_defconfig
@@ -53,7 +53,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -64,7 +63,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -110,7 +108,6 @@
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/am64x_evm_a53_defconfig b/configs/am64x_evm_a53_defconfig
index a501f3f..3f002ae 100644
--- a/configs/am64x_evm_a53_defconfig
+++ b/configs/am64x_evm_a53_defconfig
@@ -148,9 +148,6 @@
 CONFIG_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_TPS65219=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
-CONFIG_REMOTEPROC_TI_PRU=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_EMULATION=y
diff --git a/configs/am64x_evm_r5_defconfig b/configs/am64x_evm_r5_defconfig
index 0ceac16..b222bcd 100644
--- a/configs/am64x_evm_r5_defconfig
+++ b/configs/am64x_evm_r5_defconfig
@@ -59,7 +59,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -71,7 +70,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
@@ -138,7 +136,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_SPL_DM_REGULATOR_GPIO=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig
index e9b7367..12c4cb9 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -66,7 +66,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_MMC_SPEED_MODE_SET=y
 CONFIG_CMD_PCI=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_TIME=y
 CONFIG_MTDIDS_DEFAULT="nor0=47040000.spi.0"
@@ -144,8 +143,6 @@
 CONFIG_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
-CONFIG_REMOTEPROC_TI_PRU=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/am65x_evm_r5_defconfig b/configs/am65x_evm_r5_defconfig
index 289c41c..386749e 100644
--- a/configs/am65x_evm_r5_defconfig
+++ b/configs/am65x_evm_r5_defconfig
@@ -53,7 +53,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -65,7 +64,6 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -123,7 +121,6 @@
 CONFIG_RAM=y
 CONFIG_SPL_RAM=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/am65x_evm_r5_usbdfu_defconfig b/configs/am65x_evm_r5_usbdfu_defconfig
index 0b5eaeb..227de53 100644
--- a/configs/am65x_evm_r5_usbdfu_defconfig
+++ b/configs/am65x_evm_r5_usbdfu_defconfig
@@ -47,7 +47,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
@@ -55,7 +54,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -104,7 +102,6 @@
 CONFIG_RAM=y
 CONFIG_SPL_RAM=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYSRESET=y
diff --git a/configs/am65x_evm_r5_usbmsc_defconfig b/configs/am65x_evm_r5_usbmsc_defconfig
index ef2ff41..90a857b 100644
--- a/configs/am65x_evm_r5_usbmsc_defconfig
+++ b/configs/am65x_evm_r5_usbmsc_defconfig
@@ -47,14 +47,12 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
 CONFIG_CMD_ASKENV=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -101,7 +99,6 @@
 CONFIG_RAM=y
 CONFIG_SPL_RAM=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYSRESET=y
diff --git a/configs/bk4r1_defconfig b/configs/bk4r1_defconfig
index 3ed587a..2b72ec9 100644
--- a/configs/bk4r1_defconfig
+++ b/configs/bk4r1_defconfig
@@ -59,6 +59,7 @@
 CONFIG_ARP_TIMEOUT=500
 CONFIG_NETCONSOLE=y
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="led 5 on; boot"
 CONFIG_VYBRID_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
diff --git a/configs/brppt2_defconfig b/configs/brppt2_defconfig
index f02aef2..d468465 100644
--- a/configs/brppt2_defconfig
+++ b/configs/brppt2_defconfig
@@ -76,6 +76,7 @@
 # CONFIG_OF_TRANSLATE is not set
 # CONFIG_SPL_BLK is not set
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="setenv b_mode 0; run b_default;"
 CONFIG_SYS_I2C_MXC=y
 CONFIG_MMC_BROKEN_CD=y
 # CONFIG_SPL_DM_MMC is not set
diff --git a/configs/capricorn_cxg3_defconfig b/configs/capricorn_cxg3_defconfig
index 4832a79..10e0cbd 100644
--- a/configs/capricorn_cxg3_defconfig
+++ b/configs/capricorn_cxg3_defconfig
@@ -95,6 +95,7 @@
 CONFIG_SPL_DM=y
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_BOOTCOUNT_ENV=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SPL_CLK=y
 CONFIG_CLK_IMX8=y
 CONFIG_CPU=y
diff --git a/configs/display5_defconfig b/configs/display5_defconfig
index 765920b..55f9bba 100644
--- a/configs/display5_defconfig
+++ b/configs/display5_defconfig
@@ -96,6 +96,7 @@
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_BOUNCE_BUFFER=y
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run recovery"
 CONFIG_SPL_SYS_I2C_LEGACY=y
 CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
 CONFIG_I2C_DEFAULT_BUS_NUMBER=0x2
diff --git a/configs/draco-etamin_defconfig b/configs/draco-etamin_defconfig
index f650dbc..6c175dd 100644
--- a/configs/draco-etamin_defconfig
+++ b/configs/draco-etamin_defconfig
@@ -79,6 +79,7 @@
 # CONFIG_SPL_BLK is not set
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_BOOTCOUNT_ENV=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_CLK=y
 CONFIG_CLK_TI_CTRL=y
 CONFIG_DFU_NAND=y
diff --git a/configs/draco-rastaban_defconfig b/configs/draco-rastaban_defconfig
index 511956e..521a090 100644
--- a/configs/draco-rastaban_defconfig
+++ b/configs/draco-rastaban_defconfig
@@ -76,6 +76,7 @@
 # CONFIG_SPL_BLK is not set
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_BOOTCOUNT_ENV=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_CLK=y
 CONFIG_CLK_TI_CTRL=y
 CONFIG_DFU_NAND=y
diff --git a/configs/draco-thuban_defconfig b/configs/draco-thuban_defconfig
index 1b2ce3b..2c16db2 100644
--- a/configs/draco-thuban_defconfig
+++ b/configs/draco-thuban_defconfig
@@ -76,6 +76,7 @@
 # CONFIG_SPL_BLK is not set
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_BOOTCOUNT_ENV=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_CLK=y
 CONFIG_CLK_TI_CTRL=y
 CONFIG_DFU_NAND=y
diff --git a/configs/ge_b1x5v2_defconfig b/configs/ge_b1x5v2_defconfig
index 215858c..fec4b67 100644
--- a/configs/ge_b1x5v2_defconfig
+++ b/configs/ge_b1x5v2_defconfig
@@ -78,6 +78,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_DM_BOOTCOUNT_SPI_FLASH=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="setenv mmcpart 1; run hasfirstboot || setenv mmcpart 2; run hasfirstboot || setenv mmcpart 0; if test ${mmcpart} != 0; then setenv bootcause REVERT; run swappartitions loadimage doboot; fi; run failbootcmd"
 CONFIG_DM_PCA953X=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_MXC=y
diff --git a/configs/ge_bx50v3_defconfig b/configs/ge_bx50v3_defconfig
index c24513f..676b5bc 100644
--- a/configs/ge_bx50v3_defconfig
+++ b/configs/ge_bx50v3_defconfig
@@ -52,6 +52,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_DM_BOOTCOUNT_I2C_EEPROM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run doquiet; setenv partnum 1; run hasfirstboot || setenv partnum 2; run hasfirstboot || setenv partnum 0; if test ${partnum} != 0; then run swappartitions loadimage doboot; fi; run failbootcmd"
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_MXC=y
 CONFIG_I2C_MUX=y
diff --git a/configs/imx6q_bosch_acc_defconfig b/configs/imx6q_bosch_acc_defconfig
index 54758df..017c274 100644
--- a/configs/imx6q_bosch_acc_defconfig
+++ b/configs/imx6q_bosch_acc_defconfig
@@ -86,6 +86,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_DM_BOOTCOUNT_PMIC_PFUZE100=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run handle_ustate; run switch_bootset; run save_env; run bootcmd"
 CONFIG_SYS_I2C_MXC=y
 CONFIG_SUPPORT_EMMC_BOOT=y
 CONFIG_FSL_USDHC=y
diff --git a/configs/imx6qdl_icore_mmc_defconfig b/configs/imx6qdl_icore_mmc_defconfig
index fb0787d..269fe27 100644
--- a/configs/imx6qdl_icore_mmc_defconfig
+++ b/configs/imx6qdl_icore_mmc_defconfig
@@ -72,6 +72,7 @@
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_BOUNCE_BUFFER=y
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run recoveryboot"
 CONFIG_SYS_BOOTCOUNT_MAGIC=0x0B01C041
 CONFIG_SYS_I2C_MXC=y
 CONFIG_FSL_USDHC=y
diff --git a/configs/imx8mm-mx8menlo_defconfig b/configs/imx8mm-mx8menlo_defconfig
index ae9595e..ad31075 100644
--- a/configs/imx8mm-mx8menlo_defconfig
+++ b/configs/imx8mm-mx8menlo_defconfig
@@ -102,6 +102,7 @@
 CONFIG_TFTP_BLOCKSIZE=4096
 CONFIG_SPL_DM=y
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="mmc partconf 0 mmcpart ; if test ${mmcpart} -eq 1 ; then mmc partconf 0 1 2 0 ; else mmc partconf 0 1 1 0 ; fi ; boot"
 CONFIG_SYS_BOOTCOUNT_MAGIC=0xB0C40000
 CONFIG_SPL_CLK_COMPOSITE_CCF=y
 CONFIG_CLK_COMPOSITE_CCF=y
diff --git a/configs/imx8mm_data_modul_edm_sbc_defconfig b/configs/imx8mm_data_modul_edm_sbc_defconfig
index 66cb133..debaa7c 100644
--- a/configs/imx8mm_data_modul_edm_sbc_defconfig
+++ b/configs/imx8mm_data_modul_edm_sbc_defconfig
@@ -37,3 +37,4 @@
 CONFIG_SPL_USB_HOST=y
 CONFIG_SPL_USB_SDP_SUPPORT=y
 CONFIG_SYS_LOAD_ADDR=0x60000000
+CONFIG_BOOTCOUNT_ALTBOOTCMD=run bootcmd
diff --git a/configs/imx8mp_data_modul_edm_sbc_defconfig b/configs/imx8mp_data_modul_edm_sbc_defconfig
index ea8109b..5024c09 100644
--- a/configs/imx8mp_data_modul_edm_sbc_defconfig
+++ b/configs/imx8mp_data_modul_edm_sbc_defconfig
@@ -52,3 +52,4 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
 CONFIG_USB_XHCI_HCD=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
diff --git a/configs/imx8mp_dhcom_drc02_defconfig b/configs/imx8mp_dhcom_drc02_defconfig
index c43839c..dccf5ff 100644
--- a/configs/imx8mp_dhcom_drc02_defconfig
+++ b/configs/imx8mp_dhcom_drc02_defconfig
@@ -5,3 +5,4 @@
 CONFIG_DEFAULT_DEVICE_TREE="imx8mp-dhcom-drc02"
 CONFIG_DEFAULT_FDT_FILE="imx8mp-dhcom-drc02.dtb"
 CONFIG_PREBOOT=""
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd ; reset"
diff --git a/configs/imx8mp_dhcom_pdk2_defconfig b/configs/imx8mp_dhcom_pdk2_defconfig
index aae2e21..4f50806 100644
--- a/configs/imx8mp_dhcom_pdk2_defconfig
+++ b/configs/imx8mp_dhcom_pdk2_defconfig
@@ -7,3 +7,4 @@
 CONFIG_PREBOOT=""
 CONFIG_OF_UPSTREAM=y
 CONFIG_OF_UPSTREAM_INCLUDE_LOCAL_FALLBACK_DTBOS=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd ; reset"
diff --git a/configs/imx8mp_dhcom_pdk3_defconfig b/configs/imx8mp_dhcom_pdk3_defconfig
index f40bf26..d505ddf 100644
--- a/configs/imx8mp_dhcom_pdk3_defconfig
+++ b/configs/imx8mp_dhcom_pdk3_defconfig
@@ -14,3 +14,4 @@
 CONFIG_PHY_IMX8M_PCIE=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_MUX_PCA954x=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd ; reset"
diff --git a/configs/imx8mp_dhcom_picoitx_defconfig b/configs/imx8mp_dhcom_picoitx_defconfig
index 99cd5f2..d98ca9e 100644
--- a/configs/imx8mp_dhcom_picoitx_defconfig
+++ b/configs/imx8mp_dhcom_picoitx_defconfig
@@ -5,3 +5,4 @@
 CONFIG_DEFAULT_DEVICE_TREE="imx8mp-dhcom-picoitx"
 CONFIG_DEFAULT_FDT_FILE="imx8mp-dhcom-picoitx.dtb"
 CONFIG_PREBOOT=""
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd ; reset"
diff --git a/configs/iot2050_defconfig b/configs/iot2050_defconfig
index 2d5f18e..72d4b8e 100644
--- a/configs/iot2050_defconfig
+++ b/configs/iot2050_defconfig
@@ -70,7 +70,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PCI=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_WDT=y
 # CONFIG_CMD_SETEXPR is not set
@@ -131,7 +130,6 @@
 CONFIG_PINCTRL_SINGLE=y
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_SCI_POWER_DOMAIN=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/j7200_evm_a72_defconfig b/configs/j7200_evm_a72_defconfig
index ac5b10b..4760f75 100644
--- a/configs/j7200_evm_a72_defconfig
+++ b/configs/j7200_evm_a72_defconfig
@@ -67,7 +67,6 @@
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_MTD=y
 CONFIG_CMD_PCI=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_UFS=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_MTDIDS_DEFAULT="nor0=47040000.spi.0,nor0=47034000.hyperbus"
@@ -167,7 +166,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_RAM=y
 CONFIG_SPL_RAM=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SCSI=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/j7200_evm_r5_defconfig b/configs/j7200_evm_r5_defconfig
index 265ae2e..ae5849b 100644
--- a/configs/j7200_evm_r5_defconfig
+++ b/configs/j7200_evm_r5_defconfig
@@ -57,7 +57,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -68,7 +67,6 @@
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -138,7 +136,6 @@
 CONFIG_SPL_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_TPS65941=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/j721e_beagleboneai64_a72_defconfig b/configs/j721e_beagleboneai64_a72_defconfig
index a5d9597..fad01c2 100644
--- a/configs/j721e_beagleboneai64_a72_defconfig
+++ b/configs/j721e_beagleboneai64_a72_defconfig
@@ -67,7 +67,6 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_CMD_EFIDEBUG=y
@@ -144,8 +143,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_RAM=y
 CONFIG_SPL_RAM=y
-CONFIG_REMOTEPROC_TI_K3_DSP=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_EMULATION=y
diff --git a/configs/j721e_beagleboneai64_r5_defconfig b/configs/j721e_beagleboneai64_r5_defconfig
index 77e4496..086ad99 100644
--- a/configs/j721e_beagleboneai64_r5_defconfig
+++ b/configs/j721e_beagleboneai64_r5_defconfig
@@ -52,13 +52,11 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -111,7 +109,6 @@
 CONFIG_SPL_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_TPS65941=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig
index 1ddb196..71e6c20 100644
--- a/configs/j721e_evm_a72_defconfig
+++ b/configs/j721e_evm_a72_defconfig
@@ -68,7 +68,6 @@
 CONFIG_CMD_DFU=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_UFS=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
@@ -171,8 +170,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_RAM=y
 CONFIG_SPL_RAM=y
-CONFIG_REMOTEPROC_TI_K3_DSP=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_EMULATION=y
diff --git a/configs/j721e_evm_r5_defconfig b/configs/j721e_evm_r5_defconfig
index c4e9f2d..c8324d4 100644
--- a/configs/j721e_evm_r5_defconfig
+++ b/configs/j721e_evm_r5_defconfig
@@ -61,7 +61,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -72,7 +71,6 @@
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -148,7 +146,6 @@
 CONFIG_SPL_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_TPS65941=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/j721s2_evm_a72_defconfig b/configs/j721s2_evm_a72_defconfig
index ab943eb..5e84abf 100644
--- a/configs/j721s2_evm_a72_defconfig
+++ b/configs/j721s2_evm_a72_defconfig
@@ -64,7 +64,6 @@
 CONFIG_SPL_YMODEM_SUPPORT=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_UFS=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_MTDIDS_DEFAULT="nor0=47040000.spi.0,nor0=47034000.hyperbus"
@@ -161,8 +160,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_RAM=y
 CONFIG_SPL_RAM=y
-CONFIG_REMOTEPROC_TI_K3_DSP=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SCSI=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/j721s2_evm_r5_defconfig b/configs/j721s2_evm_r5_defconfig
index 7ec9af8..6ea1d71 100644
--- a/configs/j721s2_evm_r5_defconfig
+++ b/configs/j721s2_evm_r5_defconfig
@@ -62,7 +62,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -74,7 +73,6 @@
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -148,7 +146,6 @@
 CONFIG_SPL_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_TPS65941=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/j722s_evm_a53_defconfig b/configs/j722s_evm_a53_defconfig
index 667d633..2062eca 100644
--- a/configs/j722s_evm_a53_defconfig
+++ b/configs/j722s_evm_a53_defconfig
@@ -55,7 +55,6 @@
 CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_CMD_CLK=y
 CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_CMD_MTDPARTS=y
 CONFIG_CMD_UBI=y
@@ -131,9 +130,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_SPL_DM_REGULATOR_GPIO=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
-CONFIG_REMOTEPROC_TI_K3_DSP=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/j722s_evm_r5_defconfig b/configs/j722s_evm_r5_defconfig
index a78a66d..d51b21d 100644
--- a/configs/j722s_evm_r5_defconfig
+++ b/configs/j722s_evm_r5_defconfig
@@ -49,7 +49,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -61,7 +60,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -113,7 +111,6 @@
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/j784s4_evm_a72_defconfig b/configs/j784s4_evm_a72_defconfig
index f058e3b..1ac2430 100644
--- a/configs/j784s4_evm_a72_defconfig
+++ b/configs/j784s4_evm_a72_defconfig
@@ -61,7 +61,6 @@
 CONFIG_CMD_ASKENV=y
 CONFIG_CMD_NVEDIT_EFI=y
 CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_EFIDEBUG=y
 CONFIG_OF_CONTROL=y
@@ -140,8 +139,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_RAM=y
 CONFIG_SPL_RAM=y
-CONFIG_REMOTEPROC_TI_K3_DSP=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_EMULATION=y
diff --git a/configs/j784s4_evm_r5_defconfig b/configs/j784s4_evm_r5_defconfig
index b991ffb..a307055 100644
--- a/configs/j784s4_evm_r5_defconfig
+++ b/configs/j784s4_evm_r5_defconfig
@@ -55,7 +55,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -128,7 +127,6 @@
 CONFIG_SPL_DM_REGULATOR=y
 CONFIG_SPL_DM_REGULATOR_TPS6287X=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_SERIAL=y
 CONFIG_SOC_DEVICE=y
diff --git a/configs/kmcent2_defconfig b/configs/kmcent2_defconfig
index 4e37df2..76e98c9 100644
--- a/configs/kmcent2_defconfig
+++ b/configs/kmcent2_defconfig
@@ -60,6 +60,7 @@
 CONFIG_USE_ETHPRIME=y
 CONFIG_ETHPRIME="fm1-mac5"
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_FSL_CAAM=y
 CONFIG_DDR_CLK_FREQ=66666666
diff --git a/configs/kmcoge5ne_defconfig b/configs/kmcoge5ne_defconfig
index 6b2fc2e..cf50e2d 100644
--- a/configs/kmcoge5ne_defconfig
+++ b/configs/kmcoge5ne_defconfig
@@ -166,6 +166,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_BOOTCOUNT_MEM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_SYS_BR0_PRELIM_BOOL=y
 CONFIG_SYS_BR0_PRELIM=0xF0001001
diff --git a/configs/kmeter1_defconfig b/configs/kmeter1_defconfig
index 55e87b0..7638fc2 100644
--- a/configs/kmeter1_defconfig
+++ b/configs/kmeter1_defconfig
@@ -145,6 +145,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_BOOTCOUNT_MEM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_SYS_BR0_PRELIM_BOOL=y
 CONFIG_SYS_BR0_PRELIM=0xF0001001
diff --git a/configs/kmopti2_defconfig b/configs/kmopti2_defconfig
index df419b0..1c75045 100644
--- a/configs/kmopti2_defconfig
+++ b/configs/kmopti2_defconfig
@@ -152,6 +152,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_BOOTCOUNT_MEM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BR0_PRELIM_BOOL=y
 CONFIG_SYS_BR0_PRELIM=0xF0001001
 CONFIG_SYS_OR0_PRELIM=0xF0000E55
diff --git a/configs/kmsupx5_defconfig b/configs/kmsupx5_defconfig
index 1436860..5dd9817 100644
--- a/configs/kmsupx5_defconfig
+++ b/configs/kmsupx5_defconfig
@@ -137,6 +137,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_BOOTCOUNT_MEM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_SYS_BR0_PRELIM_BOOL=y
 CONFIG_SYS_BR0_PRELIM=0xF0001001
diff --git a/configs/kmtepr2_defconfig b/configs/kmtepr2_defconfig
index cce7a04..2b240b3 100644
--- a/configs/kmtepr2_defconfig
+++ b/configs/kmtepr2_defconfig
@@ -151,6 +151,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_BOOTCOUNT_MEM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BR0_PRELIM_BOOL=y
 CONFIG_SYS_BR0_PRELIM=0xF0001001
 CONFIG_SYS_OR0_PRELIM=0xF0000E55
diff --git a/configs/lxr2_defconfig b/configs/lxr2_defconfig
index 7ab8179..b41a6ed 100644
--- a/configs/lxr2_defconfig
+++ b/configs/lxr2_defconfig
@@ -77,6 +77,7 @@
 CONFIG_ARP_TIMEOUT=200
 CONFIG_BOUNCE_BUFFER=y
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run swupdate"
 CONFIG_SYS_BOOTCOUNT_MAGIC=0xB0C4000
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_DM_I2C=y
diff --git a/configs/m53menlo_defconfig b/configs/m53menlo_defconfig
index 6130cd8..ccd1cb7 100644
--- a/configs/m53menlo_defconfig
+++ b/configs/m53menlo_defconfig
@@ -79,6 +79,7 @@
 CONFIG_HOSTNAME="m53menlo"
 CONFIG_VERSION_VARIABLE=y
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="if test ${mmcpart} -eq 1 ; then setenv mmcpart 2 ; else setenv mmcpart 1 ; fi ; boot"
 CONFIG_SYS_BOOTCOUNT_MAGIC=0x0B01C041
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_MXC=y
diff --git a/configs/mx53ppd_defconfig b/configs/mx53ppd_defconfig
index d91c59f..4ec8516 100644
--- a/configs/mx53ppd_defconfig
+++ b/configs/mx53ppd_defconfig
@@ -47,6 +47,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_DM_BOOTCOUNT_I2C_EEPROM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run doquiet; setenv partnum 1; run hasfirstboot || setenv partnum 2; run hasfirstboot || setenv partnum 0; if test ${partnum} != 0; then run swappartitions loadimage doboot; fi; run failbootcmd"
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_MXC=y
 CONFIG_I2C_MUX=y
diff --git a/configs/pg_wcom_expu1_defconfig b/configs/pg_wcom_expu1_defconfig
index 1120191..4b82b07 100644
--- a/configs/pg_wcom_expu1_defconfig
+++ b/configs/pg_wcom_expu1_defconfig
@@ -73,6 +73,7 @@
 CONFIG_VERSION_VARIABLE=y
 # CONFIG_SCSI_AHCI is not set
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_DDR_CLK_FREQ=50000000
 CONFIG_SYS_FSL_DDR3=y
diff --git a/configs/pg_wcom_expu1_update_defconfig b/configs/pg_wcom_expu1_update_defconfig
index 772aa21..53d5478 100644
--- a/configs/pg_wcom_expu1_update_defconfig
+++ b/configs/pg_wcom_expu1_update_defconfig
@@ -71,6 +71,7 @@
 CONFIG_VERSION_VARIABLE=y
 # CONFIG_SCSI_AHCI is not set
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_DDR_CLK_FREQ=50000000
 CONFIG_SYS_FSL_DDR3=y
diff --git a/configs/pg_wcom_seli8_defconfig b/configs/pg_wcom_seli8_defconfig
index 6cde217..731ca43 100644
--- a/configs/pg_wcom_seli8_defconfig
+++ b/configs/pg_wcom_seli8_defconfig
@@ -73,6 +73,7 @@
 CONFIG_VERSION_VARIABLE=y
 # CONFIG_SCSI_AHCI is not set
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_DDR_CLK_FREQ=50000000
 CONFIG_SYS_FSL_DDR3=y
diff --git a/configs/pg_wcom_seli8_update_defconfig b/configs/pg_wcom_seli8_update_defconfig
index e8afc95..2598e47 100644
--- a/configs/pg_wcom_seli8_update_defconfig
+++ b/configs/pg_wcom_seli8_update_defconfig
@@ -71,6 +71,7 @@
 CONFIG_VERSION_VARIABLE=y
 # CONFIG_SCSI_AHCI is not set
 CONFIG_BOOTCOUNT_LIMIT=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_DDR_CLK_FREQ=50000000
 CONFIG_SYS_FSL_DDR3=y
diff --git a/configs/phycore_am62ax_a53_defconfig b/configs/phycore_am62ax_a53_defconfig
index 421dd85..8c4fcc3 100644
--- a/configs/phycore_am62ax_a53_defconfig
+++ b/configs/phycore_am62ax_a53_defconfig
@@ -67,7 +67,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_MTD=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_CMD_CACHE=y
@@ -143,8 +142,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
 CONFIG_REMOTEPROC_TI_K3_ARM64=y
-CONFIG_REMOTEPROC_TI_K3_DSP=y
-CONFIG_REMOTEPROC_TI_K3_R5F=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_RV3028=y
diff --git a/configs/phycore_am62ax_r5_defconfig b/configs/phycore_am62ax_r5_defconfig
index a71ebf0..25d2d9b 100644
--- a/configs/phycore_am62ax_r5_defconfig
+++ b/configs/phycore_am62ax_r5_defconfig
@@ -49,7 +49,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 CONFIG_SPL_SPI_LOAD=y
 CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000
 CONFIG_SPL_THERMAL=y
@@ -59,7 +58,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -112,7 +110,6 @@
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/phycore_am62x_r5_defconfig b/configs/phycore_am62x_r5_defconfig
index 25adca4..f157103 100644
--- a/configs/phycore_am62x_r5_defconfig
+++ b/configs/phycore_am62x_r5_defconfig
@@ -55,7 +55,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -66,7 +65,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_FAT=y
@@ -114,7 +112,6 @@
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/phycore_am64x_r5_defconfig b/configs/phycore_am64x_r5_defconfig
index d060a0f..2552479 100644
--- a/configs/phycore_am64x_r5_defconfig
+++ b/configs/phycore_am64x_r5_defconfig
@@ -61,7 +61,6 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 # CONFIG_SPL_SPI_FLASH_TINY is not set
 CONFIG_SPL_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPL_SPI_LOAD=y
@@ -73,7 +72,6 @@
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
@@ -140,7 +138,6 @@
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_SPL_DM_REGULATOR_GPIO=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/pxm2_defconfig b/configs/pxm2_defconfig
index 162b1f1..fd2727e 100644
--- a/configs/pxm2_defconfig
+++ b/configs/pxm2_defconfig
@@ -85,6 +85,7 @@
 # CONFIG_SPL_BLK is not set
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_BOOTCOUNT_ENV=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_DFU_NAND=y
 CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000
 CONFIG_DM_I2C=y
diff --git a/configs/rut_defconfig b/configs/rut_defconfig
index dd8df54..b2930e8 100644
--- a/configs/rut_defconfig
+++ b/configs/rut_defconfig
@@ -86,6 +86,7 @@
 # CONFIG_SPL_BLK is not set
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_BOOTCOUNT_ENV=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_DFU_NAND=y
 CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000
 CONFIG_DM_I2C=y
diff --git a/configs/smegw01_defconfig b/configs/smegw01_defconfig
index 6dc95e5..ae6c9b6 100644
--- a/configs/smegw01_defconfig
+++ b/configs/smegw01_defconfig
@@ -60,6 +60,7 @@
 CONFIG_BOUNCE_BUFFER=y
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_BOOTCOUNT_ENV=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="echo Performing rollback...; if test \"${mmcpart_committed}\" = 1; then setenv mmcpart 2; setenv mmcpart_committed 2; else setenv mmcpart 1; setenv mmcpart_committed 1; fi; setenv bootcount 0; setenv upgrade_available; setenv ustate 3; saveenv; run bootcmd;"
 CONFIG_DFU_MMC=y
 CONFIG_DM_I2C=y
 CONFIG_SUPPORT_EMMC_BOOT=y
diff --git a/configs/socfpga_secu1_defconfig b/configs/socfpga_secu1_defconfig
index dc6d66a..84badec 100644
--- a/configs/socfpga_secu1_defconfig
+++ b/configs/socfpga_secu1_defconfig
@@ -74,6 +74,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_DM_BOOTCOUNT_RTC=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd;"
 CONFIG_DWAPB_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
diff --git a/configs/stm32mp13_dhcor_defconfig b/configs/stm32mp13_dhcor_defconfig
index ff948b9..4dc3954 100644
--- a/configs/stm32mp13_dhcor_defconfig
+++ b/configs/stm32mp13_dhcor_defconfig
@@ -44,3 +44,4 @@
 CONFIG_USB_ONBOARD_HUB=y
 CONFIG_USB_HUB_DEBOUNCE_TIMEOUT=2000
 CONFIG_ERRNO_STR=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="
diff --git a/configs/stm32mp15_dhcom_basic_defconfig b/configs/stm32mp15_dhcom_basic_defconfig
index a28f286..f89c921 100644
--- a/configs/stm32mp15_dhcom_basic_defconfig
+++ b/configs/stm32mp15_dhcom_basic_defconfig
@@ -8,3 +8,4 @@
 CONFIG_SYS_I2C_EEPROM_BUS=3
 CONFIG_OF_LIST="st/stm32mp157c-dhcom-pdk2 st/stm32mp153c-dhcom-drc02 st/stm32mp157c-dhcom-picoitx"
 CONFIG_SYS_I2C_EEPROM_ADDR=0x50
+CONFIG_BOOTCOUNT_ALTBOOTCMD="
diff --git a/configs/stm32mp15_dhcor_basic_defconfig b/configs/stm32mp15_dhcor_basic_defconfig
index f6f2af6..bde6687 100644
--- a/configs/stm32mp15_dhcor_basic_defconfig
+++ b/configs/stm32mp15_dhcor_basic_defconfig
@@ -8,3 +8,4 @@
 CONFIG_SYS_I2C_EEPROM_ADDR=0x53
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ90X1=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="
diff --git a/configs/tuge1_defconfig b/configs/tuge1_defconfig
index d1b7719..ab0fd12 100644
--- a/configs/tuge1_defconfig
+++ b/configs/tuge1_defconfig
@@ -137,6 +137,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_BOOTCOUNT_MEM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BOOTCOUNT_BE=y
 CONFIG_SYS_BR0_PRELIM_BOOL=y
 CONFIG_SYS_BR0_PRELIM=0xF0001001
diff --git a/configs/tuxx1_defconfig b/configs/tuxx1_defconfig
index 1dc737e..e5a99b2 100644
--- a/configs/tuxx1_defconfig
+++ b/configs/tuxx1_defconfig
@@ -151,6 +151,7 @@
 CONFIG_BOOTCOUNT_LIMIT=y
 CONFIG_DM_BOOTCOUNT=y
 CONFIG_BOOTCOUNT_MEM=y
+CONFIG_BOOTCOUNT_ALTBOOTCMD="run bootcmd"
 CONFIG_SYS_BR0_PRELIM_BOOL=y
 CONFIG_SYS_BR0_PRELIM=0xF0001001
 CONFIG_SYS_OR0_PRELIM=0xF0000E55
diff --git a/configs/verdin-am62_a53_defconfig b/configs/verdin-am62_a53_defconfig
index e7a88c9..ecd3284 100644
--- a/configs/verdin-am62_a53_defconfig
+++ b/configs/verdin-am62_a53_defconfig
@@ -76,7 +76,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_READ=y
-CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_CMD_BOOTCOUNT=y
diff --git a/configs/verdin-am62_r5_defconfig b/configs/verdin-am62_r5_defconfig
index d4f904a..9ac4b53 100644
--- a/configs/verdin-am62_r5_defconfig
+++ b/configs/verdin-am62_r5_defconfig
@@ -48,14 +48,12 @@
 CONFIG_SPL_DM_RESET=y
 CONFIG_SPL_POWER_DOMAIN=y
 CONFIG_SPL_RAM_DEVICE=y
-CONFIG_SPL_REMOTEPROC=y
 CONFIG_SPL_YMODEM_SUPPORT=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_ASKENV=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_REMOTEPROC=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_OF_CONTROL=y
@@ -97,7 +95,6 @@
 CONFIG_POWER_DOMAIN=y
 CONFIG_TI_POWER_DOMAIN=y
 CONFIG_K3_SYSTEM_CONTROLLER=y
-CONFIG_REMOTEPROC_TI_K3_ARM64=y
 CONFIG_RESET_TI_SCI=y
 CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_DM_SERIAL=y
diff --git a/doc/develop/tests_writing.rst b/doc/develop/tests_writing.rst
index 54efb7e..5f3c43d 100644
--- a/doc/develop/tests_writing.rst
+++ b/doc/develop/tests_writing.rst
@@ -261,7 +261,7 @@
    /* Test 'ms' command with 32-bit values */
    static int mem_test_ms_new_thing(struct unit_test_state *uts)
    {
-         /* test code here*/
+         /* test code here */
 
          return 0;
    }
@@ -291,32 +291,20 @@
    /* Declare a new wibble test */
    #define WIBBLE_TEST(_name, _flags)   UNIT_TEST(_name, _flags, wibble_test)
 
-   /* Tetss go here */
-
-   /* At the bottom of the file: */
-
-   int do_ut_wibble(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
-   {
-     struct unit_test *tests = UNIT_TEST_SUITE_START(wibble_test);
-     const int n_ents = UNIT_TEST_SUITE_COUNT(wibble_test);
-
-     return cmd_ut_category("cmd_wibble", "wibble_test_", tests, n_ents, argc, argv);
-   }
+   /* Tests go here */
 
 Then add new tests to it as above.
 
 Register this new suite in test/cmd_ut.c by adding to cmd_ut_sub[]::
 
-  /* Within cmd_ut_sub[]... */
-
-  U_BOOT_CMD_MKENT(wibble, CONFIG_SYS_MAXARGS, 1, do_ut_wibble, "", ""),
+  /* with the other SUITE_DECL() declarations */
+  SUITE_DECL(wibble);
 
-and adding new help to ut_help_text[]::
+  /* Within suites[]... */
+  SUITE(wibble, "my test of wibbles");
 
-  "ut wibble - Test the wibble feature\n"
-
-If your feature is conditional on a particular Kconfig, then you can use #ifdef
-to control that.
+If your feature is conditional on a particular Kconfig, you do not need to add
+an #ifdef since the suite will automatically be compiled out in that case.
 
 Finally, add the test to the build by adding to the Makefile in the same
 directory::
@@ -326,17 +314,35 @@
 Note that CMDLINE is never enabled in SPL, so this test will only be present in
 U-Boot proper. See below for how to do SPL tests.
 
-As before, you can add an extra Kconfig check if needed::
+You can add an extra Kconfig check if needed::
 
   ifneq ($(CONFIG_$(XPL_)WIBBLE),)
   obj-$(CONFIG_$(XPL_)CMDLINE) += wibble.o
   endif
 
+Each suite can have an optional init and uninit function. These are run before
+and after any suite tests, respectively::
+
+   #define WIBBLE_TEST_INIT(_name, _flags)  UNIT_TEST_INIT(_name, _flags, wibble_test)
+   #define WIBBLE_TEST_UNINIT(_name, _flags)  UNIT_TEST_UNINIT(_name, _flags, wibble_test)
 
-Example commit: 919e7a8fb64 ("test: Add a simple test for bloblist") [1]
+   static int wibble_test_init(struct unit_test_state *uts)
+   {
+         /* init code here */
+
+         return 0;
+   }
+   WIBBLE_TEST_INIT(wibble_test_init, 0);
 
-[1] https://gitlab.denx.de/u-boot/u-boot/-/commit/919e7a8fb64
+   static int wibble_test_uninit(struct unit_test_state *uts)
+   {
+         /* uninit code here */
+
+         return 0;
+   }
+   WIBBLE_TEST_INIT(wibble_test_uninit, 0);
 
+Both functions are included in the totals for each suite.
 
 Making the test run from pytest
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/usage/cmd/ut.rst b/doc/usage/cmd/ut.rst
index e794922..1acf312 100644
--- a/doc/usage/cmd/ut.rst
+++ b/doc/usage/cmd/ut.rst
@@ -11,34 +11,44 @@
 
 ::
 
-    ut [-r<runs>] [-fs] [-I<n>:<one_test>] [<suite> [<test>]]
-
-       <runs>      Number of times to run each test
-       -f          Force 'manual' tests to run as well
-       <n>         Run <one test> after <n> other tests have run
-       <one_test>  Name of the 'one' test to run
-       <suite>     Test suite to run, or `all`
-       <test>      Name of single test to run
+    ut [-r<runs>] [-f] [-I<n>:<one_test>] [-r<n>] [<suite> | 'all' [<test>]]
+    ut [-s] info
 
 Description
 -----------
 
 The ut command runs unit tests written in C.
 
+suite
+    Specifies the suite to run, This can be a single suite, or a comma-separated
+    list
+
+test
+    Speciifes a particular test to run, within a suite, or all suites
+
+-f
+    Forces running of a manual test.
+
+-r <n>
+    Specifies the number of types to run each test
+
+-I <n>:<one_test>
+    Test to run after <n> other tests have run.  This is used to find which test
+    causes another test to fail. If the one test fails, testing stops
+    immediately.
+
 Typically the command is run on :ref:`arch/sandbox/sandbox:sandbox` since it
 includes a near-complete set of emulators, no code-size limits, many CONFIG
 options enabled and runs easily in CI without needing QEMU. It is also possible
 to run some tests on real boards.
 
-For a list of available test suites, type `ut info -s`.
-
 Each test is normally run once, although those marked with `UTF_DM` are
 run with livetree and flattree where possible. To run a test more than once,
 use the `-r` flag.
 
 Manual tests are normally skipped by this command. Use `-f` to run them. See
-See :ref:`develop/tests_writing:mixing python and c` for more information on
-manual test.
+:ref:`develop/tests_writing:mixing python and c` for more information on manual
+tests.
 
 When running unit tests, some may have side effects which cause a subsequent
 test to break. This can sometimes be seen when using 'ut dm' or similar. To
@@ -50,9 +60,22 @@
 Generally all tests in the suite are run. To run just a single test from the
 suite, provide the <test> argument.
 
+To specify a list of suites to run, <suites> can also be a comma-separated list.
+
 See :ref:`develop/tests_writing:writing c tests` for more information on how to
 write unit tests.
 
+ut all
+~~~~~~
+
+Instead of a suite name 'all' may be used to run all tests.
+
+ut info
+~~~~~~~
+
+This provides information about the total number of suites and tests. Use the
+`-s` flag to show a detailed list of suites.
+
 Example
 -------
 
@@ -97,26 +120,84 @@
 
 Run one of the suites::
 
-    => ut bloblist
-    Running 14 bloblist tests
-    Test: bloblist_test_align: bloblist.c
-    Test: bloblist_test_bad_blob: bloblist.c
-    Test: bloblist_test_blob: bloblist.c
-    Test: bloblist_test_blob_ensure: bloblist.c
-    Test: bloblist_test_blob_maxsize: bloblist.c
-    Test: bloblist_test_checksum: bloblist.c
-    Test: bloblist_test_cmd_info: bloblist.c
-    Test: bloblist_test_cmd_list: bloblist.c
-    Test: bloblist_test_grow: bloblist.c
-    Test: bloblist_test_init: bloblist.c
-    Test: bloblist_test_reloc: bloblist.c
-    Test: bloblist_test_resize_fail: bloblist.c
-    Test: bloblist_test_resize_last: bloblist.c
-    Test: bloblist_test_shrink: bloblist.c
-    Failures: 0
+    => ut common
+    Running 14 common tests
+    Test: cli_ch_test: cread.c
+    Test: cread_test: cread.c
+    Test: dm_test_cyclic_running: cyclic.c
+    Test: print_display_buffer: print.c
+    Test: print_do_hex_dump: print.c
+    Test: print_efi_ut: print.c
+    Test: print_guid: print.c
+    Test: print_hexdump_line: print.c
+    Test: print_printf: print.c
+    Test: snprint: print.c
+    Test: test_autoboot: test_autoboot.c
+    Enter password "a" in 1 seconds to stop autoboot
+    Enter password "a" in 1 seconds to stop autoboot
+    Enter password "a" in 1 seconds to stop autoboot
+    Enter password "a" in 1 seconds to stop autoboot
+    Enter password "a" in 1 seconds to stop autoboot
+    Enter password "a" in 1 seconds to stop autoboot
+    Autoboot password unlock not successful
+    Test: test_event_base: event.c
+    Test: test_event_probe: event.c
+    Test: test_event_probe: event.c (flat tree)
+    Test: test_event_simple: event.c
+    Tests run: 14, 2611 ms, average 186 ms, skipped: 2, failures: 0
 
 Run just a single test in a suite::
 
+    => ut fdt_overlay change_int_property
+    Test: fdt_overlay_init: cmd_ut_fdt_overlay.c
+    Test: change_int_property: cmd_ut_fdt_overlay.c
+    Tests run: 2, 0 ms, average 0 ms, failures: 0
+
-    => ut bloblist bloblist_test_grow
-    Test: bloblist_test_grow: bloblist.c
-    Failures: 0
+Run a selection of three suites::
+
+    => ut bloblist,mem,fdt_overlay
+    Running 14 bloblist tests
+    Test: align: bloblist.c
+    Test: bad_blob: bloblist.c
+    Test: blob: bloblist.c
+    Test: blob_ensure: bloblist.c
+    Test: blob_maxsize: bloblist.c
+    Test: checksum: bloblist.c
+    Test: cmd_info: bloblist.c
+    Test: cmd_list: bloblist.c
+    Test: grow: bloblist.c
+    Test: init: bloblist.c
+    Test: reloc: bloblist.c
+    Test: resize_fail: bloblist.c
+    Test: resize_last: bloblist.c
+    Test: shrink: bloblist.c
+    Tests run: 14, 1 ms, average: 0 ms, failures: 0
+    Running 13 mem tests
+    Test: cp_b: mem_copy.c
+    Test: cp_l: mem_copy.c
+    Test: cp_q: mem_copy.c
+    Test: cp_w: mem_copy.c
+    Test: ms_b: mem_search.c
+    Test: ms_cont: mem_search.c
+    Test: ms_cont_end: mem_search.c
+    Test: ms_l: mem_search.c
+    Test: ms_limit: mem_search.c
+    Test: ms_mult: mem_search.c
+    Test: ms_quiet: mem_search.c
+    Test: ms_s: mem_search.c
+    Test: ms_w: mem_search.c
+    Tests run: 13, 13 ms, average: 1 ms, failures: 0
+    Running 10 fdt_overlay tests
+    Test: fdt_overlay_init: cmd_ut_fdt_overlay.c
+    Test: add_node_by_path: cmd_ut_fdt_overlay.c
+    Test: add_node_by_phandle: cmd_ut_fdt_overlay.c
+    Test: add_str_property: cmd_ut_fdt_overlay.c
+    Test: add_subnode_property: cmd_ut_fdt_overlay.c
+    Test: change_int_property: cmd_ut_fdt_overlay.c
+    Test: change_str_property: cmd_ut_fdt_overlay.c
+    Test: local_phandle: cmd_ut_fdt_overlay.c
+    Test: local_phandles: cmd_ut_fdt_overlay.c
+    Test: stacked: cmd_ut_fdt_overlay.c
+    Tests run: 10, 12 ms, average: 1 ms, failures: 0
+    Suites run: 3, total tests run: 37, 26 ms, average: 0 ms, failures: 0
+    Average test time: 0 ms, worst case 'mem' took 1 ms
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index 0080d2a..99b6c75 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -183,6 +183,9 @@
 	  counter being cleared.
 	  If set to 0, do not set a boot limit in the environment.
 
+config BOOTCOUNT_ALTBOOTCMD
+	string "Alternative boot command when BOOTLIMIT is reached"
+
 config SYS_BOOTCOUNT_SINGLEWORD
 	bool "Use single word to pack boot count and magic value"
 	depends on BOOTCOUNT_GENERIC
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 2790b16..3d2831a 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -55,6 +55,7 @@
 	depends on DM
 	depends on ARCH_K3
 	depends on OF_CONTROL
+	default y if SYS_K3_SPL_ATF
 	help
 	  Say y here to support TI's ARM64 processor subsystems
 	  on various TI K3 family of SoCs through the remote processor
@@ -70,6 +71,16 @@
 	  on various TI K3 family of SoCs through the remote processor
 	  framework.
 
+config REMOTEPROC_TI_K3_M4F
+	bool "TI K3 M4F remoteproc support"
+	select REMOTEPROC
+	depends on ARCH_K3
+	depends on TI_SCI_PROTOCOL
+	help
+	  Say y here to support TI's M4F remote processor subsystems
+	  on various TI K3 family of SoCs through the remote processor
+	  framework.
+
 config REMOTEPROC_TI_K3_R5F
 	bool "TI K3 R5F remoteproc support"
 	select REMOTEPROC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 3a092b7..f81e500 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o
 obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o
 obj-$(CONFIG_REMOTEPROC_TI_K3_DSP) += ti_k3_dsp_rproc.o
+obj-$(CONFIG_REMOTEPROC_TI_K3_M4F) += ti_k3_m4_rproc.o
 obj-$(CONFIG_REMOTEPROC_TI_K3_R5F) += ti_k3_r5f_rproc.o
 obj-$(CONFIG_REMOTEPROC_TI_POWER) += ti_power_proc.o
 obj-$(CONFIG_REMOTEPROC_TI_PRU) += pru_rproc.o
diff --git a/drivers/remoteproc/ti_k3_m4_rproc.c b/drivers/remoteproc/ti_k3_m4_rproc.c
new file mode 100644
index 0000000..31b9de7
--- /dev/null
+++ b/drivers/remoteproc/ti_k3_m4_rproc.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments' K3 M4 Remoteproc driver
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/
+ *	Hari Nagalla <hnagalla@ti.com>
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <remoteproc.h>
+#include <errno.h>
+#include <clk.h>
+#include <reset.h>
+#include <asm/io.h>
+#include <power-domain.h>
+#include <dm/device_compat.h>
+#include <linux/err.h>
+#include <linux/sizes.h>
+#include <linux/soc/ti/ti_sci_protocol.h>
+#include "ti_sci_proc.h"
+#include <mach/security.h>
+
+/**
+ * struct k3_m4_mem - internal memory structure
+ * @cpu_addr: MPU virtual address of the memory region
+ * @bus_addr: Bus address used to access the memory region
+ * @dev_addr: Device address from remoteproc view
+ * @size: Size of the memory region
+ */
+struct k3_m4_mem {
+	void __iomem *cpu_addr;
+	phys_addr_t bus_addr;
+	phys_addr_t dev_addr;
+	size_t size;
+};
+
+/**
+ * struct k3_m4_mem_data - memory definitions for m4 remote core
+ * @name: name for this memory entry
+ * @dev_addr: device address for the memory entry
+ */
+struct k3_m4_mem_data {
+	const char *name;
+	const u32 dev_addr;
+};
+
+/**
+ * struct k3_m4_boot_data - internal data structure used for boot
+ * @boot_align_addr: Boot vector address alignment granularity
+ */
+struct k3_m4_boot_data {
+	u32 boot_align_addr;
+};
+
+/**
+ * struct k3_m4_privdata - Structure representing Remote processor data.
+ * @m4_rst:		m4 rproc reset control data
+ * @tsp:		Pointer to TISCI proc contrl handle
+ * @data:		Pointer to DSP specific boot data structure
+ * @mem:		Array of available memories
+ * @num_mem:		Number of available memories
+ */
+struct k3_m4_privdata {
+	struct reset_ctl m4_rst;
+	struct ti_sci_proc tsp;
+	struct k3_m4_boot_data *data;
+	struct k3_m4_mem *mem;
+	int num_mems;
+};
+
+/*
+ * The M4 cores have a local reset that affects only the CPU, and a
+ * generic module reset that powers on the device and allows the M4 internal
+ * memories to be accessed while the local reset is asserted. This function is
+ * used to release the global reset on M4F to allow loading into the M4F
+ * internal RAMs. This helper function is invoked in k3_m4_load() before any
+ * actual firmware loading happens and is undone only in k3_m4_stop(). The local
+ * reset cannot be released on M4 cores until after the firmware images are loaded.
+ */
+static int k3_m4_prepare(struct udevice *dev)
+{
+	struct k3_m4_privdata *m4 = dev_get_priv(dev);
+	int ret;
+
+	ret = ti_sci_proc_power_domain_on(&m4->tsp);
+	if (ret)
+		dev_err(dev, "cannot enable internal RAM loading, ret = %d\n",
+			ret);
+
+	return ret;
+}
+
+/*
+ * This function is the counterpart to k3_m4_prepare() and is used to assert
+ * the global reset on M4 cores. This completes the second step of powering
+ * down the M4 cores. The cores themselves are halted through the local reset
+ * in first step. This function is invoked in k3_m4_stop() after the local
+ * reset is asserted.
+ */
+static int k3_m4_unprepare(struct udevice *dev)
+{
+	struct k3_m4_privdata *m4 = dev_get_priv(dev);
+
+	return ti_sci_proc_power_domain_off(&m4->tsp);
+}
+
+/**
+ * k3_m4_load() - Load up the Remote processor image
+ * @dev:	rproc device pointer
+ * @addr:	Address at which image is available
+ * @size:	size of the image
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_m4_load(struct udevice *dev, ulong addr, ulong size)
+{
+	struct k3_m4_privdata *m4 = dev_get_priv(dev);
+	void *image_addr = (void *)addr;
+	int ret;
+
+	ret = ti_sci_proc_request(&m4->tsp);
+	if (ret)
+		return ret;
+
+	ret = k3_m4_prepare(dev);
+	if (ret) {
+		dev_err(dev, "Prepare failed for core %d\n",
+			m4->tsp.proc_id);
+		goto proc_release;
+	}
+
+	ti_secure_image_post_process(&image_addr, &size);
+
+	ret = rproc_elf_load_image(dev, addr, size);
+	if (ret < 0) {
+		dev_err(dev, "Loading elf failed %d\n", ret);
+		goto unprepare;
+	}
+
+unprepare:
+	if (ret)
+		k3_m4_unprepare(dev);
+proc_release:
+	ti_sci_proc_release(&m4->tsp);
+	return ret;
+}
+
+/**
+ * k3_m4_start() - Start the remote processor
+ * @dev:	rproc device pointer
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+static int k3_m4_start(struct udevice *dev)
+{
+	struct k3_m4_privdata *m4 = dev_get_priv(dev);
+	int ret;
+
+	ret = ti_sci_proc_request(&m4->tsp);
+	if (ret)
+		return ret;
+
+	ret = reset_deassert(&m4->m4_rst);
+
+	ti_sci_proc_release(&m4->tsp);
+
+	return ret;
+}
+
+static int k3_m4_stop(struct udevice *dev)
+{
+	struct k3_m4_privdata *m4 = dev_get_priv(dev);
+
+	ti_sci_proc_request(&m4->tsp);
+	reset_assert(&m4->m4_rst);
+	k3_m4_unprepare(dev);
+	ti_sci_proc_release(&m4->tsp);
+
+	return 0;
+}
+
+static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len)
+{
+	struct k3_m4_privdata *m4 = dev_get_priv(dev);
+	phys_addr_t bus_addr, dev_addr;
+	void __iomem *va = NULL;
+	size_t size;
+	u32 offset;
+	int i;
+
+	if (len <= 0)
+		return NULL;
+
+	for (i = 0; i < m4->num_mems; i++) {
+		bus_addr = m4->mem[i].bus_addr;
+		dev_addr = m4->mem[i].dev_addr;
+		size = m4->mem[i].size;
+
+		if (da >= dev_addr && ((da + len) <= (dev_addr + size))) {
+			offset = da - dev_addr;
+			va = m4->mem[i].cpu_addr + offset;
+			return (__force void *)va;
+		}
+
+		if (da >= bus_addr && (da + len) <= (bus_addr + size)) {
+			offset = da - bus_addr;
+			va = m4->mem[i].cpu_addr + offset;
+			return (__force void *)va;
+		}
+	}
+
+	/* Assume it is DDR region and return da */
+	return map_physmem(da, len, MAP_NOCACHE);
+}
+
+static const struct dm_rproc_ops k3_m4_ops = {
+	.load = k3_m4_load,
+	.start = k3_m4_start,
+	.stop = k3_m4_stop,
+	.device_to_virt = k3_m4_da_to_va,
+};
+
+static int ti_sci_proc_of_to_priv(struct udevice *dev, struct ti_sci_proc *tsp)
+{
+	u32 ids[2];
+	int ret;
+
+	tsp->sci = ti_sci_get_by_phandle(dev, "ti,sci");
+	if (IS_ERR(tsp->sci)) {
+		dev_err(dev, "ti_sci get failed: %ld\n", PTR_ERR(tsp->sci));
+		return PTR_ERR(tsp->sci);
+	}
+
+	ret = dev_read_u32_array(dev, "ti,sci-proc-ids", ids, 2);
+	if (ret) {
+		dev_err(dev, "Proc IDs not populated %d\n", ret);
+		return ret;
+	}
+
+	tsp->ops = &tsp->sci->ops.proc_ops;
+	tsp->proc_id = ids[0];
+	tsp->host_id = ids[1];
+	tsp->dev_id = dev_read_u32_default(dev, "ti,sci-dev-id",
+					   TI_SCI_RESOURCE_NULL);
+	if (tsp->dev_id == TI_SCI_RESOURCE_NULL) {
+		dev_err(dev, "Device ID not populated %d\n", ret);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static const struct k3_m4_mem_data am6_m4_mems[] = {
+	{ .name = "iram", .dev_addr = 0x0 },
+	{ .name = "dram", .dev_addr = 0x30000 },
+};
+
+static int k3_m4_of_get_memories(struct udevice *dev)
+{
+	struct k3_m4_privdata *m4 = dev_get_priv(dev);
+	int i;
+
+	m4->num_mems = ARRAY_SIZE(am6_m4_mems);
+	m4->mem = calloc(m4->num_mems, sizeof(*m4->mem));
+	if (!m4->mem)
+		return -ENOMEM;
+
+	for (i = 0; i < m4->num_mems; i++) {
+		m4->mem[i].bus_addr = dev_read_addr_size_name(dev,
+							      am6_m4_mems[i].name,
+					  (fdt_addr_t *)&m4->mem[i].size);
+		if (m4->mem[i].bus_addr == FDT_ADDR_T_NONE) {
+			dev_err(dev, "%s bus address not found\n",
+				am6_m4_mems[i].name);
+			return -EINVAL;
+		}
+		m4->mem[i].cpu_addr = map_physmem(m4->mem[i].bus_addr,
+						  m4->mem[i].size,
+						  MAP_NOCACHE);
+		m4->mem[i].dev_addr = am6_m4_mems[i].dev_addr;
+	}
+
+	return 0;
+}
+
+/**
+ * k3_of_to_priv() - generate private data from device tree
+ * @dev:	corresponding k3 m4 processor device
+ * @m4:		pointer to driver specific private data
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_m4_of_to_priv(struct udevice *dev, struct k3_m4_privdata *m4)
+{
+	int ret;
+
+	ret = reset_get_by_index(dev, 0, &m4->m4_rst);
+	if (ret) {
+		dev_err(dev, "reset_get() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = ti_sci_proc_of_to_priv(dev, &m4->tsp);
+	if (ret)
+		return ret;
+
+	ret =  k3_m4_of_get_memories(dev);
+	if (ret)
+		return ret;
+
+	m4->data = (struct k3_m4_boot_data *)dev_get_driver_data(dev);
+
+	return 0;
+}
+
+/**
+ * k3_m4_probe() - Basic probe
+ * @dev:	corresponding k3 remote processor device
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+static int k3_m4_probe(struct udevice *dev)
+{
+	struct k3_m4_privdata *m4;
+	int ret;
+
+	m4 = dev_get_priv(dev);
+	ret = k3_m4_of_to_priv(dev, m4);
+	if (ret)
+		return ret;
+
+	/*
+	 * The M4 local resets are deasserted by default on Power-On-Reset.
+	 * Assert the local resets to ensure the M4s don't execute bogus code
+	 * in .load() callback when the module reset is released to support
+	 * internal memory loading. This is needed for M4 cores.
+	 */
+	reset_assert(&m4->m4_rst);
+
+	return 0;
+}
+
+static int k3_m4_remove(struct udevice *dev)
+{
+	struct k3_m4_privdata *m4 = dev_get_priv(dev);
+
+	free(m4->mem);
+
+	return 0;
+}
+
+static const struct k3_m4_boot_data m4_data = {
+	.boot_align_addr = SZ_1K,
+};
+
+static const struct udevice_id k3_m4_ids[] = {
+	{ .compatible = "ti,am64-m4fss", .data = (ulong)&m4_data, },
+	{}
+};
+
+U_BOOT_DRIVER(k3_m4) = {
+	.name = "k3_m4",
+	.of_match = k3_m4_ids,
+	.id = UCLASS_REMOTEPROC,
+	.ops = &k3_m4_ops,
+	.probe = k3_m4_probe,
+	.remove = k3_m4_remove,
+	.priv_auto = sizeof(struct k3_m4_privdata),
+};
diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c
index d78b3fa..57268e7 100644
--- a/drivers/remoteproc/ti_k3_r5f_rproc.c
+++ b/drivers/remoteproc/ti_k3_r5f_rproc.c
@@ -886,6 +886,7 @@
 	{ .compatible = "ti,j7200-r5f", .data = (ulong)&j7200_j721s2_data, },
 	{ .compatible = "ti,j721s2-r5f", .data = (ulong)&j7200_j721s2_data, },
 	{ .compatible = "ti,am62-r5f", .data = (ulong)&am62_data, },
+	{ .compatible = "ti,am64-r5f", .data = (ulong)&j7200_j721s2_data, },
 	{}
 };
 
@@ -930,6 +931,7 @@
 	{ .compatible = "ti,j7200-r5fss"},
 	{ .compatible = "ti,j721s2-r5fss"},
 	{ .compatible = "ti,am62-r5fss"},
+	{ .compatible = "ti,am64-r5fss"},
 	{}
 };
 
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index a8ec2f4..50bd7be 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -124,8 +124,19 @@
 	u8		*rxd = din;
 	int		cpha = !!(priv->mode & SPI_CPHA);
 	int		cidle = !!(priv->mode & SPI_CPOL);
+	int		txrx = plat->flags;
 	unsigned int	j;
 
+	if (priv->mode & SPI_3WIRE) {
+		if (txd && rxd)
+			return -EINVAL;
+
+		txrx = txd ? SPI_MASTER_NO_RX : SPI_MASTER_NO_TX;
+		dm_gpio_set_dir_flags(&plat->mosi,
+				      txd ? GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE :
+					    GPIOD_IS_IN | GPIOD_PULL_UP);
+	}
+
 	debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n",
 	      dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd,
 	      bitlen);
@@ -160,7 +171,7 @@
 		 */
 		if (cpha)
 			soft_spi_scl(dev, !cidle);
-		if ((plat->flags & SPI_MASTER_NO_TX) == 0)
+		if ((txrx & SPI_MASTER_NO_TX) == 0)
 			soft_spi_sda(dev, !!(tmpdout & 0x80));
 		udelay(plat->spi_delay_us);
 
@@ -174,8 +185,10 @@
 		else
 			soft_spi_scl(dev, cidle);
 		tmpdin	<<= 1;
-		if ((plat->flags & SPI_MASTER_NO_RX) == 0)
-			tmpdin	|= dm_gpio_get_value(&plat->miso);
+		if ((txrx & SPI_MASTER_NO_RX) == 0)
+			tmpdin |= dm_gpio_get_value((priv->mode & SPI_3WIRE) ?
+							    &plat->mosi :
+							    &plat->miso);
 		tmpdout	<<= 1;
 		udelay(plat->spi_delay_us);
 
diff --git a/drivers/timer/sandbox_timer.c b/drivers/timer/sandbox_timer.c
index e8b54a0..c1baf3c 100644
--- a/drivers/timer/sandbox_timer.c
+++ b/drivers/timer/sandbox_timer.c
@@ -18,6 +18,11 @@
 	sandbox_timer_offset += offset;
 }
 
+ulong timer_test_get_offset(void)
+{
+	return sandbox_timer_offset;
+};
+
 u64 notrace timer_early_get_count(void)
 {
 	return os_get_nsec() / 1000 + sandbox_timer_offset * 1000;
diff --git a/include/configs/am335x_guardian.h b/include/configs/am335x_guardian.h
index 96efd38..385dec2 100644
--- a/include/configs/am335x_guardian.h
+++ b/include/configs/am335x_guardian.h
@@ -63,11 +63,6 @@
 		  "fi; " \
 		  "setenv extrabootargs $extrabootargs \"swi_attached\"; " \
 		"fi;" \
-		"run bootcmd_ubifs0;\0" \
-	"altbootcmd=" \
-		"setenv boot_syslinux_conf \"extlinux/extlinux-rollback.conf\"; " \
-		"run distro_bootcmd; " \
-		"setenv boot_syslinux_conf \"extlinux/extlinux.conf\"; " \
 		"run bootcmd_ubifs0;\0"
 
 #endif /* ! CONFIG_XPL_BUILD */
diff --git a/include/configs/bk4r1.h b/include/configs/bk4r1.h
index 5df8d03..6d24c5d 100644
--- a/include/configs/bk4r1.h
+++ b/include/configs/bk4r1.h
@@ -16,8 +16,6 @@
 #define BK4_EXTRA_ENV_SETTINGS \
 	"bootlimit=3\0" \
 	"eraseuserdata=false\0" \
-	"altbootcmd=led 5 on; " \
-		"boot\0" \
 	"set_gpio103=mw 0x400ff0c4 0x0080; mw 0x4004819C 0x000011bf\0" \
 	"set_gpio102=mw 0x400ff0c4 0x40; mw 0x40048198 0x000011bf\0" \
 	"set_gpio96=mw 0x40048180 0x282; mw 0x400ff0c4 0x1\0"\
diff --git a/include/configs/brppt2.h b/include/configs/brppt2.h
index d01f0d3..93559a1 100644
--- a/include/configs/brppt2.h
+++ b/include/configs/brppt2.h
@@ -64,7 +64,6 @@
 " do echo \"### booting ${target} ###\"; run b_${target};" \
 " if test ${b_break} = 1; then; exit; fi; done\0" \
 "loaddev=mmc 0\0" \
-"altbootcmd=setenv b_mode 0; run b_default;\0" \
 "bootlimit=1\0" \
 "net2nor=sf probe && dhcp &&" \
 " tftp ${loadaddr} SPL && sf erase 0 +${filesize} &&" \
diff --git a/include/configs/display5.h b/include/configs/display5.h
index 51fa2b0..98b1e5a 100644
--- a/include/configs/display5.h
+++ b/include/configs/display5.h
@@ -170,7 +170,6 @@
 	"display=tianma-tm070-800x480\0" \
 	"board=display5\0" \
 	"mmcdev=0\0" \
-	"altbootcmd=run recovery\0" \
 	"bootdelay=1\0" \
 	"baudrate=115200\0" \
 	"ethact=FEC\0" \
diff --git a/include/configs/ge_b1x5v2.h b/include/configs/ge_b1x5v2.h
index f3d85c9..5e3f671 100644
--- a/include/configs/ge_b1x5v2.h
+++ b/include/configs/ge_b1x5v2.h
@@ -82,14 +82,6 @@
 	"doboot=" \
 		"echo Booting from mmc:${mmcdev}:${mmcpart} ...; " \
 		"run helix;\0" \
-	"altbootcmd=" \
-		"setenv mmcpart 1; run hasfirstboot || setenv mmcpart 2; " \
-		"run hasfirstboot || setenv mmcpart 0; " \
-		"if test ${mmcpart} != 0; then " \
-			"setenv bootcause REVERT; " \
-			"run swappartitions loadimage doboot; " \
-		"fi; " \
-		"run failbootcmd\0" \
 	"tryboot=" \
 		"setenv mmcpart 1; run hasfirstboot || setenv mmcpart 2; " \
 		"run loadimage || run swappartitions && run loadimage || " \
diff --git a/include/configs/ge_bx50v3.h b/include/configs/ge_bx50v3.h
index 07b3670..c8ef048 100644
--- a/include/configs/ge_bx50v3.h
+++ b/include/configs/ge_bx50v3.h
@@ -67,14 +67,6 @@
 		"Try again, or contact GE Service for support.\"; " \
 		"bootcount reset; " \
 		"while true; do sleep 1; done; \0" \
-	"altbootcmd=" \
-		"run doquiet; " \
-		"setenv partnum 1; run hasfirstboot || setenv partnum 2; " \
-		"run hasfirstboot || setenv partnum 0; " \
-		"if test ${partnum} != 0; then " \
-			"run swappartitions loadimage doboot; " \
-		"fi; " \
-		"run failbootcmd\0" \
 	"loadimage=" \
 		"ext2load ${dev} ${devnum}:${partnum} ${loadaddr} ${image}\0" \
 	"doboot=" \
diff --git a/include/configs/imx6-engicam.h b/include/configs/imx6-engicam.h
index 786b70f..3d5701c 100644
--- a/include/configs/imx6-engicam.h
+++ b/include/configs/imx6-engicam.h
@@ -47,7 +47,6 @@
 	"loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
 	"loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
 	"loadfit=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${fit_image}\0" \
-	"altbootcmd=run recoveryboot\0"\
 	"fitboot=echo Booting FIT image from mmc ...; " \
 		"run mmcargs; " \
 		"bootm ${loadaddr}\0" \
diff --git a/include/configs/imx6q-bosch-acc.h b/include/configs/imx6q-bosch-acc.h
index 64ddbf7..84da825 100644
--- a/include/configs/imx6q-bosch-acc.h
+++ b/include/configs/imx6q-bosch-acc.h
@@ -42,8 +42,7 @@
 	"env_persisted=0\0" \
 	"env_persist=if test ${env_persisted} != 1; " \
 		"then env set env_persisted 1; run save_env; fi;\0" \
-	"save_env=env save; env save\0" \
-	"altbootcmd=run handle_ustate; run switch_bootset; run save_env; run bootcmd\0"
+	"save_env=env save; env save\0"
 
 #define CFG_ENV_FLAGS_LIST_STATIC \
 	"bootset:bw," \
diff --git a/include/configs/imx8mm-mx8menlo.h b/include/configs/imx8mm-mx8menlo.h
index 7058d63..626ccae 100644
--- a/include/configs/imx8mm-mx8menlo.h
+++ b/include/configs/imx8mm-mx8menlo.h
@@ -18,14 +18,6 @@
 	"devtype=mmc\0"							\
 	"devnum=1\0"							\
 	"distro_bootpart=1\0"						\
-	"altbootcmd="							\
-		"mmc partconf 0 mmcpart ; "				\
-		"if test ${mmcpart} -eq 1 ; then "			\
-			"mmc partconf 0 1 2 0 ; "			\
-		"else "							\
-			"mmc partconf 0 1 1 0 ; "			\
-		"fi ; "							\
-		"boot\0"						\
 	"boot_file=fitImage\0"						\
 	"console=ttymxc0\0"						\
 	"fdt_addr=0x43000000\0"						\
diff --git a/include/configs/imx8mm_data_modul_edm_sbc.h b/include/configs/imx8mm_data_modul_edm_sbc.h
index 57ecb5e..5ce4219 100644
--- a/include/configs/imx8mm_data_modul_edm_sbc.h
+++ b/include/configs/imx8mm_data_modul_edm_sbc.h
@@ -34,7 +34,6 @@
 #define CFG_SYS_FSL_ESDHC_ADDR	0
 
 #define CFG_EXTRA_ENV_SETTINGS						\
-	"altbootcmd=run bootcmd\0"					\
 	"bootlimit=3\0"							\
 	"devtype=mmc\0"							\
 	"devpart=1\0"							\
diff --git a/include/configs/imx8mp_data_modul_edm_sbc.h b/include/configs/imx8mp_data_modul_edm_sbc.h
index de5bdd3..58a03b3 100644
--- a/include/configs/imx8mp_data_modul_edm_sbc.h
+++ b/include/configs/imx8mp_data_modul_edm_sbc.h
@@ -24,7 +24,6 @@
 #define FEC_QUIRK_ENET_MAC
 
 #define CFG_EXTRA_ENV_SETTINGS						\
-	"altbootcmd=run bootcmd\0"					\
 	"bootlimit=3\0"							\
 	"devtype=mmc\0"							\
 	"devpart=1\0"							\
diff --git a/include/configs/imx8mp_dhcom_pdk2.h b/include/configs/imx8mp_dhcom_pdk2.h
index c848fce..f3e239d 100644
--- a/include/configs/imx8mp_dhcom_pdk2.h
+++ b/include/configs/imx8mp_dhcom_pdk2.h
@@ -28,7 +28,6 @@
 #define CFG_SYS_FSL_ESDHC_ADDR	0
 
 #define CFG_EXTRA_ENV_SETTINGS						\
-	"altbootcmd=run bootcmd ; reset\0"				\
 	"bootlimit=3\0"							\
 	"dfu_alt_info="							\
 		/* RAM block at DRAM offset 256..768 MiB */		\
diff --git a/include/configs/m53menlo.h b/include/configs/m53menlo.h
index 1ea4fa5..a6aafb5 100644
--- a/include/configs/m53menlo.h
+++ b/include/configs/m53menlo.h
@@ -93,13 +93,6 @@
 	"splashfile=boot/usplash.bmp.gz\0"				\
 	"splashimage=0x88000000\0"					\
 	"splashpos=m,m\0"						\
-	"altbootcmd="							\
-		"if test ${mmcpart} -eq 1 ; then "			\
-			"setenv mmcpart 2 ; "				\
-		"else "							\
-			"setenv mmcpart 1 ; "				\
-		"fi ; "							\
-		"boot\0"						\
 	"stdout=serial,vidconsole\0"					\
 	"stderr=serial,vidconsole\0"					\
 	"addcons="							\
diff --git a/include/configs/mx53ppd.h b/include/configs/mx53ppd.h
index 6d1f669..3707de2 100644
--- a/include/configs/mx53ppd.h
+++ b/include/configs/mx53ppd.h
@@ -59,14 +59,6 @@
 		"Try again, or contact GE Service for support.\"; " \
 		"bootcount reset; " \
 		"while true; do sleep 1; done; \0" \
-	"altbootcmd=" \
-		"run doquiet; " \
-		"setenv partnum 1; run hasfirstboot || setenv partnum 2; " \
-		"run hasfirstboot || setenv partnum 0; " \
-		"if test ${partnum} != 0; then " \
-			"run swappartitions loadimage doboot; " \
-		"fi; " \
-		"run failbootcmd\0" \
 	"loadimage=" \
 		"ext2load ${dev} ${devnum}:${partnum} ${loadaddr} ${image}\0" \
 	"doboot=" \
diff --git a/include/configs/siemens-am33x-common.h b/include/configs/siemens-am33x-common.h
index 74b7fe8..a918dc1 100644
--- a/include/configs/siemens-am33x-common.h
+++ b/include/configs/siemens-am33x-common.h
@@ -128,7 +128,6 @@
 	"verify=no \0" \
 	"project_dir=targetdir\0" \
 	"upgrade_available=0\0" \
-	"altbootcmd=run bootcmd\0" \
 	"partitionset_active=A\0" \
 	"loadaddr=0x82000000\0" \
 	"kloadaddr=0x81000000\0" \
diff --git a/include/configs/siemens-env-common.h b/include/configs/siemens-env-common.h
index 36fa5d9..c028823 100644
--- a/include/configs/siemens-env-common.h
+++ b/include/configs/siemens-env-common.h
@@ -183,7 +183,6 @@
 	"rootfs_name=/dev/mmcblk0\0" \
 	"upgrade_available=0\0" \
 	"bootlimit=3\0" \
-	"altbootcmd=run bootcmd\0" \
 	"optargs=\0" \
 
 /**********************************************************************/
diff --git a/include/configs/snapper9g45.h b/include/configs/snapper9g45.h
index df8ed45..8ea708d 100644
--- a/include/configs/snapper9g45.h
+++ b/include/configs/snapper9g45.h
@@ -58,8 +58,7 @@
 	"boot_tftp=setenv bootargs $bootargs_def ip=any nfsroot=$nfsroot; setenv autoload y && bootp && bootm\0" \
 	"boot_usb=setenv bootargs $bootargs_def; usb start && usb storage && fatload usb 0:1 $loadaddr dds-xm200.bin && bootm\0" \
 	"boot_mmc=setenv bootargs $bootargs_def; mmc rescan && fatload mmc 0:1 $loadaddr dds-xm200.bin && bootm\0" \
-	"bootcmd=run boot_mmc ; run boot_usb ; run boot_working ; run boot_safe\0" \
-	"altbootcmd=run boot_mmc ; run boot_usb ; run boot_safe ; run boot_working\0"
+	"bootcmd=run boot_mmc ; run boot_usb ; run boot_working ; run boot_safe\0"
 
 /* Console settings */
 
diff --git a/include/env/pg-wcom/common.env b/include/env/pg-wcom/common.env
index 4b660ce..5f2ba1c 100644
--- a/include/env/pg-wcom/common.env
+++ b/include/env/pg-wcom/common.env
@@ -22,7 +22,6 @@
 		WCOM_UBI_LINUX_MTD
 
 addpanic=setenv bootargs ${bootargs} panic=1 panic_on_oops=1
-altbootcmd=run bootcmd
 backup_bank=0
 boot=bootm ${load_addr_r} - ${fdt_addr_r}
 
diff --git a/include/env_default.h b/include/env_default.h
index aa3dd40..60c39f9 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -115,6 +115,9 @@
 #if defined(CONFIG_BOOTCOUNT_BOOTLIMIT) && (CONFIG_BOOTCOUNT_BOOTLIMIT > 0)
 	"bootlimit="	__stringify(CONFIG_BOOTCOUNT_BOOTLIMIT)"\0"
 #endif
+#ifdef CONFIG_BOOTCOUNT_ALTBOOTCMD
+	"altbootcmd="	CONFIG_BOOTCOUNT_ALTBOOTCMD            "\0"
+#endif
 #ifdef CONFIG_MTDIDS_DEFAULT
 	 "mtdids="	CONFIG_MTDIDS_DEFAULT		"\0"
 #endif
diff --git a/include/test/fdt_overlay.h b/include/test/fdt_overlay.h
new file mode 100644
index 0000000..251ad0e
--- /dev/null
+++ b/include/test/fdt_overlay.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2016 NextThing Co
+ * Copyright (c) 2016 Free Electrons
+ */
+
+#ifndef __TEST_OVERLAY_H__
+#define __TEST_OVERLAY_H__
+
+#include <test/test.h>
+
+/* Declare a new FDT-overlay test */
+#define FDT_OVERLAY_TEST(_name, _flags)	UNIT_TEST(_name, _flags, fdt_overlay)
+
+/* Declare init for FDT-overlay test */
+#define FDT_OVERLAY_TEST_INIT(_name, _flags)		\
+	UNIT_TEST_INIT(_name, _flags, fdt_overlay)
+
+#endif /* __TEST_OVERLAY_H__ */
diff --git a/include/test/optee.h b/include/test/optee.h
index f4255b3..0a548a5 100644
--- a/include/test/optee.h
+++ b/include/test/optee.h
@@ -8,7 +8,9 @@
 
 #include <test/test.h>
 
-/* Declare a new environment test */
+/* Declare a new optee test */
 #define OPTEE_TEST(_name, _flags)	UNIT_TEST(_name, _flags, optee)
+#define OPTEE_TEST_INIT(_name, _flags)	UNIT_TEST_INIT(_name, _flags, optee)
+#define OPTEE_TEST_UNINIT(_name, _flags) UNIT_TEST_UNINIT(_name, _flags, optee)
 
 #endif /* __TEST_OPTEE_H__ */
diff --git a/include/test/overlay.h b/include/test/overlay.h
deleted file mode 100644
index 5dc9839..0000000
--- a/include/test/overlay.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2016 NextThing Co
- * Copyright (c) 2016 Free Electrons
- */
-
-#ifndef __TEST_OVERLAY_H__
-#define __TEST_OVERLAY_H__
-
-#include <test/test.h>
-
-/* Declare a new environment test */
-#define OVERLAY_TEST(_name, _flags)	UNIT_TEST(_name, _flags, overlay)
-
-#endif /* __TEST_OVERLAY_H__ */
diff --git a/include/test/suites.h b/include/test/suites.h
deleted file mode 100644
index 774dd89..0000000
--- a/include/test/suites.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * (C) Copyright 2015
- * Joe Hershberger, National Instruments, joe.hershberger@ni.com
- */
-
-#ifndef __TEST_SUITES_H__
-#define __TEST_SUITES_H__
-
-struct cmd_tbl;
-struct unit_test;
-struct unit_test_state;
-
-/* 'command' functions normally called do_xxx where xxx is the command name */
-typedef int (*ut_cmd_func)(struct unit_test_state *uts, struct cmd_tbl *cmd,
-			   int flags, int argc, char *const argv[]);
-
-/**
- * cmd_ut_category() - Run a category of unit tests
- *
- * @uts: Unit-test state, which must be ready for use, i.e. ut_init_state()
- *	has been called. The caller is responsible for calling
- *	ut_uninit_state() after this function returns
- * @name:	Category name
- * @prefix:	Prefix of test name
- * @tests:	List of tests to run
- * @n_ents:	Number of tests in @tests
- * @argc:	Argument count provided. Must be >= 1. If this is 1 then all
- *		tests are run, otherwise only the one named @argv[1] is run.
- * @argv:	Arguments: argv[1] is the test to run (if @argc >= 2)
- * Return: 0 if OK, CMD_RET_FAILURE on failure
- */
-int cmd_ut_category(struct unit_test_state *uts, const char *name,
-		    const char *prefix, struct unit_test *tests, int n_ents,
-		    int argc, char *const argv[]);
-
-int do_ut_bootstd(struct unit_test_state *uts, struct cmd_tbl *cmdtp, int flag,
-		  int argc, char *const argv[]);
-int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
-int do_ut_overlay(struct unit_test_state *uts, struct cmd_tbl *cmdtp, int flag,
-		  int argc, char *const argv[]);
-
-#endif /* __TEST_SUITES_H__ */
diff --git a/include/test/test.h b/include/test/test.h
index bac43c8..0f2b68a 100644
--- a/include/test/test.h
+++ b/include/test/test.h
@@ -16,11 +16,15 @@
  * @skip_count: Number of tests that were skipped
  * @test_count: Number of tests run. If a test is run muiltiple times, only one
  *	is counted
+ * @start: Timer value when test started
+ * @duration_ms: Suite duration in milliseconds
  */
 struct ut_stats {
 	int fail_count;
 	int skip_count;
 	int test_count;
+	ulong start;
+	ulong duration_ms;
 };
 
 /*
@@ -29,6 +33,8 @@
  * @cur: Statistics for the current run
  * @total: Statistics for all test runs
  * @run_count: Number of times ut_run_list() has been called
+ * @worst: Sute which had the first per-text run time
+ * @worst_ms: Time taken by that test
  * @start: Store the starting mallinfo when doing leak test
  * @of_live: true to use livetree if available, false to use flattree
  * @of_root: Record of the livetree root node (used for setting up tests)
@@ -52,6 +58,8 @@
 	struct ut_stats cur;
 	struct ut_stats total;
 	int run_count;
+	const struct suite *worst;
+	int worst_ms;
 	struct mallinfo start;
 	struct device_node *of_root;
 	bool of_live;
@@ -92,6 +100,8 @@
 	UTF_ETH_BOOTDEV	= BIT(9),	/* enable Ethernet bootdevs */
 	UTF_SF_BOOTDEV	= BIT(10),	/* enable SPI flash bootdevs */
 	UFT_BLOBLIST	= BIT(11),	/* test changes gd->bloblist */
+	UTF_INIT	= BIT(12),	/* test inits a suite */
+	UTF_UNINIT	= BIT(13),	/* test uninits a suite */
 };
 
 /**
@@ -139,6 +149,24 @@
 		.func = _name,						\
 	}
 
+/* init function for unit-test suite (the 'A' makes it first) */
+#define UNIT_TEST_INIT(_name, _flags, _suite)				\
+	ll_entry_declare(struct unit_test, A ## _name, ut_ ## _suite) = {	\
+		.file = __FILE__,					\
+		.name = #_name,						\
+		.flags = (_flags) | UTF_INIT,				\
+		.func = _name,						\
+	}
+
+/* uninit function for unit-test suite (the 'aaa' makes it last) */
+#define UNIT_TEST_UNINIT(_name, _flags, _suite)				\
+	ll_entry_declare(struct unit_test, zzz ## _name, ut_ ## _suite) = { \
+		.file = __FILE__,					\
+		.name = #_name,						\
+		.flags = (_flags) | UTF_UNINIT,				\
+		.func = _name,						\
+	}
+
 /* Get the start of a list of unit tests for a particular suite */
 #define UNIT_TEST_SUITE_START(_suite) \
 	ll_entry_start(struct unit_test, ut_ ## _suite)
diff --git a/include/time.h b/include/time.h
index 3b2ba09..f5b86bf 100644
--- a/include/time.h
+++ b/include/time.h
@@ -28,7 +28,7 @@
  */
 unsigned long get_timer_us_long(unsigned long base);
 
-/*
+/**
  * timer_test_add_offset()
  *
  * Allow tests to add to the time reported through lib/time.c functions
@@ -36,6 +36,19 @@
  */
 void timer_test_add_offset(unsigned long offset);
 
+#ifdef CONFIG_SANDBOX
+/**
+ * timer_test_get_offset()
+ *
+ * Get the total offset currently being added the time
+ *
+ * Return:: number of milliseconds the system time has been advanced
+ */
+ulong timer_test_get_offset(void);
+#else
+static inline ulong timer_test_get_offset(void) { return 0; }
+#endif
+
 /**
  * usec_to_tick() - convert microseconds to clock ticks
  *
diff --git a/test/Kconfig b/test/Kconfig
index 558a9cd..31016ee 100644
--- a/test/Kconfig
+++ b/test/Kconfig
@@ -20,9 +20,18 @@
 	  of-platdata and SPL handover. To run these tests with the sandbox_spl
 	  board, use the -u (unit test) option.
 
+if UNIT_TEST
+
+config UNIT_TEST_DURATION
+	bool "Report unit-test duration"
+	default y
+	help
+	  Enable this short the time taken by each test suite. This is reported
+	  after the suite runs, alongside the pass/fail results. In addition,
+	  an overall total is reported if multiple suites are run.
+
 config UT_LIB
 	bool "Unit tests for library functions"
-	depends on UNIT_TEST
 	default y if !SANDBOX_VPL
 	help
 	  Enables the 'ut lib' command which tests library functions like
@@ -63,16 +72,15 @@
 	  Enables rsa_verify() test, currently rsa_verify_with_pkey only()
 	  only, at the 'ut lib' command.
 
-endif
+endif  # UT_LIB
 
 config UT_BOOTSTD
 	bool "Unit tests for standard boot"
-	depends on UNIT_TEST && BOOTSTD && SANDBOX
+	depends on BOOTSTD && SANDBOX
 	default y
 
 config UT_COMPRESSION
 	bool "Unit test for compression"
-	depends on UNIT_TEST
 	depends on CMDLINE && GZIP_COMPRESSED && BZIP2 && LZMA && LZO && LZ4 && ZSTD
 	default y
 	help
@@ -81,7 +89,6 @@
 
 config UT_LOG
 	bool "Unit tests for logging functions"
-	depends on UNIT_TEST
 	default y
 	help
 	  Enables the 'ut log' command which tests logging functions like
@@ -90,7 +97,6 @@
 
 config UT_TIME
 	bool "Unit tests for time functions"
-	depends on UNIT_TEST
 	help
 	  Enables the 'ut time' command which tests that the time functions
 	  work correctly. The test is fairly simple and will not catch all
@@ -99,7 +105,6 @@
 
 config UT_UNICODE
 	bool "Unit tests for Unicode functions"
-	depends on UNIT_TEST
 	default y
 	select CHARSET
 	help
@@ -111,7 +116,9 @@
 source "test/image/Kconfig"
 source "test/lib/Kconfig"
 source "test/optee/Kconfig"
-source "test/overlay/Kconfig"
+source "test/fdt_overlay/Kconfig"
+
+endif  # UNIT_TEST
 
 config POST
 	bool "Power On Self Test support"
diff --git a/test/Makefile b/test/Makefile
index 47a07d6..99d4797 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -14,11 +14,14 @@
 ifneq ($(CONFIG_HUSH_PARSER),)
 obj-$(CONFIG_$(XPL_)CMDLINE) += hush/
 endif
+obj-$(CONFIG_UT_OPTEE) += optee/
 obj-y += ut.o
 
 ifeq ($(CONFIG_XPL_BUILD),)
 obj-y += boot/
 obj-$(CONFIG_UNIT_TEST) += common/
+obj-$(CONFIG_UT_ENV) += env/
+obj-$(CONFIG_UT_FDT_OVERLAY) += fdt_overlay/
 obj-y += log/
 else
 obj-$(CONFIG_SPL_UT_LOAD) += image/
diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c
index 8c44afd..5f07430 100644
--- a/test/boot/bootdev.c
+++ b/test/boot/bootdev.c
@@ -12,7 +12,6 @@
 #include <bootflow.h>
 #include <mapmem.h>
 #include <os.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include "bootstd_common.h"
 
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index a8735c1..eb7f00a 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -21,7 +21,6 @@
 #endif
 #include <dm/device-internal.h>
 #include <dm/lists.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include "bootstd_common.h"
 #include "../../boot/bootflow_internal.h"
diff --git a/test/boot/bootm.c b/test/boot/bootm.c
index 7e0ccb0..1d1efe7 100644
--- a/test/boot/bootm.c
+++ b/test/boot/bootm.c
@@ -7,7 +7,6 @@
 
 #include <bootm.h>
 #include <asm/global_data.h>
-#include <test/suites.h>
 #include <test/test.h>
 #include <test/ut.h>
 
diff --git a/test/boot/bootmeth.c b/test/boot/bootmeth.c
index 18ae6d7..577f259 100644
--- a/test/boot/bootmeth.c
+++ b/test/boot/bootmeth.c
@@ -9,7 +9,6 @@
 #include <bootmeth.h>
 #include <bootstd.h>
 #include <dm.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include "bootstd_common.h"
 
diff --git a/test/boot/bootstd_common.c b/test/boot/bootstd_common.c
index 724e3d9..052c0fe 100644
--- a/test/boot/bootstd_common.c
+++ b/test/boot/bootstd_common.c
@@ -13,7 +13,6 @@
 #include <mmc.h>
 #include <usb.h>
 #include <linux/log2.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include <u-boot/crc.h>
 #include "bootstd_common.h"
@@ -21,8 +20,14 @@
 /* tracks whether bootstd_setup_for_tests() has been run yet */
 bool vbe_setup_done;
 
-/* set up MMC for VBE tests */
-int bootstd_setup_for_tests(void)
+/**
+ * bootstd_setup_for_tests() - Set up MMC data for VBE tests
+ *
+ * Some data is needed for VBE tests to work. This function sets that up.
+ *
+ * @return 0 if OK, -ve on error
+ */
+static int bootstd_setup_for_tests(struct unit_test_state *uts)
 {
 	ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
 	struct udevice *mmc;
@@ -55,6 +60,7 @@
 
 	return 0;
 }
+BOOTSTD_TEST_INIT(bootstd_setup_for_tests, 0);
 
 int bootstd_test_drop_bootdev_order(struct unit_test_state *uts)
 {
@@ -93,20 +99,3 @@
 {
 	usb_started = false;
 }
-
-int do_ut_bootstd(struct unit_test_state *uts, struct cmd_tbl *cmdtp, int flag,
-		  int argc, char *const argv[])
-{
-	struct unit_test *tests = UNIT_TEST_SUITE_START(bootstd);
-	const int n_ents = UNIT_TEST_SUITE_COUNT(bootstd);
-	int ret;
-
-	ret = bootstd_setup_for_tests();
-	if (ret) {
-		printf("Failed to set up for bootstd tests (err=%d)\n", ret);
-		return CMD_RET_FAILURE;
-	}
-
-	return cmd_ut_category(uts, "bootstd", "bootstd_",
-			       tests, n_ents, argc, argv);
-}
diff --git a/test/boot/bootstd_common.h b/test/boot/bootstd_common.h
index ea3ecd1..c61698a 100644
--- a/test/boot/bootstd_common.h
+++ b/test/boot/bootstd_common.h
@@ -13,6 +13,7 @@
 
 /* Declare a new bootdev test */
 #define BOOTSTD_TEST(_name, _flags)	UNIT_TEST(_name, _flags, bootstd)
+#define BOOTSTD_TEST_INIT(_name, _flags) UNIT_TEST_INIT(_name, _flags, bootstd)
 
 #define NVDATA_START_BLK	((0x400 + 0x400) / MMC_MAX_BLOCK_LEN)
 #define VERSION_START_BLK	((0x400 + 0x800) / MMC_MAX_BLOCK_LEN)
@@ -36,15 +37,6 @@
 int bootstd_test_drop_bootdev_order(struct unit_test_state *uts);
 
 /**
- * bootstd_setup_for_tests() - Set up MMC data for VBE tests
- *
- * Some data is needed for VBE tests to work. This function sets that up.
- *
- * @return 0 if OK, -ve on error
- */
-int bootstd_setup_for_tests(void);
-
-/**
  * bootstd_test_check_mmc_hunter() - Check that the mmc bootdev hunter was used
  *
  * @uts: Unit test state to use for ut_assert...() functions
diff --git a/test/boot/expo.c b/test/boot/expo.c
index db14ff8..1d283a2 100644
--- a/test/boot/expo.c
+++ b/test/boot/expo.c
@@ -10,7 +10,6 @@
 #include <menu.h>
 #include <video.h>
 #include <linux/input.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include "bootstd_common.h"
 #include <test/cedit-test.h>
diff --git a/test/boot/image.c b/test/boot/image.c
index 0894e30..4df7b17 100644
--- a/test/boot/image.c
+++ b/test/boot/image.c
@@ -7,7 +7,6 @@
  */
 
 #include <image.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include "bootstd_common.h"
 
diff --git a/test/boot/measurement.c b/test/boot/measurement.c
index 5a49c7a..1d38663 100644
--- a/test/boot/measurement.c
+++ b/test/boot/measurement.c
@@ -8,7 +8,6 @@
 
 #include <bootm.h>
 #include <malloc.h>
-#include <test/suites.h>
 #include <test/test.h>
 #include <test/ut.h>
 #include <asm/io.h>
diff --git a/test/boot/upl.c b/test/boot/upl.c
index aa58cdf..eec8902 100644
--- a/test/boot/upl.c
+++ b/test/boot/upl.c
@@ -10,7 +10,6 @@
 #include <mapmem.h>
 #include <upl.h>
 #include <dm/ofnode.h>
-#include <test/suites.h>
 #include <test/test.h>
 #include <test/ut.h>
 #include "bootstd_common.h"
diff --git a/test/boot/vbe_simple.c b/test/boot/vbe_simple.c
index 4fe4323..c37de62 100644
--- a/test/boot/vbe_simple.c
+++ b/test/boot/vbe_simple.c
@@ -11,7 +11,6 @@
 #include <image.h>
 #include <of_live.h>
 #include <vbe.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include "bootstd_common.h"
 
@@ -33,9 +32,6 @@
 	ofnode node;
 	u32 vernum;
 
-	/* Set up the VBE info */
-	ut_assertok(bootstd_setup_for_tests());
-
 	/* Read the version back */
 	ut_assertok(vbe_find_by_any("firmware0", &dev));
 	ut_assertok(bootmeth_get_state_desc(dev, info, sizeof(info)));
diff --git a/test/cmd/addrmap.c b/test/cmd/addrmap.c
index 1f2deb1..72798b9 100644
--- a/test/cmd/addrmap.c
+++ b/test/cmd/addrmap.c
@@ -6,7 +6,6 @@
  */
 
 #include <console.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 /* Declare a new addrmap test */
diff --git a/test/cmd/bdinfo.c b/test/cmd/bdinfo.c
index 7408c27..09f44ee 100644
--- a/test/cmd/bdinfo.c
+++ b/test/cmd/bdinfo.c
@@ -10,7 +10,6 @@
 #include <mapmem.h>
 #include <asm/global_data.h>
 #include <dm/uclass.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include <dm.h>
 #include <env.h>
diff --git a/test/cmd/exit.c b/test/cmd/exit.c
index 71c37ed..fdde054 100644
--- a/test/cmd/exit.c
+++ b/test/cmd/exit.c
@@ -8,7 +8,6 @@
 #include <console.h>
 #include <mapmem.h>
 #include <asm/global_data.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/test/cmd/fdt.c b/test/cmd/fdt.c
index ab6dbd4..c11c181 100644
--- a/test/cmd/fdt.c
+++ b/test/cmd/fdt.c
@@ -10,7 +10,6 @@
 #include <mapmem.h>
 #include <asm/global_data.h>
 #include <linux/libfdt.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/test/cmd/font.c b/test/cmd/font.c
index af88d1b..7ae648d 100644
--- a/test/cmd/font.c
+++ b/test/cmd/font.c
@@ -8,7 +8,6 @@
 #include <console.h>
 #include <dm.h>
 #include <video_console.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 /* Declare a new fdt test */
diff --git a/test/cmd/loadm.c b/test/cmd/loadm.c
index 3c623aa..043cd25 100644
--- a/test/cmd/loadm.c
+++ b/test/cmd/loadm.c
@@ -13,7 +13,6 @@
 #include <mapmem.h>
 #include <asm/global_data.h>
 #include <dm/test.h>
-#include <test/suites.h>
 #include <test/test.h>
 #include <test/ut.h>
 
diff --git a/test/cmd/mbr.c b/test/cmd/mbr.c
index 45bab04..e651256 100644
--- a/test/cmd/mbr.c
+++ b/test/cmd/mbr.c
@@ -15,7 +15,6 @@
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <linux/sizes.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/test/cmd/pci_mps.c b/test/cmd/pci_mps.c
index 8b3ea4a..6618c24 100644
--- a/test/cmd/pci_mps.c
+++ b/test/cmd/pci_mps.c
@@ -8,7 +8,6 @@
  */
 
 #include <console.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 #define PCI_MPS_TEST(_name, _flags) UNIT_TEST(_name, _flags, pci_mps)
diff --git a/test/cmd/seama.c b/test/cmd/seama.c
index 1edc3fc..39f85f1 100644
--- a/test/cmd/seama.c
+++ b/test/cmd/seama.c
@@ -7,7 +7,6 @@
 
 #include <command.h>
 #include <dm.h>
-#include <test/suites.h>
 #include <test/test.h>
 #include <test/ut.h>
 
diff --git a/test/cmd/setexpr.c b/test/cmd/setexpr.c
index 5e9b577..85803eb 100644
--- a/test/cmd/setexpr.c
+++ b/test/cmd/setexpr.c
@@ -9,7 +9,6 @@
 #include <console.h>
 #include <mapmem.h>
 #include <dm/test.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 #define BUF_SIZE	0x100
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index fbfdaaa..44e5fdf 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -7,7 +7,6 @@
 #include <command.h>
 #include <console.h>
 #include <vsprintf.h>
-#include <test/suites.h>
 #include <test/test.h>
 #include <test/ut.h>
 
@@ -20,77 +19,31 @@
  * @name: Name of suite
  * @start: First test in suite
  * @end: End test in suite (points to the first test in the next suite)
- * @cmd: Command to use to run the suite
  * @help: Help-string to show for this suite
  */
 struct suite {
 	const char *name;
 	struct unit_test *start;
 	struct unit_test *end;
-	ut_cmd_func cmd;
 	const char *help;
 };
 
-static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
-		     int flag, int argc, char *const argv[]);
+static int do_ut_all(struct unit_test_state *uts, const char *select_name,
+		     int runs_per_test, bool force_run,
+		     const char *test_insert);
 
-static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
-		      char *const argv[]);
-
-int cmd_ut_category(struct unit_test_state *uts, const char *name,
-		    const char *prefix, struct unit_test *tests, int n_ents,
-		    int argc, char *const argv[])
-{
-	const char *test_insert = NULL;
-	int runs_per_text = 1;
-	bool force_run = false;
-	int ret;
-
-	while (argc > 1 && *argv[1] == '-') {
-		const char *str = argv[1];
-
-		switch (str[1]) {
-		case 'r':
-			runs_per_text = dectoul(str + 2, NULL);
-			break;
-		case 'f':
-			force_run = true;
-			break;
-		case 'I':
-			test_insert = str + 2;
-			break;
-		}
-		argv++;
-		argc--;
-	}
-
-	ret = ut_run_list(uts, name, prefix, tests, n_ents,
-			  cmd_arg1(argc, argv), runs_per_text, force_run,
-			  test_insert);
-
-	return ret ? CMD_RET_FAILURE : 0;
-}
+static int do_ut_info(bool show_suites);
 
 /* declare linker-list symbols for the start and end of a suite */
 #define SUITE_DECL(_name) \
 	ll_start_decl(suite_start_ ## _name, struct unit_test, ut_ ## _name); \
 	ll_end_decl(suite_end_ ## _name, struct unit_test, ut_ ## _name)
 
-/* declare a test suite which uses a subcommand to run */
-#define SUITE_CMD(_name, _cmd_func, _help) { \
-	#_name, \
-	suite_start_ ## _name, \
-	suite_end_ ## _name, \
-	_cmd_func, \
-	_help, \
-	}
-
 /* declare a test suite which can be run directly without a subcommand */
 #define SUITE(_name, _help) { \
 	#_name, \
 	suite_start_ ## _name, \
 	suite_end_ ## _name, \
-	NULL, \
 	_help, \
 	}
 
@@ -105,6 +58,7 @@
 SUITE_DECL(env);
 SUITE_DECL(exit);
 SUITE_DECL(fdt);
+SUITE_DECL(fdt_overlay);
 SUITE_DECL(font);
 SUITE_DECL(hush);
 SUITE_DECL(lib);
@@ -114,7 +68,6 @@
 SUITE_DECL(measurement);
 SUITE_DECL(mem);
 SUITE_DECL(optee);
-SUITE_DECL(overlay);
 SUITE_DECL(pci_mps);
 SUITE_DECL(seama);
 SUITE_DECL(setexpr);
@@ -125,15 +78,14 @@
 	SUITE(bdinfo, "bdinfo (board info) command"),
 	SUITE(bloblist, "bloblist implementation"),
 	SUITE(bootm, "bootm command"),
-#ifdef CONFIG_UT_BOOTSTD
-	SUITE_CMD(bootstd, do_ut_bootstd, "standard boot implementation"),
-#endif
+	SUITE(bootstd, "standard boot implementation"),
 	SUITE(cmd, "various commands"),
 	SUITE(common, "tests for common/ directory"),
 	SUITE(dm, "driver model"),
 	SUITE(env, "environment"),
 	SUITE(exit, "shell exit and variables"),
 	SUITE(fdt, "fdt command"),
+	SUITE(fdt_overlay, "device tree overlays"),
 	SUITE(font, "font command"),
 	SUITE(hush, "hush behaviour"),
 	SUITE(lib, "library functions"),
@@ -142,12 +94,7 @@
 	SUITE(mbr, "mbr command"),
 	SUITE(measurement, "TPM-based measured boot"),
 	SUITE(mem, "memory-related commands"),
-#ifdef CONFIG_UT_OPTEE
-	SUITE_CMD(optee, do_ut_optee, "OP-TEE"),
-#endif
-#ifdef CONFIG_UT_OVERLAY
-	SUITE_CMD(overlay, do_ut_overlay, "device tree overlays"),
-#endif
+	SUITE(optee, "OP-TEE"),
 	SUITE(pci_mps, "PCI Express Maximum Payload Size"),
 	SUITE(seama, "seama command parameters loading and decoding"),
 	SUITE(setexpr, "setexpr command"),
@@ -167,33 +114,59 @@
 {
 	int n_ents = ste->end - ste->start;
 
-	return n_ents || ste->cmd;
+	return n_ents;
 }
 
 /** run_suite() - Run a suite of tests */
 static int run_suite(struct unit_test_state *uts, struct suite *ste,
-		     struct cmd_tbl *cmdtp, int flag, int argc,
-		     char *const argv[])
+		     const char *select_name, int runs_per_test, bool force_run,
+		     const char *test_insert)
 {
+	int n_ents = ste->end - ste->start;
+	char prefix[30];
 	int ret;
 
-	if (ste->cmd) {
-		ret = ste->cmd(uts, cmdtp, flag, argc, argv);
-	} else {
-		int n_ents = ste->end - ste->start;
-		char prefix[30];
+	/* use a standard prefix */
+	snprintf(prefix, sizeof(prefix), "%s_test_", ste->name);
 
-		/* use a standard prefix */
-		snprintf(prefix, sizeof(prefix), "%s_test", ste->name);
-		ret = cmd_ut_category(uts, ste->name, prefix, ste->start,
-				      n_ents, argc, argv);
-	}
+	ret = ut_run_list(uts, ste->name, prefix, ste->start, n_ents,
+			  select_name, runs_per_test, force_run, test_insert);
 
 	return ret;
 }
 
+static void show_stats(struct unit_test_state *uts)
+{
+	if (uts->run_count < 2)
+		return;
+
+	ut_report(&uts->total, uts->run_count);
+	if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) &&
+	    uts->total.test_count && uts->worst) {
+		ulong avg = uts->total.duration_ms / uts->total.test_count;
+
+		printf("Average test time: %ld ms, worst case '%s' took %d ms\n",
+		       avg, uts->worst->name, uts->worst_ms);
+	}
+}
+
+static void update_stats(struct unit_test_state *uts, const struct suite *ste)
+{
+	if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION) && uts->cur.test_count) {
+		ulong avg;
+
+		avg = uts->cur.duration_ms ?
+			uts->cur.duration_ms /
+			uts->cur.test_count : 0;
+		if (avg > uts->worst_ms) {
+			uts->worst_ms = avg;
+			uts->worst = ste;
+		}
+	}
+}
+
-static int do_ut_all(struct unit_test_state *uts, struct cmd_tbl *cmdtp,
-		     int flag, int argc, char *const argv[])
+static int do_ut_all(struct unit_test_state *uts, const char *select_name,
+		     int runs_per_test, bool force_run, const char *test_insert)
 {
 	int i;
 	int retval;
@@ -201,25 +174,23 @@
 
 	for (i = 0; i < ARRAY_SIZE(suites); i++) {
 		struct suite *ste = &suites[i];
-		char *const argv[] = {(char *)ste->name, NULL};
 
 		if (has_tests(ste)) {
 			printf("----Running %s tests----\n", ste->name);
-			retval = run_suite(uts, ste, cmdtp, flag, 1, argv);
+			retval = run_suite(uts, ste, select_name, runs_per_test,
+					   force_run, test_insert);
 			if (!any_fail)
 				any_fail = retval;
+			update_stats(uts, ste);
 		}
 	}
-	ut_report(&uts->total, uts->run_count);
 
 	return any_fail;
 }
 
-static int do_ut_info(struct cmd_tbl *cmdtp, int flag, int argc,
-		      char *const argv[])
+static int do_ut_info(bool show_suites)
 {
 	int suite_count, i;
-	const char *flags;
 
 	for (suite_count = 0, i = 0; i < ARRAY_SIZE(suites); i++) {
 		struct suite *ste = &suites[i];
@@ -231,24 +202,26 @@
 	printf("Test suites: %d\n", suite_count);
 	printf("Total tests: %d\n", (int)UNIT_TEST_ALL_COUNT());
 
-	flags = cmd_arg1(argc, argv);
-	if (flags && !strcmp("-s", flags)) {
-		int i;
+	if (show_suites) {
+		int i, total;
 
 		puts("\nTests  Suite         Purpose");
 		puts("\n-----  ------------  -------------------------\n");
-		for (i = 0; i < ARRAY_SIZE(suites); i++) {
+		for (i = 0, total = 0; i < ARRAY_SIZE(suites); i++) {
 			struct suite *ste = &suites[i];
 			long n_ent = ste->end - ste->start;
 
-			if (n_ent)
-				printf("%5ld", n_ent);
-			else if (ste->cmd)
-				printf("%5s", "?");
-			else  /* suite is not present */
-				continue;
-			printf("  %-13.13s %s\n", ste->name, ste->help);
+			if (n_ent) {
+				printf("%5ld  %-13.13s %s\n", n_ent, ste->name,
+				       ste->help);
+				total += n_ent;
+			}
 		}
+		puts("-----  ------------  -------------------------\n");
+		printf("%5d  %-13.13s\n", total, "Total");
+
+		if (UNIT_TEST_ALL_COUNT() != total)
+			puts("Error: Suite test-count does not match total\n");
 	}
 
 	return 0;
@@ -269,37 +242,77 @@
 
 static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
+	const char *test_insert = NULL, *select_name;
 	struct unit_test_state uts;
+	bool show_suites = false;
+	bool force_run = false;
+	int runs_per_text = 1;
 	struct suite *ste;
-	const char *name;
+	char *name;
 	int ret;
 
-	if (argc < 2)
-		return CMD_RET_USAGE;
-
 	/* drop initial "ut" arg */
 	argc--;
 	argv++;
 
+	while (argc > 0 && *argv[0] == '-') {
+		const char *str = argv[0];
+
+		switch (str[1]) {
+		case 'r':
+			runs_per_text = dectoul(str + 2, NULL);
+			break;
+		case 'f':
+			force_run = true;
+			break;
+		case 'I':
+			test_insert = str + 2;
+			if (!strchr(test_insert, ':'))
+				return CMD_RET_USAGE;
+			break;
+		case 's':
+			show_suites = true;
+			break;
+		}
+		argv++;
+		argc--;
+	}
+
+	if (argc < 1)
+		return CMD_RET_USAGE;
+
 	ut_init_state(&uts);
 	name = argv[0];
+	select_name = cmd_arg1(argc, argv);
 	if (!strcmp(name, "all")) {
-		ret = do_ut_all(&uts, cmdtp, flag, argc, argv);
+		ret = do_ut_all(&uts, select_name, runs_per_text, force_run,
+				test_insert);
 	} else if (!strcmp(name, "info")) {
-		ret = do_ut_info(cmdtp, flag, argc, argv);
+		ret = do_ut_info(show_suites);
 	} else {
-		ste = find_suite(argv[0]);
-		if (!ste) {
-			printf("Suite '%s' not found\n", argv[0]);
-			return CMD_RET_FAILURE;
-		} else if (!has_tests(ste)) {
-			/* perhaps a Kconfig option needs to be set? */
-			printf("Suite '%s' is not enabled\n", argv[0]);
-			return CMD_RET_FAILURE;
-		}
+		int any_fail = 0;
+		const char *p;
+
+		for (; p = strsep(&name, ","), p; name = NULL) {
+			ste = find_suite(p);
+			if (!ste) {
+				printf("Suite '%s' not found\n", p);
+				return CMD_RET_FAILURE;
+			} else if (!has_tests(ste)) {
+				/* perhaps a Kconfig option needs to be set? */
+				printf("Suite '%s' is not enabled\n", p);
+				return CMD_RET_FAILURE;
+			}
 
-		ret = run_suite(&uts, ste, cmdtp, flag, argc, argv);
+			ret = run_suite(&uts, ste, select_name, runs_per_text,
+					force_run, test_insert);
+			if (!any_fail)
+				any_fail = ret;
+			update_stats(&uts, ste);
+		}
+		ret = any_fail;
 	}
+	show_stats(&uts);
 	if (ret)
 		return ret;
 	ut_uninit_state(&uts);
@@ -308,14 +321,16 @@
 }
 
 U_BOOT_LONGHELP(ut,
-	"[-r] [-f] [<suite>] - run unit tests\n"
+	"[-rs] [-f] [-I<n>:<one_test>][<suites>] - run unit tests\n"
 	"   -r<runs>   Number of times to run each test\n"
 	"   -f         Force 'manual' tests to run as well\n"
-	"   <suite>    Test suite to run, or all\n"
+	"   -I         Test to run after <n> other tests have run\n"
+	"   -s         Show all suites with ut info\n"
+	"   <suites>   Comma-separated list of suites to run\n"
 	"\n"
-	"\nOptions for <suite>:"
-	"\nall - execute all enabled tests"
-	"\ninfo [-s] - show info about tests [and suites]"
+	"Options for <suite>:\n"
+	"all       - execute all enabled tests\n"
+	"info      - show info about tests [and suites]"
 	);
 
 U_BOOT_CMD(
diff --git a/test/common/bloblist.c b/test/common/bloblist.c
index ab8f41c..797bde2 100644
--- a/test/common/bloblist.c
+++ b/test/common/bloblist.c
@@ -6,7 +6,6 @@
 #include <bloblist.h>
 #include <log.h>
 #include <mapmem.h>
-#include <test/suites.h>
 #include <test/test.h>
 #include <test/ut.h>
 
diff --git a/test/dm/Kconfig b/test/dm/Kconfig
index e5b341e..640421c 100644
--- a/test/dm/Kconfig
+++ b/test/dm/Kconfig
@@ -1,6 +1,6 @@
 config UT_DM
 	bool "Enable driver model unit test command"
-	depends on SANDBOX && UNIT_TEST
+	depends on SANDBOX
 	help
 	  This enables the 'ut dm' command which runs a series of unit
 	  tests on the driver model code. Each subsystem (uclass) is tested.
diff --git a/test/dm/mux-cmd.c b/test/dm/mux-cmd.c
index 6eb3b28..bd02cda 100644
--- a/test/dm/mux-cmd.c
+++ b/test/dm/mux-cmd.c
@@ -26,8 +26,6 @@
 	int i;
 	unsigned long val;
 
-	sandbox_set_enable_memio(true);
-
 	ut_assertok(uclass_get_device_by_name(UCLASS_MUX, "a-mux-controller",
 					      &dev));
 	chip = dev_get_uclass_priv(dev);
@@ -119,8 +117,6 @@
 	char cmd[BUF_SIZE];
 	unsigned int i, state;
 
-	sandbox_set_enable_memio(true);
-
 	ut_assertok(uclass_get_device_by_name(UCLASS_MUX, "a-mux-controller",
 					      &dev));
 	chip = dev_get_uclass_priv(dev);
@@ -153,8 +149,6 @@
 	char cmd[BUF_SIZE];
 	unsigned int i, state;
 
-	sandbox_set_enable_memio(true);
-
 	ut_assertok(uclass_get_device_by_name(UCLASS_MUX, "a-mux-controller",
 					      &dev));
 	chip = dev_get_uclass_priv(dev);
diff --git a/test/env/Kconfig b/test/env/Kconfig
index 6cb8233..21d88f4 100644
--- a/test/env/Kconfig
+++ b/test/env/Kconfig
@@ -1,6 +1,5 @@
 config UT_ENV
 	bool "Enable env unit tests"
-	depends on UNIT_TEST
 	default y
 	help
 	  This enables the 'ut env' command which runs a series of unit
diff --git a/test/env/cmd_ut_env.c b/test/env/cmd_ut_env.c
index 81d1bb2..43f1b7d 100644
--- a/test/env/cmd_ut_env.c
+++ b/test/env/cmd_ut_env.c
@@ -5,7 +5,6 @@
  */
 
 #include <test/env.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 static int env_test_env_cmd(struct unit_test_state *uts)
diff --git a/test/overlay/Kconfig b/test/fdt_overlay/Kconfig
similarity index 81%
rename from test/overlay/Kconfig
rename to test/fdt_overlay/Kconfig
index 8818489..c50b882 100644
--- a/test/overlay/Kconfig
+++ b/test/fdt_overlay/Kconfig
@@ -1,6 +1,6 @@
-config UT_OVERLAY
+config UT_FDT_OVERLAY
 	bool "Enable Device Tree Overlays Unit Tests"
-	depends on UNIT_TEST && OF_CONTROL && SANDBOX
+	depends on OF_CONTROL && SANDBOX
 	default y
 	select OF_LIBFDT_OVERLAY
 	help
diff --git a/test/overlay/Makefile b/test/fdt_overlay/Makefile
similarity index 89%
rename from test/overlay/Makefile
rename to test/fdt_overlay/Makefile
index 47937e3..5625c0d 100644
--- a/test/overlay/Makefile
+++ b/test/fdt_overlay/Makefile
@@ -4,7 +4,7 @@
 # Copyright (c) 2016 Free Electrons
 
 # Test files
-obj-y += cmd_ut_overlay.o
+obj-y += cmd_ut_fdt_overlay.o
 
 DTC_FLAGS += -@
 
diff --git a/test/fdt_overlay/cmd_ut_fdt_overlay.c b/test/fdt_overlay/cmd_ut_fdt_overlay.c
new file mode 100644
index 0000000..0084033
--- /dev/null
+++ b/test/fdt_overlay/cmd_ut_fdt_overlay.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2016 NextThing Co
+ * Copyright (c) 2016 Free Electrons
+ */
+
+#include <command.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <image.h>
+#include <log.h>
+#include <malloc.h>
+
+#include <linux/sizes.h>
+
+#include <test/fdt_overlay.h>
+#include <test/ut.h>
+
+/* 4k ought to be enough for anybody */
+#define FDT_COPY_SIZE	(4 * SZ_1K)
+
+extern u32 __dtb_test_fdt_base_begin;
+extern u32 __dtbo_test_fdt_overlay_begin;
+extern u32 __dtbo_test_fdt_overlay_stacked_begin;
+
+static void *fdt;
+
+static int fdt_overlay_init(struct unit_test_state *uts)
+{
+	void *fdt_base = &__dtb_test_fdt_base_begin;
+	void *fdt_overlay = &__dtbo_test_fdt_overlay_begin;
+	void *fdt_overlay_stacked = &__dtbo_test_fdt_overlay_stacked_begin;
+	void *fdt_overlay_copy, *fdt_overlay_stacked_copy;
+
+	ut_assertok(fdt_check_header(fdt_base));
+	ut_assertok(fdt_check_header(fdt_overlay));
+
+	fdt = malloc(FDT_COPY_SIZE);
+	fdt_overlay_copy = malloc(FDT_COPY_SIZE);
+	fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE);
+	ut_assertnonnull(fdt);
+	ut_assertnonnull(fdt_overlay_copy);
+	ut_assertnonnull(fdt_overlay_stacked_copy);
+
+	/*
+	 * Resize the FDT to 4k so that we have room to operate on
+	 *
+	 * (and relocate it since the memory might be mapped
+	 * read-only)
+	 */
+	ut_assertok(fdt_open_into(fdt_base, fdt, FDT_COPY_SIZE));
+
+	/*
+	 * Resize the overlay to 4k so that we have room to operate on
+	 *
+	 * (and relocate it since the memory might be mapped
+	 * read-only)
+	 */
+	ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
+				  FDT_COPY_SIZE));
+
+	/*
+	 * Resize the stacked overlay to 4k so that we have room to operate on
+	 *
+	 * (and relocate it since the memory might be mapped
+	 * read-only)
+	 */
+	ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy,
+				  FDT_COPY_SIZE));
+
+	/* Apply the overlay */
+	ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_copy));
+
+	/* Apply the stacked overlay */
+	ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_stacked_copy));
+
+	free(fdt_overlay_stacked_copy);
+	free(fdt_overlay_copy);
+
+	return 0;
+}
+FDT_OVERLAY_TEST_INIT(fdt_overlay_init, 0);
+
+static int fdt_getprop_str(void *fdt, const char *path, const char *name,
+			   const char **out)
+{
+	int node_off;
+	int len;
+
+	node_off = fdt_path_offset(fdt, path);
+	if (node_off < 0)
+		return node_off;
+
+	*out = fdt_stringlist_get(fdt, node_off, name, 0, &len);
+
+	return len < 0 ? len : 0;
+}
+
+static int fdt_overlay_test_change_int_property(struct unit_test_state *uts)
+{
+	int off;
+
+	off = fdt_path_offset(fdt, "/test-node");
+	ut_assert(off >= 0);
+
+	ut_asserteq(43, fdtdec_get_uint(fdt, off, "test-int-property", 0));
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_change_int_property, 0);
+
+static int fdt_overlay_test_change_str_property(struct unit_test_state *uts)
+{
+	const char *val = NULL;
+
+	ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property",
+				    &val));
+	ut_asserteq_str("foobar", val);
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_change_str_property, 0);
+
+static int fdt_overlay_test_add_str_property(struct unit_test_state *uts)
+{
+	const char *val = NULL;
+
+	ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property-2",
+				    &val));
+	ut_asserteq_str("foobar2", val);
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_add_str_property, 0);
+
+static int fdt_overlay_test_add_node_by_phandle(struct unit_test_state *uts)
+{
+	int off;
+
+	off = fdt_path_offset(fdt, "/test-node/new-node");
+	ut_assert(off >= 0);
+
+	ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_add_node_by_phandle, 0);
+
+static int fdt_overlay_test_add_node_by_path(struct unit_test_state *uts)
+{
+	int off;
+
+	off = fdt_path_offset(fdt, "/new-node");
+	ut_assert(off >= 0);
+
+	ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_add_node_by_path, 0);
+
+static int fdt_overlay_test_add_subnode_property(struct unit_test_state *uts)
+{
+	int off;
+
+	off = fdt_path_offset(fdt, "/test-node/sub-test-node");
+	ut_assert(off >= 0);
+
+	ut_assertnonnull(fdt_getprop(fdt, off, "sub-test-property", NULL));
+	ut_assertnonnull(fdt_getprop(fdt, off, "new-sub-test-property", NULL));
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_add_subnode_property, 0);
+
+static int fdt_overlay_test_local_phandle(struct unit_test_state *uts)
+{
+	uint32_t local_phandle;
+	u32 val[2];
+	int off;
+
+	off = fdt_path_offset(fdt, "/new-local-node");
+	ut_assert(off >= 0);
+
+	local_phandle = fdt_get_phandle(fdt, off);
+	ut_assert(local_phandle);
+
+	ut_assertok(fdtdec_get_int_array(fdt, 0, "test-several-phandle", val,
+					 ARRAY_SIZE(val)));
+	ut_asserteq(local_phandle, val[0]);
+	ut_asserteq(local_phandle, val[1]);
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_local_phandle, 0);
+
+static int fdt_overlay_test_local_phandles(struct unit_test_state *uts)
+{
+	uint32_t local_phandle, test_phandle;
+	u32 val[2];
+	int off;
+
+	off = fdt_path_offset(fdt, "/new-local-node");
+	ut_assert(off >= 0);
+
+	local_phandle = fdt_get_phandle(fdt, off);
+	ut_assert(local_phandle);
+
+	off = fdt_path_offset(fdt, "/test-node");
+	ut_assert(off >= 0);
+
+	test_phandle = fdt_get_phandle(fdt, off);
+	ut_assert(test_phandle);
+
+	ut_assertok(fdtdec_get_int_array(fdt, 0, "test-phandle", val,
+					 ARRAY_SIZE(val)));
+	ut_asserteq(test_phandle, val[0]);
+	ut_asserteq(local_phandle, val[1]);
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_local_phandles, 0);
+
+static int fdt_overlay_test_stacked(struct unit_test_state *uts)
+{
+	int off;
+
+	off = fdt_path_offset(fdt, "/new-local-node");
+	ut_assert(off > 0);
+
+	ut_asserteq(43,
+		    fdtdec_get_uint(fdt, off, "stacked-test-int-property", 0));
+
+	return CMD_RET_SUCCESS;
+}
+FDT_OVERLAY_TEST(fdt_overlay_test_stacked, 0);
diff --git a/test/overlay/test-fdt-base.dts b/test/fdt_overlay/test-fdt-base.dts
similarity index 100%
rename from test/overlay/test-fdt-base.dts
rename to test/fdt_overlay/test-fdt-base.dts
diff --git a/test/overlay/test-fdt-overlay-stacked.dtso b/test/fdt_overlay/test-fdt-overlay-stacked.dtso
similarity index 100%
rename from test/overlay/test-fdt-overlay-stacked.dtso
rename to test/fdt_overlay/test-fdt-overlay-stacked.dtso
diff --git a/test/overlay/test-fdt-overlay.dtso b/test/fdt_overlay/test-fdt-overlay.dtso
similarity index 100%
rename from test/overlay/test-fdt-overlay.dtso
rename to test/fdt_overlay/test-fdt-overlay.dtso
diff --git a/test/log/cont_test.c b/test/log/cont_test.c
index 32b1c79..3b3b791 100644
--- a/test/log/cont_test.c
+++ b/test/log/cont_test.c
@@ -9,7 +9,6 @@
 #include <asm/global_data.h>
 #include <test/log.h>
 #include <test/test.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/test/log/nolog_test.c b/test/log/nolog_test.c
index 341dbfc..1913e68 100644
--- a/test/log/nolog_test.c
+++ b/test/log/nolog_test.c
@@ -13,7 +13,6 @@
 #include <asm/global_data.h>
 #include <test/log.h>
 #include <test/test.h>
-#include <test/suites.h>
 #include <test/ut.h>
 
 DECLARE_GLOBAL_DATA_PTR;
diff --git a/test/log/pr_cont_test.c b/test/log/pr_cont_test.c
index 7734e92..67d8ac5 100644
--- a/test/log/pr_cont_test.c
+++ b/test/log/pr_cont_test.c
@@ -8,7 +8,6 @@
 #include <console.h>
 #include <test/log.h>
 #include <test/test.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include <asm/global_data.h>
 #include <linux/printk.h>
diff --git a/test/log/syslog_test.c b/test/log/syslog_test.c
index c4180f7..98b9143 100644
--- a/test/log/syslog_test.c
+++ b/test/log/syslog_test.c
@@ -15,7 +15,6 @@
 #include <hexdump.h>
 #include <test/log.h>
 #include <test/test.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include <asm/eth.h>
 #include "syslog_test.h"
diff --git a/test/log/syslog_test_ndebug.c b/test/log/syslog_test_ndebug.c
index b10e636..dfd0217 100644
--- a/test/log/syslog_test_ndebug.c
+++ b/test/log/syslog_test_ndebug.c
@@ -12,7 +12,6 @@
 #include <hexdump.h>
 #include <test/log.h>
 #include <test/test.h>
-#include <test/suites.h>
 #include <test/ut.h>
 #include <asm/eth.h>
 #include "syslog_test.h"
diff --git a/test/optee/Kconfig b/test/optee/Kconfig
index 2f6834a..63e2cbf 100644
--- a/test/optee/Kconfig
+++ b/test/optee/Kconfig
@@ -1,6 +1,6 @@
 config UT_OPTEE
 	bool "Enable OP-TEE Unit Tests"
-	depends on UNIT_TEST && OF_CONTROL && OPTEE
+	depends on OF_CONTROL && OPTEE
 	default y
 	help
 	  This enables the 'ut optee' command which runs a series of unit
diff --git a/test/optee/Makefile b/test/optee/Makefile
index 8793fd7..ec56750 100644
--- a/test/optee/Makefile
+++ b/test/optee/Makefile
@@ -3,7 +3,7 @@
 # Copyright (C) 2019, Theobroma Systems Design und Consulting GmbH
 
 # Test files
-obj-y += cmd_ut_optee.o
+obj-y += optee.o
 
 DTC_FLAGS += -@
 
diff --git a/test/optee/cmd_ut_optee.c b/test/optee/optee.c
similarity index 70%
rename from test/optee/cmd_ut_optee.c
rename to test/optee/optee.c
index fc66747..658621f 100644
--- a/test/optee/cmd_ut_optee.c
+++ b/test/optee/optee.c
@@ -14,7 +14,6 @@
 
 #include <test/ut.h>
 #include <test/optee.h>
-#include <test/suites.h>
 
 /* 4k ought to be enough for anybody */
 #define FDT_COPY_SIZE	(4 * SZ_1K)
@@ -26,6 +25,41 @@
 static void *fdt;
 static bool expect_success;
 
+static int optee_test_init(struct unit_test_state *uts)
+{
+	void *fdt_optee = &__dtb_test_optee_optee_begin;
+	void *fdt_no_optee = &__dtb_test_optee_no_optee_begin;
+	void *fdt_base = &__dtb_test_optee_base_begin;
+	int ret = -ENOMEM;
+
+	ut_assertok(fdt_check_header(fdt_base));
+	ut_assertok(fdt_check_header(fdt_optee));
+	ut_assertok(fdt_check_header(fdt_no_optee));
+
+	fdt = malloc(FDT_COPY_SIZE);
+	if (!fdt)
+		return ret;
+
+	/*
+	 * Resize the FDT to 4k so that we have room to operate on
+	 *
+	 * (and relocate it since the memory might be mapped
+	 * read-only)
+	 */
+	ut_assertok(fdt_open_into(fdt_base, fdt, FDT_COPY_SIZE));
+
+	return 0;
+}
+OPTEE_TEST_INIT(optee_test_init, 0);
+
+static int optee_test_uninit(struct unit_test_state *uts)
+{
+	free(fdt);
+
+	return 0;
+}
+OPTEE_TEST_UNINIT(optee_test_uninit, 0);
+
 static int optee_fdt_firmware(struct unit_test_state *uts)
 {
 	const void *prop;
@@ -46,7 +80,6 @@
 
 	return CMD_RET_SUCCESS;
 }
-OPTEE_TEST(optee_fdt_firmware, 0);
 
 static int optee_fdt_protected_memory(struct unit_test_state *uts)
 {
@@ -89,60 +122,50 @@
 
 	return CMD_RET_SUCCESS;
 }
-OPTEE_TEST(optee_fdt_protected_memory, 0);
 
-int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+/* (1) Try to copy optee nodes from empty dt */
+static int optee_fdt_copy_empty(struct unit_test_state *uts)
 {
-	struct unit_test *tests = UNIT_TEST_SUITE_START(optee);
-	const int n_ents = UNIT_TEST_SUITE_COUNT(optee);
-	struct unit_test_state *uts;
-	void *fdt_optee = &__dtb_test_optee_optee_begin;
 	void *fdt_no_optee = &__dtb_test_optee_no_optee_begin;
-	void *fdt_base = &__dtb_test_optee_base_begin;
-	int ret = -ENOMEM;
-
-	uts = calloc(1, sizeof(*uts));
-	if (!uts)
-		return -ENOMEM;
-
-	ut_assertok(fdt_check_header(fdt_base));
-	ut_assertok(fdt_check_header(fdt_optee));
-	ut_assertok(fdt_check_header(fdt_no_optee));
-
-	fdt = malloc(FDT_COPY_SIZE);
-	if (!fdt)
-		return ret;
 
-	/*
-	 * Resize the FDT to 4k so that we have room to operate on
-	 *
-	 * (and relocate it since the memory might be mapped
-	 * read-only)
-	 */
-	ut_assertok(fdt_open_into(fdt_base, fdt, FDT_COPY_SIZE));
-
-	/*
-	 * (1) Try to copy optee nodes from empty dt.
-	 * This should still run successfully.
-	 */
+	/* This should still run successfully */
 	ut_assertok(optee_copy_fdt_nodes(fdt_no_optee, fdt));
 
 	expect_success = false;
-	ret = cmd_ut_category("optee", "", tests, n_ents, argc, argv);
+	ut_assertok(optee_fdt_firmware(uts));
+	ut_assertok(optee_fdt_protected_memory(uts));
 
-	/* (2) Try to copy optee nodes from prefilled dt */
+	return 0;
+}
+OPTEE_TEST(optee_fdt_copy_empty, 0);
+
+/* (2) Try to copy optee nodes from prefilled dt */
+static int optee_fdt_copy_prefilled(struct unit_test_state *uts)
+{
+	void *fdt_optee = &__dtb_test_optee_optee_begin;
+
 	ut_assertok(optee_copy_fdt_nodes(fdt_optee, fdt));
 
 	expect_success = true;
-	ret = cmd_ut_category("optee", "", tests, n_ents, argc, argv);
+	ut_assertok(optee_fdt_firmware(uts));
+	ut_assertok(optee_fdt_protected_memory(uts));
+
+	return 0;
+}
+OPTEE_TEST(optee_fdt_copy_prefilled, 0);
 
-	/* (3) Try to copy OP-TEE nodes into a already filled DT */
+/* (3) Try to copy OP-TEE nodes into a already filled DT */
+static int optee_fdt_copy_already_filled(struct unit_test_state *uts)
+{
+	void *fdt_optee = &__dtb_test_optee_optee_begin;
+
 	ut_assertok(fdt_open_into(fdt_optee, fdt, FDT_COPY_SIZE));
 	ut_assertok(optee_copy_fdt_nodes(fdt_optee, fdt));
 
 	expect_success = true;
-	ret = cmd_ut_category("optee", "", tests, n_ents, argc, argv);
+	ut_assertok(optee_fdt_firmware(uts));
+	ut_assertok(optee_fdt_protected_memory(uts));
 
-	free(fdt);
-	return ret;
+	return 0;
 }
+OPTEE_TEST(optee_fdt_copy_already_filled, 0);
diff --git a/test/overlay/cmd_ut_overlay.c b/test/overlay/cmd_ut_overlay.c
deleted file mode 100644
index aefa147..0000000
--- a/test/overlay/cmd_ut_overlay.c
+++ /dev/null
@@ -1,280 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2016 NextThing Co
- * Copyright (c) 2016 Free Electrons
- */
-
-#include <command.h>
-#include <errno.h>
-#include <fdt_support.h>
-#include <image.h>
-#include <log.h>
-#include <malloc.h>
-
-#include <linux/sizes.h>
-
-#include <test/ut.h>
-#include <test/overlay.h>
-#include <test/suites.h>
-
-/* 4k ought to be enough for anybody */
-#define FDT_COPY_SIZE	(4 * SZ_1K)
-
-extern u32 __dtb_test_fdt_base_begin;
-extern u32 __dtbo_test_fdt_overlay_begin;
-extern u32 __dtbo_test_fdt_overlay_stacked_begin;
-
-static void *fdt;
-
-static int ut_fdt_getprop_u32_by_index(void *fdt, const char *path,
-				    const char *name, int index,
-				    u32 *out)
-{
-	const fdt32_t *val;
-	int node_off;
-	int len;
-
-	node_off = fdt_path_offset(fdt, path);
-	if (node_off < 0)
-		return node_off;
-
-	val = fdt_getprop(fdt, node_off, name, &len);
-	if (!val || (len < (sizeof(uint32_t) * (index + 1))))
-		return -FDT_ERR_NOTFOUND;
-
-	*out = fdt32_to_cpu(*(val + index));
-
-	return 0;
-}
-
-static int ut_fdt_getprop_u32(void *fdt, const char *path, const char *name,
-			   u32 *out)
-{
-	return ut_fdt_getprop_u32_by_index(fdt, path, name, 0, out);
-}
-
-static int fdt_getprop_str(void *fdt, const char *path, const char *name,
-			   const char **out)
-{
-	int node_off;
-	int len;
-
-	node_off = fdt_path_offset(fdt, path);
-	if (node_off < 0)
-		return node_off;
-
-	*out = fdt_stringlist_get(fdt, node_off, name, 0, &len);
-
-	return len < 0 ? len : 0;
-}
-
-static int fdt_overlay_change_int_property(struct unit_test_state *uts)
-{
-	u32 val = 0;
-
-	ut_assertok(ut_fdt_getprop_u32(fdt, "/test-node", "test-int-property",
-				    &val));
-	ut_asserteq(43, val);
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_change_int_property, 0);
-
-static int fdt_overlay_change_str_property(struct unit_test_state *uts)
-{
-	const char *val = NULL;
-
-	ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property",
-				    &val));
-	ut_asserteq_str("foobar", val);
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_change_str_property, 0);
-
-static int fdt_overlay_add_str_property(struct unit_test_state *uts)
-{
-	const char *val = NULL;
-
-	ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property-2",
-				    &val));
-	ut_asserteq_str("foobar2", val);
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_add_str_property, 0);
-
-static int fdt_overlay_add_node_by_phandle(struct unit_test_state *uts)
-{
-	int off;
-
-	off = fdt_path_offset(fdt, "/test-node/new-node");
-	ut_assert(off >= 0);
-
-	ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_add_node_by_phandle, 0);
-
-static int fdt_overlay_add_node_by_path(struct unit_test_state *uts)
-{
-	int off;
-
-	off = fdt_path_offset(fdt, "/new-node");
-	ut_assert(off >= 0);
-
-	ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_add_node_by_path, 0);
-
-static int fdt_overlay_add_subnode_property(struct unit_test_state *uts)
-{
-	int off;
-
-	off = fdt_path_offset(fdt, "/test-node/sub-test-node");
-	ut_assert(off >= 0);
-
-	ut_assertnonnull(fdt_getprop(fdt, off, "sub-test-property", NULL));
-	ut_assertnonnull(fdt_getprop(fdt, off, "new-sub-test-property", NULL));
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_add_subnode_property, 0);
-
-static int fdt_overlay_local_phandle(struct unit_test_state *uts)
-{
-	uint32_t local_phandle;
-	u32 val = 0;
-	int off;
-
-	off = fdt_path_offset(fdt, "/new-local-node");
-	ut_assert(off >= 0);
-
-	local_phandle = fdt_get_phandle(fdt, off);
-	ut_assert(local_phandle);
-
-	ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
-					     0, &val));
-	ut_asserteq(local_phandle, val);
-
-	ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
-					     1, &val));
-	ut_asserteq(local_phandle, val);
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_local_phandle, 0);
-
-static int fdt_overlay_local_phandles(struct unit_test_state *uts)
-{
-	uint32_t local_phandle, test_phandle;
-	u32 val = 0;
-	int off;
-
-	off = fdt_path_offset(fdt, "/new-local-node");
-	ut_assert(off >= 0);
-
-	local_phandle = fdt_get_phandle(fdt, off);
-	ut_assert(local_phandle);
-
-	off = fdt_path_offset(fdt, "/test-node");
-	ut_assert(off >= 0);
-
-	test_phandle = fdt_get_phandle(fdt, off);
-	ut_assert(test_phandle);
-
-	ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0,
-					     &val));
-	ut_asserteq(test_phandle, val);
-
-	ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1,
-					     &val));
-	ut_asserteq(local_phandle, val);
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_local_phandles, 0);
-
-static int fdt_overlay_stacked(struct unit_test_state *uts)
-{
-	u32 val = 0;
-
-	ut_assertok(ut_fdt_getprop_u32(fdt, "/new-local-node",
-				       "stacked-test-int-property", &val));
-	ut_asserteq(43, val);
-
-	return CMD_RET_SUCCESS;
-}
-OVERLAY_TEST(fdt_overlay_stacked, 0);
-
-int do_ut_overlay(struct unit_test_state *uts, struct cmd_tbl *cmdtp, int flag,
-		  int argc, char *const argv[])
-{
-	struct unit_test *tests = UNIT_TEST_SUITE_START(overlay);
-	const int n_ents = UNIT_TEST_SUITE_COUNT(overlay);
-	void *fdt_base = &__dtb_test_fdt_base_begin;
-	void *fdt_overlay = &__dtbo_test_fdt_overlay_begin;
-	void *fdt_overlay_stacked = &__dtbo_test_fdt_overlay_stacked_begin;
-	void *fdt_overlay_copy, *fdt_overlay_stacked_copy;
-	int ret = -ENOMEM;
-
-	ut_assertok(fdt_check_header(fdt_base));
-	ut_assertok(fdt_check_header(fdt_overlay));
-
-	fdt = malloc(FDT_COPY_SIZE);
-	if (!fdt)
-		goto err1;
-
-	fdt_overlay_copy = malloc(FDT_COPY_SIZE);
-	if (!fdt_overlay_copy)
-		goto err2;
-
-	fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE);
-	if (!fdt_overlay_stacked_copy)
-		goto err3;
-
-	/*
-	 * Resize the FDT to 4k so that we have room to operate on
-	 *
-	 * (and relocate it since the memory might be mapped
-	 * read-only)
-	 */
-	ut_assertok(fdt_open_into(fdt_base, fdt, FDT_COPY_SIZE));
-
-	/*
-	 * Resize the overlay to 4k so that we have room to operate on
-	 *
-	 * (and relocate it since the memory might be mapped
-	 * read-only)
-	 */
-	ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
-				  FDT_COPY_SIZE));
-
-	/*
-	 * Resize the stacked overlay to 4k so that we have room to operate on
-	 *
-	 * (and relocate it since the memory might be mapped
-	 * read-only)
-	 */
-	ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy,
-				  FDT_COPY_SIZE));
-
-	/* Apply the overlay */
-	ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_copy));
-
-	/* Apply the stacked overlay */
-	ut_assertok(fdt_overlay_apply(fdt, fdt_overlay_stacked_copy));
-
-	ret = cmd_ut_category(uts, "overlay", "", tests, n_ents, argc, argv);
-
-	free(fdt_overlay_stacked_copy);
-err3:
-	free(fdt_overlay_copy);
-err2:
-	free(fdt);
-err1:
-	return ret;
-}
diff --git a/test/py/requirements.txt b/test/py/requirements.txt
index 75760f9..acfe17d 100644
--- a/test/py/requirements.txt
+++ b/test/py/requirements.txt
@@ -1,30 +1,4 @@
-atomicwrites==1.4.1
-attrs==19.3.0
-concurrencytest==0.1.2
-coverage==6.2
-extras==1.0.0
 filelock==3.0.12
-fixtures==3.0.0
-importlib-metadata==0.23
-linecache2==1.0.0
-more-itertools==7.2.0
-packaging==24.1
-pbr==5.4.3
-pluggy==0.13.0
-py==1.11.0
-pycryptodomex==3.19.1
-pyelftools==0.27
-pygit2==1.13.3
-pyparsing==3.0.7
+pycryptodomex==3.21.0
 pytest==6.2.5
 pytest-xdist==2.5.0
-python-mimeparse==1.6.0
-python-subunit==1.3.0
-requests==2.32.3
-setuptools==70.3.0
-six==1.16.0
-testtools==2.3.0
-traceback2==1.4.0
-unittest2==1.1.0
-wcwidth==0.1.7
-zipp==3.19.2
diff --git a/test/py/tests/test_suite.py b/test/py/tests/test_suite.py
index 73c1853..9ddc883 100644
--- a/test/py/tests/test_suite.py
+++ b/test/py/tests/test_suite.py
@@ -7,10 +7,10 @@
 # List of test suites we expect to find with 'ut info' and 'ut all'
 EXPECTED_SUITES = [
     'addrmap', 'bdinfo', 'bloblist', 'bootm', 'bootstd',
-    'cmd', 'common', 'dm', 'env', 'exit',
+    'cmd', 'common', 'dm', 'env', 'exit', 'fdt_overlay',
     'fdt', 'font', 'hush', 'lib',
     'loadm', 'log', 'mbr', 'measurement', 'mem',
-    'overlay', 'pci_mps', 'setexpr', 'upl',
+    'pci_mps', 'setexpr', 'upl',
     ]
 
 
@@ -66,11 +66,12 @@
             msg = m.group(3)
             if DEBUG_ME:
                 cons.log.info(f"test_name {test_name} msg '{msg}'")
-            if msg == ' (flat tree)' and test_name not in tests:
-                tests.add(test_name)
+            full_name = f'{cur_suite}.{test_name}'
+            if msg == ' (flat tree)' and full_name not in tests:
+                tests.add(full_name)
                 test_count += 1
             if not msg or 'skipped as it is manual' in msg:
-                tests.add(test_name)
+                tests.add(full_name)
                 test_count += 1
         if DEBUG_ME:
             cons.log.info(f'test_count {test_count}')
@@ -134,7 +135,7 @@
 
        - The number of suites matches that reported by the 'ut info'
        - Where available, the number of tests is each suite matches that
-         reported by 'ut info -s'
+         reported by 'ut -s info'
        - The total number of tests adds up to the total that are actually run
          with 'ut all'
        - All suites are run with 'ut all'
@@ -166,7 +167,7 @@
 
     # Run 'ut info' and compare with the log results
     with cons.log.section('Check suite test-counts'):
-        output = cons.run_command('ut info -s')
+        output = cons.run_command('ut -s info')
 
         suite_count, total_test_count, test_count = process_ut_info(cons,
                                                                     output)
@@ -186,3 +187,22 @@
 
         assert suite_count == len(EXPECTED_SUITES)
         assert total_test_count == len(all_tests)
+
+    # Run three suites
+    with cons.log.section('Check multiple suites'):
+        output = cons.run_command('ut bloblist,setexpr,mem')
+        assert 'Suites run: 3' in output
+
+    # Run a particular test
+    with cons.log.section('Check single test'):
+        output = cons.run_command('ut bloblist reloc')
+        assert 'Test: reloc: bloblist.c' in output
+
+    # Run tests multiple times
+    with cons.log.section('Check multiple runs'):
+        output = cons.run_command('ut -r2 bloblist')
+        lines = output.splitlines()
+        run = len([line for line in lines if 'Test:' in line])
+        count = re.search(r'Tests run: (\d*)', lines[-1]).group(1)
+
+        assert run == 2 * int(count)
diff --git a/test/test-main.c b/test/test-main.c
index 22b9b46..cabc736 100644
--- a/test/test-main.c
+++ b/test/test-main.c
@@ -14,6 +14,7 @@
 #include <net.h>
 #include <of_live.h>
 #include <os.h>
+#include <spl.h>
 #include <usb.h>
 #include <dm/ofnode.h>
 #include <dm/root.h>
@@ -513,11 +514,12 @@
  *	the first call to this function. On exit, @uts->cur.fail_count is
  *	incremented by the number of failures (0, one hopes)
  * @test: Test to run
+ * @leaf: Part of the name to show, or NULL to use test->name
  * Return: 0 if all tests passed, -EAGAIN if the test should be skipped, -1 if
  *	any failed
  */
 static int ut_run_test_live_flat(struct unit_test_state *uts,
-				 struct unit_test *test)
+				 struct unit_test *test, const char *leaf)
 {
 	int runs, ret;
 
@@ -529,7 +531,7 @@
 	if (CONFIG_IS_ENABLED(OF_LIVE)) {
 		if (!(test->flags & UTF_FLAT_TREE)) {
 			uts->of_live = true;
-			ret = ut_run_test(uts, test, test->name);
+			ret = ut_run_test(uts, test, leaf ?: test->name);
 			if (ret != -EAGAIN) {
 				ut_assertok(ret);
 				runs++;
@@ -557,7 +559,7 @@
 	    (!runs || ut_test_run_on_flattree(test)) &&
 	    !(gd->flags & GD_FLG_FDT_CHANGED)) {
 		uts->of_live = false;
-		ret = ut_run_test(uts, test, test->name);
+		ret = ut_run_test(uts, test, leaf ?: test->name);
 		if (ret != -EAGAIN) {
 			ut_assertok(ret);
 			runs++;
@@ -593,6 +595,7 @@
 			struct unit_test *tests, int count,
 			const char *select_name, const char *test_insert)
 {
+	int prefix_len = prefix ? strlen(prefix) : 0;
 	struct unit_test *test, *one;
 	int found = 0;
 	int pos = 0;
@@ -617,7 +620,8 @@
 		const char *test_name = test->name;
 		int ret, i, old_fail_count;
 
-		if (!test_matches(prefix, test_name, select_name))
+		if (!(test->flags & (UTF_INIT | UTF_UNINIT)) &&
+		    !test_matches(prefix, test_name, select_name))
 			continue;
 
 		if (test->flags & UTF_MANUAL) {
@@ -645,7 +649,7 @@
 
 		uts->cur.test_count++;
 		if (one && upto == pos) {
-			ret = ut_run_test_live_flat(uts, one);
+			ret = ut_run_test_live_flat(uts, one, NULL);
 			if (uts->cur.fail_count != old_fail_count) {
 				printf("Test '%s' failed %d times (position %d)\n",
 				       one->name,
@@ -655,8 +659,11 @@
 			return -EBADF;
 		}
 
+		if (prefix_len && !strncmp(test_name, prefix, prefix_len))
+			test_name = test_name + prefix_len;
+
 		for (i = 0; i < uts->runs_per_test; i++)
-			ret = ut_run_test_live_flat(uts, test);
+			ret = ut_run_test_live_flat(uts, test, test_name);
 		if (uts->cur.fail_count != old_fail_count) {
 			printf("Test '%s' failed %d times\n", test_name,
 			       uts->cur.fail_count - old_fail_count);
@@ -680,6 +687,12 @@
 	else
 		printf("Tests");
 	printf(" run: %d, ", stats->test_count);
+	if (stats && stats->test_count) {
+		ulong dur = stats->duration_ms;
+
+		printf("%ld ms, average: %ld ms, ", dur,
+		       dur ? dur / stats->test_count : 0);
+	}
 	if (stats->skip_count)
 		printf("skipped: %d, ", stats->skip_count);
 	printf("failures: %d\n", stats->fail_count);
@@ -692,16 +705,22 @@
 {
 	;
 	bool has_dm_tests = false;
+	ulong start_offset = 0;
+	ulong test_offset = 0;
 	int ret;
 
 	memset(&uts->cur, '\0', sizeof(struct ut_stats));
+	if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION)) {
+		uts->cur.start = get_timer(0);
+		start_offset = timer_test_get_offset();
+	}
 
 	if (!CONFIG_IS_ENABLED(OF_PLATDATA) &&
 	    ut_list_has_dm_tests(tests, count, prefix, select_name)) {
 		has_dm_tests = true;
 		/*
 		 * If we have no device tree, or it only has a root node, then
-		 * these * tests clearly aren't going to work...
+		 * these tests clearly aren't going to work...
 		 */
 		if (!gd->fdt_blob || fdt_next_node(gd->fdt_blob, 0, NULL) < 0) {
 			puts("Please run with test device tree:\n"
@@ -732,13 +751,19 @@
 	if (has_dm_tests)
 		dm_test_restore(uts->of_root);
 
-	ut_report(&uts->cur, 1);
 	if (ret == -ENOENT)
 		printf("Test '%s' not found\n", select_name);
+	if (CONFIG_IS_ENABLED(UNIT_TEST_DURATION)) {
+		test_offset = timer_test_get_offset() - start_offset;
+
+		uts->cur.duration_ms = get_timer(uts->cur.start) - test_offset;
+	}
+	ut_report(&uts->cur, 1);
 
 	uts->total.skip_count += uts->cur.skip_count;
 	uts->total.fail_count += uts->cur.fail_count;
 	uts->total.test_count += uts->cur.test_count;
+	uts->total.duration_ms += uts->cur.duration_ms;
 	uts->run_count++;
 
 	return ret;
diff --git a/tools/binman/requirements.txt b/tools/binman/requirements.txt
new file mode 100644
index 0000000..f068ef7
--- /dev/null
+++ b/tools/binman/requirements.txt
@@ -0,0 +1,5 @@
+importlib_resources==6.5.2
+jsonschema==4.23.0
+pycryptodomex==3.21.0
+pyelftools==0.31
+yamllint==1.35.1
diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py
index cbf1345..2568e4e 100644
--- a/tools/buildman/builder.py
+++ b/tools/buildman/builder.py
@@ -19,8 +19,8 @@
 
 from buildman import builderthread
 from buildman import toolchain
-from patman import gitutil
 from u_boot_pylib import command
+from u_boot_pylib import gitutil
 from u_boot_pylib import terminal
 from u_boot_pylib import tools
 from u_boot_pylib.terminal import tprint
diff --git a/tools/buildman/builderthread.py b/tools/buildman/builderthread.py
index 29e6cf3..78c95a6 100644
--- a/tools/buildman/builderthread.py
+++ b/tools/buildman/builderthread.py
@@ -17,8 +17,8 @@
 import threading
 
 from buildman import cfgutil
-from patman import gitutil
 from u_boot_pylib import command
+from u_boot_pylib import gitutil
 from u_boot_pylib import tools
 
 RETURN_CODE_RETRY = -1
diff --git a/tools/buildman/control.py b/tools/buildman/control.py
index 55d4d77..5109b1c 100644
--- a/tools/buildman/control.py
+++ b/tools/buildman/control.py
@@ -20,9 +20,9 @@
 from buildman import cfgutil
 from buildman import toolchain
 from buildman.builder import Builder
-from patman import gitutil
 from patman import patchstream
 from u_boot_pylib import command
+from u_boot_pylib import gitutil
 from u_boot_pylib import terminal
 from u_boot_pylib import tools
 from u_boot_pylib.terminal import print_clear, tprint
diff --git a/tools/buildman/func_test.py b/tools/buildman/func_test.py
index 4e12c67..c7c4f50 100644
--- a/tools/buildman/func_test.py
+++ b/tools/buildman/func_test.py
@@ -18,8 +18,8 @@
 from buildman import cmdline
 from buildman import control
 from buildman import toolchain
-from patman import gitutil
 from u_boot_pylib import command
+from u_boot_pylib import gitutil
 from u_boot_pylib import terminal
 from u_boot_pylib import test_util
 from u_boot_pylib import tools
diff --git a/tools/buildman/main.py b/tools/buildman/main.py
index a948f36..72571b2 100755
--- a/tools/buildman/main.py
+++ b/tools/buildman/main.py
@@ -50,8 +50,7 @@
     # 'entry' module.
     result = test_util.run_test_suites(
         'buildman', debug, verbose, False, args.threads, test_name, [],
-        [test.TestBuild, func_test.TestFunctional,
-         'buildman.toolchain', 'patman.gitutil'])
+        [test.TestBuild, func_test.TestFunctional, 'buildman.toolchain'])
 
     return (0 if result.wasSuccessful() else 1)
 
diff --git a/tools/buildman/requirements.txt b/tools/buildman/requirements.txt
index 052d0ed..d48650c 100644
--- a/tools/buildman/requirements.txt
+++ b/tools/buildman/requirements.txt
@@ -1,5 +1,2 @@
-coverage==6.2
-jsonschema==4.17.3
-pycryptodome==3.20
-pyyaml==6.0
-yamllint==1.26.3
+filelock==3.0.12
+importlib_resources==6.5.2
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile
index d2848ab..85d6784 100644
--- a/tools/docker/Dockerfile
+++ b/tools/docker/Dockerfile
@@ -122,7 +122,6 @@
 	python3 \
 	python3-dev \
 	python3-pip \
-	python3-pyelftools \
 	python3-sphinx \
 	python3-virtualenv \
 	rpm2cpio \
@@ -308,12 +307,18 @@
 # COPY / ADD directives don't work as we need them to.
 RUN wget -O /tmp/pytest-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/test/py/requirements.txt
 RUN wget -O /tmp/sphinx-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/doc/sphinx/requirements.txt
+RUN wget -O /tmp/binman-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/tools/binman/requirements.txt
 RUN wget -O /tmp/buildman-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/tools/buildman/requirements.txt
+RUN wget -O /tmp/patman-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/tools/patman/requirements.txt
+RUN wget -O /tmp/u_boot_pylib-requirements.txt https://source.denx.de/u-boot/u-boot/-/raw/master/tools/u_boot_pylib/requirements.txt
 RUN virtualenv -p /usr/bin/python3 /tmp/venv && \
 	. /tmp/venv/bin/activate && \
 	pip install -r /tmp/pytest-requirements.txt \
 		-r /tmp/sphinx-requirements.txt \
-		-r /tmp/buildman-requirements.txt && \
+		-r /tmp/binman-requirements.txt \
+		-r /tmp/buildman-requirements.txt \
+		-r /tmp/patman-requirements.txt \
+		-r /tmp/u_boot_pylib-requirements.txt && \
 	deactivate && \
 	rm -rf /tmp/venv /tmp/*-requirements.txt
 
diff --git a/tools/patman/__init__.py b/tools/patman/__init__.py
index 08eeffd..6de0e9f 100644
--- a/tools/patman/__init__.py
+++ b/tools/patman/__init__.py
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0+
 
 __all__ = ['checkpatch', 'commit', 'control', 'func_test', 'get_maintainer',
-           'gitutil', '__main__', 'patchstream', 'project', 'series',
-           'settings','setup', 'status', 'test_checkpatch', 'test_settings']
+           '__main__', 'patchstream', 'project', 'series',
+           'settings', 'setup', 'status', 'test_checkpatch', 'test_settings']
diff --git a/tools/patman/__main__.py b/tools/patman/__main__.py
index f645b38..36f1c08 100755
--- a/tools/patman/__main__.py
+++ b/tools/patman/__main__.py
@@ -49,7 +49,7 @@
         result = test_util.run_test_suites(
             'patman', False, False, False, None, None, None,
             [test_checkpatch.TestPatch, func_test.TestFunctional,
-             'gitutil', 'settings'])
+             'settings'])
 
         sys.exit(0 if result.wasSuccessful() else 1)
 
diff --git a/tools/patman/checkpatch.py b/tools/patman/checkpatch.py
index e03cac1..2975881 100644
--- a/tools/patman/checkpatch.py
+++ b/tools/patman/checkpatch.py
@@ -8,8 +8,8 @@
 import re
 import sys
 
-from patman import gitutil
 from u_boot_pylib import command
+from u_boot_pylib import gitutil
 from u_boot_pylib import terminal
 
 EMACS_PREFIX = r'(?:[0-9]{4}.*\.patch:[0-9]+: )?'
diff --git a/tools/patman/cmdline.py b/tools/patman/cmdline.py
index d6496c0..562bc82 100644
--- a/tools/patman/cmdline.py
+++ b/tools/patman/cmdline.py
@@ -13,8 +13,8 @@
 import pathlib
 import sys
 
-from patman import gitutil
 from patman import project
+from u_boot_pylib import gitutil
 from patman import settings
 
 PATMAN_DIR = pathlib.Path(__file__).parent
diff --git a/tools/patman/control.py b/tools/patman/control.py
index b292da9..fb5a424 100644
--- a/tools/patman/control.py
+++ b/tools/patman/control.py
@@ -12,8 +12,8 @@
 import sys
 
 from patman import checkpatch
-from patman import gitutil
 from patman import patchstream
+from u_boot_pylib import gitutil
 from u_boot_pylib import terminal
 
 
diff --git a/tools/patman/func_test.py b/tools/patman/func_test.py
index af6c025..bf333dc 100644
--- a/tools/patman/func_test.py
+++ b/tools/patman/func_test.py
@@ -18,11 +18,11 @@
 
 from patman.commit import Commit
 from patman import control
-from patman import gitutil
 from patman import patchstream
 from patman.patchstream import PatchStream
 from patman.series import Series
 from patman import settings
+from u_boot_pylib import gitutil
 from u_boot_pylib import terminal
 from u_boot_pylib import tools
 from u_boot_pylib.test_util import capture_sys_output
diff --git a/tools/patman/get_maintainer.py b/tools/patman/get_maintainer.py
index 8df3d12..200ee96 100644
--- a/tools/patman/get_maintainer.py
+++ b/tools/patman/get_maintainer.py
@@ -7,8 +7,8 @@
 import shlex
 import shutil
 
-from patman import gitutil
 from u_boot_pylib import command
+from u_boot_pylib import gitutil
 
 
 def find_get_maintainer(script_file_name):
diff --git a/tools/patman/patchstream.py b/tools/patman/patchstream.py
index 4955f6a..08795c4 100644
--- a/tools/patman/patchstream.py
+++ b/tools/patman/patchstream.py
@@ -15,9 +15,9 @@
 import tempfile
 
 from patman import commit
-from patman import gitutil
 from patman.series import Series
 from u_boot_pylib import command
+from u_boot_pylib import gitutil
 
 # Tags that we detect and remove
 RE_REMOVE = re.compile(r'^BUG=|^TEST=|^BRANCH=|^Review URL:'
diff --git a/tools/patman/project.py b/tools/patman/project.py
index 4459042..d6143a6 100644
--- a/tools/patman/project.py
+++ b/tools/patman/project.py
@@ -4,7 +4,7 @@
 
 import os.path
 
-from patman import gitutil
+from u_boot_pylib import gitutil
 
 def detect_project():
     """Autodetect the name of the current project.
diff --git a/tools/patman/requirements.txt b/tools/patman/requirements.txt
new file mode 100644
index 0000000..e8cbc6c
--- /dev/null
+++ b/tools/patman/requirements.txt
@@ -0,0 +1,5 @@
+ConfigParser==7.1.0
+importlib_resources==6.5.2
+pygit2==1.13.3
+Requests==2.32.3
+setuptools==75.8.0
diff --git a/tools/patman/series.py b/tools/patman/series.py
index 6866e1d..d7f2f01 100644
--- a/tools/patman/series.py
+++ b/tools/patman/series.py
@@ -12,8 +12,8 @@
 import time
 
 from patman import get_maintainer
-from patman import gitutil
 from patman import settings
+from u_boot_pylib import gitutil
 from u_boot_pylib import terminal
 from u_boot_pylib import tools
 
diff --git a/tools/patman/settings.py b/tools/patman/settings.py
index 68c93e3..d66b22b 100644
--- a/tools/patman/settings.py
+++ b/tools/patman/settings.py
@@ -12,7 +12,7 @@
 import os
 import re
 
-from patman import gitutil
+from u_boot_pylib import gitutil
 
 """Default settings per-project.
 
diff --git a/tools/patman/test_checkpatch.py b/tools/patman/test_checkpatch.py
index db7860f..11d003b 100644
--- a/tools/patman/test_checkpatch.py
+++ b/tools/patman/test_checkpatch.py
@@ -11,10 +11,10 @@
 import unittest
 
 from patman import checkpatch
-from patman import gitutil
 from patman import patchstream
 from patman import series
 from patman import commit
+from u_boot_pylib import gitutil
 
 
 class Line:
diff --git a/tools/u_boot_pylib/__init__.py b/tools/u_boot_pylib/__init__.py
index 63c88e8..807a62e 100644
--- a/tools/u_boot_pylib/__init__.py
+++ b/tools/u_boot_pylib/__init__.py
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0+
 
-__all__ = ['command', 'cros_subprocess','terminal', 'test_util', 'tools',
-	   'tout']
+__all__ = ['command', 'cros_subprocess', 'gitutil', 'terminal', 'test_util',
+           'tools', 'tout']
diff --git a/tools/u_boot_pylib/__main__.py b/tools/u_boot_pylib/__main__.py
index 8f98d7b..c0762bc 100755
--- a/tools/u_boot_pylib/__main__.py
+++ b/tools/u_boot_pylib/__main__.py
@@ -13,7 +13,6 @@
     sys.path.append(os.path.join(our_path, '..'))
 
     # Run tests
-    from u_boot_pylib import terminal
     from u_boot_pylib import test_util
 
     result = test_util.run_test_suites(
diff --git a/tools/patman/gitutil.py b/tools/u_boot_pylib/gitutil.py
similarity index 100%
rename from tools/patman/gitutil.py
rename to tools/u_boot_pylib/gitutil.py
diff --git a/tools/u_boot_pylib/requirements.txt b/tools/u_boot_pylib/requirements.txt
new file mode 100644
index 0000000..1087e6f
--- /dev/null
+++ b/tools/u_boot_pylib/requirements.txt
@@ -0,0 +1 @@
+concurrencytest==0.1.2