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

- sunXi SPI fixups (Andre)
- bcm iproc qspi (Rayagonda)
diff --git a/.mailmap b/.mailmap
index b36ae66..1f88ea9 100644
--- a/.mailmap
+++ b/.mailmap
@@ -22,11 +22,13 @@
 Aneesh V <aneesh@ti.com>
 Anup Patel <anup@brainfault.org> <anup.patel@wdc.com>
 Atish Patra <atishp@atishpatra.org> <atish.patra@wdc.com>
+Bin Meng <bmeng.cn@gmail.com> <bin.meng@windriver.com>
 Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
 Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
 Dirk Behme <dirk.behme@googlemail.com>
 Fabio Estevam <fabio.estevam@nxp.com>
 Heinrich Schuchardt <xypron.glpk@gmx.de> <heinrich.schuchardt@canonical.com>
+Heinrich Schuchardt <xypron.glpk@gmx.de> xypron.glpk@gmx.de <xypron.glpk@gmx.de>
 Jagan Teki <402jagan@gmail.com>
 Jagan Teki <jaganna@gmail.com>
 Jagan Teki <jaganna@xilinx.com>
@@ -35,7 +37,15 @@
 Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net>
 Igor Opaniuk <igor.opaniuk@gmail.com> <igor.opaniuk@linaro.org>
 Igor Opaniuk <igor.opaniuk@gmail.com> <igor.opaniuk@toradex.com>
+Marek Vasut <marex@denx.de> <marek.vasut+renesas@gmail.com>
+Marek Vasut <marex@denx.de> <marek.vasut@gmail.com>
+Marek Vasut <marex@denx.de> <marex at denx.de>
 Markus Klotzbuecher <mk@denx.de>
+Masahiro Yamada <yamada.masahiro@socionext.com> <yamada.m@jp.panasonic.com>
+Masahiro Yamada <yamada.masahiro@socionext.com> <masahiroy@kernel.org>
+Michal Simek <michal.simek@xilinx.com> <monstr@monstr.eu>
+Michal Simek <michal.simek@xilinx.com> <Monstr@seznam.cz>
+Michal Simek <michal.simek@xilinx.com> <root@monstr.eu>
 Nicolas Saenz Julienne <nsaenz@kernel.org> <nsaenzjulienne@suse.de>
 Patrice Chotard <patrice.chotard@foss.st.com> <patrice.chotard@st.com>
 Patrick Delaunay <patrick.delaunay@foss.st.com> <patrick.delaunay@st.com>
@@ -47,10 +57,19 @@
 Ruchika Gupta <ruchika.gupta@nxp.com> <ruchika.gupta@freescale.com>
 Sandeep Paulraj <s-paulraj@ti.com>
 Shaohui Xie <Shaohui.Xie@freescale.com>
-Stefan Roese <stroese>
+Stefan Roese <sr@denx.de> <stroese>
 Stefano Babic <sbabic@denx.de>
+Tom Rini <trini@konsulko.com> <trini@ti.com>
 TsiChung Liew <Tsi-Chung.Liew@freescale.com>
-Wolfgang Denk <wdenk>
+Wolfgang Denk <wd@denx.de> <wdenk>
+Wolfgang Denk <wd@denx.de> <wd@pollux.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@pollux.(none)>
+Wolfgang Denk <wd@denx.de> <wd@fifi.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@nyx.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@atlas.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@castor.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@xpert.denx.de>
+Wolfgang Denk <wd@denx.de> <wd@nyx.(none)>
 York Sun <yorksun@freescale.com>
 York Sun <york.sun@nxp.com>
 Ɓukasz Majewski <l.majewski@samsung.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index fb171e0..82fc49e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1161,6 +1161,13 @@
 T:	git https://source.denx.de/u-boot/custodians/u-boot-sh.git
 F:	arch/sh/
 
+SL28CLPD
+M:	Michael Walle <michael@walle.cc>
+S:	Maintained
+F:	drivers/gpio/sl28cpld-gpio.c
+F:	drivers/misc/sl28cpld.c
+F:	drivers/watchdog/sl28cpld-wdt.c
+
 SPI
 M:	Jagan Teki <jagan@amarulasolutions.com>
 S:	Maintained
@@ -1319,6 +1326,14 @@
 F:	test/dm/virtio.c
 F:	doc/develop/driver-model/virtio.rst
 
+WATCHDOG
+M:	Stefan Roese <sr@denx.de>
+S:	Maintained
+T:	git https://source.denx.de/u-boot/custodians/u-boot-watchdog.git
+F:	cmd/wdt.c
+F:	drivers/watchdog/
+F:	include/watchdog*.h
+
 X86
 M:	Simon Glass <sjg@chromium.org>
 M:	Bin Meng <bmeng.cn@gmail.com>
diff --git a/Makefile b/Makefile
index 697cc51..f8f3f24 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 VERSION = 2022
 PATCHLEVEL = 04
 SUBLEVEL =
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc3
 NAME =
 
 # *DOCUMENTATION*
@@ -1411,7 +1411,7 @@
 	$(if $(KEYDIR),-k $(KEYDIR))
 
 MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \
-		-R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage
+		-R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -A $(ARCH) -T pblimage
 
 ifeq ($(CONFIG_MPC85xx)$(CONFIG_OF_SEPARATE),yy)
 UBOOT_BIN := u-boot-with-dtb.bin
@@ -2227,7 +2227,8 @@
 		-o -name '*.asn1.[ch]' \
 		-o -name '*.symtypes' -o -name 'modules.order' \
 		-o -name modules.builtin -o -name '.tmp_*.o.*' \
-		-o -name 'dsdt.aml' -o -name 'dsdt.asl.tmp' -o -name 'dsdt.c' \
+		-o -name 'dsdt_generated.aml' -o -name 'dsdt_generated.asl.tmp' \
+		-o -name 'dsdt_generated.c' \
 		-o -name '*.efi' -o -name '*.gcno' -o -name '*.so' \) \
 		-type f -print | xargs rm -f
 
diff --git a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
index 08be7ed..2592403 100644
--- a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
+++ b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
@@ -25,9 +25,9 @@
 	mov	sp, r0
 	mov	lr, r1
 	ldr	r0, =fel_stash
-	ldr	r1, [r0, #16]
-	mcr	p15, 0, r1, c1, c0, 0	@ Write CP15 Control Register
 	ldr	r1, [r0, #12]
+	mcr	p15, 0, r1, c1, c0, 0	@ Write CP15 SCTLR register
+	ldr	r1, [r0, #8]
 	msr	cpsr, r1		@ Write CPSR
 	bx	lr
 ENDPROC(return_to_fel)
diff --git a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi
index d4b8332..2dcb3c2 100644
--- a/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi
+++ b/arch/arm/dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi
@@ -27,6 +27,7 @@
 		fit {
 			offset = <CONFIG_SPL_PAD_TO>;
 			description = "FIT image with multiple configurations";
+			fit,fdt-list = "of-list";
 
 			images {
 				uboot {
@@ -41,95 +42,20 @@
 					};
 				};
 
-				fdt-1 {
-					description = "fsl-ls1028a-kontron-sl28";
+				@fdt-SEQ {
+					description = "NAME";
 					type = "flat_dt";
-					arch = "arm";
 					compression = "none";
-
-					blob {
-						filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28.dtb";
-					};
-				};
-
-				fdt-2 {
-					description = "fsl-ls1028a-kontron-sl28-var1";
-					type = "flat_dt";
-					arch = "arm";
-					compression = "none";
-
-					blob {
-						filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var1.dtb";
-					};
-				};
-
-				fdt-3 {
-					description = "fsl-ls1028a-kontron-sl28-var2";
-					type = "flat_dt";
-					arch = "arm";
-					compression = "none";
-
-					blob {
-						filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var2.dtb";
-					};
-				};
-
-				fdt-4 {
-					description = "fsl-ls1028a-kontron-sl28-var3";
-					type = "flat_dt";
-					arch = "arm";
-					compression = "none";
-
-					blob {
-						filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var3.dtb";
-					};
-				};
-
-				fdt-5 {
-					description = "fsl-ls1028a-kontron-sl28-var4";
-					type = "flat_dt";
-					arch = "arm";
-					compression = "none";
-
-					blob {
-						filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var4.dtb";
-					};
 				};
 			};
 
 			configurations {
-				default = "conf-1";
+				default = "@config-DEFAULT-SEQ";
 
-				conf-1 {
-					description = "fsl-ls1028a-kontron-sl28";
+				@config-SEQ {
+					description = "NAME";
 					firmware = "uboot";
-					fdt = "fdt-1";
-				};
-
-				conf-2 {
-					description = "fsl-ls1028a-kontron-sl28-var1";
-					firmware = "uboot";
-					fdt = "fdt-2";
-				};
-
-				conf-3 {
-					description = "fsl-ls1028a-kontron-sl28-var2";
-					firmware = "uboot";
-					fdt = "fdt-3";
-				};
-
-				conf-4 {
-					description = "fsl-ls1028a-kontron-sl28-var3";
-					firmware = "uboot";
-					loadables = "uboot";
-					fdt = "fdt-4";
-				};
-
-				conf-5 {
-					description = "fsl-ls1028a-kontron-sl28-var4";
-					firmware = "uboot";
-					loadables = "uboot";
-					fdt = "fdt-5";
+					fdt = "fdt-SEQ";
 				};
 			};
 		};
@@ -189,27 +115,7 @@
 		};
 
 		configurations {
-			conf-1 {
-				firmware = "bl31";
-				loadables = "uboot";
-			};
-
-			conf-2 {
-				firmware = "bl31";
-				loadables = "uboot";
-			};
-
-			conf-3 {
-				firmware = "bl31";
-				loadables = "uboot";
-			};
-
-			conf-4 {
-				firmware = "bl31";
-				loadables = "uboot";
-			};
-
-			conf-5 {
+			@config-SEQ {
 				firmware = "bl31";
 				loadables = "uboot";
 			};
@@ -238,23 +144,7 @@
 		};
 
 		configurations {
-			conf-1 {
-				loadables = "uboot", "bl32";
-			};
-
-			conf-2 {
-				loadables = "uboot", "bl32";
-			};
-
-			conf-3 {
-				loadables = "uboot", "bl32";
-			};
-
-			conf-4 {
-				loadables = "uboot", "bl32";
-			};
-
-			conf-5 {
+			@config-SEQ {
 				loadables = "uboot", "bl32";
 			};
 		};
diff --git a/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi b/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi
index 286e25f..d80c550 100644
--- a/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi
+++ b/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) Siemens AG, 2018-2021
+ * Copyright (c) Siemens AG, 2018-2022
  *
  * Authors:
  *   Le Jin <le.jin@siemens.com>
@@ -27,6 +27,29 @@
 
 &cbass_mcu {
 	u-boot,dm-spl;
+
+	mcu_navss: bus@28380000 {
+		ringacc@2b800000 {
+			reg =	<0x0 0x2b800000 0x0 0x400000>,
+				<0x0 0x2b000000 0x0 0x400000>,
+				<0x0 0x28590000 0x0 0x100>,
+				<0x0 0x2a500000 0x0 0x40000>,
+				<0x0 0x28440000 0x0 0x40000>;
+			reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg";
+			ti,dma-ring-reset-quirk;
+		};
+
+		dma-controller@285c0000 {
+			reg =	<0x0 0x285c0000 0x0 0x100>,
+				<0x0 0x284c0000 0x0 0x4000>,
+				<0x0 0x2a800000 0x0 0x40000>,
+				<0x0 0x284a0000 0x0 0x4000>,
+				<0x0 0x2aa00000 0x0 0x40000>,
+				<0x0 0x28400000 0x0 0x2000>;
+			reg-names = "gcfg", "rchan", "rchanrt", "tchan",
+					    "tchanrt", "rflow";
+		};
+	};
 };
 
 &cbass_wakeup {
diff --git a/arch/arm/dts/sama7g5ek.dts b/arch/arm/dts/sama7g5ek.dts
index 6adb044..ac6f23f 100644
--- a/arch/arm/dts/sama7g5ek.dts
+++ b/arch/arm/dts/sama7g5ek.dts
@@ -125,7 +125,9 @@
 	#address-cells = <1>;
 	#size-cells = <0>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_gmac0_default &pinctrl_gmac0_txc_default>;
+	pinctrl-0 = <&pinctrl_gmac0_default
+		     &pinctrl_gmac0_mdio_default
+		     &pinctrl_gmac0_txc_default>;
 	phy-mode = "rgmii-id";
 	status = "okay";
 
@@ -138,7 +140,7 @@
 	#address-cells = <1>;
 	#size-cells = <0>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_gmac1_default>;
+	pinctrl-0 = <&pinctrl_gmac1_default &pinctrl_gmac1_mdio_default>;
 	phy-mode = "rmii";
 	status = "okay";
 
@@ -235,14 +237,20 @@
 			 <PIN_PA15__G0_TXEN>,
 			 <PIN_PA30__G0_RXCK>,
 			 <PIN_PA18__G0_RXDV>,
-			 <PIN_PA22__G0_MDC>,
-			 <PIN_PA23__G0_MDIO>,
 			 <PIN_PA25__G0_125CK>;
+		slew-rate = <0>;
+		bias-disable;
+	};
+
+	pinctrl_gmac0_mdio_default: gmac0_mdio_default {
+		pinmux = <PIN_PA22__G0_MDC>,
+			 <PIN_PA23__G0_MDIO>;
 		bias-disable;
 	};
 
 	pinctrl_gmac0_txc_default: gmac0_txc_default {
 		pinmux = <PIN_PA24__G0_TXCK>;
+		slew-rate = <0>;
 		bias-pull-up;
 	};
 
@@ -254,8 +262,13 @@
 			 <PIN_PD25__G1_RX0>,
 			 <PIN_PD26__G1_RX1>,
 			 <PIN_PD27__G1_RXER>,
-			 <PIN_PD24__G1_RXDV>,
-			 <PIN_PD28__G1_MDC>,
+			 <PIN_PD24__G1_RXDV>;
+		slew-rate = <0>;
+		bias-disable;
+	};
+
+	pinctrl_gmac1_mdio_default: gmac1_mdio_default {
+		pinmux = <PIN_PD28__G1_MDC>,
 			 <PIN_PD29__G1_MDIO>;
 		bias-disable;
 	};
diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
index 7f7eb05..edd0fbf 100644
--- a/arch/arm/include/asm/arch-sunxi/gpio.h
+++ b/arch/arm/include/asm/arch-sunxi/gpio.h
@@ -160,6 +160,7 @@
 #define SUNXI_GPC_SDC2		3
 #define SUN6I_GPC_SDC3		4
 #define SUN50I_GPC_SPI0		4
+#define SUNIV_GPC_SPI0		2
 
 #define SUNXI_GPD_LCD0		2
 #define SUNXI_GPD_LVDS0		3
diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
index 58cdf80..b543d24 100644
--- a/arch/arm/include/asm/arch-sunxi/spl.h
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
@@ -19,6 +19,15 @@
 #define SUNXI_BOOTED_FROM_MMC0_HIGH	0x10
 #define SUNXI_BOOTED_FROM_MMC2_HIGH	0x12
 
+/*
+ * Values taken from the F1C200s BootROM stack
+ * to determine where we booted from.
+ */
+#define SUNIV_BOOTED_FROM_MMC0	0xffff40f8
+#define SUNIV_BOOTED_FROM_NAND	0xffff4114
+#define SUNIV_BOOTED_FROM_SPI	0xffff4130
+#define SUNIV_BOOTED_FROM_MMC1	0xffff4150
+
 #define is_boot0_magic(addr)	(memcmp((void *)(addr), BOOT0_MAGIC, 8) == 0)
 
 uint32_t sunxi_get_boot_device(void);
diff --git a/arch/arm/mach-apple/board.c b/arch/arm/mach-apple/board.c
index f9f8a2f..54005f3 100644
--- a/arch/arm/mach-apple/board.c
+++ b/arch/arm/mach-apple/board.c
@@ -265,3 +265,36 @@
 {
 	return SZ_256K;
 }
+
+int board_late_init(void)
+{
+	unsigned long base;
+	unsigned long top;
+	u32 status = 0;
+
+	/* Reserve 4M each for scriptaddr and pxefile_addr_r at the top of RAM
+	 * at least 1M below the stack.
+	 */
+	top = gd->start_addr_sp - CONFIG_STACK_SIZE - SZ_8M - SZ_1M;
+	top = ALIGN_DOWN(top, SZ_8M);
+
+	status |= env_set_hex("scriptaddr", top + SZ_4M);
+	status |= env_set_hex("pxefile_addr_r", top);
+
+	/* somewhat based on the Linux Kernel boot requirements:
+	 * align by 2M and maximal FDT size 2M
+	 */
+	base = ALIGN(gd->ram_base, SZ_2M);
+
+	status |= env_set_hex("fdt_addr_r", base);
+	status |= env_set_hex("kernel_addr_r", base + SZ_2M);
+	status |= env_set_hex("ramdisk_addr_r", base + SZ_128M);
+	status |= env_set_hex("loadaddr", base + SZ_2G);
+	status |= env_set_hex("kernel_comp_addr_r", base + SZ_2G - SZ_128M);
+	status |= env_set_hex("kernel_comp_size", SZ_128M);
+
+	if (status)
+		log_warning("late_init: Failed to set run time variables\n");
+
+	return 0;
+}
diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c
index ffb7aad..8a6b1de 100644
--- a/arch/arm/mach-k3/am6_init.c
+++ b/arch/arm/mach-k3/am6_init.c
@@ -251,7 +251,8 @@
 	k3_sysfw_print_ver();
 
 	/* Perform EEPROM-based board detection */
-	do_board_detect();
+	if (IS_ENABLED(CONFIG_TI_I2C_BOARD_DETECT))
+		do_board_detect();
 
 #if defined(CONFIG_CPU_V7R) && defined(CONFIG_K3_AVS0)
 	ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(k3_avs),
diff --git a/arch/arm/mach-mvebu/armada3700/cpu.c b/arch/arm/mach-mvebu/armada3700/cpu.c
index 23492f4..52b5109 100644
--- a/arch/arm/mach-mvebu/armada3700/cpu.c
+++ b/arch/arm/mach-mvebu/armada3700/cpu.c
@@ -316,8 +316,8 @@
 
 int a3700_fdt_fix_pcie_regions(void *blob)
 {
-	int acells, pacells, scells;
-	u32 base, fix_offset;
+	u32 base, lowest_cpu_addr, fix_offset;
+	int pci_cells, cpu_cells, size_cells;
 	const u32 *ranges;
 	int node, pnode;
 	int ret, i, len;
@@ -331,51 +331,80 @@
 		return node;
 
 	ranges = fdt_getprop(blob, node, "ranges", &len);
-	if (!ranges || len % sizeof(u32))
-		return -ENOENT;
+	if (!ranges || !len || len % sizeof(u32))
+		return -EINVAL;
 
 	/*
 	 * The "ranges" property is an array of
-	 * { <child address> <parent address> <size in child address space> }
+	 *   { <PCI address> <CPU address> <size in PCI address space> }
+	 * where number of PCI address cells and size cells is stored in the
+	 * "#address-cells" and "#size-cells" properties of the same node
+	 * containing the "ranges" property and number of CPU address cells
+	 * is stored in the parent's "#address-cells" property.
 	 *
-	 * All 3 elements can span a diffent number of cells. Fetch their sizes.
+	 * All 3 elements can span a diffent number of cells. Fetch them.
 	 */
 	pnode = fdt_parent_offset(blob, node);
-	acells = fdt_address_cells(blob, node);
-	pacells = fdt_address_cells(blob, pnode);
-	scells = fdt_size_cells(blob, node);
+	pci_cells = fdt_address_cells(blob, node);
+	cpu_cells = fdt_address_cells(blob, pnode);
+	size_cells = fdt_size_cells(blob, node);
 
-	/* Child PCI addresses always use 3 cells */
-	if (acells != 3)
-		return -ENOENT;
+	/* PCI addresses always use 3 cells */
+	if (pci_cells != 3)
+		return -EINVAL;
 
-	/* Calculate fixup offset from first child address (in last cell) */
-	fix_offset = base - fdt32_to_cpu(ranges[2]);
+	/* CPU addresses on Armada 37xx always use 2 cells */
+	if (cpu_cells != 2)
+		return -EINVAL;
 
-	/* If fixup offset is zero then there is nothing to fix */
+	for (i = 0; i < len / sizeof(u32);
+	     i += pci_cells + cpu_cells + size_cells) {
+		/*
+		 * Parent CPU addresses on Armada 37xx are always 32-bit, so
+		 * check that the high word is zero.
+		 */
+		if (fdt32_to_cpu(ranges[i + pci_cells]))
+			return -EINVAL;
+
+		if (i == 0 ||
+		    fdt32_to_cpu(ranges[i + pci_cells + 1]) < lowest_cpu_addr)
+			lowest_cpu_addr = fdt32_to_cpu(ranges[i + pci_cells + 1]);
+	}
+
+	/* Calculate fixup offset from the lowest (first) CPU address */
+	fix_offset = base - lowest_cpu_addr;
+
+	/* If fixup offset is zero there is nothing to fix */
 	if (!fix_offset)
 		return 0;
 
 	/*
-	 * Fix address (last cell) of each child address and each parent
-	 * address
+	 * Fix each CPU address and corresponding PCI address if PCI address
+	 * is not already remapped (has the same value)
 	 */
-	for (i = 0; i < len / sizeof(u32); i += acells + pacells + scells) {
+	for (i = 0; i < len / sizeof(u32);
+	     i += pci_cells + cpu_cells + size_cells) {
+		u32 cpu_addr;
+		u64 pci_addr;
 		int idx;
 
-		/* fix child address */
-		idx = i + acells - 1;
+		/* Fix CPU address */
+		idx = i + pci_cells + cpu_cells - 1;
+		cpu_addr = fdt32_to_cpu(ranges[idx]);
 		ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
-						      fdt32_to_cpu(ranges[idx]) +
-						      fix_offset);
+						      cpu_addr + fix_offset);
 		if (ret)
 			return ret;
 
-		/* fix parent address */
-		idx = i + acells + pacells - 1;
+		/* Fix PCI address only if it isn't remapped (is same as CPU) */
+		idx = i + pci_cells - 1;
+		pci_addr = ((u64)fdt32_to_cpu(ranges[idx - 1]) << 32) |
+			   fdt32_to_cpu(ranges[idx]);
+		if (cpu_addr != pci_addr)
+			continue;
+
 		ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
-						      fdt32_to_cpu(ranges[idx]) +
-						      fix_offset);
+						      cpu_addr + fix_offset);
 		if (ret)
 			return ret;
 	}
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 4dab917..73da6b8 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -1035,7 +1035,7 @@
 
 config SPL_SPI_SUNXI
 	bool "Support for SPI Flash on Allwinner SoCs in SPL"
-	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6
+	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6 || MACH_SUNIV
 	help
 	  Enable support for SPI Flash. This option allows SPL to read from
 	  sunxi SPI Flash. It uses the same method as the boot ROM, so does
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 57078f7..0071de1 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -191,12 +191,48 @@
 
 #define SUNXI_INVALID_BOOT_SOURCE	-1
 
+static int suniv_get_boot_source(void)
+{
+	/* Get the last function call from BootROM's stack. */
+	u32 brom_call = *(u32 *)(uintptr_t)(fel_stash.sp - 4);
+
+	/* translate SUNIV BootROM stack to standard SUNXI boot sources */
+	switch (brom_call) {
+	case SUNIV_BOOTED_FROM_MMC0:
+		return SUNXI_BOOTED_FROM_MMC0;
+	case SUNIV_BOOTED_FROM_SPI:
+		return SUNXI_BOOTED_FROM_SPI;
+	case SUNIV_BOOTED_FROM_MMC1:
+		return SUNXI_BOOTED_FROM_MMC2;
+	/* SPI NAND is not supported yet. */
+	case SUNIV_BOOTED_FROM_NAND:
+		return SUNXI_INVALID_BOOT_SOURCE;
+	}
+	/* If we get here something went wrong try to boot from FEL.*/
+	printf("Unknown boot source from BROM: 0x%x\n", brom_call);
+	return SUNXI_INVALID_BOOT_SOURCE;
+}
+
 static int sunxi_get_boot_source(void)
 {
+	/*
+	 * On the ARMv5 SoCs, the SPL header in SRAM is overwritten by the
+	 * exception vectors in U-Boot proper, so we won't find any
+	 * information there. Also the FEL stash is only valid in the SPL,
+	 * so we can't use that either. So if this is called from U-Boot
+	 * proper, just return MMC0 as a placeholder, for now.
+	 */
+	if (IS_ENABLED(CONFIG_MACH_SUNIV) &&
+	    !IS_ENABLED(CONFIG_SPL_BUILD))
+		return SUNXI_BOOTED_FROM_MMC0;
+
 	if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
 		return SUNXI_INVALID_BOOT_SOURCE;
 
-	return readb(SPL_ADDR + 0x28);
+	if (IS_ENABLED(CONFIG_MACH_SUNIV))
+		return suniv_get_boot_source();
+	else
+		return readb(SPL_ADDR + 0x28);
 }
 
 /* The sunxi internal brom will try to loader external bootloader
@@ -276,36 +312,10 @@
 	return sector;
 }
 
-#ifdef CONFIG_MACH_SUNIV
-/*
- * The suniv BROM does not pass the boot media type to SPL, so we try with the
- * boot sequence in BROM: mmc0->spinor->fail.
- * TODO: This has the slight chance of being wrong (invalid SPL signature,
- * but valid U-Boot legacy image on the SD card), but this should be rare.
- * It looks like we can deduce from some BROM state upon entering the SPL
- * (registers, SP, or stack itself) where the BROM was coming from and use
- * that here.
- */
-void board_boot_order(u32 *spl_boot_list)
-{
-	/*
-	 * See the comments above in sunxi_get_boot_device() for information
-	 * about FEL boot.
-	 */
-	if (!is_boot0_magic(SPL_ADDR + 4)) {
-		spl_boot_list[0] = BOOT_DEVICE_BOARD;
-		return;
-	}
-
-	spl_boot_list[0] = BOOT_DEVICE_MMC1;
-	spl_boot_list[1] = BOOT_DEVICE_SPI;
-}
-#else
 u32 spl_boot_device(void)
 {
 	return sunxi_get_boot_device();
 }
-#endif
 
 __weak void sunxi_sram_init(void)
 {
diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
index 910e805..734c165 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -90,6 +90,7 @@
 
 #define SPI0_CLK_DIV_BY_2           0x1000
 #define SPI0_CLK_DIV_BY_4           0x1001
+#define SPI0_CLK_DIV_BY_32          0x100f
 
 /*****************************************************************************/
 
@@ -132,7 +133,8 @@
 	if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
 		return 0x05010000;
 
-	if (!is_sun6i_gen_spi())
+	if (!is_sun6i_gen_spi() ||
+	    IS_ENABLED(CONFIG_MACH_SUNIV))
 		return 0x01C05000;
 
 	return 0x01C68000;
@@ -156,11 +158,16 @@
 	if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
 		setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
 
-	/* Divide by 4 */
-	writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ?
-				  SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL));
-	/* 24MHz from OSC24M */
-	writel((1 << 31), CCM_SPI0_CLK);
+	if (IS_ENABLED(CONFIG_MACH_SUNIV)) {
+		/* Divide by 32, clock source is AHB clock 200MHz */
+		writel(SPI0_CLK_DIV_BY_32, base + SUN6I_SPI0_CCTL);
+	} else {
+		/* Divide by 4 */
+		writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ?
+					  SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL));
+		/* 24MHz from OSC24M */
+		writel((1 << 31), CCM_SPI0_CLK);
+	}
 
 	if (is_sun6i_gen_spi()) {
 		/* Enable SPI in the master mode and do a soft reset */
@@ -191,7 +198,8 @@
 					     SUN4I_CTL_ENABLE);
 
 	/* Disable the SPI0 clock */
