Merge tag 'efi-2022-04-rc1' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request for efi-2022-04-rc1

Documentation:

* Fix building HTML documentation of readthedocs.io
* Add ARM Juno board documentation
* Build requirements for Alpine Linux
* Include DM headers in API documentation

UEFI:

* Fix section alignment of EFI binaries
* Fix header length of RISC-V EFI binaries allowing to run them on EDK II
* Remove kaslr-seed from device tree if the EFI_RNG_PROTOCOL is provided

Other:

* Let 'part list' show all 128 GPT partitions
diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig
index 0a3fdfa..9967376 100644
--- a/arch/arm/cpu/armv8/Kconfig
+++ b/arch/arm/cpu/armv8/Kconfig
@@ -102,7 +102,7 @@
 	bool "Use PSCI for reset and shutdown"
 	default y
 	select ARM_SMCCC if OF_CONTROL
-	depends on !ARCH_EXYNOS7 && !ARCH_BCM283X && \
+	depends on !ARCH_APPLE && !ARCH_BCM283X && !ARCH_EXYNOS7 && \
 		   !TARGET_LS2080AQDS && \
 		   !TARGET_LS2080ARDB && !TARGET_LS2080A_EMU && \
 		   !TARGET_LS1088ARDB && !TARGET_LS1088AQDS && \
diff --git a/cmd/adc.c b/cmd/adc.c
index 16f914a..75739bc 100644
--- a/cmd/adc.c
+++ b/cmd/adc.c
@@ -81,8 +81,8 @@
 	ret = adc_channel_single_shot(argv[1], simple_strtol(argv[2], NULL, 0),
 				      &data);
 	if (ret) {
-		printf("Error getting single shot for device %s channel %s\n",
-		       argv[1], argv[2]);
+		printf("Error getting single shot for device %s channel %s (ret=%d)\n",
+		       argv[1], argv[2], ret);
 		return CMD_RET_FAILURE;
 	}
 
diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
index f8434ca..74c9348 100644
--- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
@@ -1632,7 +1632,7 @@
 					mtd->oobsize / trans,
 					host->hwcfg.sector_size_1k);
 
-		if (!ret) {
+		if (ret != -EBADMSG) {
 			*err_addr = brcmnand_read_reg(ctrl,
 					BRCMNAND_UNCORR_ADDR) |
 				((u64)(brcmnand_read_reg(ctrl,
diff --git a/drivers/nvme/nvme_show.c b/drivers/nvme/nvme_show.c
index 15e459d..72cbac8 100644
--- a/drivers/nvme/nvme_show.c
+++ b/drivers/nvme/nvme_show.c
@@ -106,24 +106,41 @@
 {
 	struct nvme_ns *ns = dev_get_priv(udev);
 	struct nvme_dev *dev = ns->dev;
-	ALLOC_CACHE_ALIGN_BUFFER(char, buf_ns, sizeof(struct nvme_id_ns));
-	struct nvme_id_ns *id = (struct nvme_id_ns *)buf_ns;
-	ALLOC_CACHE_ALIGN_BUFFER(char, buf_ctrl, sizeof(struct nvme_id_ctrl));
-	struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf_ctrl;
+	struct nvme_id_ctrl *ctrl;
+	struct nvme_id_ns *id;
+	int ret = 0;
 
-	if (nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl))
-		return -EIO;
+	ctrl = memalign(dev->page_size, sizeof(struct nvme_id_ctrl));
+	if (!ctrl)
+		return -ENOMEM;
+
+	if (nvme_identify(dev, 0, 1, (dma_addr_t)(long)ctrl)) {
+		ret = -EIO;
+		goto free_ctrl;
+	}
 
 	print_optional_admin_cmd(le16_to_cpu(ctrl->oacs), ns->devnum);
 	print_optional_nvm_cmd(le16_to_cpu(ctrl->oncs), ns->devnum);
 	print_format_nvme_attributes(ctrl->fna, ns->devnum);
 
-	if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)(long)id))
-		return -EIO;
+	id = memalign(dev->page_size, sizeof(struct nvme_id_ns));
+	if (!id) {
+		ret = -ENOMEM;
+		goto free_ctrl;
+	}
+
+	if (nvme_identify(dev, ns->ns_id, 0, (dma_addr_t)(long)id)) {
+		ret = -EIO;
+		goto free_id;
+	}
 
 	print_formats(id, ns);
 	print_data_protect_cap(id->dpc, ns->devnum);
 	print_metadata_cap(id->mc, ns->devnum);
 
-	return 0;
+free_id:
+	free(id);
+free_ctrl:
+	free(ctrl);
+	return ret;
 }
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index c0acf33..c796892 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -5,6 +5,7 @@
  * Author: Matt Porter <mporter@mvista.com>
  *
  * Copyright 2000 MontaVista Software Inc.
+ * Copyright (c) 2021  Maciej W. Rozycki <macro@orcam.me.uk>
  */
 
 #include <common.h>
@@ -12,6 +13,7 @@
 #include <errno.h>
 #include <log.h>
 #include <pci.h>
+#include <time.h>
 #include "pci_internal.h"
 
 /* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */
@@ -180,6 +182,168 @@
 	dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x80);
 }
 
