From 1926a6d63420a831d7d2e91ea0a22a9f36b22d5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Philip=20M=C3=BCller?= <philm@manjaro.org>
Date: Fri, 11 Mar 2022 10:04:43 +0100
Subject: [PATCH] [pkg-upd] 2022.04rc3+git+589c659-1

---
 ...659035a44a683b087fd75fe0b7667f7be7f5.patch | 4694 +++++++++++++++++
 ...ci-Add-HS400-Enhanced-Strobe-support.patch |    0
 ...k-power-on-and-init-counts-in-uclass.patch |  430 --
 ...ci-Fix-RK3399-eMMC-PHY-power-cycling.patch |    0
 ...0-Enhanced-Strobe-support-for-RK3399.patch |    0
 ...0-Enhanced-Strobe-support-for-RK3568.patch |    0
 ...mc-sdhci-allow-disabling-sdma-in-spl.patch |    0
 PKGBUILD                                      |   30 +-
 boot.txt                                      |    2 +-
 9 files changed, 4713 insertions(+), 443 deletions(-)
 create mode 100644 1000-upstream-589c659035a44a683b087fd75fe0b7667f7be7f5.patch
 rename 2002-mmc-sdhci-Add-HS400-Enhanced-Strobe-support.patch => 2001-mmc-sdhci-Add-HS400-Enhanced-Strobe-support.patch (100%)
 delete mode 100644 2001-phy-Track-power-on-and-init-counts-in-uclass.patch
 rename 2003-rockchip-sdhci-Fix-RK3399-eMMC-PHY-power-cycling.patch => 2002-rockchip-sdhci-Fix-RK3399-eMMC-PHY-power-cycling.patch (100%)
 rename 2004-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3399.patch => 2003-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3399.patch (100%)
 rename 2005-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3568.patch => 2004-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3568.patch (100%)
 rename 2006-mmc-sdhci-allow-disabling-sdma-in-spl.patch => 2005-mmc-sdhci-allow-disabling-sdma-in-spl.patch (100%)