-	writel(0, CCM_SPI0_CLK);
+	if (!IS_ENABLED(CONFIG_MACH_SUNIV))
+		writel(0, CCM_SPI0_CLK);
 
 	/* Close the SPI0 gate */
 	if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
@@ -212,6 +220,8 @@
 	if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
 	    IS_ENABLED(CONFIG_MACH_SUN50I_H6))
 		pin_function = SUN50I_GPC_SPI0;
+	else if (IS_ENABLED(CONFIG_MACH_SUNIV))
+		pin_function = SUNIV_GPC_SPI0;
 
 	spi0_pinmux_setup(pin_function);
 	spi0_enable_clock();
diff --git a/board/advantech/som-db5800-som-6867/.gitignore b/board/advantech/som-db5800-som-6867/.gitignore
index 6eb8a54..39e46ba 100644
--- a/board/advantech/som-db5800-som-6867/.gitignore
+++ b/board/advantech/som-db5800-som-6867/.gitignore
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
diff --git a/board/advantech/som-db5800-som-6867/Makefile b/board/advantech/som-db5800-som-6867/Makefile
index 7975547..95af6c4 100644
--- a/board/advantech/som-db5800-som-6867/Makefile
+++ b/board/advantech/som-db5800-som-6867/Makefile
@@ -3,4 +3,4 @@
 # Copyright (C) 2015, Google, Inc
 
 obj-y	+= som-db5800-som-6867.o
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
diff --git a/board/alliedtelesis/x530/x530.c b/board/alliedtelesis/x530/x530.c
index 8b31045..c0ec2af 100644
--- a/board/alliedtelesis/x530/x530.c
+++ b/board/alliedtelesis/x530/x530.c
@@ -73,6 +73,7 @@
 	{0},				/* timing parameters */
 	{ {0} },			/* electrical configuration */
 	{0},				/* electrical parameters */
+	0,				/* ODT configuration */
 	0,				/* Clock enable mask */
 	160				/* Clock delay */
 };
diff --git a/board/congatec/conga-qeval20-qa3-e3845/.gitignore b/board/congatec/conga-qeval20-qa3-e3845/.gitignore
index 6eb8a54..39e46ba 100644
--- a/board/congatec/conga-qeval20-qa3-e3845/.gitignore
+++ b/board/congatec/conga-qeval20-qa3-e3845/.gitignore
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
diff --git a/board/congatec/conga-qeval20-qa3-e3845/Makefile b/board/congatec/conga-qeval20-qa3-e3845/Makefile
index 451a4fc..215f568 100644
--- a/board/congatec/conga-qeval20-qa3-e3845/Makefile
+++ b/board/congatec/conga-qeval20-qa3-e3845/Makefile
@@ -3,4 +3,4 @@
 # Copyright (C) 2015, Google, Inc
 
 obj-y	+= conga-qeval20-qa3.o
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
diff --git a/board/dfi/dfi-bt700/Makefile b/board/dfi/dfi-bt700/Makefile
index 50d88f2..1c4329a 100644
--- a/board/dfi/dfi-bt700/Makefile
+++ b/board/dfi/dfi-bt700/Makefile
@@ -3,4 +3,4 @@
 # Copyright (C) 2015, Google, Inc
 
 obj-y	+= dfi-bt700.o
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
diff --git a/board/eets/pdu001/Makefile b/board/eets/pdu001/Makefile
index a5990ce3..35ea397 100644
--- a/board/eets/pdu001/Makefile
+++ b/board/eets/pdu001/Makefile
@@ -6,8 +6,4 @@
 # SPDX-License-Identifier: GPL-2.0+
 #
 
-ifeq ($(CONFIG_$(SPL_)SKIP_LOWLEVEL_INIT),)
-obj-y	:= mux.o
-endif
-
-obj-y	+= board.o
+obj-y	:= board.o mux.o
diff --git a/board/eets/pdu001/board.c b/board/eets/pdu001/board.c
index 9f3cfd4..2b483da 100644
--- a/board/eets/pdu001/board.c
+++ b/board/eets/pdu001/board.c
@@ -216,6 +216,36 @@
 	return &dpll_ddr;
 }
 
+void set_uart_mux_conf(void)
+{
+	switch (CONFIG_CONS_INDEX) {
+		case 1: {
+			enable_uart0_pin_mux();
+			break;
+		}
+		case 2: {
+			enable_uart1_pin_mux();
+			break;
+		}
+		case 3: {
+			enable_uart2_pin_mux();
+			break;
+		}
+		case 4: {
+			enable_uart3_pin_mux();
+			break;
+		}
+		case 5: {
+			enable_uart4_pin_mux();
+			break;
+		}
+		case 6: {
+			enable_uart5_pin_mux();
+			break;
+		}
+	}
+}
+
 void set_mux_conf_regs(void)
 {
 	/* done first by the ROM and afterwards by the pin controller driver */
@@ -240,6 +270,8 @@
 #ifdef CONFIG_DEBUG_UART
 void board_debug_uart_init(void)
 {
+	setup_early_clocks();
+
 	/* done by pin controller driver if not debugging */
 	enable_uart_pin_mux(CONFIG_DEBUG_UART_BASE);
 }
diff --git a/board/google/chromebook_coral/Makefile b/board/google/chromebook_coral/Makefile
index f7a0ca6..846558d 100644
--- a/board/google/chromebook_coral/Makefile
+++ b/board/google/chromebook_coral/Makefile
@@ -3,4 +3,4 @@
 # Copyright 2019 Google LLC
 
 obj-y	+= coral.o
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
diff --git a/board/intel/bayleybay/.gitignore b/board/intel/bayleybay/.gitignore
index 6eb8a54..39e46ba 100644
--- a/board/intel/bayleybay/.gitignore
+++ b/board/intel/bayleybay/.gitignore
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
diff --git a/board/intel/bayleybay/Makefile b/board/intel/bayleybay/Makefile
index d194471..fa263b7 100644
--- a/board/intel/bayleybay/Makefile
+++ b/board/intel/bayleybay/Makefile
@@ -3,4 +3,4 @@
 # Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
 
 obj-y	+= bayleybay.o
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
diff --git a/board/intel/edison/.gitignore b/board/intel/edison/.gitignore
index 6eb8a54..39e46ba 100644
--- a/board/intel/edison/.gitignore
+++ b/board/intel/edison/.gitignore
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
diff --git a/board/intel/edison/Makefile b/board/intel/edison/Makefile
index 1eaf7ca..f7f70df 100644
--- a/board/intel/edison/Makefile
+++ b/board/intel/edison/Makefile
@@ -5,4 +5,4 @@
 #
 
 obj-y	+= edison.o
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
diff --git a/board/intel/galileo/.gitignore b/board/intel/galileo/.gitignore
index 6eb8a54..39e46ba 100644
--- a/board/intel/galileo/.gitignore
+++ b/board/intel/galileo/.gitignore
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
diff --git a/board/intel/galileo/Makefile b/board/intel/galileo/Makefile
index 4130bb0..7d5f4df 100644
--- a/board/intel/galileo/Makefile
+++ b/board/intel/galileo/Makefile
@@ -3,4 +3,4 @@
 # Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
 
 obj-y	+= galileo.o
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
diff --git a/board/intel/minnowmax/.gitignore b/board/intel/minnowmax/.gitignore
index 6eb8a54..39e46ba 100644
--- a/board/intel/minnowmax/.gitignore
+++ b/board/intel/minnowmax/.gitignore
@@ -1,3 +1,3 @@
-dsdt.aml
-dsdt.asl.tmp
-dsdt.c
+dsdt_generated.aml
+dsdt_generated.asl.tmp
+dsdt_generated.c
diff --git a/board/intel/minnowmax/Makefile b/board/intel/minnowmax/Makefile
index d339b5a..a20322a 100644
--- a/board/intel/minnowmax/Makefile
+++ b/board/intel/minnowmax/Makefile
@@ -3,4 +3,4 @@
 # Copyright (C) 2015, Google, Inc
 
 obj-y	+= minnowmax.o
-obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt.o
+obj-$(CONFIG_GENERATE_ACPI_TABLE) += dsdt_generated.o
diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c
index e84b356..3c48a91 100644
--- a/board/kontron/sl28/sl28.c
+++ b/board/kontron/sl28/sl28.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <errno.h>
 #include <fsl_ddr.h>
@@ -14,7 +15,9 @@
 #include <asm/arch/soc.h>
 #include <fsl_immap.h>
 #include <netdev.h>
+#include <wdt.h>
 
+#include <sl28cpld.h>
 #include <fdtdec.h>
 #include <miiphy.h>
 
@@ -39,16 +42,68 @@
 	return pci_eth_init(bis);
 }
 
+static int __sl28cpld_read(uint reg)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_NOP,
+					  DM_DRIVER_GET(sl28cpld), &dev);
+	if (ret)
+		return ret;
+
+	return sl28cpld_read(dev, reg);
+}
+
+static void print_cpld_version(void)
+{
+	int version = __sl28cpld_read(SL28CPLD_VERSION);
+
+	if (version < 0)
+		printf("CPLD:  error reading version (%d)\n", version);
+	else
+		printf("CPLD:  v%d\n", version);
+}
+
 int checkboard(void)
 {
 	printf("EL:    %d\n", current_el());
+	if (CONFIG_IS_ENABLED(SL28CPLD))
+		print_cpld_version();
+
+	return 0;
+}
+
+static void stop_recovery_watchdog(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_WDT,
+					  DM_DRIVER_GET(sl28cpld_wdt), &dev);
+	if (!ret)
+		wdt_stop(dev);
+}
+
+int fsl_board_late_init(void)
+{
+	/*
+	 * Usually, the after a board reset, the watchdog is enabled by
+	 * default. This is to supervise the bootloader boot-up. Therefore,
+	 * to prevent a watchdog reset if we don't actively kick it, we have
+	 * to disable it.
+	 *
+	 * If the watchdog isn't enabled at reset (which is a configuration
+	 * option) disabling it doesn't hurt either.
+	 */
+	if (!CONFIG_IS_ENABLED(WATCHDOG_AUTOSTART))
+		stop_recovery_watchdog();
+
 	return 0;
 }
 
 void detail_board_ddr_info(void)
 {
-	puts("\nDDR    ");
-	print_size(gd->bd->bi_dram[0].size + gd->bd->bi_dram[1].size, "");
 	print_ddr_info(0);
 }
 
diff --git a/board/solidrun/clearfog/clearfog.c b/board/solidrun/clearfog/clearfog.c
index c920cf8..03adb59 100644
--- a/board/solidrun/clearfog/clearfog.c
+++ b/board/solidrun/clearfog/clearfog.c
@@ -147,6 +147,7 @@
 	{0},				/* timing parameters */
 	{ {0} },			/* electrical configuration */
 	{0,},				/* electrical parameters */
+	0,				/* ODT configuration */
 	0x3,				/* clock enable mask */
 };
 
diff --git a/board/ste/stemmy/stemmy.c b/board/ste/stemmy/stemmy.c
index 5f1150c..060d562 100644
--- a/board/ste/stemmy/stemmy.c
+++ b/board/ste/stemmy/stemmy.c
@@ -4,6 +4,7 @@
  */
 #include <common.h>
 #include <env.h>
+#include <fdt_support.h>
 #include <init.h>
 #include <log.h>
 #include <stdlib.h>
@@ -95,6 +96,33 @@
 	env_set("serial#", serial);
 }
 
+#define SBL_BOARD "board_id="
+#define SBL_LCDTYPE "lcdtype="
+static ulong board_id = 0;
+static ulong lcdtype = 0;
+
+static void parse_cmdline(const struct tag_cmdline *cmdline)
+{
+	char *buf;
+
+	/* Export this to sbl_cmdline (secondary boot loader command line) */
+	env_set("sbl_cmdline", cmdline->cmdline);
+
+	buf = strstr(cmdline->cmdline, SBL_BOARD);
+	if (!buf)
+		return;
+	buf += strlen(SBL_BOARD);
+
+	board_id = simple_strtoul(buf, NULL, 10);
+
+	buf = strstr(cmdline->cmdline, SBL_LCDTYPE);
+	if (!buf)
+		return;
+	buf += strlen(SBL_LCDTYPE);
+
+	lcdtype = simple_strtoul(buf, NULL, 10);
+}
+
 /*
  * The downstream/vendor kernel (provided by Samsung) uses ATAGS for booting.
  * It also requires an extremely long cmdline provided by the primary bootloader
@@ -126,6 +154,9 @@
 		if (t->hdr.tag == ATAG_SERIAL)
 			parse_serial(&t->u.serialnr);
 
+		if (t->hdr.tag == ATAG_CMDLINE)
+			parse_cmdline(&t->u.cmdline);
+
 		fw_atags_size += t->hdr.size * sizeof(u32);
 	}
 
@@ -165,3 +196,287 @@
 	memcpy(*in_params, fw_atags_copy, fw_atags_size);
 	*(u8 **)in_params += fw_atags_size;
 }
+
+/* These numbers are unique per product but not across all products */
+#define SAMSUNG_CODINA_LCD_LMS380KF01 4
+#define SAMSUNG_CODINA_LCD_S6D27A1 13
+#define SAMSUNG_SKOMER_LCD_HVA40WV1 10
+#define SAMSUNG_SKOMER_LCD_NT35512 12
+
+static void codina_patch_display(void *fdt)
+{
+	int node;
+	int ret;
+
+	node = fdt_path_offset(fdt, "/spi-gpio-0/panel");
+	if (node < 0) {
+		printf("cannot find Codina panel node\n");
+		return;
+	}
+	if (lcdtype == SAMSUNG_CODINA_LCD_LMS380KF01) {
+		ret = fdt_setprop_string(fdt, node, "compatible", "samsung,lms380kf01");
+		if (ret < 0)
+			printf("could not set LCD compatible\n");
+		else
+			printf("updated LCD compatible to LMS380KF01\n");
+	} else if (lcdtype == SAMSUNG_CODINA_LCD_S6D27A1) {
+		ret = fdt_setprop_string(fdt, node, "compatible", "samsung,s6d27a1");
+		if (ret < 0)
+			printf("could not set LCD compatible\n");
+		else
+			printf("updated LCD compatible to S6D27A1\n");
+	} else {
+		printf("unknown LCD type\n");
+	}
+}
+
+static void skomer_kyle_patch_display(void *fdt)
+{
+	int node;
+	int ret;
+
+	node = fdt_path_offset(fdt, "/soc/mcde/dsi/panel");
+	if (node < 0) {
+		printf("cannot find Skomer/Kyle panel node\n");
+		return;
+	}
+	if (lcdtype == SAMSUNG_SKOMER_LCD_HVA40WV1) {
+		ret = fdt_setprop_string(fdt, node, "compatible", "hydis,hva40wv1");
+		if (ret < 0)
+			printf("could not set LCD compatible\n");
+		else
+			printf("updated LCD compatible to Hydis HVA40WV1\n");
+	} else if (lcdtype == SAMSUNG_SKOMER_LCD_NT35512) {
+		/*
+		 * FIXME: This panel is actually a BOE product, but we don't know
+		 * the exact product name, so the compatible for the NT35512
+		 * is used for the time being. The vendor drivers also call it NT35512.
+		 */
+		ret = fdt_setprop_string(fdt, node, "compatible", "novatek,nt35512");
+		if (ret < 0)
+			printf("could not set LCD compatible\n");
+		else
+			printf("updated LCD compatible to Novatek NT35512\n");
+	} else {
+		printf("unknown LCD type\n");
+	}
+}
+
+int ft_board_setup(void *fdt, struct bd_info *bd)
+{
+	const char *str;
+	int node;
+	int ret;
+
+	printf("stemmy patch: DTB at 0x%08lx\n", (ulong)fdt);
+
+	/* Inspect FDT to see what we've got here */
+	ret = fdt_check_header(fdt);
+	if (ret < 0) {
+		printf("invalid DTB\n");
+		return ret;
+	}
+	node = fdt_path_offset(fdt, "/");
+	if (node < 0) {
+		printf("cannot find root node\n");
+		return node;
+	}
+	str = fdt_stringlist_get(fdt, node, "compatible", 0, NULL);
+	if (!str) {
+		printf("could not find board compatible\n");
+		return -1;
+	}
+
+	if (!strcmp(str, "samsung,janice")) {
+		switch(board_id) {
+		case 7:
+			printf("Janice GT-I9070 Board Rev 0.0\n");
+			break;
+		case 8:
+			printf("Janice GT-I9070 Board Rev 0.1\n");
+			break;
+		case 9:
+			printf("Janice GT-I9070 Board Rev 0.2\n");
+			break;
+		case 10:
+			printf("Janice GT-I9070 Board Rev 0.3\n");
+			break;
+		case 11:
+			printf("Janice GT-I9070 Board Rev 0.4\n");
+			break;
+		case 12:
+			printf("Janice GT-I9070 Board Rev 0.5\n");
+			break;
+		case 13:
+			printf("Janice GT-I9070 Board Rev 0.6\n");
+			break;
+		default:
+			break;
+		}
+	} else if (!strcmp(str, "samsung,gavini")) {
+		switch(board_id) {
+		case 7:
+			printf("Gavini GT-I8530 Board Rev 0.0\n");
+			break;
+		case 8:
+			printf("Gavini GT-I8530 Board Rev 0.0A\n");
+			break;
+		case 9:
+			printf("Gavini GT-I8530 Board Rev 0.0B\n");
+			break;
+		case 10:
+			printf("Gavini GT-I8530 Board Rev 0.0A_EMUL\n");
+			break;
+		case 11:
+			printf("Gavini GT-I8530 Board Rev 0.0C\n");
+			break;
+		case 12:
+			printf("Gavini GT-I8530 Board Rev 0.0D\n");
+			break;
+		case 13:
+			printf("Gavini GT-I8530 Board Rev 0.1\n");
+			break;
+		case 14:
+			printf("Gavini GT-I8530 Board Rev 0.3\n");
+			break;
+		default:
+			break;
+		}
+	} else if (!strcmp(str, "samsung,codina")) {
+		switch(board_id) {
+		case 7:
+			printf("Codina GT-I8160 Board Rev 0.0\n");
+			break;
+		case 8:
+			printf("Codina GT-I8160 Board Rev 0.1\n");
+			break;
+		case 9:
+			printf("Codina GT-I8160 Board Rev 0.2\n");
+			break;
+		case 10:
+			printf("Codina GT-I8160 Board Rev 0.3\n");
+			break;
+		case 11:
+			printf("Codina GT-I8160 Board Rev 0.4\n");
+			break;
+		case 12:
+			printf("Codina GT-I8160 Board Rev 0.5\n");
+			break;
+		default:
+			break;
+		}
+		codina_patch_display(fdt);
+	} else if (!strcmp(str, "samsung,codina-tmo")) {
+		switch(board_id) {
+		case 0x101:
+			printf("Codina SGH-T599 Board pre-Rev 0.0\n");
+			break;
+		case 0x102:
+			printf("Codina SGH-T599 Board Rev 0.0\n");
+			break;
+		case 0x103:
+			printf("Codina SGH-T599 Board Rev 0.1\n");
+			break;
+		case 0x104:
+			printf("Codina SGH-T599 Board Rev 0.2\n");
+			break;
+		case 0x105:
+			printf("Codina SGH-T599 Board Rev 0.4\n");
+			break;
+		case 0x106:
+			printf("Codina SGH-T599 Board Rev 0.6\n");
+			break;
+		case 0x107:
+			printf("Codina SGH-T599 Board Rev 0.7\n");
+			break;
+		default:
+			break;
+		}
+		codina_patch_display(fdt);
+	} else if (!strcmp(str, "samsung,golden")) {
+		switch(board_id) {
+		case 0x102:
+			printf("Golden GT-I8190 Board SW bringup\n");
+			break;
+		case 0x103:
+			printf("Golden GT-I8190 Board Rev 0.2\n");
+			break;
+		case 0x104:
+			printf("Golden GT-I8190 Board Rev 0.3\n");
+			break;
+		case 0x105:
+			printf("Golden GT-I8190 Board Rev 0.4\n");
+			break;
+		case 0x106:
+			printf("Golden GT-I8190 Board Rev 0.5\n");
+			break;
+		case 0x107:
+			printf("Golden GT-I8190 Board Rev 0.6\n");
+			break;
+		default:
+			break;
+		}
+	} else if (!strcmp(str, "samsung,skomer")) {
+		switch(board_id) {
+		case 0x101:
+			printf("Skomer GT-S7710 Board Rev 0.0\n");
+			break;
+		case 0x102:
+			printf("Skomer GT-S7710 Board Rev 0.1\n");
+			break;
+		case 0x103:
+			printf("Skomer GT-S7710 Board Rev 0.2\n");
+			break;
+		case 0x104:
+			printf("Skomer GT-S7710 Board Rev 0.3\n");
+			break;
+		case 0x105:
+			printf("Skomer GT-S7710 Board Rev 0.4\n");
+			break;
+		case 0x106:
+			printf("Skomer GT-S7710 Board Rev 0.5\n");
+			break;
+		case 0x107:
+			printf("Skomer GT-S7710 Board Rev 0.6\n");
+			break;
+		case 0x108:
+			printf("Skomer GT-S7710 Board Rev 0.7\n");
+			break;
+		case 0x109:
+			printf("Skomer GT-S7710 Board Rev 0.8\n");
+			break;
+		default:
+			break;
+		}
+		skomer_kyle_patch_display(fdt);
+	} else if (!strcmp(str, "samsung,kyle")) {
+		switch(board_id) {
+		case 0x101:
+			printf("Kyle SGH-I407 Board Rev 0.0\n");
+			break;
+		case 0x102:
+			printf("Kyle SGH-I407 Board Rev 0.1\n");
+			break;
+		case 0x103:
+			printf("Kyle SGH-I407 Board Rev 0.2\n");
+			break;
+		case 0x104:
+			printf("Kyle SGH-I407 Board Rev 0.3\n");
+			break;
+		case 0x105:
+			printf("Kyle SGH-I407 Board Rev 0.4\n");
+			break;
+		case 0x106:
+			printf("Kyle SGH-I407 Board Rev 0.5\n");
+			break;
+		case 0x107:
+			printf("Kyle SGH-I407 Board Rev 0.6\n");
+			break;
+		default:
+			break;
+		}
+		skomer_kyle_patch_display(fdt);
+	}
+
+	return 0;
+}
diff --git a/board/ti/am65x/evm.c b/board/ti/am65x/evm.c
index fbe33cb..7182a8c 100644
--- a/board/ti/am65x/evm.c
+++ b/board/ti/am65x/evm.c
@@ -129,6 +129,7 @@
 }
 #endif
 
+#ifdef CONFIG_TI_I2C_BOARD_DETECT
 int do_board_detect(void)
 {
 	int ret;
@@ -353,23 +354,26 @@
 
 	return 0;
 }
+#endif
 
 int board_late_init(void)
 {
-	struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
+	if (IS_ENABLED(CONFIG_TI_I2C_BOARD_DETECT)) {
+		struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
 
-	setup_board_eeprom_env();
+		setup_board_eeprom_env();
 
-	/*
-	 * The first MAC address for ethernet a.k.a. ethernet0 comes from
-	 * efuse populated via the am654 gigabit eth switch subsystem driver.
-	 * All the other ones are populated via EEPROM, hence continue with
-	 * an index of 1.
-	 */
-	board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt);
+		/*
+		 * The first MAC address for ethernet a.k.a. ethernet0 comes from
+		 * efuse populated via the am654 gigabit eth switch subsystem driver.
+		 * All the other ones are populated via EEPROM, hence continue with
+		 * an index of 1.
+		 */
+		board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt);
 
-	/* Check for and probe any plugged-in daughtercards */
-	probe_daughtercards();
+		/* Check for and probe any plugged-in daughtercards */
+		probe_daughtercards();
+	}
 
 	return 0;
 }
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 94d18ca..46eebd5 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -353,6 +353,19 @@
 	/* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
 	switch_to_non_secure_mode();
 
+	/*
+	 * The UEFI standard requires that the watchdog timer is set to five
+	 * minutes when invoking an EFI boot option.
+	 *
+	 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
+	 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
+	 */
+	ret = efi_set_watchdog(300);
+	if (ret != EFI_SUCCESS) {
+		log_err("ERROR: Failed to set watchdog timer\n");
+		goto out;
+	}
+
 	/* Call our payload! */
 	ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
 	if (ret != EFI_SUCCESS) {
@@ -366,11 +379,15 @@
 
 	efi_restore_gd();
 
+out:
 	free(load_options);
 
 	if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD))
 		efi_initrd_deregister();
 
+	/* Control is returned to U-Boot, disable EFI watchdog */
+	efi_set_watchdog(0);
+
 	return ret;
 }
 
diff --git a/cmd/clk.c b/cmd/clk.c
index dbbdc31..a483fd8 100644
--- a/cmd/clk.c
+++ b/cmd/clk.c
@@ -99,20 +99,6 @@
 }
 
 #if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(CLK)
