Merge https://source.denx.de/u-boot/custodians/u-boot-sunxi

- Fix ARMv5/F1C100 FEL booting
- Fix F1C100 reset
- Introduce proper F1C100 boot method detection
- Enable SPI booting for F1C100

Boot tested from FEL, SPI, SD card and eMMC (where applicable) on
Pine64-LTS, Pine-H64, BananaPi M1, OrangePi Zero, LicheePi Nano(F1C100).
diff --git a/.mailmap b/.mailmap
index b36ae66..36fc116 100644
--- a/.mailmap
+++ b/.mailmap
@@ -22,6 +22,7 @@
 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>
@@ -35,7 +36,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 +56,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..0f39bc6 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
diff --git a/Makefile b/Makefile
index e6fc80a..f8f3f24 100644
--- a/Makefile
+++ b/Makefile
@@ -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
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/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;
+
+	/* CPU addresses on Armada 37xx always use 2 cells */
+	if (cpu_cells != 2)
+		return -EINVAL;
 
-	/* Calculate fixup offset from first child address (in last cell) */
-	fix_offset = base - fdt32_to_cpu(ranges[2]);
+	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 fixup offset is zero then there is nothing to fix */
+		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/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/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/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/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/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/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/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.
+
+| 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.
 
-  > i2c md 4a 3.1 1
+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/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/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/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/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/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/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/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/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/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/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/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 void *
+kwboot_msg_write_handler(void *arg)
+{
+	int tty = *(int *)((void **)arg)[0];
+	const void *msg = ((void **)arg)[1];
+	int rsp_timeo = msg_rsp_timeo;
+	int i, dummy_oldtype;
+
+	/* allow to cancel this thread at any time */
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy_oldtype);
+
+	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);
+	}
+}
+
 static int
-kwboot_bootmsg(int tty, void *msg)
+kwboot_msg_start_thread(pthread_t *thread, int *tty, void *msg)
 {
-	struct kwboot_block block;
+	void *arg[2];
 	int rc;
-	char c;
-	int count;
 
-	if (msg == NULL)
-		kwboot_printv("Please reboot the target into UART boot mode...");
-	else
-		kwboot_printv("Sending boot message. Please reboot the target...");
+	arg[0] = tty;
+	arg[1] = msg;
+	rc = pthread_create(thread, NULL, kwboot_msg_write_handler, arg);
+	if (rc) {
+		errno = rc;
+		return -1;
+	}
 
-	do {
-		rc = tcflush(tty, TCIOFLUSH);
-		if (rc)
-			break;
+	return 0;
+}
 
-		for (count = 0; count < 128; count++) {
-			rc = kwboot_tty_send(tty, msg, 8, 0);
-			if (rc) {
-				usleep(msg_req_delay * 1000);
-				continue;
-			}
-		}
+static int
+kwboot_msg_stop_thread(pthread_t thread)
+{
+	int rc;
 
-		rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
+	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;
 
-	kwboot_printv("Sending debug message. Please reboot the target...");
+	/* flush input and output queue */
+	tcflush(tty, TCIOFLUSH);
 
-	do {
-		char buf[16];
+	rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_debug);
+	if (rc) {
+		perror("Failed to start write thread");
+		return rc;
+	}
 
-		rc = tcflush(tty, TCIOFLUSH);
-		if (rc)
-			break;
+	kwboot_printv("Sending debug message. Please reboot the target...");
+	kwboot_spinner();
 
-		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/mkimage.c b/tools/mkimage.c
index 7601451..74bd072 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -381,6 +381,11 @@
 	}
 
 	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
@@ -391,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) {
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;