+/*
+ * Check if the link of a downstream PCIe port operates correctly.
+ *
+ * For that check if the optional Data Link Layer Link Active status gets
+ * on within a 200ms period or failing that wait until the completion of
+ * that period and check if link training has shown the completed status
+ * continuously throughout the second half of that period.
+ *
+ * Observation with the ASMedia ASM2824 Gen 3 switch indicates it takes
+ * 11-44ms to indicate the Data Link Layer Link Active status at 2.5GT/s,
+ * though it may take a couple of link training iterations.
+ */
+static bool dm_pciauto_exp_link_stable(struct udevice *dev, int pcie_off)
+{
+	u64 loops = 0, trcount = 0, ntrcount = 0, flips = 0;
+	bool dllla, lnktr, plnktr;
+	u16 exp_lnksta;
+	pci_dev_t bdf;
+	u64 end;
+
+	dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKSTA, &exp_lnksta);
+	plnktr = !!(exp_lnksta & PCI_EXP_LNKSTA_LT);
+
+	end = get_ticks() + usec_to_tick(200000);
+	do {
+		dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKSTA,
+				     &exp_lnksta);
+		dllla = !!(exp_lnksta & PCI_EXP_LNKSTA_DLLLA);
+		lnktr = !!(exp_lnksta & PCI_EXP_LNKSTA_LT);
+
+		flips += plnktr ^ lnktr;
+		if (lnktr) {
+			ntrcount = 0;
+			trcount++;
+		} else {
+			ntrcount++;
+		}
+		loops++;
+
+		plnktr = lnktr;
+	} while (!dllla && get_ticks() < end);
+
+	bdf = dm_pci_get_bdf(dev);
+	debug("PCI Autoconfig: %02x.%02x.%02x: Fixup link: DL active: %u; "
+	      "%3llu flips, %6llu loops of which %6llu while training, "
+	      "final %6llu stable\n",
+	      PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf),
+	      (unsigned int)dllla,
+	      (unsigned long long)flips, (unsigned long long)loops,
+	      (unsigned long long)trcount, (unsigned long long)ntrcount);
+
+	return dllla || ntrcount >= loops / 2;
+}
+
+/*
+ * Retrain the link of a downstream PCIe port by hand if necessary.
+ *
+ * This is needed at least where a downstream port of the ASMedia ASM2824
+ * Gen 3 switch is wired to the upstream port of the Pericom PI7C9X2G304
+ * Gen 2 switch, and observed with the Delock Riser Card PCI Express x1 >
+ * 2 x PCIe x1 device, P/N 41433, plugged into the SiFive HiFive Unmatched
+ * board.
+ *
+ * In such a configuration the switches are supposed to negotiate the link
+ * speed of preferably 5.0GT/s, falling back to 2.5GT/s.  However the link
+ * continues switching between the two speeds indefinitely and the data
+ * link layer never reaches the active state, with link training reported
+ * repeatedly active ~84% of the time.  Forcing the target link speed to
+ * 2.5GT/s with the upstream ASM2824 device makes the two switches talk to
+ * each other correctly however.  And more interestingly retraining with a
+ * higher target link speed afterwards lets the two successfully negotiate
+ * 5.0GT/s.
+ *
+ * As this can potentially happen with any device and is cheap in the case
+ * of correctly operating hardware, let's do it for all downstream ports,
+ * for root complexes, PCIe switches and PCI/PCI-X to PCIe bridges.
+ *
+ * First check if automatic link training may have failed to complete, as
+ * indicated by the optional Data Link Layer Link Active status being off
+ * and the Link Bandwidth Management Status indicating that hardware has
+ * changed the link speed or width in an attempt to correct unreliable
+ * link operation.  If this is the case, then check if the link operates
+ * correctly by seeing whether it is being trained excessively.  If it is,
+ * then conclude the link is broken.
+ *
+ * In that case restrict the speed to 2.5GT/s, observing that the Target
+ * Link Speed field is sticky and therefore the link will stay restricted
+ * even after a device reset is later made by an OS that is unaware of the
+ * problem.  With the speed restricted request that the link be retrained
+ * and check again if the link operates correctly.  If not, then set the
+ * Target Link Speed back to the original value.
+ *
+ * This requires the presence of the Link Control 2 register, so make sure
+ * the PCI Express Capability Version is at least 2.  Also don't try, for
+ * obvious reasons, to limit the speed if 2.5GT/s is the only link speed
+ * supported.
+ */
+static void dm_pciauto_exp_fixup_link(struct udevice *dev, int pcie_off)
+{
+	u16 exp_lnksta, exp_lnkctl, exp_lnkctl2;
+	u16 exp_flags, exp_type, exp_version;
+	u32 exp_lnkcap;
+	pci_dev_t bdf;
+
+	dm_pci_read_config16(dev, pcie_off + PCI_EXP_FLAGS, &exp_flags);
+	exp_version = exp_flags & PCI_EXP_FLAGS_VERS;
+	if (exp_version < 2)
+		return;
+
+	exp_type = (exp_flags & PCI_EXP_FLAGS_TYPE) >> 4;
+	switch (exp_type) {
+	case PCI_EXP_TYPE_ROOT_PORT:
+	case PCI_EXP_TYPE_DOWNSTREAM:
+	case PCI_EXP_TYPE_PCIE_BRIDGE:
+		break;
+	default:
+		return;
+	}
+
+	dm_pci_read_config32(dev, pcie_off + PCI_EXP_LNKCAP, &exp_lnkcap);
+	if ((exp_lnkcap & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+		return;
+
+	dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKSTA, &exp_lnksta);
+	if ((exp_lnksta & (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_DLLLA)) !=
+	    PCI_EXP_LNKSTA_LBMS)
+		return;
+
+	if (dm_pciauto_exp_link_stable(dev, pcie_off))
+		return;
+
+	bdf = dm_pci_get_bdf(dev);
+	printf("PCI Autoconfig: %02x.%02x.%02x: "
+	       "Downstream link non-functional\n",
+	       PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+	printf("PCI Autoconfig: %02x.%02x.%02x: "
+	       "Retrying with speed restricted to 2.5GT/s...\n",
+	       PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+	dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKCTL, &exp_lnkctl);
+	dm_pci_read_config16(dev, pcie_off + PCI_EXP_LNKCTL2, &exp_lnkctl2);
+
+	dm_pci_write_config16(dev, pcie_off + PCI_EXP_LNKCTL2,
+			      (exp_lnkctl2 & ~PCI_EXP_LNKCTL2_TLS) |
+			      PCI_EXP_LNKCTL2_TLS_2_5GT);
+	dm_pci_write_config16(dev, pcie_off + PCI_EXP_LNKCTL,
+			      exp_lnkctl | PCI_EXP_LNKCTL_RL);
+
+	if (dm_pciauto_exp_link_stable(dev, pcie_off)) {
+		printf("PCI Autoconfig: %02x.%02x.%02x: Succeeded!\n",
+		       PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+	} else {
+		printf("PCI Autoconfig: %02x.%02x.%02x: Failed!\n",
+		       PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
+
+		dm_pci_write_config16(dev, pcie_off + PCI_EXP_LNKCTL2,
+				      exp_lnkctl2);
+		dm_pci_write_config16(dev, pcie_off + PCI_EXP_LNKCTL,
+				      exp_lnkctl | PCI_EXP_LNKCTL_RL);
+	}
+}
+
 void dm_pciauto_prescan_setup_bridge(struct udevice *dev, int sub_bus)
 {
 	struct pci_region *pci_mem;
@@ -189,6 +353,7 @@
 	u8 io_32;
 	struct udevice *ctlr = pci_get_controller(dev);
 	struct pci_controller *ctlr_hose = dev_get_uclass_priv(ctlr);
+	int pcie_off;
 
 	pci_mem = ctlr_hose->pci_mem;
 	pci_prefetch = ctlr_hose->pci_prefetch;
@@ -275,6 +440,11 @@
 		}
 	}
 
+	/* For PCIe devices see if we need to retrain the link by hand */
+	pcie_off = dm_pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (pcie_off)
+		dm_pciauto_exp_fixup_link(dev, pcie_off);
+
 	/* Enable memory and I/O accesses, enable bus master */
 	dm_pci_write_config16(dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER);
 }
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index ab2a5d1..86c589a 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_plat {
 	void __iomem *pmu;
-	int power_on_count;
 	int gpio_vbus;
 	int gpio_vbus_det;
 	int gpio_id_det;
@@ -225,10 +224,6 @@
 		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 @@
 	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 706e9fd..49e2ec2 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 @@
 		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_init(struct phy *phy)
 {
+	struct phy_counts *counts;
 	struct phy_ops const *ops;
 	int ret;
 
@@ -126,10 +217,19 @@
 	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_exit(struct phy *phy)
 {
+	struct phy_counts *counts;
 	struct phy_ops const *ops;
 	int ret;
 
@@ -162,16 +263,28 @@
 	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 @@
 	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 @@
 	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 @@
 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/env/fat.c b/env/fat.c
index 9d37d26..fdccd6c 100644
--- a/env/fat.c
+++ b/env/fat.c
@@ -77,7 +77,7 @@
 		 * This printf is embedded in the messages from env_save that
 		 * will calling it. The missing \n is intentional.
 		 */
-		printf("Unable to use %s %d:%d... ",
+		printf("Unable to use %s %d:%d... \n",
 		       CONFIG_ENV_FAT_INTERFACE, dev, part);
 		return 1;
 	}
@@ -93,7 +93,7 @@
 		 * This printf is embedded in the messages from env_save that
 		 * will calling it. The missing \n is intentional.
 		 */
-		printf("Unable to write \"%s\" from %s%d:%d... ",
+		printf("Unable to write \"%s\" from %s%d:%d... \n",
 			file, CONFIG_ENV_FAT_INTERFACE, dev, part);
 		return 1;
 	}
@@ -135,7 +135,7 @@
 		 * This printf is embedded in the messages from env_save that
 		 * will calling it. The missing \n is intentional.
 		 */
-		printf("Unable to use %s %d:%d... ",
+		printf("Unable to use %s %d:%d... \n",
 		       CONFIG_ENV_FAT_INTERFACE, dev, part);
 		goto err_env_relocate;
 	}
@@ -153,7 +153,7 @@
 		 * This printf is embedded in the messages from env_save that
 		 * will calling it. The missing \n is intentional.
 		 */
-		printf("Unable to read \"%s\" from %s%d:%d... ",
+		printf("Unable to read \"%s\" from %s%d:%d... \n",
 			CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part);
 		goto err_env_relocate;
 	}
diff --git a/include/configs/qemu-arm.h b/include/configs/qemu-arm.h
index 1287fd1..9fc53b4 100644
--- a/include/configs/qemu-arm.h
+++ b/include/configs/qemu-arm.h
@@ -21,11 +21,35 @@
 
 /* Environment options */
 
+#if CONFIG_IS_ENABLED(CMD_USB)
+# define BOOT_TARGET_USB(func) func(USB, usb, 0)
+#else
+# define BOOT_TARGET_USB(func)
+#endif
+
+#if CONFIG_IS_ENABLED(CMD_SCSI)
+# define BOOT_TARGET_SCSI(func) func(SCSI, scsi, 0)
+#else
+# define BOOT_TARGET_SCSI(func)
+#endif
+
+#if CONFIG_IS_ENABLED(CMD_VIRTIO)
+# define BOOT_TARGET_VIRTIO(func) func(VIRTIO, virtio, 0)
+#else
+# define BOOT_TARGET_VIRTIO(func)
+#endif
+
+#if CONFIG_IS_ENABLED(CMD_DHCP)
+# define BOOT_TARGET_DHCP(func) func(DHCP, dhcp, na)
+#else
+# define BOOT_TARGET_DHCP(func)
+#endif
+
 #define BOOT_TARGET_DEVICES(func) \
-	func(USB, usb, 0) \
-	func(SCSI, scsi, 0) \
-	func(VIRTIO, virtio, 0) \
-	func(DHCP, dhcp, na)
+	BOOT_TARGET_USB(func) \
+	BOOT_TARGET_SCSI(func) \
+	BOOT_TARGET_VIRTIO(func) \
+	BOOT_TARGET_DHCP(func)
 
 #include <config_distro_bootcmd.h>
 
diff --git a/include/pci.h b/include/pci.h
index 0ea41a7..ad1171b 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -5,6 +5,7 @@
  *
  * (C) Copyright 2002
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Copyright (c) 2021  Maciej W. Rozycki <macro@orcam.me.uk>
  */
 
 #ifndef _PCI_H
@@ -475,16 +476,24 @@
 
 /* PCI Express capabilities */
 #define PCI_EXP_FLAGS		2	/* Capabilities register */
+#define  PCI_EXP_FLAGS_VERS	0x000f	/* Capability Version */
 #define  PCI_EXP_FLAGS_TYPE	0x00f0	/* Device/Port type */
-#define  PCI_EXP_TYPE_ROOT_PORT 0x4	/* Root Port */
+#define   PCI_EXP_TYPE_ROOT_PORT   0x4	/* Root Port */
+#define   PCI_EXP_TYPE_DOWNSTREAM  0x6	/* Downstream Port */
+#define   PCI_EXP_TYPE_PCIE_BRIDGE 0x8	/* PCI/PCI-X to PCIe Bridge */
 #define PCI_EXP_DEVCAP		4	/* Device capabilities */
 #define  PCI_EXP_DEVCAP_FLR	0x10000000 /* Function Level Reset */
 #define PCI_EXP_DEVCTL		8	/* Device Control */
 #define  PCI_EXP_DEVCTL_BCR_FLR	0x8000  /* Bridge Configuration Retry / FLR */
 #define PCI_EXP_LNKCAP		12	/* Link Capabilities */
 #define  PCI_EXP_LNKCAP_SLS	0x0000000f /* Supported Link Speeds */
+#define  PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
+#define  PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
+#define  PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
 #define  PCI_EXP_LNKCAP_MLW	0x000003f0 /* Maximum Link Width */
 #define  PCI_EXP_LNKCAP_DLLLARC	0x00100000 /* Data Link Layer Link Active Reporting Capable */
+#define PCI_EXP_LNKCTL		16	/* Link Control */
+#define  PCI_EXP_LNKCTL_RL	0x0020	/* Retrain Link */
 #define PCI_EXP_LNKSTA		18	/* Link Status */
 #define  PCI_EXP_LNKSTA_CLS	0x000f	/* Current Link Speed */
 #define  PCI_EXP_LNKSTA_CLS_2_5GB 0x0001 /* Current Link Speed 2.5GT/s */
@@ -492,7 +501,9 @@
 #define  PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */
 #define  PCI_EXP_LNKSTA_NLW	0x03f0	/* Negotiated Link Width */
 #define  PCI_EXP_LNKSTA_NLW_SHIFT 4	/* start of NLW mask in link status */
+#define  PCI_EXP_LNKSTA_LT	0x0800	/* Link Training */
 #define  PCI_EXP_LNKSTA_DLLLA	0x2000	/* Data Link Layer Link Active */
+#define  PCI_EXP_LNKSTA_LBMS	0x4000	/* Link Bandwidth Management Status */
 #define PCI_EXP_SLTCAP		20	/* Slot Capabilities */
 #define  PCI_EXP_SLTCAP_PSN	0xfff80000 /* Physical Slot Number */
 #define PCI_EXP_RTCTL		28	/* Root Control */
@@ -503,8 +514,14 @@
 #define  PCI_EXP_DEVCAP2_ARI	0x00000020 /* ARI Forwarding Supported */
 #define PCI_EXP_DEVCTL2		40	/* Device Control 2 */
 #define  PCI_EXP_DEVCTL2_ARI	0x0020 /* Alternative Routing-ID */
-
+#define PCI_EXP_LNKCAP2		44	/* Link Capability 2 */
+#define  PCI_EXP_LNKCAP2_SLS	0x000000fe /* Supported Link Speeds Vector */
 #define PCI_EXP_LNKCTL2		48	/* Link Control 2 */
+#define  PCI_EXP_LNKCTL2_TLS	0x000f	/* Target Link Speed */
+#define  PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Target Link Speed 2.5GT/s */
+#define  PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Target Link Speed 5.0GT/s */
+#define  PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Target Link Speed 8.0GT/s */
+
 /* Single Root I/O Virtualization Registers */
 #define PCI_SRIOV_CAP		0x04	/* SR-IOV Capabilities */
 #define PCI_SRIOV_CTRL		0x08	/* SR-IOV Control */
diff --git a/include/vsprintf.h b/include/vsprintf.h
index b474630..8bfafa0 100644
--- a/include/vsprintf.h
+++ b/include/vsprintf.h
@@ -308,6 +308,14 @@
 void str_to_upper(const char *in, char *out, size_t len);
 
 /**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	format of buffer
+ * @args:	arguments
+ */
+int vsscanf(const char *inp, char const *fmt0, va_list ap);
+
+/**
  * sscanf - Unformat a buffer into a list of arguments
  * @buf:	input buffer
  * @fmt:	formatting of buffer
diff --git a/lib/Kconfig b/lib/Kconfig
index 1883ac7..35fc9e4 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -837,11 +837,11 @@
 	  Define the number of supported reserved regions in the library logical
 	  memory blocks.
 
-endmenu
-
 config PHANDLE_CHECK_SEQ
 	bool "Enable phandle check while getting sequence number"
 	help
 	  When there are multiple device tree nodes with same name,
           enable this config option to distinguish them using
 	  phandles in fdtdec_get_alias_seq() function.
+
+endmenu
diff --git a/lib/image-sparse.c b/lib/image-sparse.c
index d80fdbb..5ec0f94 100644
--- a/lib/image-sparse.c
+++ b/lib/image-sparse.c
@@ -46,9 +46,66 @@
 #include <asm/cache.h>
 
 #include <linux/math64.h>
+#include <linux/err.h>
 
 static void default_log(const char *ignored, char *response) {}
 
+static lbaint_t write_sparse_chunk_raw(struct sparse_storage *info,
+				       lbaint_t blk, lbaint_t blkcnt,
+				       void *data,
+				       char *response)
+{
+	lbaint_t n = blkcnt, write_blks, blks = 0, aligned_buf_blks = 100;
+	uint32_t *aligned_buf = NULL;
+
+	if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) {
+		write_blks = info->write(info, blk, n, data);
+		if (write_blks < n)
+			goto write_fail;
+
+		return write_blks;
+	}
+
+	aligned_buf = memalign(ARCH_DMA_MINALIGN, info->blksz * aligned_buf_blks);
+	if (!aligned_buf) {
+		info->mssg("Malloc failed for: CHUNK_TYPE_RAW", response);
+		return -ENOMEM;
+	}
+
+	while (blkcnt > 0) {
+		n = min(aligned_buf_blks, blkcnt);
+		memcpy(aligned_buf, data, n * info->blksz);
+
+		/* write_blks might be > n due to NAND bad-blocks */
+		write_blks = info->write(info, blk + blks, n, aligned_buf);
+		if (write_blks < n) {
+			free(aligned_buf);
+			goto write_fail;
+		}
+
+		blks += write_blks;
+		data += n * info->blksz;
+		blkcnt -= n;
+	}
+
+	free(aligned_buf);
+	return blks;
+
+write_fail:
+	if (IS_ERR_VALUE(write_blks)) {
+		printf("%s: Write failed, block #" LBAFU " [" LBAFU "] (%lld)\n",
+		       __func__, blk + blks, n, (long long)write_blks);
+		info->mssg("flash write failure", response);
+		return write_blks;
+	}
+
+	/* write_blks < n */
+	printf("%s: Write failed, block #" LBAFU " [" LBAFU "]\n",
+	       __func__, blk + blks, n);
+	info->mssg("flash write failure(incomplete)", response);
+	return -1;
+}
+
 int write_sparse_image(struct sparse_storage *info,
 		       const char *part_name, void *data, char *response)
 {
@@ -152,15 +209,11 @@
 				return -1;
 			}
 
-			blks = info->write(info, blk, blkcnt, data);
-			/* blks might be > blkcnt (eg. NAND bad-blocks) */
-			if (blks < blkcnt) {
-				printf("%s: %s" LBAFU " [" LBAFU "]\n",
-				       __func__, "Write failed, block #",
-				       blk, blks);
-				info->mssg("flash write failure", response);
+			blks = write_sparse_chunk_raw(info, blk, blkcnt,
+						      data, response);
+			if (blks < 0)
 				return -1;
-			}
+
 			blk += blks;
 			bytes_written += ((u64)blkcnt) * info->blksz;
 			total_blocks += chunk_header->chunk_sz;
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 5696d3a..cf59e2b 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2617,7 +2617,7 @@
 	}
 
 	# Do not disable fdt / initrd relocation
-	if ($rawline =~ /.*(fdt|initrd)_high=0xffffffff/) {
+	if ($rawline =~ /^\+.*(fdt|initrd)_high=0xffffffff/) {
 		ERROR("DISABLE_FDT_OR_INITRD_RELOC",
 		     "fdt or initrd relocation disabled at boot time\n" . $herecurr);
 	}
diff --git a/test/dm/phy.c b/test/dm/phy.c
index ecbd47b..df4c73f 100644
--- a/test/dm/phy.c
+++ b/test/dm/phy.c
@@ -79,12 +79,15 @@
 	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 @@
 	 */
 	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 @@
 
 	/* 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 @@
 	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);
diff --git a/test/py/tests/test_lsblk.py b/test/py/tests/test_lsblk.py
index 40ffe01..a719a48 100644
--- a/test/py/tests/test_lsblk.py
+++ b/test/py/tests/test_lsblk.py
@@ -4,6 +4,7 @@
 
 import pytest
 
+@pytest.mark.boardspec('sandbox')
 @pytest.mark.buildconfigspec('blk')
 @pytest.mark.buildconfigspec('cmd_lsblk')
 def test_lsblk(u_boot_console):