-struct udevice *clk_lookup(const char *name)
-{
-	int i = 0;
-	struct udevice *dev;
-
-	do {
-		uclass_get_device(UCLASS_CLK, i++, &dev);
-		if (!strcmp(name, dev->name))
-			return dev;
-	} while (dev);
-
-	return NULL;
-}
-
 static int do_clk_setfreq(struct cmd_tbl *cmdtp, int flag, int argc,
 			  char *const argv[])
 {
@@ -120,16 +106,17 @@
 	s32 freq;
 	struct udevice *dev;
 
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
 	freq = dectoul(argv[2], NULL);
 
-	dev = clk_lookup(argv[1]);
-
-	if (dev)
+	if (!uclass_get_device_by_name(UCLASS_CLK, argv[1], &dev))
 		clk = dev_get_clk_ptr(dev);
 
 	if (!clk) {
 		printf("clock '%s' not found.\n", argv[1]);
-		return -EINVAL;
+		return CMD_RET_FAILURE;
 	}
 
 	freq = clk_set_rate(clk, freq);
@@ -173,7 +160,7 @@
 #ifdef CONFIG_SYS_LONGHELP
 static char clk_help_text[] =
 	"dump - Print clock frequencies\n"
-	"setfreq [clk] [freq] - Set clock frequency";
+	"clk setfreq [clk] [freq] - Set clock frequency";
 #endif
 
 U_BOOT_CMD(clk, 4, 1, do_clk, "CLK sub-system", clk_help_text);
diff --git a/cmd/pwm.c b/cmd/pwm.c
index 7947e61..7e82955 100644
--- a/cmd/pwm.c
+++ b/cmd/pwm.c
@@ -111,5 +111,5 @@
 	   "invert <pwm_dev_num> <channel> <polarity> - invert polarity\n"
 	   "pwm config <pwm_dev_num> <channel> <period_ns> <duty_ns> - config PWM\n"
 	   "pwm enable <pwm_dev_num> <channel> - enable PWM output\n"
-	   "pwm disable <pwm_dev_num> <channel> - eisable PWM output\n"
+	   "pwm disable <pwm_dev_num> <channel> - disable PWM output\n"
 	   "Note: All input values are in decimal");
diff --git a/configs/apple_m1_defconfig b/configs/apple_m1_defconfig
index 9254e24..360ec3f 100644
--- a/configs/apple_m1_defconfig
+++ b/configs/apple_m1_defconfig
@@ -3,10 +3,11 @@
 CONFIG_DEFAULT_DEVICE_TREE="t8103-j274"
 CONFIG_DEBUG_UART_BASE=0x235200000
 CONFIG_DEBUG_UART_CLOCK=24000000
-CONFIG_SYS_LOAD_ADDR=0x880000000
+CONFIG_SYS_LOAD_ADDR=0x0
 CONFIG_USE_PREBOOT=y
 # CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_BOARD_LATE_INIT=y
 # CONFIG_NET is not set
 CONFIG_APPLE_SPI_KEYB=y
 # CONFIG_MMC is not set
diff --git a/configs/gazerbeam_defconfig b/configs/gazerbeam_defconfig
index 5d8d199..199afb4 100644
--- a/configs/gazerbeam_defconfig
+++ b/configs/gazerbeam_defconfig
@@ -157,7 +157,7 @@
 CONFIG_AXI=y
 CONFIG_IHS_AXI=y
 CONFIG_CLK=y
-CONFIG_ICS8N3QV01=y
+CONFIG_CLK_ICS8N3QV01=y
 CONFIG_CPU=y
 CONFIG_CPU_MPC83XX=y
 CONFIG_SYS_BR0_PRELIM_BOOL=y
diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig
index b843a84..60c96f8 100644
--- a/configs/j721e_evm_a72_defconfig
+++ b/configs/j721e_evm_a72_defconfig
@@ -193,3 +193,4 @@
 CONFIG_CADENCE_UFS=y
 CONFIG_TI_J721E_UFS=y
 CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_MMC_SPEED_MODE_SET=y
diff --git a/configs/j721e_hs_evm_a72_defconfig b/configs/j721e_hs_evm_a72_defconfig
index ae184b0..6479f9b 100644
--- a/configs/j721e_hs_evm_a72_defconfig
+++ b/configs/j721e_hs_evm_a72_defconfig
@@ -162,3 +162,4 @@
 CONFIG_CADENCE_UFS=y
 CONFIG_TI_J721E_UFS=y
 CONFIG_OF_LIBFDT_OVERLAY=y
+CONFIG_MMC_SPEED_MODE_SET=y
diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig
index b61276c..cf8aedf 100644
--- a/configs/kontron_sl28_defconfig
+++ b/configs/kontron_sl28_defconfig
@@ -42,23 +42,23 @@
 CONFIG_CMD_NVEDIT_EFI=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
+CONFIG_CMD_WDT=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_EFIDEBUG=y
 CONFIG_CMD_RNG=y
 CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
-CONFIG_OF_LIST=""
+CONFIG_OF_LIST="fsl-ls1028a-kontron-sl28 fsl-ls1028a-kontron-sl28-var1 fsl-ls1028a-kontron-sl28-var2 fsl-ls1028a-kontron-sl28-var3 fsl-ls1028a-kontron-sl28-var4"
 CONFIG_ENV_OVERWRITE=y
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
-CONFIG_NET_RANDOM_ETHADDR=y
-CONFIG_NETCONSOLE=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_SATA=y
 CONFIG_SCSI_AHCI=y
@@ -69,8 +69,10 @@
 CONFIG_ECC_INIT_VIA_DDRCONTROLLER=y
 CONFIG_DFU_MMC=y
 CONFIG_DFU_SF=y
+CONFIG_SL28CPLD_GPIO=y
 CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
 CONFIG_I2C_MUX=y
+CONFIG_SL28CPLD=y
 CONFIG_MMC_HS400_SUPPORT=y
 CONFIG_FSL_ESDHC=y
 CONFIG_FSL_ESDHC_SUPPORT_ADMA2=y
@@ -102,6 +104,11 @@
 CONFIG_USB_DWC3_LAYERSCAPE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DOWNLOAD=y
+# CONFIG_WATCHDOG is not set
+# CONFIG_WATCHDOG_AUTOSTART is not set
+CONFIG_WDT=y
+CONFIG_WDT_SL28CPLD=y
+CONFIG_WDT_SP805=y
 CONFIG_OF_LIBFDT_ASSUME_MASK=0x0
 CONFIG_OF_LIBFDT_OVERLAY=y
 CONFIG_EFI_SET_TIME=y
diff --git a/configs/licheepi_nano_defconfig b/configs/licheepi_nano_defconfig
index 2ac0ef4..67b7b85 100644
--- a/configs/licheepi_nano_defconfig
+++ b/configs/licheepi_nano_defconfig
@@ -9,3 +9,5 @@
 CONFIG_DRAM_CLK=156
 CONFIG_DRAM_ZQ=0
 # CONFIG_VIDEO_SUNXI is not set
+CONFIG_SPL_SPI_SUNXI=y
+# CONFIG_SYSRESET is not set
diff --git a/configs/rzg2_beacon_defconfig b/configs/rzg2_beacon_defconfig
index e6a0d68..91b3fa2 100644
--- a/configs/rzg2_beacon_defconfig
+++ b/configs/rzg2_beacon_defconfig
@@ -62,7 +62,7 @@
 CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_BITBANGMII=y
-CONFIG_PHY_REALTEK=y
+CONFIG_PHY_ATHEROS=y
 CONFIG_DM_ETH=y
 CONFIG_RENESAS_RAVB=y
 CONFIG_DM_REGULATOR=y
diff --git a/configs/stemmy_defconfig b/configs/stemmy_defconfig
index ea43cb6..c02db99 100644
--- a/configs/stemmy_defconfig
+++ b/configs/stemmy_defconfig
@@ -36,3 +36,5 @@
 CONFIG_SYS_WHITE_ON_BLACK=y
 CONFIG_VIDEO_MCDE_SIMPLE=y
 # CONFIG_EFI_LOADER is not set
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_OF_LIBFDT=y
diff --git a/configs/turris_omnia_defconfig b/configs/turris_omnia_defconfig
index 280dd55..5b1fdbf 100644
--- a/configs/turris_omnia_defconfig
+++ b/configs/turris_omnia_defconfig
@@ -93,3 +93,4 @@
 CONFIG_USB_EHCI_HCD=y
 CONFIG_WDT=y
 CONFIG_WDT_ORION=y
+CONFIG_EXT4_WRITE=y
diff --git a/doc/api/clk.rst b/doc/api/clk.rst
new file mode 100644
index 0000000..7c27066
--- /dev/null
+++ b/doc/api/clk.rst
@@ -0,0 +1,19 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Clock API
+=========
+
+.. kernel-doc:: include/clk.h
+   :doc: Overview
+
+Client API
+----------
+
+.. kernel-doc:: include/clk.h
+   :internal:
+
+Driver API
+----------
+
+.. kernel-doc:: include/clk-uclass.h
+   :internal:
diff --git a/doc/api/index.rst b/doc/api/index.rst
index 3f36174..72fea98 100644
--- a/doc/api/index.rst
+++ b/doc/api/index.rst
@@ -6,6 +6,7 @@
 .. toctree::
    :maxdepth: 2
 
+   clk
    dfu
    dm
    efi
diff --git a/doc/arch/x86.rst b/doc/arch/x86.rst
index 5494155..634387a 100644
--- a/doc/arch/x86.rst
+++ b/doc/arch/x86.rst
@@ -732,7 +732,7 @@
 To generate SMBIOS tables in U-Boot, for use by the OS, enable the
 CONFIG_GENERATE_SMBIOS_TABLE option. The easiest way to provide the values to
 use is via the device tree. For details see
-device-tree-bindings/sysinfo/smbios.txt
+:download:`smbios.txt <../device-tree-bindings/sysinfo/smbios.txt>`.
 
 TODO List
 ---------
diff --git a/doc/board/kontron/sl28.rst b/doc/board/kontron/sl28.rst
index c7b18be..44435d9 100644
--- a/doc/board/kontron/sl28.rst
+++ b/doc/board/kontron/sl28.rst
@@ -23,34 +23,17 @@
 Install the bootloader on the board
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Please note, this bootloader doesn't support the builtin watchdog (yet),
-therefore you have to disable it, see below. Otherwise you'll end up in
-the failsafe bootloader on every reset::
+To install the bootloader binary use the following command::
 
  > tftp path/to/u-boot.rom
  > sf probe 0
  > sf update $fileaddr 0x210000 $filesize
 
-The board is fully failsafe, you can't break anything. But because you've
-disabled the builtin watchdog you might have to manually enter failsafe
-mode by asserting the ``FORCE_RECOV#`` line during board reset.
-
-Disable the builtin watchdog
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-- boot into the failsafe bootloader, either by asserting the
-  ``FORCE_RECOV#`` line or if you still have the original bootloader
-  installed you can use the command::
-
-  > wdt dev cpld_watchdog@4a; wdt expire 1
-
-- in the failsafe bootloader use the "sl28 nvm" command to disable
-  the automatic start of the builtin watchdog::
-
-  > sl28 nvm 0008
-
-- power-cycle the board
-
+The board is fully failsafe, you can't break anything. If builtin watchdog
+is enabled, you'll automatically end up in the failsafe bootloader if
+something goes wrong. If the watchdog is disabled, you have to manually
+enter failsafe mode by asserting the ``FORCE_RECOV#`` line during board
+reset.
 
 Update image
 ------------
@@ -67,20 +50,41 @@
 folder. On the next EFI boot this will automatically update your
 bootloader.
 
-Useful I2C tricks
------------------
+Builtin watchdog
+----------------
 
-The board has a board management controller which is not supported in
-u-boot (yet). But you can use the i2c command to access it.
+The builtin watchdog will supervise the bootloader startup. If anything
+goes wrong it will reset the board and boot into the failsafe bootloader.
 
-- reset into failsafe bootloader::
+Once the bootloader is started successfully, it will disable the watchdog
+timer.
 
-  > i2c mw 4a 5.1 0; i2c mw 4a 6.1 6b; i2c mw 4a 4.1 42
+wdt command flags
+^^^^^^^^^^^^^^^^^
 
-- read board management controller version::
+The `wdt start` as well as the `wdt expire` command take a flags argument.
+The supported bitmask is as follows.
 
-  > i2c md 4a 3.1 1
+| Bit | Description                   |
+| --- | ----------------------------- |
+|   0 | Enable failsafe mode          |
+|   1 | Lock the control register     |
+|   2 | Disable board reset           |
+|   3 | Enable WDT_TIME_OUT# line     |
 
+For example, you can use `wdt expire 1` to issue a reset and boot into the
+failsafe bootloader.
+
+Disable the builtin watchdog
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If for some reason, this isn't a desired behavior, the watchdog can also
+be configured to not be enabled on board reset. It's configuration is saved
+in the non-volatile board configuration bits. To change these you can use
+the `sl28 nvm` command.
+
+For more information on the non-volatile board configuration bits, see the
+following section.
 
 Non-volatile Board Configuration Bits
 -------------------------------------
diff --git a/doc/develop/index.rst b/doc/develop/index.rst
index 9714887..93ebfa4 100644
--- a/doc/develop/index.rst
+++ b/doc/develop/index.rst
@@ -22,6 +22,7 @@
    makefiles
    menus
    printf
+   smbios
    uefi/index
    version
 
diff --git a/doc/develop/smbios.rst b/doc/develop/smbios.rst
new file mode 100644
index 0000000..a4efb0a
--- /dev/null
+++ b/doc/develop/smbios.rst
@@ -0,0 +1,22 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+SMBIOS tables
+=============
+
+The System Management BIOS (SMBIOS) table is used to deliver management
+information from the firmware to the operating system. The content is
+standardized in [1]_.
+
+In Linux you can use the dmidecode command to view the contents of the SMBIOS
+table.
+
+When booting via UEFI the SMBIOS table is transferred as an UEFI configuration
+table to the operating system.
+
+To generate SMBIOS tables in U-Boot, the CONFIG_GENERATE_SMBIOS_TABLE option
+must be enabled. The easiest way to provide the values to use is via the device
+tree. For details see
+:download:`smbios.txt <../device-tree-bindings/sysinfo/smbios.txt>`.
+
+.. [1] `System Management BIOS (SMBIOS) Reference, version 3.5
+   <https://www.dmtf.org/content/dmtf-releases-smbios-35>`_
diff --git a/doc/kwboot.1 b/doc/kwboot.1
index acdea89..f555ff2 100644
--- a/doc/kwboot.1
+++ b/doc/kwboot.1
@@ -1,4 +1,4 @@
-.TH KWBOOT 1 "2021-08-25"
+.TH KWBOOT 1 "2022-03-02"
 
 .SH NAME
 kwboot \- Boot Marvell Kirkwood (and others 32-bit) SoCs over a serial link.
@@ -11,7 +11,7 @@
 .SH "DESCRIPTION"
 
 The \fBkwboot\fP program boots boards based on Marvell's 32-bit
-platforms including Kirkwood, Dove, A370, AXP, A375, A38x
+platforms including Kirkwood, Dove, Avanta, A370, AXP, A375, A38x
 and A39x over their integrated UART. Boot image files will typically
 contain a second stage boot loader, such as U-Boot. The image file
 must conform to Marvell's BootROM firmware image format
@@ -48,6 +48,48 @@
 written to stdout after the header is sent.
 
 .TP
+.B "\-b"
+Do only handshake on \fITTY\fP without uploading any file. File upload
+could be done later via option \fB\-D\fP or via any other Xmodem
+application, like \fBsx\fP(1).
+
+.TP
+.B "\-d"
+Do special handshake on \fITTY\fP for console debug mode.
+
+This will instruct BootROM to enter builtin simple console debug mode.
+Should be combined with option \fB\-t\fP.
+
+To get a BootROM help, type this command followed by ENTER key:
+
+.RS 1.2i
+.TP
+.B ?
+.RE
+.IP
+
+Armada 38x BootROM has a bug which cause that BootROM's standard output
+is turned off on UART when SPI-NOR contains valid boot image. Nevertheless
+BootROM's standard input and BootROM's terminal echo are active and working
+fine. To workaround this BootROM bug with standard output, it is possible
+to manually overwrite BootROM variables stored in SRAM which BootROM use
+for checking if standard output is enabled or not. To enable BootROM
+standard output on UART, type this command folled by ENTER key:
+
+.RS 1.2i
+.TP
+.B w 0x40034100 1
+.RE
+
+.TP
+.BI "\-D" " image"
+Upload file \fIimage\fP over \fITTY\fP without initial handshake.
+
+This method is used primary on Dove platforms, where BootROM does
+not support initial handshake for entering UART upload mode and
+strapping pins (exported via e.g. buttons) are used instead.
+
+.TP
 .BI "\-p"
 Obsolete. Does nothing.
 
@@ -56,12 +98,32 @@
 default.
 
 .TP
+.B "\-q"
+Obsolete. Does nothing.
+
+It is unknown whether it did something in the past.
+
+.TP
+.BI "\-s" " response-timeout"
+Specify custom response timeout when doing handshake. Default value is 50 ms.
+It is the timeout between sending two consecutive handshake patterns, meaning
+how long to wait for response from BootROM. Affects only option \fB\-b\fP with
+image file and option \fB\-d\fP.
+
+Option \fB-a\fP specify response timeout suitable for Armada XP BootROM and
+currently it is 1000 ms.
+
+Some testing showed that specifying 24 ms as response timeout make handshake
+with Armada 385 BootROM more stable.
+
+.TP
 .BI "\-t"
 Run a terminal program, connecting standard input and output to
 .RB \fITTY\fP.
 
-If used in combination with \fB-b\fP, terminal mode is entered
-immediately following a successful image upload.
+If used in combination with \fB\-b\fP, \fB\-D\fP or \fB\-d\fP option,
+terminal mode is entered immediately following a successful image upload
+or successful handshake (if not doing image upload).
 
 If standard I/O streams connect to a console, this mode will terminate
 after receiving \fBctrl-\e\fP followed by \fBc\fP from console input.
@@ -85,9 +147,42 @@
 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000,
 2000000, 2500000, 3125000, 4000000 and 5200000.
 
+.SH "EXAMPLES"
+
+Instruct BootROM to enter boot Xmodem boot mode, send \fIu-boot-spl.kwb\fP
+kwbimage file via Xmodem on \fI/dev/ttyUSB0\fP at 115200 Bd and run terminal
+program:
+.IP
+.B kwboot -b u-boot-spl.kwb -t /dev/ttyUSB0
+
+.PP
+Instruct BootROM to enter boot Xmodem boot mode, send header of
+\fIu-boot-spl.kwb\fP kwbimage file via Xmodem at 115200 Bd, then instruct
+BootROM to change baudrate to 5200000 Bd, send data part of the kwbimage
+file via Xmodem at high speed and finally run terminal program:
+.IP
+.B kwboot -b u-boot-spl.kwb -B 5200000 -t /dev/ttyUSB0
+
+.PP
+Only send \fIu-boot-spl.kwb\fP kwbimage file via Xmodem on \fI/dev/ttyUSB0\fP
+at 115200 Bd:
+.IP
+.B kwboot -D u-boot-spl.kwb /dev/ttyUSB0
+
+.PP
+Instruct BootROM to enter console debug mode and run terminal program on
+\fI/dev/ttyUSB0\fP at 115200 Bd:
+.IP
+.B kwboot -d -t /dev/ttyUSB0
+
+.PP
+Only run terminal program on \fI/dev/ttyUSB0\fP at 115200 Bd:
+.IP
+.B kwboot -t /dev/ttyUSB0
+
 .SH "SEE ALSO"
 .PP
-\fBmkimage\fP(1)
+\fBmkimage\fP(1), \fBsx\fP(1)
 
 .SH "AUTHORS"
 
diff --git a/doc/mkimage.1 b/doc/mkimage.1
index fc84cca..2870062 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -1,10 +1,10 @@
-.TH MKIMAGE 1 "2010-05-16"
+.TH MKIMAGE 1 "2022-02-07"
 
 .SH NAME
 mkimage \- Generate image for U-Boot
 .SH SYNOPSIS
 .B mkimage
-.RB "\-l [" "uimage file name" "]"
+.RB [ \-T " \fItype\fP] " \-l " [\fIuimage file name\fP]"
 
 .B mkimage
 .RB [\fIoptions\fP] " \-f [" "image tree source file" "]" " [" "uimage file name" "]"
@@ -47,6 +47,12 @@
 .BI "\-l [" "uimage file name" "]"
 mkimage lists the information contained in the header of an existing U-Boot image.
 
+.TP
+.BI "\-T [" "image type" "]"
+Parse image file as type.
+Pass \-h as the image to see the list of supported image type.
+Without this option image type is autodetected.
+
 .P
 .B Create old legacy image:
 
diff --git a/doc/usage/fatload.rst b/doc/usage/fatload.rst
new file mode 100644
index 0000000..93acb27
--- /dev/null
+++ b/doc/usage/fatload.rst
@@ -0,0 +1,80 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+fatload command
+===============
+
+Synopsis
+--------
+
+::
+
+    fatload <interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]
+
+Description
+-----------
+
+The fatload command is used to read a file from a FAT filesystem into memory.
+You can always use the :doc:`load command <load>` instead.
+
+The number of transferred bytes is saved in the environment variable filesize.
+The load address is saved in the environment variable fileaddr.
+
+interface
+    interface for accessing the block device (mmc, sata, scsi, usb, ....)
+
+dev
+    device number
+
+part
+    partition number, defaults to 0 (whole device)
+
+addr
+    load address, defaults to environment variable loadaddr or if loadaddr is
+    not set to configuration variable CONFIG_SYS_LOAD_ADDR
+
+filename
+    path to file, defaults to environment variable bootfile
+
+bytes
+    maximum number of bytes to load
+
+pos
+    number of bytes to skip
+
+addr, bytes, pos are hexadecimal numbers.
+
+If either 'pos' or 'bytes' are not aligned according to the minimum alignment
+requirement for DMA transfer (ARCH_DMA_MINALIGN) additional buffering will be
+used, a misaligned buffer warning will be printed, and performance will suffer
+for the load.
+
+Example
+-------
+
+::
+
+    => fatload mmc 0:1 ${kernel_addr_r} snp.efi
+    149280 bytes read in 11 ms (12.9 MiB/s)
+    =>
+    => fatload mmc 0:1 ${kernel_addr_r} snp.efi 1000000
+    149280 bytes read in 9 ms (15.8 MiB/s)
+    =>
+    => fatload mmc 0:1 ${kernel_addr_r} snp.efi 1000000 100
+    149024 bytes read in 10 ms (14.2 MiB/s)
+    =>
+    => fatload mmc 0:1 ${kernel_addr_r} snp.efi 10
+    16 bytes read in 1 ms (15.6 KiB/s)
+    =>
+
+Configuration
+-------------
+
+The fatload command is only available if CONFIG_CMD_FAT=y.
+
+Return value
+------------
+
+The return value $? is set to 0 (true) if the file was successfully loaded
+even if the number of bytes is less then the specified length.
+
+If an error occurs, the return value $? is set to 1 (false).
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 964d761..0aacf53 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -34,6 +34,7 @@
    exit
    false
    fatinfo
+   fatload
    for
    load
    loady
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index baac8d2..6dc271f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -30,22 +30,6 @@
 	  setting up clocks within TPL, and allows the same drivers to be
 	  used as U-Boot proper.
 
-config CLK_BCM6345
-	bool "Clock controller driver for BCM6345"
-	depends on CLK && ARCH_BMIPS
-	default y
-	help
-	  This clock driver adds support for enabling and disabling peripheral
-	  clocks on BCM6345 SoCs. HW has no rate changing capabilities.
-
-config CLK_BOSTON
-	def_bool y if TARGET_BOSTON
-	depends on CLK
-	select REGMAP
-	select SYSCON
-	help
-	  Enable this to support the clocks
-
 config SPL_CLK_CCF
 	bool "SPL Common Clock Framework [CCF] support "
 	depends on SPL
@@ -73,6 +57,37 @@
 	  Enable this option if you want to (re-)use the Linux kernel's Common
 	  Clock Framework [CCF] composite code in U-Boot's clock driver.
 
+config CLK_BCM6345
+	bool "Clock controller driver for BCM6345"
+	depends on CLK && ARCH_BMIPS
+	default y
+	help
+	  This clock driver adds support for enabling and disabling peripheral
+	  clocks on BCM6345 SoCs. HW has no rate changing capabilities.
+
+config CLK_BOSTON
+	def_bool y if TARGET_BOSTON
+	depends on CLK
+	select REGMAP
+	select SYSCON
+	help
+	  Enable this to support the clocks
+
+config CLK_CDCE9XX
+	bool "Enable CDCD9XX clock driver"
+	depends on CLK
+	help
+	   Enable the clock synthesizer driver for CDCE913/925/937/949
+	   series of chips.
+
+config CLK_ICS8N3QV01
+	bool "Enable ICS8N3QV01 VCXO driver"
+	depends on CLK
+	help
+	  Support for the ICS8N3QV01 Quad-Frequency VCXO (Voltage-Controlled
+	  Crystal Oscillator). The output frequency can be programmed via an
+	  I2C interface.
+
 config CLK_INTEL
 	bool "Enable clock driver for Intel x86"
 	depends on CLK && X86
@@ -83,6 +98,25 @@
 	  set up by U-Boot itself but only statically. Thus the driver does not
 	  support changing clock rates, only querying them.
 
+config CLK_K210
+	bool "Clock support for Kendryte K210"
+	depends on CLK
+	help
+	  This enables support clock driver for Kendryte K210 platforms.
+
+config CLK_K210_SET_RATE
+	bool "Enable setting the Kendryte K210 PLL rate"
+	depends on CLK_K210
+	help
+	  Add functionality to calculate new rates for K210 PLLs. Enabling this
+	  feature adds around 1K to U-Boot's final size.
+
+config CLK_MPC83XX
+	bool "Enable MPC83xx clock driver"
+	depends on CLK
+	help
+	  Support for the clock driver of the MPC83xx series of SoCs.
+
 config CLK_OCTEON
 	bool "Clock controller driver for Marvell MIPS Octeon"
 	depends on CLK && ARCH_OCTEON
@@ -90,6 +124,22 @@
 	help
 	  Enable this to support the clocks on Octeon MIPS platforms.
 
+config SANDBOX_CLK_CCF
+	bool "Sandbox Common Clock Framework [CCF] support "
+	depends on SANDBOX
+	select CLK_CCF
+	help
+	  Enable this option if you want to test the Linux kernel's Common
+	  Clock Framework [CCF] code in U-Boot's Sandbox clock driver.
+
+config CLK_SCMI
+	bool "Enable SCMI clock driver"
+	depends on SCMI_FIRMWARE
+	help
+	  Enable this option if you want to support clock devices exposed
+	  by a SCMI agent based on SCMI clock protocol communication
+	  with a SCMI server.
+
 config CLK_STM32F
 	bool "Enable clock driver support for STM32F family"
 	depends on CLK && (STM32F7 || STM32F4)
@@ -98,6 +148,14 @@
 	  This clock driver adds support for RCC clock management
 	  for STM32F4 and STM32F7 SoCs.
 