diff --git a/1000-upstream-589c659035a44a683b087fd75fe0b7667f7be7f5.patch b/1000-upstream-589c659035a44a683b087fd75fe0b7667f7be7f5.patch
new file mode 100644
index 0000000..eab647b
--- /dev/null
+++ b/1000-upstream-589c659035a44a683b087fd75fe0b7667f7be7f5.patch
@@ -0,0 +1,4694 @@
+From 17a9f3f53d644d025a1a9e6d3a61fc71adf8b9d8 Mon Sep 17 00:00:00 2001
+From: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
+Date: Fri, 28 Jan 2022 13:10:10 +0200
+Subject: [PATCH 01/53] ARM: dts: at91: sama7g5ek: disable slew rate for GMACs
+ non MDIO pins
+
+Non GMAC's MDIO pins should have slew rate disabled for R(G)MII modes. Set
+them accordingly in DT.
+
+Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
+Tested-by: Eugen Hristev <eugen.hristev@microchip.com>
+Reviewed-by: Claudiu Beznea <claudiu.beznea@microchip.com>
+---
+ arch/arm/dts/sama7g5ek.dts | 25 +++++++++++++++++++------
+ 1 file changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm/dts/sama7g5ek.dts b/arch/arm/dts/sama7g5ek.dts
+index 6adb0442581..ac6f23f64e0 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;
+ 	};
+
+From 42595eb7067c6c076e1c98213438be727f883fe2 Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Fri, 25 Feb 2022 18:06:24 +0530
+Subject: [PATCH 02/53] misc: add sl28cpld base driver
+
+Add a multi-function device driver which will probe its children and
+provides methods to access the device.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+[Rebased]
+Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ MAINTAINERS             |   5 ++
+ drivers/misc/Kconfig    |   8 +++
+ drivers/misc/Makefile   |   1 +
+ drivers/misc/sl28cpld.c | 105 ++++++++++++++++++++++++++++++++++++++++
+ include/sl28cpld.h      |  14 ++++++
+ 5 files changed, 133 insertions(+)
+ create mode 100644 drivers/misc/sl28cpld.c
+ create mode 100644 include/sl28cpld.h
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index fb171e0c687..8b3870ff964 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1161,6 +1161,11 @@ S:	Maintained
+ 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/misc/sl28cpld.c
++
+ SPI
+ M:	Jagan Teki <jagan@amarulasolutions.com>
+ S:	Maintained
+diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
+index 0ade3e32b0e..7029bb7b5c5 100644
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -512,4 +512,12 @@ config ESM_PMIC
+ 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 bca7b24e99a..f22eff601a1 100644
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -82,3 +82,4 @@ obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o
+ 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 00000000000..01ef1c6178f
+--- /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/include/sl28cpld.h b/include/sl28cpld.h
+new file mode 100644
+index 00000000000..d116607cfb1
+--- /dev/null
++++ b/include/sl28cpld.h
+@@ -0,0 +1,14 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (c) 2021 Michael Walle <michael@walle.cc>
++ */
++
++#ifndef __SL28CPLD_H
++#define __SL28CPLD_H
++
++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
+
+From f606c9a8959728f7df539e182fb799d3ccc92cc6 Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Mon, 15 Nov 2021 23:45:43 +0100
+Subject: [PATCH 03/53] watchdog: add sl28cpld watchdog driver
+
+The watchdog timer is part of the sl28cpld management controller. The
+watchdog timer usually supervises the bootloader boot-up and if it bites
+the failsafe bootloader will be activated. Apart from that it supports
+the usual board level reset and one SMARC speciality: driving the
+WDT_TIMEOUT# signal.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ MAINTAINERS                     |   1 +
+ doc/board/kontron/sl28.rst      |  53 +++++++++++-----
+ drivers/watchdog/Kconfig        |   7 ++
+ drivers/watchdog/Makefile       |   1 +
+ drivers/watchdog/sl28cpld-wdt.c | 109 ++++++++++++++++++++++++++++++++
+ 5 files changed, 154 insertions(+), 17 deletions(-)
+ create mode 100644 drivers/watchdog/sl28cpld-wdt.c
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 8b3870ff964..989ea41e2c3 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1165,6 +1165,7 @@ SL28CLPD
+ M:	Michael Walle <michael@walle.cc>
+ S:	Maintained
+ F:	drivers/misc/sl28cpld.c
++F:	drivers/watchdog/sl28cpld-wdt.c
+ 
+ SPI
+ M:	Jagan Teki <jagan@amarulasolutions.com>
+diff --git a/doc/board/kontron/sl28.rst b/doc/board/kontron/sl28.rst
+index c7b18bed10c..c2cdc5e4241 100644
+--- a/doc/board/kontron/sl28.rst
++++ b/doc/board/kontron/sl28.rst
+@@ -35,23 +35,6 @@ 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
+-
+-
+ Update image
+ ------------
+ 
+@@ -82,6 +65,42 @@ u-boot (yet). But you can use the i2c command to access it.
+   > i2c md 4a 3.1 1
+ 
+ 
++Builtin watchdog
++----------------
++
++The builtin watchdog will supervise the bootloader startup. If anything
++goes wrong it will reset the board and boot into the failsafe bootloader.
++
++Once the bootloader is started successfully, it will disable the watchdog
++timer.
++
++wdt command flags
++^^^^^^^^^^^^^^^^^
++
++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.
++
++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/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
+index cabac290539..f90f0ca02bc 100644
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -266,6 +266,13 @@ config WDT_SBSA
+ 	   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 6d2b3822c06..a35bd559f51 100644
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -35,6 +35,7 @@ obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o
+ 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 00000000000..af5a6b1a28a
+--- /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,
++};
+
+From 07d6cb93781d47a8cb94c63b6419c68923b6f09d Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Fri, 25 Feb 2022 18:10:24 +0530
+Subject: [PATCH 04/53] gpio: add sl28cpld driver
+
+The gpio block is part of the sl28cpld sl28cpld management controller.
+There are three different flavors: the usual input and output where the
+direction is configurable, but also input only and output only variants.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+[Rebased]
+Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ MAINTAINERS                  |   1 +
+ drivers/gpio/Kconfig         |   6 ++
+ drivers/gpio/Makefile        |   1 +
+ drivers/gpio/sl28cpld-gpio.c | 165 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 173 insertions(+)
+ create mode 100644 drivers/gpio/sl28cpld-gpio.c
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 989ea41e2c3..0f39bc6bc92 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1164,6 +1164,7 @@ 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
+ 
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 8d0e47c67d9..522dfc195ec 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -544,4 +544,10 @@ config ZYNQMP_GPIO_MODEPIN
+ 	  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 63e9be6034f..33f7d41b7db 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -70,4 +70,5 @@ obj-$(CONFIG_NX_GPIO)		+= nx_gpio.o
+ 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 00000000000..700fc3df298
+--- /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,
++};
+
+From fea51613222edba814d33a21d9485463cf3988f3 Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Mon, 15 Nov 2021 23:45:45 +0100
+Subject: [PATCH 05/53] board: sl28: fix DRAM pretty print
+
+The current console output is:
+
+DRAM:  4 GiB
+DDR    4 GiB (DDR3, 32-bit, CL=11, ECC on)
+
+The size is printed twice and we can save one line of console output if
+we join both lines. The new output is as follows:
+
+DRAM:  4 GiB (DDR3, 32-bit, CL=11, ECC on)
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ board/kontron/sl28/sl28.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c
+index e84b3569186..a4ee8a1ef3e 100644
+--- a/board/kontron/sl28/sl28.c
++++ b/board/kontron/sl28/sl28.c
+@@ -47,8 +47,6 @@ int checkboard(void)
+ 
+ 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);
+ }
+ 
+
+From d36b683a0f4d9cd22aded61595b771c88203f3ab Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Mon, 15 Nov 2021 23:45:46 +0100
+Subject: [PATCH 06/53] board: sl28: print CPLD version on bootup
+
+Most of the time it is very useful to have the version of the board
+management controller. Now that we have a driver, print it during
+startup.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ board/kontron/sl28/sl28.c | 28 ++++++++++++++++++++++++++++
+ include/sl28cpld.h        |  2 ++
+ 2 files changed, 30 insertions(+)
+
+diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c
+index a4ee8a1ef3e..9cde48e61ef 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>
+@@ -15,6 +16,7 @@
+ #include <fsl_immap.h>
+ #include <netdev.h>
+ 
++#include <sl28cpld.h>
+ #include <fdtdec.h>
+ #include <miiphy.h>
+ 
+@@ -39,9 +41,35 @@ int board_eth_init(struct bd_info *bis)
+ 	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;
+ }
+ 
+diff --git a/include/sl28cpld.h b/include/sl28cpld.h
+index d116607cfb1..9a7c6de31f5 100644
+--- a/include/sl28cpld.h
++++ b/include/sl28cpld.h
+@@ -6,6 +6,8 @@
+ #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,
+
+From 34502f7aa343c58c9b4a7206e9fd44e3b89b4dea Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Mon, 15 Nov 2021 23:45:47 +0100
+Subject: [PATCH 07/53] board: sl28: enable sl28cpld support
+
+Enable the GPIO and watchdog driver. Don't start the watchdog
+automatically, though.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ configs/kontron_sl28_defconfig | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig
+index b61276cf1dd..a0c0c3c6a19 100644
+--- a/configs/kontron_sl28_defconfig
++++ b/configs/kontron_sl28_defconfig
+@@ -42,12 +42,14 @@ CONFIG_CMD_GREPENV=y
+ 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
+@@ -69,8 +71,10 @@ CONFIG_DDR_ECC=y
+ 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 +106,10 @@ CONFIG_USB_DWC3=y
+ 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_OF_LIBFDT_ASSUME_MASK=0x0
+ CONFIG_OF_LIBFDT_OVERLAY=y
+ CONFIG_EFI_SET_TIME=y
+
+From 2ba8a446ceece208c5926b623ddfd66bd163ff27 Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Mon, 15 Nov 2021 23:45:48 +0100
+Subject: [PATCH 08/53] board: sl28: enable SoC watchdog support
+
+The SoC provides two additional watchdogs integrated in the SoC. Enable
+support for these.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ configs/kontron_sl28_defconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig
+index a0c0c3c6a19..a4d9254815a 100644
+--- a/configs/kontron_sl28_defconfig
++++ b/configs/kontron_sl28_defconfig
+@@ -110,6 +110,7 @@ CONFIG_USB_GADGET_DOWNLOAD=y
+ # 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
+
+From 453d1711d22c4bccd48848a8450aa95cbc5008cc Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Mon, 15 Nov 2021 23:45:49 +0100
+Subject: [PATCH 09/53] board: sl28: disable recovery watchdog
+
+This board has an internal watchdog which supervises the board startup.
+Although, the initial state of the watchdog is configurable, it is
+enabled by default. In board_late_init(), which means almost everything
+worked as expected, disable the watchdog.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ board/kontron/sl28/sl28.c  | 29 +++++++++++++++++++++++++++++
+ doc/board/kontron/sl28.rst | 12 ++++++------
+ 2 files changed, 35 insertions(+), 6 deletions(-)
+
+diff --git a/board/kontron/sl28/sl28.c b/board/kontron/sl28/sl28.c
+index 9cde48e61ef..3c48a9141d0 100644
+--- a/board/kontron/sl28/sl28.c
++++ b/board/kontron/sl28/sl28.c
+@@ -15,6 +15,7 @@
+ #include <asm/arch/soc.h>
+ #include <fsl_immap.h>
+ #include <netdev.h>
++#include <wdt.h>
+ 
+ #include <sl28cpld.h>
+ #include <fdtdec.h>
+@@ -73,6 +74,34 @@ int checkboard(void)
+ 	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)
+ {
+ 	print_ddr_info(0);
+diff --git a/doc/board/kontron/sl28.rst b/doc/board/kontron/sl28.rst
+index c2cdc5e4241..04483e1e573 100644
+--- a/doc/board/kontron/sl28.rst
++++ b/doc/board/kontron/sl28.rst
+@@ -23,17 +23,17 @@ Copy u-boot.rom to a TFTP server.
+ 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.
++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
+ ------------
+
+From 2810da7c80ad7d25ef987d65bcaad2479f1df30e Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Mon, 15 Nov 2021 23:45:50 +0100
+Subject: [PATCH 10/53] board: sl28: remove "Useful I2C tricks" section from
+ docs
+
+They are no longer needed, because we now have proper driver support for
+the sl28cpld management controller.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ doc/board/kontron/sl28.rst | 15 ---------------
+ 1 file changed, 15 deletions(-)
+
+diff --git a/doc/board/kontron/sl28.rst b/doc/board/kontron/sl28.rst
+index 04483e1e573..44435d90c62 100644
+--- a/doc/board/kontron/sl28.rst
++++ b/doc/board/kontron/sl28.rst
+@@ -50,21 +50,6 @@ Afterward you can copy this file to your ESP into the /EFI/UpdateCapsule/
+ folder. On the next EFI boot this will automatically update your
+ bootloader.
+ 
+-Useful I2C tricks
+------------------
+-
+-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.
+-
+-- reset into failsafe bootloader::
+-
+-  > i2c mw 4a 5.1 0; i2c mw 4a 6.1 6b; i2c mw 4a 4.1 42
+-
+-- read board management controller version::
+-
+-  > i2c md 4a 3.1 1
+-
+-
+ Builtin watchdog
+ ----------------
+ 
+
+From 62ba0e5df6e81f0a45b589273c043d451986767c Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Fri, 25 Feb 2022 18:18:40 +0530
+Subject: [PATCH 11/53] board: sl28: disable random MAC address generation
+
+Nowadays, u-boot (when CONFIG_NET_RANDOM_ETHADDR is set) will set
+enetaddr to a random value if not set and then pass the randomly
+generated MAC address to linux.
+
+This is bad for the following reasons:
+ (1) it makes it impossible for linux to detect this error
+ (2) linux won't trigger any fallback mechanism for the case where
+     it didn't find any valid MAC address
+ (3) a saveenv will store this randomly generated MAC address in the
+     environment
+
+Probably, the user will also be unaware that something is wrong. He will
+just get different MAC addresses on each reboot, asking himself why this
+is the case.
+
+As this board usually have a serial port, the user can just fix this by
+setting the MAC address manually in the environment. Also disable the
+netconsole just in case, because it cannot be guaranteed that it will
+work in any case. After all, this was just a convenience option, because
+the bootloader - right now - doesn't have the ability to read the MAC
+address, which is stored in the OTP. But it is far more important to
+have a clear view of whats wrong with a board and that means we can no
+longer use this Kconfig option.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+[Rebased]
+Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ configs/kontron_sl28_defconfig | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig
+index a4d9254815a..b743c2ba9e7 100644
+--- a/configs/kontron_sl28_defconfig
++++ b/configs/kontron_sl28_defconfig
+@@ -59,8 +59,6 @@ CONFIG_OF_LIST=""
+ 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
+
+From 554a85313bc7bb50704c2a8d6f4857037aea2426 Mon Sep 17 00:00:00 2001
+From: Michael Walle <michael@walle.cc>
+Date: Fri, 25 Feb 2022 18:21:56 +0530
+Subject: [PATCH 12/53] board: sl28: use fit image generator
+
+Simplify the binman config and fdt nodes by using the "@..-SEQ"
+substitutions and CONFIG_OF_LIST.
+
+Signed-off-by: Michael Walle <michael@walle.cc>
+[Rebased]
+Signed-off-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ .../dts/fsl-ls1028a-kontron-sl28-u-boot.dtsi  | 128 ++----------------
+ configs/kontron_sl28_defconfig                |   2 +-
+ 2 files changed, 10 insertions(+), 120 deletions(-)
+
+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 d4b833284e2..2dcb3c2a58f 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";
+-
+-				conf-1 {
+-					description = "fsl-ls1028a-kontron-sl28";
+-					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";
+-				};
++				default = "@config-DEFAULT-SEQ";
+ 
+-				conf-5 {
+-					description = "fsl-ls1028a-kontron-sl28-var4";
++				@config-SEQ {
++					description = "NAME";
+ 					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/configs/kontron_sl28_defconfig b/configs/kontron_sl28_defconfig
+index b743c2ba9e7..cf8aedfdfd7 100644
+--- a/configs/kontron_sl28_defconfig
++++ b/configs/kontron_sl28_defconfig
+@@ -55,7 +55,7 @@ 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
+
+From 453db6056850e1ac1be0a12df72fcf3bd5f61bd3 Mon Sep 17 00:00:00 2001
+From: Daniel Klauer <daniel.klauer@gin.de>
+Date: Wed, 9 Feb 2022 15:53:41 +0100
+Subject: [PATCH 13/53] lx2160a: Fix distroboot device list for configs without
+ USB/SCSI/etc
+
+The BOOT_TARGET_DEVICES list for distro_bootcmd was hard-coded to assume
+that all boot devices are available/enabled in the configuration,
+thus ignoring the actual config settings. The config_distro_bootcmd.h
+header file specifically has compile-time checks to detect such problems.
+
+To allow disabling USB, SCSI, etc. in custom lx2160a board configs,
+make it depend on the config settings and use only the enabled features.
+
+Signed-off-by: Daniel Klauer <daniel.klauer@gin.de>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ include/configs/lx2160a_common.h | 34 +++++++++++++++++++++++++++-----
+ 1 file changed, 29 insertions(+), 5 deletions(-)
+
+diff --git a/include/configs/lx2160a_common.h b/include/configs/lx2160a_common.h
+index e31f8d087f7..4f4b5713dc7 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 */
+
+From 2058967d2fe8f93142d774bc47241d80894027d5 Mon Sep 17 00:00:00 2001
+From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Date: Thu, 17 Feb 2022 11:51:36 +0800
+Subject: [PATCH 14/53] tools: pblimage: fix image header verification function
+
+The Layerscape platforms have different RCW header value from FSL
+PowerPC platforms, the current image header verification callback
+is only working on PowerPC, it will fail on Layerscape, this patch
+is to fix this issue.
+
+This is a historical problem and exposed by the following patch:
+http://patchwork.ozlabs.org/project/uboot/patch/20220114173443.9877-1-pali@kernel.org
+
+Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+Reviewed-by: Priyanka Jain <priyanka.jain@nxp.com>
+---
+ Makefile         |  2 +-
+ tools/pblimage.c | 10 ++++++++--
+ tools/pblimage.h |  3 ++-
+ 3 files changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index 66d9e78cc77..4d9cda7f305 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1411,7 +1411,7 @@ MKIMAGEFLAGS_u-boot-spl.kwb = -n $(KWD_CONFIG_FILE) \
+ 	$(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/tools/pblimage.c b/tools/pblimage.c
+index 3c823e96cf1..bd639c276f9 100644
+--- a/tools/pblimage.c
++++ b/tools/pblimage.c
+@@ -230,19 +230,25 @@ static int pblimage_verify_header(unsigned char *ptr, int image_size,
+ 			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 81c5492926b..0222e8067b4 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;
+
+From a41b88ec02ea1dbf4e5e6e895625a5fee96097c5 Mon Sep 17 00:00:00 2001
+From: Tim Harvey <tharvey@gateworks.com>
+Date: Mon, 28 Feb 2022 14:53:21 -0800
+Subject: [PATCH 15/53] phy: nop-phy: Fix phy reset if no reset-gpio defined
+
+Ensure there is a valid reset-gpio defined before using it.
+
+Fixes: f9852acdce02 ("phy: nop-phy: Fix enabling reset")
+Cc: Adam Ford <aford173@gmail.com>
+Signed-off-by: Tim Harvey <tharvey@gateworks.com>
+---
+ drivers/phy/nop-phy.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/phy/nop-phy.c b/drivers/phy/nop-phy.c
+index e2ee6e92068..d0904f4f075 100644
+--- a/drivers/phy/nop-phy.c
++++ b/drivers/phy/nop-phy.c
+@@ -45,11 +45,13 @@ static int nop_phy_init(struct phy *phy)
+ 
+ #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;
+
+From a08b04b5c75a7e9122dfc733c66b978aa0afe4ba Mon Sep 17 00:00:00 2001
+From: Jesse Taube <mr.bossman075@gmail.com>
+Date: Fri, 11 Feb 2022 19:32:33 -0500
+Subject: [PATCH 16/53] mach-sunxi: Add boot device detection for SUNIV/F1C100s
+
+In contrast to other Allwinner SoCs the F1C100s BROM does not store a
+boot source indicator in the eGON header in SRAM. This leaves the SPL
+guessing where we were exactly booted from, and for instance trying
+the SD card first, even though we booted from SPI flash.
+
+By inspecting the BROM code and by experimentation, Samuel found that the
+top of the BROM stack contains unique pointers for each of the boot
+sources, which we can use as a boot source indicator.
+
+This patch removes the existing board_boot_order bodge and replace it
+with a proper boot source indication function.
+
+The only caveat is that this only works in the SPL, as the SPL header
+gets overwritten with the exception vectors, once U-Boot proper takes
+over. Always return MMC0 as the boot source, when called from U-Boot
+proper, as a placeholder for now, until we find another way.
+
+Signed-off-by: Jesse Taube <Mr.Bossman075@gmail.com>
+Suggested-by: Samuel Holland <samuel@sholland.org>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/include/asm/arch-sunxi/spl.h |  9 ++++
+ arch/arm/mach-sunxi/board.c           | 64 ++++++++++++++++-----------
+ 2 files changed, 46 insertions(+), 27 deletions(-)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
+index 58cdf806d9a..b543d24e5a0 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-sunxi/board.c b/arch/arm/mach-sunxi/board.c
+index 57078f7a7b2..0071de19ffd 100644
+--- a/arch/arm/mach-sunxi/board.c
++++ b/arch/arm/mach-sunxi/board.c
+@@ -191,12 +191,48 @@ SPL_LOAD_IMAGE_METHOD("FEL", 0, BOOT_DEVICE_BOARD, spl_board_load_image);
+ 
+ #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 @@ unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
+ 	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)
+ {
+
+From 0dcdaff8b88e996de5d9c91141084cbfcfb01be6 Mon Sep 17 00:00:00 2001
+From: Jesse Taube <mr.bossman075@gmail.com>
+Date: Fri, 11 Feb 2022 19:32:34 -0500
+Subject: [PATCH 17/53] mach-sunxi: Add SPL SPI boot for SUNIV
+
+The SUNIV SoCs come with a sun6i-style SPI controller at the base address
+of sun4i SPI controller. The module clock of the SPI controller is
+missing which leaves us running directly from the AHB clock, which is
+set to 200MHz.
+
+Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
+[Icenowy: Original implementation]
+Signed-off-by: Jesse Taube <Mr.Bossman075@gmail.com>
+[Jesse: adaptation to Upstream U-Boot]
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/include/asm/arch-sunxi/gpio.h |  1 +
+ arch/arm/mach-sunxi/spl_spi_sunxi.c    | 24 +++++++++++++++++-------
+ 2 files changed, 18 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/include/asm/arch-sunxi/gpio.h b/arch/arm/include/asm/arch-sunxi/gpio.h
+index 7f7eb0517cf..edd0fbf49fe 100644
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -160,6 +160,7 @@ enum sunxi_gpio_number {
+ #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/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
+index 910e8050161..734c165e5d2 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 @@ static uintptr_t spi0_base_address(void)
+ 	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 @@ static void spi0_enable_clock(void)
+ 	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 @@ static void spi0_disable_clock(void)
+ 					     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 @@ static void spi0_init(void)
+ 	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();
+
+From 640f2f3bf1d6320274b17192a1ab9d8030211302 Mon Sep 17 00:00:00 2001
+From: Jesse Taube <mr.bossman075@gmail.com>
+Date: Fri, 11 Feb 2022 19:32:35 -0500
+Subject: [PATCH 18/53] mach-sunxi: Enable SPI boot for SUNIV and licheepi nano
+
+Enable SPI boot in SPL on SUNIV architecture and use
+it in the licheepi nano that uses the F1C100s.
+
+Signed-off-by: Jesse Taube <Mr.Bossman075@gmail.com>
+Reviewed-by: Andre Przywara <andre.przywara@arm.com>
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/mach-sunxi/Kconfig     | 2 +-
+ configs/licheepi_nano_defconfig | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
+index 205fe3c9d3c..d1c60d24082 100644
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -1038,7 +1038,7 @@ config SPL_STACK_R_ADDR
+ 
+ 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/configs/licheepi_nano_defconfig b/configs/licheepi_nano_defconfig
+index 2ac0ef42856..9fd1dcc9958 100644
+--- a/configs/licheepi_nano_defconfig
++++ b/configs/licheepi_nano_defconfig
+@@ -9,3 +9,4 @@ CONFIG_MACH_SUNIV=y
+ CONFIG_DRAM_CLK=156
+ CONFIG_DRAM_ZQ=0
+ # CONFIG_VIDEO_SUNXI is not set
++CONFIG_SPL_SPI_SUNXI=y
+
+From c21f3d45711135179b4abbdc9462109a41060df6 Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Tue, 1 Mar 2022 12:21:58 +0000
+Subject: [PATCH 19/53] sunxi: f1c100s: Fix FEL registers restore
+
+Commit 88998f777531 ("arm: arm926ej-s: Add sunxi code") introduced
+the ARM926 version of the code to save and restore some FEL state, to
+be able to return to the BROM FEL code after the SPL has run.
+
+However during review a change was made, that happened to mess up the
+register restore part, so SCTLR and CPSR ended up with the wrong values,
+breaking return to FEL.
+
+Use the same offset that we actually save those registers to, to make
+FEL booting actually work on the Lichee Pi Nano.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ arch/arm/cpu/arm926ejs/sunxi/fel_utils.S | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
+index 08be7ed11aa..25924033c63 100644
+--- a/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
++++ b/arch/arm/cpu/arm926ejs/sunxi/fel_utils.S
+@@ -25,9 +25,9 @@ ENTRY(return_to_fel)
+ 	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)
+
+From cfcf1952c11e6ffcbbf88eb63c49edca2acf1d5e Mon Sep 17 00:00:00 2001
+From: Andre Przywara <andre.przywara@arm.com>
+Date: Wed, 2 Mar 2022 01:30:55 +0000
+Subject: [PATCH 20/53] sunxi: f1c100s: Drop SYSRESET to enable reset
+ functionality
+
+The F1C100s DT contains the wrong compatible string for the watchdog,
+which breaks reset functionality.
+Updating the DT goes via the Linux tree, but to allow reset
+functionality meanwhile (useful for development!), disable SYSRESET for
+now, to let the old-fashioned watchdog driver kick in and provide the
+reset_cpu() implementation.
+
+Signed-off-by: Andre Przywara <andre.przywara@arm.com>
+---
+ configs/licheepi_nano_defconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/configs/licheepi_nano_defconfig b/configs/licheepi_nano_defconfig
+index 9fd1dcc9958..67b7b85c491 100644
+--- a/configs/licheepi_nano_defconfig
++++ b/configs/licheepi_nano_defconfig
+@@ -10,3 +10,4 @@ CONFIG_DRAM_CLK=156
+ CONFIG_DRAM_ZQ=0
+ # CONFIG_VIDEO_SUNXI is not set
+ CONFIG_SPL_SPI_SUNXI=y
++# CONFIG_SYSRESET is not set
+
+From 7938b3be7cedcfe54e891c86e4297b0dccde0f9f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Fri, 18 Feb 2022 12:24:13 +0100
+Subject: [PATCH 21/53] tools: kwboot: Fix quitting terminal
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Sometimes kwboot after quitting terminal prints error message:
+
+  terminal: Bad address
+
+This is caused by trying to call write() syscall with count of (size_t)-1
+bytes.
+
+When quit sequence is split into more read() calls then number of input
+bytes (nin) at the end of cycle can underflow and be negative. Fix it.
+
+Fixes: de7514046ea5 ("tools: kwboot: Fix detection of quit esc sequence")
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ tools/kwboot.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index 68c0ef1f1b0..2d2d545d825 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -1197,7 +1197,7 @@ kwboot_term_pipe(int in, int out, const char *quit, int *s)
+ 			if (buf[i] == quit[*s]) {
+ 				(*s)++;
+ 				if (!quit[*s]) {
+-					nin = i - *s;
++					nin = (i > *s) ? (i - *s) : 0;
+ 					break;
+ 				}
+ 			} else {
+@@ -1208,7 +1208,7 @@ kwboot_term_pipe(int in, int out, const char *quit, int *s)
+ 		}
+ 
+ 		if (i == nin)
+-			nin -= *s;
++			nin -= (nin > *s) ? *s : nin;
+ 	}
+ 
+ 	if (kwboot_write(out, buf, nin) < 0)
+
+From 68285176a9552ba264878cdc6c7daccb5806b569 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Fri, 18 Feb 2022 12:25:22 +0100
+Subject: [PATCH 22/53] pci: pci_mvebu: Remove unused SELECT and lane_mask
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Macro SELECT() is unused and struct mvebu_pcie field lane_mask is unused
+too. Remove them.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Marek Behún <marek.behun@nic.cz>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ drivers/pci/pci_mvebu.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
+index 5a0a59a8b9e..16fe54fd366 100644
+--- a/drivers/pci/pci_mvebu.c
++++ b/drivers/pci/pci_mvebu.c
+@@ -30,8 +30,6 @@
+ #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
+@@ -77,7 +75,6 @@ struct mvebu_pcie {
+ 	u32 lane;
+ 	bool is_x4;
+ 	int devfn;
+-	u32 lane_mask;
+ 	int sec_busno;
+ 	char name[16];
+ 	unsigned int mem_target;
+
+From fc27e5df637dd4c954b67dd1415b9af144718a9e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Fri, 18 Feb 2022 12:25:23 +0100
+Subject: [PATCH 23/53] pci: pci_mvebu: Cleanup macro names
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use "MVPCIE_" prefix instead of generic "PCIE_" prefix for pci_mvebu.c
+specific macros. Define offset macros for Root Port registers and use
+standard register macros from pci.h when accessing Root Port registers.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Marek Behún <marek.behun@nic.cz>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ drivers/pci/pci_mvebu.c | 130 +++++++++++++++++++---------------------
+ 1 file changed, 60 insertions(+), 70 deletions(-)
+
+diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
+index 16fe54fd366..f07669374d7 100644
+--- a/drivers/pci/pci_mvebu.c
++++ b/drivers/pci/pci_mvebu.c
+@@ -30,35 +30,25 @@
+ #include <linux/sizes.h>
+ 
+ /* PCIe unit register offsets */
+-#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
+@@ -87,8 +77,8 @@ struct mvebu_pcie {
+ 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)
+@@ -112,20 +102,20 @@ static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno)
+ {
+ 	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)
+@@ -195,18 +185,18 @@ static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
+ 		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;
+@@ -286,18 +276,18 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
+ 		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;
+@@ -321,20 +311,20 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
+ 
+ 	/* 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;
+@@ -342,12 +332,12 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
+ 		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;
+ 	}
+@@ -357,14 +347,14 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
+ 		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 */
+@@ -403,9 +393,9 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie)
+ 	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
+@@ -414,10 +404,10 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie)
+ 	 * 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)
+@@ -440,7 +430,7 @@ static int mvebu_pcie_probe(struct udevice *dev)
+ 	 * 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
+@@ -448,10 +438,10 @@ static int mvebu_pcie_probe(struct udevice *dev)
+ 	 * 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
+
+From 7f59ed68728e732062f4fb0c1e8940f5bf550ded Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun@nic.cz>
+Date: Fri, 18 Feb 2022 17:46:25 +0100
+Subject: [PATCH 24/53] arm: mvebu: turris_omnia: Enable ext4 write support in
+ defconfig
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Enable ext4 write support in Turris Omnia's defconfig. Some users find
+it useful.
+
+Signed-off-by: Marek Behún <marek.behun@nic.cz>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ configs/turris_omnia_defconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/configs/turris_omnia_defconfig b/configs/turris_omnia_defconfig
+index 280dd55f001..5b1fdbfb2d3 100644
+--- a/configs/turris_omnia_defconfig
++++ b/configs/turris_omnia_defconfig
+@@ -93,3 +93,4 @@ CONFIG_USB_XHCI_HCD=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_WDT=y
+ CONFIG_WDT_ORION=y
++CONFIG_EXT4_WRITE=y
+
+From 1fd54253bca7d43d046bba4853fe5fafd034bc17 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 23 Feb 2022 13:52:32 +0100
+Subject: [PATCH 25/53] arm: a37xx: pci: Fix a3700_fdt_fix_pcie_regions()
+ function again
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The a3700_fdt_fix_pcie_regions() function still computes nonsense.
+
+It computes the fixup offset from the PCI address taken from the first
+row of the "ranges" array, which means that:
+- PCI address must equal CPU address (otherwise the computed fix offset
+  will be wrong),
+- the first row must contain the lowest address.
+
+This is the case for the default device-tree, which is why we didn't
+notice it.
+
+It also adds the fixup offset to all PCI and CPU addresses, which is
+wrong.
+
+Instead:
+1) The fixup offset must be computed from the CPU address, not PCI
+   address.
+
+2) The fixup offset must be computed from the row containing the lowest
+   CPU address, which is not necessarily contained in the first row.
+
+3) The PCI address - the address to which the PCIe controller remaps the
+   address space as seen from the point of view of the PCIe device -
+   must be fixed by the fix offset in the same way as the CPU address
+   only in the special case when the CPU adn PCI addresses are the same.
+   Same addresses means that remapping is disabled, and thus if we
+   change the CPU address, we need also to change the PCI address so
+   that the remapping is still disabled afterwards.
+
+Consider an example:
+  The ranges entries contain:
+    PCI address   CPU address
+    70000000      EA000000
+    E9000000      E9000000
+    EB000000      EB000000
+
+  By default CPU PCIe window is at:        E8000000 - F0000000
+  Consider the case when TF-A moves it to: F2000000 - FA000000
+
+  Until now the function would take the PCI address of the first entry:
+  70000000, and the new base, F2000000, to compute the fix offset:
+  F2000000 - 70000000 = 82000000, and then add 8200000 to all addresses,
+  resulting in
+    PCI address   CPU address
+    F2000000      6C000000
+    6B000000      6B000000
+    6D000000      6D000000
+  which is complete nonsense - none of the CPU addresses is in the
+  requested window.
+
+  Now it will take the lowest CPU address, which is in second row,
+  E9000000, and compute the fix offset F2000000 - E9000000 = 09000000,
+  and then add it to all CPU addresses and those PCI addresses which
+  equal to their corresponding CPU addresses, resulting in
+    PCI address   CPU address
+    70000000      F3000000
+    F2000000      F2000000
+    F4000000      F4000000
+  where all of the CPU addresses are in the needed window.
+
+Fixes: 4a82fca8e330 ("arm: a37xx: pci: Fix a3700_fdt_fix_pcie_regions() function")
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Marek Behún <marek.behun@nic.cz>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ arch/arm/mach-mvebu/armada3700/cpu.c | 81 +++++++++++++++++++---------
+ 1 file changed, 55 insertions(+), 26 deletions(-)
+
+diff --git a/arch/arm/mach-mvebu/armada3700/cpu.c b/arch/arm/mach-mvebu/armada3700/cpu.c
+index 23492f49dae..52b5109b735 100644
+--- a/arch/arm/mach-mvebu/armada3700/cpu.c
++++ b/arch/arm/mach-mvebu/armada3700/cpu.c
+@@ -316,8 +316,8 @@ static int fdt_setprop_inplace_u32_partial(void *blob, int node,
+ 
+ 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 @@ int a3700_fdt_fix_pcie_regions(void *blob)
+ 		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;
++
++	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 first child address (in last cell) */
+-	fix_offset = base - fdt32_to_cpu(ranges[2]);
++	/* Calculate fixup offset from the lowest (first) CPU address */
++	fix_offset = base - lowest_cpu_addr;
+ 
+-	/* If fixup offset is zero then there is nothing to fix */
++	/* 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;
+ 	}
+
+From 2454de2c34531941756d259771fd0266ea2d5d0b Mon Sep 17 00:00:00 2001
+From: Francois Berder <fberder@outlook.fr>
+Date: Mon, 28 Feb 2022 10:31:45 +0100
+Subject: [PATCH 26/53] drivers: rtc: fix null pointer access in
+ armada38x_rtc_reset
+
+Replace null pointer by pointer to device registers when calling
+armada38x_rtc_write.
+
+Signed-off-by: Francois Berder <fberder@outlook.fr>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ drivers/rtc/armada38x.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/rtc/armada38x.c b/drivers/rtc/armada38x.c
+index 2d264acf779..2af64e39122 100644
+--- a/drivers/rtc/armada38x.c
++++ b/drivers/rtc/armada38x.c
+@@ -121,7 +121,7 @@ static int armada38x_rtc_reset(struct udevice *dev)
+ 		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;
+
+From 87724d5c905be4fb5eeed0e31384664721db4098 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <marek.behun@nic.cz>
+Date: Mon, 28 Feb 2022 15:59:37 +0100
+Subject: [PATCH 27/53] arm64: a37xx: pinctrl: Fix PWM pins indexes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Commit 5534fb4f4833 ("arm64: a37xx: pinctrl: Correct PWM pins
+definitions") introduced bogus definitions os PWM pins: all 4 pins have
+index 11, instead of having indexes 11, 12, 13, 14.
+
+Fix this.
+
+Signed-off-by: Marek Behún <marek.behun@nic.cz>
+Reviewed-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+index 1cf1f06f101..e76ef153e60 100644
+--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
++++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+@@ -162,11 +162,11 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = {
+ 	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"),
+
+From 0a6f0297c677946907b7ba34d34995fe03055aad Mon Sep 17 00:00:00 2001
+From: Chris Packham <judge.packham@gmail.com>
+Date: Tue, 1 Mar 2022 13:53:23 +1300
+Subject: [PATCH 28/53] ARM: mvebu: x530: clearfog: Add ODT configuration
+
+Commit 369e532691e0 ("ddr: marvell: a38x: allow board specific ODT
+configuration") added the odt_config member to struct
+mv_ddr_topology_map ahead of the clk_enable and ck_delay members. This
+means that any boards that configured either of clk_enable or ck_delay
+needed to have their board topology updated. This affects the x530 and
+clearfog boards. Other A38x boards don't touch any of the trailing
+members of mv_ddr_topology_map so don't need updating.
+
+Fixes: 369e532691e0 ("ddr: marvell: a38x: allow board specific ODT configuration")
+Signed-off-by: Chris Packham <judge.packham@gmail.com>
+Acked-by: Baruch Siach <baruch@tkos.co.il>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ board/alliedtelesis/x530/x530.c    | 1 +
+ board/solidrun/clearfog/clearfog.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/board/alliedtelesis/x530/x530.c b/board/alliedtelesis/x530/x530.c
+index 8b31045a074..c0ec2afa301 100644
+--- a/board/alliedtelesis/x530/x530.c
++++ b/board/alliedtelesis/x530/x530.c
+@@ -73,6 +73,7 @@ static struct mv_ddr_topology_map board_topology_map = {
+ 	{0},				/* timing parameters */
+ 	{ {0} },			/* electrical configuration */
+ 	{0},				/* electrical parameters */
++	0,				/* ODT configuration */
+ 	0,				/* Clock enable mask */
+ 	160				/* Clock delay */
+ };
+diff --git a/board/solidrun/clearfog/clearfog.c b/board/solidrun/clearfog/clearfog.c
+index c920cf8d6b5..03adb591d82 100644
+--- a/board/solidrun/clearfog/clearfog.c
++++ b/board/solidrun/clearfog/clearfog.c
+@@ -147,6 +147,7 @@ static struct mv_ddr_topology_map board_topology_map = {
+ 	{0},				/* timing parameters */
+ 	{ {0} },			/* electrical configuration */
+ 	{0,},				/* electrical parameters */
++	0,				/* ODT configuration */
+ 	0x3,				/* clock enable mask */
+ };
+ 
+
+From d8865f8677c6dd43109e22bfbb85a3cd6bf6aca1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:18 +0100
+Subject: [PATCH 29/53] tools: kwboot: Check for return value of
+ kwboot_tty_send() and tcflush()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Failure of kwboot_tty_send() and tcflush() functions is fatal, it does not
+make sense to continue. So return error back to the caller like in other
+places where are called these functions.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ tools/kwboot.c | 30 +++++++++++++++++++-----------
+ 1 file changed, 19 insertions(+), 11 deletions(-)
+
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index 2d2d545d825..5a7c53ce892 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -740,10 +740,8 @@ kwboot_bootmsg(int tty, void *msg)
+ 
+ 		for (count = 0; count < 128; count++) {
+ 			rc = kwboot_tty_send(tty, msg, 8, 0);
+-			if (rc) {
+-				usleep(msg_req_delay * 1000);
+-				continue;
+-			}
++			if (rc)
++				break;
+ 		}
+ 
+ 		rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
+@@ -772,11 +770,19 @@ kwboot_bootmsg(int tty, void *msg)
+ 	 */
+ 
+ 	/* 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,7 +791,11 @@ kwboot_bootmsg(int tty, void *msg)
+ 	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;
+ }
+@@ -805,10 +815,8 @@ kwboot_debugmsg(int tty, void *msg)
+ 			break;
+ 
+ 		rc = kwboot_tty_send(tty, msg, 8, 0);
+-		if (rc) {
+-			usleep(msg_req_delay * 1000);
+-			continue;
+-		}
++		if (rc)
++			break;
+ 
+ 		rc = kwboot_tty_recv(tty, buf, 16, msg_rsp_timeo);
+ 
+
+From 132016e2706affdd9e150c4e34fd2d1f5bd05749 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:19 +0100
+Subject: [PATCH 30/53] tools: kwboot: Remove msg_req_delay
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Variable msg_req_delay is set but never used. So completely remove it.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ tools/kwboot.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index 5a7c53ce892..4dfb1038b4f 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -48,11 +48,9 @@ static unsigned char kwboot_msg_debug[] = {
+ };
+ 
+ /* 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 +283,6 @@ static const char kwb_baud_magic[16] = "$baudratechange";
+ 
+ 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;
+ 
+@@ -1725,7 +1722,6 @@ kwboot_usage(FILE *stream, char *progname)
+ 		"  -D <image>: boot <image> without preamble (Dove)\n");
+ 	fprintf(stream, "  -d: enter 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");
+@@ -1804,12 +1800,11 @@ main(int argc, char **argv)
+ 			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':
+
+From c1d911f15f81a09126f52fac3e78e2eb6cfd224b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:20 +0100
+Subject: [PATCH 31/53] tools: kwboot: Cleanup bootmsg and debugmsg variables
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Function kwboot_debugmsg() is always called with kwboot_msg_debug as msg
+and function kwboot_bootmsg() with kwboot_msg_debug as msg. Function
+kwboot_bootmsg() is never called with NULL msg.
+
+Simplify, cleanup and remove dead code.
+
+No functional change.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ tools/kwboot.c | 31 ++++++++++++++-----------------
+ 1 file changed, 14 insertions(+), 17 deletions(-)
+
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index 4dfb1038b4f..4e2acb52458 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -718,17 +718,14 @@ kwboot_open_tty(const char *path, int baudrate)
+ }
+ 
+ static int
+-kwboot_bootmsg(int tty, void *msg)
++kwboot_bootmsg(int tty)
+ {
+ 	struct kwboot_block block;
+ 	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...");
++	kwboot_printv("Sending boot message. Please reboot the target...");
+ 
+ 	do {
+ 		rc = tcflush(tty, TCIOFLUSH);
+@@ -736,7 +733,7 @@ kwboot_bootmsg(int tty, void *msg)
+ 			break;
+ 
+ 		for (count = 0; count < 128; count++) {
+-			rc = kwboot_tty_send(tty, msg, 8, 0);
++			rc = kwboot_tty_send(tty, kwboot_msg_boot, sizeof(kwboot_msg_boot), 0);
+ 			if (rc)
+ 				break;
+ 		}
+@@ -798,7 +795,7 @@ kwboot_bootmsg(int tty, void *msg)
+ }
+ 
+ static int
+-kwboot_debugmsg(int tty, void *msg)
++kwboot_debugmsg(int tty)
+ {
+ 	int rc;
+ 
+@@ -811,7 +808,7 @@ kwboot_debugmsg(int tty, void *msg)
+ 		if (rc)
+ 			break;
+ 
+-		rc = kwboot_tty_send(tty, msg, 8, 0);
++		rc = kwboot_tty_send(tty, kwboot_msg_debug, sizeof(kwboot_msg_debug), 0);
+ 		if (rc)
+ 			break;
+ 
+@@ -1737,8 +1734,8 @@ main(int argc, char **argv)
+ {
+ 	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;
+@@ -1748,8 +1745,8 @@ main(int argc, char **argv)
+ 
+ 	rv = 1;
+ 	tty = -1;
+-	bootmsg = NULL;
+-	debugmsg = NULL;
++	bootmsg = 0;
++	debugmsg = 0;
+ 	imgpath = NULL;
+ 	img = NULL;
+ 	term = 0;
+@@ -1771,7 +1768,7 @@ main(int argc, char **argv)
+ 		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] != '-')
+@@ -1781,14 +1778,14 @@ main(int argc, char **argv)
+ 		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':
+@@ -1869,13 +1866,13 @@ main(int argc, char **argv)
+ 	}
+ 
+ 	if (debugmsg) {
+-		rc = kwboot_debugmsg(tty, debugmsg);
++		rc = kwboot_debugmsg(tty);
+ 		if (rc) {
+ 			perror("debugmsg");
+ 			goto out;
+ 		}
+ 	} else if (bootmsg) {
+-		rc = kwboot_bootmsg(tty, bootmsg);
++		rc = kwboot_bootmsg(tty);
+ 		if (rc) {
+ 			perror("bootmsg");
+ 			goto out;
+
+From 913866af6c97c37bbdb8165c32d8046b8ec2c5e1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:21 +0100
+Subject: [PATCH 32/53] tools: kwboot: Use separate thread for sending boot
+ message pattern
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+After BootROM successfully detects boot message pattern on UART it waits
+until host stop sending data on UART. For example Armada 385 BootROM
+requires that host does not send anything on UART at least 24 ms. If host
+is still sending something then BootROM waits (possibly infinitely).
+
+BootROM successfully detects boot message pattern if it receives it in
+small period of time after power on.
+
+So to ensure that host put BootROM into UART boot mode, host must send
+continuous stream of boot message pattern with a small gap (for A385 at
+least 24 ms) after series of pattern. But this gap cannot be too often or
+too long to ensure that it does not cover whole BootROM time window when it
+is detecting for boot message pattern.
+
+Therefore it is needed to do following steps in cycle without any delay:
+1. send series of boot message pattern over UART
+2. wait until kernel transmit all data
+3. sleep small period of time
+
+At the same time, host needs to monitor input queue, data received on the
+UART and checking if it contains NAK byte by which BootROM informs that
+xmodem transfer is ready.
+
+But it is not possible to wait until kernel transmit all data on UART and
+at the same time in the one process to also wait for input data. This is
+limitation of POSIX tty API and also by linux kernel that it does not
+provide asynchronous function for waiting until all data are transmitted.
+There is only synchronous variant tcdrain().
+
+So to correctly implement this handshake on systems with linux kernel, it
+is needed to use tcdrain() in separate thread.
+
+Implement sending of boot message pattern in one thread and reading of
+reply in the main thread. Use pthread library for threads.
+
+This change makes UART booting on Armada 385 more reliable. It is possible
+to start kwboot and power on board after minute and kwboot correctly put
+board into UART boot mode.
+
+Old implementation without separate thread has an issue that it read just
+one byte from UART input queue and then it send 128 message pattern to the
+output queue. If some noise was on UART then kwboot was not able to read
+BootROM response as its input queue was just overflowed and kwboot was
+sending more data than receiving.
+
+This change basically fixed above issue too.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ tools/Makefile |   3 ++
+ tools/kwboot.c | 120 +++++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 104 insertions(+), 19 deletions(-)
+
+diff --git a/tools/Makefile b/tools/Makefile
+index 5409ff2879c..f8fb9fe09ee 100644
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -196,6 +196,9 @@ hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
+ hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
+ HOSTCFLAGS_mkexynosspl.o := -pedantic
+ 
++HOSTCFLAGS_kwboot.o += -pthread
++HOSTLDLIBS_kwboot += -pthread
++
+ ifdtool-objs := $(LIBFDT_OBJS) ifdtool.o
+ hostprogs-$(CONFIG_X86) += ifdtool
+ 
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index 4e2acb52458..9fd90b9bec7 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -28,6 +28,7 @@
+ #include <stdint.h>
+ #include <time.h>
+ #include <sys/stat.h>
++#include <pthread.h>
+ 
+ #ifdef __linux__
+ #include "termios_linux.h"
+@@ -717,37 +718,120 @@ kwboot_open_tty(const char *path, int baudrate)
+ 	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_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;
+-	int rc;
++	pthread_t write_thread;
++	int rc, err;
+ 	char c;
+-	int count;
+-
+-	kwboot_printv("Sending boot message. Please reboot the target...");
+ 
+-	do {
+-		rc = tcflush(tty, TCIOFLUSH);
+-		if (rc)
+-			break;
++	/* flush input and output queue */
++	tcflush(tty, TCIOFLUSH);
+ 
+-		for (count = 0; count < 128; count++) {
+-			rc = kwboot_tty_send(tty, kwboot_msg_boot, sizeof(kwboot_msg_boot), 0);
+-			if (rc)
+-				break;
+-		}
++	rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_boot);
++	if (rc) {
++		perror("Failed to start write thread");
++		return rc;
++	}
+ 
+-		rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
++	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
+@@ -1873,10 +1957,8 @@ main(int argc, char **argv)
+ 		}
+ 	} else if (bootmsg) {
+ 		rc = kwboot_bootmsg(tty);
+-		if (rc) {
+-			perror("bootmsg");
++		if (rc)
+ 			goto out;
+-		}
+ 	}
+ 
+ 	if (img) {
+
+From 93976af58926626077eca8b7bbd1aa592649ec01 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:22 +0100
+Subject: [PATCH 33/53] tools: kwboot: Fix sending and processing debug message
+ pattern (-d option)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+-d option is currently broken. In most cases BootROM does not detect this
+message pattern. For sending debug message pattern it is needed to do same
+steps as for boot message pattern.
+
+Implement sending debug message pattern via same separate thread like it is
+for boot message pattern.
+
+Checking if BootROM entered into UART debug mode is different than
+detecting UART boot mode. When in boot mode, BootROM sends xmodem NAK
+bytes. When in debug mode, BootROM activates console echo and reply back
+every written byte (extept \r\n which is interpreted as executing command
+and \b which is interpreting as removing the last sent byte).
+
+So in kwboot, check that BootROM send back at least 4 debug message
+patterns as a echo reply for debug message patterns which kwboot is sending
+in the loop.
+
+Then there is another observation, if host writes too many bytes (as
+command) then BootROM command line buffer may overflow after trying to
+execute such long command. To workaround this overflow, it is enough to
+remove bytes from the input line buffer by sending 3 \b bytes for every
+sent character. So do it.
+
+With this change, it is possbile to enter into the UART debug mode with
+kwboot -d option.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ tools/kwboot.c | 139 +++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 123 insertions(+), 16 deletions(-)
+
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index 9fd90b9bec7..3ab49e74bb6 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -881,30 +881,139 @@ kwboot_bootmsg(int tty)
+ static int
+ 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, kwboot_msg_debug, sizeof(kwboot_msg_debug), 0);
+-		if (rc)
++	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
+@@ -1951,10 +2060,8 @@ main(int argc, char **argv)
+ 
+ 	if (debugmsg) {
+ 		rc = kwboot_debugmsg(tty);
+-		if (rc) {
+-			perror("debugmsg");
++		if (rc)
+ 			goto out;
+-		}
+ 	} else if (bootmsg) {
+ 		rc = kwboot_bootmsg(tty);
+ 		if (rc)
+
+From e8d26e8276358fcd1c2fe28293d3b4c82a735731 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:23 +0100
+Subject: [PATCH 34/53] tools: kwboot: Add support for backspace key in mini
+ terminal
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Marvell BootROM recognize only '\b' byte as backspace. Use terminfo
+for retrieving current backspace sequence and replace any occurrence of
+backspace sequence by the '\b' byte.
+
+Reading terminfo database is possible via tigetstr() function from system
+library libtinfo.so.*. So link kwboot with -ltinfo.
+
+Normally terminfo functions are in <term.h> system header file. But this
+header file conflicts with U-Boot "termios_linux.h" header file. So declare
+terminfo functions manually.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ tools/Makefile |   2 +-
+ tools/kwboot.c | 109 +++++++++++++++++++++++++++++++++++++++++++------
+ 2 files changed, 97 insertions(+), 14 deletions(-)
+
+diff --git a/tools/Makefile b/tools/Makefile
+index f8fb9fe09ee..60231c728ce 100644
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -197,7 +197,7 @@ hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
+ HOSTCFLAGS_mkexynosspl.o := -pedantic
+ 
+ HOSTCFLAGS_kwboot.o += -pthread
+-HOSTLDLIBS_kwboot += -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 3ab49e74bb6..26cfe6dea6a 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -36,6 +36,13 @@
+ #include <termios.h>
+ #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
+  */
+@@ -1376,37 +1383,84 @@ kwboot_xmodem(int tty, const void *_img, size_t size, int baudrate)
+ }
+ 
+ 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) ? (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 -= (nin > *s) ? *s : nin;
++		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;
+@@ -1415,7 +1469,8 @@ kwboot_term_pipe(int in, int out, const char *quit, int *s)
+ 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;
+ 
+@@ -1434,6 +1489,33 @@ kwboot_terminal(int tty)
+ 			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
+@@ -1441,6 +1523,7 @@ kwboot_terminal(int tty)
+ 
+ 	rc = 0;
+ 	s = 0;
++	k = 0;
+ 
+ 	do {
+ 		fd_set rfds;
+@@ -1460,13 +1543,13 @@ kwboot_terminal(int tty)
+ 			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;
+ 		}
+
+From bdc4dbaefe98890cc7ec7b6aa2d4e85b086527cd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:24 +0100
+Subject: [PATCH 35/53] tools: kwboot: Update usage
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add all supported Armada SoCs and document -b and -d options in usage.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ tools/kwboot.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index 26cfe6dea6a..11aca00bf1e 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -1986,14 +1986,15 @@ static void
+ 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, 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, "  -s <resp-timeo>: use specific response-timeout\n");
+ 	fprintf(stream,
+
+From 787fcf5c004d3e4e9fd4b8b6e092bcfe73714cbb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:25 +0100
+Subject: [PATCH 36/53] tools: kwboot: Update manpage
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Document -D, -b, -d, -q and -s options.
+
+Add common examples how to use kwboot.
+
+Add information about Armada 38x BootROM bug for debug console mode and how
+to workaround it.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ doc/kwboot.1 | 103 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 99 insertions(+), 4 deletions(-)
+
+diff --git a/doc/kwboot.1 b/doc/kwboot.1
+index acdea891d9f..bda049bde56 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.
+@@ -47,6 +47,48 @@ code in it's header which may also print some output via UART (for
+ example U-Boot SPL does this). In such a case, this output is also
+ 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.
+@@ -55,13 +97,33 @@ In the past, when this option was used, the program patched the header
+ in the image prior upload, to "UART boot" type. This is now done by
+ 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 @@ Tested values for \fIbaudrate\fP for Armada 38x include: 115200,
+ 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"
+ 
+
+From 0b5909d3afaff4fe552cb01de3cb6e537e8bfece Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:26 +0100
+Subject: [PATCH 37/53] tools: kwboot: Update doc about Avanta
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Testes proved that current kwboot version supports also Avanta SoCs.
+It looks like that Avanta SoCs are using same kwbimage format as Armada.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Tested-by: Tony Dinh <mibodhi@gmail.com>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ doc/kwboot.1   | 2 +-
+ tools/kwboot.c | 6 +++---
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/doc/kwboot.1 b/doc/kwboot.1
+index bda049bde56..f555ff26a25 100644
+--- a/doc/kwboot.1
++++ b/doc/kwboot.1
+@@ -11,7 +11,7 @@ kwboot \- Boot Marvell Kirkwood (and others 32-bit) SoCs over a serial link.
+ .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
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index 11aca00bf1e..cd1879246a8 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -1,7 +1,7 @@
+ /*
+  * 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>
+@@ -1990,7 +1990,7 @@ kwboot_usage(FILE *stream, char *progname)
+ 		progname);
+ 	fprintf(stream, "\n");
+ 	fprintf(stream,
+-		"  -b <image>: boot <image> with preamble (Kirkwood, Armada 370/XP/375/38x/39x)\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, "  -b: enter xmodem boot mode\n");
+
+From f4fa962fcdbd69589021a096f1af0690fe884279 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 2 Mar 2022 11:49:27 +0100
+Subject: [PATCH 38/53] tools: kwboot: Update references with public links
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Public documents about BootROM of some Marvell SoCs are available in the
+public Web Archive. Put this information into source code.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+Tested-by: Stefan Roese <sr@denx.de>
+---
+ tools/kwboot.c | 31 ++++++++++++++++++++++++++++---
+ 1 file changed, 28 insertions(+), 3 deletions(-)
+
+diff --git a/tools/kwboot.c b/tools/kwboot.c
+index cd1879246a8..69d1be0f482 100644
+--- a/tools/kwboot.c
++++ b/tools/kwboot.c
+@@ -7,9 +7,34 @@
+  * (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"
+
+From 4ff9a8c33c5f2514ee6e66788259399b6626f6b5 Mon Sep 17 00:00:00 2001
+From: Romain Naour <romain.naour@smile.fr>
+Date: Thu, 10 Feb 2022 23:13:36 +0100
+Subject: [PATCH 39/53] configs: ti: use standard configuration nodes naming
+
+Currently, any u-boot bootloader for ti armv7 platforms using
+DEFAULT_FIT_TI_ARGS to boot with a fitimage (boot_fit = 1)
+doesn't boot when built with Yocto Poky (openembedded-core).
+
+  ## Loading kernel from FIT Image at 90000000 ...
+  Could not find configuration node
+  ERROR: can't get kernel image!
+
+Arago forked the kernel-fitimage class [1] and altered the
+configuration nodes naming while adding the OPTEE support by
+using FITIMAGE_CONF_BY_NAME by default [2].
+
+The "upstream" kernel-fitimage class from openembedded-core still
+add the "conf-" prefix for each configuration nodes [3].
+
+The ITS file format (from doc/uImage.FIT/source_file_format.txt)
+is not really accurate with the expected naming of these nodes.
+But in practice the "conf-" prefix is widely used.
+
+When the FIT image support has been added for ti armv7 platforms
+the naming from Arago has been used [3]. Fix this issue by adding
+the prefix expected by the ITS file generated by kernel-fitimage
+class from openembedded-core.
+
+[1] http://arago-project.org/git/meta-arago.git?p=meta-arago.git;a=commitdiff;h=719ab1b2098bcdc59c249e3529fa82cb1b9130e6
+[2] http://arago-project.org/git/meta-arago.git?p=meta-arago.git;a=commitdiff;h=f23f2876a0cda89241d031bb7ba0b4256ed90035
+[3] https://git.openembedded.org/openembedded-core/tree/meta/classes/kernel-fitimage.bbclass?h=yocto-3.1.13#n290
+[3] 1e93cc8473e4fe018aececc8ed3bf8fc2b3ff561
+
+Signed-off-by: Romain Naour <romain.naour@smile.fr>
+Cc: Tom Rini <trini@konsulko.com>
+Reviewed-by: Denys Dmytriyenko <denys@konsulko.com>
+---
+ include/configs/ti_armv7_common.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/configs/ti_armv7_common.h b/include/configs/ti_armv7_common.h
+index 97337070092..7483bc821d3 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,
+
+From f7fbe547d99729cfa36238ba1629c26589834867 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Tue, 15 Feb 2022 07:47:55 +0100
+Subject: [PATCH 40/53] arm: mach-k3: am6_init: Use CONFIG_TI_I2C_BOARD_DETECT
+
+We only want to call do_board_detect() if CONFIG_TI_I2C_BOARD_DETECT
+is set. Same as done for am64.
+
+This makes it possible to add a custom am65 based board design to
+U-Boot that does not use this board detection mechanism.
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ arch/arm/mach-k3/am6_init.c |  3 ++-
+ board/ti/am65x/evm.c        | 26 +++++++++++++++-----------
+ 2 files changed, 17 insertions(+), 12 deletions(-)
+
+diff --git a/arch/arm/mach-k3/am6_init.c b/arch/arm/mach-k3/am6_init.c
+index ffb7aaded2e..8a6b1de7641 100644
+--- a/arch/arm/mach-k3/am6_init.c
++++ b/arch/arm/mach-k3/am6_init.c
+@@ -251,7 +251,8 @@ void board_init_f(ulong dummy)
+ 	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/board/ti/am65x/evm.c b/board/ti/am65x/evm.c
+index fbe33cbea55..7182a8cad1a 100644
+--- a/board/ti/am65x/evm.c
++++ b/board/ti/am65x/evm.c
+@@ -129,6 +129,7 @@ int ft_board_setup(void *blob, struct bd_info *bd)
+ }
+ #endif
+ 
++#ifdef CONFIG_TI_I2C_BOARD_DETECT
+ int do_board_detect(void)
+ {
+ 	int ret;
+@@ -353,23 +354,26 @@ static int probe_daughtercards(void)
+ 
+ 	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;
+ }
+
+From 4403e1a31cca73d516c2302e2950ddc8ea7d0c37 Mon Sep 17 00:00:00 2001
+From: Aswath Govindraju <a-govindraju@ti.com>
+Date: Wed, 16 Feb 2022 11:27:24 +0530
+Subject: [PATCH 41/53] configs: j721e_*_evm_a72_defconfig: Enable config for
+ setting mmc speed mode
+
+Enable config for setting mmc speed mode from U-Boot command line.
+
+Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
+---
+ configs/j721e_evm_a72_defconfig    | 1 +
+ configs/j721e_hs_evm_a72_defconfig | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig
+index b843a84415b..60c96f89613 100644
+--- a/configs/j721e_evm_a72_defconfig
++++ b/configs/j721e_evm_a72_defconfig
+@@ -193,3 +193,4 @@ CONFIG_UFS=y
+ 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 ae184b03587..6479f9baff0 100644
+--- a/configs/j721e_hs_evm_a72_defconfig
++++ b/configs/j721e_hs_evm_a72_defconfig
+@@ -162,3 +162,4 @@ CONFIG_UFS=y
+ CONFIG_CADENCE_UFS=y
+ CONFIG_TI_J721E_UFS=y
+ CONFIG_OF_LIBFDT_OVERLAY=y
++CONFIG_MMC_SPEED_MODE_SET=y
+
+From 39834ccdd43f492c61c0d8b4db55988b1f47a4dc Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Wed, 16 Feb 2022 09:06:49 +0100
+Subject: [PATCH 42/53] arm: dts: iot2050: Add cfg register space for ringacc
+ and udmap
+
+Recent unrelated fixes (9876ae7db6da) revealed that we were missing bits
+from 2af181b53e28 in the IOT2050 dt. Add them, but only for main U-Boot.
+SPL loads from QSPI only, thus cannot use DMA.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+---
+ .../dts/k3-am65-iot2050-common-u-boot.dtsi    | 25 ++++++++++++++++++-
+ 1 file changed, 24 insertions(+), 1 deletion(-)
+
+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 286e25f3794..d80c5501d2f 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 {
+
+From 55fd1c442e747338604ef0075a4a888a40399ddc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?S=C3=A9bastien=20Szymanski?=
+ <sebastien.szymanski@armadeus.com>
+Date: Fri, 25 Feb 2022 14:48:54 +0100
+Subject: [PATCH 43/53] cmd: pwm: fix typo 'eisable' -> 'disable'
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fixed misspelled 'disable' in help text.
+
+Signed-off-by: Sébastien Szymanski <sebastien.szymanski@armadeus.com>
+---
+ cmd/pwm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/cmd/pwm.c b/cmd/pwm.c
+index 7947e61aeed..7e82955239f 100644
+--- a/cmd/pwm.c
++++ b/cmd/pwm.c
+@@ -111,5 +111,5 @@ U_BOOT_CMD(pwm, 6, 0, do_pwm,
+ 	   "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");
+
+From 5017f9b595da6e5c8f064a43fc6cd42cb62c082a Mon Sep 17 00:00:00 2001
+From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+Date: Tue, 1 Mar 2022 08:53:56 +0100
+Subject: [PATCH 44/53] mkimage: error handling for FIT image
+
+If parameter -F is given but FIT support is missing, a NULL pointer might
+dereferenced (Coverity CID 350249).
+
+If incorrect parameters are given, provide a message and show usage.
+
+Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+---
+ tools/mkimage.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/tools/mkimage.c b/tools/mkimage.c
+index 760145119dc..74bd072832c 100644
+--- a/tools/mkimage.c
++++ b/tools/mkimage.c
+@@ -381,6 +381,11 @@ int main(int argc, char **argv)
+ 	}
+ 
+ 	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 @@ int main(int argc, char **argv)
+ 			retval = tparams->fflag_handle(&params);
+ 
+ 		if (retval != EXIT_SUCCESS)
+-			exit (retval);
++			usage("Bad parameters for FIT image type");
+ 	}
+ 
+ 	if (params.lflag || params.fflag) {
+
+From 4fa4227cdd14020bb6d588293f3cb8591aeebfa0 Mon Sep 17 00:00:00 2001
+From: Michal Simek <michal.simek@xilinx.com>
+Date: Tue, 1 Mar 2022 12:43:32 +0100
+Subject: [PATCH 45/53] .mailmap: Record all address for main U-Boot
+ contributor
+
+Based on looking at top contributors it was seen that top statistics from
+top contributors don't include all contributions from different email
+addresses. That's why I checked all top contributors are checked it.
+
+git shortlog -n $START..$END -e -s
+
+The patch is adding mapping for Bin Meng, Marek Vasut, Masahiro Yamada,
+Michal Simek, Tom Rini, Wolfgang Denk.
+And also use mapping for Stefan Roese and Wolfgang Denk to be properly
+counted.
+
+Signed-off-by: Michal Simek <michal.simek@xilinx.com>
+Acked-by: Bin Meng <bmeng.cn@gmail.com>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ .mailmap | 22 ++++++++++++++++++++--
+ 1 file changed, 20 insertions(+), 2 deletions(-)
+
+diff --git a/.mailmap b/.mailmap
+index b36ae66719e..36fc1164a2b 100644
+--- a/.mailmap
++++ b/.mailmap
+@@ -22,6 +22,7 @@ Andreas Bießmann <andreas@biessmann.org>
+ 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 @@ Jagan Teki <jagannadha.sutradharudu-teki@xilinx.com>
+ 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 @@ Ricardo Ribalda <ricardo@ribalda.com> <ricardo.ribalda@gmail.com>
+ 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>
+
+From 9b5ad4f5da756939eac4123fc347af533eeb339e Mon Sep 17 00:00:00 2001
+From: Yann Droneaud <ydroneaud@opteya.com>
+Date: Tue, 1 Mar 2022 16:12:34 +0100
+Subject: [PATCH 46/53] lib: rsa: use actual OpenSSL 1.1.0 EVP MD API
+
+Since OpenSSL 1.1.0, EVP_MD_CTX_create() is EVP_MD_CTX_new()
+                     EVP_MD_CTX_destroy() is EVP_MD_CTX_free()
+                     EVP_MD_CTX_init() is EVP_MD_CTX_reset()
+
+As there's no need to reset a newly created EVP_MD_CTX, moreover
+EVP_DigestSignInit() does the reset, thus call to EVP_MD_CTX_init()
+can be dropped.
+As there's no need to reset an EVP_MD_CTX before it's destroyed,
+as it will be reset by EVP_MD_CTX_free(), call to EVP_MD_CTX_reset()
+is not needed and can be dropped.
+
+Signed-off-by: Yann Droneaud <ydroneaud@opteya.com>
+---
+ lib/rsa/rsa-sign.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
+index 3e7b7982890..b2a21199e48 100644
+--- a/lib/rsa/rsa-sign.c
++++ b/lib/rsa/rsa-sign.c
+@@ -383,12 +383,11 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
+ 		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 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
+ 		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 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
+ 	return 0;
+ 
+ err_sign:
+-	EVP_MD_CTX_destroy(context);
++	EVP_MD_CTX_free(context);
+ err_create:
+ 	free(sig);
+ err_alloc:
+
+From a12366a807a8fbba67b6da6e842e8296af60aba0 Mon Sep 17 00:00:00 2001
+From: Stefan Roese <sr@denx.de>
+Date: Thu, 13 Jan 2022 16:57:31 +0100
+Subject: [PATCH 47/53] MAINTAINERS: Add watchdog maintainers entry
+
+I've been handling "inofficially" the watchdog related patches for a few
+years now. Let's make this official and add a tree for it and also add
+myself here in the MAINTAINERS file.
+
+Signed-off-by: Stefan Roese <sr@denx.de>
+Cc: Tom Rini <trini@konsulko.com>
+Cc: Harald Seiler <hws@denx.de>
+Reviewed-by: Tom Rini <trini@konsulko.com>
+---
+ MAINTAINERS | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 0f39bc6bc92..82fc49e31d4 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -1326,6 +1326,14 @@ F:	include/virtio*.h
+ 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>
+
+From a12492ebbc88dab74b1d6e27d8194a56eb1fbbff Mon Sep 17 00:00:00 2001
+From: Philippe Reynes <philippe.reynes@softathome.com>
+Date: Thu, 10 Feb 2022 18:17:54 +0100
+Subject: [PATCH 48/53] drivers: watchdog: wdt-uclass.c: add a property u-boot,
+ noautostart
+
+Since commit 492ee6b8d0e7 ("watchdog: wdt-uclass.c: handle all DM
+watchdogs in watchdog_reset()"), all the watchdog are started when
+the config WATCHDOG_AUTOSTART.
+
+To avoid a binary choice none/all, a property u-boot,noautostart
+may be added in the watchdog node of the u-boot device tree to not
+autostart this watchdog.
+
+Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
+Reviewed-by: Simon Glass <sjg@chromium.org>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ drivers/watchdog/wdt-uclass.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c
+index 6d0f4738676..dbf556467d3 100644
+--- a/drivers/watchdog/wdt-uclass.c
++++ b/drivers/watchdog/wdt-uclass.c
+@@ -36,6 +36,8 @@ struct wdt_priv {
+ 	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 @@ static void init_watchdog_dev(struct udevice *dev)
+ 			       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 @@ static int wdt_pre_probe(struct udevice *dev)
+ 	 * 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.
+
+From 65066773a3e4c3f1dfc5eac8400ca7a7268e4fb7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
+Date: Wed, 23 Feb 2022 14:21:40 +0100
+Subject: [PATCH 49/53] watchdog: armada_37xx: Probe driver also when watchdog
+ is already running
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+If Armada 37xx watchdog is started before U-Boot then CNTR_CTRL_ACTIVE bit
+is set, U-Boot armada-37xx-wdt.c driver fails to initialize and so U-Boot
+is unable to use or kick this watchdog.
+
+Do not check for CNTR_CTRL_ACTIVE bit and always initialize watchdog. Same
+behavior is implemented in Linux kernel driver.
+
+This change allows to activate watchdog in firmware which loads U-Boot.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: Marek Behún <marek.behun@nic.cz>
+Reviewed-by: Stefan Roese <sr@denx.de>
+---
+ drivers/watchdog/armada-37xx-wdt.c | 17 +++--------------
+ 1 file changed, 3 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/watchdog/armada-37xx-wdt.c b/drivers/watchdog/armada-37xx-wdt.c
+index 2e119b9b5aa..bacebbc7926 100644
+--- a/drivers/watchdog/armada-37xx-wdt.c
++++ b/drivers/watchdog/armada-37xx-wdt.c
+@@ -58,13 +58,11 @@ static void counter_disable(struct a37xx_wdt *priv, int id)
+ 	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 @@ static int init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src)
+ 	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_expire_now(struct udevice *dev, ulong flags)
+ 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;
+ 
+
+From 817e153fe546c2da9df8e8affc94d12036815659 Mon Sep 17 00:00:00 2001
+From: Jan Kiszka <jan.kiszka@siemens.com>
+Date: Tue, 8 Mar 2022 07:25:50 +0100
+Subject: [PATCH 50/53] watchdog: rti_wdt: Add 10% safety margin to clock
+ frequency
+
+When running against RC_OSC_32k, the watchdog may suffer from running
+faster than expected, expiring earlier. The Linux kernel adds a 10%
+margin to the timeout calculation by slowing down the read clock rate
+accordingly. Do the same here, also to have comparable preset values
+for both drivers.
+
+Along this, fix the name of the local var holding to frequency - in Hz,
+not kHz.
+
+Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
+Signed-off-by: Stefan Roese <sr@denx.de>
+---
+ drivers/watchdog/rti_wdt.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c
+index 253286d349b..8d93f19b984 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 @@ static int rti_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
+ 	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 @@ static int rti_wdt_probe(struct udevice *dev)
+ 	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;
+ }
+
+From 45eb35c1979e928a2b086b090be86ac249114e62 Mon Sep 17 00:00:00 2001
+From: Michal Simek <michal.simek@xilinx.com>
+Date: Mon, 7 Mar 2022 08:41:21 +0100
+Subject: [PATCH 51/53] .mailmap: Fix Heinrich's xypron.glpk@gmx.de record
+
+There is one issue with Heinrich xypron.glpk@gmx.de <xypron.glpk@gmx.de>
+record which should be specifically grouped with his name.
+
+Signed-off-by: Michal Simek <michal.simek@xilinx.com>
+---
+ .mailmap | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/.mailmap b/.mailmap
+index 36fc1164a2b..1f88ea953ce 100644
+--- a/.mailmap
++++ b/.mailmap
+@@ -28,6 +28,7 @@ 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>
+
+From c12f9d2e5496489c22aa265725cc71697d2de0cb Mon Sep 17 00:00:00 2001
+From: Mark Kettenis <kettenis@openbsd.org>
+Date: Mon, 21 Feb 2022 22:17:37 +0100
+Subject: [PATCH 52/53] drivers: serial: Make sure we really return a serial
+ device
+
+The stdout-path property in the device tree does not necessarily
+point at a serial device. On machines such as the Apple M1 laptops
+where the serial port isn't easy to access and users expect to see
+console output on the integrated display stdout-path may point at
+the device tree node for the framebuffer for example.
+
+If stdout-path does not point at a node for a serial device, the
+serial_check_stdout() will not find a bound device and will drop
+down into code that attempts to use lists_bind_fdt() to bind a
+device anyway. However, that fallback code does not check that
+the uclass of the device is UCLASS_SERIAL. So if stdout-path points
+at the framebuffer instead of the serial device it will return a
+UCLASS_VIDEO device. Since the code that calls this function
+expects the returned device to be a UCLASS_SERIAL device, U-Boot
+will crash as soon as it attempts to send output to the console.
+
+Add a check here to verify that the uclass of the bound device
+really is UCLASS_SERIAL. If it isn't, serial_check_stdout() will
+return an error and serial_find_console_or_panic() will use the
+serial device with sequence number 0 as the console and all is fine.
+
+Signed-off-by: Mark Kettenis <kettenis@openbsd.org>
+Reviewed-by: Simon Glass <sjg@chromium.org>
+---
+ drivers/serial/serial-uclass.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
+index 362cedd9552..f30f352bd7a 100644
+--- a/drivers/serial/serial-uclass.c
++++ b/drivers/serial/serial-uclass.c
+@@ -66,7 +66,8 @@ static int serial_check_stdout(const void *blob, struct udevice **devp)
+ 	 */
+ 	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;
+ 	}
+ 
+
+From b38fbddbaa3dca0a190f9655f753e72405290431 Mon Sep 17 00:00:00 2001
+From: Philippe Reynes <philippe.reynes@softathome.com>
+Date: Tue, 8 Mar 2022 10:37:19 +0100
+Subject: [PATCH 53/53] board: .gitignore: replace dsdt.c by dsdt_generated.c
+
+Since commit 5d94cbd1dca7 ("scripts: Makefile.lib: generate
+dsdt_generated.c instead of dsdt.c"), the file generated
+is named dsdt_generated.c instead of dsdt.c.
+So all files .gitignore referencing dsdt.c should be
+upated with dsdt_generated.c.
+
+Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
+Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
+---
+ board/advantech/som-db5800-som-6867/.gitignore    | 6 +++---
+ board/congatec/conga-qeval20-qa3-e3845/.gitignore | 6 +++---
+ board/intel/bayleybay/.gitignore                  | 6 +++---
+ board/intel/edison/.gitignore                     | 6 +++---
+ board/intel/galileo/.gitignore                    | 6 +++---
+ board/intel/minnowmax/.gitignore                  | 6 +++---
+ 6 files changed, 18 insertions(+), 18 deletions(-)
+
+diff --git a/board/advantech/som-db5800-som-6867/.gitignore b/board/advantech/som-db5800-som-6867/.gitignore
+index 6eb8a5481ab..39e46ba0ae7 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/congatec/conga-qeval20-qa3-e3845/.gitignore b/board/congatec/conga-qeval20-qa3-e3845/.gitignore
+index 6eb8a5481ab..39e46ba0ae7 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/intel/bayleybay/.gitignore b/board/intel/bayleybay/.gitignore
+index 6eb8a5481ab..39e46ba0ae7 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/edison/.gitignore b/board/intel/edison/.gitignore
+index 6eb8a5481ab..39e46ba0ae7 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/galileo/.gitignore b/board/intel/galileo/.gitignore
+index 6eb8a5481ab..39e46ba0ae7 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/minnowmax/.gitignore b/board/intel/minnowmax/.gitignore
+index 6eb8a5481ab..39e46ba0ae7 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/2002-mmc-sdhci-Add-HS400-Enhanced-Strobe-support.patch b/2001-mmc-sdhci-Add-HS400-Enhanced-Strobe-support.patch
similarity index 100%
rename from 2002-mmc-sdhci-Add-HS400-Enhanced-Strobe-support.patch
rename to 2001-mmc-sdhci-Add-HS400-Enhanced-Strobe-support.patch
diff --git a/2001-phy-Track-power-on-and-init-counts-in-uclass.patch b/2001-phy-Track-power-on-and-init-counts-in-uclass.patch
deleted file mode 100644
index d0283bc..0000000
--- a/2001-phy-Track-power-on-and-init-counts-in-uclass.patch
+++ /dev/null
@@ -1,430 +0,0 @@
-From 226fce6108fe364e35f3eb9a84ff1a7ec93727ce Mon Sep 17 00:00:00 2001
-From: Alper Nebi Yasak <alpernebiyasak@gmail.com>
-Date: Thu, 30 Dec 2021 22:36:51 +0300
-Subject: [PATCH] phy: Track power-on and init counts in uclass
-
-On boards using the RK3399 SoC, the USB OHCI and EHCI controllers share
-the same PHY device instance. While these controllers are being stopped
-they both attempt to power-off and deinitialize it, but trying to
-power-off the deinitialized PHY device results in a hang. This usually
-happens just before booting an OS, and can be explicitly triggered by
-running "usb start; usb stop" in the U-Boot shell.
-
-Implement a uclass-wide counting mechanism for PHY initialization and
-power state change requests, so that we don't power-off/deinitialize a
-PHY instance until all of its users want it done. The Allwinner A10 USB
-PHY driver does this counting in-driver, remove those parts in favour of
-this in-uclass implementation.
-
-The sandbox PHY operations test needs some changes since the uclass will
-no longer call into the drivers for actions matching its tracked state
-(e.g. powering-off a powered-off PHY). Update that test, and add a new
-one which simulates multiple users of a single PHY.
-
-The major complication here is that PHY handles aren't deduplicated per
-instance, so the obvious idea of putting the counts in the PHY handles
-don't immediately work. It seems possible to bind a child udevice per
-PHY instance to the PHY provider and deduplicate the handles in each
-child's uclass-private areas, like in the CLK framework. An alternative
-approach could be to use those bound child udevices themselves as the
-PHY handles. Instead, to avoid the architectural changes those would
-require, this patch solves things by dynamically allocating a list of
-structs (one per instance) in the provider's uclass-private area.
-
-Signed-off-by: Alper Nebi Yasak <alpernebiyasak@gmail.com>
-Reviewed-by: Simon Glass <sjg@chromium.org>
-Tested-by: Peter Robinson <pbrobinson@gmail.com> - Rock960
----
- drivers/phy/allwinner/phy-sun4i-usb.c |   9 --
- drivers/phy/phy-uclass.c              | 137 ++++++++++++++++++++++++++
- test/dm/phy.c                         |  83 +++++++++++++++-
- 3 files changed, 215 insertions(+), 14 deletions(-)
-
-diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
-index ab2a5d17fc..86c589a65f 100644
---- a/drivers/phy/allwinner/phy-sun4i-usb.c
-+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
-@@ -125,7 +125,6 @@ struct sun4i_usb_phy_info {
- 
- struct sun4i_usb_phy_plat {
- 	void __iomem *pmu;
--	int power_on_count;
- 	int gpio_vbus;
- 	int gpio_vbus_det;
- 	int gpio_id_det;
-@@ -225,10 +224,6 @@ static int sun4i_usb_phy_power_on(struct phy *phy)
- 		initial_usb_scan_delay = 0;
- 	}
- 
--	usb_phy->power_on_count++;
--	if (usb_phy->power_on_count != 1)
--		return 0;
--
- 	if (usb_phy->gpio_vbus >= 0)
- 		gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_UP);
- 
-@@ -240,10 +235,6 @@ static int sun4i_usb_phy_power_off(struct phy *phy)
- 	struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev);
- 	struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
- 
--	usb_phy->power_on_count--;
--	if (usb_phy->power_on_count != 0)
--		return 0;
--
- 	if (usb_phy->gpio_vbus >= 0)
- 		gpio_set_value(usb_phy->gpio_vbus, SUNXI_GPIO_PULL_DISABLE);
- 
-diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c
-index 706e9fdf3a..49e2ec25c2 100644
---- a/drivers/phy/phy-uclass.c
-+++ b/drivers/phy/phy-uclass.c
-@@ -11,12 +11,96 @@
- #include <dm/device_compat.h>
- #include <dm/devres.h>
- #include <generic-phy.h>
-+#include <linux/list.h>
-+
-+/**
-+ * struct phy_counts - Init and power-on counts of a single PHY port
-+ *
-+ * This structure is used to keep track of PHY initialization and power
-+ * state change requests, so that we don't power off and deinitialize a
-+ * PHY instance until all of its users want it done. Otherwise, multiple
-+ * consumers using the same PHY port can cause problems (e.g. one might
-+ * call power_off() after another's exit() and hang indefinitely).
-+ *
-+ * @id: The PHY ID within a PHY provider
-+ * @power_on_count: Times generic_phy_power_on() was called for this ID
-+ *                  without a matching generic_phy_power_off() afterwards
-+ * @init_count: Times generic_phy_init() was called for this ID
-+ *              without a matching generic_phy_exit() afterwards
-+ * @list: Handle for a linked list of these structures corresponding to
-+ *        ports of the same PHY provider
-+ */
-+struct phy_counts {
-+	unsigned long id;
-+	int power_on_count;
-+	int init_count;
-+	struct list_head list;
-+};
- 
- static inline struct phy_ops *phy_dev_ops(struct udevice *dev)
- {
- 	return (struct phy_ops *)dev->driver->ops;
- }
- 
-+static struct phy_counts *phy_get_counts(struct phy *phy)
-+{
-+	struct list_head *uc_priv;
-+	struct phy_counts *counts;
-+
-+	if (!generic_phy_valid(phy))
-+		return NULL;
-+
-+	uc_priv = dev_get_uclass_priv(phy->dev);
-+	list_for_each_entry(counts, uc_priv, list)
-+		if (counts->id == phy->id)
-+			return counts;
-+
-+	return NULL;
-+}
-+
-+static int phy_alloc_counts(struct phy *phy)
-+{
-+	struct list_head *uc_priv;
-+	struct phy_counts *counts;
-+
-+	if (!generic_phy_valid(phy))
-+		return 0;
-+	if (phy_get_counts(phy))
-+		return 0;
-+
-+	uc_priv = dev_get_uclass_priv(phy->dev);
-+	counts = kzalloc(sizeof(*counts), GFP_KERNEL);
-+	if (!counts)
-+		return -ENOMEM;
-+
-+	counts->id = phy->id;
-+	counts->power_on_count = 0;
-+	counts->init_count = 0;
-+	list_add(&counts->list, uc_priv);
-+
-+	return 0;
-+}
-+
-+static int phy_uclass_pre_probe(struct udevice *dev)
-+{
-+	struct list_head *uc_priv = dev_get_uclass_priv(dev);
-+
-+	INIT_LIST_HEAD(uc_priv);
-+
-+	return 0;
-+}
-+
-+static int phy_uclass_pre_remove(struct udevice *dev)
-+{
-+	struct list_head *uc_priv = dev_get_uclass_priv(dev);
-+	struct phy_counts *counts, *next;
-+
-+	list_for_each_entry_safe(counts, next, uc_priv, list)
-+		kfree(counts);
-+
-+	return 0;
-+}
-+
- static int generic_phy_xlate_offs_flags(struct phy *phy,
- 					struct ofnode_phandle_args *args)
- {
-@@ -88,6 +172,12 @@ int generic_phy_get_by_index_nodev(ofnode node, int index, struct phy *phy)
- 		goto err;
- 	}
- 
-+	ret = phy_alloc_counts(phy);
-+	if (ret) {
-+		debug("phy_alloc_counts() failed: %d\n", ret);
-+		goto err;
-+	}
-+
- 	return 0;
- 
- err:
-@@ -118,6 +208,7 @@ int generic_phy_get_by_name(struct udevice *dev, const char *phy_name,
- 
- int generic_phy_init(struct phy *phy)
- {
-+	struct phy_counts *counts;
- 	struct phy_ops const *ops;
- 	int ret;
- 
-@@ -126,10 +217,19 @@ int generic_phy_init(struct phy *phy)
- 	ops = phy_dev_ops(phy->dev);
- 	if (!ops->init)
- 		return 0;
-+
-+	counts = phy_get_counts(phy);
-+	if (counts->init_count > 0) {
-+		counts->init_count++;
-+		return 0;
-+	}
-+
- 	ret = ops->init(phy);
- 	if (ret)
- 		dev_err(phy->dev, "PHY: Failed to init %s: %d.\n",
- 			phy->dev->name, ret);
-+	else
-+		counts->init_count = 1;
- 
- 	return ret;
- }
-@@ -154,6 +254,7 @@ int generic_phy_reset(struct phy *phy)
- 
- int generic_phy_exit(struct phy *phy)
- {
-+	struct phy_counts *counts;
- 	struct phy_ops const *ops;
- 	int ret;
- 
-@@ -162,16 +263,28 @@ int generic_phy_exit(struct phy *phy)
- 	ops = phy_dev_ops(phy->dev);
- 	if (!ops->exit)
- 		return 0;
-+
-+	counts = phy_get_counts(phy);
-+	if (counts->init_count == 0)
-+		return 0;
-+	if (counts->init_count > 1) {
-+		counts->init_count--;
-+		return 0;
-+	}
-+
- 	ret = ops->exit(phy);
- 	if (ret)
- 		dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n",
- 			phy->dev->name, ret);
-+	else
-+		counts->init_count = 0;
- 
- 	return ret;
- }
- 
- int generic_phy_power_on(struct phy *phy)
- {
-+	struct phy_counts *counts;
- 	struct phy_ops const *ops;
- 	int ret;
- 
-@@ -180,16 +293,26 @@ int generic_phy_power_on(struct phy *phy)
- 	ops = phy_dev_ops(phy->dev);
- 	if (!ops->power_on)
- 		return 0;
-+
-+	counts = phy_get_counts(phy);
-+	if (counts->power_on_count > 0) {
-+		counts->power_on_count++;
-+		return 0;
-+	}
-+
- 	ret = ops->power_on(phy);
- 	if (ret)
- 		dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n",
- 			phy->dev->name, ret);
-+	else
-+		counts->power_on_count = 1;
- 
- 	return ret;
- }
- 
- int generic_phy_power_off(struct phy *phy)
- {
-+	struct phy_counts *counts;
- 	struct phy_ops const *ops;
- 	int ret;
- 
-@@ -198,10 +321,21 @@ int generic_phy_power_off(struct phy *phy)
- 	ops = phy_dev_ops(phy->dev);
- 	if (!ops->power_off)
- 		return 0;
-+
-+	counts = phy_get_counts(phy);
-+	if (counts->power_on_count == 0)
-+		return 0;
-+	if (counts->power_on_count > 1) {
-+		counts->power_on_count--;
-+		return 0;
-+	}
-+
- 	ret = ops->power_off(phy);
- 	if (ret)
- 		dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n",
- 			phy->dev->name, ret);
-+	else
-+		counts->power_on_count = 0;
- 
- 	return ret;
- }
-@@ -316,4 +450,7 @@ int generic_phy_power_off_bulk(struct phy_bulk *bulk)
- UCLASS_DRIVER(phy) = {
- 	.id		= UCLASS_PHY,
- 	.name		= "phy",
-+	.pre_probe	= phy_uclass_pre_probe,
-+	.pre_remove	= phy_uclass_pre_remove,
-+	.per_device_auto = sizeof(struct list_head),
- };
-diff --git a/test/dm/phy.c b/test/dm/phy.c
-index ecbd47bf12..df4c73fc70 100644
---- a/test/dm/phy.c
-+++ b/test/dm/phy.c
-@@ -79,12 +79,15 @@ static int dm_test_phy_ops(struct unit_test_state *uts)
- 	ut_assertok(generic_phy_power_off(&phy1));
- 
- 	/*
--	 * test operations after exit().
--	 * The sandbox phy driver does not allow it.
-+	 * Test power_on() failure after exit().
-+	 * The sandbox phy driver does not allow power-on/off after
-+	 * exit, but the uclass counts power-on/init calls and skips
-+	 * calling the driver's ops when e.g. powering off an already
-+	 * powered-off phy.
- 	 */
- 	ut_assertok(generic_phy_exit(&phy1));
- 	ut_assert(generic_phy_power_on(&phy1) != 0);
--	ut_assert(generic_phy_power_off(&phy1) != 0);
-+	ut_assertok(generic_phy_power_off(&phy1));
- 
- 	/*
- 	 * test normal operations again (after re-init)
-@@ -99,6 +102,17 @@ static int dm_test_phy_ops(struct unit_test_state *uts)
- 	 */
- 	ut_assertok(generic_phy_reset(&phy1));
- 
-+	/*
-+	 * Test power_off() failure after exit().
-+	 * For this we need to call exit() while the phy is powered-on,
-+	 * so that the uclass actually calls the driver's power-off()
-+	 * and reports the resulting failure.
-+	 */
-+	ut_assertok(generic_phy_power_on(&phy1));
-+	ut_assertok(generic_phy_exit(&phy1));
-+	ut_assert(generic_phy_power_off(&phy1) != 0);
-+	ut_assertok(generic_phy_power_on(&phy1));
-+
- 	/* PHY2 has a known problem with power off */
- 	ut_assertok(generic_phy_init(&phy2));
- 	ut_assertok(generic_phy_power_on(&phy2));
-@@ -106,8 +120,8 @@ static int dm_test_phy_ops(struct unit_test_state *uts)
- 
- 	/* PHY3 has a known problem with power off and power on */
- 	ut_assertok(generic_phy_init(&phy3));
--	ut_asserteq(-EIO, generic_phy_power_off(&phy3));
--	ut_asserteq(-EIO, generic_phy_power_off(&phy3));
-+	ut_asserteq(-EIO, generic_phy_power_on(&phy3));
-+	ut_assertok(generic_phy_power_off(&phy3));
- 
- 	return 0;
- }
-@@ -145,3 +159,62 @@ static int dm_test_phy_bulk(struct unit_test_state *uts)
- 	return 0;
- }
- DM_TEST(dm_test_phy_bulk, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
-+
-+static int dm_test_phy_multi_exit(struct unit_test_state *uts)
-+{
-+	struct phy phy1_method1;
-+	struct phy phy1_method2;
-+	struct phy phy1_method3;
-+	struct udevice *parent;
-+
-+	/* Get the same phy instance in 3 different ways. */
-+	ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS,
-+					      "gen_phy_user", &parent));
-+	ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method1));
-+	ut_asserteq(0, phy1_method1.id);
-+	ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method2));
-+	ut_asserteq(0, phy1_method2.id);
-+	ut_asserteq_ptr(phy1_method1.dev, phy1_method1.dev);
-+
-+	ut_assertok(uclass_get_device_by_name(UCLASS_SIMPLE_BUS,
-+					      "gen_phy_user1", &parent));
-+	ut_assertok(generic_phy_get_by_name(parent, "phy1", &phy1_method3));
-+	ut_asserteq(0, phy1_method3.id);
-+	ut_asserteq_ptr(phy1_method1.dev, phy1_method3.dev);
-+
-+	/*
-+	 * Test using the same PHY from different handles.
-+	 * In non-test code these could be in different drivers.
-+	 */
-+
-+	/*
-+	 * These must only call the driver's ops at the first init()
-+	 * and power_on().
-+	 */
-+	ut_assertok(generic_phy_init(&phy1_method1));
-+	ut_assertok(generic_phy_init(&phy1_method2));
-+	ut_assertok(generic_phy_power_on(&phy1_method1));
-+	ut_assertok(generic_phy_power_on(&phy1_method2));
-+	ut_assertok(generic_phy_init(&phy1_method3));
-+	ut_assertok(generic_phy_power_on(&phy1_method3));
-+
-+	/*
-+	 * These must not call the driver's ops as other handles still
-+	 * want the PHY powered-on and initialized.
-+	 */
-+	ut_assertok(generic_phy_power_off(&phy1_method3));
-+	ut_assertok(generic_phy_exit(&phy1_method3));
-+
-+	/*
-+	 * We would get an error here if the generic_phy_exit() above
-+	 * actually called the driver's exit(), as the sandbox driver
-+	 * doesn't allow power-off() after exit().
-+	 */
-+	ut_assertok(generic_phy_power_off(&phy1_method1));
-+	ut_assertok(generic_phy_power_off(&phy1_method2));
-+	ut_assertok(generic_phy_exit(&phy1_method1));
-+	ut_assertok(generic_phy_exit(&phy1_method2));
-+
-+	return 0;
-+}
-+DM_TEST(dm_test_phy_multi_exit, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
--- 
-2.33.1
-
diff --git a/2003-rockchip-sdhci-Fix-RK3399-eMMC-PHY-power-cycling.patch b/2002-rockchip-sdhci-Fix-RK3399-eMMC-PHY-power-cycling.patch
similarity index 100%
rename from 2003-rockchip-sdhci-Fix-RK3399-eMMC-PHY-power-cycling.patch
rename to 2002-rockchip-sdhci-Fix-RK3399-eMMC-PHY-power-cycling.patch
diff --git a/2004-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3399.patch b/2003-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3399.patch
similarity index 100%
rename from 2004-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3399.patch
rename to 2003-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3399.patch
diff --git a/2005-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3568.patch b/2004-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3568.patch
similarity index 100%
rename from 2005-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3568.patch
rename to 2004-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3568.patch
diff --git a/2006-mmc-sdhci-allow-disabling-sdma-in-spl.patch b/2005-mmc-sdhci-allow-disabling-sdma-in-spl.patch
similarity index 100%
rename from 2006-mmc-sdhci-allow-disabling-sdma-in-spl.patch
rename to 2005-mmc-sdhci-allow-disabling-sdma-in-spl.patch
diff --git a/PKGBUILD b/PKGBUILD
index ebb9f25..9a2afe7 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -5,13 +5,14 @@
 # Contributor: Dragan Simic <dsimic@buserror.io>
 
 pkgname=uboot-pinephonepro
-pkgver=2022.01
-pkgrel=0.2
+pkgver=2022.04rc3
+pkgrel=1
 epoch=4
 _tfaver=2.6
+_commit=589c659035a44a683b087fd75fe0b7667f7be7f5
 pkgdesc="U-Boot for Pine64 PinePhone Pro"
 arch=('aarch64')
-url='https://git.sr.ht/~martijnbraam/u-boot'
+url='https://source.denx.de/u-boot/u-boot'
 license=('GPL')
 makedepends=('git' 'arm-none-eabi-gcc' 'dtc' 'bc')
 depends=('uboot-tools')
@@ -25,30 +26,30 @@ source=("ftp://ftp.denx.de/pub/u-boot/u-boot-${pkgver/rc/-rc}.tar.bz2"
         "ppp-prepare-fstab.service"
         "ppp-uboot-flash"
         "ppp-uboot-mkscr"
+        "1000-upstream-${_commit}.patch::https://github.com/u-boot/u-boot/compare/v${pkgver/rc/-rc}...${_commit}.patch"
         "1001-Correct-boot-order-to-be-USB-SD-eMMC.patch"
         "1002-rockchip-Add-initial-support-for-the-PinePhone-Pro.patch"
         #"1003-Configure-USB-power-settings-for-PinePhone-Pro.patch"
         "1004-mtd-spi-nor-ids-Add-GigaDevice-GD25LQ128E-entry.patch"
-        "2001-phy-Track-power-on-and-init-counts-in-uclass.patch"
-        "2002-mmc-sdhci-Add-HS400-Enhanced-Strobe-support.patch"
-        "2003-rockchip-sdhci-Fix-RK3399-eMMC-PHY-power-cycling.patch"
-        "2004-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3399.patch"
-        "2005-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3568.patch"
-        "2006-mmc-sdhci-allow-disabling-sdma-in-spl.patch"
+        "2001-mmc-sdhci-Add-HS400-Enhanced-Strobe-support.patch"
+        "2002-rockchip-sdhci-Fix-RK3399-eMMC-PHY-power-cycling.patch"
+        "2003-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3399.patch"
+        "2004-rockchip-sdhci-Add-HS400-Enhanced-Strobe-support-for-RK3568.patch"
+        "2005-mmc-sdhci-allow-disabling-sdma-in-spl.patch"
         "3001-pinephone-pro-Remove-cargo-culted-iodomain-config.patch"
         "3002-pine64-pinephonePro-SPI-support.patch")
-sha256sums=('81b4543227db228c03f8a1bf5ddbc813b0bb8f6555ce46064ef721a6fc680413'
+sha256sums=('4731da5228dc35827a9d9ebc8f541b01aa6af36c27be24e10aff06e596bee2de'
             '4e59f02ccb042d5d18c89c849701b96e6cf4b788709564405354b5d313d173f7'
-            '4e356b3868c0c1ac061c2c15c7ba80c627e1743214680409f418f9b4c00eb3f7'
+            '12311da7e1a8d7bf19ddf78568e58da0888b0ca89e937aecccae4d896d20b7e2'
             'de7e36cdc7ed2fb5abb9155c97f87926361aa5be87d794c9016776160f3430ec'
             'e55fb02dfb6213eabbb899b468dc5f68d36a11c05feda4c14e80282415222fea'
             '6265fb9d3bc84bf1217383b52587b1d5a36372d88a824932586a802a502f62ba'
             '05eaccb2e8ea1eba3e86a4e7fcf12fd232195b5018c049ddf36e5a82a968cc24'
+            '527e061dba87b9a080517c27407bfaf883753cf2ddd2e302dbdaf6dca6888ecc'
             '017d33aac55f8a5ed22170c97b4792ba755a4dad04f6c0cdd85119bbc81e87b3'
             '7c3d76f4bee0e54900142043241248072e334387065212141e1f600afe0aafba'
             #'b750ba47843defafd8be1cc2615983c93e9cde5a4f5a7b55308a6f00f3fe6611'
             '1c9cc403f527733b9ef093505c147074ac5afa881380d65ae3819f2bad75c8cd'
-            'feb6ed9924f1b8f76066002cf3e414592e9ac8977f8e7aca8adc0c3d8bdb687f'
             '68ff1130b396cf106ee16fd2e697fc61eb6fb3e873d78551b8247de73386ed1e'
             'ee52b4374f159e648b6b21e40b399804c763bb3ddde60b016fcd6e0da8135f2f'
             '17e4adb43ac13a1297b5df8e1b7d3d03b555f5b5bc2085647e105cbd0897a238'
@@ -118,6 +119,11 @@ build() {
   update_config 'CONFIG_IDENT_STRING' '" Manjaro Linux ARM"'
   update_config 'CONFIG_BOOTDELAY' '0'
 
+  # Try a couple of SPI tweaks;  if actually needed, these options
+  # will be propely moved to a PinePhone Pro configuration patch later
+  update_config 'CONFIG_SPL_DM_SEQ_ALIAS' 'y'
+  update_config 'CONFIG_SF_DEFAULT_BUS' '1'
+
   # Disable DMA for eMMC, to make suspend/resume work;  this option
   # will be propely moved to a PinePhone Pro configuration patch later
   update_config 'CONFIG_SPL_MMC_SDHCI_SDMA' 'n'
diff --git a/boot.txt b/boot.txt
index 60e610a..909b741 100644
--- a/boot.txt
+++ b/boot.txt
@@ -19,7 +19,7 @@ gpio set 154
 part uuid ${devtype} ${devnum}:1 uuid_boot
 part uuid ${devtype} ${devnum}:2 uuid_root
 
-setenv bootargs loglevel=4 console=tty0 console=${console} earlycon=uart8250,mmio32,0xff1a0000 consoleblank=0 boot=PARTUUID=${uuid_boot} root=PARTUUID=${uuid_root} rw rootwait quiet audit=0 bootsplash.bootfile=bootsplash-themes/manjaro/bootsplash
+setenv bootargs loglevel=4 console=ttyS2,1500000 console=tty0 earlycon=uart8250,mmio32,0xff1a0000 consoleblank=0 boot=PARTUUID=${uuid_boot} root=PARTUUID=${uuid_root} rw rootwait quiet audit=0 bootsplash.bootfile=bootsplash-themes/manjaro/bootsplash
 
 if load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} /Image; then
   gpio clear 105
-- 
GitLab