+config CLK_STM32MP1
+	bool "Enable RCC clock driver for STM32MP1"
+	depends on ARCH_STM32MP && CLK
+	default y
+	help
+	  Enable the STM32 clock (RCC) driver. Enable support for
+	  manipulating STM32MP1's on-SoC clocks.
+
 config CLK_HSDK
 	bool "Enable cgu clock driver for HSDK boards"
 	depends on CLK && TARGET_HSDK
@@ -105,6 +163,15 @@
 	  Enable this to support the cgu clocks on Synopsys ARC HSDK and
 	  Synopsys ARC HSDK-4xD boards
 
+config CLK_VERSACLOCK
+	tristate "Enable VersaClock 5/6 devices"
+	depends on CLK
+	depends on CLK_CCF
+	depends on OF_CONTROL
+	help
+	  This driver supports the IDT VersaClock 5 and VersaClock 6
+	  programmable clock generators.
+
 config CLK_VERSAL
 	bool "Enable clock driver support for Versal"
 	depends on ARCH_VERSAL
@@ -120,14 +187,6 @@
 	  This clock driver adds support for clock generators present on
 	  Arm Versatile Express platforms.
 
-config CLK_ZYNQ
-	bool "Enable clock driver support for Zynq"
-	depends on CLK && ARCH_ZYNQ
-	default y
-	help
-	  This clock driver adds support for clock related settings for
-	  Zynq platform.
-
 config CLK_XLNX_CLKWZRD
 	bool "Xilinx Clocking Wizard"
 	depends on CLK
@@ -139,6 +198,14 @@
 	  set_duty_cycle API, this driver only supports set_rate to modify
 	  the frequency.
 
+config CLK_ZYNQ
+	bool "Enable clock driver support for Zynq"
+	depends on CLK && ARCH_ZYNQ
+	default y
+	help
+	  This clock driver adds support for clock related settings for
+	  Zynq platform.
+
 config CLK_ZYNQMP
 	bool "Enable clock driver support for ZynqMP"
 	depends on ARCH_ZYNQMP
@@ -147,42 +214,6 @@
 	  This clock driver adds support for clock realted settings for
 	  ZynqMP platform.
 
-config CLK_STM32MP1
-	bool "Enable RCC clock driver for STM32MP1"
-	depends on ARCH_STM32MP && CLK
-	default y
-	help
-	  Enable the STM32 clock (RCC) driver. Enable support for
-	  manipulating STM32MP1's on-SoC clocks.
-
-config CLK_CDCE9XX
-	bool "Enable CDCD9XX clock driver"
-	depends on CLK
-	help
-	   Enable the clock synthesizer driver for CDCE913/925/937/949
-	   series of chips.
-
-config CLK_SCMI
-	bool "Enable SCMI clock driver"
-	depends on SCMI_FIRMWARE
-	help
-	  Enable this option if you want to support clock devices exposed
-	  by a SCMI agent based on SCMI clock protocol communication
-	  with a SCMI server.
-
-config CLK_K210
-	bool "Clock support for Kendryte K210"
-	depends on CLK
-	help
-	  This enables support clock driver for Kendryte K210 platforms.
-
-config CLK_K210_SET_RATE
-	bool "Enable setting the Kendryte K210 PLL rate"
-	depends on CLK_K210
-	help
-	  Add functionality to calculate new rates for K210 PLLs. Enabling this
-	  feature adds around 1K to U-Boot's final size.
-
 source "drivers/clk/analogbits/Kconfig"
 source "drivers/clk/at91/Kconfig"
 source "drivers/clk/exynos/Kconfig"
@@ -198,35 +229,4 @@
 source "drivers/clk/ti/Kconfig"
 source "drivers/clk/uniphier/Kconfig"
 
-config ICS8N3QV01
-	bool "Enable ICS8N3QV01 VCXO driver"
-	depends on CLK
-	help
-	  Support for the ICS8N3QV01 Quad-Frequency VCXO (Voltage-Controlled
-	  Crystal Oscillator). The output frequency can be programmed via an
-	  I2C interface.
-
-config CLK_MPC83XX
-	bool "Enable MPC83xx clock driver"
-	depends on CLK
-	help
-	  Support for the clock driver of the MPC83xx series of SoCs.
-
-config SANDBOX_CLK_CCF
-	bool "Sandbox Common Clock Framework [CCF] support "
-	depends on SANDBOX
-	select CLK_CCF
-	help
-	  Enable this option if you want to test the Linux kernel's Common
-	  Clock Framework [CCF] code in U-Boot's Sandbox clock driver.
-
-config CLK_VERSACLOCK
-	tristate "Enable VersaClock 5/6 devices"
-	depends on CLK
-	depends on CLK_CCF
-	depends on OF_CONTROL
-	help
-	  This driver supports the IDT VersaClock 5 and VersaClock 6
-	  programmable clock generators.
-
 endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 711ae5b..f922a7c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -15,41 +15,41 @@
 obj-y += imx/
 obj-y += tegra/
 obj-y += ti/
+obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/
 obj-$(CONFIG_ARCH_ASPEED) += aspeed/
 obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
-obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
 obj-$(CONFIG_ARCH_MESON) += meson/
+obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_ARCH_SOCFPGA) += altera/
+obj-$(CONFIG_ARCH_SUNXI) += sunxi/
 obj-$(CONFIG_CLK_AT91) += at91/
-obj-$(CONFIG_CLK_MVEBU) += mvebu/
 obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o
 obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
+obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o
 obj-$(CONFIG_CLK_EXYNOS) += exynos/
-obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/
 obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o
 obj-$(CONFIG_CLK_K210) += clk_kendryte.o
 obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
 obj-$(CONFIG_CLK_MPFS) += microchip/
+obj-$(CONFIG_CLK_MVEBU) += mvebu/
 obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o
 obj-$(CONFIG_CLK_OWL) += owl/
 obj-$(CONFIG_CLK_RENESAS) += renesas/
 obj-$(CONFIG_CLK_SCMI) += clk_scmi.o
 obj-$(CONFIG_CLK_SIFIVE) += sifive/
-obj-$(CONFIG_ARCH_SUNXI) += sunxi/
 obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
 obj-$(CONFIG_CLK_STM32MP1) += clk_stm32mp1.o
 obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
+obj-$(CONFIG_CLK_VERSACLOCK) += clk_versaclock.o
+obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
 obj-$(CONFIG_CLK_VEXPRESS_OSC) += clk_vexpress_osc.o
+obj-$(CONFIG_CLK_XLNX_CLKWZRD) += clk-xlnx-clock-wizard.o
 obj-$(CONFIG_CLK_ZYNQ) += clk_zynq.o
 obj-$(CONFIG_CLK_ZYNQMP) += clk_zynqmp.o
-obj-$(CONFIG_CLK_XLNX_CLKWZRD) += clk-xlnx-clock-wizard.o
-obj-$(CONFIG_ICS8N3QV01) += ics8n3qv01.o
+obj-$(CONFIG_CLK_ICS8N3QV01) += ics8n3qv01.o
 obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
+obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
-obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
-obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
-obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o
-obj-$(CONFIG_CLK_VERSACLOCK) += clk_versaclock.o
diff --git a/drivers/clk/clk-cdce9xx.c b/drivers/clk/clk-cdce9xx.c
index 6634b7b..f23465d 100644
--- a/drivers/clk/clk-cdce9xx.c
+++ b/drivers/clk/clk-cdce9xx.c
@@ -86,19 +86,13 @@
 	return ret;
 }
 
-static int cdce9xx_clk_of_xlate(struct clk *clk,
-				struct ofnode_phandle_args *args)
+static int cdce9xx_clk_request(struct clk *clk)
 {
 	struct cdce9xx_clk_data *data = dev_get_priv(clk->dev);
 
-	if (args->args_count != 1)
+	if (clk->id > data->chip->num_outputs)
 		return -EINVAL;
 
-	if (args->args[0] > data->chip->num_outputs)
-		return -EINVAL;
-
-	clk->id = args->args[0];
-
 	return 0;
 }
 
@@ -241,7 +235,7 @@
 };
 
 static const struct clk_ops cdce9xx_clk_ops = {
-	.of_xlate = cdce9xx_clk_of_xlate,
+	.request = cdce9xx_clk_request,
 	.get_rate = cdce9xx_clk_get_rate,
 	.set_rate = cdce9xx_clk_set_rate,
 };
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index d245b67..c20c928 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -432,17 +432,6 @@
 	return clk_get_by_index_nodev(node, index, clk);
 }
 
-int clk_get_optional_nodev(ofnode node, const char *name, struct clk *clk)
-{
-	int ret;
-
-	ret = clk_get_by_name_nodev(node, name, clk);
-	if (ret == -ENODATA)
-		return 0;
-
-	return ret;
-}
-
 int clk_release_all(struct clk *clk, int count)
 {
 	int i, ret;
@@ -652,7 +641,7 @@
 				return 0;
 			}
 			if (clkp->dev->parent &&
-			    device_get_uclass_id(clkp->dev) == UCLASS_CLK) {
+			    device_get_uclass_id(clkp->dev->parent) == UCLASS_CLK) {
 				ret = clk_enable(dev_get_clk_ptr(clkp->dev->parent));
 				if (ret) {
 					printf("Enable %s failed\n",
@@ -726,7 +715,7 @@
 		}
 
 		if (clkp && clkp->dev->parent &&
-		    device_get_uclass_id(clkp->dev) == UCLASS_CLK) {
+		    device_get_uclass_id(clkp->dev->parent) == UCLASS_CLK) {
 			ret = clk_disable(dev_get_clk_ptr(clkp->dev->parent));
 			if (ret) {
 				printf("Disable %s failed\n",
@@ -823,16 +812,6 @@
 	return clk;
 }
 
-struct clk *devm_clk_get_optional(struct udevice *dev, const char *id)
-{
-	struct clk *clk = devm_clk_get(dev, id);
-
-	if (PTR_ERR(clk) == -ENODATA)
-		return NULL;
-
-	return clk;
-}
-
 void devm_clk_put(struct udevice *dev, struct clk *clk)
 {
 	int rc;
diff --git a/drivers/clk/clk_versaclock.c b/drivers/clk/clk_versaclock.c
index 89c8d02..26c014c 100644
--- a/drivers/clk/clk_versaclock.c
+++ b/drivers/clk/clk_versaclock.c
@@ -618,24 +618,6 @@
 	return vc5_update_bits(vc->i2c, VC5_OUT_DIV_CONTROL(num), mask, src);
 }
 
-/*
- * The device references to the Versaclock point to the head, so xlate needs to
- * redirect it to clk_out[idx]
- */
-static int vc5_clk_out_xlate(struct clk *hw, struct ofnode_phandle_args *args)
-{
-	unsigned int idx = args->args[0];
-
-	if (args->args_count != 1) {
-		debug("Invalid args_count: %d\n", args->args_count);
-		return -EINVAL;
-	}
-
-	hw->id = idx;
-
-	return 0;
-}
-
 static unsigned long vc5_clk_out_set_rate(struct clk *hw, unsigned long rate)
 {
 	struct udevice *dev;
@@ -671,7 +653,6 @@
 static const struct clk_ops vc5_clk_ops = {
 	.enable	= vc5_clk_out_prepare,
 	.disable	= vc5_clk_out_unprepare,
-	.of_xlate	= vc5_clk_out_xlate,
 	.set_rate	= vc5_clk_out_set_rate,
 	.get_rate	= vc5_clk_out_get_rate,
 };
diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c
index 18915c3..e80500e 100644
--- a/drivers/clk/clk_zynq.c
+++ b/drivers/clk/clk_zynq.c
@@ -472,8 +472,9 @@
 
 	for (i = 0; i < 2; i++) {
 		sprintf(name, "gem%d_emio_clk", i);
-		ret = clk_get_by_name(dev, name, &priv->gem_emio_clk[i]);
-		if (ret < 0 && ret != -ENODATA) {
+		ret = clk_get_by_name_optional(dev, name,
+					       &priv->gem_emio_clk[i]);
+		if (ret) {
 			dev_err(dev, "failed to get %s clock\n", name);
 			return ret;
 		}
diff --git a/drivers/clk/ics8n3qv01.c b/drivers/clk/ics8n3qv01.c
index 6bc1b8b..33fb6ed 100644
--- a/drivers/clk/ics8n3qv01.c
+++ b/drivers/clk/ics8n3qv01.c
@@ -180,11 +180,6 @@
 	return 0;
 }
 
-static int ics8n3qv01_request(struct clk *clock)
-{
-	return 0;
-}
-
 static ulong ics8n3qv01_get_rate(struct clk *clk)
 {
 	struct ics8n3qv01_priv *priv = dev_get_priv(clk->dev);
@@ -203,7 +198,6 @@
 }
 
 static const struct clk_ops ics8n3qv01_ops = {
-	.request = ics8n3qv01_request,
 	.get_rate = ics8n3qv01_get_rate,
 	.set_rate = ics8n3qv01_set_rate,
 	.enable = ics8n3qv01_enable,
diff --git a/drivers/clk/tegra/tegra-car-clk.c b/drivers/clk/tegra/tegra-car-clk.c
index 09a7cf4..c5214b9 100644
--- a/drivers/clk/tegra/tegra-car-clk.c
+++ b/drivers/clk/tegra/tegra-car-clk.c
@@ -30,14 +30,6 @@
 	return 0;
 }
 
-static int tegra_car_clk_free(struct clk *clk)
-{
-	debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev,
-	      clk->id);
-
-	return 0;
-}
-
 static ulong tegra_car_clk_get_rate(struct clk *clk)
 {
 	enum clock_id parent;
@@ -82,7 +74,6 @@
 
 static struct clk_ops tegra_car_clk_ops = {
 	.request = tegra_car_clk_request,
-	.rfree = tegra_car_clk_free,
 	.get_rate = tegra_car_clk_get_rate,
 	.set_rate = tegra_car_clk_set_rate,
 	.enable = tegra_car_clk_enable,
diff --git a/drivers/clk/ti/clk-sci.c b/drivers/clk/ti/clk-sci.c
index acb9ead..74df5a3 100644
--- a/drivers/clk/ti/clk-sci.c
+++ b/drivers/clk/ti/clk-sci.c
@@ -64,18 +64,6 @@
 	return 0;
 }
 
-static int ti_sci_clk_request(struct clk *clk)
-{
-	debug("%s(clk=%p)\n", __func__, clk);
-	return 0;
-}
-
-static int ti_sci_clk_free(struct clk *clk)
-{
-	debug("%s(clk=%p)\n", __func__, clk);
-	return 0;
-}
-
 static ulong ti_sci_clk_get_rate(struct clk *clk)
 {
 	struct ti_sci_clk_data *data = dev_get_priv(clk->dev);
@@ -208,8 +196,6 @@
 
 static struct clk_ops ti_sci_clk_ops = {
 	.of_xlate = ti_sci_clk_of_xlate,
-	.request = ti_sci_clk_request,
-	.rfree = ti_sci_clk_free,
 	.get_rate = ti_sci_clk_get_rate,
 	.set_rate = ti_sci_clk_set_rate,
 	.set_parent = ti_sci_clk_set_parent,
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8d0e47c..522dfc1 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -544,4 +544,10 @@
 	  are accessed using xilinx firmware. In modepin register, [3:0] bits
 	  set direction, [7:4] bits read IO, [11:8] bits set/clear IO.
 
+config SL28CPLD_GPIO
+	bool "Kontron sl28cpld GPIO driver"
+	depends on DM_GPIO && SL28CPLD
+	help
+	  Support GPIO access on Kontron sl28cpld board management controllers.
+
 endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 63e9be6..33f7d41 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -70,4 +70,5 @@
 obj-$(CONFIG_SIFIVE_GPIO)	+= sifive-gpio.o
 obj-$(CONFIG_NOMADIK_GPIO)	+= nmk_gpio.o
 obj-$(CONFIG_MAX7320_GPIO)	+= max7320_gpio.o
+obj-$(CONFIG_SL28CPLD_GPIO)	+= sl28cpld-gpio.o
 obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN)	+= zynqmp_gpio_modepin.o
diff --git a/drivers/gpio/sl28cpld-gpio.c b/drivers/gpio/sl28cpld-gpio.c
new file mode 100644
index 0000000..700fc3d
--- /dev/null
+++ b/drivers/gpio/sl28cpld-gpio.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * GPIO driver for the sl28cpld
+ *
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <sl28cpld.h>
+
+/* GPIO flavor */
+#define SL28CPLD_GPIO_DIR	0x00
+#define SL28CPLD_GPIO_OUT	0x01
+#define SL28CPLD_GPIO_IN	0x02
+
+/* input-only flavor */
+#define SL28CPLD_GPI_IN		0x00
+
+/* output-only flavor */
+#define SL28CPLD_GPO_OUT	0x00
+
+enum {
+	SL28CPLD_GPIO,
+	SL28CPLD_GPI,
+	SL28CPLD_GPO,
+};
+
+static int sl28cpld_gpio_get_value(struct udevice *dev, unsigned int gpio)
+{
+	ulong type = dev_get_driver_data(dev);
+	int val, reg;
+
+	switch (type) {
+	case SL28CPLD_GPIO:
+		reg = SL28CPLD_GPIO_IN;
+		break;
+	case SL28CPLD_GPI:
+		reg = SL28CPLD_GPI_IN;
+		break;
+	case SL28CPLD_GPO:
+		/* we are output only, thus just return the output value */
+		reg = SL28CPLD_GPO_OUT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = sl28cpld_read(dev, reg);
+
+	return val < 0 ? val : !!(val & BIT(gpio));
+}
+
+static int sl28cpld_gpio_set_value(struct udevice *dev, unsigned int gpio,
+				   int value)
+{
+	ulong type = dev_get_driver_data(dev);
+	uint reg;
+
+	switch (type) {
+	case SL28CPLD_GPIO:
+		reg = SL28CPLD_GPIO_OUT;
+		break;
+	case SL28CPLD_GPO:
+		reg = SL28CPLD_GPO_OUT;
+		break;
+	case SL28CPLD_GPI:
+	default:
+		return -EINVAL;
+	}
+
+	if (value)
+		return sl28cpld_update(dev, reg, 0, BIT(gpio));
+	else
+		return sl28cpld_update(dev, reg, BIT(gpio), 0);
+}
+
+static int sl28cpld_gpio_direction_input(struct udevice *dev, unsigned int gpio)
+{
+	ulong type = dev_get_driver_data(dev);
+
+	switch (type) {
+	case SL28CPLD_GPI:
+		return 0;
+	case SL28CPLD_GPIO:
+		return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, BIT(gpio), 0);
+	case SL28CPLD_GPO:
+	default:
+		return -EINVAL;
+	}
+}
+
+static int sl28cpld_gpio_direction_output(struct udevice *dev,
+					  unsigned int gpio, int value)
+{
+	ulong type = dev_get_driver_data(dev);
+	int ret;
+
+	/* set_value() will report an error if we are input-only */
+	ret = sl28cpld_gpio_set_value(dev, gpio, value);
+	if (ret)
+		return ret;
+
+	if (type == SL28CPLD_GPIO)
+		return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, 0, BIT(gpio));
+
+	return 0;
+}
+
+static int sl28cpld_gpio_get_function(struct udevice *dev, unsigned int gpio)
+{
+	ulong type = dev_get_driver_data(dev);
+	int val;
+
+	switch (type) {
+	case SL28CPLD_GPIO:
+		val = sl28cpld_read(dev, SL28CPLD_GPIO_DIR);
+		if (val < 0)
+			return val;
+		if (val & BIT(gpio))
+			return GPIOF_OUTPUT;
+		else
+			return GPIOF_INPUT;
+	case SL28CPLD_GPI:
+		return GPIOF_INPUT;
+	case SL28CPLD_GPO:
+		return GPIOF_OUTPUT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct dm_gpio_ops sl28cpld_gpio_ops = {
+	.direction_input = sl28cpld_gpio_direction_input,
+	.direction_output = sl28cpld_gpio_direction_output,
+	.get_value = sl28cpld_gpio_get_value,
+	.set_value = sl28cpld_gpio_set_value,
+	.get_function = sl28cpld_gpio_get_function,
+};
+
+static int sl28cpld_gpio_probe(struct udevice *dev)
+{
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	uc_priv->gpio_count = 8;
+	uc_priv->bank_name = dev_read_name(dev);
+
+	return 0;
+}
+
+static const struct udevice_id sl28cpld_gpio_ids[] = {
+	{ .compatible = "kontron,sl28cpld-gpio", .data = SL28CPLD_GPIO},
+	{ .compatible = "kontron,sl28cpld-gpo", .data = SL28CPLD_GPO},
+	{ .compatible = "kontron,sl28cpld-gpi", .data = SL28CPLD_GPI},
+	{ }
+};
+
+U_BOOT_DRIVER(sl28cpld_gpio) = {
+	.name	= "sl28cpld_gpio",
+	.id	= UCLASS_GPIO,
+	.of_match = sl28cpld_gpio_ids,
+	.probe	= sl28cpld_gpio_probe,
+	.ops	= &sl28cpld_gpio_ops,
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0ade3e3..7029bb7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -512,4 +512,12 @@
 config FSL_IFC
 	bool
 
+config SL28CPLD
+	bool "Enable Kontron sl28cpld multi-function driver"
+	depends on DM_I2C
+	help
+	  Support for the Kontron sl28cpld management controller. This is
+	  the base driver which provides common access methods for the
+	  sub-drivers.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index bca7b24..f22eff6 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -82,3 +82,4 @@
 obj-$(CONFIG_K3_AVS0) += k3_avs.o
 obj-$(CONFIG_ESM_K3) += k3_esm.o
 obj-$(CONFIG_ESM_PMIC) += esm_pmic.o
+obj-$(CONFIG_SL28CPLD) += sl28cpld.o
diff --git a/drivers/misc/sl28cpld.c b/drivers/misc/sl28cpld.c
new file mode 100644
index 0000000..01ef1c6
--- /dev/null
+++ b/drivers/misc/sl28cpld.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+
+struct sl28cpld_child_plat {
+	uint offset;
+};
+
+/*
+ * The access methods works either with the first argument being a child
+ * device or with the MFD device itself.
+ */
+static int sl28cpld_read_child(struct udevice *dev, uint offset)
+{
+	struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev);
+	struct udevice *mfd = dev_get_parent(dev);
+
+	return dm_i2c_reg_read(mfd, offset + plat->offset);
+}
+
+int sl28cpld_read(struct udevice *dev, uint offset)
+{
+	if (dev->driver == DM_DRIVER_GET(sl28cpld))
+		return dm_i2c_reg_read(dev, offset);
+	else
+		return sl28cpld_read_child(dev, offset);
+}
+
+static int sl28cpld_write_child(struct udevice *dev, uint offset,
+				uint8_t value)
+{
+	struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev);
+	struct udevice *mfd = dev_get_parent(dev);
+
+	return dm_i2c_reg_write(mfd, offset + plat->offset, value);
+}
+
+int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value)
+{
+	if (dev->driver == DM_DRIVER_GET(sl28cpld))
+		return dm_i2c_reg_write(dev, offset, value);
+	else
+		return sl28cpld_write_child(dev, offset, value);
+}
+
+int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear,
+		    uint8_t set)
+{
+	int val;
+
+	val = sl28cpld_read(dev, offset);
+	if (val < 0)
+		return val;
+
+	val &= ~clear;
+	val |= set;
+
+	return sl28cpld_write(dev, offset, val);
+}
+
+static int sl28cpld_probe(struct udevice *dev)
+{
+	i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
+			   DM_I2C_CHIP_WR_ADDRESS);
+
+	return 0;
+}
+
+static int sl28cpld_child_post_bind(struct udevice *dev)
+{
+	struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev);
+	int offset;
+
+	if (!dev_has_ofnode(dev))
+		return 0;
+
+	offset = dev_read_u32_default(dev, "reg", -1);
+	if (offset == -1)
+		return -EINVAL;
+
+	plat->offset = offset;
+
+	return 0;
+}
+
+static const struct udevice_id sl28cpld_ids[] = {
+	{ .compatible = "kontron,sl28cpld" },
+	{}
+};
+
+U_BOOT_DRIVER(sl28cpld) = {
+	.name		= "sl28cpld",
+	.id		= UCLASS_NOP,
+	.of_match	= sl28cpld_ids,
+	.probe		= sl28cpld_probe,
+	.bind		= dm_scan_fdt_dev,
+	.flags		= DM_FLAG_PRE_RELOC,
+	.per_child_plat_auto = sizeof(struct sl28cpld_child_plat),
+	.child_post_bind = sl28cpld_child_post_bind,
+};
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c
index 1d1118c..4078d33 100644
--- a/drivers/net/ravb.c
+++ b/drivers/net/ravb.c
@@ -52,6 +52,7 @@
 #define CSR_OPS			0x0000000F
 #define CSR_OPS_CONFIG		BIT(1)
 
+#define APSR_RDM		BIT(13)
 #define APSR_TDM		BIT(14)
 
 #define TCCR_TSRQ0		BIT(0)
@@ -376,6 +377,9 @@
 	struct ravb_priv *eth = dev_get_priv(dev);
 	struct eth_pdata *pdata = dev_get_plat(dev);
 	int ret = 0;
+	int mode = 0;
+	unsigned int delay;
+	bool explicit_delay = false;
 
 	/* Set CONFIG mode */
 	ret = ravb_reset(dev);
@@ -402,9 +406,33 @@
 	    (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77995))
 		return 0;
 
-	if ((pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
-	    (pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID))
-		writel(APSR_TDM, eth->iobase + RAVB_REG_APSR);
+	if (!dev_read_u32(dev, "rx-internal-delay-ps", &delay)) {
+		/* Valid values are 0 and 1800, according to DT bindings */
+		if (delay) {
+			mode |= APSR_RDM;
+			explicit_delay = true;
+		}
+	}
+
+	if (!dev_read_u32(dev, "tx-internal-delay-ps", &delay)) {
+		/* Valid values are 0 and 2000, according to DT bindings */
+		if (delay) {
+			mode |= APSR_TDM;
+			explicit_delay = true;
+		}
+	}
+
+	if (!explicit_delay) {
+		if (pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
+		    pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID)
+			mode |= APSR_RDM;
+
+		if (pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
+		    pdata->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID)
+			mode |= APSR_TDM;
+	}
+
+	writel(mode, eth->iobase + RAVB_REG_APSR);
 
 	return 0;
 }
diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 5a0a59a..f076693 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -30,37 +30,25 @@
 #include <linux/sizes.h>
 
 /* PCIe unit register offsets */
-#define SELECT(x, n)			((x >> n) & 1UL)
-
-#define PCIE_DEV_ID_OFF			0x0000
-#define PCIE_CMD_OFF			0x0004
-#define PCIE_DEV_REV_OFF		0x0008
-#define  PCIE_BAR_LO_OFF(n)		(0x0010 + ((n) << 3))
-#define  PCIE_BAR_HI_OFF(n)		(0x0014 + ((n) << 3))
-#define PCIE_EXP_ROM_BAR_OFF		0x0030
-#define PCIE_CAPAB_OFF			0x0060
-#define PCIE_CTRL_STAT_OFF		0x0068
-#define PCIE_HEADER_LOG_4_OFF		0x0128
-#define  PCIE_BAR_CTRL_OFF(n)		(0x1804 + (((n) - 1) * 4))
-#define  PCIE_WIN04_CTRL_OFF(n)		(0x1820 + ((n) << 4))
-#define  PCIE_WIN04_BASE_OFF(n)		(0x1824 + ((n) << 4))
-#define  PCIE_WIN04_REMAP_OFF(n)	(0x182c + ((n) << 4))
-#define PCIE_WIN5_CTRL_OFF		0x1880
-#define PCIE_WIN5_BASE_OFF		0x1884
-#define PCIE_WIN5_REMAP_OFF		0x188c
-#define PCIE_CONF_ADDR_OFF		0x18f8
-#define PCIE_CONF_DATA_OFF		0x18fc
-#define PCIE_MASK_OFF			0x1910
-#define  PCIE_MASK_ENABLE_INTS          (0xf << 24)
-#define PCIE_CTRL_OFF			0x1a00
-#define  PCIE_CTRL_X1_MODE		BIT(0)
-#define  PCIE_CTRL_RC_MODE		BIT(1)
-#define PCIE_STAT_OFF			0x1a04
-#define  PCIE_STAT_BUS                  (0xff << 8)
-#define  PCIE_STAT_DEV                  (0x1f << 16)
-#define  PCIE_STAT_LINK_DOWN		BIT(0)
-#define PCIE_DEBUG_CTRL			0x1a60
-#define  PCIE_DEBUG_SOFT_RESET		BIT(20)
+#define MVPCIE_ROOT_PORT_PCI_CFG_OFF	0x0000
+#define MVPCIE_ROOT_PORT_PCI_EXP_OFF	0x0060
+#define MVPCIE_BAR_LO_OFF(n)		(0x0010 + ((n) << 3))
+#define MVPCIE_BAR_HI_OFF(n)		(0x0014 + ((n) << 3))
+#define MVPCIE_BAR_CTRL_OFF(n)		(0x1804 + (((n) - 1) * 4))
+#define MVPCIE_WIN04_CTRL_OFF(n)	(0x1820 + ((n) << 4))
+#define MVPCIE_WIN04_BASE_OFF(n)	(0x1824 + ((n) << 4))
+#define MVPCIE_WIN04_REMAP_OFF(n)	(0x182c + ((n) << 4))
+#define MVPCIE_WIN5_CTRL_OFF		0x1880
+#define MVPCIE_WIN5_BASE_OFF		0x1884
+#define MVPCIE_WIN5_REMAP_OFF		0x188c
+#define MVPCIE_CONF_ADDR_OFF		0x18f8
+#define MVPCIE_CONF_DATA_OFF		0x18fc
+#define MVPCIE_CTRL_OFF			0x1a00
+#define  MVPCIE_CTRL_RC_MODE		BIT(1)
+#define MVPCIE_STAT_OFF			0x1a04
+#define  MVPCIE_STAT_BUS		(0xff << 8)
+#define  MVPCIE_STAT_DEV		(0x1f << 16)
+#define  MVPCIE_STAT_LINK_DOWN		BIT(0)
 
 #define LINK_WAIT_RETRIES	100
 #define LINK_WAIT_TIMEOUT	1000
@@ -77,7 +65,6 @@
 	u32 lane;
 	bool is_x4;
 	int devfn;
-	u32 lane_mask;
 	int sec_busno;
 	char name[16];
 	unsigned int mem_target;
@@ -90,8 +77,8 @@
 static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
 {
 	u32 val;
-	val = readl(pcie->base + PCIE_STAT_OFF);
-	return !(val & PCIE_STAT_LINK_DOWN);
+	val = readl(pcie->base + MVPCIE_STAT_OFF);
+	return !(val & MVPCIE_STAT_LINK_DOWN);
 }
 
 static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie)
@@ -115,20 +102,20 @@
 {
 	u32 stat;
 
-	stat = readl(pcie->base + PCIE_STAT_OFF);
-	stat &= ~PCIE_STAT_BUS;
+	stat = readl(pcie->base + MVPCIE_STAT_OFF);
+	stat &= ~MVPCIE_STAT_BUS;
 	stat |= busno << 8;
-	writel(stat, pcie->base + PCIE_STAT_OFF);
+	writel(stat, pcie->base + MVPCIE_STAT_OFF);
 }
 
 static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie *pcie, int devno)
 {
 	u32 stat;
 
-	stat = readl(pcie->base + PCIE_STAT_OFF);
-	stat &= ~PCIE_STAT_DEV;
+	stat = readl(pcie->base + MVPCIE_STAT_OFF);
+	stat &= ~MVPCIE_STAT_DEV;
 	stat |= devno << 16;
-	writel(stat, pcie->base + PCIE_STAT_OFF);
+	writel(stat, pcie->base + MVPCIE_STAT_OFF);
 }
 
 static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose)
@@ -198,18 +185,18 @@
 		addr = PCI_CONF1_EXT_ADDRESS(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
 
 	/* write address */
-	writel(addr, pcie->base + PCIE_CONF_ADDR_OFF);
+	writel(addr, pcie->base + MVPCIE_CONF_ADDR_OFF);
 
 	/* read data */
 	switch (size) {
 	case PCI_SIZE_8:
-		data = readb(pcie->base + PCIE_CONF_DATA_OFF + (offset & 3));
+		data = readb(pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 3));
 		break;
 	case PCI_SIZE_16:
-		data = readw(pcie->base + PCIE_CONF_DATA_OFF + (offset & 2));
+		data = readw(pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 2));
 		break;
 	case PCI_SIZE_32:
-		data = readl(pcie->base + PCIE_CONF_DATA_OFF);
+		data = readl(pcie->base + MVPCIE_CONF_DATA_OFF);
 		break;
 	default:
 		return -EINVAL;
@@ -289,18 +276,18 @@
 		addr = PCI_CONF1_EXT_ADDRESS(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
 
 	/* write address */
-	writel(addr, pcie->base + PCIE_CONF_ADDR_OFF);
+	writel(addr, pcie->base + MVPCIE_CONF_ADDR_OFF);
 
 	/* write data */
 	switch (size) {
 	case PCI_SIZE_8:
-		writeb(value, pcie->base + PCIE_CONF_DATA_OFF + (offset & 3));
+		writeb(value, pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 3));
 		break;
 	case PCI_SIZE_16:
-		writew(value, pcie->base + PCIE_CONF_DATA_OFF + (offset & 2));
+		writew(value, pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 2));
 		break;
 	case PCI_SIZE_32:
-		writel(value, pcie->base + PCIE_CONF_DATA_OFF);
+		writel(value, pcie->base + MVPCIE_CONF_DATA_OFF);
 		break;
 	default:
 		return -EINVAL;
@@ -324,20 +311,20 @@
 
 	/* First, disable and clear BARs and windows. */
 	for (i = 1; i < 3; i++) {
-		writel(0, pcie->base + PCIE_BAR_CTRL_OFF(i));
-		writel(0, pcie->base + PCIE_BAR_LO_OFF(i));
-		writel(0, pcie->base + PCIE_BAR_HI_OFF(i));
+		writel(0, pcie->base + MVPCIE_BAR_CTRL_OFF(i));
+		writel(0, pcie->base + MVPCIE_BAR_LO_OFF(i));
+		writel(0, pcie->base + MVPCIE_BAR_HI_OFF(i));
 	}
 
 	for (i = 0; i < 5; i++) {
-		writel(0, pcie->base + PCIE_WIN04_CTRL_OFF(i));
-		writel(0, pcie->base + PCIE_WIN04_BASE_OFF(i));
-		writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
+		writel(0, pcie->base + MVPCIE_WIN04_CTRL_OFF(i));
+		writel(0, pcie->base + MVPCIE_WIN04_BASE_OFF(i));
+		writel(0, pcie->base + MVPCIE_WIN04_REMAP_OFF(i));
 	}
 
-	writel(0, pcie->base + PCIE_WIN5_CTRL_OFF);
-	writel(0, pcie->base + PCIE_WIN5_BASE_OFF);
-	writel(0, pcie->base + PCIE_WIN5_REMAP_OFF);
+	writel(0, pcie->base + MVPCIE_WIN5_CTRL_OFF);
+	writel(0, pcie->base + MVPCIE_WIN5_BASE_OFF);
+	writel(0, pcie->base + MVPCIE_WIN5_REMAP_OFF);
 
 	/* Setup windows for DDR banks. Count total DDR size on the fly. */
 	size = 0;
@@ -345,12 +332,12 @@
 		const struct mbus_dram_window *cs = dram->cs + i;
 
 		writel(cs->base & 0xffff0000,
-		       pcie->base + PCIE_WIN04_BASE_OFF(i));
-		writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
+		       pcie->base + MVPCIE_WIN04_BASE_OFF(i));
+		writel(0, pcie->base + MVPCIE_WIN04_REMAP_OFF(i));
 		writel(((cs->size - 1) & 0xffff0000) |
 		       (cs->mbus_attr << 8) |
 		       (dram->mbus_dram_target_id << 4) | 1,
-		       pcie->base + PCIE_WIN04_CTRL_OFF(i));
+		       pcie->base + MVPCIE_WIN04_CTRL_OFF(i));
 
 		size += cs->size;
 	}
@@ -360,14 +347,14 @@
 		size = 1 << fls(size);
 
 	/* Setup BAR[1] to all DRAM banks. */
-	writel(dram->cs[0].base | 0xc, pcie->base + PCIE_BAR_LO_OFF(1));
-	writel(0, pcie->base + PCIE_BAR_HI_OFF(1));
+	writel(dram->cs[0].base | 0xc, pcie->base + MVPCIE_BAR_LO_OFF(1));
+	writel(0, pcie->base + MVPCIE_BAR_HI_OFF(1));
 	writel(((size - 1) & 0xffff0000) | 0x1,
-	       pcie->base + PCIE_BAR_CTRL_OFF(1));
+	       pcie->base + MVPCIE_BAR_CTRL_OFF(1));
 
 	/* Setup BAR[0] to internal registers. */
-	writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0));
-	writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
+	writel(pcie->intregs, pcie->base + MVPCIE_BAR_LO_OFF(0));
+	writel(0, pcie->base + MVPCIE_BAR_HI_OFF(0));
 }
 
 /* Only enable PCIe link, do not setup it */
@@ -406,9 +393,9 @@
 	u32 reg;
 
 	/* Setup PCIe controller to Root Complex mode */
-	reg = readl(pcie->base + PCIE_CTRL_OFF);
-	reg |= PCIE_CTRL_RC_MODE;
-	writel(reg, pcie->base + PCIE_CTRL_OFF);
+	reg = readl(pcie->base + MVPCIE_CTRL_OFF);
+	reg |= MVPCIE_CTRL_RC_MODE;
+	writel(reg, pcie->base + MVPCIE_CTRL_OFF);
 
 	/*
 	 * Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link
@@ -417,10 +404,10 @@
 	 * be set to number of SerDes PCIe lanes (1 or 4). If this register is
 	 * not set correctly then link with endpoint card is not established.
 	 */
-	reg = readl(pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
+	reg = readl(pcie->base + MVPCIE_ROOT_PORT_PCI_EXP_OFF + PCI_EXP_LNKCAP);
 	reg &= ~PCI_EXP_LNKCAP_MLW;
 	reg |= (pcie->is_x4 ? 4 : 1) << 4;
-	writel(reg, pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
+	writel(reg, pcie->base + MVPCIE_ROOT_PORT_PCI_EXP_OFF + PCI_EXP_LNKCAP);
 }
 
 static int mvebu_pcie_probe(struct udevice *dev)
@@ -443,7 +430,7 @@
 	 * have the same format in Marvell's specification as in PCIe
 	 * specification, but their meaning is totally different and they do
 	 * different things: they are aliased into internal mvebu registers
-	 * (e.g. PCIE_BAR_LO_OFF) and these should not be changed or
+	 * (e.g. MVPCIE_BAR_LO_OFF) and these should not be changed or
 	 * reconfigured by pci device drivers.
 	 *
 	 * So our driver converts Type 0 config space to Type 1 and reports
@@ -451,10 +438,10 @@
 	 * Type 1 registers is redirected to the virtual cfgcache[] buffer,
 	 * which avoids changing unrelated registers.
 	 */
-	reg = readl(pcie->base + PCIE_DEV_REV_OFF);
+	reg = readl(pcie->base + MVPCIE_ROOT_PORT_PCI_CFG_OFF + PCI_CLASS_REVISION);
 	reg &= ~0xffffff00;
 	reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8;
-	writel(reg, pcie->base + PCIE_DEV_REV_OFF);
+	writel(reg, pcie->base + MVPCIE_ROOT_PORT_PCI_CFG_OFF + PCI_CLASS_REVISION);
 
 	/*
 	 * mvebu uses local bus number and local device number to determinate
diff --git a/drivers/phy/nop-phy.c b/drivers/phy/nop-phy.c
index e2ee6e9..d0904f4 100644
--- a/drivers/phy/nop-phy.c
+++ b/drivers/phy/nop-phy.c
@@ -45,11 +45,13 @@
 
 #if CONFIG_IS_ENABLED(DM_GPIO)
 	/* Take phy out of reset */
-	ret = dm_gpio_set_value(&priv->reset_gpio, false);
-	if (ret) {
-		if (CONFIG_IS_ENABLED(CLK))
-			clk_disable_bulk(&priv->bulk);
-		return ret;
+	if (dm_gpio_is_valid(&priv->reset_gpio)) {
+		ret = dm_gpio_set_value(&priv->reset_gpio, false);
+		if (ret) {
+			if (CONFIG_IS_ENABLED(CLK))
+				clk_disable_bulk(&priv->bulk);
+			return ret;
+		}
 	}
 #endif
 	return 0;
diff --git a/drivers/phy/phy-mtk-tphy.c b/drivers/phy/phy-mtk-tphy.c
index 824244b..2dd964f 100644
--- a/drivers/phy/phy-mtk-tphy.c
+++ b/drivers/phy/phy-mtk-tphy.c
@@ -723,13 +723,13 @@
 		tphy->phys[index] = instance;
 		index++;
 
-		err = clk_get_optional_nodev(subnode, "ref",
-					     &instance->ref_clk);
+		err = clk_get_by_name_nodev_optional(subnode, "ref",
+						     &instance->ref_clk);
 		if (err)
 			return err;
 
-		err = clk_get_optional_nodev(subnode, "da_ref",
-					     &instance->da_ref_clk);
+		err = clk_get_by_name_nodev_optional(subnode, "da_ref",
+						     &instance->da_ref_clk);
 		if (err)
 			return err;
 	}
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 1cf1f06..e76ef15 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -162,11 +162,11 @@
 	PIN_GRP_GPIO("emmc_nb", 27, 9, BIT(2), "emmc"),
 	PIN_GRP_GPIO_3("pwm0", 11, 1, BIT(3) | BIT(20), 0, BIT(20), BIT(3),
 		       "pwm", "led"),
-	PIN_GRP_GPIO_3("pwm1", 11, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4),
+	PIN_GRP_GPIO_3("pwm1", 12, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4),
 		       "pwm", "led"),
-	PIN_GRP_GPIO_3("pwm2", 11, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5),
+	PIN_GRP_GPIO_3("pwm2", 13, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5),
 		       "pwm", "led"),
-	PIN_GRP_GPIO_3("pwm3", 11, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6),
+	PIN_GRP_GPIO_3("pwm3", 14, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6),
 		       "pwm", "led"),
 	PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"),
 	PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"),
diff --git a/drivers/rng/meson-rng.c b/drivers/rng/meson-rng.c
index 5a4f45a..e0a1e8c 100644
--- a/drivers/rng/meson-rng.c
+++ b/drivers/rng/meson-rng.c
@@ -91,8 +91,8 @@
 		return -ENODEV;
 
 	/* Get optional "core" clock */
-	err = clk_get_by_name(dev, "core", &pdata->clk);
-	if (err && err != -ENODATA)
+	err = clk_get_by_name_optional(dev, "core", &pdata->clk);
+	if (err)
 		return err;
 
 	return 0;
diff --git a/drivers/rtc/armada38x.c b/drivers/rtc/armada38x.c
index 2d264ac..2af64e3 100644
--- a/drivers/rtc/armada38x.c
+++ b/drivers/rtc/armada38x.c
@@ -121,7 +121,7 @@
 		armada38x_rtc_write(0, rtc, RTC_CONF_TEST);
 		mdelay(500);
 		armada38x_rtc_write(0, rtc, RTC_TIME);
-		armada38x_rtc_write(BIT(0) | BIT(1), 0, RTC_STATUS);
+		armada38x_rtc_write(BIT(0) | BIT(1), rtc, RTC_STATUS);
 	}
 
 	return 0;
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 362cedd..f30f352 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -66,7 +66,8 @@
 	 */
 	if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
 					devp, NULL, false)) {
-		if (!device_probe(*devp))
+		if (device_get_uclass_id(*devp) == UCLASS_SERIAL &&
+		    !device_probe(*devp))
 			return 0;
 	}
 
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index cabac29..f90f0ca 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -266,6 +266,13 @@
 	   In the single stage mode, when the timeout is reached, your system
 	   will be reset by WS1. The first signal (WS0) is ignored.
 
+config WDT_SL28CPLD
+	bool "sl28cpld watchdog timer support"
+	depends on WDT && SL28CPLD
+	help
+	  Enable support for the watchdog timer in the Kontron sl28cpld
+	  management controller.
+
 config WDT_SP805
 	bool "SP805 watchdog timer support"
 	depends on WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 6d2b382..a35bd55 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -35,6 +35,7 @@
 obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o
 obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o
 obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o
+obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o
 obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
 obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
 obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
diff --git a/drivers/watchdog/armada-37xx-wdt.c b/drivers/watchdog/armada-37xx-wdt.c
index 2e119b9..bacebbc 100644
--- a/drivers/watchdog/armada-37xx-wdt.c
+++ b/drivers/watchdog/armada-37xx-wdt.c
@@ -58,13 +58,11 @@
 	clrbits_le32(priv->reg + CNTR_CTRL(id), CNTR_CTRL_ENABLE);
 }
 
-static int init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src)
+static void init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src)
 {
 	u32 reg;
 
 	reg = readl(priv->reg + CNTR_CTRL(id));
-	if (reg & CNTR_CTRL_ACTIVE)
-		return -EBUSY;
 
 	reg &= ~(CNTR_CTRL_MODE_MASK | CNTR_CTRL_PRESCALE_MASK |
 		 CNTR_CTRL_TRIG_SRC_MASK);
@@ -79,8 +77,6 @@
 	reg |= trig_src;
 
 	writel(reg, priv->reg + CNTR_CTRL(id));
-
-	return 0;
 }
 
 static int a37xx_wdt_reset(struct udevice *dev)
@@ -116,16 +112,9 @@
 static int a37xx_wdt_start(struct udevice *dev, u64 ms, ulong flags)
 {
 	struct a37xx_wdt *priv = dev_get_priv(dev);
-	int err;
 
-	err = init_counter(priv, 0, CNTR_CTRL_MODE_ONESHOT, 0);
-	if (err < 0)
-		return err;
-
-	err = init_counter(priv, 1, CNTR_CTRL_MODE_HWSIG,
-			   CNTR_CTRL_TRIG_SRC_PREV_CNTR);
-	if (err < 0)
-		return err;
+	init_counter(priv, 0, CNTR_CTRL_MODE_ONESHOT, 0);
+	init_counter(priv, 1, CNTR_CTRL_MODE_HWSIG, CNTR_CTRL_TRIG_SRC_PREV_CNTR);
 
 	priv->timeout = ms * priv->clk_rate / 1000 / CNTR_CTRL_PRESCALE_MIN;
 
diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c
index 253286d..8d93f19 100644
--- a/drivers/watchdog/rti_wdt.c
+++ b/drivers/watchdog/rti_wdt.c
@@ -41,7 +41,7 @@
 
 struct rti_wdt_priv {
 	phys_addr_t regs;
-	unsigned int clk_khz;
+	unsigned int clk_hz;
 };
 
 #ifdef CONFIG_WDT_K3_RTI_LOAD_FW
@@ -139,7 +139,7 @@
 	if (ret < 0)
 		return ret;
 
-	timer_margin = timeout_ms * priv->clk_khz / 1000;
+	timer_margin = timeout_ms * priv->clk_hz / 1000;
 	timer_margin >>= WDT_PRELOAD_SHIFT;
 	if (timer_margin > WDT_PRELOAD_MAX)
 		timer_margin = WDT_PRELOAD_MAX;
@@ -185,7 +185,15 @@
 	if (ret)
 		return ret;
 
-	priv->clk_khz = clk_get_rate(&clk);
+	priv->clk_hz = clk_get_rate(&clk);
+
+	/*
+	 * If watchdog is running at 32k clock, it is not accurate.
+	 * Adjust frequency down in this case so that it does not expire
+	 * earlier than expected.
+	 */
+	if (priv->clk_hz < 32768)
+		priv->clk_hz = priv->clk_hz * 9 / 10;
 
 	return 0;
 }
diff --git a/drivers/watchdog/sl28cpld-wdt.c b/drivers/watchdog/sl28cpld-wdt.c
new file mode 100644
index 0000000..af5a6b1
--- /dev/null
+++ b/drivers/watchdog/sl28cpld-wdt.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Watchdog driver for the sl28cpld
+ *
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <wdt.h>
+#include <sl28cpld.h>
+#include <div64.h>
+
+#define SL28CPLD_WDT_CTRL		0x00
+#define  WDT_CTRL_EN0			BIT(0)
+#define  WDT_CTRL_EN1			BIT(1)
+#define  WDT_CTRL_EN_MASK		GENMASK(1, 0)
+#define  WDT_CTRL_LOCK			BIT(2)
+#define  WDT_CTRL_ASSERT_SYS_RESET	BIT(6)
+#define  WDT_CTRL_ASSERT_WDT_TIMEOUT	BIT(7)
+#define SL28CPLD_WDT_TIMEOUT		0x01
+#define SL28CPLD_WDT_KICK		0x02
+#define  WDT_KICK_VALUE			0x6b
+
+static int sl28cpld_wdt_reset(struct udevice *dev)
+{
+	return sl28cpld_write(dev, SL28CPLD_WDT_KICK, WDT_KICK_VALUE);
+}
+
+static int sl28cpld_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+	int ret, val;
+
+	val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
+	if (val < 0)
+		return val;
+
+	/* (1) disable watchdog */
+	val &= ~WDT_CTRL_EN_MASK;
+	ret = sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
+	if (ret)
+		return ret;
+
+	/* (2) set timeout */
+	ret = sl28cpld_write(dev, SL28CPLD_WDT_TIMEOUT, lldiv(timeout, 1000));
+	if (ret)
+		return ret;
+
+	/* (3) kick it, will reset timer to the timeout value */
+	ret = sl28cpld_wdt_reset(dev);
+	if (ret)
+		return ret;
+
+	/* (4) enable either recovery or normal one */
+	if (flags & BIT(0))
+		val |= WDT_CTRL_EN1;
+	else
+		val |= WDT_CTRL_EN0;
+
+	if (flags & BIT(1))
+		val |= WDT_CTRL_LOCK;
+
+	if (flags & BIT(2))
+		val &= ~WDT_CTRL_ASSERT_SYS_RESET;
+	else
+		val |= WDT_CTRL_ASSERT_SYS_RESET;
+
+	if (flags & BIT(3))
+		val |= WDT_CTRL_ASSERT_WDT_TIMEOUT;
+	else
+		val &= ~WDT_CTRL_ASSERT_WDT_TIMEOUT;
+
+	return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
+}
+
+static int sl28cpld_wdt_stop(struct udevice *dev)
+{
+	int val;
+
+	val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
+	if (val < 0)
+		return val;
+
+	return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val & ~WDT_CTRL_EN_MASK);
+}
+
+static int sl28cpld_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+	return sl28cpld_wdt_start(dev, 0, flags);
+}
+
+static const struct wdt_ops sl28cpld_wdt_ops = {
+	.start = sl28cpld_wdt_start,
+	.reset = sl28cpld_wdt_reset,
+	.stop = sl28cpld_wdt_stop,
+	.expire_now = sl28cpld_wdt_expire_now,
+};
+
+static const struct udevice_id sl28cpld_wdt_ids[] = {
+	{ .compatible = "kontron,sl28cpld-wdt", },
+	{}
+};
+
+U_BOOT_DRIVER(sl28cpld_wdt) = {
+	.name = "sl28cpld-wdt",
+	.id = UCLASS_WDT,
+	.of_match = sl28cpld_wdt_ids,
+	.ops = &sl28cpld_wdt_ops,
+};
diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c
index 6d0f473..dbf5564 100644
--- a/drivers/watchdog/wdt-uclass.c
+++ b/drivers/watchdog/wdt-uclass.c
@@ -36,6 +36,8 @@
 	ulong next_reset;
 	/* Whether watchdog_start() has been called on the device. */
 	bool running;
+	/* No autostart */
+	bool noautostart;
 };
 
 static void init_watchdog_dev(struct udevice *dev)
@@ -52,7 +54,7 @@
 			       dev->name);
 	}
 
-	if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART)) {
+	if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART) || priv->noautostart) {
 		printf("WDT:   Not starting %s\n", dev->name);
 		return;
 	}
@@ -256,16 +258,19 @@
 	 * indicated by a hw_margin_ms property.
 	 */
 	ulong reset_period = 1000;
+	bool noautostart = false;
 	struct wdt_priv *priv;
 
 	if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
 		timeout = dev_read_u32_default(dev, "timeout-sec", timeout);
 		reset_period = dev_read_u32_default(dev, "hw_margin_ms",
 						    4 * reset_period) / 4;
+		noautostart = dev_read_bool(dev, "u-boot,noautostart");
 	}
 	priv = dev_get_uclass_priv(dev);
 	priv->timeout = timeout;
 	priv->reset_period = reset_period;
+	priv->noautostart = noautostart;
 	/*
 	 * Pretend this device was last reset "long" ago so the first
 	 * watchdog_reset will actually call its ->reset method.
diff --git a/include/clk-uclass.h b/include/clk-uclass.h
index 50e8681..e44f1ca 100644
--- a/include/clk-uclass.h
+++ b/include/clk-uclass.h
@@ -16,96 +16,127 @@
 
 /**
  * struct clk_ops - The functions that a clock driver must implement.
+ * @of_xlate: Translate a client's device-tree (OF) clock specifier.
+ * @request: Request a translated clock.
+ * @rfree: Free a previously requested clock.
+ * @round_rate: Adjust a rate to the exact rate a clock can provide.
+ * @get_rate: Get current clock rate.
+ * @set_rate: Set current clock rate.
+ * @set_parent: Set current clock parent
+ * @enable: Enable a clock.
+ * @disable: Disable a clock.
+ *
+ * The individual methods are described more fully below.
  */
 struct clk_ops {
-	/**
-	 * of_xlate - Translate a client's device-tree (OF) clock specifier.
-	 *
-	 * The clock core calls this function as the first step in implementing
-	 * a client's clk_get_by_*() call.
-	 *
-	 * If this function pointer is set to NULL, the clock core will use a
-	 * default implementation, which assumes #clock-cells = <1>, and that
-	 * the DT cell contains a simple integer clock ID.
-	 *
-	 * At present, the clock API solely supports device-tree. If this
-	 * changes, other xxx_xlate() functions may be added to support those
-	 * other mechanisms.
-	 *
-	 * @clock:	The clock struct to hold the translation result.
-	 * @args:	The clock specifier values from device tree.
-	 * @return 0 if OK, or a negative error code.
-	 */
 	int (*of_xlate)(struct clk *clock,
 			struct ofnode_phandle_args *args);
-	/**
-	 * request - Request a translated clock.
-	 *
-	 * The clock core calls this function as the second step in
-	 * implementing a client's clk_get_by_*() call, following a successful
-	 * xxx_xlate() call, or as the only step in implementing a client's
-	 * clk_request() call.
-	 *
-	 * @clock:	The clock struct to request; this has been fille in by
-	 *		a previoux xxx_xlate() function call, or by the caller
-	 *		of clk_request().
-	 * @return 0 if OK, or a negative error code.
-	 */
 	int (*request)(struct clk *clock);
-	/**
-	 * rfree - Free a previously requested clock.
-	 *
-	 * This is the implementation of the client clk_free() API.
-	 *
-	 * @clock:	The clock to free.
-	 * @return 0 if OK, or a negative error code.
-	 */
 	int (*rfree)(struct clk *clock);
-	/**
-	 * round_rate() - Adjust a rate to the exact rate a clock can provide.
-	 *
-	 * @clk:	The clock to manipulate.
-	 * @rate:	Desidered clock rate in Hz.
-	 * @return rounded rate in Hz, or -ve error code.
-	 */
 	ulong (*round_rate)(struct clk *clk, ulong rate);
-	/**
-	 * get_rate() - Get current clock rate.
-	 *
-	 * @clk:	The clock to query.
-	 * @return clock rate in Hz, or -ve error code
-	 */
 	ulong (*get_rate)(struct clk *clk);
-	/**
-	 * set_rate() - Set current clock rate.
-	 *
-	 * @clk:	The clock to manipulate.
-	 * @rate:	New clock rate in Hz.
-	 * @return new rate, or -ve error code.
-	 */
 	ulong (*set_rate)(struct clk *clk, ulong rate);
-	/**
-	 * set_parent() - Set current clock parent
-	 *
-	 * @clk:        The clock to manipulate.
-	 * @parent:     New clock parent.
-	 * @return zero on success, or -ve error code.
-	 */
 	int (*set_parent)(struct clk *clk, struct clk *parent);
-	/**
-	 * enable() - Enable a clock.
-	 *
-	 * @clk:	The clock to manipulate.
-	 * @return zero on success, or -ve error code.
-	 */
 	int (*enable)(struct clk *clk);
-	/**
-	 * disable() - Disable a clock.
-	 *
-	 * @clk:	The clock to manipulate.
-	 * @return zero on success, or -ve error code.
-	 */
 	int (*disable)(struct clk *clk);
 };
 
+#if 0 /* For documentation only */
+/**
+ * of_xlate() - Translate a client's device-tree (OF) clock specifier.
+ * @clock:	The clock struct to hold the translation result.
+ * @args:	The clock specifier values from device tree.
+ *
+ * The clock core calls this function as the first step in implementing
+ * a client's clk_get_by_*() call.
+ *
+ * If this function pointer is set to NULL, the clock core will use a
+ * default implementation, which assumes #clock-cells = <1>, and that
+ * the DT cell contains a simple integer clock ID.
+ *
+ * At present, the clock API solely supports device-tree. If this
+ * changes, other xxx_xlate() functions may be added to support those
+ * other mechanisms.
+ *
+ * Return: 0 if OK, or a negative error code.
+ */
+int of_xlate(struct clk *clock, struct ofnode_phandle_args *args);
+
+/**
+ * request() - Request a translated clock.
+ * @clock:	The clock struct to request; this has been fille in by
+ *		a previoux xxx_xlate() function call, or by the caller
+ *		of clk_request().
+ *
+ * The clock core calls this function as the second step in
+ * implementing a client's clk_get_by_*() call, following a successful
+ * xxx_xlate() call, or as the only step in implementing a client's
+ * clk_request() call.
+ *
+ * Return: 0 if OK, or a negative error code.
+ */
+int request(struct clk *clock);
+
+/**
+ * rfree() - Free a previously requested clock.
+ * @clock:	The clock to free.
+ *
+ * This is the implementation of the client clk_free() API.
+ *
+ * Return: 0 if OK, or a negative error code.
+ */
+int rfree(struct clk *clock);
+
+/**
+ * round_rate() - Adjust a rate to the exact rate a clock can provide.
+ * @clk:	The clock to manipulate.
+ * @rate:	Desidered clock rate in Hz.
+ *
+ * Return: rounded rate in Hz, or -ve error code.
+ */
+ulong round_rate(struct clk *clk, ulong rate);
+
+/**
+ * get_rate() - Get current clock rate.
+ * @clk:	The clock to query.
+ *
+ * Return: clock rate in Hz, or -ve error code
+ */
+ulong get_rate(struct clk *clk);
+
+/**
+ * set_rate() - Set current clock rate.
+ * @clk:	The clock to manipulate.
+ * @rate:	New clock rate in Hz.
+ *
+ * Return: new rate, or -ve error code.
+ */
+ulong set_rate(struct clk *clk, ulong rate);
+
+/**
+ * set_parent() - Set current clock parent
+ * @clk:        The clock to manipulate.
+ * @parent:     New clock parent.
+ *
+ * Return: zero on success, or -ve error code.
+ */
+int set_parent(struct clk *clk, struct clk *parent);
+
+/**
+ * enable() - Enable a clock.
+ * @clk:	The clock to manipulate.
+ *
+ * Return: zero on success, or -ve error code.
+ */
+int enable(struct clk *clk);
+
+/**
+ * disable() - Disable a clock.
+ * @clk:	The clock to manipulate.
+ *
+ * Return: zero on success, or -ve error code.
+ */
+int disable(struct clk *clk);
+#endif
+
 #endif
diff --git a/include/clk.h b/include/clk.h
index 040d2d6..23e4d4e 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -14,6 +14,8 @@
 #include <linux/types.h>
 
 /**
+ * DOC: Overview
+ *
  * A clock is a hardware signal that oscillates autonomously at a specific
  * frequency and duty cycle. Most hardware modules require one or more clock
  * signal to drive their operation. Clock signals are typically generated
@@ -34,22 +36,22 @@
 
 /**
  * struct clk - A handle to (allowing control of) a single clock.
+ * @dev: The device which implements the clock signal.
+ * @rate: The clock rate (in HZ).
+ * @flags: Flags used across common clock structure (e.g. %CLK_)
+ *         Clock IP blocks specific flags (i.e. mux, div, gate, etc) are defined
+ *         in struct's for those devices (e.g. &struct clk_mux).
+ * @enable_count: The number of times this clock has been enabled.
+ * @id: The clock signal ID within the provider.
+ * @data: An optional data field for scenarios where a single integer ID is not
+ *	  sufficient. If used, it can be populated through an .of_xlate op and
+ *	  processed during the various clock ops.
  *
  * Clients provide storage for clock handles. The content of the structure is
  * managed solely by the clock API and clock drivers. A clock struct is
  * initialized by "get"ing the clock struct. The clock struct is passed to all
  * other clock APIs to identify which clock signal to operate upon.
  *
- * @dev: The device which implements the clock signal.
- * @rate: The clock rate (in HZ).
- * @flags: Flags used across common clock structure (e.g. CLK_)
- *         Clock IP blocks specific flags (i.e. mux, div, gate, etc) are defined
- *         in struct's for those devices (e.g. struct clk_mux).
- * @id: The clock signal ID within the provider.
- * @data: An optional data field for scenarios where a single integer ID is not
- *	  sufficient. If used, it can be populated through an .of_xlate op and
- *	  processed during the various clock ops.
- *
  * Should additional information to identify and configure any clock signal
  * for any provider be required in the future, the struct could be expanded to
  * either (a) add more fields to allow clock providers to store additional
@@ -72,15 +74,14 @@
 
 /**
  * struct clk_bulk - A handle to (allowing control of) a bulk of clocks.
+ * @clks: An array of clock handles.
+ * @count: The number of clock handles in the clks array.
  *
  * Clients provide storage for the clock bulk. The content of the structure is
  * managed solely by the clock API. A clock bulk struct is
  * initialized by "get"ing the clock bulk struct.
  * The clock bulk struct is passed to all other bulk clock APIs to apply
  * the API to all the clock in the bulk struct.
- *
- * @clks: An array of clock handles.
- * @count: The number of clock handles in the clks array.
  */
 struct clk_bulk {
 	struct clk *clks;
@@ -91,16 +92,19 @@
 struct phandle_1_arg;
 /**
  * clk_get_by_phandle() - Get a clock by its phandle information (of-platadata)
+ * @dev: Device containing the phandle
+ * @cells: Phandle info
+ * @clk: A pointer to a clock struct to initialise
  *
  * This function is used when of-platdata is enabled.
  *
  * This looks up a clock using the phandle info. With dtoc, each phandle in the
- * 'clocks' property is transformed into an idx representing the device. For
- * example:
+ * 'clocks' property is transformed into an idx representing the device.
+ * For example::
  *
  *	clocks = <&dpll_mpu_ck 23>;
  *
- * might result in:
+ * might result in::
  *
  *	.clocks = {1, {23}},},
  *
@@ -109,9 +113,6 @@
  * this example it would return a clock containing the 'dpll_mpu_ck' device and
  * the clock ID 23.
  *
- * @dev: Device containing the phandle
- * @cells: Phandle info
- * @clock: A pointer to a clock struct to initialise
  * Return: 0 if OK, or a negative error code.
  */
 int clk_get_by_phandle(struct udevice *dev, const struct phandle_1_arg *cells,
@@ -119,6 +120,10 @@
 
 /**
  * clk_get_by_index() - Get/request a clock by integer index.
+ * @dev:	The client device.
+ * @index:	The index of the clock to request, within the client's list of
+ *		clocks.
+ * @clk:	A pointer to a clock struct to initialize.
  *
  * This looks up and requests a clock. The index is relative to the client
  * device; each device is assumed to have n clocks associated with it somehow,
@@ -126,30 +131,26 @@
  * device clock indices to provider clocks may be via device-tree properties,
  * board-provided mapping tables, or some other mechanism.
  *
- * @dev:	The client device.
- * @index:	The index of the clock to request, within the client's list of
- *		clocks.
- * @clock	A pointer to a clock struct to initialize.
  * Return: 0 if OK, or a negative error code.
  */
 int clk_get_by_index(struct udevice *dev, int index, struct clk *clk);
 
 /**
- * clk_get_by_index_nodev - Get/request a clock by integer index
- * without a device.
- *
- * This is a version of clk_get_by_index() that does not use a device.
- *
+ * clk_get_by_index_nodev() - Get/request a clock by integer index without a
+ *                            device.
  * @node:	The client ofnode.
  * @index:	The index of the clock to request, within the client's list of
  *		clocks.
- * @clock	A pointer to a clock struct to initialize.
+ * @clk:	A pointer to a clock struct to initialize.
+ *
  * Return: 0 if OK, or a negative error code.
  */
 int clk_get_by_index_nodev(ofnode node, int index, struct clk *clk);
 
 /**
- * clk_get_bulk - Get/request all clocks of a device.
+ * clk_get_bulk() - Get/request all clocks of a device.
+ * @dev:	The client device.
+ * @bulk:	A pointer to a clock bulk struct to initialize.
  *
  * This looks up and requests all clocks of the client device; each device is
  * assumed to have n clocks associated with it somehow, and this function finds
@@ -157,14 +158,16 @@
  * device clock indices to provider clocks may be via device-tree properties,
  * board-provided mapping tables, or some other mechanism.
  *
- * @dev:	The client device.
- * @bulk	A pointer to a clock bulk struct to initialize.
  * Return: 0 if OK, or a negative error code.
  */
 int clk_get_bulk(struct udevice *dev, struct clk_bulk *bulk);
 
 /**
- * clk_get_by_name - Get/request a clock by name.
+ * clk_get_by_name() - Get/request a clock by name.
+ * @dev:	The client device.
+ * @name:	The name of the clock to request, within the client's list of
+ *		clocks.
+ * @clk:	A pointer to a clock struct to initialize.
  *
  * This looks up and requests a clock. The name is relative to the client
  * device; each device is assumed to have n clocks associated with it somehow,
@@ -172,83 +175,71 @@
  * device clock names to provider clocks may be via device-tree properties,
  * board-provided mapping tables, or some other mechanism.
  *
- * @dev:	The client device.
- * @name:	The name of the clock to request, within the client's list of
- *		clocks.
- * @clock:	A pointer to a clock struct to initialize.
  * Return: 0 if OK, or a negative error code.
  */
 int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk);
 
 /**
  * clk_get_by_name_nodev - Get/request a clock by name without a device.
- *
- * This is a version of clk_get_by_name() that does not use a device.
- *
  * @node:	The client ofnode.
  * @name:	The name of the clock to request, within the client's list of
  *		clocks.
- * @clock:	A pointer to a clock struct to initialize.
+ * @clk:	A pointer to a clock struct to initialize.
+ *
  * Return: 0 if OK, or a negative error code.
  */
 int clk_get_by_name_nodev(ofnode node, const char *name, struct clk *clk);
 
 /**
- * clk_get_optional_nodev - Get/request an optinonal clock by name
- *		without a device.
- * @node:	The client ofnode.
- * @name:	The name of the clock to request.
- * @name:	The name of the clock to request, within the client's list of
- *		clocks.
- * @clock:	A pointer to a clock struct to initialize.
- *
- * Behaves the same as clk_get_by_name_nodev() except where there is
- * no clock producer, in this case, skip the error number -ENODATA, and
- * the function returns 0.
- */
-int clk_get_optional_nodev(ofnode node, const char *name, struct clk *clk);
-
-/**
- * devm_clk_get - lookup and obtain a managed reference to a clock producer.
+ * devm_clk_get() - lookup and obtain a managed reference to a clock producer.
  * @dev: device for clock "consumer"
  * @id: clock consumer ID
  *
- * Returns a struct clk corresponding to the clock producer, or
- * valid IS_ERR() condition containing errno.  The implementation
- * uses @dev and @id to determine the clock consumer, and thereby
- * the clock producer.  (IOW, @id may be identical strings, but
- * clk_get may return different clock producers depending on @dev.)
+ * The implementation uses @dev and @id to determine the clock consumer, and
+ * thereby the clock producer. (IOW, @id may be identical strings, but clk_get
+ * may return different clock producers depending on @dev.)
  *
  * Drivers must assume that the clock source is not enabled.
  *
- * devm_clk_get should not be called from within interrupt context.
- *
  * The clock will automatically be freed when the device is unbound
  * from the bus.
+ *
+ * Return:
+ * a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno
  */
 struct clk *devm_clk_get(struct udevice *dev, const char *id);
 
 /**
- * devm_clk_get_optional - lookup and obtain a managed reference to an optional
- *			   clock producer.
+ * devm_clk_get_optional() - lookup and obtain a managed reference to an
+ *                           optional clock producer.
  * @dev: device for clock "consumer"
  * @id: clock consumer ID
  *
  * Behaves the same as devm_clk_get() except where there is no clock producer.
- * In this case, instead of returning -ENOENT, the function returns NULL.
+ * In this case, instead of returning -%ENOENT, the function returns NULL.
  */
-struct clk *devm_clk_get_optional(struct udevice *dev, const char *id);
+static inline struct clk *devm_clk_get_optional(struct udevice *dev,
+						const char *id)
+{
+	struct clk *clk = devm_clk_get(dev, id);
+
+	if (PTR_ERR(clk) == -ENODATA)
+		return NULL;
+
+	return clk;
+}
 
 /**
  * clk_release_all() - Disable (turn off)/Free an array of previously
  * requested clocks.
+ * @clk:	A clock struct array that was previously successfully
+ *		requested by clk_request/get_by_*().
+ * @count:	Number of clock contained in the array
  *
  * For each clock contained in the clock array, this function will check if
  * clock has been previously requested and then will disable and free it.
  *
- * @clk:	A clock struct array that was previously successfully
- *		requested by clk_request/get_by_*().
- * @count	Number of clock contained in the array
  * Return: zero on success, or -ve error code.
  */
 int clk_release_all(struct clk *clk, int count);
@@ -290,12 +281,6 @@
 	return -ENOSYS;
 }
 
-static inline int
-clk_get_optional_nodev(ofnode node, const char *name, struct clk *clk)
-{
-	return -ENOSYS;
-}
-
 static inline int clk_release_all(struct clk *clk, int count)
 {
 	return -ENOSYS;
@@ -303,6 +288,54 @@
 #endif
 
 /**
+ * clk_get_by_name_optional() - Get/request a optional clock by name.
+ * @dev:	The client device.
+ * @name:	The name of the clock to request, within the client's list of
+ *		clocks.
+ * @clk:	A pointer to a clock struct to initialize.
+ *
+ * Behaves the same as clk_get_by_name(), except when there is no clock
+ * provider. In the latter case, return 0.
+ *
+ * Return: 0 if OK, or a negative error code.
+ */
+static inline int clk_get_by_name_optional(struct udevice *dev,
+					   const char *name, struct clk *clk)
+{
+	int ret;
+
+	ret = clk_get_by_name(dev, name, clk);
+	if (ret == -ENODATA)
+		return 0;
+
+	return ret;
+}
+
+/**
+ * clk_get_by_name_nodev_optional - Get/request an optinonal clock by name
+ *		without a device.
+ * @node:	The client ofnode.
+ * @name:	The name of the clock to request, within the client's list of
+ *		clocks.
+ * @clk:	A pointer to a clock struct to initialize.
+ *
+ * Behaves the same as clk_get_by_name_nodev() except where there is
+ * no clock producer, in this case, skip the error number -%ENODATA, and
+ * the function returns 0.
+ */
+static inline int clk_get_by_name_nodev_optional(ofnode node, const char *name,
+						 struct clk *clk)
+{
+	int ret;
+
+	ret = clk_get_by_name_nodev(node, name, clk);
+	if (ret == -ENODATA)
+		return 0;
+
+	return ret;
+}
+
+/**
  * enum clk_defaults_stage - What stage clk_set_defaults() is called at
  * @CLK_DEFAULTS_PRE: Called before probe. Setting of defaults for clocks owned
  *                    by this clock driver will be defered until after probing.
@@ -327,12 +360,13 @@
 
 #if CONFIG_IS_ENABLED(OF_REAL) && CONFIG_IS_ENABLED(CLK)
 /**
- * clk_set_defaults - Process 'assigned-{clocks/clock-parents/clock-rates}'
+ * clk_set_defaults - Process ``assigned-{clocks/clock-parents/clock-rates}``
  *                    properties to configure clocks
- *
  * @dev:        A device to process (the ofnode associated with this device
  *              will be processed).
  * @stage:	The stage of the probing process this function is called during.
+ *
+ * Return: zero on success, or -ve error code.
  */
 int clk_set_defaults(struct udevice *dev, enum clk_defaults_stage stage);
 #else
@@ -345,12 +379,12 @@
 /**
  * clk_release_bulk() - Disable (turn off)/Free an array of previously
  * requested clocks in a clock bulk struct.
+ * @bulk:	A clock bulk struct that was previously successfully
+ *		requested by clk_get_bulk().
  *
  * For each clock contained in the clock bulk struct, this function will check
  * if clock has been previously requested and then will disable and free it.
  *
- * @clk:	A clock bulk struct that was previously successfully
- *		requested by clk_get_bulk().
  * Return: zero on success, or -ve error code.
  */
 static inline int clk_release_bulk(struct clk_bulk *bulk)
@@ -360,35 +394,35 @@
 
 #if CONFIG_IS_ENABLED(CLK)
 /**
- * clk_request - Request a clock by provider-specific ID.
+ * clk_request() - Request a clock by provider-specific ID.
+ * @dev:	The clock provider device.
+ * @clk:	A pointer to a clock struct to initialize. The caller must
+ *		have already initialized any field in this struct which the
+ *		clock provider uses to identify the clock.
  *
  * This requests a clock using a provider-specific ID. Generally, this function
  * should not be used, since clk_get_by_index/name() provide an interface that
  * better separates clients from intimate knowledge of clock providers.
  * However, this function may be useful in core SoC-specific code.
  *
- * @dev:	The clock provider device.
- * @clock:	A pointer to a clock struct to initialize. The caller must
- *		have already initialized any field in this struct which the
- *		clock provider uses to identify the clock.
  * Return: 0 if OK, or a negative error code.
  */
 int clk_request(struct udevice *dev, struct clk *clk);
 
 /**
- * clk_free - Free a previously requested clock.
- *
- * @clock:	A clock struct that was previously successfully requested by
+ * clk_free() - Free a previously requested clock.
+ * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
+ *
  * Return: 0 if OK, or a negative error code.
  */
 int clk_free(struct clk *clk);
 
 /**
  * clk_get_rate() - Get current clock rate.
- *
  * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
+ *
  * Return: clock rate in Hz on success, 0 for invalid clock, or -ve error code
  *	   for other errors.
  */
@@ -396,98 +430,98 @@
 
 /**
  * clk_get_parent() - Get current clock's parent.
- *
  * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
+ *
  * Return: pointer to parent's struct clk, or error code passed as pointer
  */
 struct clk *clk_get_parent(struct clk *clk);
 
 /**
  * clk_get_parent_rate() - Get parent of current clock rate.
- *
  * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
+ *
  * Return: clock rate in Hz, or -ve error code.
  */
 long long clk_get_parent_rate(struct clk *clk);
 
 /**
  * clk_round_rate() - Adjust a rate to the exact rate a clock can provide
+ * @clk: A clock struct that was previously successfully requested by
+ *       clk_request/get_by_*().
+ * @rate: desired clock rate in Hz.
  *
  * This answers the question "if I were to pass @rate to clk_set_rate(),
  * what clock rate would I end up with?" without changing the hardware
- * in any way.  In other words:
+ * in any way. In other words::
  *
  *   rate = clk_round_rate(clk, r);
  *
- * and:
+ * and::
  *
  *   rate = clk_set_rate(clk, r);
  *
  * are equivalent except the former does not modify the clock hardware
  * in any way.
  *
- * @clk: A clock struct that was previously successfully requested by
- *       clk_request/get_by_*().
- * @rate: desired clock rate in Hz.
  * Return: rounded rate in Hz, or -ve error code.
  */
 ulong clk_round_rate(struct clk *clk, ulong rate);
 
 /**
  * clk_set_rate() - Set current clock rate.
- *
  * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
  * @rate:	New clock rate in Hz.
+ *
  * Return: new rate, or -ve error code.
  */
 ulong clk_set_rate(struct clk *clk, ulong rate);
 
 /**
  * clk_set_parent() - Set current clock parent.
- *
  * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
  * @parent:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
+ *
  * Return: new rate, or -ve error code.
  */
 int clk_set_parent(struct clk *clk, struct clk *parent);
 
 /**
  * clk_enable() - Enable (turn on) a clock.
- *
  * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
+ *
  * Return: zero on success, or -ve error code.
  */
 int clk_enable(struct clk *clk);
 
 /**
  * clk_enable_bulk() - Enable (turn on) all clocks in a clock bulk struct.
- *
  * @bulk:	A clock bulk struct that was previously successfully requested
  *		by clk_get_bulk().
+ *
  * Return: zero on success, or -ve error code.
  */
 int clk_enable_bulk(struct clk_bulk *bulk);
 
 /**
  * clk_disable() - Disable (turn off) a clock.
- *
  * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
+ *
  * Return: zero on success, or -ve error code.
  */
 int clk_disable(struct clk *clk);
 
 /**
  * clk_disable_bulk() - Disable (turn off) all clocks in a clock bulk struct.
- *
  * @bulk:	A clock bulk struct that was previously successfully requested
  *		by clk_get_bulk().
+ *
  * Return: zero on success, or -ve error code.
  */
 int clk_disable_bulk(struct clk_bulk *bulk);
@@ -497,28 +531,25 @@
  * @p: clk compared against q
  * @q: clk compared against p
  *
- * Returns true if the two struct clk pointers both point to the same hardware
- * clock node.
- *
- * Returns false otherwise. Note that two NULL clks are treated as matching.
+ * Return:
+ * %true if the two struct clk pointers both point to the same hardware clock
+ * node, and %false otherwise. Note that two %NULL clks are treated as matching.
  */
 bool clk_is_match(const struct clk *p, const struct clk *q);
 
 /**
  * clk_get_by_id() - Get the clock by its ID
- *
  * @id:	The clock ID to search for
- *
  * @clkp:	A pointer to clock struct that has been found among added clocks
  *              to UCLASS_CLK
+ *
  * Return: zero on success, or -ENOENT on error
  */
 int clk_get_by_id(ulong id, struct clk **clkp);
 
 /**
  * clk_dev_binded() - Check whether the clk has a device binded
- *
- * @clk		A pointer to the clk
+ * @clk:	A pointer to the clk
  *
  * Return: true on binded, or false on no
  */
@@ -604,8 +635,8 @@
 
 /**
  * clk_valid() - check if clk is valid
- *
  * @clk:	the clock to check
+ *
  * Return: true if valid, or false
  */
 static inline bool clk_valid(struct clk *clk)
diff --git a/include/configs/apple.h b/include/configs/apple.h
index f12e9bd..b06660a 100644
--- a/include/configs/apple.h
+++ b/include/configs/apple.h
@@ -9,10 +9,6 @@
 	"stdout=serial,vidconsole\0" \
 	"stderr=serial,vidconsole\0"
 
-#define ENV_MEM_LAYOUT_SETTINGS \
-	"fdt_addr_r=0x960100000\0" \
-	"kernel_addr_r=0x960200000\0"
-
 #if CONFIG_IS_ENABLED(CMD_NVME)
 	#define BOOT_TARGET_NVME(func) func(NVME, nvme, 0)
 #else
@@ -33,7 +29,6 @@
 
 #define CONFIG_EXTRA_ENV_SETTINGS \
 	ENV_DEVICE_SETTINGS \
-	ENV_MEM_LAYOUT_SETTINGS \
 	BOOTENV
 
 #endif
diff --git a/include/configs/lx2160a_common.h b/include/configs/lx2160a_common.h
index e31f8d0..4f4b571 100644
--- a/include/configs/lx2160a_common.h
+++ b/include/configs/lx2160a_common.h
@@ -244,12 +244,36 @@
 		"run distro_bootcmd;run sd2_bootcmd;"		\
 		"env exists secureboot && esbc_halt;"
 
+#ifdef CONFIG_CMD_USB
+#define BOOT_TARGET_DEVICES_USB(func) func(USB, usb, 0)
+#else
+#define BOOT_TARGET_DEVICES_USB(func)
+#endif
+
+#ifdef CONFIG_MMC
+#define BOOT_TARGET_DEVICES_MMC(func, instance) func(MMC, mmc, instance)
+#else
+#define BOOT_TARGET_DEVICES_MMC(func)
+#endif
+
+#ifdef CONFIG_SCSI
+#define BOOT_TARGET_DEVICES_SCSI(func) func(SCSI, scsi, 0)
+#else
+#define BOOT_TARGET_DEVICES_SCSI(func)
+#endif
+
+#ifdef CONFIG_CMD_DHCP
+#define BOOT_TARGET_DEVICES_DHCP(func) func(DHCP, dhcp, na)
+#else
+#define BOOT_TARGET_DEVICES_DHCP(func)
+#endif
+
 #define BOOT_TARGET_DEVICES(func) \
-	func(USB, usb, 0) \
-	func(MMC, mmc, 0) \
-	func(MMC, mmc, 1) \
-	func(SCSI, scsi, 0) \
-	func(DHCP, dhcp, na)
+	BOOT_TARGET_DEVICES_USB(func) \
+	BOOT_TARGET_DEVICES_MMC(func, 0) \
+	BOOT_TARGET_DEVICES_MMC(func, 1) \
+	BOOT_TARGET_DEVICES_SCSI(func) \
+	BOOT_TARGET_DEVICES_DHCP(func)
 #include <config_distro_bootcmd.h>
 
 #endif /* __LX2_COMMON_H */
diff --git a/include/configs/ti_armv7_common.h b/include/configs/ti_armv7_common.h
index 9733707..7483bc8 100644
--- a/include/configs/ti_armv7_common.h
+++ b/include/configs/ti_armv7_common.h
@@ -55,7 +55,7 @@
 		"do;" \
 		"setenv overlaystring ${overlaystring}'#'${overlay};" \
 		"done;\0" \
-	"run_fit=bootm ${addr_fit}#${fdtfile}${overlaystring}\0" \
+	"run_fit=bootm ${addr_fit}#conf-${fdtfile}${overlaystring}\0" \
 
 /*
  * DDR information.  If the CONFIG_NR_DRAM_BANKS is not defined,
diff --git a/include/sl28cpld.h b/include/sl28cpld.h
new file mode 100644
index 0000000..9a7c6de
--- /dev/null
+++ b/include/sl28cpld.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
+ */
+
+#ifndef __SL28CPLD_H
+#define __SL28CPLD_H
+
+#define SL28CPLD_VERSION	0x03
+
+int sl28cpld_read(struct udevice *dev, uint offset);
+int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value);
+int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear,
+		    uint8_t set);
+
+#endif
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index f4519c7..613b531 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -14,6 +14,7 @@
 #include <env.h>
 #include <fdtdec.h>
 #include <fs.h>
+#include <hang.h>
 #include <malloc.h>
 #include <mapmem.h>
 #include <sort.h>
@@ -1118,10 +1119,13 @@
 			index = 0;
 		ret = efi_capsule_read_file(files[i], &capsule);
 		if (ret == EFI_SUCCESS) {
-			ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0));
+			ret = efi_capsule_update_firmware(capsule);
 			if (ret != EFI_SUCCESS)
-				log_err("Applying capsule %ls failed\n",
+				log_err("Applying capsule %ls failed.\n",
 					files[i]);
+			else
+				log_info("Applying capsule %ls succeeded.\n",
+					 files[i]);
 
 			/* create CapsuleXXXX */
 			set_capsule_result(index, capsule, ret);
@@ -1142,6 +1146,16 @@
 		free(files[i]);
 	free(files);
 
-	return ret;
+	/*
+	 * UEFI spec requires to reset system after complete processing capsule
+	 * update on the storage.
+	 */
+	log_info("Reboot after firmware update");
+	/* Cold reset is required for loading the new firmware. */
+	do_reset(NULL, 0, 0, NULL);
+	hang();
+	/* not reach here */
+
+	return 0;
 }
 #endif /* CONFIG_EFI_CAPSULE_ON_DISK */
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index 1bd1fdc..79ed077 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -518,12 +518,11 @@
 			goto out;
 
 		EFI_PRINT("Verifying last certificate in chain\n");
-		if (signer->self_signed) {
-			if (efi_lookup_certificate(signer, db))
-				if (efi_signature_check_revocation(sinfo,
-								   signer, dbx))
-					break;
-		} else if (efi_verify_certificate(signer, db, &root)) {
+		if (efi_lookup_certificate(signer, db))
+			if (efi_signature_check_revocation(sinfo, signer, dbx))
+				break;
+		if (!signer->self_signed &&
+		    efi_verify_certificate(signer, db, &root)) {
 			bool check;
 
 			check = efi_signature_check_revocation(sinfo, root,
diff --git a/lib/efi_loader/efi_watchdog.c b/lib/efi_loader/efi_watchdog.c
index 87ca6c5..d741076 100644
--- a/lib/efi_loader/efi_watchdog.c
+++ b/lib/efi_loader/efi_watchdog.c
@@ -75,17 +75,6 @@
 		printf("ERROR: Failed to register watchdog event\n");
 		return r;
 	}
-	/*
-	 * The UEFI standard requires that the watchdog timer is set to five
-	 * minutes when invoking an EFI boot option.
-	 *
-	 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
-	 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
-	 */
-	r = efi_set_watchdog(300);
-	if (r != EFI_SUCCESS) {
-		printf("ERROR: Failed to set watchdog timer\n");
-		return r;
-	}
+
 	return EFI_SUCCESS;
 }
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
index 3e7b798..b2a2119 100644
--- a/lib/rsa/rsa-sign.c
+++ b/lib/rsa/rsa-sign.c
@@ -383,12 +383,11 @@
 		goto err_alloc;
 	}
 
-	context = EVP_MD_CTX_create();
+	context = EVP_MD_CTX_new();
 	if (!context) {
 		ret = rsa_err("EVP context creation failed");
 		goto err_create;
 	}
-	EVP_MD_CTX_init(context);
 
 	ckey = EVP_PKEY_CTX_new(pkey, NULL);
 	if (!ckey) {
@@ -425,8 +424,7 @@
 		goto err_sign;
 	}
 
-	EVP_MD_CTX_reset(context);
-	EVP_MD_CTX_destroy(context);
+	EVP_MD_CTX_free(context);
 
 	debug("Got signature: %zu bytes, expected %d\n", size, EVP_PKEY_size(pkey));
 	*sigp = sig;
@@ -435,7 +433,7 @@
 	return 0;
 
 err_sign:
-	EVP_MD_CTX_destroy(context);
+	EVP_MD_CTX_free(context);
 err_create:
 	free(sig);
 err_alloc:
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 93cb09a..c14da10 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -456,8 +456,8 @@
 # which is pure ASL code. The Intel ASL (ACPI (Advanced Configuration and Power
 # Interface) Source Language compiler (iasl) then converts this ASL code into a
 # C file containing the hex data to build into U-Boot. This file is called
-# dsdt.hex (despite us setting the prefix to .../dsdt.asl.tmp) so must be
-# renamed to dsdt.c for consumption by the build system.
+# dsdt_generated.hex (despite us setting the prefix to .../dsdt_generated.asl.tmp)
+# so must be renamed to dsdt_generated.c for consumption by the build system.
 ASL_TMP = $(patsubst %.c,%.asl.tmp,$@)
 
 quiet_cmd_acpi_c_asl= ASL     $<
@@ -468,9 +468,9 @@
 		$(if $(KBUILD_VERBOSE:1=), >/dev/null) && \
 	mv $(patsubst %.c,%.hex,$@) $@
 
-$(obj)/dsdt.c:    $(src)/dsdt.asl
+$(obj)/dsdt_generated.c:    $(src)/dsdt.asl
 	$(call cmd,acpi_c_asl)
-	$(Q)sed -i -e "s,dsdt_aml_code,AmlCode," $@
+	$(Q)sed -i -e "s,dsdt_generated_aml_code,AmlCode," $@
 
 # Bzip2
 # ---------------------------------------------------------------------------
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware.py b/test/py/tests/test_efi_capsule/test_capsule_firmware.py
index 6e803f6..1dcf1c7 100644
--- a/test/py/tests/test_efi_capsule/test_capsule_firmware.py
+++ b/test/py/tests/test_efi_capsule/test_capsule_firmware.py
@@ -143,13 +143,14 @@
                 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
             assert 'Test01' in ''.join(output)
 
-        # reboot
-        u_boot_console.restart_uboot()
-
         capsule_early = u_boot_config.buildconfig.get(
             'config_efi_capsule_on_disk_early')
         capsule_auth = u_boot_config.buildconfig.get(
             'config_efi_capsule_authenticate')
+
+        # reboot
+        u_boot_console.restart_uboot(expect_reset = capsule_early)
+
         with u_boot_console.log.section('Test Case 2-b, after reboot'):
             if not capsule_early:
                 # make sure that dfu_alt_info exists even persistent variables
@@ -162,7 +163,7 @@
 
                 # need to run uefi command to initiate capsule handling
                 output = u_boot_console.run_command(
-                    'env print -e Capsule0000')
+                    'env print -e Capsule0000', wait_for_reboot = True)
 
             output = u_boot_console.run_command_list([
                 'host bind 0 %s' % disk_img,
@@ -218,13 +219,14 @@
                 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
             assert 'Test02' in ''.join(output)
 
-        # reboot
-        u_boot_console.restart_uboot()
-
         capsule_early = u_boot_config.buildconfig.get(
             'config_efi_capsule_on_disk_early')
         capsule_auth = u_boot_config.buildconfig.get(
             'config_efi_capsule_authenticate')
+
+        # reboot
+        u_boot_console.restart_uboot(expect_reset = capsule_early)
+
         with u_boot_console.log.section('Test Case 3-b, after reboot'):
             if not capsule_early:
                 # make sure that dfu_alt_info exists even persistent variables
@@ -237,9 +239,12 @@
 
                 # need to run uefi command to initiate capsule handling
                 output = u_boot_console.run_command(
-                    'env print -e Capsule0000')
+                    'env print -e Capsule0000', wait_for_reboot = True)
 
-            output = u_boot_console.run_command_list(['efidebug capsule esrt'])
+            # make sure the dfu_alt_info exists because it is required for making ESRT.
+            output = u_boot_console.run_command_list([
+                'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
+                'efidebug capsule esrt'])
 
             # ensure that EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID is in the ESRT.
             assert 'AE13FF2D-9AD4-4E25-9AC8-6D80B3B22147' in ''.join(output)
@@ -293,13 +298,14 @@
                 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
             assert 'Test03' in ''.join(output)
 
-        # reboot
-        u_boot_console.restart_uboot()
-
         capsule_early = u_boot_config.buildconfig.get(
             'config_efi_capsule_on_disk_early')
         capsule_auth = u_boot_config.buildconfig.get(
             'config_efi_capsule_authenticate')
+
+        # reboot
+        u_boot_console.restart_uboot(expect_reset = capsule_early)
+
         with u_boot_console.log.section('Test Case 4-b, after reboot'):
             if not capsule_early:
                 # make sure that dfu_alt_info exists even persistent variables
@@ -312,9 +318,12 @@
 
                 # need to run uefi command to initiate capsule handling
                 output = u_boot_console.run_command(
-                    'env print -e Capsule0000')
+                    'env print -e Capsule0000', wait_for_reboot = True)
 
-            output = u_boot_console.run_command_list(['efidebug capsule esrt'])
+            # make sure the dfu_alt_info exists because it is required for making ESRT.
+            output = u_boot_console.run_command_list([
+                'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
+                'efidebug capsule esrt'])
 
             # ensure that  EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID is in the ESRT.
             assert 'E2BB9C06-70E9-4B14-97A3-5A7913176E3F' in ''.join(output)
diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py
index 384fd53..3938ec1 100644
--- a/test/py/u_boot_console_base.py
+++ b/test/py/u_boot_console_base.py
@@ -139,8 +139,55 @@
             self.p.close()
         self.logstream.close()
 
+    def wait_for_boot_prompt(self, loop_num = 1):
+        """Wait for the boot up until command prompt. This is for internal use only.
+        """
+        try:
+            bcfg = self.config.buildconfig
+            config_spl = bcfg.get('config_spl', 'n') == 'y'
+            config_spl_serial = bcfg.get('config_spl_serial', 'n') == 'y'
+            env_spl_skipped = self.config.env.get('env__spl_skipped', False)
+            env_spl2_skipped = self.config.env.get('env__spl2_skipped', True)
+
+            while loop_num > 0:
+                loop_num -= 1
+                if config_spl and config_spl_serial and not env_spl_skipped:
+                    m = self.p.expect([pattern_u_boot_spl_signon] +
+                                      self.bad_patterns)
+                    if m != 0:
+                        raise Exception('Bad pattern found on SPL console: ' +
+                                        self.bad_pattern_ids[m - 1])
+                if not env_spl2_skipped:
+                    m = self.p.expect([pattern_u_boot_spl2_signon] +
+                                      self.bad_patterns)
+                    if m != 0:
+                        raise Exception('Bad pattern found on SPL2 console: ' +
+                                        self.bad_pattern_ids[m - 1])
+                m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns)
+                if m != 0:
+                    raise Exception('Bad pattern found on console: ' +
+                                    self.bad_pattern_ids[m - 1])
+            self.u_boot_version_string = self.p.after
+            while True:
+                m = self.p.expect([self.prompt_compiled,
+                    pattern_stop_autoboot_prompt] + self.bad_patterns)
+                if m == 0:
+                    break
+                if m == 1:
+                    self.p.send(' ')
+                    continue
+                raise Exception('Bad pattern found on console: ' +
+                                self.bad_pattern_ids[m - 2])
+
+        except Exception as ex:
+            self.log.error(str(ex))
+            self.cleanup_spawn()
+            raise
+        finally:
+            self.log.timestamp()
+
     def run_command(self, cmd, wait_for_echo=True, send_nl=True,
-            wait_for_prompt=True):
+            wait_for_prompt=True, wait_for_reboot=False):
         """Execute a command via the U-Boot console.
 
         The command is always sent to U-Boot.
@@ -168,6 +215,9 @@
             wait_for_prompt: Boolean indicating whether to wait for the
                 command prompt to be sent by U-Boot. This typically occurs
                 immediately after the command has been executed.
+            wait_for_reboot: Boolean indication whether to wait for the
+                reboot U-Boot. If this sets True, wait_for_prompt must also
+                be True.
 
         Returns:
             If wait_for_prompt == False:
@@ -202,11 +252,14 @@
                                     self.bad_pattern_ids[m - 1])
             if not wait_for_prompt:
                 return
-            m = self.p.expect([self.prompt_compiled] + self.bad_patterns)
-            if m != 0:
-                self.at_prompt = False
-                raise Exception('Bad pattern found on console: ' +
-                                self.bad_pattern_ids[m - 1])
+            if wait_for_reboot:
+                self.wait_for_boot_prompt()
+            else:
+                m = self.p.expect([self.prompt_compiled] + self.bad_patterns)
+                if m != 0:
+                    self.at_prompt = False
+                    raise Exception('Bad pattern found on console: ' +
+                                    self.bad_pattern_ids[m - 1])
             self.at_prompt = True
             self.at_prompt_logevt = self.logstream.logfile.cur_evt
             # Only strip \r\n; space/TAB might be significant if testing
@@ -321,7 +374,7 @@
         finally:
             self.p.timeout = orig_timeout
 
-    def ensure_spawned(self):
+    def ensure_spawned(self, expect_reset=False):
         """Ensure a connection to a correctly running U-Boot instance.
 
         This may require spawning a new Sandbox process or resetting target
@@ -330,7 +383,9 @@
         This is an internal function and should not be called directly.
 
         Args:
-            None.
+            expect_reset: Boolean indication whether this boot is expected
+                to be reset while the 1st boot process after main boot before
+                prompt. False by default.
 
         Returns:
             Nothing.
@@ -349,41 +404,11 @@
             if not self.config.gdbserver:
                 self.p.timeout = 30000
             self.p.logfile_read = self.logstream
-            bcfg = self.config.buildconfig
-            config_spl = bcfg.get('config_spl', 'n') == 'y'
-            config_spl_serial = bcfg.get('config_spl_serial',
-                                                 'n') == 'y'
-            env_spl_skipped = self.config.env.get('env__spl_skipped',
-                                                  False)
-            env_spl2_skipped = self.config.env.get('env__spl2_skipped',
-                                                  True)
-            if config_spl and config_spl_serial and not env_spl_skipped:
-                m = self.p.expect([pattern_u_boot_spl_signon] +
-                                  self.bad_patterns)
-                if m != 0:
-                    raise Exception('Bad pattern found on SPL console: ' +
-                                    self.bad_pattern_ids[m - 1])
-            if not env_spl2_skipped:
-                m = self.p.expect([pattern_u_boot_spl2_signon] +
-                                  self.bad_patterns)
-                if m != 0:
-                    raise Exception('Bad pattern found on SPL2 console: ' +
-                                    self.bad_pattern_ids[m - 1])
-            m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns)
-            if m != 0:
-                raise Exception('Bad pattern found on console: ' +
-                                self.bad_pattern_ids[m - 1])
-            self.u_boot_version_string = self.p.after
-            while True:
-                m = self.p.expect([self.prompt_compiled,
-                    pattern_stop_autoboot_prompt] + self.bad_patterns)
-                if m == 0:
-                    break
-                if m == 1:
-                    self.p.send(' ')
-                    continue
-                raise Exception('Bad pattern found on console: ' +
-                                self.bad_pattern_ids[m - 2])
+            if expect_reset:
+                loop_num = 2
+            else:
+                loop_num = 1
+            self.wait_for_boot_prompt(loop_num = loop_num)
             self.at_prompt = True
             self.at_prompt_logevt = self.logstream.logfile.cur_evt
         except Exception as ex:
@@ -416,10 +441,10 @@
             pass
         self.p = None
 
-    def restart_uboot(self):
+    def restart_uboot(self, expect_reset=False):
         """Shut down and restart U-Boot."""
         self.cleanup_spawn()
-        self.ensure_spawned()
+        self.ensure_spawned(expect_reset)
 
     def get_spawn_output(self):
         """Return the start-up output from U-Boot
diff --git a/test/py/u_boot_console_sandbox.py b/test/py/u_boot_console_sandbox.py
index 7e1eb0e..ce4ca7e 100644
--- a/test/py/u_boot_console_sandbox.py
+++ b/test/py/u_boot_console_sandbox.py
@@ -57,11 +57,14 @@
         cmd += self.sandbox_flags
         return Spawn(cmd, cwd=self.config.source_dir)
 
-    def restart_uboot_with_flags(self, flags):
+    def restart_uboot_with_flags(self, flags, expect_reset=False):
         """Run U-Boot with the given command-line flags
 
         Args:
             flags: List of flags to pass, each a string
+            expect_reset: Boolean indication whether this boot is expected
+                to be reset while the 1st boot process after main boot before
+                prompt. False by default.
 
         Returns:
             A u_boot_spawn.Spawn object that is attached to U-Boot.
@@ -69,7 +72,7 @@
 
         try:
             self.sandbox_flags = flags
-            return self.restart_uboot()
+            return self.restart_uboot(expect_reset)
         finally:
             self.sandbox_flags = []
 
diff --git a/tools/Makefile b/tools/Makefile
index 5409ff2..60231c7 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -196,6 +196,9 @@
 hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
 HOSTCFLAGS_mkexynosspl.o := -pedantic
 
+HOSTCFLAGS_kwboot.o += -pthread
+HOSTLDLIBS_kwboot += -pthread -ltinfo
+
 ifdtool-objs := $(LIBFDT_OBJS) ifdtool.o
 hostprogs-$(CONFIG_X86) += ifdtool
 
diff --git a/tools/dumpimage.c b/tools/dumpimage.c
index e548143..4791dd0 100644
--- a/tools/dumpimage.c
+++ b/tools/dumpimage.c
@@ -12,9 +12,7 @@
 static void usage(void);
 
 /* parameters initialized by core will be used by the image type code */
-static struct image_tool_params params = {
-	.type = IH_TYPE_KERNEL,
-};
+static struct image_tool_params params;
 
 /*
  * dumpimage_extract_subimage -
@@ -110,7 +108,7 @@
 		}
 	}
 
-	if (argc < 2)
+	if (argc < 2 || (params.iflag && params.lflag))
 		usage();
 
 	if (optind >= argc) {
@@ -122,7 +120,7 @@
 
 	/* set tparams as per input type_id */
 	tparams = imagetool_get_type(params.type);
-	if (tparams == NULL) {
+	if (!params.lflag && tparams == NULL) {
 		fprintf(stderr, "%s: unsupported type: %s\n",
 			params.cmdname, genimg_get_type_name(params.type));
 		exit(EXIT_FAILURE);
@@ -132,7 +130,7 @@
 	 * check the passed arguments parameters meets the requirements
 	 * as per image type to be generated/listed
 	 */
-	if (tparams->check_params) {
+	if (tparams && tparams->check_params) {
 		if (tparams->check_params(&params)) {
 			fprintf(stderr, "%s: Parameter check failed\n",
 				params.cmdname);
@@ -159,7 +157,7 @@
 		exit(EXIT_FAILURE);
 	}
 
-	if ((uint32_t)sbuf.st_size < tparams->header_size) {
+	if (tparams && (uint32_t)sbuf.st_size < tparams->header_size) {
 		fprintf(stderr, "%s: Bad size: \"%s\" is not valid image\n",
 			params.cmdname, params.imagefile);
 		exit(EXIT_FAILURE);
@@ -203,8 +201,9 @@
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: %s -l image\n"
-		"          -l ==> list image header information\n",
+	fprintf(stderr, "Usage: %s [-T type] -l image\n"
+		"          -l ==> list image header information\n"
+		"          -T ==> parse image file as 'type'\n",
 		params.cmdname);
 	fprintf(stderr,
 		"       %s [-T type] [-p position] [-o outfile] image\n"
diff --git a/tools/imagetool.c b/tools/imagetool.c
index ba1f64a..5ad6d74 100644
--- a/tools/imagetool.c
+++ b/tools/imagetool.c
@@ -26,6 +26,12 @@
 	return NULL;
 }
 
+static int imagetool_verify_print_header_by_type(
+	void *ptr,
+	struct stat *sbuf,
+	struct image_type_params *tparams,
+	struct image_tool_params *params);
+
 int imagetool_verify_print_header(
 	void *ptr,
 	struct stat *sbuf,
@@ -39,6 +45,9 @@
 	struct image_type_params **start = __start_image_type;
 	struct image_type_params **end = __stop_image_type;
 
+	if (tparams)
+		return imagetool_verify_print_header_by_type(ptr, sbuf, tparams, params);
+
 	for (curr = start; curr != end; curr++) {
 		if ((*curr)->verify_header) {
 			retval = (*curr)->verify_header((unsigned char *)ptr,
@@ -65,7 +74,7 @@
 	return retval;
 }
 
-int imagetool_verify_print_header_by_type(
+static int imagetool_verify_print_header_by_type(
 	void *ptr,
 	struct stat *sbuf,
 	struct image_type_params *tparams,
diff --git a/tools/imagetool.h b/tools/imagetool.h
index c3f80fc..5169b02 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -178,33 +178,19 @@
 /*
  * imagetool_verify_print_header() - verifies the image header
  *
- * Scan registered image types and verify the image_header for each
- * supported image type. If verification is successful, this prints
- * the respective header.
- *
- * Return: 0 on success, negative if input image format does not match with
- * any of supported image types
- */
-int imagetool_verify_print_header(
-	void *ptr,
-	struct stat *sbuf,
-	struct image_type_params *tparams,
-	struct image_tool_params *params);
-
-/*
- * imagetool_verify_print_header_by_type() - verifies the image header
- *
  * Verify the image_header for the image type given by tparams.
+ * If tparams is NULL then scan registered image types and verify the
+ * image_header for each supported image type.
  * If verification is successful, this prints the respective header.
  * @ptr: pointer the the image header
  * @sbuf: stat information about the file pointed to by ptr
- * @tparams: image type parameters
+ * @tparams: image type parameters or NULL
  * @params: mkimage parameters
  *
  * Return: 0 on success, negative if input image format does not match with
  * the given image type
  */
-int imagetool_verify_print_header_by_type(
+int imagetool_verify_print_header(
 	void *ptr,
 	struct stat *sbuf,
 	struct image_type_params *tparams,
diff --git a/tools/kwboot.c b/tools/kwboot.c
index 68c0ef1..69d1be0 100644
--- a/tools/kwboot.c
+++ b/tools/kwboot.c
@@ -1,15 +1,40 @@
 /*
  * Boot a Marvell SoC, with Xmodem over UART0.
- *  supports Kirkwood, Dove, Armada 370, Armada XP, Armada 375, Armada 38x and
- *           Armada 39x
+ *  supports Kirkwood, Dove, Avanta, Armada 370, Armada XP, Armada 375,
+ *           Armada 38x and Armada 39x.
  *
  * (c) 2012 Daniel Stodden <daniel.stodden@gmail.com>
  * (c) 2021 Pali Rohár <pali@kernel.org>
  * (c) 2021 Marek Behún <marek.behun@nic.cz>
  *
- * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281
- *   Integrated Controller: Functional Specifications" December 2,
- *   2008. Chapter 24.2 "BootROM Firmware".
+ * References:
+ * - "88F6180, 88F6190, 88F6192, and 88F6281: Integrated Controller: Functional
+ *   Specifications" December 2, 2008. Chapter 24.2 "BootROM Firmware".
+ *   https://web.archive.org/web/20130730091033/https://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+ * - "88AP510: High-Performance SoC with Integrated CPU, 2D/3D Graphics
+ *   Processor, and High-Definition Video Decoder: Functional Specifications"
+ *   August 3, 2011. Chapter 5 "BootROM Firmware"
+ *   https://web.archive.org/web/20120130172443/https://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf
+ * - "88F6710, 88F6707, and 88F6W11: ARMADA(R) 370 SoC: Functional Specifications"
+ *   May 26, 2014. Chapter 6 "BootROM Firmware".
+ *   https://web.archive.org/web/20140617183701/https://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-FunctionalSpec-datasheet.pdf
+ * - "MV78230, MV78260, and MV78460: ARMADA(R) XP Family of Highly Integrated
+ *   Multi-Core ARMv7 Based SoC Processors: Functional Specifications"
+ *   May 29, 2014. Chapter 6 "BootROM Firmware".
+ *   https://web.archive.org/web/20180829171131/https://www.marvell.com/embedded-processors/armada-xp/assets/ARMADA-XP-Functional-SpecDatasheet.pdf
+ * - "ARMADA(R) 375 Value-Performance Dual Core CPU System on Chip: Functional
+ *   Specifications" Doc. No. MV-S109377-00, Rev. A. September 18, 2013.
+ *   Chapter 7 "Boot Sequence"
+ *   CONFIDENTIAL, no public documentation available
+ * - "88F6810, 88F6811, 88F6821, 88F6W21, 88F6820, and 88F6828: ARMADA(R) 38x
+ *   Family High-Performance Single/Dual CPU System on Chip: Functional
+ *   Specifications" Doc. No. MV-S109094-00, Rev. C. August 2, 2015.
+ *   Chapter 7 "Boot Flow"
+ *   CONFIDENTIAL, no public documentation available
+ * - "88F6920, 88F6925 and 88F6928: ARMADA(R) 39x High-Performance Dual Core CPU
+ *   System on Chip Functional Specifications" Doc. No. MV-S109896-00, Rev. B.
+ *   December 22, 2015. Chapter 7 "Boot Flow"
+ *   CONFIDENTIAL, no public documentation available
  */
 
 #include "kwbimage.h"
@@ -28,6 +53,7 @@
 #include <stdint.h>
 #include <time.h>
 #include <sys/stat.h>
+#include <pthread.h>
 
 #ifdef __linux__
 #include "termios_linux.h"
@@ -36,6 +62,13 @@
 #endif
 
 /*
+ * These functions are in <term.h> header file, but this header file conflicts
+ * with "termios_linux.h" header file. So declare these functions manually.
+ */
+extern int setupterm(const char *, int, int *);
+extern char *tigetstr(const char *);
+
+/*
  * Marvell BootROM UART Sensing
  */
 
@@ -48,11 +81,9 @@
 };
 
 /* Defines known to work on Kirkwood */
-#define KWBOOT_MSG_REQ_DELAY	10 /* ms */
 #define KWBOOT_MSG_RSP_TIMEO	50 /* ms */
 
 /* Defines known to work on Armada XP */
-#define KWBOOT_MSG_REQ_DELAY_AXP	1000 /* ms */
 #define KWBOOT_MSG_RSP_TIMEO_AXP	1000 /* ms */
 
 /*
@@ -285,7 +316,6 @@
 
 static int kwboot_verbose;
 
-static int msg_req_delay = KWBOOT_MSG_REQ_DELAY;
 static int msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO;
 static int blk_rsp_timeo = KWBOOT_BLK_RSP_TIMEO;
 
@@ -720,42 +750,120 @@
 	return rc;
 }
 
-static int
-kwboot_bootmsg(int tty, void *msg)
+static void *
+kwboot_msg_write_handler(void *arg)
 {
-	struct kwboot_block block;
-	int rc;
-	char c;
-	int count;
+	int tty = *(int *)((void **)arg)[0];
+	const void *msg = ((void **)arg)[1];
+	int rsp_timeo = msg_rsp_timeo;
+	int i, dummy_oldtype;
 
-	if (msg == NULL)
-		kwboot_printv("Please reboot the target into UART boot mode...");
-	else
-		kwboot_printv("Sending boot message. Please reboot the target...");
+	/* allow to cancel this thread at any time */
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy_oldtype);
 
-	do {
-		rc = tcflush(tty, TCIOFLUSH);
-		if (rc)
-			break;
-
-		for (count = 0; count < 128; count++) {
-			rc = kwboot_tty_send(tty, msg, 8, 0);
-			if (rc) {
-				usleep(msg_req_delay * 1000);
-				continue;
+	while (1) {
+		/* write 128 samples of message pattern into the output queue without waiting */
+		for (i = 0; i < 128; i++) {
+			if (kwboot_tty_send(tty, msg, 8, 1) < 0) {
+				perror("\nFailed to send message pattern");
+				exit(1);
 			}
 		}
+		/* wait until output queue is transmitted and then make pause */
+		if (tcdrain(tty) < 0) {
+			perror("\nFailed to send message pattern");
+			exit(1);
+		}
+		/* BootROM requires pause on UART after it detects message pattern */
+		usleep(rsp_timeo * 1000);
+	}
+}
 
-		rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
+static int
+kwboot_msg_start_thread(pthread_t *thread, int *tty, void *msg)
+{
+	void *arg[2];
+	int rc;
 
+	arg[0] = tty;
+	arg[1] = msg;
+	rc = pthread_create(thread, NULL, kwboot_msg_write_handler, arg);
+	if (rc) {
+		errno = rc;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+kwboot_msg_stop_thread(pthread_t thread)
+{
+	int rc;
+
+	rc = pthread_cancel(thread);
+	if (rc) {
+		errno = rc;
+		return -1;
+	}
+
+	rc = pthread_join(thread, NULL);
+	if (rc) {
+		errno = rc;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+kwboot_bootmsg(int tty)
+{
+	struct kwboot_block block;
+	pthread_t write_thread;
+	int rc, err;
+	char c;
+
+	/* flush input and output queue */
+	tcflush(tty, TCIOFLUSH);
+
+	rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_boot);
+	if (rc) {
+		perror("Failed to start write thread");
+		return rc;
+	}
+
+	kwboot_printv("Sending boot message. Please reboot the target...");
+
+	err = 0;
+	while (1) {
 		kwboot_spinner();
 
-	} while (rc || c != NAK);
+		rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
+		if (rc && errno == ETIMEDOUT) {
+			continue;
+		} else if (rc) {
+			err = errno;
+			break;
+		}
+
+		if (c == NAK)
+			break;
+	}
 
 	kwboot_printv("\n");
 
-	if (rc)
+	rc = kwboot_msg_stop_thread(write_thread);
+	if (rc) {
+		perror("Failed to stop write thread");
 		return rc;
+	}
+
+	if (err) {
+		errno = err;
+		perror("Failed to read response for boot message pattern");
+		return -1;
+	}
 
 	/*
 	 * At this stage we have sent more boot message patterns and BootROM
@@ -772,11 +880,19 @@
 	 */
 
 	/* flush output queue with remaining boot message patterns */
-	tcflush(tty, TCOFLUSH);
+	rc = tcflush(tty, TCOFLUSH);
+	if (rc) {
+		perror("Failed to flush output queue");
+		return rc;
+	}
 
 	/* send one xmodem packet with 0xff bytes to force BootROM to re-sync */
 	memset(&block, 0xff, sizeof(block));
-	kwboot_tty_send(tty, &block, sizeof(block), 0);
+	rc = kwboot_tty_send(tty, &block, sizeof(block), 0);
+	if (rc) {
+		perror("Failed to send sync sequence");
+		return rc;
+	}
 
 	/*
 	 * Sending 132 bytes via 115200B/8-N-1 takes 11.45 ms, reading 132 bytes
@@ -785,40 +901,151 @@
 	usleep(30 * 1000);
 
 	/* flush remaining NAK replies from input queue */
-	tcflush(tty, TCIFLUSH);
+	rc = tcflush(tty, TCIFLUSH);
+	if (rc) {
+		perror("Failed to flush input queue");
+		return rc;
+	}
 
 	return 0;
 }
 
 static int
-kwboot_debugmsg(int tty, void *msg)
+kwboot_debugmsg(int tty)
 {
-	int rc;
+	unsigned char buf[8192];
+	pthread_t write_thread;
+	int rc, err, i, pos;
+	size_t off;
+
+	/* flush input and output queue */
+	tcflush(tty, TCIOFLUSH);
+
+	rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_debug);
+	if (rc) {
+		perror("Failed to start write thread");
+		return rc;
+	}
 
 	kwboot_printv("Sending debug message. Please reboot the target...");
+	kwboot_spinner();
 
-	do {
-		char buf[16];
-
-		rc = tcflush(tty, TCIOFLUSH);
-		if (rc)
-			break;
-
-		rc = kwboot_tty_send(tty, msg, 8, 0);
-		if (rc) {
-			usleep(msg_req_delay * 1000);
+	err = 0;
+	off = 0;
+	while (1) {
+		/* Read immediately all bytes in queue without waiting */
+		rc = read(tty, buf + off, sizeof(buf) - off);
+		if ((rc < 0 && errno == EINTR) || rc == 0) {
 			continue;
+		} else if (rc < 0) {
+			err = errno;
+			break;
 		}
-
-		rc = kwboot_tty_recv(tty, buf, 16, msg_rsp_timeo);
+		off += rc - 1;
 
 		kwboot_spinner();
 
-	} while (rc);
+		/*
+		 * Check if we received at least 4 debug message patterns
+		 * (console echo from BootROM) in cyclic buffer
+		 */
+
+		for (pos = 0; pos < sizeof(kwboot_msg_debug); pos++)
+			if (buf[off] == kwboot_msg_debug[(pos + off) % sizeof(kwboot_msg_debug)])
+				break;
+
+		for (i = off; i >= 0; i--)
+			if (buf[i] != kwboot_msg_debug[(pos + i) % sizeof(kwboot_msg_debug)])
+				break;
+
+		off -= i;
+
+		if (off >= 4 * sizeof(kwboot_msg_debug))
+			break;
+
+		/* If not move valid suffix from end of the buffer to the beginning of buffer */
+		memmove(buf, buf + i + 1, off);
+	}
 
 	kwboot_printv("\n");
 
-	return rc;
+	rc = kwboot_msg_stop_thread(write_thread);
+	if (rc) {
+		perror("Failed to stop write thread");
+		return rc;
+	}
+
+	if (err) {
+		errno = err;
+		perror("Failed to read response for debug message pattern");
+		return -1;
+	}
+
+	/* flush output queue with remaining debug message patterns */
+	rc = tcflush(tty, TCOFLUSH);
+	if (rc) {
+		perror("Failed to flush output queue");
+		return rc;
+	}
+
+	kwboot_printv("Clearing input buffer...\n");
+
+	/*
+	 * Wait until BootROM transmit all remaining echo characters.
+	 * Experimentally it was measured that for Armada 385 BootROM
+	 * it is required to wait at least 0.415s. So wait 0.5s.
+	 */
+	usleep(500 * 1000);
+
+	/*
+	 * In off variable is stored number of characters received after the
+	 * successful detection of echo reply. So these characters are console
+	 * echo for other following debug message patterns. BootROM may have in
+	 * its output queue other echo characters which were being transmitting
+	 * before above sleep call. So read remaining number of echo characters
+	 * sent by the BootROM now.
+	 */
+	while ((rc = kwboot_tty_recv(tty, &buf[0], 1, 0)) == 0)
+		off++;
+	if (errno != ETIMEDOUT) {
+		perror("Failed to read response");
+		return rc;
+	}
+
+	/*
+	 * Clear every echo character set by the BootROM by backspace byte.
+	 * This is required prior writing any command to the BootROM debug
+	 * because BootROM command line buffer has limited size. If length
+	 * of the command is larger than buffer size then it looks like
+	 * that Armada 385 BootROM crashes after sending ENTER. So erase it.
+	 * Experimentally it was measured that for Armada 385 BootROM it is
+	 * required to send at least 3 backspace bytes for one echo character.
+	 * This is unknown why. But lets do it.
+	 */
+	off *= 3;
+	memset(buf, '\x08', sizeof(buf));
+	while (off > sizeof(buf)) {
+		rc = kwboot_tty_send(tty, buf, sizeof(buf), 1);
+		if (rc) {
+			perror("Failed to send clear sequence");
+			return rc;
+		}
+		off -= sizeof(buf);
+	}
+	rc = kwboot_tty_send(tty, buf, off, 0);
+	if (rc) {
+		perror("Failed to send clear sequence");
+		return rc;
+	}
+
+	usleep(msg_rsp_timeo * 1000);
+	rc = tcflush(tty, TCIFLUSH);
+	if (rc) {
+		perror("Failed to flush input queue");
+		return rc;
+	}
+
+	return 0;
 }
 
 static size_t
@@ -1181,37 +1408,84 @@
 }
 
 static int
-kwboot_term_pipe(int in, int out, const char *quit, int *s)
+kwboot_term_pipe(int in, int out, const char *quit, int *s, const char *kbs, int *k)
 {
 	char buf[128];
-	ssize_t nin;
+	ssize_t nin, noff;
 
 	nin = read(in, buf, sizeof(buf));
 	if (nin <= 0)
 		return -1;
 
-	if (quit) {
+	noff = 0;
+
+	if (quit || kbs) {
 		int i;
 
 		for (i = 0; i < nin; i++) {
-			if (buf[i] == quit[*s]) {
+			if ((quit || kbs) &&
+			    (!quit || buf[i] != quit[*s]) &&
+			    (!kbs || buf[i] != kbs[*k])) {
+				const char *prefix;
+				int plen;
+
+				if (quit && kbs) {
+					prefix = (*s >= *k) ? quit : kbs;
+					plen = (*s >= *k) ? *s : *k;
+				} else if (quit) {
+					prefix = quit;
+					plen = *s;
+				} else {
+					prefix = kbs;
+					plen = *k;
+				}
+
+				if (plen > i && kwboot_write(out, prefix, plen - i) < 0)
+					return -1;
+			}
+
+			if (quit && buf[i] == quit[*s]) {
 				(*s)++;
 				if (!quit[*s]) {
-					nin = i - *s;
+					nin = (i > *s) ? (i - *s) : 0;
 					break;
 				}
-			} else {
-				if (*s > i && kwboot_write(out, quit, *s - i) < 0)
-					return -1;
+			} else if (quit) {
 				*s = 0;
 			}
+
+			if (kbs && buf[i] == kbs[*k]) {
+				(*k)++;
+				if (!kbs[*k]) {
+					if (i > *k + noff &&
+					    kwboot_write(out, buf + noff, i - *k - noff) < 0)
+						return -1;
+					/*
+					 * Replace backspace key by '\b' (0x08)
+					 * byte which is the only recognized
+					 * backspace byte by Marvell BootROM.
+					 */
+					if (write(out, "\x08", 1) < 0)
+						return -1;
+					noff = i + 1;
+					*k = 0;
+				}
+			} else if (kbs) {
+				*k = 0;
+			}
 		}
 
-		if (i == nin)
-			nin -= *s;
+		if (i == nin) {
+			i = 0;
+			if (quit && i < *s)
+				i = *s;
+			if (kbs && i < *k)
+				i = *k;
+			nin -= (nin > i) ? i : nin;
+		}
 	}
 
-	if (kwboot_write(out, buf, nin) < 0)
+	if (nin > noff && kwboot_write(out, buf + noff, nin - noff) < 0)
 		return -1;
 
 	return 0;
@@ -1220,7 +1494,8 @@
 static int
 kwboot_terminal(int tty)
 {
-	int rc, in, s;
+	int rc, in, s, k;
+	const char *kbs = NULL;
 	const char *quit = "\34c";
 	struct termios otio, tio;
 
@@ -1239,6 +1514,33 @@
 			goto out;
 		}
 
+		/*
+		 * Get sequence for backspace key used by the current
+		 * terminal. Every occurrence of this sequence will be
+		 * replaced by '\b' byte which is the only recognized
+		 * backspace byte by Marvell BootROM.
+		 *
+		 * Note that we cannot read this sequence from termios
+		 * c_cc[VERASE] as VERASE is valid only when ICANON is
+		 * set in termios c_lflag, which is not case for us.
+		 *
+		 * Also most terminals do not set termios c_cc[VERASE]
+		 * as c_cc[VERASE] can specify only one-byte sequence
+		 * and instead let applications to read (possible
+		 * multi-byte) sequence for backspace key from "kbs"
+		 * terminfo database based on $TERM env variable.
+		 *
+		 * So read "kbs" from terminfo database via tigetstr()
+		 * call after successful setupterm(). Most terminals
+		 * use byte 0x7F for backspace key, so replacement with
+		 * '\b' is required.
+		 */
+		if (setupterm(NULL, STDOUT_FILENO, &rc) == 0) {
+			kbs = tigetstr("kbs");
+			if (kbs == (char *)-1)
+				kbs = NULL;
+		}
+
 		kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
 			      quit[0] | 0100, quit[1]);
 	} else
@@ -1246,6 +1548,7 @@
 
 	rc = 0;
 	s = 0;
+	k = 0;
 
 	do {
 		fd_set rfds;
@@ -1265,13 +1568,13 @@
 			break;
 
 		if (FD_ISSET(tty, &rfds)) {
-			rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL);
+			rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL, NULL, NULL);
 			if (rc)
 				break;
 		}
 
 		if (in >= 0 && FD_ISSET(in, &rfds)) {
-			rc = kwboot_term_pipe(in, tty, quit, &s);
+			rc = kwboot_term_pipe(in, tty, quit, &s, kbs, &k);
 			if (rc)
 				break;
 		}
@@ -1708,16 +2011,16 @@
 kwboot_usage(FILE *stream, char *progname)
 {
 	fprintf(stream,
-		"Usage: %s [OPTIONS] [-b <image> | -D <image> ] [-B <baud> ] <TTY>\n",
+		"Usage: %s [OPTIONS] [-b <image> | -D <image> | -b | -d ] [-B <baud> ] [-t] <TTY>\n",
 		progname);
 	fprintf(stream, "\n");
 	fprintf(stream,
-		"  -b <image>: boot <image> with preamble (Kirkwood, Armada 370/XP)\n");
+		"  -b <image>: boot <image> with preamble (Kirkwood, Avanta, Armada 370/XP/375/38x/39x)\n");
 	fprintf(stream,
 		"  -D <image>: boot <image> without preamble (Dove)\n");
-	fprintf(stream, "  -d: enter debug mode\n");
+	fprintf(stream, "  -b: enter xmodem boot mode\n");
+	fprintf(stream, "  -d: enter console debug mode\n");
 	fprintf(stream, "  -a: use timings for Armada XP\n");
-	fprintf(stream, "  -q <req-delay>:  use specific request-delay\n");
 	fprintf(stream, "  -s <resp-timeo>: use specific response-timeout\n");
 	fprintf(stream,
 		"  -o <block-timeo>: use specific xmodem block timeout\n");
@@ -1733,8 +2036,8 @@
 {
 	const char *ttypath, *imgpath;
 	int rv, rc, tty, term;
-	void *bootmsg;
-	void *debugmsg;
+	int bootmsg;
+	int debugmsg;
 	void *img;
 	size_t size;
 	size_t after_img_rsv;
@@ -1744,8 +2047,8 @@
 
 	rv = 1;
 	tty = -1;
-	bootmsg = NULL;
-	debugmsg = NULL;
+	bootmsg = 0;
+	debugmsg = 0;
 	imgpath = NULL;
 	img = NULL;
 	term = 0;
@@ -1767,7 +2070,7 @@
 		case 'b':
 			if (imgpath || bootmsg || debugmsg)
 				goto usage;
-			bootmsg = kwboot_msg_boot;
+			bootmsg = 1;
 			if (prev_optind == optind)
 				goto usage;
 			if (optind < argc - 1 && argv[optind] && argv[optind][0] != '-')
@@ -1777,14 +2080,14 @@
 		case 'D':
 			if (imgpath || bootmsg || debugmsg)
 				goto usage;
-			bootmsg = NULL;
+			bootmsg = 0;
 			imgpath = optarg;
 			break;
 
 		case 'd':
 			if (imgpath || bootmsg || debugmsg)
 				goto usage;
-			debugmsg = kwboot_msg_debug;
+			debugmsg = 1;
 			break;
 
 		case 'p':
@@ -1796,12 +2099,11 @@
 			break;
 
 		case 'a':
-			msg_req_delay = KWBOOT_MSG_REQ_DELAY_AXP;
 			msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO_AXP;
 			break;
 
 		case 'q':
-			msg_req_delay = atoi(optarg);
+			/* nop, for backward compatibility */
 			break;
 
 		case 's':
@@ -1866,17 +2168,13 @@
 	}
 
 	if (debugmsg) {
-		rc = kwboot_debugmsg(tty, debugmsg);
-		if (rc) {
-			perror("debugmsg");
+		rc = kwboot_debugmsg(tty);
+		if (rc)
 			goto out;
-		}
 	} else if (bootmsg) {
-		rc = kwboot_bootmsg(tty, bootmsg);
-		if (rc) {
-			perror("bootmsg");
+		rc = kwboot_bootmsg(tty);
+		if (rc)
 			goto out;
-		}
 	}
 
 	if (img) {
diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
index f7590e4..c118335 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -212,8 +212,6 @@
 	ret = read_bin_file(ctx->key_file, &key.data, &file_size);
 	if (ret < 0)
 		return -1;
-	if (ret < 0)
-		return -1;
 	if (file_size > UINT_MAX)
 		return -1;
 	key.size = file_size;
diff --git a/tools/mkimage.c b/tools/mkimage.c
index c8f4ecd..74bd072 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -82,8 +82,9 @@
 static void usage(const char *msg)
 {
 	fprintf(stderr, "Error: %s\n", msg);
-	fprintf(stderr, "Usage: %s -l image\n"
-			 "          -l ==> list image header information\n",
+	fprintf(stderr, "Usage: %s [-T type] -l image\n"
+			 "          -l ==> list image header information\n"
+			 "          -T ==> parse image file as 'type'\n",
 		params.cmdname);
 	fprintf(stderr,
 		"       %s [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image\n"
@@ -329,7 +330,7 @@
 			params.datafile = datafile;
 		else if (!params.datafile)
 			usage("Missing data file for auto-FIT (use -d)");
-	} else if (type != IH_TYPE_INVALID) {
+	} else if (params.lflag || type != IH_TYPE_INVALID) {
 		if (type == IH_TYPE_SCRIPT && !params.datafile)
 			usage("Missing data file for script (use -d)");
 		params.type = type;
@@ -358,7 +359,7 @@
 
 	/* set tparams as per input type_id */
 	tparams = imagetool_get_type(params.type);
-	if (tparams == NULL) {
+	if (tparams == NULL && !params.lflag) {
 		fprintf (stderr, "%s: unsupported type %s\n",
 			params.cmdname, genimg_get_type_name(params.type));
 		exit (EXIT_FAILURE);
@@ -368,18 +369,23 @@
 	 * check the passed arguments parameters meets the requirements
 	 * as per image type to be generated/listed
 	 */
-	if (tparams->check_params)
+	if (tparams && tparams->check_params)
 		if (tparams->check_params (&params))
 			usage("Bad parameters for image type");
 
 	if (!params.eflag) {
 		params.ep = params.addr;
 		/* If XIP, entry point must be after the U-Boot header */
-		if (params.xflag)
+		if (params.xflag && tparams)
 			params.ep += tparams->header_size;
 	}
 
 	if (params.fflag){
+		if (!tparams) {
+			fprintf(stderr, "%s: Missing FIT support\n",
+				params.cmdname);
+			exit (EXIT_FAILURE);
+		}
 		if (tparams->fflag_handle)
 			/*
 			 * in some cases, some additional processing needs
@@ -390,7 +396,7 @@
 			retval = tparams->fflag_handle(&params);
 
 		if (retval != EXIT_SUCCESS)
-			exit (retval);
+			usage("Bad parameters for FIT image type");
 	}
 
 	if (params.lflag || params.fflag) {
@@ -436,7 +442,7 @@
 				params.cmdname, params.imagefile);
 			exit (EXIT_FAILURE);
 #endif
-		} else if (sbuf.st_size < (off_t)tparams->header_size) {
+		} else if (tparams && sbuf.st_size < (off_t)tparams->header_size) {
 			fprintf (stderr,
 				"%s: Bad size: \"%s\" is not valid image: size %llu < %u\n",
 				params.cmdname, params.imagefile,
@@ -455,21 +461,12 @@
 			exit (EXIT_FAILURE);
 		}
 
-		if (params.fflag) {
-			/*
-			 * Verifies the header format based on the expected header for image
-			 * type in tparams
-			 */
-			retval = imagetool_verify_print_header_by_type(ptr, &sbuf,
-					tparams, &params);
-		} else {
-			/**
-			 * When listing the image, we are not given the image type. Simply check all
-			 * image types to find one that matches our header
-			 */
-			retval = imagetool_verify_print_header(ptr, &sbuf,
-					tparams, &params);
-		}
+		/*
+		 * Verifies the header format based on the expected header for image
+		 * type in tparams. If tparams is NULL simply check all image types
+		 * to find one that matches our header.
+		 */
+		retval = imagetool_verify_print_header(ptr, &sbuf, tparams, &params);
 
 		(void) munmap((void *)ptr, sbuf.st_size);
 		(void) close (ifd);
diff --git a/tools/pblimage.c b/tools/pblimage.c
index 3c823e9..bd639c2 100644
--- a/tools/pblimage.c
+++ b/tools/pblimage.c
@@ -230,19 +230,25 @@
 			struct image_tool_params *params)
 {
 	struct pbl_header *pbl_hdr = (struct pbl_header *) ptr;
+	uint32_t rcwheader;
+
+	if (params->arch == IH_ARCH_ARM)
+		rcwheader = RCW_ARM_HEADER;
+	else
+		rcwheader = RCW_PPC_HEADER;
 
 	/* Only a few checks can be done: search for magic numbers */
 	if (ENDIANNESS == 'l') {
 		if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE))
 			return -FDT_ERR_BADSTRUCTURE;
 
-		if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER))
+		if (pbl_hdr->rcwheader != reverse_byte(rcwheader))
 			return -FDT_ERR_BADSTRUCTURE;
 	} else {
 		if (pbl_hdr->preamble != RCW_PREAMBLE)
 			return -FDT_ERR_BADSTRUCTURE;
 
-		if (pbl_hdr->rcwheader != RCW_HEADER)
+		if (pbl_hdr->rcwheader != rcwheader)
 			return -FDT_ERR_BADSTRUCTURE;
 	}
 	return 0;
diff --git a/tools/pblimage.h b/tools/pblimage.h
index 81c5492..0222e80 100644
--- a/tools/pblimage.h
+++ b/tools/pblimage.h
@@ -8,7 +8,8 @@
 
 #define RCW_BYTES	64
 #define RCW_PREAMBLE	0xaa55aa55
-#define RCW_HEADER	0x010e0100
+#define RCW_ARM_HEADER	0x01ee0100
+#define RCW_PPC_HEADER	0x010e0100
 
 struct pbl_header {
 	uint32_t preamble;