Merge tag 'u-boot-at91-2022.04-b' of https://source.denx.de/u-boot/custodians/u-boot-at91

Second set of u-boot-at91 features for the 2022.04 cycle:

This small feature set includes few changes for sama7g5 and sama7g5ek:
turn blue led on at boot, changes required for the Rev4 of the board,
better sync with the Linux DT with regards to the new DT nodes.
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml
index 670bbc0..c0f72a8 100644
--- a/.azure-pipelines.yml
+++ b/.azure-pipelines.yml
@@ -2,14 +2,16 @@
   windows_vm: windows-2019
   ubuntu_vm: ubuntu-18.04
   macos_vm: macOS-10.15
-  ci_runner_image: trini/u-boot-gitlab-ci-runner:focal-20211006-14Nov2021
+  ci_runner_image: trini/u-boot-gitlab-ci-runner:focal-20220105-10Jan2022
   # Add '-u 0' options for Azure pipelines, otherwise we get "permission
   # denied" error when it tries to "useradd -m -u 1001 vsts_azpcontainer",
   # since our $(ci_runner_image) user is not root.
   container_option: -u 0
   work_dir: /u
 
-jobs:
+stages:
+- stage: testsuites
+  jobs:
   - job: tools_only_windows
     displayName: 'Ensure host tools build for Windows'
     pool:
@@ -199,6 +201,8 @@
           export PATH=/opt/gcc-11.1.0-nolibc/arm-linux-gnueabi/bin:$PATH
           test/nokia_rx51_test.sh
 
+- stage: test_py
+  jobs:
   - job: test_py
     displayName: 'test.py'
     pool:
@@ -381,6 +385,8 @@
           # Some tests using libguestfs-tools need the fuse device to run
           docker run "$@" --device /dev/fuse:/dev/fuse -v $PWD:$(work_dir) $(ci_runner_image) /bin/bash $(work_dir)/test.sh
 
+- stage: world_build
+  jobs:
   - job: build_the_world
     displayName: 'Build the World'
     pool:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d06cca4..4c44c01 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,7 +2,7 @@
 
 # Grab our configured image.  The source for this is found at:
 # https://source.denx.de/u-boot/gitlab-ci-runner
-image: trini/u-boot-gitlab-ci-runner:focal-20211006-14Nov2021
+image: trini/u-boot-gitlab-ci-runner:focal-20220105-10Jan2022
 
 # We run some tests in different order, to catch some failures quicker.
 stages:
diff --git a/.readthedocs.yml b/.readthedocs.yml
index 44949ea..7c6c255 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -5,6 +5,13 @@
 # Required
 version: 2
 
+build:
+  os: "ubuntu-20.04"
+  apt_packages:
+    - python3-six
+  tools:
+    python: "3.9"
+
 # Build documentation in the docs/ directory with Sphinx
 sphinx:
   configuration: doc/conf.py
@@ -12,8 +19,6 @@
 # Optionally build your docs in additional formats such as PDF and ePub
 formats: []
 
-# Optionally set the version of Python and requirements required to build your docs
-# python:
-#   version: 3.7
-#   install:
-#     - requirements: docs/requirements.txt
+python:
+  install:
+    - requirements: doc/sphinx/requirements.txt
diff --git a/MAINTAINERS b/MAINTAINERS
index f4bd3d7..38c68ee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -116,6 +116,7 @@
 F:	configs/apple_m1_defconfig
 F:	drivers/iommu/apple_dart.c
 F:	drivers/pinctrl/pinctrl-apple.c
+F:	drivers/watchdog/apple_wdt.c
 F:	include/configs/apple.h
 
 ARM
@@ -736,7 +737,6 @@
 
 EFI PAYLOAD
 M:	Heinrich Schuchardt <xypron.glpk@gmx.de>
-R:	Alexander Graf <agraf@csgraf.de>
 S:	Maintained
 T:	git https://source.denx.de/u-boot/custodians/u-boot-efi.git
 F:	doc/api/efi.rst
diff --git a/Makefile b/Makefile
index 95afb98..b08bad4 100644
--- a/Makefile
+++ b/Makefile
@@ -1129,6 +1129,10 @@
 	$(call deprecated,CONFIG_DM_ETH,Ethernet drivers,v2020.07,$(CONFIG_NET))
 	$(call deprecated,CONFIG_DM_I2C,I2C drivers,v2022.04,$(CONFIG_SYS_I2C_LEGACY))
 	$(call deprecated,CONFIG_DM_KEYBOARD,Keyboard drivers,v2022.10,$(CONFIG_KEYBOARD))
+	@# CONFIG_SYS_TIMER_RATE has brackets in it for some boards which
+	@# confuses this rule. Use if() to send just a single character which
+	@# is enable to tell 'deprecated' that one of these symbols exists
+	$(call deprecated,CONFIG_TIMER,Timer drivers,v2023.01,$(if $(strip $(CONFIG_SYS_TIMER_RATE)$(CONFIG_SYS_TIMER_COUNTER)),x))
 	@# Check that this build does not use CONFIG options that we do not
 	@# know about unless they are in Kconfig. All the existing CONFIG
 	@# options are whitelisted, so new ones should not be added.
@@ -1777,9 +1781,9 @@
 quiet_cmd_u-boot__ ?= LD      $@
       cmd_u-boot__ ?= $(LD) $(KBUILD_LDFLAGS) $(LDFLAGS_u-boot) -o $@		\
 		-T u-boot.lds $(u-boot-init)					\
-		$(if $(CONFIG_EFI_APP_64BIT),,--whole-archive)			\
+		--whole-archive							\
 			$(u-boot-main)						\
-		$(if $(CONFIG_EFI_APP_64BIT),,--no-whole-archive)		\
+		--no-whole-archive						\
 		$(PLATFORM_LIBS) -Map u-boot.map;				\
 		$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
 endif
@@ -2184,7 +2188,9 @@
 	       u-boot* MLO* SPL System.map fit-dtb.blob* \
 	       u-boot-ivt.img.log u-boot-dtb.imx.log SPL.log u-boot.imx.log \
 	       lpc32xx-* bl31.c bl31.elf bl31_*.bin image.map tispl.bin* \
-	       idbloader.img flash.bin flash.log defconfig keep-syms-lto.c
+	       idbloader.img flash.bin flash.log defconfig keep-syms-lto.c \
+	       mkimage-out.spl.mkimage mkimage.spl.mkimage imx-boot.map \
+	       itb.fit.fit itb.fit.itb itb.map spl.map
 
 # Directories & files removed with 'make mrproper'
 MRPROPER_DIRS  += include/config include/generated spl tpl \
diff --git a/README b/README
index 77782d0..5549849 100644
--- a/README
+++ b/README
@@ -2912,8 +2912,7 @@
 * Target Operating System (Provisions for OpenBSD, NetBSD, FreeBSD,
   4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks,
   LynxOS, pSOS, QNX, RTEMS, INTEGRITY;
-  Currently supported: Linux, NetBSD, VxWorks, QNX, RTEMS, LynxOS,
-  INTEGRITY).
+  Currently supported: Linux, NetBSD, VxWorks, QNX, RTEMS, INTEGRITY).
 * Target CPU Architecture (Provisions for Alpha, ARM, Intel x86,
   IA64, MIPS, NDS32, Nios II, PowerPC, IBM S390, SuperH, Sparc, Sparc 64 Bit;
   Currently supported: ARM, Intel x86, MIPS, NDS32, Nios II, PowerPC).
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 7264d72..4495497 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -942,6 +942,12 @@
 	select OF_CONTROL
 	select PINCTRL
 	select POSITION_INDEPENDENT
+	select POWER_DOMAIN
+	select REGMAP
+	select SYSCON
+	select SYSRESET
+	select SYSRESET_WATCHDOG
+	select SYSRESET_WATCHDOG_AUTO
 	select USB
 	imply CMD_DM
 	imply CMD_GPT
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/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c
index 41c89b8..60769e1 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch2_serdes.c
@@ -249,7 +249,7 @@
 
 	/*
 	 * If SVDD set failed, will not return directly, so that the
-	 * serdes lanes can complete reseting.
+	 * serdes lanes can complete resetting.
 	 */
 	ret = set_serdes_volt(svdd_tar);
 	if (ret)
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index aeaec71..1b65e65 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -34,7 +34,10 @@
 
 dtb-$(CONFIG_ARCH_APPLE) += \
 	t8103-j274.dtb \
-	t8103-j293.dtb
+	t8103-j293.dtb \
+	t8103-j313.dtb \
+	t8103-j456.dtb \
+	t8103-j457.dtb
 
 dtb-$(CONFIG_ARCH_DAVINCI) += \
 	da850-evm.dtb \
diff --git a/arch/arm/dts/armada-375.dtsi b/arch/arm/dts/armada-375.dtsi
index 62a548a..ff0ad7a 100644
--- a/arch/arm/dts/armada-375.dtsi
+++ b/arch/arm/dts/armada-375.dtsi
@@ -384,9 +384,10 @@
 				interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			system-controller@18200 {
+			systemc: system-controller@18200 {
 				compatible = "marvell,armada-375-system-controller";
 				reg = <0x18200 0x100>;
+				#reset-cells = <2>;
 			};
 
 			gateclk: clock-gating-control@18220 {
@@ -616,6 +617,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 5>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -634,6 +636,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <1>;
 				clocks = <&gateclk 6>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
diff --git a/arch/arm/dts/armada-380.dtsi b/arch/arm/dts/armada-380.dtsi
index cff1269..f3d7f4b 100644
--- a/arch/arm/dts/armada-380.dtsi
+++ b/arch/arm/dts/armada-380.dtsi
@@ -73,6 +73,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 8>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -92,6 +93,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 5>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -111,6 +113,7 @@
 				marvell,pcie-port = <2>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 6>;
+				resets = <&systemc 0 2>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/dts/armada-385.dtsi b/arch/arm/dts/armada-385.dtsi
index f0022d1..581a7d9 100644
--- a/arch/arm/dts/armada-385.dtsi
+++ b/arch/arm/dts/armada-385.dtsi
@@ -78,6 +78,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 8>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -97,6 +98,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 5>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -116,6 +118,7 @@
 				marvell,pcie-port = <2>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 6>;
+				resets = <&systemc 0 2>;
 				status = "disabled";
 			};
 
@@ -138,6 +141,7 @@
 				marvell,pcie-port = <3>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 7>;
+				resets = <&systemc 0 3>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/dts/armada-38x.dtsi b/arch/arm/dts/armada-38x.dtsi
index 72c49be..061bd78 100644
--- a/arch/arm/dts/armada-38x.dtsi
+++ b/arch/arm/dts/armada-38x.dtsi
@@ -328,6 +328,7 @@
 				compatible = "marvell,armada-380-system-controller",
 					     "marvell,armada-370-xp-system-controller";
 				reg = <0x18200 0x100>;
+				#reset-cells = <2>;
 			};
 
 			gateclk: clock-gating-control@18220 {
diff --git a/arch/arm/dts/armada-cp110.dtsi b/arch/arm/dts/armada-cp110.dtsi
index abf1e4e..ddc10d2 100644
--- a/arch/arm/dts/armada-cp110.dtsi
+++ b/arch/arm/dts/armada-cp110.dtsi
@@ -231,7 +231,7 @@
 				#address-cells = <1>;
 				#size-cells = <0>;
 				clocks = <&CP110_LABEL(syscon0) 1 2>;
-				nand-enable-arbiter;
+				marvell,nand-enable-arbiter;
 				num-cs = <1>;
 				nand-ecc-strength = <8>;
 				nand-ecc-step-size = <512>;
diff --git a/arch/arm/dts/armada-xp-98dx3236.dtsi b/arch/arm/dts/armada-xp-98dx3236.dtsi
index 5df1d18..1a48ff3 100644
--- a/arch/arm/dts/armada-xp-98dx3236.dtsi
+++ b/arch/arm/dts/armada-xp-98dx3236.dtsi
@@ -85,6 +85,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 5>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 		};
@@ -136,6 +137,7 @@
 			systemc: system-controller@18200 {
 				compatible = "marvell,armada-370-xp-system-controller";
 				reg = <0x18200 0x500>;
+				#reset-cells = <2>;
 			};
 
 			gateclk: clock-gating-control@18220 {
diff --git a/arch/arm/dts/armada-xp-mv78230.dtsi b/arch/arm/dts/armada-xp-mv78230.dtsi
index 8558bf6..63d7f48 100644
--- a/arch/arm/dts/armada-xp-mv78230.dtsi
+++ b/arch/arm/dts/armada-xp-mv78230.dtsi
@@ -92,6 +92,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 5>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -110,6 +111,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <1>;
 				clocks = <&gateclk 6>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -128,6 +130,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <2>;
 				clocks = <&gateclk 7>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -146,6 +149,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <3>;
 				clocks = <&gateclk 8>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -164,6 +168,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 9>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/dts/armada-xp-mv78260.dtsi b/arch/arm/dts/armada-xp-mv78260.dtsi
index 2d85fe8..5dc413d 100644
--- a/arch/arm/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/dts/armada-xp-mv78260.dtsi
@@ -107,6 +107,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 5>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -125,6 +126,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <1>;
 				clocks = <&gateclk 6>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -143,6 +145,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <2>;
 				clocks = <&gateclk 7>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -161,6 +164,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <3>;
 				clocks = <&gateclk 8>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -179,6 +183,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 9>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -197,6 +202,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <1>;
 				clocks = <&gateclk 10>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -215,6 +221,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <2>;
 				clocks = <&gateclk 11>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -233,6 +240,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <3>;
 				clocks = <&gateclk 12>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -251,6 +259,7 @@
 				marvell,pcie-port = <2>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 26>;
+				resets = <&systemc 0 2>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/dts/armada-xp-mv78460.dtsi b/arch/arm/dts/armada-xp-mv78460.dtsi
index 230a3fd..6fbd0ce 100644
--- a/arch/arm/dts/armada-xp-mv78460.dtsi
+++ b/arch/arm/dts/armada-xp-mv78460.dtsi
@@ -128,6 +128,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 5>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -146,6 +147,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <1>;
 				clocks = <&gateclk 6>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -164,6 +166,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <2>;
 				clocks = <&gateclk 7>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -182,6 +185,7 @@
 				marvell,pcie-port = <0>;
 				marvell,pcie-lane = <3>;
 				clocks = <&gateclk 8>;
+				resets = <&systemc 0 0>;
 				status = "disabled";
 			};
 
@@ -200,6 +204,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 9>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -218,6 +223,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <1>;
 				clocks = <&gateclk 10>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -236,6 +242,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <2>;
 				clocks = <&gateclk 11>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -254,6 +261,7 @@
 				marvell,pcie-port = <1>;
 				marvell,pcie-lane = <3>;
 				clocks = <&gateclk 12>;
+				resets = <&systemc 0 1>;
 				status = "disabled";
 			};
 
@@ -272,6 +280,7 @@
 				marvell,pcie-port = <2>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 26>;
+				resets = <&systemc 0 2>;
 				status = "disabled";
 			};
 
@@ -290,6 +299,7 @@
 				marvell,pcie-port = <3>;
 				marvell,pcie-lane = <0>;
 				clocks = <&gateclk 27>;
+				resets = <&systemc 0 3>;
 				status = "disabled";
 			};
 		};
diff --git a/arch/arm/dts/armada-xp-synology-ds414.dts b/arch/arm/dts/armada-xp-synology-ds414.dts
index 861967c..35909e3 100644
--- a/arch/arm/dts/armada-xp-synology-ds414.dts
+++ b/arch/arm/dts/armada-xp-synology-ds414.dts
@@ -187,6 +187,7 @@
 	pcie@1,0 {
 		/* Port 0, Lane 0 */
 		status = "okay";
+		num-lanes = <4>;
 	};
 
 	/*
diff --git a/arch/arm/dts/armada-xp-theadorable.dts b/arch/arm/dts/armada-xp-theadorable.dts
index 24cc1cc..a06a65a 100644
--- a/arch/arm/dts/armada-xp-theadorable.dts
+++ b/arch/arm/dts/armada-xp-theadorable.dts
@@ -214,5 +214,6 @@
 	pcie@9,0 {
 		/* Port 2, Lane 0 */
 		status = "okay";
+		num-lanes = <4>;
 	};
 };
diff --git a/arch/arm/dts/armada-xp.dtsi b/arch/arm/dts/armada-xp.dtsi
index d856d96..fb5640b 100644
--- a/arch/arm/dts/armada-xp.dtsi
+++ b/arch/arm/dts/armada-xp.dtsi
@@ -78,6 +78,7 @@
 			systemc: system-controller@18200 {
 				compatible = "marvell,armada-370-xp-system-controller";
 				reg = <0x18200 0x500>;
+				#reset-cells = <2>;
 			};
 
 			gateclk: clock-gating-control@18220 {
diff --git a/arch/arm/dts/t8103-j274-u-boot.dtsi b/arch/arm/dts/t8103-j274-u-boot.dtsi
new file mode 100644
index 0000000..6c8dd5a
--- /dev/null
+++ b/arch/arm/dts/t8103-j274-u-boot.dtsi
@@ -0,0 +1 @@
+#include "t8103-u-boot.dtsi"
diff --git a/arch/arm/dts/t8103-j274.dts b/arch/arm/dts/t8103-j274.dts
index aef1ae2..9bc592b 100644
--- a/arch/arm/dts/t8103-j274.dts
+++ b/arch/arm/dts/t8103-j274.dts
@@ -10,126 +10,120 @@
 /dts-v1/;
 
 #include "t8103.dtsi"
+#include "t8103-jxxx.dtsi"
 
 / {
 	compatible = "apple,j274", "apple,t8103", "apple,arm-platform";
 	model = "Apple Mac mini (M1, 2020)";
 
 	aliases {
-		serial0 = &serial0;
-		ethernet0 = &eth0;
-		wifi0 = &wifi0;
+		ethernet0 = &ethernet0;
 	};
+};
 
-	chosen {
-		#address-cells = <2>;
-		#size-cells = <2>;
-		ranges;
+&wifi0 {
+	brcm,board-type = "apple,atlantisb";
+};
 
-		stdout-path = "serial0";
+/*
+ * Provide labels for the USB type C ports.
+ */
 
-		framebuffer0: framebuffer@0 {
-			compatible = "apple,simple-framebuffer", "simple-framebuffer";
-			reg = <0 0 0 0>; /* To be filled by loader */
-			/* Format properties will be added by loader */
-			status = "disabled";
+&typec0 {
+	label = "USB-C Back-left";
+};
+
+&typec1 {
+	label = "USB-C Back-right";
+};
+
+/*
+ * Force the bus number assignments so that we can declare some of the
+ * on-board devices and properties that are populated by the bootloader
+ * (such as MAC addresses).
+ */
+
+&port01 {
+	bus-range = <2 2>;
+};
+
+&port02 {
+	bus-range = <3 3>;
+	ethernet0: ethernet@0,0 {
+		reg = <0x30000 0x0 0x0 0x0 0x0>;
+		/* To be filled by the loader */
+		local-mac-address = [00 10 18 00 00 00];
+	};
+};
+
+&i2c1 {
+	clock-frequency = <50000>;
+
+	speaker_amp: codec@31 {
+		compatible = "ti,tas5770l", "ti,tas2770";
+		reg = <0x31>;
+		reset-gpios = <&pinctrl_ap 181 GPIO_ACTIVE_HIGH>;
+		#sound-dai-cells = <0>;
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	clock-frequency = <50000>;
+
+	jack_codec: codec@48 {
+		compatible = "cirrus,cs42l83", "cirrus,cs42l42";
+		reg = <0x48>;
+		reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <183 IRQ_TYPE_LEVEL_LOW>;
+		#sound-dai-cells = <0>;
+		cirrus,ts-inv = <1>;
+	};
+};
+
+/ {
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "Mac mini integrated audio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		simple-audio-card,dai-link@0 {
+			reg = <0>;
+			format = "left_j";
+			tdm-slot-width = <32>;
+			mclk-fs = <64>;
+
+			link0_cpu: cpu {
+				sound-dai = <&mca 0>;
+				bitclock-master;
+				frame-master;
+			};
+
+			link0_codec: codec {
+				sound-dai = <&speaker_amp>;
+			};
+		};
+
+		simple-audio-card,dai-link@1 {
+			bitclock-inversion;
+			frame-inversion;
+			reg = <1>;
+			format = "i2s";
+			mclk-fs = <64>;
+			tdm-slot-width = <32>;
+
+			link1_cpu: cpu {
+				sound-dai = <&mca 2>;
+				bitclock-master;
+				frame-master;
+			};
+
+			link1_codec: codec {
+				sound-dai = <&jack_codec>;
+			};
 		};
 	};
-
-	memory@800000000 {
-		device_type = "memory";
-		reg = <0x8 0 0x2 0>; /* To be filled by loader */
-	};
-};
-
-&serial0 {
-	status = "okay";
-};
-
-&pcie0_dart_0 {
-	status = "okay";
-};
-
-&pcie0_dart_1 {
-	status = "okay";
-};
-
-&pcie0_dart_2 {
-	status = "okay";
-};
-
-&pcie0 {
-	status = "okay";
-
-	pci0: pci@0,0 {
-		device_type = "pci";
-		reg = <0x0 0x0 0x0 0x0 0x0>;
-		pwren-gpios = <&smc 13 0>;
-		reset-gpios = <&pinctrl_ap 152 0>;
-		max-link-speed = <2>;
-
-		#address-cells = <3>;
-		#size-cells = <2>;
-		ranges;
-	};
-
-	pci1: pci@1,0 {
-		device_type = "pci";
-		reg = <0x800 0x0 0x0 0x0 0x0>;
-		reset-gpios = <&pinctrl_ap 153 0>;
-		max-link-speed = <2>;
-
-		#address-cells = <3>;
-		#size-cells = <2>;
-		ranges;
-	};
-
-	pci2: pci@2,0 {
-		device_type = "pci";
-		reg = <0x1000 0x0 0x0 0x0 0x0>;
-		reset-gpios = <&pinctrl_ap 33 0>;
-		max-link-speed = <1>;
-
-		#address-cells = <3>;
-		#size-cells = <2>;
-		ranges;
-	};
-};
-
-&pci0 {
-	wifi0: network@0,0 {
-		reg = <0x10000 0x0 0x0 0x0 0x0>;
-		local-mac-address = [00 00 00 00 00 00];
-	};
-};
-
-&pci2 {
-	eth0: ethernet@0,0 {
-		reg = <0x30000 0x0 0x0 0x0 0x0>;
-		local-mac-address = [00 00 00 00 00 00];
-	};
-};
-
-&dwc3_0_dart_0 {
-	status = "okay";
-};
-
-&dwc3_0_dart_1 {
-	status = "okay";
-};
-
-&dwc3_0 {
-	status = "okay";
-};
-
-&dwc3_1_dart_0 {
-	status = "okay";
-};
-
-&dwc3_1_dart_1 {
-	status = "okay";
-};
-
-&dwc3_1 {
-	status = "okay";
 };
diff --git a/arch/arm/dts/t8103-j293-u-boot.dtsi b/arch/arm/dts/t8103-j293-u-boot.dtsi
new file mode 100644
index 0000000..6c8dd5a
--- /dev/null
+++ b/arch/arm/dts/t8103-j293-u-boot.dtsi
@@ -0,0 +1 @@
+#include "t8103-u-boot.dtsi"
diff --git a/arch/arm/dts/t8103-j293.dts b/arch/arm/dts/t8103-j293.dts
index 4a22596..de1a21d 100644
--- a/arch/arm/dts/t8103-j293.dts
+++ b/arch/arm/dts/t8103-j293.dts
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+ OR MIT
 /*
- * Apple Macbook Pro (M1, 2020)
+ * Apple MacBook Pro (13-inch, M1, 2020)
  *
  * target-type: J293
  *
@@ -10,88 +10,107 @@
 /dts-v1/;
 
 #include "t8103.dtsi"
+#include "t8103-jxxx.dtsi"
 
 / {
 	compatible = "apple,j293", "apple,t8103", "apple,arm-platform";
-	model = "Apple Macbook Pro (M1, 2020)";
+	model = "Apple MacBook Pro (13-inch, M1, 2020)";
+};
 
-	aliases {
-		serial0 = &serial0;
-		wifi0 = &wifi0;
+&wifi0 {
+	brcm,board-type = "apple,honshu";
+};
+
+/*
+ * Provide labels for the USB type C ports.
+ */
+
+&typec0 {
+	label = "USB-C Left-back";
+};
+
+&typec1 {
+	label = "USB-C Left-front";
+};
+
+&spi3 {
+	status = "okay";
+
+	hid-transport@0 {
+		compatible = "apple,spi-hid-transport";
+		reg = <0>;
+		spi-max-frequency = <8000000>;
+		/*
+		 * cs-setup and cs-hold delays are derived from Apple's ADT
+		 * Mac OS driver meta data secify 45 us for 'cs to clock' and
+		 * 'clock to cs' delays.
+		 */
+		spi-cs-setup-delay-ns = <20000>;
+		spi-cs-hold-delay-ns = <20000>;
+		spi-cs-inactive-delay-ns = <250000>;
+		spien-gpios = <&pinctrl_ap 195 0>;
+		interrupts-extended = <&pinctrl_nub 13 IRQ_TYPE_LEVEL_LOW>;
 	};
+};
 
-	chosen {
-		#address-cells = <2>;
-		#size-cells = <2>;
-		ranges;
+/*
+ * Remove unused PCIe ports and disable the associated DARTs.
+ */
 
-		stdout-path = "serial0";
+&pcie0_dart_1 {
+	status = "disabled";
+};
 
-		framebuffer0: framebuffer@0 {
-			compatible = "apple,simple-framebuffer", "simple-framebuffer";
-			reg = <0 0 0 0>; /* To be filled by loader */
-			/* Format properties will be added by loader */
-			status = "disabled";
+&pcie0_dart_2 {
+	status = "disabled";
+};
+
+/delete-node/ &port01;
+/delete-node/ &port02;
+
+&i2c2 {
+	status = "okay";
+	clock-frequency = <50000>;
+
+	jack_codec: codec@48 {
+		compatible = "cirrus,cs42l83", "cirrus,cs42l42";
+		reg = <0x48>;
+		reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <183 IRQ_TYPE_LEVEL_LOW>;
+		#sound-dai-cells = <0>;
+		cirrus,ts-inv = <1>;
+	};
+};
+
+&i2c4 {
+	status = "okay";
+};
+
+/ {
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "MacBook integrated audio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		simple-audio-card,dai-link@0 {
+			bitclock-inversion;
+			frame-inversion;
+			reg = <0>;
+			format = "i2s";
+			mclk-fs = <64>;
+			tdm-slot-width = <32>;
+
+			link0_cpu: cpu {
+				sound-dai = <&mca 2>;
+				bitclock-master;
+				frame-master;
+			};
+
+			link0_codec: codec {
+				sound-dai = <&jack_codec>;
+			};
 		};
 	};
-
-	memory@800000000 {
-		device_type = "memory";
-		reg = <0x8 0 0x2 0>; /* To be filled by loader */
-	};
-};
-
-&serial0 {
-	status = "okay";
-};
-
-&pcie0_dart_0 {
-	status = "okay";
-};
-
-&pcie0 {
-	status = "okay";
-
-	pci0: pci@0,0 {
-		device_type = "pci";
-		reg = <0x0 0x0 0x0 0x0 0x0>;
-		pwren-gpios = <&smc 13 0>;
-		reset-gpios = <&pinctrl_ap 152 0>;
-		max-link-speed = <2>;
-
-		#address-cells = <3>;
-		#size-cells = <2>;
-		ranges;
-	};
-};
-
-&pci0 {
-	wifi0: network@0,0 {
-		reg = <0x10000 0x0 0x0 0x0 0x0>;
-		local-mac-address = [00 00 00 00 00 00];
-	};
-};
-
-&dwc3_0_dart_0 {
-	status = "okay";
-};
-
-&dwc3_0_dart_1 {
-	status = "okay";
-};
-
-&dwc3_0 {
-	status = "okay";
-};
-
-&dwc3_1_dart_0 {
-	status = "okay";
-};
-
-&dwc3_1_dart_1 {
-	status = "okay";
-};
-
-&dwc3_1 {
-	status = "okay";
 };
diff --git a/arch/arm/dts/t8103-j313-u-boot.dtsi b/arch/arm/dts/t8103-j313-u-boot.dtsi
new file mode 100644
index 0000000..6c8dd5a
--- /dev/null
+++ b/arch/arm/dts/t8103-j313-u-boot.dtsi
@@ -0,0 +1 @@
+#include "t8103-u-boot.dtsi"
diff --git a/arch/arm/dts/t8103-j313.dts b/arch/arm/dts/t8103-j313.dts
new file mode 100644
index 0000000..5efe8d7
--- /dev/null
+++ b/arch/arm/dts/t8103-j313.dts
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Apple MacBook Air (M1, 2020)
+ *
+ * target-type: J313
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t8103.dtsi"
+#include "t8103-jxxx.dtsi"
+
+/ {
+	compatible = "apple,j313", "apple,t8103", "apple,arm-platform";
+	model = "Apple MacBook Air (M1, 2020)";
+};
+
+&wifi0 {
+	brcm,board-type = "apple,shikoku";
+};
+
+/*
+ * Provide labels for the USB type C ports.
+ */
+
+&typec0 {
+	label = "USB-C Left-back";
+};
+
+&typec1 {
+	label = "USB-C Left-front";
+};
+
+&spi3 {
+	status = "okay";
+
+	hid-transport@0 {
+		compatible = "apple,spi-hid-transport";
+		reg = <0>;
+		spi-max-frequency = <8000000>;
+		/*
+		 * cs-setup and cs-hold delays are derived from Apple's ADT
+		 * Mac OS driver meta data secify 45 us for 'cs to clock' and
+		 * 'clock to cs' delays.
+		 */
+		spi-cs-setup-delay-ns = <20000>;
+		spi-cs-hold-delay-ns = <20000>;
+		spi-cs-inactive-delay-ns = <250000>;
+		spien-gpios = <&pinctrl_ap 195 0>;
+		interrupts-extended = <&pinctrl_nub 13 IRQ_TYPE_LEVEL_LOW>;
+	};
+};
+
+/*
+ * Remove unused PCIe ports and disable the associated DARTs.
+ */
+
+&pcie0_dart_1 {
+	status = "disabled";
+};
+
+&pcie0_dart_2 {
+	status = "disabled";
+};
+
+/delete-node/ &port01;
+/delete-node/ &port02;
+
+&i2c3 {
+	clock-frequency = <50000>;
+
+	jack_codec: codec@48 {
+		compatible = "cirrus,cs42l83", "cirrus,cs42l42";
+		reg = <0x48>;
+		reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <183 IRQ_TYPE_LEVEL_LOW>;
+		#sound-dai-cells = <0>;
+		cirrus,ts-inv = <1>;
+	};
+};
+
+/ {
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "MacBook integrated audio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		simple-audio-card,dai-link@0 {
+			bitclock-inversion;
+			frame-inversion;
+			reg = <0>;
+			format = "i2s";
+			mclk-fs = <64>;
+			tdm-slot-width = <32>;
+
+			link0_cpu: cpu {
+				sound-dai = <&mca 2>;
+				bitclock-master;
+				frame-master;
+			};
+
+			link0_codec: codec {
+				sound-dai = <&jack_codec>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/dts/t8103-j456-u-boot.dtsi b/arch/arm/dts/t8103-j456-u-boot.dtsi
new file mode 100644
index 0000000..6c8dd5a
--- /dev/null
+++ b/arch/arm/dts/t8103-j456-u-boot.dtsi
@@ -0,0 +1 @@
+#include "t8103-u-boot.dtsi"
diff --git a/arch/arm/dts/t8103-j456.dts b/arch/arm/dts/t8103-j456.dts
new file mode 100644
index 0000000..8624168
--- /dev/null
+++ b/arch/arm/dts/t8103-j456.dts
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Apple iMac (24-inch, 4x USB-C, M1, 2020)
+ *
+ * target-type: J456
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t8103.dtsi"
+#include "t8103-jxxx.dtsi"
+
+/ {
+	compatible = "apple,j456", "apple,t8103", "apple,arm-platform";
+	model = "Apple iMac (24-inch, 4x USB-C, M1, 2020)";
+
+	aliases {
+		ethernet0 = &ethernet0;
+	};
+};
+
+&wifi0 {
+	brcm,board-type = "apple,capri";
+};
+
+&i2c0 {
+	hpm2: usb-pd@3b {
+		compatible = "apple,cd321x";
+		reg = <0x3b>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <106 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "irq";
+	};
+
+	hpm3: usb-pd@3c {
+		compatible = "apple,cd321x";
+		reg = <0x3c>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <106 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "irq";
+	};
+};
+
+/*
+ * Provide labels for the USB type C ports.
+ */
+
+&typec0 {
+	label = "USB-C Back-right";
+};
+
+&typec1 {
+	label = "USB-C Back-right-middle";
+};
+
+/*
+ * Force the bus number assignments so that we can declare some of the
+ * on-board devices and properties that are populated by the bootloader
+ * (such as MAC addresses).
+ */
+
+&port01 {
+	bus-range = <2 2>;
+};
+
+&port02 {
+	bus-range = <3 3>;
+	ethernet0: ethernet@0,0 {
+		reg = <0x30000 0x0 0x0 0x0 0x0>;
+		/* To be filled by the loader */
+		local-mac-address = [00 10 18 00 00 00];
+	};
+};
+
+&i2c1 {
+	clock-frequency = <50000>;
+
+	jack_codec: codec@48 {
+		compatible = "cirrus,cs42l83", "cirrus,cs42l42";
+		reg = <0x48>;
+		reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <183 IRQ_TYPE_LEVEL_LOW>;
+		#sound-dai-cells = <0>;
+		cirrus,ts-inv = <1>;
+	};
+};
+
+/ {
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "iMac integrated audio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		simple-audio-card,dai-link@0 {
+			bitclock-inversion;
+			frame-inversion;
+			reg = <0>;
+			format = "i2s";
+			mclk-fs = <64>;
+			tdm-slot-width = <32>;
+
+			link0_cpu: cpu {
+				sound-dai = <&mca 2>;
+				bitclock-master;
+				frame-master;
+			};
+
+			link0_codec: codec {
+				sound-dai = <&jack_codec>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/dts/t8103-j457-u-boot.dtsi b/arch/arm/dts/t8103-j457-u-boot.dtsi
new file mode 100644
index 0000000..6c8dd5a
--- /dev/null
+++ b/arch/arm/dts/t8103-j457-u-boot.dtsi
@@ -0,0 +1 @@
+#include "t8103-u-boot.dtsi"
diff --git a/arch/arm/dts/t8103-j457.dts b/arch/arm/dts/t8103-j457.dts
new file mode 100644
index 0000000..f3eec8d
--- /dev/null
+++ b/arch/arm/dts/t8103-j457.dts
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Apple iMac (24-inch, 2x USB-C, M1, 2020)
+ *
+ * target-type: J457
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+/dts-v1/;
+
+#include "t8103.dtsi"
+#include "t8103-jxxx.dtsi"
+
+/ {
+	compatible = "apple,j457", "apple,t8103", "apple,arm-platform";
+	model = "Apple iMac (24-inch, 2x USB-C, M1, 2020)";
+
+	aliases {
+		ethernet0 = &ethernet0;
+	};
+};
+
+&wifi0 {
+	brcm,board-type = "apple,santorini";
+};
+
+/*
+ * Provide labels for the USB type C ports.
+ */
+
+&typec0 {
+	label = "USB-C Back-right";
+};
+
+&typec1 {
+	label = "USB-C Back-left";
+};
+
+/*
+ * Force the bus number assignments so that we can declare some of the
+ * on-board devices and properties that are populated by the bootloader
+ * (such as MAC addresses).
+ */
+
+&port02 {
+	bus-range = <3 3>;
+	ethernet0: ethernet@0,0 {
+		reg = <0x30000 0x0 0x0 0x0 0x0>;
+		/* To be filled by the loader */
+		local-mac-address = [00 10 18 00 00 00];
+	};
+};
+
+/*
+ * Remove unused PCIe port and disable the associated DART.
+ */
+
+&pcie0_dart_1 {
+	status = "disabled";
+};
+
+/delete-node/ &port01;
+
+&i2c1 {
+	clock-frequency = <50000>;
+
+	jack_codec: codec@48 {
+		compatible = "cirrus,cs42l83", "cirrus,cs42l42";
+		reg = <0x48>;
+		reset-gpios = <&pinctrl_nub 11 GPIO_ACTIVE_HIGH>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <183 IRQ_TYPE_LEVEL_LOW>;
+		#sound-dai-cells = <0>;
+		cirrus,ts-inv = <1>;
+	};
+};
+
+/ {
+	sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,name = "iMac integrated audio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		simple-audio-card,dai-link@0 {
+			bitclock-inversion;
+			frame-inversion;
+			reg = <0>;
+			format = "i2s";
+			mclk-fs = <64>;
+			tdm-slot-width = <32>;
+
+			link0_cpu: cpu {
+				sound-dai = <&mca 2>;
+				bitclock-master;
+				frame-master;
+			};
+
+			link0_codec: codec {
+				sound-dai = <&jack_codec>;
+			};
+		};
+	};
+};
diff --git a/arch/arm/dts/t8103-jxxx.dtsi b/arch/arm/dts/t8103-jxxx.dtsi
new file mode 100644
index 0000000..b4bd8c4
--- /dev/null
+++ b/arch/arm/dts/t8103-jxxx.dtsi
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * Apple M1 Mac mini, MacBook Air/Pro, iMac 24" (M1, 2020/2021)
+ *
+ * This file contains parts common to all Apple M1 devices using the t8103.
+ *
+ * target-type: J274, J293, J313, J456, J457
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+#include <dt-bindings/spmi/spmi.h>
+
+/ {
+	aliases {
+		serial0 = &serial0;
+		serial2 = &serial2;
+		wifi0 = &wifi0;
+	};
+
+	chosen {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		stdout-path = "serial0";
+
+		framebuffer0: framebuffer@0 {
+			compatible = "apple,simple-framebuffer", "simple-framebuffer";
+			reg = <0 0 0 0>; /* To be filled by loader */
+			/* Format properties will be added by loader */
+			status = "disabled";
+		};
+	};
+
+	memory@800000000 {
+		device_type = "memory";
+		reg = <0x8 0 0x2 0>; /* To be filled by loader */
+	};
+};
+
+&serial0 {
+	status = "okay";
+};
+
+&serial2 {
+	status = "okay";
+};
+
+&i2c0 {
+	hpm0: usb-pd@38 {
+		compatible = "apple,cd321x";
+		reg = <0x38>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <106 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "irq";
+
+		typec0: connector {
+			compatible = "usb-c-connector";
+			power-role = "dual";
+			data-role = "dual";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				port@0 {
+					reg = <0>;
+					typec0_con_hs: endpoint {
+						remote-endpoint = <&typec0_usb_hs>;
+					};
+				};
+			};
+		};
+	};
+
+	hpm1: usb-pd@3f {
+		compatible = "apple,cd321x";
+		reg = <0x3f>;
+		interrupt-parent = <&pinctrl_ap>;
+		interrupts = <106 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "irq";
+
+		typec1: connector {
+			compatible = "usb-c-connector";
+			power-role = "dual";
+			data-role = "dual";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				port@0 {
+					reg = <0>;
+					typec1_con_hs: endpoint {
+						remote-endpoint = <&typec1_usb_hs>;
+					};
+				};
+			};
+		};
+	};
+};
+
+/* USB controllers */
+&dwc3_0 {
+	port {
+		typec0_usb_hs: endpoint {
+			remote-endpoint = <&typec0_con_hs>;
+		};
+	};
+};
+
+&dwc3_1 {
+	port {
+		typec1_usb_hs: endpoint {
+			remote-endpoint = <&typec1_con_hs>;
+		};
+	};
+};
+
+/*
+ * Force the bus number assignments so that we can declare some of the
+ * on-board devices and properties that are populated by the bootloader
+ * (such as MAC addresses).
+ */
+&port00 {
+	bus-range = <1 1>;
+	pwren-gpios = <&smc 13 0>;
+	wifi0: network@0,0 {
+		compatible = "pci14e4,4425";
+		reg = <0x10000 0x0 0x0 0x0 0x0>;
+		/* To be filled by the loader */
+		local-mac-address = [00 00 00 00 00 00];
+		apple,antenna-sku = "XX";
+	};
+};
+
+&spmi {
+	status = "okay";
+
+	pmu@f {
+		compatible = "apple,sera-pmu";
+		reg = <0xf SPMI_USID>;
+	};
+};
diff --git a/arch/arm/dts/t8103-pmgr.dtsi b/arch/arm/dts/t8103-pmgr.dtsi
new file mode 100644
index 0000000..82ea4aa
--- /dev/null
+++ b/arch/arm/dts/t8103-pmgr.dtsi
@@ -0,0 +1,1138 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+/*
+ * PMGR Power domains for the Apple T8103 "M1" SoC
+ *
+ * Copyright The Asahi Linux Contributors
+ */
+
+
+&pmgr {
+	ps_sbr: power-controller@100 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x100 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "sbr";
+		apple,always-on; /* Core device */
+	};
+
+	ps_aic: power-controller@108 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x108 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "aic";
+		apple,always-on; /* Core device */
+	};
+
+	ps_dwi: power-controller@110 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x110 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dwi";
+		apple,always-on; /* Core device */
+	};
+
+	ps_soc_spmi0: power-controller@118 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x118 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "soc_spmi0";
+	};
+
+	ps_soc_spmi1: power-controller@120 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x120 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "soc_spmi1";
+	};
+
+	ps_soc_spmi2: power-controller@128 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x128 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "soc_spmi2";
+	};
+
+	ps_gpio: power-controller@130 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x130 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "gpio";
+	};
+
+	ps_pms_busif: power-controller@138 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x138 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pms_busif";
+		apple,always-on; /* Core device */
+	};
+
+	ps_pms: power-controller@140 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x140 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pms";
+		apple,always-on; /* Core device */
+	};
+
+	ps_pms_fpwm0: power-controller@148 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x148 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pms_fpwm0";
+		power-domains = <&ps_pms>;
+	};
+
+	ps_pms_fpwm1: power-controller@150 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x150 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pms_fpwm1";
+		power-domains = <&ps_pms>;
+	};
+
+	ps_pms_fpwm2: power-controller@158 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x158 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pms_fpwm2";
+		power-domains = <&ps_pms>;
+	};
+
+	ps_pms_fpwm3: power-controller@160 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x160 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pms_fpwm3";
+		power-domains = <&ps_pms>;
+	};
+
+	ps_pms_fpwm4: power-controller@168 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x168 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pms_fpwm4";
+		power-domains = <&ps_pms>;
+	};
+
+	ps_soc_dpe: power-controller@170 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x170 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "soc_dpe";
+		apple,always-on; /* Core device */
+	};
+
+	ps_pmgr_soc_ocla: power-controller@178 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x178 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pmgr_soc_ocla";
+	};
+
+	ps_ispsens0: power-controller@180 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x180 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "ispsens0";
+	};
+
+	ps_ispsens1: power-controller@188 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x188 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "ispsens1";
+	};
+
+	ps_ispsens2: power-controller@190 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x190 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "ispsens2";
+	};
+
+	ps_ispsens3: power-controller@198 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x198 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "ispsens3";
+	};
+
+	ps_pcie_ref: power-controller@1a0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1a0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pcie_ref";
+	};
+
+	ps_aft0: power-controller@1a8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1a8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "aft0";
+	};
+
+	ps_devc0_ivdmc: power-controller@1b0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1b0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "devc0_ivdmc";
+	};
+
+	ps_imx: power-controller@1b8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1b8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "imx";
+		apple,always-on; /* Apple fabric, critical block */
+	};
+
+	ps_sio_busif: power-controller@1c0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1c0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "sio_busif";
+	};
+
+	ps_sio: power-controller@1c8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1c8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "sio";
+		power-domains = <&ps_sio_busif>;
+	};
+
+	ps_sio_cpu: power-controller@1d0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1d0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "sio_cpu";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_fpwm0: power-controller@1d8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1d8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "fpwm0";
+	};
+
+	ps_fpwm1: power-controller@1e0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1e0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "fpwm1";
+	};
+
+	ps_fpwm2: power-controller@1e8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1e8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "fpwm2";
+	};
+
+	ps_i2c0: power-controller@1f0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1f0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "i2c0";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_i2c1: power-controller@1f8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x1f8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "i2c1";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_i2c2: power-controller@200 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x200 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "i2c2";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_i2c3: power-controller@208 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x208 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "i2c3";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_i2c4: power-controller@210 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x210 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "i2c4";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_spi_p: power-controller@218 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x218 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "spi_p";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_uart_p: power-controller@220 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x220 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart_p";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_audio_p: power-controller@228 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x228 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "audio_p";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_sio_adma: power-controller@230 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x230 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "sio_adma";
+		power-domains = <&ps_sio>, <&ps_pms>;
+	};
+
+	ps_aes: power-controller@238 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x238 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "aes";
+		power-domains = <&ps_sio>;
+	};
+
+	ps_spi0: power-controller@240 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x240 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "spi0";
+		power-domains = <&ps_sio>, <&ps_spi_p>;
+	};
+
+	ps_spi1: power-controller@248 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x248 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "spi1";
+		power-domains = <&ps_sio>, <&ps_spi_p>;
+	};
+
+	ps_spi2: power-controller@250 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x250 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "spi2";
+		power-domains = <&ps_sio>, <&ps_spi_p>;
+	};
+
+	ps_spi3: power-controller@258 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x258 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "spi3";
+		power-domains = <&ps_sio>, <&ps_spi_p>;
+	};
+
+	ps_uart_n: power-controller@268 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x268 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart_n";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart0: power-controller@270 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x270 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart0";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart1: power-controller@278 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x278 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart1";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart2: power-controller@280 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x280 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart2";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart3: power-controller@288 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x288 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart3";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart4: power-controller@290 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x290 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart4";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart5: power-controller@298 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x298 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart5";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart6: power-controller@2a0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2a0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart6";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart7: power-controller@2a8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2a8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart7";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_uart8: power-controller@2b0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2b0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "uart8";
+		power-domains = <&ps_uart_p>;
+	};
+
+	ps_mca0: power-controller@2b8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2b8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mca0";
+		power-domains = <&ps_audio_p>, <&ps_sio_adma>, <&ps_mca1>, <&ps_mca2>, <&ps_mca3>, <&ps_mca4>, <&ps_mca5>;
+	};
+
+	ps_mca1: power-controller@2c0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2c0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mca1";
+		power-domains = <&ps_audio_p>, <&ps_sio_adma>;
+	};
+
+	ps_mca2: power-controller@2c8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2c8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mca2";
+		power-domains = <&ps_audio_p>, <&ps_sio_adma>;
+	};
+
+	ps_mca3: power-controller@2d0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2d0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mca3";
+		power-domains = <&ps_audio_p>, <&ps_sio_adma>;
+	};
+
+	ps_mca4: power-controller@2d8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2d8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mca4";
+		power-domains = <&ps_audio_p>, <&ps_sio_adma>;
+	};
+
+	ps_mca5: power-controller@2e0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2e0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mca5";
+		power-domains = <&ps_audio_p>, <&ps_sio_adma>;
+	};
+
+	ps_dpa0: power-controller@2e8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2e8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dpa0";
+		power-domains = <&ps_audio_p>;
+	};
+
+	ps_dpa1: power-controller@2f0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2f0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dpa1";
+		power-domains = <&ps_audio_p>;
+	};
+
+	ps_mcc: power-controller@2f8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x2f8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mcc";
+		apple,always-on; /* Memory controller */
+	};
+
+	ps_spi4: power-controller@260 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x260 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "spi4";
+		power-domains = <&ps_sio>, <&ps_spi_p>;
+	};
+
+	ps_dcs0: power-controller@300 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x300 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dcs0";
+		apple,always-on; /* LPDDR4 interface */
+	};
+
+	ps_dcs1: power-controller@310 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x310 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dcs1";
+		apple,always-on; /* LPDDR4 interface */
+	};
+
+	ps_dcs2: power-controller@308 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x308 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dcs2";
+		apple,always-on; /* LPDDR4 interface */
+	};
+
+	ps_dcs3: power-controller@318 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x318 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dcs3";
+		apple,always-on; /* LPDDR4 interface */
+	};
+
+	ps_smx: power-controller@340 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x340 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "smx";
+		apple,always-on; /* Apple fabric, critical block */
+	};
+
+	ps_apcie: power-controller@348 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x348 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "apcie";
+		power-domains = <&ps_imx>, <&ps_pcie_ref>;
+	};
+
+	ps_rmx: power-controller@350 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x350 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "rmx";
+		/* Apple Fabric, display/image stuff: this can power down */
+	};
+
+	ps_mmx: power-controller@358 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x358 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mmx";
+		/* Apple Fabric, media stuff: this can power down */
+	};
+
+	ps_disp0_fe: power-controller@360 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x360 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "disp0_fe";
+		power-domains = <&ps_rmx>;
+		apple,always-on; /* TODO: figure out if we can enable PM here */
+	};
+
+	ps_dispext_fe: power-controller@368 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x368 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dispext_fe";
+		power-domains = <&ps_rmx>;
+	};
+
+	ps_dispext_cpu0: power-controller@378 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x378 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dispext_cpu0";
+		power-domains = <&ps_dispext_fe>;
+		apple,min-state = <4>;
+	};
+
+	ps_jpg: power-controller@3c0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3c0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "jpg";
+		power-domains = <&ps_mmx>;
+	};
+
+	ps_msr: power-controller@3c8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3c8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "msr";
+		power-domains = <&ps_mmx>;
+	};
+
+	ps_msr_ase_core: power-controller@3d0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3d0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "msr_ase_core";
+	};
+
+	ps_pmp: power-controller@3d8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3d8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pmp";
+	};
+
+	ps_pms_sram: power-controller@3e0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3e0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "pms_sram";
+	};
+
+	ps_apcie_gp: power-controller@3e8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3e8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "apcie_gp";
+		power-domains = <&ps_apcie>;
+	};
+
+	ps_ans2: power-controller@3f0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3f0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "ans2";
+		/*
+		 * The ADT makes ps_apcie_st depend on ps_ans2 instead, but this
+		 * doesn't make much sense since ANS2 uses APCIE_ST.
+		 */
+		power-domains = <&ps_apcie_st>;
+	};
+
+	ps_gfx: power-controller@3f8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3f8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "gfx";
+	};
+
+	ps_dcs4: power-controller@320 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x320 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dcs4";
+		apple,always-on; /* LPDDR4 interface */
+	};
+
+	ps_dcs5: power-controller@330 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x330 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dcs5";
+		apple,always-on; /* LPDDR4 interface */
+	};
+
+	ps_dcs6: power-controller@328 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x328 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dcs6";
+		apple,always-on; /* LPDDR4 interface */
+	};
+
+	ps_dcs7: power-controller@338 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x338 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dcs7";
+		apple,always-on; /* LPDDR4 interface */
+	};
+
+	ps_dispdfr_fe: power-controller@3a8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3a8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dispdfr_fe";
+		power-domains = <&ps_rmx>;
+	};
+
+	ps_dispdfr_be: power-controller@3b0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3b0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "dispdfr_be";
+		power-domains = <&ps_dispdfr_fe>;
+	};
+
+	ps_mipi_dsi: power-controller@3b8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x3b8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "mipi_dsi";
+		power-domains = <&ps_dispdfr_be>;
+	};
+
+	ps_isp_sys: power-controller@400 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x400 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "isp_sys";
+		power-domains = <&ps_rmx>;
+	};
+
+	ps_venc_sys: power-controller@408 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x408 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "venc_sys";
+		power-domains = <&ps_mmx>;
+	};
+
+	ps_avd_sys: power-controller@410 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x410 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "avd_sys";
+		power-domains = <&ps_mmx>;
+	};
+
+	ps_apcie_st: power-controller@418 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x418 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "apcie_st";
+		power-domains = <&ps_apcie>;
+	};
+
+	ps_ane_sys: power-controller@470 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x470 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "ane_sys";
+	};
+
+	ps_atc0_common: power-controller@420 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x420 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc0_common";
+	};
+
+	ps_atc0_pcie: power-controller@428 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x428 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc0_pcie";
+		power-domains = <&ps_atc0_common>;
+	};
+
+	ps_atc0_cio: power-controller@430 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x430 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc0_cio";
+		power-domains = <&ps_atc0_common>;
+	};
+
+	ps_atc0_cio_pcie: power-controller@438 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x438 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc0_cio_pcie";
+		power-domains = <&ps_atc0_cio>;
+	};
+
+	ps_atc0_cio_usb: power-controller@440 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x440 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc0_cio_usb";
+		power-domains = <&ps_atc0_cio>;
+	};
+
+	ps_atc1_common: power-controller@448 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x448 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc1_common";
+	};
+
+	ps_atc1_pcie: power-controller@450 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x450 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc1_pcie";
+		power-domains = <&ps_atc1_common>;
+	};
+
+	ps_atc1_cio: power-controller@458 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x458 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc1_cio";
+		power-domains = <&ps_atc1_common>;
+	};
+
+	ps_atc1_cio_pcie: power-controller@460 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x460 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc1_cio_pcie";
+		power-domains = <&ps_atc1_cio>;
+	};
+
+	ps_atc1_cio_usb: power-controller@468 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x468 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc1_cio_usb";
+		power-domains = <&ps_atc1_cio>;
+	};
+
+	ps_sep: power-controller@c00 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0xc00 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "sep";
+		apple,always-on; /* Locked on */
+	};
+
+	ps_venc_dma: power-controller@8000 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x8000 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "venc_dma";
+		power-domains = <&ps_venc_sys>;
+	};
+
+	ps_venc_pipe4: power-controller@8008 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x8008 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "venc_pipe4";
+		power-domains = <&ps_venc_dma>;
+	};
+
+	ps_venc_pipe5: power-controller@8010 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x8010 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "venc_pipe5";
+		power-domains = <&ps_venc_dma>;
+	};
+
+	ps_venc_me0: power-controller@8018 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x8018 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "venc_me0";
+		power-domains = <&ps_venc_pipe4>, <&ps_venc_pipe5>;
+	};
+
+	ps_venc_me1: power-controller@8020 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x8020 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "venc_me1";
+		power-domains = <&ps_venc_pipe4>, <&ps_venc_pipe5>;
+	};
+
+	ps_ane_sys_cpu: power-controller@c000 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0xc000 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "ane_sys_cpu";
+		power-domains = <&ps_ane_sys>;
+	};
+
+	ps_disp0_cpu0: power-controller@10018 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x10018 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "disp0_cpu0";
+		power-domains = <&ps_disp0_fe>;
+		apple,always-on; /* TODO: figure out if we can enable PM here */
+		apple,min-state = <4>;
+	};
+};
+
+&pmgr_mini {
+	ps_debug: power-controller@58 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x58 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "debug";
+		apple,always-on; /* Core AON device */
+	};
+
+	ps_nub_spmi0: power-controller@60 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x60 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "nub_spmi0";
+		apple,always-on; /* Core AON device */
+	};
+
+	ps_nub_aon: power-controller@70 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x70 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "nub_aon";
+		apple,always-on; /* Core AON device */
+	};
+
+	ps_nub_gpio: power-controller@80 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x80 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "nub_gpio";
+		apple,always-on; /* Core AON device */
+	};
+
+	ps_nub_fabric: power-controller@a8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0xa8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "nub_fabric";
+		apple,always-on; /* Core AON device */
+	};
+
+	ps_nub_sram: power-controller@b0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0xb0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "nub_sram";
+		apple,always-on; /* Core AON device */
+	};
+
+	ps_debug_usb: power-controller@b8 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0xb8 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "debug_usb";
+		apple,always-on; /* Core AON device */
+		power-domains = <&ps_debug>;
+	};
+
+	ps_debug_auth: power-controller@c0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0xc0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "debug_auth";
+		apple,always-on; /* Core AON device */
+		power-domains = <&ps_debug>;
+	};
+
+	ps_nub_spmi1: power-controller@68 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x68 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "nub_spmi1";
+		apple,always-on; /* Core AON device */
+	};
+
+	ps_msg: power-controller@78 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x78 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "msg";
+	};
+
+	ps_atc0_usb_aon: power-controller@88 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x88 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc0_usb_aon";
+	};
+
+	ps_atc1_usb_aon: power-controller@90 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x90 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc1_usb_aon";
+	};
+
+	ps_atc0_usb: power-controller@98 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0x98 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc0_usb";
+		power-domains = <&ps_atc0_usb_aon>, <&ps_atc0_common>;
+	};
+
+	ps_atc1_usb: power-controller@a0 {
+		compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
+		reg = <0xa0 4>;
+		#power-domain-cells = <0>;
+		#reset-cells = <0>;
+		label = "atc1_usb";
+		power-domains = <&ps_atc1_usb_aon>, <&ps_atc1_common>;
+	};
+};
diff --git a/arch/arm/dts/t8103-u-boot.dtsi b/arch/arm/dts/t8103-u-boot.dtsi
new file mode 100644
index 0000000..43f5529
--- /dev/null
+++ b/arch/arm/dts/t8103-u-boot.dtsi
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+ OR MIT
+
+&serial0 {
+	u-boot,dm-pre-reloc;
+};
+
+&pmgr {
+	u-boot,dm-pre-reloc;
+};
+
+&ps_sio_busif {
+	u-boot,dm-pre-reloc;
+};
+
+&ps_sio {
+	u-boot,dm-pre-reloc;
+};
+
+&ps_uart_p {
+	u-boot,dm-pre-reloc;
+};
+
+&ps_uart0 {
+	u-boot,dm-pre-reloc;
+};
diff --git a/arch/arm/dts/t8103.dtsi b/arch/arm/dts/t8103.dtsi
index 7d9cb27..ed7840f 100644
--- a/arch/arm/dts/t8103.dtsi
+++ b/arch/arm/dts/t8103.dtsi
@@ -11,7 +11,6 @@
 #include <dt-bindings/interrupt-controller/apple-aic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/pinctrl/apple.h>
-#include <dt-bindings/spmi/spmi.h>
 
 / {
 	compatible = "apple,t8103", "apple,arm-platform";
@@ -91,11 +90,11 @@
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupt-parent = <&aic>;
-		interrupt-names = "hyp-phys", "hyp-virt", "phys", "virt";
-		interrupts = <AIC_FIQ AIC_TMR_HV_PHYS IRQ_TYPE_LEVEL_HIGH>,
-			     <AIC_FIQ AIC_TMR_HV_VIRT IRQ_TYPE_LEVEL_HIGH>,
-			     <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
-			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "phys", "virt", "hyp-phys", "hyp-virt";
+		interrupts = <AIC_FIQ AIC_TMR_GUEST_PHYS IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_FIQ AIC_TMR_GUEST_VIRT IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_FIQ AIC_TMR_HV_PHYS IRQ_TYPE_LEVEL_HIGH>,
+			     <AIC_FIQ AIC_TMR_HV_VIRT IRQ_TYPE_LEVEL_HIGH>;
 	};
 
 	clkref: clock-ref {
@@ -105,24 +104,114 @@
 		clock-output-names = "clkref";
 	};
 
+	clk_120m: clock-120m {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <120000000>;
+		clock-output-names = "clk_120m";
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
 		ranges;
-		dma-ranges;
-		dma-coherent;
 		nonposted-mmio;
 
+		i2c0: i2c@235010000 {
+			compatible = "apple,t8103-i2c", "apple,i2c";
+			reg = <0x2 0x35010000 0x0 0x4000>;
+			clocks = <&clkref>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 627 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-0 = <&i2c0_pins>;
+			pinctrl-names = "default";
+			#address-cells = <0x1>;
+			#size-cells = <0x0>;
+			power-domains = <&ps_i2c0>;
+		};
+
+		i2c1: i2c@235014000 {
+			compatible = "apple,t8103-i2c", "apple,i2c";
+			reg = <0x2 0x35014000 0x0 0x4000>;
+			clocks = <&clkref>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 628 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-0 = <&i2c1_pins>;
+			pinctrl-names = "default";
+			#address-cells = <0x1>;
+			#size-cells = <0x0>;
+			power-domains = <&ps_i2c1>;
+		};
+
+		i2c2: i2c@235018000 {
+			compatible = "apple,t8103-i2c", "apple,i2c";
+			reg = <0x2 0x35018000 0x0 0x4000>;
+			clocks = <&clkref>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 629 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-0 = <&i2c2_pins>;
+			pinctrl-names = "default";
+			#address-cells = <0x1>;
+			#size-cells = <0x0>;
+			power-domains = <&ps_i2c2>;
+			status = "disabled"; /* not used in all devices */
+		};
+
+		i2c3: i2c@23501c000 {
+			compatible = "apple,t8103-i2c", "apple,i2c";
+			reg = <0x2 0x3501c000 0x0 0x4000>;
+			clocks = <&clkref>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 630 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-0 = <&i2c3_pins>;
+			pinctrl-names = "default";
+			#address-cells = <0x1>;
+			#size-cells = <0x0>;
+			power-domains = <&ps_i2c3>;
+		};
+
+		i2c4: i2c@235020000 {
+			compatible = "apple,t8103-i2c", "apple,i2c";
+			reg = <0x2 0x35020000 0x0 0x4000>;
+			clocks = <&clkref>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 631 IRQ_TYPE_LEVEL_HIGH>;
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+			#address-cells = <0x1>;
+			#size-cells = <0x0>;
+			power-domains = <&ps_i2c4>;
+			status = "disabled"; /* only used in J293 */
+		};
+
+		spi3: spi@23510c000 {
+			compatible = "apple,t8103-spi", "apple,spi";
+			reg = <0x2 0x3510c000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 617 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk_120m>;
+			pinctrl-0 = <&spi3_pins>;
+			pinctrl-names = "default";
+			power-domains = <&ps_spi3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled"; /* only used in J293/J313 */
+		};
+
 		serial0: serial@235200000 {
 			compatible = "apple,s5l-uart";
 			reg = <0x2 0x35200000 0x0 0x1000>;
 			reg-io-width = <4>;
 			interrupt-parent = <&aic>;
 			interrupts = <AIC_IRQ 605 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clkref>, <&clkref>, <&clkref>;
-			clock-names = "uart", "clk_uart_baud0", "clk_uart_baud1";
+			/*
+			 * TODO: figure out the clocking properly, there may
+			 * be a third selectable clock.
+			 */
+			clocks = <&clkref>, <&clkref>;
+			clock-names = "uart", "clk_uart_baud0";
 			power-domains = <&ps_uart0>;
 			status = "disabled";
 		};
@@ -133,8 +222,8 @@
 			reg-io-width = <4>;
 			interrupt-parent = <&aic>;
 			interrupts = <AIC_IRQ 607 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clkref>, <&clkref>, <&clkref>;
-			clock-names = "uart", "clk_uart_baud0", "clk_uart_baud1";
+			clocks = <&clkref>, <&clkref>;
+			clock-names = "uart", "clk_uart_baud0";
 			power-domains = <&ps_uart2>;
 			status = "disabled";
 		};
@@ -144,131 +233,28 @@
 			#interrupt-cells = <3>;
 			interrupt-controller;
 			reg = <0x2 0x3b100000 0x0 0x8000>;
+			power-domains = <&ps_aic>;
 		};
 
-		pmgr: power-controller@23b700000 {
+		pmgr: power-management@23b700000 {
 			compatible = "apple,t8103-pmgr", "apple,pmgr", "syscon", "simple-mfd";
 			#address-cells = <1>;
-			#size-cells = <0>;
-
-			reg = <0x2 0x3b700000 0x0 0x14000>;
-
-			ps_pcie_ref: power-controller@1a0 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x1a0>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "pcie_ref";
-			};
-
-			ps_imx: power-controller@1b8 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x1b8>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "imx";
-				apple,always-on;
-			};
-
-			ps_sio: power-controller@1c0 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x1c0>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "sio";
-			};
-
-			ps_uart_p: power-controller@220 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x220>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				power-domains = <&ps_sio>;
-				apple,domain-name = "uart_p";
-			};
-
-			ps_uart0: power-controller@270 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x270>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				power-domains = <&ps_uart_p>;
-				apple,domain-name = "uart0";
-			};
-
-			ps_uart1: power-controller@278 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x278>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "uart1";
-				power-domains = <&ps_uart_p>;
-			};
-
-			ps_uart2: power-controller@280 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x280>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "uart2";
-				power-domains = <&ps_uart_p>;
-			};
-
-			ps_uart3: power-controller@288 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x288>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "uart3";
-				power-domains = <&ps_uart_p>;
-			};
-
-			ps_apcie: power-controller@348 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x348>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "apcie";
-				power-domains = <&ps_imx>;
-			};
-
-			ps_apcie_gp: power-controller@3e8 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x3e8>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "apcie_gp";
-				power-domains = <&ps_apcie>;
-			};
-
-			ps_ans2: power-controller@3f0 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x3f0>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "ans2";
-				power-domains = <&ps_apcie_st>;
-			};
-
-			ps_apcie_st: power-controller@418 {
-				compatible = "apple,t8103-pmgr-pwrstate", "apple,pmgr-pwrstate";
-				reg = <0x418>;
-				#power-domain-cells = <0>;
-				#reset-cells = <0>;
-				apple,domain-name = "apcie_st";
-				power-domains = <&ps_apcie>;
-			};
+			#size-cells = <1>;
+			reg = <0x2 0x3b700000 0 0x14000>;
 		};
 
 		pinctrl_ap: pinctrl@23c100000 {
 			compatible = "apple,t8103-pinctrl", "apple,pinctrl";
 			reg = <0x2 0x3c100000 0x0 0x100000>;
+			power-domains = <&ps_gpio>;
 
 			gpio-controller;
 			#gpio-cells = <2>;
 			gpio-ranges = <&pinctrl_ap 0 0 212>;
+			apple,npins = <212>;
 
 			interrupt-controller;
+			#interrupt-cells = <2>;
 			interrupt-parent = <&aic>;
 			interrupts = <AIC_IRQ 190 IRQ_TYPE_LEVEL_HIGH>,
 				     <AIC_IRQ 191 IRQ_TYPE_LEVEL_HIGH>,
@@ -278,46 +264,67 @@
 				     <AIC_IRQ 195 IRQ_TYPE_LEVEL_HIGH>,
 				     <AIC_IRQ 196 IRQ_TYPE_LEVEL_HIGH>;
 
-			i2c0_pins: i2c0_pins {
-				pinmux = <APPLE_PINMUX(188, 1)>,
-					 <APPLE_PINMUX(192, 1)>;
+			i2c0_pins: i2c0-pins {
+				pinmux = <APPLE_PINMUX(192, 1)>,
+					 <APPLE_PINMUX(188, 1)>;
+			};
+
+			i2c1_pins: i2c1-pins {
+				pinmux = <APPLE_PINMUX(201, 1)>,
+					 <APPLE_PINMUX(199, 1)>;
+			};
+
+			i2c2_pins: i2c2-pins {
+				pinmux = <APPLE_PINMUX(163, 1)>,
+					 <APPLE_PINMUX(162, 1)>;
+			};
+
+			i2c3_pins: i2c3-pins {
+				pinmux = <APPLE_PINMUX(73, 1)>,
+					 <APPLE_PINMUX(72, 1)>;
+			};
+
+			i2c4_pins: i2c4-pins {
+				pinmux = <APPLE_PINMUX(135, 1)>,
+					 <APPLE_PINMUX(134, 1)>;
+			};
+
+			spi3_pins: spi3-pins {
+				pinmux = <APPLE_PINMUX(46, 1)>,
+					<APPLE_PINMUX(47, 1)>,
+					<APPLE_PINMUX(48, 1)>,
+					<APPLE_PINMUX(49, 1)>;
 			};
 
 			pcie_pins: pcie-pins {
 				pinmux = <APPLE_PINMUX(150, 1)>,
-				         <APPLE_PINMUX(151, 1)>,
+					 <APPLE_PINMUX(151, 1)>,
 					 <APPLE_PINMUX(32, 1)>;
 			};
 		};
 
-		pinctrl_aop: pinctrl@24a820000 {
-			compatible = "apple,t8103-pinctrl", "apple,pinctrl";
-			reg = <0x2 0x4a820000 0x0 0x4000>;
-
-			gpio-controller;
-			#gpio-cells = <2>;
-			gpio-ranges = <&pinctrl_aop 0 0 42>;
-
-			interrupt-controller;
+		spmi: spmi@23d0d9300 {
+			compatible = "apple,t8103-spmi", "apple,spmi";
+			reg = <0x2 0x3d0d9300 0x0 0x100>;
 			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 268 IRQ_TYPE_LEVEL_HIGH>,
-				     <AIC_IRQ 269 IRQ_TYPE_LEVEL_HIGH>,
-				     <AIC_IRQ 270 IRQ_TYPE_LEVEL_HIGH>,
-				     <AIC_IRQ 271 IRQ_TYPE_LEVEL_HIGH>,
-				     <AIC_IRQ 272 IRQ_TYPE_LEVEL_HIGH>,
-				     <AIC_IRQ 273 IRQ_TYPE_LEVEL_HIGH>,
-				     <AIC_IRQ 274 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <AIC_IRQ 343 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <2>;
+			#size-cells = <0>;
+			status = "disabled";
 		};
 
 		pinctrl_nub: pinctrl@23d1f0000 {
 			compatible = "apple,t8103-pinctrl", "apple,pinctrl";
 			reg = <0x2 0x3d1f0000 0x0 0x4000>;
+			power-domains = <&ps_nub_gpio>;
 
 			gpio-controller;
 			#gpio-cells = <2>;
 			gpio-ranges = <&pinctrl_nub 0 0 23>;
+			apple,npins = <23>;
 
 			interrupt-controller;
+			#interrupt-cells = <2>;
 			interrupt-parent = <&aic>;
 			interrupts = <AIC_IRQ 330 IRQ_TYPE_LEVEL_HIGH>,
 				     <AIC_IRQ 331 IRQ_TYPE_LEVEL_HIGH>,
@@ -328,6 +335,21 @@
 				     <AIC_IRQ 336 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		pmgr_mini: power-management@23d280000 {
+			compatible = "apple,t8103-pmgr", "apple,pmgr", "syscon", "simple-mfd";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x2 0x3d280000 0 0x4000>;
+		};
+
+		wdt: watchdog@23d2b0000 {
+			compatible = "apple,t8103-wdt", "apple,wdt";
+			reg = <0x2 0x3d2b0000 0x0 0x4000>;
+			clocks = <&clkref>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 338 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
 		pinctrl_smc: pinctrl@23e820000 {
 			compatible = "apple,t8103-pinctrl", "apple,pinctrl";
 			reg = <0x2 0x3e820000 0x0 0x4000>;
@@ -335,8 +357,10 @@
 			gpio-controller;
 			#gpio-cells = <2>;
 			gpio-ranges = <&pinctrl_smc 0 0 16>;
+			apple,npins = <16>;
 
 			interrupt-controller;
+			#interrupt-cells = <2>;
 			interrupt-parent = <&aic>;
 			interrupts = <AIC_IRQ 391 IRQ_TYPE_LEVEL_HIGH>,
 				     <AIC_IRQ 392 IRQ_TYPE_LEVEL_HIGH>,
@@ -347,100 +371,176 @@
 				     <AIC_IRQ 397 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
-		i2c0: i2c@20a110000 {
-			compatible = "apple,i2c-v0";
-			reg = <0x2 0x35010000 0x0 0x4000>;
+		smc_mbox: mbox@23e408000 {
+			compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4";
+			reg = <0x2 0x3e408000 0x0 0x4000>;
 			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 627 IRQ_TYPE_LEVEL_HIGH>;
-			clocks = <&clkref>;
-			pinctrl-0 = <&i2c0_pins>;
-			pinctrl-names = "default";
-			#address-cells = <0x1>;
-			#size-cells = <0x0>;
-
-			hpm0: hpm@38 {
-				compatible = "ti,tps6598x";
-				reg = <0x38>;
-			};
-
-			hpm1: hpm@3f {
-				compatible = "ti,tps6598x";
-				reg = <0x3f>;
-			};
-                };
-
-		ans_mbox: mbox@277400000 {
-			compatible = "apple,iop-mailbox-m1";
-			reg = <0x2 0x77400000 0x0 0x20000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 583 IRQ_TYPE_LEVEL_HIGH>,
-				     <AIC_IRQ 586 IRQ_TYPE_LEVEL_HIGH>;
-			power-domains = <&ps_ans2>;
-			#mbox-cells = <1>;
-			endpoints = <32>;
-		};
-
-		ans@27bcc0000 {
-			compatible = "apple,nvme-m1";
-			reg = <0x2 0x7bcc0000 0x0 0x40000>,
-			      <0x2 0x7bc50000 0x0 0x4000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 590 IRQ_TYPE_LEVEL_HIGH>;
-			power-domains = <&ps_apcie_st>;
-			mboxes = <&ans_mbox 32>;
-		};
-
-		pcie0_dart_0: iommu@681008000 {
-			compatible = "apple,t8103-dart", "apple,dart-m1";
-			reg = <0x6 0x81008000 0x0 0x4000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 696 IRQ_TYPE_LEVEL_HIGH>;
-			#iommu-cells = <1>;
-			status = "disabled";
-		};
-
-		pcie0_dart_1: iommu@682008000 {
-			compatible = "apple,t8103-dart", "apple,dart-m1";
-			reg = <0x6 0x82008000 0x0 0x4000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 699 IRQ_TYPE_LEVEL_HIGH>;
-			#iommu-cells = <1>;
-			status = "disabled";
-		};
-
-		pcie0_dart_2: iommu@683008000 {
-			compatible = "apple,t8103-dart", "apple,dart-m1";
-			reg = <0x6 0x83008000 0x0 0x4000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 702 IRQ_TYPE_LEVEL_HIGH>;
-			#iommu-cells = <1>;
-			status = "disabled";
-		};
-
-		smc_mbox: mbox@23e400000 {
-			compatible = "apple,iop-mailbox-m1";
-			reg = <0x2 0x3e400000 0x0 0x20000>;
-			#mbox-cells = <1>;
-			endpoints = <32>;
+			interrupts = <AIC_IRQ 400 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 401 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 402 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 403 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "send-empty", "send-not-empty",
+					  "recv-empty", "recv-not-empty";
+			#mbox-cells = <0>;
 		};
 
 		smc: smc@23e050000 {
-			compatible = "apple,smc-m1";
+			compatible = "apple,smc";
 			reg = <0x2 0x3e050000 0x0 0x4000>;
-			mboxes = <&smc_mbox 32>;
+			mboxes = <&smc_mbox>;
 			gpio-controller;
 			#gpio-cells = <2>;
 			gpio-13 = <0x00800000>;
 		};
 
+		pinctrl_aop: pinctrl@24a820000 {
+			compatible = "apple,t8103-pinctrl", "apple,pinctrl";
+			reg = <0x2 0x4a820000 0x0 0x4000>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl_aop 0 0 42>;
+			apple,npins = <42>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 268 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 269 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 270 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 271 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 272 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 273 IRQ_TYPE_LEVEL_HIGH>,
+				     <AIC_IRQ 274 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		ans_mbox: mbox@277408000 {
+			compatible = "apple,t8103-asc-mailbox", "apple,asc-mailbox-v4";
+			reg = <0x2 0x77408000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 583 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_IRQ 584 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_IRQ 585 IRQ_TYPE_LEVEL_HIGH>,
+				<AIC_IRQ 586 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "send-empty", "send-not-empty",
+				"recv-empty", "recv-not-empty";
+			#mbox-cells = <0>;
+			power-domains = <&ps_ans2>;
+		};
+
+		sart: sart@27bc50000 {
+			compatible = "apple,t8103-sart", "apple,sart2";
+			reg = <0x2 0x7bc50000 0x0 0x10000>;
+			power-domains = <&ps_ans2>;
+		};
+
+		nvme@27bcc0000 {
+			compatible = "apple,t8103-nvme-ans2", "apple,nvme-ans2";
+			reg = <0x2 0x7bcc0000 0x0 0x40000>,
+				<0x2 0x77400000 0x0 0x4000>;
+			reg-names = "nvme", "ans";
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 590 IRQ_TYPE_LEVEL_HIGH>;
+			mboxes = <&ans_mbox>;
+			apple,sart = <&sart>;
+			power-domains = <&ps_ans2>;
+			resets = <&ps_ans2>;
+		};
+
+		dwc3_0: usb@382280000 {
+			compatible = "apple,t8103-dwc3", "apple,dwc3", "snps,dwc3";
+			reg = <0x3 0x82280000 0x0 0x100000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 777 IRQ_TYPE_LEVEL_HIGH>;
+			usb-role-switch;
+			role-switch-default-mode = "host";
+			iommus = <&dwc3_0_dart_0 0>, <&dwc3_0_dart_1 1>;
+			power-domains = <&ps_atc0_usb>;
+		};
+
+		dwc3_0_dart_0: iommu@382f00000 {
+			compatible = "apple,t8103-dart";
+			reg = <0x3 0x82f00000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 781 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			power-domains = <&ps_atc0_usb>;
+		};
+
+		dwc3_0_dart_1: iommu@382f80000 {
+			compatible = "apple,t8103-dart";
+			reg = <0x3 0x82f80000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 781 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			power-domains = <&ps_atc0_usb>;
+		};
+
+		dwc3_1: usb@502280000 {
+			compatible = "apple,t8103-dwc3", "apple,dwc3", "snps,dwc3";
+			reg = <0x5 0x02280000 0x0 0x100000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 857 IRQ_TYPE_LEVEL_HIGH>;
+			usb-role-switch;
+			role-switch-default-mode = "host";
+			iommus = <&dwc3_1_dart_0 0>, <&dwc3_1_dart_1 1>;
+			power-domains = <&ps_atc1_usb>;
+		};
+
+		dwc3_1_dart_0: iommu@502f00000 {
+			compatible = "apple,t8103-dart";
+			reg = <0x5 0x02f00000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 861 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			power-domains = <&ps_atc1_usb>;
+		};
+
+		dwc3_1_dart_1: iommu@502f80000 {
+			compatible = "apple,t8103-dart";
+			reg = <0x5 0x02f80000 0x0 0x4000>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 861 IRQ_TYPE_LEVEL_HIGH>;
+			#iommu-cells = <1>;
+			power-domains = <&ps_atc1_usb>;
+		};
+
+		pcie0_dart_0: dart@681008000 {
+			compatible = "apple,t8103-dart";
+			reg = <0x6 0x81008000 0x0 0x4000>;
+			#iommu-cells = <1>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 696 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&ps_apcie_gp>;
+		};
+
+		pcie0_dart_1: dart@682008000 {
+			compatible = "apple,t8103-dart";
+			reg = <0x6 0x82008000 0x0 0x4000>;
+			#iommu-cells = <1>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 699 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&ps_apcie_gp>;
+		};
+
+		pcie0_dart_2: dart@683008000 {
+			compatible = "apple,t8103-dart";
+			reg = <0x6 0x83008000 0x0 0x4000>;
+			#iommu-cells = <1>;
+			interrupt-parent = <&aic>;
+			interrupts = <AIC_IRQ 702 IRQ_TYPE_LEVEL_HIGH>;
+			power-domains = <&ps_apcie_gp>;
+		};
+
 		pcie0: pcie@690000000 {
 			compatible = "apple,t8103-pcie", "apple,pcie";
+			device_type = "pci";
 
 			reg = <0x6 0x90000000 0x0 0x1000000>,
-			      <0x6 0x80000000 0x0 0x4000>,
-			      <0x6 0x81000000 0x0 0x8000>,
-			      <0x6 0x82000000 0x0 0x8000>,
-			      <0x6 0x83000000 0x0 0x8000>;
+			      <0x6 0x80000000 0x0 0x100000>,
+			      <0x6 0x81000000 0x0 0x4000>,
+			      <0x6 0x82000000 0x0 0x4000>,
+			      <0x6 0x83000000 0x0 0x4000>;
 			reg-names = "config", "rc", "port0", "port1", "port2";
 
 			interrupt-parent = <&aic>;
@@ -452,6 +552,7 @@
 			msi-parent = <&pcie0>;
 			msi-ranges = <&aic AIC_IRQ 704 IRQ_TYPE_EDGE_RISING 32>;
 
+
 			iommu-map = <0x100 &pcie0_dart_0 1 1>,
 				    <0x200 &pcie0_dart_1 1 1>,
 				    <0x300 &pcie0_dart_2 1 1>;
@@ -460,101 +561,136 @@
 			bus-range = <0 3>;
 			#address-cells = <3>;
 			#size-cells = <2>;
-			ranges = <0x43000000 0x6 0xa0000000 0x6 0xa0000000
-			          0x0 0x20000000>,
-				 <0x02000000 0x0 0xc0000000 0x6 0xc0000000
-				  0x0 0x40000000>;
+			ranges = <0x43000000 0x6 0xa0000000 0x6 0xa0000000 0x0 0x20000000>,
+				 <0x02000000 0x0 0xc0000000 0x6 0xc0000000 0x0 0x40000000>;
 
-			power-domains = <&ps_apcie>, <&ps_apcie_gp>, <&ps_pcie_ref>;
+			power-domains = <&ps_apcie_gp>;
 			pinctrl-0 = <&pcie_pins>;
 			pinctrl-names = "default";
 
-			device_type = "pci";
-			status = "disabled";
+			port00: pci@0,0 {
+				device_type = "pci";
+				reg = <0x0 0x0 0x0 0x0 0x0>;
+				reset-gpios = <&pinctrl_ap 152 GPIO_ACTIVE_LOW>;
+
+				#address-cells = <3>;
+				#size-cells = <2>;
+				ranges;
+
+				interrupt-controller;
+				#interrupt-cells = <1>;
+
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &port00 0 0 0 0>,
+						<0 0 0 2 &port00 0 0 0 1>,
+						<0 0 0 3 &port00 0 0 0 2>,
+						<0 0 0 4 &port00 0 0 0 3>;
+			};
+
+			port01: pci@1,0 {
+				device_type = "pci";
+				reg = <0x800 0x0 0x0 0x0 0x0>;
+				reset-gpios = <&pinctrl_ap 153 GPIO_ACTIVE_LOW>;
+
+				#address-cells = <3>;
+				#size-cells = <2>;
+				ranges;
+
+				interrupt-controller;
+				#interrupt-cells = <1>;
+
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &port01 0 0 0 0>,
+						<0 0 0 2 &port01 0 0 0 1>,
+						<0 0 0 3 &port01 0 0 0 2>,
+						<0 0 0 4 &port01 0 0 0 3>;
+			};
+
+			port02: pci@2,0 {
+				device_type = "pci";
+				reg = <0x1000 0x0 0x0 0x0 0x0>;
+				reset-gpios = <&pinctrl_ap 33 GPIO_ACTIVE_LOW>;
+
+				#address-cells = <3>;
+				#size-cells = <2>;
+				ranges;
+
+				interrupt-controller;
+				#interrupt-cells = <1>;
+
+				interrupt-map-mask = <0 0 0 7>;
+				interrupt-map = <0 0 0 1 &port02 0 0 0 0>,
+						<0 0 0 2 &port02 0 0 0 1>,
+						<0 0 0 3 &port02 0 0 0 2>,
+						<0 0 0 4 &port02 0 0 0 3>;
+			};
 		};
 
-		dwc3_0_dart_0: iommu@382f00000 {
-			compatible = "apple,t8103-dart";
-			reg = <0x3 0x82f00000 0x0 0x4000>;
+		dart_sio: iommu@235004000 {
+			compatible = "apple,t8103-dart", "apple,dart";
+			reg = <0x2 0x35004000 0x0 0x4000>;
 			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 781 IRQ_TYPE_LEVEL_HIGH>;
+			interrupts = <AIC_IRQ 635 IRQ_TYPE_LEVEL_HIGH>;
 			#iommu-cells = <1>;
-			status = "disabled";
+			power-domains = <&ps_sio_cpu>;
 		};
 
-		dwc3_0_dart_1: iommu@382f80000 {
-			compatible = "apple,t8103-dart";
-			reg = <0x3 0x82f80000 0x0 0x4000>;
+		nco_inp: clock-ref {
+			compatible = "fixed-factor-clock";
+			clocks = <&clkref>;
+			#clock-cells = <0>;
+			clock-mult = <75>;
+			clock-div = <2>; // 24 MHz * (75/2) = 900 MHz
+			clock-output-names = "nco_inp";
+		};
+
+		nco: nco@23b044000 {
+			compatible = "apple,t8103-nco", "apple,nco";
+			reg = <0x2 0x3b044000 0x0 0x14000>;
+			clocks = <&nco_inp>;
+			#clock-cells = <1>;
+			apple,nchannels = <5>;
+		};
+
+		admac: dma-controller@238200000 {
+			compatible = "apple,t8103-admac", "apple,admac";
+			reg = <0x2 0x38200000 0x0 0x34000>;
+			dma-channels = <12>;
 			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 781 IRQ_TYPE_LEVEL_HIGH>;
-			#iommu-cells = <1>;
-			status = "disabled";
+			interrupts = <AIC_IRQ 626 IRQ_TYPE_LEVEL_HIGH>;
+			#dma-cells = <1>;
+			iommus = <&dart_sio 2>;
+			power-domains = <&ps_sio_adma>;
 		};
 
-		dwc3_0: usb@382280000{
-			compatible = "snps,dwc3";
-			reg = <0x3 0x82280000 0x0 0x100000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 777 IRQ_TYPE_LEVEL_HIGH>;
-			dr_mode = "host";
-			iommus = <&dwc3_0_dart_0 0>, <&dwc3_0_dart_1 1>;
-			status = "disabled";
-		};
+		mca: mca {
+			compatible = "apple,t8103-mca", "apple,mca";
+			reg = <0x2 0x38400000 0x0 0x18000>,
+				<0x2 0x38300000 0x0 0x30000>;
+			reg-names = "clusters", "switch";
+			clocks = <&nco 0>, <&nco 1>, <&nco 2>, <&nco 3>;
+			power-domains = <&ps_mca0>; //, <&ps_mca1>, <&ps_mca2>, <&ps_mca3>, <&ps_mca4>, <&ps_mca5>;
+			resets = <&ps_mca0>, <&ps_mca1>, <&ps_mca2>, <&ps_mca3>, <&ps_mca4>, <&ps_mca5>;
 
-		dwc3_1_dart_0: iommu@502f00000 {
-			compatible = "apple,t8103-dart";
-			reg = <0x5 0x02f00000 0x0 0x4000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 861 IRQ_TYPE_LEVEL_HIGH>;
-			#iommu-cells = <1>;
-			status = "disabled";
-		};
+			#sound-dai-cells = <1>;
+			apple,nclusters = <6>;
+			apple,mclk-range = <2600000 25000000>;
 
-		dwc3_1_dart_1: iommu@502f80000 {
-			compatible = "apple,t8103-dart";
-			reg = <0x5 0x02f80000 0x0 0x4000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 861 IRQ_TYPE_LEVEL_HIGH>;
-			#iommu-cells = <1>;
-			status = "disabled";
-		};
+			route {
+				dmas = <&admac 2>;
+				dma-names = "tx";
+				apple,serdes = <1>;
+				sound-dai = <&mca 0>;
+			};
 
-		dwc3_1: usb@502280000{
-			compatible = "snps,dwc3";
-			reg = <0x5 0x02280000 0x0 0x100000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 857 IRQ_TYPE_LEVEL_HIGH>;
-			dr_mode = "host";
-			iommus = <&dwc3_1_dart_0 0>, <&dwc3_1_dart_1 1>;
-			status = "disabled";
-		};
-
-		reboot@23d2b0000 {
-			compatible = "apple,reboot-v0";
-			reg = <0x2 0x3d2b0000 0x0 0x4000>;
-		};
-
-		spi@23510c000 {
-			compatible = "apple,t8103-spi", "apple,spi";
-			reg = <0x2 0x3510c000 0x0 0x4000>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 617 IRQ_TYPE_LEVEL_HIGH>;
-			cs-gpios = <&pinctrl_ap 49 GPIO_ACTIVE_HIGH>;
-		};
-
-		spmi@23d0d8000 {
-			compatible = "apple,t8103-spmi", "apple,spmi";
-			reg = <0x2 0x3d0d9300 0x0 0x100>;
-			interrupt-parent = <&aic>;
-			interrupts = <AIC_IRQ 343 IRQ_TYPE_LEVEL_HIGH>;
-
-			#address-cells = <2>;
-			#size-cells = <0>;
-
-			pmu@f {
-				compatible = "apple,sera-pmu";
-				reg = <0xf SPMI_USID>;
+			route2 {
+				dmas = <&admac 6>;
+				dma-names = "tx";
+				apple,serdes = <3>;
+				sound-dai = <&mca 2>;
 			};
 		};
 	};
 };
+
+#include "t8103-pmgr.dtsi"
diff --git a/arch/arm/lib/crt0_aarch64_efi.S b/arch/arm/lib/crt0_aarch64_efi.S
index 492195f..7f38465 100644
--- a/arch/arm/lib/crt0_aarch64_efi.S
+++ b/arch/arm/lib/crt0_aarch64_efi.S
@@ -47,8 +47,8 @@
 
 extra_header_fields:
 	.quad	0				/* ImageBase */
-	.long	0x20				/* SectionAlignment */
-	.long	0x8				/* FileAlignment */
+	.long	0x200				/* SectionAlignment */
+	.long	0x200				/* FileAlignment */
 	.short	0				/* MajorOperatingSystemVersion */
 	.short	0				/* MinorOperatingSystemVersion */
 	.short	0				/* MajorImageVersion */
@@ -117,6 +117,7 @@
 	.short	0		/* NumberOfLineNumbers  (0 for executables) */
 	.long	0xe0500020	/* Characteristics (section flags) */
 
+	.align		9
 _start:
 	stp		x29, x30, [sp, #-32]!
 	mov		x29, sp
diff --git a/arch/arm/lib/crt0_arm_efi.S b/arch/arm/lib/crt0_arm_efi.S
index cc8a115..75ee37b 100644
--- a/arch/arm/lib/crt0_arm_efi.S
+++ b/arch/arm/lib/crt0_arm_efi.S
@@ -47,8 +47,8 @@
 
 extra_header_fields:
 	.long	0				/* image_base */
-	.long	0x20				/* SectionAlignment */
-	.long	0x8				/* FileAlignment */
+	.long	0x200				/* SectionAlignment */
+	.long	0x200				/* FileAlignment */
 	.short	0				/* MajorOperatingSystemVersion */
 	.short	0				/* MinorOperatingSystemVersion */
 	.short	0				/* MajorImageVersion */
@@ -115,6 +115,7 @@
 	.short	0		/* NumberOfLineNumbers  (0 for executables) */
 	.long	0xe0500020	/* Characteristics (section flags) */
 
+	.align		9
 _start:
 	stmfd		sp!, {r0-r2, lr}
 
diff --git a/arch/arm/lib/elf_aarch64_efi.lds b/arch/arm/lib/elf_aarch64_efi.lds
index 90af469..c0604da 100644
--- a/arch/arm/lib/elf_aarch64_efi.lds
+++ b/arch/arm/lib/elf_aarch64_efi.lds
@@ -18,7 +18,7 @@
 		*(.gnu.linkonce.t.*)
 		*(.srodata)
 		*(.rodata*)
-		. = ALIGN(16);
+		. = ALIGN(512);
 	}
 	_etext = .;
 	_text_size = . - _text;
@@ -44,7 +44,7 @@
 		*(.bss)
 		*(.bss.*)
 		*(COMMON)
-		. = ALIGN(16);
+		. = ALIGN(512);
 		_bss_end = .;
 		_edata = .;
 	}
diff --git a/arch/arm/lib/elf_arm_efi.lds b/arch/arm/lib/elf_arm_efi.lds
index d6d742e..767ebda 100644
--- a/arch/arm/lib/elf_arm_efi.lds
+++ b/arch/arm/lib/elf_arm_efi.lds
@@ -18,7 +18,7 @@
 		*(.gnu.linkonce.t.*)
 		*(.srodata)
 		*(.rodata*)
-		. = ALIGN(16);
+		. = ALIGN(512);
 	}
 	_etext = .;
 	_text_size = . - _text;
@@ -44,7 +44,7 @@
 		*(.bss)
 		*(.bss.*)
 		*(COMMON)
-		. = ALIGN(16);
+		. = ALIGN(512);
 		_bss_end = .;
 		_edata = .;
 	}
diff --git a/arch/arm/mach-apple/board.c b/arch/arm/mach-apple/board.c
index 0bfbc47..b7e8d21 100644
--- a/arch/arm/mach-apple/board.c
+++ b/arch/arm/mach-apple/board.c
@@ -119,30 +119,6 @@
 	return fdtdec_setup_memory_banksize();
 }
 
-#define APPLE_WDT_BASE		0x23d2b0000ULL
-
-#define APPLE_WDT_SYS_CTL_ENABLE	BIT(2)
-
-typedef struct apple_wdt {
-	u32	reserved0[3];
-	u32	chip_ctl;
-	u32	sys_tmr;
-	u32	sys_cmp;
-	u32	reserved1;
-	u32	sys_ctl;
-} apple_wdt_t;
-
-void reset_cpu(void)
-{
-	apple_wdt_t *wdt = (apple_wdt_t *)APPLE_WDT_BASE;
-
-	writel(0, &wdt->sys_cmp);
-	writel(APPLE_WDT_SYS_CTL_ENABLE, &wdt->sys_ctl);
-
-	while(1)
-		wfi();
-}
-
 extern long fw_dtb_pointer;
 
 void *board_fdt_blob_setup(int *err)
diff --git a/arch/arm/mach-bcm283x/msg.c b/arch/arm/mach-bcm283x/msg.c
index 01a8ed2..fe243e2 100644
--- a/arch/arm/mach-bcm283x/msg.c
+++ b/arch/arm/mach-bcm283x/msg.c
@@ -194,7 +194,7 @@
 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
 				     &msg_notify_vl805_reset->hdr);
 	if (ret) {
-		printf("bcm2711: Faild to load vl805's firmware, %d\n", ret);
+		printf("bcm2711: Failed to load vl805's firmware, %d\n", ret);
 		return -EIO;
 	}
 
diff --git a/arch/arm/mach-keystone/ddr3.c b/arch/arm/mach-keystone/ddr3.c
index 9ee3284..53117c2 100644
--- a/arch/arm/mach-keystone/ddr3.c
+++ b/arch/arm/mach-keystone/ddr3.c
@@ -344,7 +344,7 @@
 		puts("DDR3 ECC 2-bit error interrupted\n");
 
 		if (!ecc_test) {
-			puts("Reseting the device ...\n");
+			puts("Resetting the device ...\n");
 			reset_cpu();
 		}
 	}
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 7e9c206..a5a2087 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -21,6 +21,7 @@
 
 obj-y	= cpu.o
 obj-y	+= dram.o
+obj-$(CONFIG_DM_RESET) += system-controller.o
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_ARMADA_375) += ../../../drivers/ddr/marvell/axp/xor.o
 obj-$(CONFIG_ARMADA_38X) += ../../../drivers/ddr/marvell/a38x/xor.o
@@ -30,6 +31,17 @@
 
 extra-y += kwbimage.cfg
 
+ifneq ($(CONFIG_ARMADA_370)$(CONFIG_ARMADA_XP),)
+	KWB_REPLACE += CPU
+	KWB_CFG_CPU = SHEEVA
+else ifneq ($(CONFIG_ARMADA_375)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),)
+	KWB_REPLACE += CPU
+	KWB_CFG_CPU = A9
+endif
+
+KWB_REPLACE += LOAD_ADDRESS
+KWB_CFG_LOAD_ADDRESS = $(CONFIG_SPL_TEXT_BASE)
+
 KWB_REPLACE += BOOT_FROM
 ifneq ($(CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI),)
 	KWB_CFG_BOOT_FROM=spi
@@ -58,10 +70,20 @@
 KWB_CFG_SEC_FUSE_DUMP = a38x
 endif
 
+ifdef CONFIG_ARMADA_38X
+# BootROM output is by default enabled on pre-A38x and disabled on A38x
+# DEBUG flag on A38x for non-UART boot source only enable BootROM output and nothing more
+KWB_REPLACE += DEBUG
+KWB_CFG_DEBUG = 1
+endif
+
+quiet_cmd_kwbcfg = KWBCFG  $@
+cmd_kwbcfg = sed -ne '$(foreach V,$(KWB_REPLACE),s/\#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \
+	<$< >$(dir $@)$(@F)
+
 $(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \
 		include/config/auto.conf
-	$(Q)sed -ne '$(foreach V,$(KWB_REPLACE),s/^#@$(V)/$(V) $(KWB_CFG_$(V))/;)p' \
-	<$< >$(dir $@)$(@F)
+	$(call cmd,kwbcfg)
 
 endif # CONFIG_SPL_BUILD
 obj-y	+= gpio.o
diff --git a/arch/arm/mach-mvebu/include/mach/cpu.h b/arch/arm/mach-mvebu/include/mach/cpu.h
index a7a62c7..b99d86a 100644
--- a/arch/arm/mach-mvebu/include/mach/cpu.h
+++ b/arch/arm/mach-mvebu/include/mach/cpu.h
@@ -74,10 +74,11 @@
 /*
  * Default Device Address MAP BAR values
  */
+#define MBUS_PCI_MAX_PORTS	6
 #define MBUS_PCI_MEM_BASE	MVEBU_SDRAM_SIZE_MAX
-#define MBUS_PCI_MEM_SIZE	(128 << 20)
+#define MBUS_PCI_MEM_SIZE	((MBUS_PCI_MAX_PORTS * 128) << 20)
 #define MBUS_PCI_IO_BASE	0xF1100000
-#define MBUS_PCI_IO_SIZE	(64 << 10)
+#define MBUS_PCI_IO_SIZE	((MBUS_PCI_MAX_PORTS * 64) << 10)
 #define MBUS_SPI_BASE		0xF4000000
 #define MBUS_SPI_SIZE		(8 << 20)
 #define MBUS_DFX_BASE		0xF6000000
diff --git a/arch/arm/mach-mvebu/kwbimage.cfg.in b/arch/arm/mach-mvebu/kwbimage.cfg.in
index 049d23c..ccb0997 100644
--- a/arch/arm/mach-mvebu/kwbimage.cfg.in
+++ b/arch/arm/mach-mvebu/kwbimage.cfg.in
@@ -5,8 +5,14 @@
 # Armada 38x uses version 1 image format
 VERSION		1
 
+# Type of the CPU core
+#@CPU
+
 # Boot Media configurations
 #@BOOT_FROM
 
-# Binary Header (bin_hdr) with DDR3 training code
-BINARY spl/u-boot-spl.bin
+# Enable BootROM output via DEBUG flag on SoCs which require it
+#@DEBUG
+
+# Include U-Boot SPL with DDR3 training code into Binary Header
+BINARY spl/u-boot-spl.bin #@LOAD_ADDRESS
diff --git a/arch/arm/mach-mvebu/serdes/a38x/Makefile b/arch/arm/mach-mvebu/serdes/a38x/Makefile
index 917fc13..5a70b37 100644
--- a/arch/arm/mach-mvebu/serdes/a38x/Makefile
+++ b/arch/arm/mach-mvebu/serdes/a38x/Makefile
@@ -1,6 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0+
 
-obj-$(CONFIG_SPL_BUILD)	= ctrl_pex.o
 obj-$(CONFIG_SPL_BUILD)	+= high_speed_env_spec.o
 obj-$(CONFIG_SPL_BUILD)	+= high_speed_env_spec-38x.o
 obj-$(CONFIG_SPL_BUILD)	+= seq_exec.o
diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
deleted file mode 100644
index 55c3f9c..0000000
--- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.c
+++ /dev/null
@@ -1,64 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) Marvell International Ltd. and its affiliates
- */
-
-#include <common.h>
-#include <spl.h>
-#include <asm/io.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/soc.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-
-#include "ctrl_pex.h"
-#include "sys_env_lib.h"
-
-__weak void board_pex_config(void)
-{
-	/* nothing in this weak default implementation */
-}
-
-int hws_pex_config(const struct serdes_map *serdes_map, u8 count)
-{
-	enum serdes_type serdes_type;
-	u32 idx, tmp;
-
-	DEBUG_INIT_FULL_S("\n### hws_pex_config ###\n");
-
-	tmp = reg_read(SOC_CONTROL_REG1);
-	tmp &= ~0x03;
-
-	for (idx = 0; idx < count; idx++) {
-		serdes_type = serdes_map[idx].serdes_type;
-		if ((serdes_type != PEX0) &&
-		    ((serdes_map[idx].serdes_mode == PEX_ROOT_COMPLEX_X4) ||
-		     (serdes_map[idx].serdes_mode == PEX_END_POINT_X4))) {
-			/* for PEX by4 - relevant for the first port only */
-			continue;
-		}
-
-		switch (serdes_type) {
-		case PEX0:
-			tmp |= 0x1 << PCIE0_ENABLE_OFFS;
-			break;
-		case PEX1:
-			tmp |= 0x1 << PCIE1_ENABLE_OFFS;
-			break;
-		case PEX2:
-			tmp |= 0x1 << PCIE2_ENABLE_OFFS;
-			break;
-		case PEX3:
-			tmp |= 0x1 << PCIE3_ENABLE_OFFS;
-			break;
-		default:
-			break;
-		}
-	}
-
-	reg_write(SOC_CONTROL_REG1, tmp);
-
-	board_pex_config();
-
-	return MV_OK;
-}
diff --git a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h b/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
deleted file mode 100644
index 64193d5..0000000
--- a/arch/arm/mach-mvebu/serdes/a38x/ctrl_pex.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) Marvell International Ltd. and its affiliates
- */
-
-#ifndef _CTRL_PEX_H
-#define _CTRL_PEX_H
-
-#include <pci.h>
-#include "high_speed_env_spec.h"
-
-/* Direct access to PEX0 Root Port's PCIe Capability structure */
-#define PEX0_RP_PCIE_CFG_OFFSET		(0x00080000 + 0x60)
-
-/* SOC_CONTROL_REG1 fields */
-#define PCIE0_ENABLE_OFFS		0
-#define PCIE0_ENABLE_MASK		(0x1 << PCIE0_ENABLE_OFFS)
-#define PCIE1_ENABLE_OFFS		1
-#define PCIE1_ENABLE_MASK		(0x1 << PCIE1_ENABLE_OFFS)
-#define PCIE2_ENABLE_OFFS		2
-#define PCIE2_ENABLE_MASK		(0x1 << PCIE2_ENABLE_OFFS)
-#define PCIE3_ENABLE_OFFS		3
-#define PCIE4_ENABLE_MASK		(0x1 << PCIE3_ENABLE_OFFS)
-
-int hws_pex_config(const struct serdes_map *serdes_map, u8 count);
-void board_pex_config(void);
-
-#endif
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
index 9ba60b5..2e467b5 100644
--- a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
@@ -12,7 +12,6 @@
 
 #include "high_speed_env_spec.h"
 #include "sys_env_lib.h"
-#include "ctrl_pex.h"
 
 /*
  * serdes_seq_db - holds all serdes sequences, their size and the
@@ -1555,9 +1554,6 @@
 		   After finish the Power_up sequence for all lanes,
 		   the lanes should be released from reset state.       */
 		CHECK_STATUS(hws_pex_tx_config_seq(serdes_map, count));
-
-		/* PEX configuration */
-		CHECK_STATUS(hws_pex_config(serdes_map, count));
 	}
 
 	/* USB2 configuration */
@@ -1743,21 +1739,6 @@
 				else
 					reg_data &= ~0x4000;
 				reg_write(SOC_CONTROL_REG1, reg_data);
-
-				/*
-				 * Set Maximum Link Width to X1 or X4 in Root
-				 * Port's PCIe Link Capability register.
-				 * This register is read-only but if is not set
-				 * correctly then access to PCI config space of
-				 * endpoint card behind this Root Port does not
-				 * work.
-				 */
-				reg_data = reg_read(PEX0_RP_PCIE_CFG_OFFSET +
-						    PCI_EXP_LNKCAP);
-				reg_data &= ~PCI_EXP_LNKCAP_MLW;
-				reg_data |= (is_pex_by1 ? 1 : 4) << 4;
-				reg_write(PEX0_RP_PCIE_CFG_OFFSET +
-					  PCI_EXP_LNKCAP, reg_data);
 			}
 
 			CHECK_STATUS(mv_seq_exec(serdes_num, PEX_POWER_UP_SEQ));
diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c
new file mode 100644
index 0000000..ea858b2
--- /dev/null
+++ b/arch/arm/mach-mvebu/system-controller.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0+
+// (C) 2021 Pali Rohár <pali@kernel.org>
+
+#include <common.h>
+#include <dm.h>
+#include <reset-uclass.h>
+#include <asm/io.h>
+
+#define MVEBU_SOC_CONTROL_1_REG 0x4
+
+#define MVEBU_PCIE_ID 0
+
+struct mvebu_reset_data {
+	void *base;
+};
+
+static int mvebu_reset_of_xlate(struct reset_ctl *rst,
+				struct ofnode_phandle_args *args)
+{
+	if (args->args_count < 2)
+		return -EINVAL;
+
+	rst->id = args->args[0];
+	rst->data = args->args[1];
+
+	/* Currently only PCIe is implemented */
+	if (rst->id != MVEBU_PCIE_ID)
+		return -EINVAL;
+
+	/* Four PCIe enable bits are shared across more PCIe links */
+	if (!(rst->data >= 0 && rst->data <= 3))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mvebu_reset_request(struct reset_ctl *rst)
+{
+	return 0;
+}
+
+static int mvebu_reset_free(struct reset_ctl *rst)
+{
+	return 0;
+}
+
+static int mvebu_reset_assert(struct reset_ctl *rst)
+{
+	struct mvebu_reset_data *data = dev_get_priv(rst->dev);
+
+	clrbits_32(data->base + MVEBU_SOC_CONTROL_1_REG, BIT(rst->data));
+	return 0;
+}
+
+static int mvebu_reset_deassert(struct reset_ctl *rst)
+{
+	struct mvebu_reset_data *data = dev_get_priv(rst->dev);
+
+	setbits_32(data->base + MVEBU_SOC_CONTROL_1_REG, BIT(rst->data));
+	return 0;
+}
+
+static int mvebu_reset_status(struct reset_ctl *rst)
+{
+	struct mvebu_reset_data *data = dev_get_priv(rst->dev);
+
+	return !(readl(data->base + MVEBU_SOC_CONTROL_1_REG) & BIT(rst->data));
+}
+
+static int mvebu_reset_of_to_plat(struct udevice *dev)
+{
+	struct mvebu_reset_data *data = dev_get_priv(dev);
+
+	data->base = (void *)dev_read_addr(dev);
+	if ((fdt_addr_t)data->base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct udevice_id mvebu_reset_of_match[] = {
+	{ .compatible = "marvell,armada-370-xp-system-controller" },
+	{ .compatible = "marvell,armada-375-system-controller" },
+	{ .compatible = "marvell,armada-380-system-controller" },
+	{ .compatible = "marvell,armada-390-system-controller" },
+	{ },
+};
+
+static struct reset_ops mvebu_reset_ops = {
+	.of_xlate = mvebu_reset_of_xlate,
+	.request = mvebu_reset_request,
+	.rfree = mvebu_reset_free,
+	.rst_assert = mvebu_reset_assert,
+	.rst_deassert = mvebu_reset_deassert,
+	.rst_status = mvebu_reset_status,
+};
+
+U_BOOT_DRIVER(mvebu_reset) = {
+	.name = "mvebu-reset",
+	.id = UCLASS_RESET,
+	.of_match = mvebu_reset_of_match,
+	.of_to_plat = mvebu_reset_of_to_plat,
+	.priv_auto = sizeof(struct mvebu_reset_data),
+	.ops = &mvebu_reset_ops,
+};
diff --git a/arch/riscv/lib/crt0_riscv_efi.S b/arch/riscv/lib/crt0_riscv_efi.S
index b0a7a39..a01e08a 100644
--- a/arch/riscv/lib/crt0_riscv_efi.S
+++ b/arch/riscv/lib/crt0_riscv_efi.S
@@ -71,8 +71,8 @@
 #else
 	.quad	0				/* ImageBase */
 #endif
-	.long	0x20				/* SectionAlignment */
-	.long	0x8				/* FileAlignment */
+	.long	0x200				/* SectionAlignment */
+	.long	0x200				/* FileAlignment */
 	.short	0				/* MajorOperatingSystemVersion */
 	.short	0				/* MinorOperatingSystemVersion */
 	.short	1				/* MajorImageVersion */
@@ -110,16 +110,6 @@
 	.quad	0				/* ExceptionTable */
 	.quad	0				/* CertificationTable */
 	.quad	0				/* BaseRelocationTable */
-	.quad	0				/* Debug */
-	.quad	0				/* Architecture */
-	.quad	0				/* Global Ptr */
-	.quad	0				/* TLS Table */
-	.quad	0				/* Load Config Table */
-	.quad	0				/* Bound Import */
-	.quad	0				/* IAT */
-	.quad	0				/* Delay Import Descriptor */
-	.quad	0				/* CLR Runtime Header */
-	.quad	0				/* Reserved */
 
 	/* Section table */
 section_table:
@@ -158,6 +148,7 @@
 	.short	0		/* NumberOfLineNumbers  (0 for executables) */
 	.long	0xe0500020	/* Characteristics (section flags) */
 
+	.align	9
 _start:
 	addi		sp, sp, -(SIZE_LONG * 3)
 	SAVE_LONG(a0, 0)
diff --git a/arch/riscv/lib/elf_riscv32_efi.lds b/arch/riscv/lib/elf_riscv32_efi.lds
index 629705f..c3e0d20 100644
--- a/arch/riscv/lib/elf_riscv32_efi.lds
+++ b/arch/riscv/lib/elf_riscv32_efi.lds
@@ -20,7 +20,7 @@
 		*(.gnu.linkonce.t.*)
 		*(.srodata)
 		*(.rodata*)
-		. = ALIGN(16);
+		. = ALIGN(512);
 	}
 	_etext = .;
 	_text_size = . - _text;
@@ -46,7 +46,7 @@
 		*(.bss)
 		*(.bss.*)
 		*(COMMON)
-		. = ALIGN(16);
+		. = ALIGN(512);
 		_bss_end = .;
 		_edata = .;
 	}
diff --git a/arch/riscv/lib/elf_riscv64_efi.lds b/arch/riscv/lib/elf_riscv64_efi.lds
index aece030..ecb9139 100644
--- a/arch/riscv/lib/elf_riscv64_efi.lds
+++ b/arch/riscv/lib/elf_riscv64_efi.lds
@@ -20,7 +20,7 @@
 		*(.gnu.linkonce.t.*)
 		*(.srodata)
 		*(.rodata*)
-		. = ALIGN(16);
+		. = ALIGN(512);
 	}
 	_etext = .;
 	_text_size = . - _text;
@@ -46,7 +46,7 @@
 		*(.bss)
 		*(.bss.*)
 		*(COMMON)
-		. = ALIGN(16);
+		. = ALIGN(512);
 		_bss_end = .;
 		_edata = .;
 	}
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 6837bfc..40ebe32 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -624,7 +624,13 @@
 	return os_dirent_typename[OS_FILET_UNKNOWN];
 }
 
-int os_get_filesize(const char *fname, loff_t *size)
+/*
+ * For compatibility reasons avoid loff_t here.
+ * U-Boot defines loff_t as long long.
+ * But /usr/include/linux/types.h may not define it at all.
+ * Alpine Linux being one example.
+ */
+int os_get_filesize(const char *fname, long long *size)
 {
 	struct stat buf;
 	int ret;
@@ -667,7 +673,7 @@
 {
 	struct sandbox_state *state = state_get_current();
 	int fd, ret;
-	loff_t size;
+	long long size;
 
 	ret = os_get_filesize(fname, &size);
 	if (ret < 0)
diff --git a/arch/x86/config.mk b/arch/x86/config.mk
index 589f2ae..889497b 100644
--- a/arch/x86/config.mk
+++ b/arch/x86/config.mk
@@ -20,6 +20,11 @@
 endif
 endif
 
+EFI_IS_32BIT := $(IS_32BIT)
+ifdef CONFIG_EFI_STUB_64BIT
+EFI_IS_32BIT :=
+endif
+
 ifeq ($(IS_32BIT),y)
 PLATFORM_CPPFLAGS += -march=i386 -m32
 else
@@ -44,8 +49,14 @@
 # Compiler flags to be removed when building UEFI applications
 CFLAGS_NON_EFI := -mregparm=3 -fstack-protector-strong
 
-ifeq ($(CONFIG_EFI_STUB_64BIT),)
+ifeq ($(IS_32BIT),y)
+EFIPAYLOAD_BFDARCH = i386
+else
 CFLAGS_EFI += $(call cc-option, -mno-red-zone)
+EFIPAYLOAD_BFDARCH = x86_64
+endif
+
+ifeq ($(EFI_IS_32BIT),y)
 EFIARCH = ia32
 EFIPAYLOAD_BFDTARGET = elf32-i386
 else
@@ -53,8 +64,6 @@
 EFIPAYLOAD_BFDTARGET = elf64-x86-64
 endif
 
-EFIPAYLOAD_BFDARCH = i386
-
 LDSCRIPT_EFI := $(srctree)/arch/x86/lib/elf_$(EFIARCH)_efi.lds
 EFISTUB := crt0_$(EFIARCH)_efi.o reloc_$(EFIARCH)_efi.o
 OBJCOPYFLAGS_EFI += --target=efi-app-$(EFIARCH)
diff --git a/arch/x86/cpu/broadwell/cpu_from_spl.c b/arch/x86/cpu/broadwell/cpu_from_spl.c
index e5f62e7..df5a967 100644
--- a/arch/x86/cpu/broadwell/cpu_from_spl.c
+++ b/arch/x86/cpu/broadwell/cpu_from_spl.c
@@ -23,7 +23,7 @@
 {
 	struct spl_handoff *ho;
 
-	ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(*ho));
+	ho = bloblist_find(BLOBLISTT_U_BOOT_SPL_HANDOFF, sizeof(*ho));
 	if (!ho)
 		return log_msg_ret("Missing SPL hand-off info", -ENOENT);
 	handoff_load_dram_size(ho);
@@ -56,7 +56,7 @@
 {
 	struct spl_handoff *ho;
 
-	ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(*ho));
+	ho = bloblist_find(BLOBLISTT_U_BOOT_SPL_HANDOFF, sizeof(*ho));
 	if (!ho)
 		return log_msg_ret("Missing SPL hand-off info", -ENOENT);
 	handoff_load_dram_banks(ho);
diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk
index d3033b4..87e242a 100644
--- a/arch/x86/cpu/config.mk
+++ b/arch/x86/cpu/config.mk
@@ -9,7 +9,7 @@
 LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16)
 
 ifdef CONFIG_X86_64
-ifndef CONFIG_SPL_BUILD
+ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_EFI_APP),)
 LDSCRIPT = $(srctree)/arch/x86/cpu/u-boot-64.lds
 endif
 endif
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c
index 04ce188..b777856 100644
--- a/arch/x86/cpu/efi/payload.c
+++ b/arch/x86/cpu/efi/payload.c
@@ -51,7 +51,7 @@
 
 	end = (struct efi_mem_desc *)((ulong)map + size);
 	desc = map->desc;
-	for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) {
+	for (; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) {
 		if (desc->type != EFI_CONVENTIONAL_MEMORY ||
 		    desc->physical_start >= 1ULL << 32)
 			continue;
@@ -89,7 +89,7 @@
 	end = (struct efi_mem_desc *)((ulong)map + size);
 	gd->ram_size = 0;
 	desc = map->desc;
-	for (; desc < end; desc = efi_get_next_mem_desc(map, desc)) {
+	for (; desc < end; desc = efi_get_next_mem_desc(desc, map->desc_size)) {
 		if (desc->type < EFI_MMAP_IO)
 			gd->ram_size += desc->num_pages << EFI_PAGE_SHIFT;
 	}
@@ -114,7 +114,7 @@
 	desc = map->desc;
 	for (num_banks = 0;
 	     desc < end && num_banks < CONFIG_NR_DRAM_BANKS;
-	     desc = efi_get_next_mem_desc(map, desc)) {
+	     desc = efi_get_next_mem_desc(desc, map->desc_size)) {
 		/*
 		 * We only use conventional memory and ignore
 		 * anything less than 1MB.
@@ -197,7 +197,7 @@
 
 	end = (struct efi_mem_desc *)((ulong)map + size);
 	for (desc = map->desc; desc < end;
-	     desc = efi_get_next_mem_desc(map, desc)) {
+	     desc = efi_get_next_mem_desc(desc, map->desc_size)) {
 		if (desc->num_pages == 0)
 			continue;
 
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c
index a3674e8..6a38761 100644
--- a/arch/x86/cpu/x86_64/cpu.c
+++ b/arch/x86/cpu/x86_64/cpu.c
@@ -45,3 +45,8 @@
 {
 	return CONFIG_CPU_ADDR_BITS;
 }
+
+int x86_cpu_init_f(void)
+{
+	return 0;
+}
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 18757b2..e5235b7 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -65,9 +65,8 @@
 
 lib-$(CONFIG_USE_PRIVATE_LIBGCC) += div64.o
 
-ifeq ($(CONFIG_$(SPL_)X86_64),)
-obj-$(CONFIG_EFI_APP) += crt0_ia32_efi.o reloc_ia32_efi.o
-endif
+obj-$(CONFIG_EFI_APP_32BIT) += crt0_ia32_efi.o reloc_ia32_efi.o
+obj-$(CONFIG_EFI_APP_64BIT) += crt0_x86_64_efi.o reloc_x86_64_efi.o
 
 ifneq ($(CONFIG_EFI_STUB),)
 
diff --git a/arch/x86/lib/elf_x86_64_efi.lds b/arch/x86/lib/elf_x86_64_efi.lds
index b436429..7572740 100644
--- a/arch/x86/lib/elf_x86_64_efi.lds
+++ b/arch/x86/lib/elf_x86_64_efi.lds
@@ -63,6 +63,7 @@
 		*(.rela.data*)
 		*(.rela.got)
 		*(.rela.stab)
+                *(.rela.u_boot_list*)
 	}
 
 	. = ALIGN(4096);
@@ -70,9 +71,11 @@
 	. = ALIGN(4096);
 	.dynstr : { *(.dynstr) }
 	. = ALIGN(4096);
+
+        /DISCARD/ : { *(.eh_frame) }
+
 	.ignored.reloc : {
 		*(.rela.reloc)
-		*(.eh_frame)
 		*(.note.GNU-stack)
 	}
 
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c
index 6fe5151..9060d19 100644
--- a/arch/x86/lib/relocate.c
+++ b/arch/x86/lib/relocate.c
@@ -35,6 +35,7 @@
 	return 0;
 }
 
+#ifndef CONFIG_EFI_APP
 int clear_bss(void)
 {
 	ulong dst_addr = (ulong)&__bss_start + gd->reloc_off;
@@ -46,6 +47,7 @@
 
 	return 0;
 }
+#endif
 
 #if CONFIG_IS_ENABLED(X86_64)
 static void do_elf_reloc_fixups64(unsigned int text_base, uintptr_t size,
diff --git a/board/gdsys/a38x/MAINTAINERS b/board/gdsys/a38x/MAINTAINERS
index d31e675..6492e79 100644
--- a/board/gdsys/a38x/MAINTAINERS
+++ b/board/gdsys/a38x/MAINTAINERS
@@ -1,5 +1,4 @@
 A38X BOARD
-M:	Dirk Eibach <dirk.eibach@gdsys.cc>
 M:	Mario Six <mario.six@gdsys.cc>
 S:	Maintained
 F:	board/gdsys/a38x/
diff --git a/board/gdsys/a38x/controlcenterdc.c b/board/gdsys/a38x/controlcenterdc.c
index dc424f2..7d65400 100644
--- a/board/gdsys/a38x/controlcenterdc.c
+++ b/board/gdsys/a38x/controlcenterdc.c
@@ -94,12 +94,16 @@
 	return 0;
 }
 
-void board_pex_config(void)
+void spl_board_init(void)
 {
 #ifdef CONFIG_SPL_BUILD
 	uint k;
 	struct gpio_desc gpio = {};
 
+	/* Enable PCIe link 2 */
+	setbits_32(MVEBU_REGISTER(0x18204), BIT(2));
+	mdelay(10);
+
 	if (!request_gpio_by_name(&gpio, "pca9698@22", 31, "fpga-program-gpio")) {
 		/* prepare FPGA reconfiguration */
 		dm_gpio_set_dir_flags(&gpio, GPIOD_IS_OUT);
diff --git a/board/gdsys/mpc8308/MAINTAINERS b/board/gdsys/mpc8308/MAINTAINERS
index dc0b389..57faba4 100644
--- a/board/gdsys/mpc8308/MAINTAINERS
+++ b/board/gdsys/mpc8308/MAINTAINERS
@@ -1,5 +1,5 @@
 MPC8308 BOARD
-M:	Dirk Eibach <dirk.eibach@gdsys.cc>
+M:	Mario Six <mario.six@gdsys.cc>
 S:	Maintained
 F:	board/gdsys/mpc8308/
 F:	include/configs/gazerbeam.h
diff --git a/board/iomega/iconnect/MAINTAINERS b/board/iomega/iconnect/MAINTAINERS
index 167cf07..a1b018e 100644
--- a/board/iomega/iconnect/MAINTAINERS
+++ b/board/iomega/iconnect/MAINTAINERS
@@ -1,4 +1,5 @@
 ICONNECT BOARD
+M:      Tony Dinh <mibodhi@gmail.com>
 M:	Luka Perkov <luka@openwrt.org>
 S:	Maintained
 F:	board/iomega/iconnect/
diff --git a/board/iomega/iconnect/iconnect.c b/board/iomega/iconnect/iconnect.c
index fe4be28..9e123aa 100644
--- a/board/iomega/iconnect/iconnect.c
+++ b/board/iomega/iconnect/iconnect.c
@@ -92,3 +92,10 @@
 
 	return 0;
 }
+
+int board_late_init(void)
+{
+	/* Do late init to ensure successful enumeration of PCIe devices */
+	pci_init();
+	return 0;
+}
diff --git a/boot/image.c b/boot/image.c
index f792f2a..c7ab034 100644
--- a/boot/image.c
+++ b/boot/image.c
@@ -102,9 +102,6 @@
 	{	IH_OS_INVALID,	"invalid",	"Invalid OS",		},
 	{       IH_OS_ARM_TRUSTED_FIRMWARE, "arm-trusted-firmware", "ARM Trusted Firmware"  },
 	{	IH_OS_LINUX,	"linux",	"Linux",		},
-#if defined(USE_HOSTCC)
-	{	IH_OS_LYNXOS,	"lynxos",	"LynxOS",		},
-#endif
 	{	IH_OS_NETBSD,	"netbsd",	"NetBSD",		},
 	{	IH_OS_OSE,	"ose",		"Enea OSE",		},
 	{	IH_OS_PLAN9,	"plan9",	"Plan 9",		},
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index a32acca..fcfee5e 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -1355,9 +1355,11 @@
 	struct pxe_label *label;
 	struct list_head *pos;
 	struct menu *m;
+	char *label_override;
 	int err;
 	int i = 1;
 	char *default_num = NULL;
+	char *override_num = NULL;
 
 	/*
 	 * Create a menu and add items for all the labels.
@@ -1367,6 +1369,8 @@
 	if (!m)
 		return NULL;
 
+	label_override = env_get("pxe_label_override");
+
 	list_for_each(pos, &cfg->labels) {
 		label = list_entry(pos, struct pxe_label, list);
 
@@ -1378,6 +1382,17 @@
 		if (cfg->default_label &&
 		    (strcmp(label->name, cfg->default_label) == 0))
 			default_num = label->num;
+		if (label_override && !strcmp(label->name, label_override))
+			override_num = label->num;
+	}
+
+
+	if (label_override) {
+		if (override_num)
+			default_num = override_num;
+		else
+			printf("Missing override pxe label: %s\n",
+			      label_override);
 	}
 
 	/*
diff --git a/cmd/Kconfig b/cmd/Kconfig
index d70dbd4..dd7ab8d 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1012,7 +1012,7 @@
 	select IDE
 	help
 	  Provides an 'ide' command which allows accessing the IDE drive,
-	  reseting the IDE interface, printing the partition table and
+	  resetting the IDE interface, printing the partition table and
 	  geting device info. It also enables the 'diskboot' command which
 	  permits booting from an IDE drive.
 
diff --git a/cmd/Makefile b/cmd/Makefile
index e31ac15..6623d7e 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -58,7 +58,7 @@
 obj-$(CONFIG_CMD_ECHO) += echo.o
 obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
 obj-$(CONFIG_CMD_EEPROM) += eeprom.o
-obj-$(CONFIG_EFI_STUB) += efi.o
+obj-$(CONFIG_EFI) += efi.o
 obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o
 obj-$(CONFIG_CMD_ELF) += elf.o
 obj-$(CONFIG_HUSH_PARSER) += exit.o
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/cmd/bootefi.c b/cmd/bootefi.c
index 83eab0b..3a8b2b6 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -310,6 +310,8 @@
 	/* Create memory reservations as indicated by the device tree */
 	efi_carve_out_dt_rsv(fdt);
 
+	efi_try_purge_kaslr_seed(fdt);
+
 	/* Install device tree as UEFI table */
 	ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
 	if (ret != EFI_SUCCESS) {
diff --git a/cmd/efi.c b/cmd/efi.c
index f2ed26b..c0384e0 100644
--- a/cmd/efi.c
+++ b/cmd/efi.c
@@ -13,6 +13,8 @@
 #include <sort.h>
 #include <asm/global_data.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 static const char *const type_name[] = {
 	"reserved",
 	"loader_code",
@@ -75,16 +77,17 @@
 /**
  * efi_build_mem_table() - make a sorted copy of the memory table
  *
- * @map:	Pointer to EFI memory map table
+ * @desc_base:	Pointer to EFI memory map table
  * @size:	Size of table in bytes
+ * @desc_size:	Size of each @desc_base record
  * @skip_bs:	True to skip boot-time memory and merge it with conventional
  *		memory. This will significantly reduce the number of table
  *		entries.
  * Return:	pointer to the new table. It should be freed with free() by the
  *		caller.
  */
-static void *efi_build_mem_table(struct efi_entry_memmap *map, int size,
-				 bool skip_bs)
+static void *efi_build_mem_table(struct efi_mem_desc *desc_base, int size,
+				 int desc_size, bool skip_bs)
 {
 	struct efi_mem_desc *desc, *end, *base, *dest, *prev;
 	int count;
@@ -95,15 +98,16 @@
 		debug("%s: Cannot allocate %#x bytes\n", __func__, size);
 		return NULL;
 	}
-	end = (struct efi_mem_desc *)((ulong)map + size);
-	count = ((ulong)end - (ulong)map->desc) / map->desc_size;
-	memcpy(base, map->desc, (ulong)end - (ulong)map->desc);
-	qsort(base, count, map->desc_size, h_cmp_entry);
+	end = (void *)desc_base + size;
+	count = ((ulong)end - (ulong)desc_base) / desc_size;
+	memcpy(base, desc_base, (ulong)end - (ulong)desc_base);
+	qsort(base, count, desc_size, h_cmp_entry);
 	prev = NULL;
 	addr = 0;
 	dest = base;
-	end = (struct efi_mem_desc *)((ulong)base + count * map->desc_size);
-	for (desc = base; desc < end; desc = efi_get_next_mem_desc(map, desc)) {
+	end = (struct efi_mem_desc *)((ulong)base + count * desc_size);
+	for (desc = base; desc < end;
+	     desc = efi_get_next_mem_desc(desc, desc_size)) {
 		bool merge = true;
 		u32 type = desc->type;
 
@@ -116,7 +120,7 @@
 		if (skip_bs && is_boot_services(desc->type))
 			type = EFI_CONVENTIONAL_MEMORY;
 
-		memcpy(dest, desc, map->desc_size);
+		memcpy(dest, desc, desc_size);
 		dest->type = type;
 		if (!skip_bs || !prev)
 			merge = false;
@@ -131,7 +135,7 @@
 			prev->num_pages += desc->num_pages;
 		} else {
 			prev = dest;
-			dest = efi_get_next_mem_desc(map, dest);
+			dest = efi_get_next_mem_desc(dest, desc_size);
 		}
 		addr = desc->physical_start + (desc->num_pages <<
 				EFI_PAGE_SHIFT);
@@ -143,8 +147,8 @@
 	return base;
 }
 
-static void efi_print_mem_table(struct efi_entry_memmap *map,
-				struct efi_mem_desc *desc, bool skip_bs)
+static void efi_print_mem_table(struct efi_mem_desc *desc, int desc_size,
+				bool skip_bs)
 {
 	u64 attr_seen[ATTR_SEEN_MAX];
 	int attr_seen_count;
@@ -158,7 +162,7 @@
 	attr_seen_count = 0;
 	addr = 0;
 	for (upto = 0; desc->type != EFI_MAX_MEMORY_TYPE;
-	     upto++, desc = efi_get_next_mem_desc(map, desc)) {
+	     upto++, desc = efi_get_next_mem_desc(desc, desc_size)) {
 		const char *name;
 		u64 size;
 
@@ -215,37 +219,53 @@
 static int do_efi_mem(struct cmd_tbl *cmdtp, int flag, int argc,
 		      char *const argv[])
 {
-	struct efi_mem_desc *desc;
-	struct efi_entry_memmap *map;
+	struct efi_mem_desc *orig, *desc;
+	uint version, key;
+	int desc_size;
 	int size, ret;
 	bool skip_bs;
 
 	skip_bs = !argc || *argv[0] != 'a';
-	ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
-	switch (ret) {
-	case -ENOENT:
-		printf("No EFI table available\n");
-		goto done;
-	case -EPROTONOSUPPORT:
-		printf("Incorrect EFI table version\n");
-		goto done;
+	if (IS_ENABLED(CONFIG_EFI_APP)) {
+		ret = efi_get_mmap(&orig, &size, &key, &desc_size, &version);
+		if (ret) {
+			printf("Cannot read memory map (err=%d)\n", ret);
+			return CMD_RET_FAILURE;
+		}
+	} else {
+		struct efi_entry_memmap *map;
+
+		ret = efi_info_get(EFIET_MEMORY_MAP, (void **)&map, &size);
+		switch (ret) {
+		case -ENOENT:
+			printf("No EFI table available\n");
+			goto done;
+		case -EPROTONOSUPPORT:
+			printf("Incorrect EFI table version\n");
+			goto done;
+		}
+		orig = map->desc;
+		desc_size = map->desc_size;
+		version = map->version;
 	}
-	printf("EFI table at %lx, memory map %p, size %x, version %x, descr. size %#x\n",
-	       gd->arch.table, map, size, map->version, map->desc_size);
-	if (map->version != EFI_MEM_DESC_VERSION) {
+	printf("EFI table at %lx, memory map %p, size %x, key %x, version %x, descr. size %#x\n",
+	       gd->arch.table, orig, size, key, version, desc_size);
+	if (version != EFI_MEM_DESC_VERSION) {
 		printf("Incorrect memory map version\n");
 		ret = -EPROTONOSUPPORT;
 		goto done;
 	}
 
-	desc = efi_build_mem_table(map, size, skip_bs);
+	desc = efi_build_mem_table(orig, size, desc_size, skip_bs);
 	if (!desc) {
 		ret = -ENOMEM;
 		goto done;
 	}
 
-	efi_print_mem_table(map, desc, skip_bs);
+	efi_print_mem_table(desc, desc_size, skip_bs);
 	free(desc);
+	if (IS_ENABLED(CONFIG_EFI_APP))
+		free(orig);
 done:
 	if (ret)
 		printf("Error: %d\n", ret);
diff --git a/cmd/part.c b/cmd/part.c
index e0463b5..9d419c9 100644
--- a/cmd/part.c
+++ b/cmd/part.c
@@ -89,10 +89,10 @@
 
 	if (var != NULL) {
 		int p;
-		char str[512] = { '\0', };
+		char str[3 * MAX_SEARCH_PARTITIONS] = { '\0', };
 		struct disk_partition info;
 
-		for (p = 1; p < MAX_SEARCH_PARTITIONS; p++) {
+		for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 			char t[5];
 			int r = part_get_info(desc, p, &info);
 
diff --git a/common/Kconfig b/common/Kconfig
index 0892d9b..82cd864 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -717,7 +717,7 @@
 	  from TPL to SPL to U-Boot proper (and potentially to Linux). The
 	  blob list supports multiple binary blobs of data, each with a tag,
 	  so that different U-Boot components can store data which can survive
-	  through to the next stage of the boot.
+	  through to the next phase of the boot.
 
 config SPL_BLOBLIST
 	bool "Support for a bloblist in SPL"
@@ -738,15 +738,17 @@
 
 if BLOBLIST
 
-config BLOBLIST_SIZE
-	hex "Size of bloblist"
-	depends on BLOBLIST
-	default 0x400
+choice
+	prompt "Bloblist location"
 	help
-	  Sets the size of the bloblist in bytes. This must include all
-	  overhead (alignment, bloblist header, record header). The bloblist
-	  is set up in the first part of U-Boot to run (TPL, SPL or U-Boot
-	  proper), and this sane bloblist is used for subsequent stages.
+	  Select the location of the bloblist, via various means.
+
+config BLOBLIST_FIXED
+	bool "Place bloblist at a fixed address in memory"
+	help
+	  Select this to used a fixed memory address for the bloblist. If the
+	  bloblist exists at this address from a previous phase, it used as is.
+	  If not it is created at this address in U-Boot.
 
 config BLOBLIST_ALLOC
 	bool "Allocate bloblist"
@@ -755,18 +757,31 @@
 	  specify a fixed address on systems where this is unknown or can
 	  change at runtime.
 
+endchoice
+
 config BLOBLIST_ADDR
 	hex "Address of bloblist"
 	default 0xc000 if SANDBOX
+	depends on BLOBLIST_FIXED
 	help
 	  Sets the address of the bloblist, set up by the first part of U-Boot
-	  which runs. Subsequent U-Boot stages typically use the same address.
+	  which runs. Subsequent U-Boot phases typically use the same address.
 
 	  This is not used if BLOBLIST_ALLOC is selected.
 
+config BLOBLIST_SIZE
+	hex "Size of bloblist"
+	default 0x400
+	help
+	  Sets the size of the bloblist in bytes. This must include all
+	  overhead (alignment, bloblist header, record header). The bloblist
+	  is set up in the first part of U-Boot to run (TPL, SPL or U-Boot
+	  proper), and this sane bloblist is used for subsequent phases.
+
 config BLOBLIST_SIZE_RELOC
 	hex "Size of bloblist after relocation"
-	default BLOBLIST_SIZE
+	default BLOBLIST_SIZE if BLOBLIST_FIXED || BLOBLIST_ALLOC
+	default 0 if BLOBLIST_PASSAGE
 	help
 	  Sets the size of the bloblist in bytes after relocation. Since U-Boot
 	  has a lot more memory available then, it is possible to use a larger
@@ -775,6 +790,64 @@
 
 endif # BLOBLIST
 
+if SPL_BLOBLIST
+
+choice
+	prompt "Bloblist location in SPL"
+	help
+	  Select the location of the bloblist, via various means. Typically
+	  you should use the same value for SPL as for U-Boot, since they need
+	  to look in the same place. But if BLOBLIST_ALLOC is used, then a
+	  fresh bloblist will be created each time, since there is no shared
+	  address (between phases) for the bloblist.
+
+config SPL_BLOBLIST_FIXED
+	bool "Place bloblist at a fixed address in memory"
+	help
+	  Select this to used a fixed memory address for the bloblist. If the
+	  bloblist exists at this address from a previous phase, it used as is.
+	  If not it is created at this address in SPL.
+
+config SPL_BLOBLIST_ALLOC
+	bool "Allocate bloblist"
+	help
+	  Allocate the bloblist using malloc(). This avoids the need to
+	  specify a fixed address on systems where this is unknown or can
+	  change at runtime.
+
+endchoice
+
+endif # SPL_BLOBLIST
+
+if TPL_BLOBLIST
+
+choice
+	prompt "Bloblist location in TPL"
+	help
+	  Select the location of the bloblist, via various means. Typically
+	  you should use the same value for SPL as for U-Boot, since they need
+	  to look in the same place. But if BLOBLIST_ALLOC is used, then a
+	  fresh bloblist will be created each time, since there is no shared
+	  address (between phases) for the bloblist.
+
+config TPL_BLOBLIST_FIXED
+	bool "Place bloblist at a fixed address in memory"
+	help
+	  Select this to used a fixed memory address for the bloblist. If the
+	  bloblist exists at this address from a previous phase, it used as is.
+	  If not it is created at this address in TPL.
+
+config TPL_BLOBLIST_ALLOC
+	bool "Allocate bloblist"
+	help
+	  Allocate the bloblist using malloc(). This avoids the need to
+	  specify a fixed address on systems where this is unknown or can
+	  change at runtime.
+
+endchoice
+
+endif # TPL_BLOBLIST
+
 endmenu
 
 source "common/spl/Kconfig"
diff --git a/common/bloblist.c b/common/bloblist.c
index 01b0410..056b50c 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -1,9 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
 /*
  * Copyright 2018 Google, Inc
  * Written by Simon Glass <sjg@chromium.org>
  */
 
+#define LOG_DEBUG
+#define LOG_CATEGORY	LOGC_BLOBLIST
+
 #include <common.h>
 #include <bloblist.h>
 #include <log.h>
@@ -29,26 +32,39 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static const char *const tag_name[] = {
-	[BLOBLISTT_NONE]		= "(none)",
-	[BLOBLISTT_EC_HOSTEVENT]	= "EC host event",
-	[BLOBLISTT_SPL_HANDOFF]		= "SPL hand-off",
-	[BLOBLISTT_VBOOT_CTX]		= "Chrome OS vboot context",
-	[BLOBLISTT_VBOOT_HANDOFF]	= "Chrome OS vboot hand-off",
-	[BLOBLISTT_ACPI_GNVS]		= "ACPI GNVS",
-	[BLOBLISTT_INTEL_VBT]		= "Intel Video-BIOS table",
-	[BLOBLISTT_TPM2_TCG_LOG]	= "TPM v2 log space",
-	[BLOBLISTT_TCPA_LOG]		= "TPM log space",
-	[BLOBLISTT_ACPI_TABLES]		= "ACPI tables for x86",
-	[BLOBLISTT_SMBIOS_TABLES]	= "SMBIOS tables for x86",
+static struct tag_name {
+	enum bloblist_tag_t tag;
+	const char *name;
+} tag_name[] = {
+	{ BLOBLISTT_NONE, "(none)" },
+
+	/* BLOBLISTT_AREA_FIRMWARE_TOP */
+
+	/* BLOBLISTT_AREA_FIRMWARE */
+	{ BLOBLISTT_ACPI_GNVS, "ACPI GNVS" },
+	{ BLOBLISTT_INTEL_VBT, "Intel Video-BIOS table" },
+	{ BLOBLISTT_TPM2_TCG_LOG, "TPM v2 log space" },
+	{ BLOBLISTT_TCPA_LOG, "TPM log space" },
+	{ BLOBLISTT_ACPI_TABLES, "ACPI tables for x86" },
+	{ BLOBLISTT_SMBIOS_TABLES, "SMBIOS tables for x86" },
+	{ BLOBLISTT_VBOOT_CTX, "Chrome OS vboot context" },
+
+	/* BLOBLISTT_PROJECT_AREA */
+	{ BLOBLISTT_U_BOOT_SPL_HANDOFF, "SPL hand-off" },
+
+	/* BLOBLISTT_VENDOR_AREA */
 };
 
 const char *bloblist_tag_name(enum bloblist_tag_t tag)
 {
-	if (tag < 0 || tag >= BLOBLISTT_COUNT)
-		return "invalid";
+	int i;
 
-	return tag_name[tag];
+	for (i = 0; i < ARRAY_SIZE(tag_name); i++) {
+		if (tag_name[i].tag == tag)
+			return tag_name[i].name;
+	}
+
+	return "invalid";
 }
 
 static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
@@ -120,9 +136,8 @@
 	new_alloced = data_start + ALIGN(size, align);
 
 	if (new_alloced > hdr->size) {
-		log(LOGC_BLOBLIST, LOGL_ERR,
-		    "Failed to allocate %x bytes size=%x, need size=%x\n",
-		    size, hdr->size, new_alloced);
+		log_err("Failed to allocate %x bytes size=%x, need size=%x\n",
+			size, hdr->size, new_alloced);
 		return log_msg_ret("bloblist add", -ENOSPC);
 	}
 	rec = (void *)hdr + hdr->alloced;
@@ -236,14 +251,13 @@
 	expand_by = ALIGN(new_size - rec->size, BLOBLIST_ALIGN);
 	new_alloced = ALIGN(hdr->alloced + expand_by, BLOBLIST_ALIGN);
 	if (new_size < 0) {
-		log(LOGC_BLOBLIST, LOGL_DEBUG,
-		    "Attempt to shrink blob size below 0 (%x)\n", new_size);
+		log_debug("Attempt to shrink blob size below 0 (%x)\n",
+			  new_size);
 		return log_msg_ret("size", -EINVAL);
 	}
 	if (new_alloced > hdr->size) {
-		log(LOGC_BLOBLIST, LOGL_ERR,
-		    "Failed to allocate %x bytes size=%x, need size=%x\n",
-		    new_size, hdr->size, new_alloced);
+		log_err("Failed to allocate %x bytes size=%x, need size=%x\n",
+			new_size, hdr->size, new_alloced);
 		return log_msg_ret("alloc", -ENOSPC);
 	}
 
@@ -334,8 +348,7 @@
 		return log_msg_ret("Bad size", -EFBIG);
 	chksum = bloblist_calc_chksum(hdr);
 	if (hdr->chksum != chksum) {
-		log(LOGC_BLOBLIST, LOGL_ERR, "Checksum %x != %x\n", hdr->chksum,
-		    chksum);
+		log_err("Checksum %x != %x\n", hdr->chksum, chksum);
 		return log_msg_ret("Bad checksum", -EIO);
 	}
 	gd->bloblist = hdr;
@@ -348,10 +361,24 @@
 	struct bloblist_hdr *hdr = gd->bloblist;
 
 	hdr->chksum = bloblist_calc_chksum(hdr);
+	log_debug("Finished bloblist size %lx at %lx\n", (ulong)hdr->size,
+		  (ulong)map_to_sysmem(hdr));
 
 	return 0;
 }
 
+ulong bloblist_get_base(void)
+{
+	return map_to_sysmem(gd->bloblist);
+}
+
+ulong bloblist_get_size(void)
+{
+	struct bloblist_hdr *hdr = gd->bloblist;
+
+	return hdr->size;
+}
+
 void bloblist_get_stats(ulong *basep, ulong *sizep, ulong *allocedp)
 {
 	struct bloblist_hdr *hdr = gd->bloblist;
@@ -383,10 +410,10 @@
 	struct bloblist_hdr *hdr = gd->bloblist;
 	struct bloblist_rec *rec;
 
-	printf("%-8s  %8s  Tag Name\n", "Address", "Size");
+	printf("%-8s  %8s   Tag Name\n", "Address", "Size");
 	for (rec = bloblist_first_blob(hdr); rec;
 	     rec = bloblist_next_blob(hdr, rec)) {
-		printf("%08lx  %8x  %3d %s\n",
+		printf("%08lx  %8x  %4x %s\n",
 		       (ulong)map_to_sysmem((void *)rec + rec->hdr_size),
 		       rec->size, rec->tag, bloblist_tag_name(rec->tag));
 	}
@@ -403,8 +430,9 @@
 
 int bloblist_init(void)
 {
-	bool expected;
 	int ret = -ENOENT;
+	ulong addr, size;
+	bool expected;
 
 	/**
 	 * Wed expect to find an existing bloblist in the first phase of U-Boot
@@ -413,27 +441,32 @@
 	expected = !u_boot_first_phase();
 	if (spl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST))
 		expected = false;
-	if (expected)
-		ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
-				     CONFIG_BLOBLIST_SIZE);
+	addr = bloblist_addr();
+	size = CONFIG_BLOBLIST_SIZE;
+	if (expected) {
+		ret = bloblist_check(addr, size);
+		if (ret) {
+			log_warning("Expected bloblist at %lx not found (err=%d)\n",
+				    addr, ret);
+		} else {
+			/* Get the real size, if it is not what we expected */
+			size = gd->bloblist->size;
+		}
+	}
 	if (ret) {
-		ulong addr;
-
-		log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG,
-		    "Existing bloblist not found: creating new bloblist\n");
-		if (IS_ENABLED(CONFIG_BLOBLIST_ALLOC)) {
-			void *ptr = memalign(BLOBLIST_ALIGN,
-					     CONFIG_BLOBLIST_SIZE);
+		if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) {
+			void *ptr = memalign(BLOBLIST_ALIGN, size);
 
 			if (!ptr)
 				return log_msg_ret("alloc", -ENOMEM);
 			addr = map_to_sysmem(ptr);
-		} else {
-			addr = CONFIG_BLOBLIST_ADDR;
 		}
-		ret = bloblist_new(addr, CONFIG_BLOBLIST_SIZE, 0);
+		log_debug("Creating new bloblist size %lx at %lx\n", size,
+			  addr);
+		ret = bloblist_new(addr, size, 0);
 	} else {
-		log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n");
+		log_debug("Found existing bloblist size %lx at %lx\n", size,
+			  addr);
 	}
 
 	return ret;
diff --git a/common/board_f.c b/common/board_f.c
index dd69c3b..a687600 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -283,7 +283,7 @@
 static int setup_spl_handoff(void)
 {
 #if CONFIG_IS_ENABLED(HANDOFF)
-	gd->spl_handoff = bloblist_find(BLOBLISTT_SPL_HANDOFF,
+	gd->spl_handoff = bloblist_find(BLOBLISTT_U_BOOT_SPL_HANDOFF,
 					sizeof(struct spl_handoff));
 	debug("Found SPL hand-off info %p\n", gd->spl_handoff);
 #endif
diff --git a/common/fdt_support.c b/common/fdt_support.c
index b2ba082..c6b93e7 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -1430,7 +1430,7 @@
 	node = parent;
 	parent = fdt_parent_offset(blob, node);
 	if (parent < 0) {
-		printf("Found dma-ranges in root node, shoudln't happen\n");
+		printf("Found dma-ranges in root node, shouldn't happen\n");
 		ret = -EINVAL;
 		goto out;
 	}
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 4c101ec..f51d1f3 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -408,7 +408,7 @@
 {
 	struct spl_handoff *ho;
 
-	ho = bloblist_ensure(BLOBLISTT_SPL_HANDOFF, sizeof(struct spl_handoff));
+	ho = bloblist_ensure(BLOBLISTT_U_BOOT_SPL_HANDOFF, sizeof(struct spl_handoff));
 	if (!ho)
 		return -ENOENT;
 
@@ -425,7 +425,7 @@
 	struct spl_handoff *ho;
 	int ret;
 
-	ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(struct spl_handoff));
+	ho = bloblist_find(BLOBLISTT_U_BOOT_SPL_HANDOFF, sizeof(struct spl_handoff));
 	if (!ho)
 		return -ENOENT;
 	handoff_save_dram(ho);
diff --git a/configs/controlcenterdc_defconfig b/configs/controlcenterdc_defconfig
index d6844a4..b6eb955 100644
--- a/configs/controlcenterdc_defconfig
+++ b/configs/controlcenterdc_defconfig
@@ -33,6 +33,7 @@
 CONFIG_DISPLAY_BOARDINFO_LATE=y
 CONFIG_BOARD_LATE_INIT=y
 CONFIG_LAST_STAGE_INIT=y
+CONFIG_SPL_BOARD_INIT=y
 CONFIG_SPL_SYS_MALLOC_SIMPLE=y
 CONFIG_SPL_I2C=y
 CONFIG_HUSH_PARSER=y
diff --git a/configs/db-88f6720_defconfig b/configs/db-88f6720_defconfig
index 32a7349..2e8f4c0 100644
--- a/configs/db-88f6720_defconfig
+++ b/configs/db-88f6720_defconfig
@@ -11,7 +11,7 @@
 CONFIG_ENV_OFFSET=0x100000
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_DEFAULT_DEVICE_TREE="armada-375-db"
-CONFIG_SPL_TEXT_BASE=0x40004030
+CONFIG_SPL_TEXT_BASE=0x40000030
 CONFIG_SPL_SERIAL=y
 CONFIG_SPL=y
 CONFIG_DEBUG_UART_BASE=0xf1012000
diff --git a/configs/iconnect_defconfig b/configs/iconnect_defconfig
index 605b98b..1c9c77a 100644
--- a/configs/iconnect_defconfig
+++ b/configs/iconnect_defconfig
@@ -2,6 +2,7 @@
 CONFIG_SKIP_LOWLEVEL_INIT=y
 CONFIG_SYS_DCACHE_OFF=y
 CONFIG_ARCH_CPU_INIT=y
+CONFIG_SYS_THUMB_BUILD=y
 CONFIG_ARCH_KIRKWOOD=y
 CONFIG_SYS_KWD_CONFIG="board/iomega/iconnect/kwbimage.cfg"
 CONFIG_SYS_TEXT_BASE=0x600000
@@ -18,9 +19,11 @@
 CONFIG_BOOTCOMMAND="setenv bootargs ${console} ${mtdparts} ${bootargs_root}; ubi part rootfs; ubifsmount ubi:rootfs; ubifsload 0x800000 ${kernel}; bootm 0x800000"
 CONFIG_USE_PREBOOT=y
 # CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_BOARD_LATE_INIT=y
 CONFIG_SYS_PROMPT="iconnect => "
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_NAND=y
+CONFIG_CMD_PCI=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_MII=y
@@ -43,6 +46,8 @@
 CONFIG_MTD_RAW_NAND=y
 CONFIG_MVGBE=y
 CONFIG_MII=y
+CONFIG_PCI=y
+CONFIG_PCI_MVEBU=y
 CONFIG_SYS_NS16550=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 0ca7eff..3809333 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -236,9 +236,9 @@
 	printf("\tPartition GUID\n");
 
 	for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) {
-		/* Stop at the first non valid PTE */
+		/* Skip invalid PTE */
 		if (!is_pte_valid(&gpt_pte[i]))
-			break;
+			continue;
 
 		printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1),
 			le64_to_cpu(gpt_pte[i].starting_lba),
diff --git a/doc/README.pxe b/doc/README.pxe
index b67151c..a1f0423 100644
--- a/doc/README.pxe
+++ b/doc/README.pxe
@@ -92,6 +92,12 @@
      fdtoverlay_addr_r - location in RAM at which 'pxe boot' will temporarily store
      fdt overlay(s) before applying them to the fdt blob stored at 'fdt_addr_r'.
 
+     pxe_label_override - override label to be used, if exists, instead of the
+     default label. This will allow consumers to choose a pxe label at
+     runtime instead of having to prompt the user. If "pxe_label_override" is set
+     but does not exist in the pxe menu, pxe would fallback to the default label if
+     given, and no failure is returned but rather a warning message.
+
 pxe file format
 ===============
 The pxe file format is nearly a subset of the PXELINUX file format; see
diff --git a/doc/api/dm.rst b/doc/api/dm.rst
new file mode 100644
index 0000000..df605da
--- /dev/null
+++ b/doc/api/dm.rst
@@ -0,0 +1,29 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Driver Model
+============
+
+Uclass and Driver
+-----------------
+
+.. kernel-doc:: include/dm/uclass.h
+.. kernel-doc:: include/dm/root.h
+.. kernel-doc:: include/dm/lists.h
+.. kernel-doc:: include/dm/platdata.h
+
+Device
+------
+
+.. kernel-doc:: include/dm/device.h
+.. kernel-doc:: include/dm/devres.h
+.. kernel-doc:: include/dm/read.h
+
+Device tree
+-----------
+
+.. kernel-doc:: include/dm/of.h
+.. kernel-doc:: include/dm/ofnode.h
+.. kernel-doc:: include/dm/of_extra.h
+.. kernel-doc:: include/dm/of_access.h
+.. kernel-doc:: include/dm/of_addr.h
+.. kernel-doc:: include/dm/fdtaddr.h
diff --git a/doc/api/index.rst b/doc/api/index.rst
index 806c738..3f36174 100644
--- a/doc/api/index.rst
+++ b/doc/api/index.rst
@@ -7,6 +7,7 @@
    :maxdepth: 2
 
    dfu
+   dm
    efi
    getopt
    linker_lists
diff --git a/doc/board/armltd/index.rst b/doc/board/armltd/index.rst
index c20d8a0..fc1d75a 100644
--- a/doc/board/armltd/index.rst
+++ b/doc/board/armltd/index.rst
@@ -6,4 +6,5 @@
 .. toctree::
    :maxdepth: 2
 
+   juno
    vexpress64.rst
diff --git a/doc/board/armltd/juno.rst b/doc/board/armltd/juno.rst
new file mode 100644
index 0000000..761c037
--- /dev/null
+++ b/doc/board/armltd/juno.rst
@@ -0,0 +1,114 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. Copyright (C) 2021 Arm Ltd.
+
+Arm Juno development platform
+=============================
+
+The `Juno development board`_ is an open, vendor-neutral, Armv8-A development
+platform, made by Arm Ltd. It is part of the Versatile Express family.
+There are three revisions of the board:
+
+* Juno r0, with two Cortex-A57 and four Cortex-A53 cores, without PCIe.
+* Juno r1, with two Cortex-A57 and four Cortex-A53 cores, in later silicon
+  revisions, and with PCIe slots, Gigabit Ethernet and two SATA ports.
+* Juno r2, with two Cortex-A72 and four Cortex-A53 cores, otherwise the
+  same as r1.
+
+Among other things, the motherboard contains a management controller (MCC),
+an FPGA providing I/O interfaces (IOFPGA) and 64MB of NOR flash. The provided
+platform devices resemble the VExpress peripherals.
+The actual SoC also contains a Cortex-M3 based System Control Processor (SCP).
+The `V2M-Juno TRM`_ contains more technical details.
+
+U-Boot build
+------------
+There is only one defconfig and one binary build that covers all three board
+revisions, so to generate the needed ``u-boot.bin``:
+
+.. code-block:: bash
+
+    $ make vexpress_aemv8a_juno_defconfig
+    $ make
+
+The automatic distro boot sequence looks for UEFI boot applications and
+``boot.scr`` scripts on various boot media, starting with USB, then on disks
+connected to the two SATA ports, PXE, DHCP and eventually on the NOR flash.
+
+U-Boot installation
+-------------------
+This assumes there is some firmware on the SD card or NOR flash (see below
+for more details). The U-Boot binary is included in the Trusted Firmware
+FIP image, so after building U-Boot, this needs to be repackaged or recompiled.
+
+The NOR flash will be updated by the MCC, based on the content of a micro-SD
+card, which is exported as a USB mass storage device via the rear USB-B
+socket. So to access that SD card, connect a cable to some host computer, and
+mount the FAT16 partition of the UMS device.
+If there is no device, check the upper serial port for a prompt, and
+explicitly enable the USB interface::
+
+    Cmd> usb_on
+    Enabling debug USB...
+
+Repackaging an existing FIP image
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+To prevent problems, it is probably a good idea to backup the existing firmware,
+for instance by just copying the entire ``SOFTWARE/`` directory, or at least
+the current ``fip.bin``, beforehand.
+
+To just replace the BL33 image in the exising FIP image, you can use
+`fiptool`_ from the Trusted Firmware repository, on the image file:
+
+.. code-block:: bash
+
+    git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+    cd trusted-firmware-a
+    make fiptool
+    tools/fiptool/fiptool update --nt-fw=/path/to/your/u-boot.bin /mnt/juno/SOFTWARE/fip.bin
+
+Unmount the USB mass storage device and reboot the board, the new ``fip.bin``
+will be automatically written to the NOR flash and then used.
+
+Rebuilding Trusted Firmware
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+You can also generate a new FIP image by compiling Arm Trusted Firmware,
+and providing ``u-boot.bin`` as the BL33 file. For that you can either build
+the required `SCP firmware`_ yourself, or just extract the existing
+version from your ``fip.bin``, using `fiptool`_ (see above):
+
+.. code-block:: bash
+
+    mkdir /tmp/juno; cd /tmp/juno
+    fiptool unpack /mnt/juno/SOFTWARE/fip.bin
+
+Then build TF-A:
+
+.. code-block:: bash
+
+    git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+    cd trusted-firmware-a
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=juno DEBUG=1 \
+    SCP_BL2=/tmp/juno/scp-fw.bin BL33=/path/to/your/u-boot.bin fiptool all fip
+    cp build/juno/debug/bl1.bin build/juno/debug/fip.bin /mnt/juno/SOFTWARE
+
+Then umount the USB device, and reboot, as above.
+
+Device trees
+------------
+The device tree files for the boards are maintained in the Linux kernel
+repository. They end up in the ``SOFTWARE/`` directory of the SD card, as
+``juno.dtb``, ``juno-r1.dtb``, and ``juno-r2.dtb``, respectively. The MCC
+firmware will look into the images.txt file matching the board revision, from
+the ``SITE1/`` directory. Each version there will reference its respective DTB
+file in ``SOFTWARE/``, and so the correct version will end in the NOR flash, in
+the ``board.dtb`` partition. U-Boot picks its control DTB from there, you can
+pass this on to a kernel using ``$fdtcontroladdr``.
+
+You can update the DTBs anytime, by building them using the ``dtbs`` make
+target from a Linux kernel tree, then just copying the generated binaries
+to the ``SOFTWARE/`` directory of the SD card.
+
+.. _`Juno development board`: https://developer.arm.com/tools-and-software/development-boards/juno-development-board
+.. _`V2M-Juno TRM`: https://developer.arm.com/documentation/100113/latest
+.. _`fiptool`: https://github.com/ARM-software/arm-trusted-firmware/tree/master/tools/fiptool
+.. _`SCP firmware`: https://github.com/ARM-software/SCP-firmware.git
diff --git a/doc/build/gcc.rst b/doc/build/gcc.rst
index cdd7970..0e0d87a 100644
--- a/doc/build/gcc.rst
+++ b/doc/build/gcc.rst
@@ -51,6 +51,16 @@
     zypper install bc bison flex gcc libopenssl-devel libSDL2-devel make \
       ncurses-devel python3-devel python3-pytest swig
 
+Alpine Linux
+~~~~~~~~~~~~
+
+For building U-Boot on Alpine Linux at least the following packages are needed:
+
+.. code-block:: bash
+
+    apk add alpine-sdk bc bison dtc flex linux-headers ncurses-dev \
+      openssl-dev python3 py3-setuptools python3-dev sdl2
+
 Prerequisites
 -------------
 
diff --git a/doc/develop/bloblist.rst b/doc/develop/bloblist.rst
index 47274cf..572aa65 100644
--- a/doc/develop/bloblist.rst
+++ b/doc/develop/bloblist.rst
@@ -31,7 +31,7 @@
 While each blob in the bloblist can be of any length, bloblists are designed to
 hold small amounts of data, typically a few KB at most. It is not possible to
 change the length of a blob once it has been written. Each blob is normally
-created from a C structure which can beused to access its fields.
+created from a C structure which can be used to access its fields.
 
 
 Blob tags
@@ -93,6 +93,12 @@
 passing information between U-Boot parts.
 
 
+API documentation
+-----------------
+
+.. kernel-doc:: include/bloblist.h
+
+
 Simon Glass
 sjg@chromium.org
 12-Aug-2018
diff --git a/doc/develop/driver-model/migration.rst b/doc/develop/driver-model/migration.rst
index 3dbeea6..10f474e 100644
--- a/doc/develop/driver-model/migration.rst
+++ b/doc/develop/driver-model/migration.rst
@@ -106,3 +106,15 @@
 This is a legacy option which has been replaced by driver model.
 Maintainers should submit patches switching over to using CONFIG_DM_KEYBOARD and
 other base driver model options in time for inclusion in the 2022.10 release.
+
+CONFIG_SYS_TIMER_RATE and CONFIG_SYS_TIMER_COUNTER
+--------------------------------------------------
+Deadline: 2023.01
+
+These are legacy options which have been replaced by driver model.
+Maintainers should submit patches switching over to using CONFIG_TIMER and
+other base driver model options in time for inclusion in the 2022.10 release.
+
+There is only one method to implement, unless you want to support bootstage,
+in which case you need an early timer also. For example drivers, see
+sandbox_timer.c and rockchip_timer.c
diff --git a/doc/sphinx/requirements.txt b/doc/sphinx/requirements.txt
index 4555a94..44c1878 100644
--- a/doc/sphinx/requirements.txt
+++ b/doc/sphinx/requirements.txt
@@ -1,4 +1,4 @@
 docutils==0.16
-Sphinx==3.4.3
-sphinx_rtd_theme
-six
+sphinx==3.4.3
+sphinx_rtd_theme==1.0.0
+six==1.16.0
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 094b1ab..d245b67 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -57,7 +57,7 @@
 	debug("%s(clk=%p)\n", __func__, clk);
 
 	if (args->args_count > 1) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/clk/clk_stm32f.c b/drivers/clk/clk_stm32f.c
index e7c26db..ed76601 100644
--- a/drivers/clk/clk_stm32f.c
+++ b/drivers/clk/clk_stm32f.c
@@ -703,7 +703,7 @@
 	dev_dbg(clk->dev, "clk=%p\n", clk);
 
 	if (args->args_count != 2) {
-		dev_dbg(clk->dev, "Invaild args_count: %d\n", args->args_count);
+		dev_dbg(clk->dev, "Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/clk/clk_stm32h7.c b/drivers/clk/clk_stm32h7.c
index 20b3647..d440c28 100644
--- a/drivers/clk/clk_stm32h7.c
+++ b/drivers/clk/clk_stm32h7.c
@@ -835,7 +835,7 @@
 			struct ofnode_phandle_args *args)
 {
 	if (args->args_count != 1) {
-		dev_dbg(clk->dev, "Invaild args_count: %d\n", args->args_count);
+		dev_dbg(clk->dev, "Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/clk/clk_versaclock.c b/drivers/clk/clk_versaclock.c
index 578668b..89c8d02 100644
--- a/drivers/clk/clk_versaclock.c
+++ b/drivers/clk/clk_versaclock.c
@@ -627,7 +627,7 @@
 	unsigned int idx = args->args[0];
 
 	if (args->args_count != 1) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c
index d2d0169..3a68c5a 100644
--- a/drivers/clk/renesas/clk-rcar-gen2.c
+++ b/drivers/clk/renesas/clk-rcar-gen2.c
@@ -256,7 +256,7 @@
 static int gen2_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
 {
 	if (args->args_count != 2) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c
index 6cf07fb..bcf5865 100644
--- a/drivers/clk/renesas/clk-rcar-gen3.c
+++ b/drivers/clk/renesas/clk-rcar-gen3.c
@@ -365,7 +365,7 @@
 static int gen3_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
 {
 	if (args->args_count != 2) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/clk/ti/clk-ctrl.c b/drivers/clk/ti/clk-ctrl.c
index 8ac085e..6cc02d2 100644
--- a/drivers/clk/ti/clk-ctrl.c
+++ b/drivers/clk/ti/clk-ctrl.c
@@ -83,7 +83,7 @@
 				struct ofnode_phandle_args *args)
 {
 	if (args->args_count != 2) {
-		dev_err(clk->dev, "invaild args_count: %d\n", args->args_count);
+		dev_err(clk->dev, "invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 4873c47..d917d4e 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -518,6 +518,14 @@
 
 	dev_or_flags(dev, DM_FLAG_ACTIVATED);
 
+	if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent &&
+	    (device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) &&
+	    !(drv->flags & DM_FLAG_DEFAULT_PD_CTRL_OFF)) {
+		ret = dev_power_domain_on(dev);
+		if (ret)
+			goto fail;
+	}
+
 	/*
 	 * Process pinctrl for everything except the root device, and
 	 * continue regardless of the result of pinctrl. Don't process pinctrl
@@ -540,14 +548,6 @@
 				  dev->name, ret, errno_str(ret));
 	}
 
-	if (CONFIG_IS_ENABLED(POWER_DOMAIN) && dev->parent &&
-	    (device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) &&
-	    !(drv->flags & DM_FLAG_DEFAULT_PD_CTRL_OFF)) {
-		ret = dev_power_domain_on(dev);
-		if (ret)
-			goto fail;
-	}
-
 	if (CONFIG_IS_ENABLED(IOMMU) && dev->parent &&
 	    (device_get_uclass_id(dev) != UCLASS_IOMMU)) {
 		ret = dev_iommu_enable(dev);
diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
index 3fbc0a7..431dd4e 100644
--- a/drivers/core/of_addr.c
+++ b/drivers/core/of_addr.c
@@ -367,7 +367,7 @@
 	/* switch to that node */
 	parent = of_get_parent(dev);
 	if (!parent) {
-		printf("Found dma-ranges in root node, shoudln't happen\n");
+		printf("Found dma-ranges in root node, shouldn't happen\n");
 		ret = -EINVAL;
 		goto out;
 	}
diff --git a/drivers/ddr/altera/sequencer.c b/drivers/ddr/altera/sequencer.c
index 8a016f0..e402f29 100644
--- a/drivers/ddr/altera/sequencer.c
+++ b/drivers/ddr/altera/sequencer.c
@@ -2770,7 +2770,7 @@
 	ret = rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(seq, rw_group);
 
 	debug_cond(DLEVEL >= 1,
-		   "%s:%d: g=%u found=%u; Reseting delay chain to zero\n",
+		   "%s:%d: g=%u found=%u; Resetting delay chain to zero\n",
 		   __func__, __LINE__, rw_group, !ret);
 
 	for (r = 0; r < seq->rwcfg->mem_number_of_ranks;
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
index 648b37e..42308b6 100644
--- a/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
+++ b/drivers/ddr/marvell/a38x/ddr3_training_centralization.c
@@ -55,6 +55,7 @@
 	enum hws_training_ip_stat training_result[MAX_INTERFACE_NUM];
 	u32 if_id, pattern_id, bit_id;
 	u8 bus_id;
+	u8 current_byte_status;
 	u8 cur_start_win[BUS_WIDTH_IN_BITS];
 	u8 centralization_result[MAX_INTERFACE_NUM][BUS_WIDTH_IN_BITS];
 	u8 cur_end_win[BUS_WIDTH_IN_BITS];
@@ -166,6 +167,10 @@
 						  result[search_dir_id][7]));
 				}
 
+				current_byte_status =
+					mv_ddr_tip_sub_phy_byte_status_get(if_id,
+									   bus_id);
+
 				for (bit_id = 0; bit_id < BUS_WIDTH_IN_BITS;
 				     bit_id++) {
 					/* check if this code is valid for 2 edge, probably not :( */
@@ -174,11 +179,32 @@
 							       [HWS_LOW2HIGH]
 							       [bit_id],
 							       EDGE_1);
+					if (current_byte_status &
+					    BYTE_SPLIT_OUT_MIX) {
+						if (cur_start_win[bit_id] >= 64)
+							cur_start_win[bit_id] -= 64;
+						else
+							cur_start_win[bit_id] = 0;
+						DEBUG_CENTRALIZATION_ENGINE
+							(DEBUG_LEVEL_INFO,
+							 ("pattern %d IF %d pup %d bit %d subtract 64 adll from start\n",
+							  pattern_id, if_id, bus_id, bit_id));
+					}
 					cur_end_win[bit_id] =
 						GET_TAP_RESULT(result
 							       [HWS_HIGH2LOW]
 							       [bit_id],
 							       EDGE_1);
+					if (cur_end_win[bit_id] >= 64 &&
+					    (current_byte_status &
+					     BYTE_SPLIT_OUT_MIX)) {
+						cur_end_win[bit_id] -= 64;
+						DEBUG_CENTRALIZATION_ENGINE
+							(DEBUG_LEVEL_INFO,
+							 ("pattern %d IF %d pup %d bit %d subtract 64 adll from end\n",
+							  pattern_id, if_id, bus_id, bit_id));
+					}
+
 					/* window length */
 					current_window[bit_id] =
 						cur_end_win[bit_id] -
diff --git a/drivers/ddr/marvell/a38x/mv_ddr_plat.c b/drivers/ddr/marvell/a38x/mv_ddr_plat.c
index faafc86..7c7bce7 100644
--- a/drivers/ddr/marvell/a38x/mv_ddr_plat.c
+++ b/drivers/ddr/marvell/a38x/mv_ddr_plat.c
@@ -167,8 +167,6 @@
 };
 
 
-static u32 async_mode_at_tf;
-
 static u32 dq_bit_map_2_phy_pin[] = {
 	1, 0, 2, 6, 9, 8, 3, 7,	/* 0 */
 	8, 9, 1, 7, 2, 6, 3, 0,	/* 1 */
@@ -734,7 +732,8 @@
 	u32 divider = 0;
 	u32 sar_val, ref_clk_satr;
 	u32 async_val;
-	u32 freq = mv_ddr_freq_get(frequency);
+	u32 cpu_freq;
+	u32 ddr_freq = mv_ddr_freq_get(frequency);
 
 	if (if_id != 0) {
 		DEBUG_TRAINING_ACCESS(DEBUG_LEVEL_ERROR,
@@ -751,11 +750,14 @@
 	ref_clk_satr = reg_read(DEVICE_SAMPLE_AT_RESET2_REG);
 	if (((ref_clk_satr >> DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_OFFSET) & 0x1) ==
 	    DEVICE_SAMPLE_AT_RESET2_REG_REFCLK_25MHZ)
-		divider = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val] / freq;
+		cpu_freq = a38x_vco_freq_per_sar_ref_clk_25_mhz[sar_val];
 	else
-		divider = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val] / freq;
+		cpu_freq = a38x_vco_freq_per_sar_ref_clk_40_mhz[sar_val];
 
-	if ((async_mode_at_tf == 1) && (freq > 400)) {
+	divider = cpu_freq / ddr_freq;
+
+	if (((cpu_freq % ddr_freq != 0) || (divider != 2 && divider != 3)) &&
+	    (ddr_freq > 400)) {
 		/* Set async mode */
 		dunit_write(0x20220, 0x1000, 0x1000);
 		dunit_write(0xe42f4, 0x200, 0x200);
@@ -869,8 +871,6 @@
 
 int mv_ddr_early_init(void)
 {
-	struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get();
-
 	/* FIXME: change this configuration per ddr type
 	 * configure a380 and a390 to work with receiver odt timing
 	 * the odt_config is defined:
@@ -882,9 +882,6 @@
 
 	mv_ddr_sw_db_init(0, 0);
 
-	if (tm->interface_params[0].memory_freq != MV_DDR_FREQ_SAR)
-		async_mode_at_tf = 1;
-
 	return MV_OK;
 }
 
diff --git a/drivers/dma/dma-uclass.c b/drivers/dma/dma-uclass.c
index 652ddbb..012609b 100644
--- a/drivers/dma/dma-uclass.c
+++ b/drivers/dma/dma-uclass.c
@@ -35,7 +35,7 @@
 	debug("%s(dma=%p)\n", __func__, dma);
 
 	if (args->args_count > 1) {
-		pr_err("Invaild args_count: %d\n", args->args_count);
+		pr_err("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index d5e4a02..b97c67b 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -21,6 +21,13 @@
 	help
 	  This enables the fastboot protocol over UDP.
 
+config UDP_FUNCTION_FASTBOOT_PORT
+	depends on UDP_FUNCTION_FASTBOOT
+	int "Define FASTBOOT UDP port"
+	default 5554
+	help
+	  The fastboot protocol requires a UDP port number.
+
 if FASTBOOT
 
 config FASTBOOT_BUF_ADDR
diff --git a/drivers/hwspinlock/hwspinlock-uclass.c b/drivers/hwspinlock/hwspinlock-uclass.c
index cbe7236..e012d5a 100644
--- a/drivers/hwspinlock/hwspinlock-uclass.c
+++ b/drivers/hwspinlock/hwspinlock-uclass.c
@@ -25,7 +25,7 @@
 				       struct ofnode_phandle_args *args)
 {
 	if (args->args_count > 1) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/mailbox/k3-sec-proxy.c b/drivers/mailbox/k3-sec-proxy.c
index 20fdb09..a862e55 100644
--- a/drivers/mailbox/k3-sec-proxy.c
+++ b/drivers/mailbox/k3-sec-proxy.c
@@ -116,7 +116,7 @@
 	debug("%s(chan=%p)\n", __func__, chan);
 
 	if (args->args_count != 1) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 	ind = args->args[0];
diff --git a/drivers/mailbox/mailbox-uclass.c b/drivers/mailbox/mailbox-uclass.c
index 01c9e75..85ba8c5 100644
--- a/drivers/mailbox/mailbox-uclass.c
+++ b/drivers/mailbox/mailbox-uclass.c
@@ -24,7 +24,7 @@
 	debug("%s(chan=%p)\n", __func__, chan);
 
 	if (args->args_count != 1) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index 1d66d95..08c51c4 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -77,7 +77,7 @@
 	debug("%s(chan=%p)\n", __func__, chan);
 
 	if (args->args_count != 2) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
index eb9f3b9..7b79ed2 100644
--- a/drivers/misc/irq-uclass.c
+++ b/drivers/misc/irq-uclass.c
@@ -89,7 +89,7 @@
 	log_debug("(irq=%p)\n", irq);
 
 	if (args->args_count > 1) {
-		log_debug("Invaild args_count: %d\n", args->args_count);
+		log_debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
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/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
index 8ff58a7..3a9c9ca 100644
--- a/drivers/mtd/nand/raw/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -1862,10 +1862,10 @@
 		return -EINVAL;
 	}
 
-	if (dev_read_bool(dev, "nand-enable-arbiter"))
+	if (dev_read_bool(dev, "marvell,nand-enable-arbiter"))
 		pdata->enable_arbiter = 1;
 
-	if (dev_read_bool(dev, "nand-keep-config"))
+	if (dev_read_bool(dev, "marvell,nand-keep-config"))
 		pdata->keep_config = 1;
 
 	/*
diff --git a/drivers/mtd/ubispl/ubispl.c b/drivers/mtd/ubispl/ubispl.c
index 03b31f0..b58d8e8 100644
--- a/drivers/mtd/ubispl/ubispl.c
+++ b/drivers/mtd/ubispl/ubispl.c
@@ -953,7 +953,7 @@
 	 * Check, if the total number of blocks is correct
 	 */
 	if (be32_to_cpu(vh->used_ebs) != last) {
-		ubi_dbg("Block count missmatch.");
+		ubi_dbg("Block count mismatch.");
 		ubi_dbg("vh->used_ebs: %d nrblocks: %d",
 			be32_to_cpu(vh->used_ebs), last);
 		generic_set_bit(pnum, ubi->corrupt);
diff --git a/drivers/mux/mux-uclass.c b/drivers/mux/mux-uclass.c
index 91842c5..8870305 100644
--- a/drivers/mux/mux-uclass.c
+++ b/drivers/mux/mux-uclass.c
@@ -130,7 +130,7 @@
 	log_debug("%s(muxp=%p)\n", __func__, muxp);
 
 	if (args->args_count > 1) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/net/eth-phy-uclass.c b/drivers/net/eth-phy-uclass.c
index a9b358e..1f285f7 100644
--- a/drivers/net/eth-phy-uclass.c
+++ b/drivers/net/eth-phy-uclass.c
@@ -103,7 +103,7 @@
 			return uc_priv->mdio_bus;
 		}
 	} else {
-		log_notice("FEC: can't find phy-handle\n");
+		log_debug("Can't find phy-handle for %s\n", eth_dev->name);
 	}
 
 	return NULL;
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index 40a86a3..811bc27 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -1465,7 +1465,7 @@
 	start = get_timer(0);
 	while (readl(&priv->eth->ecntrl) & FEC_ECNTRL_RESET) {
 		if (get_timer(start) > (CONFIG_SYS_HZ * 5)) {
-			printf("FEC MXC: Timeout reseting chip\n");
+			printf("FEC MXC: Timeout resetting chip\n");
 			goto err_timeout;
 		}
 		udelay(10);
diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c
index 72b500a..3ddae97 100644
--- a/drivers/net/fm/memac_phy.c
+++ b/drivers/net/fm/memac_phy.c
@@ -64,7 +64,7 @@
 {
 	unsigned int timeout = MAX_NUM_RETRIES;
 
-	while ((memac_in_32(&regs->mdio_data) & MDIO_DATA_BSY) && timeout--)
+	while ((memac_in_32(&regs->mdio_stat) & MDIO_STAT_BSY) && timeout--)
 		;
 
 	if (!timeout) {
diff --git a/drivers/net/fsl_ls_mdio.c b/drivers/net/fsl_ls_mdio.c
index 6d4e682..f213e0d 100644
--- a/drivers/net/fsl_ls_mdio.c
+++ b/drivers/net/fsl_ls_mdio.c
@@ -84,7 +84,7 @@
 	memac_out_32(&regs->mdio_ctl, mdio_ctl);
 
 	/* Wait till the MDIO write is complete */
-	while ((memac_in_32(&regs->mdio_data)) & MDIO_DATA_BSY)
+	while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
 		;
 
 	/* Return all Fs if nothing was there */
@@ -107,7 +107,7 @@
 	memac_out_32(&regs->mdio_data, MDIO_DATA(val));
 
 	/* Wait till the MDIO write is complete */
-	while ((memac_in_32(&regs->mdio_data)) & MDIO_DATA_BSY)
+	while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
 		;
 
 	return 0;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index e69cd8a..4f8d33c 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -280,6 +280,12 @@
 	---help---
 	  Adds support for the TI DP83867 1Gbit PHY.
 
+config PHY_TI_DP83869
+	select PHY_TI
+	bool "Texas Instruments Ethernet DP83869 PHY support"
+	---help---
+	  Adds support for the TI DP83869 1Gbit PHY.
+
 config PHY_TI_GENERIC
 	select PHY_TI
 	bool "Texas Instruments Generic Ethernet PHYs support"
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 218b8c7..77f7f60 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -29,6 +29,7 @@
 obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
 obj-$(CONFIG_PHY_TI) += ti_phy_init.o
 obj-$(CONFIG_PHY_TI_DP83867) += dp83867.o
+obj-$(CONFIG_PHY_TI_DP83869) += dp83869.o
 obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
 obj-$(CONFIG_PHY_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c
new file mode 100644
index 0000000..c946118
--- /dev/null
+++ b/drivers/net/phy/dp83869.c
@@ -0,0 +1,507 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TI PHY drivers
+ *
+ */
+
+#include <common.h>
+#include <phy.h>
+#include <linux/compat.h>
+#include <malloc.h>
+
+#include <dm.h>
+#include <dt-bindings/net/ti-dp83869.h>
+
+/* TI DP83869 */
+#define DP83869_DEVADDR		0x1f
+
+#define MII_DP83869_PHYCTRL	0x10
+#define MII_DP83869_MICR	0x12
+#define MII_DP83869_CFG2	0x14
+#define MII_DP83869_BISCR	0x16
+#define DP83869_CTRL		0x1f
+#define DP83869_CFG4		0x1e
+
+/* Extended Registers */
+#define DP83869_GEN_CFG3	0x0031
+#define DP83869_RGMIICTL	0x0032
+#define DP83869_STRAP_STS1	0x006E
+#define DP83869_RGMIIDCTL	0x0086
+#define DP83869_IO_MUX_CFG	0x0170
+#define DP83869_OP_MODE		0x01df
+#define DP83869_FX_CTRL		0x0c00
+
+#define DP83869_SW_RESET	BIT(15)
+#define DP83869_SW_RESTART	BIT(14)
+
+/* MICR Interrupt bits */
+#define MII_DP83869_MICR_AN_ERR_INT_EN		BIT(15)
+#define MII_DP83869_MICR_SPEED_CHNG_INT_EN	BIT(14)
+#define MII_DP83869_MICR_DUP_MODE_CHNG_INT_EN	BIT(13)
+#define MII_DP83869_MICR_PAGE_RXD_INT_EN	BIT(12)
+#define MII_DP83869_MICR_AUTONEG_COMP_INT_EN	BIT(11)
+#define MII_DP83869_MICR_LINK_STS_CHNG_INT_EN	BIT(10)
+#define MII_DP83869_MICR_FALSE_CARRIER_INT_EN	BIT(8)
+#define MII_DP83869_MICR_SLEEP_MODE_CHNG_INT_EN	BIT(4)
+#define MII_DP83869_MICR_WOL_INT_EN		BIT(3)
+#define MII_DP83869_MICR_XGMII_ERR_INT_EN	BIT(2)
+#define MII_DP83869_MICR_POL_CHNG_INT_EN	BIT(1)
+#define MII_DP83869_MICR_JABBER_INT_EN		BIT(0)
+
+#define MII_DP83869_BMCR_DEFAULT		(BMCR_ANENABLE | \
+						 BMCR_FULLDPLX | \
+						 BMCR_SPEED1000)
+
+/* This is the same bit mask as the BMCR so re-use the BMCR default */
+#define DP83869_FX_CTRL_DEFAULT MII_DP83869_BMCR_DEFAULT
+
+/* CFG1 bits */
+#define DP83869_CFG1_DEFAULT			(ADVERTISE_1000HALF | \
+						 ADVERTISE_1000FULL | \
+						 CTL1000_AS_MASTER)
+
+/* RGMIICTL bits */
+#define DP83869_RGMII_TX_CLK_DELAY_EN		BIT(1)
+#define DP83869_RGMII_RX_CLK_DELAY_EN		BIT(0)
+
+/* STRAP_STS1 bits */
+#define DP83869_STRAP_OP_MODE_MASK		GENMASK(2, 0)
+#define DP83869_STRAP_STS1_RESERVED		BIT(11)
+#define DP83869_STRAP_MIRROR_ENABLED		BIT(12)
+
+/* PHY CTRL bits */
+#define DP83869_PHYCR_RX_FIFO_DEPTH_SHIFT		12
+#define DP83869_PHYCR_RX_FIFO_DEPTH_MASK		GENMASK(13, 12)
+#define DP83869_PHYCR_TX_FIFO_DEPTH_SHIFT		14
+#define DP83869_PHYCR_TX_FIFO_DEPTH_MASK		GENMASK(15, 14)
+#define DP83869_PHYCR_RESERVED_MASK			BIT(11)
+#define DP83869_PHYCR_MDI_CROSSOVER_SHIFT		5
+#define DP83869_PHYCR_MDI_CROSSOVER_MDIX		2
+#define DP83869_PHY_CTRL_DEFAULT			0x48
+
+/* RGMIIDCTL bits */
+#define DP83869_RGMII_TX_CLK_DELAY_SHIFT	4
+#define DP83869_CLK_DELAY_DEF				7
+
+/* CFG2 bits */
+#define MII_DP83869_CFG2_SPEEDOPT_10EN		0x0040
+#define MII_DP83869_CFG2_SGMII_AUTONEGEN	0x0080
+#define MII_DP83869_CFG2_SPEEDOPT_ENH		0x0100
+#define MII_DP83869_CFG2_SPEEDOPT_CNT		0x0800
+#define MII_DP83869_CFG2_SPEEDOPT_INTLOW	0x2000
+#define MII_DP83869_CFG2_MASK			0x003F
+
+/* User setting - can be taken from DTS */
+#define DEFAULT_FIFO_DEPTH	DP83869_PHYCR_FIFO_DEPTH_4_B_NIB
+
+/* IO_MUX_CFG bits */
+#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL	0x1f
+
+#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_MAX	0x0
+#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_MIN	0x1f
+#define DP83869_IO_MUX_CFG_CLK_O_DISABLE	BIT(6)
+#define DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT	8
+#define DP83869_IO_MUX_CFG_CLK_O_SEL_MASK	\
+		GENMASK(0x1f, DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT)
+
+/* CFG3 bits */
+#define DP83869_CFG3_PORT_MIRROR_EN		BIT(0)
+
+/* OP MODE bits */
+#define DP83869_OP_MODE_MII			BIT(5)
+#define DP83869_SGMII_RGMII_BRIDGE		BIT(6)
+
+enum {
+	DP83869_PORT_MIRRORING_KEEP,
+	DP83869_PORT_MIRRORING_EN,
+	DP83869_PORT_MIRRORING_DIS,
+};
+
+struct dp83869_private {
+	int tx_fifo_depth;
+	int rx_fifo_depth;
+	s32 rx_int_delay;
+	s32 tx_int_delay;
+	int io_impedance;
+	int port_mirroring;
+	bool set_clk_output;
+	int clk_output_sel;
+	int mode;
+};
+
+static int dp83869_readext(struct phy_device *phydev, int addr, int devad, int reg)
+{
+	return phy_read_mmd(phydev, devad, reg);
+}
+
+static int dp83869_writeext(struct phy_device *phydev, int addr, int devad, int reg, u16 val)
+{
+	return phy_write_mmd(phydev, devad, reg, val);
+}
+
+static int dp83869_config_port_mirroring(struct phy_device *phydev)
+{
+	struct dp83869_private *dp83869 =
+		(struct dp83869_private *)phydev->priv;
+	u16 val;
+
+	val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_CFG4);
+
+	if (dp83869->port_mirroring == DP83869_PORT_MIRRORING_EN)
+		val |= DP83869_CFG3_PORT_MIRROR_EN;
+	else
+		val &= ~DP83869_CFG3_PORT_MIRROR_EN;
+
+	phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_CFG4, val);
+
+	return 0;
+}
+
+#ifdef CONFIG_DM_ETH
+static const int dp83869_internal_delay[] = {250, 500, 750, 1000, 1250, 1500,
+					     1750, 2000, 2250, 2500, 2750, 3000,
+					     3250, 3500, 3750, 4000};
+
+static int dp83869_set_strapped_mode(struct phy_device *phydev)
+{
+	struct dp83869_private *dp83869 = phydev->priv;
+	int val;
+
+	val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_STRAP_STS1);
+	if (val < 0)
+		return val;
+
+	dp83869->mode = val & DP83869_STRAP_OP_MODE_MASK;
+
+	return 0;
+}
+
+/**
+ * dp83869_data_init - Convenience function for setting PHY specific data
+ *
+ * @phydev: the phy_device struct
+ */
+static int dp83869_of_init(struct phy_device *phydev)
+{
+	struct dp83869_private * const dp83869 = phydev->priv;
+	const int delay_entries = ARRAY_SIZE(dp83869_internal_delay);
+	int ret;
+	ofnode node;
+
+	node = phy_get_ofnode(phydev);
+	if (!ofnode_valid(node))
+		return -EINVAL;
+
+	dp83869->io_impedance = -EINVAL;
+
+	/* Optional configuration, set to default if required */
+	dp83869->clk_output_sel = ofnode_read_u32_default(node, "ti,clk-output-sel",
+							  DP83869_CLK_O_SEL_CHN_A_RCLK);
+
+	if (dp83869->clk_output_sel > DP83869_CLK_O_SEL_REF_CLK &&
+	    dp83869->clk_output_sel != DP83869_CLK_O_SEL_OFF)
+		dp83869->clk_output_sel = DP83869_CLK_O_SEL_REF_CLK;
+
+	/* If operation mode is not set use setting from straps */
+	ret = ofnode_read_s32(node, "ti,op-mode", &dp83869->mode);
+	if (ret == 0) {
+		if (dp83869->mode < DP83869_RGMII_COPPER_ETHERNET ||
+		    dp83869->mode > DP83869_SGMII_COPPER_ETHERNET)
+			return -EINVAL;
+	} else {
+		ret = dp83869_set_strapped_mode(phydev);
+		if (ret)
+			return ret;
+	}
+
+	if (ofnode_read_bool(node, "ti,max-output-impedance"))
+		dp83869->io_impedance = DP83869_IO_MUX_CFG_IO_IMPEDANCE_MAX;
+	else if (ofnode_read_bool(node, "ti,min-output-impedance"))
+		dp83869->io_impedance = DP83869_IO_MUX_CFG_IO_IMPEDANCE_MIN;
+
+	if (ofnode_read_bool(node, "enet-phy-lane-swap")) {
+		dp83869->port_mirroring = DP83869_PORT_MIRRORING_EN;
+	} else {
+		ret = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_STRAP_STS1);
+
+		if (ret < 0)
+			return ret;
+
+		if (ret & DP83869_STRAP_MIRROR_ENABLED)
+			dp83869->port_mirroring = DP83869_PORT_MIRRORING_EN;
+		else
+			dp83869->port_mirroring = DP83869_PORT_MIRRORING_DIS;
+	}
+
+	dp83869->rx_fifo_depth = ofnode_read_s32_default(node, "rx-fifo-depth",
+							 DP83869_PHYCR_FIFO_DEPTH_4_B_NIB);
+
+	dp83869->tx_fifo_depth = ofnode_read_s32_default(node, "tx-fifo-depth",
+							 DP83869_PHYCR_FIFO_DEPTH_4_B_NIB);
+
+	/* RX delay *must* be specified if internal delay of RX is used. */
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+		dp83869->rx_int_delay = ofnode_read_u32_default(node, "rx-internal-delay-ps",
+								DP83869_CLK_DELAY_DEF);
+		if (dp83869->rx_int_delay > delay_entries) {
+			dp83869->rx_int_delay = DP83869_CLK_DELAY_DEF;
+			pr_debug("rx-internal-delay-ps not set/invalid, default to %ups\n",
+				 dp83869_internal_delay[dp83869->rx_int_delay]);
+		}
+
+		dp83869->rx_int_delay = dp83869_internal_delay[dp83869->rx_int_delay];
+	}
+
+	/* TX delay *must* be specified if internal delay of RX is used. */
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+		dp83869->tx_int_delay = ofnode_read_u32_default(node, "tx-internal-delay-ps",
+								DP83869_CLK_DELAY_DEF);
+		if (dp83869->tx_int_delay > delay_entries) {
+			dp83869->tx_int_delay = DP83869_CLK_DELAY_DEF;
+			pr_debug("tx-internal-delay-ps not set/invalid, default to %ups\n",
+				 dp83869_internal_delay[dp83869->tx_int_delay]);
+		}
+
+		dp83869->tx_int_delay = dp83869_internal_delay[dp83869->tx_int_delay];
+	}
+
+	return 0;
+}
+#else
+static int dp83869_of_init(struct phy_device *phydev)
+{
+	struct dp83869_private *dp83869 = phydev->priv;
+
+	dp83869->rx_int_delay = DP83869_RGMIIDCTL_2_25_NS;
+	dp83869->tx_int_delay = DP83869_RGMIIDCTL_2_75_NS;
+	dp83869->fifo_depth = DEFAULT_FIFO_DEPTH;
+	dp83869->io_impedance = -EINVAL;
+
+	return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
+static int dp83869_configure_rgmii(struct phy_device *phydev,
+				   struct dp83869_private *dp83869)
+{
+	int ret = 0, val;
+
+	if (phy_interface_is_rgmii(phydev)) {
+		val = phy_read(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL);
+		if (val < 0)
+			return val;
+
+		val &= ~(DP83869_PHYCR_TX_FIFO_DEPTH_MASK | DP83869_PHYCR_RX_FIFO_DEPTH_MASK);
+		val |= (dp83869->tx_fifo_depth << DP83869_PHYCR_TX_FIFO_DEPTH_SHIFT);
+		val |= (dp83869->rx_fifo_depth << DP83869_PHYCR_RX_FIFO_DEPTH_SHIFT);
+
+		ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL, val);
+		if (ret)
+			return ret;
+	}
+
+	if (dp83869->io_impedance >= 0) {
+		val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG);
+
+		val &= ~DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
+		val |= dp83869->io_impedance & DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL;
+
+		ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG, val);
+
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int dp83869_configure_mode(struct phy_device *phydev,
+				  struct dp83869_private *dp83869)
+{
+	int phy_ctrl_val;
+	int ret, val;
+
+	if (dp83869->mode < DP83869_RGMII_COPPER_ETHERNET ||
+	    dp83869->mode > DP83869_SGMII_COPPER_ETHERNET)
+		return -EINVAL;
+
+	/* Below init sequence for each operational mode is defined in
+	 * section 9.4.8 of the datasheet.
+	 */
+	ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE,
+			    dp83869->mode);
+	if (ret)
+		return ret;
+
+	ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, MII_DP83869_BMCR_DEFAULT);
+	if (ret)
+		return ret;
+
+	phy_ctrl_val = (dp83869->rx_fifo_depth << DP83869_PHYCR_RX_FIFO_DEPTH_SHIFT |
+			dp83869->tx_fifo_depth << DP83869_PHYCR_TX_FIFO_DEPTH_SHIFT |
+			DP83869_PHY_CTRL_DEFAULT);
+
+	switch (dp83869->mode) {
+	case DP83869_RGMII_COPPER_ETHERNET:
+		ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL,
+				phy_ctrl_val);
+		if (ret)
+			return ret;
+
+		ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, DP83869_CFG1_DEFAULT);
+		if (ret)
+			return ret;
+
+		ret = dp83869_configure_rgmii(phydev, dp83869);
+		if (ret)
+			return ret;
+		break;
+	case DP83869_RGMII_SGMII_BRIDGE:
+		val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE);
+
+		val |= DP83869_SGMII_RGMII_BRIDGE;
+
+		ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, val);
+
+		if (ret)
+			return ret;
+
+		ret = phy_write_mmd(phydev, DP83869_DEVADDR,
+				    DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT);
+		if (ret)
+			return ret;
+
+		break;
+	case DP83869_1000M_MEDIA_CONVERT:
+		ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL,
+				phy_ctrl_val);
+		if (ret)
+			return ret;
+
+		ret = phy_write_mmd(phydev, DP83869_DEVADDR,
+				    DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT);
+		if (ret)
+			return ret;
+		break;
+	case DP83869_100M_MEDIA_CONVERT:
+		ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL,
+				phy_ctrl_val);
+		if (ret)
+			return ret;
+		break;
+	case DP83869_SGMII_COPPER_ETHERNET:
+		ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83869_PHYCTRL,
+				phy_ctrl_val);
+		if (ret)
+			return ret;
+
+		ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, DP83869_CFG1_DEFAULT);
+		if (ret)
+			return ret;
+
+		ret = phy_write_mmd(phydev, DP83869_DEVADDR,
+				    DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT);
+		if (ret)
+			return ret;
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int dp83869_config(struct phy_device *phydev)
+{
+	struct dp83869_private *dp83869;
+	unsigned int val;
+	int ret;
+
+	dp83869 = (struct dp83869_private *)phydev->priv;
+
+	ret = dp83869_of_init(phydev);
+	if (ret)
+		return ret;
+
+	ret = dp83869_configure_mode(phydev, dp83869);
+	if (ret)
+		return ret;
+
+	if (dp83869->port_mirroring != DP83869_PORT_MIRRORING_KEEP)
+		dp83869_config_port_mirroring(phydev);
+
+	/* Clock output selection if muxing property is set */
+	if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) {
+		val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG);
+
+		val &= ~DP83869_IO_MUX_CFG_CLK_O_SEL_MASK;
+		val |= dp83869->clk_output_sel << DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT;
+
+		ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG, val);
+
+		if (ret)
+			return ret;
+	}
+
+	if (phy_interface_is_rgmii(phydev)) {
+		ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL,
+				    dp83869->rx_int_delay |
+			dp83869->tx_int_delay << DP83869_RGMII_TX_CLK_DELAY_SHIFT);
+		if (ret)
+			return ret;
+
+		val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL);
+		val |= (DP83869_RGMII_TX_CLK_DELAY_EN |
+			DP83869_RGMII_RX_CLK_DELAY_EN);
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+			val &= ~(DP83869_RGMII_TX_CLK_DELAY_EN |
+				 DP83869_RGMII_RX_CLK_DELAY_EN);
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+			val &= ~DP83869_RGMII_TX_CLK_DELAY_EN;
+
+		if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+			val &= ~DP83869_RGMII_RX_CLK_DELAY_EN;
+
+		ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL,
+				    val);
+	}
+
+	genphy_config_aneg(phydev);
+	return 0;
+}
+
+static int dp83869_probe(struct phy_device *phydev)
+{
+	struct dp83869_private *dp83869;
+
+	dp83869 = kzalloc(sizeof(*dp83869), GFP_KERNEL);
+	if (!dp83869)
+		return -ENOMEM;
+
+	phydev->priv = dp83869;
+	return 0;
+}
+
+static struct phy_driver DP83869_driver = {
+	.name = "TI DP83869",
+	.uid = 0x2000a0f1,
+	.mask = 0xfffffff0,
+	.features = PHY_GBIT_FEATURES,
+	.probe = dp83869_probe,
+	.config = &dp83869_config,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+	.readext = dp83869_readext,
+	.writeext = dp83869_writeext
+};
+
+int phy_dp83869_init(void)
+{
+	phy_register(&DP83869_driver);
+	return 0;
+}
diff --git a/drivers/net/phy/ti_phy_init.c b/drivers/net/phy/ti_phy_init.c
index 50eff77..075b19a 100644
--- a/drivers/net/phy/ti_phy_init.c
+++ b/drivers/net/phy/ti_phy_init.c
@@ -88,6 +88,10 @@
 	phy_dp83867_init();
 #endif
 
+#ifdef CONFIG_PHY_TI_DP83869
+	phy_dp83869_init();
+#endif
+
 #ifdef CONFIG_PHY_TI_GENERIC
 	phy_register(&dp83822_driver);
 	phy_register(&dp83825s_driver);
diff --git a/drivers/net/phy/ti_phy_init.h b/drivers/net/phy/ti_phy_init.h
index 6c7f6c6..bcb3d32 100644
--- a/drivers/net/phy/ti_phy_init.h
+++ b/drivers/net/phy/ti_phy_init.h
@@ -11,5 +11,6 @@
 #define _TI_GEN_PHY_H
 
 int phy_dp83867_init(void);
+int phy_dp83869_init(void);
 
 #endif /* _TI_GEN_PHY_H */
diff --git a/drivers/net/sja1105.c b/drivers/net/sja1105.c
index 17bab33..4ca8709 100644
--- a/drivers/net/sja1105.c
+++ b/drivers/net/sja1105.c
@@ -3276,12 +3276,6 @@
 	sja1105_packing(packed_buf, &device_id, 31, 0, SJA1105_SIZE_DEVICE_ID,
 			UNPACK);
 
-	if (device_id != priv->info->device_id) {
-		printf("Expected device ID 0x%llx but read 0x%llx\n",
-		       priv->info->device_id, device_id);
-		return -ENODEV;
-	}
-
 	rc = sja1105_xfer_buf(priv, SPI_READ, regs->prod_id, packed_buf,
 			      SJA1105_SIZE_DEVICE_ID);
 	if (rc < 0)
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/Kconfig b/drivers/pci/Kconfig
index 42f8cb6..630d6e6 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -265,6 +265,7 @@
 	bool "Enable Armada XP/38x PCIe driver"
 	depends on ARCH_MVEBU
 	select MISC
+	select DM_RESET
 	help
 	  Say Y here if you want to enable PCIe controller support on
 	  Armada XP/38x SoCs.
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/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c
index 18f79d2..b3ea034 100644
--- a/drivers/pci/pci_mvebu.c
+++ b/drivers/pci/pci_mvebu.c
@@ -18,13 +18,16 @@
 #include <dm/lists.h>
 #include <dm/of_access.h>
 #include <pci.h>
+#include <reset.h>
 #include <asm/io.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/soc.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/mbus.h>
+#include <linux/sizes.h>
 
 /* PCIe unit register offsets */
 #define SELECT(x, n)			((x >> n) & 1UL)
@@ -59,6 +62,9 @@
 #define PCIE_DEBUG_CTRL			0x1a60
 #define  PCIE_DEBUG_SOFT_RESET		BIT(20)
 
+#define LINK_WAIT_RETRIES	100
+#define LINK_WAIT_TIMEOUT	1000
+
 struct mvebu_pcie {
 	struct pci_controller hose;
 	void __iomem *base;
@@ -66,8 +72,10 @@
 	struct resource mem;
 	void __iomem *iobase;
 	struct resource io;
+	u32 intregs;
 	u32 port;
 	u32 lane;
+	bool is_x4;
 	int devfn;
 	u32 lane_mask;
 	int first_busno;
@@ -80,14 +88,6 @@
 	u32 cfgcache[(0x3c - 0x10) / 4];
 };
 
-/*
- * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
- * into SoCs address space. Each controller will map 128M of MEM
- * and 64K of I/O space when registered.
- */
-static void __iomem *mvebu_pcie_membase = (void __iomem *)MBUS_PCI_MEM_BASE;
-static void __iomem *mvebu_pcie_iobase = (void __iomem *)MBUS_PCI_IO_BASE;
-
 static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
 {
 	u32 val;
@@ -95,6 +95,23 @@
 	return !(val & PCIE_STAT_LINK_DOWN);
 }
 
+static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie)
+{
+	int retries;
+
+	/* check if the link is up or not */
+	for (retries = 0; retries < LINK_WAIT_RETRIES; retries++) {
+		if (mvebu_pcie_link_up(pcie)) {
+			printf("%s: Link up\n", pcie->name);
+			return;
+		}
+
+		udelay(LINK_WAIT_TIMEOUT);
+	}
+
+	printf("%s: Link down\n", pcie->name);
+}
+
 static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno)
 {
 	u32 stat;
@@ -357,10 +374,63 @@
 	       pcie->base + PCIE_BAR_CTRL_OFF(1));
 
 	/* Setup BAR[0] to internal registers. */
-	writel(SOC_REGS_PHY_BASE, pcie->base + PCIE_BAR_LO_OFF(0));
+	writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0));
 	writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
 }
 
+/* Only enable PCIe link, do not setup it */
+static int mvebu_pcie_enable_link(struct mvebu_pcie *pcie, ofnode node)
+{
+	struct reset_ctl rst;
+	int ret;
+
+	ret = reset_get_by_index_nodev(node, 0, &rst);
+	if (ret == -ENOENT) {
+		return 0;
+	} else if (ret < 0) {
+		printf("%s: cannot get reset controller: %d\n", pcie->name, ret);
+		return ret;
+	}
+
+	ret = reset_request(&rst);
+	if (ret) {
+		printf("%s: cannot request reset controller: %d\n", pcie->name, ret);
+		return ret;
+	}
+
+	ret = reset_deassert(&rst);
+	reset_free(&rst);
+	if (ret) {
+		printf("%s: cannot enable PCIe port: %d\n", pcie->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* Setup PCIe link but do not enable it */
+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);
+
+	/*
+	 * Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link
+	 * Capability register. This register is defined by PCIe specification
+	 * as read-only but this mvebu controller has it as read-write and must
+	 * 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 &= ~PCI_EXP_LNKCAP_MLW;
+	reg |= (pcie->is_x4 ? 4 : 1) << 4;
+	writel(reg, pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
+}
+
 static int mvebu_pcie_probe(struct udevice *dev)
 {
 	struct mvebu_pcie *pcie = dev_get_plat(dev);
@@ -368,11 +438,6 @@
 	struct pci_controller *hose = dev_get_uclass_priv(ctlr);
 	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);
-
 	/*
 	 * Change Class Code of PCI Bridge device to PCI Bridge (0x600400)
 	 * because default value is Memory controller (0x508000) which
@@ -433,26 +498,26 @@
 	mvebu_pcie_set_local_bus_nr(pcie, 0);
 	mvebu_pcie_set_local_dev_nr(pcie, 1);
 
-	pcie->mem.start = (u32)mvebu_pcie_membase;
-	pcie->mem.end = pcie->mem.start + MBUS_PCI_MEM_SIZE - 1;
-	mvebu_pcie_membase += MBUS_PCI_MEM_SIZE;
-
-	if (mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
+	if (resource_size(&pcie->mem) &&
+	    mvebu_mbus_add_window_by_id(pcie->mem_target, pcie->mem_attr,
 					(phys_addr_t)pcie->mem.start,
 					resource_size(&pcie->mem))) {
-		printf("PCIe unable to add mbus window for mem at %08x+%08x\n",
+		printf("%s: unable to add mbus window for mem at %08x+%08x\n",
+		       pcie->name,
 		       (u32)pcie->mem.start, (unsigned)resource_size(&pcie->mem));
+		pcie->mem.start = 0;
+		pcie->mem.end = -1;
 	}
 
-	pcie->io.start = (u32)mvebu_pcie_iobase;
-	pcie->io.end = pcie->io.start + MBUS_PCI_IO_SIZE - 1;
-	mvebu_pcie_iobase += MBUS_PCI_IO_SIZE;
-
-	if (mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
+	if (resource_size(&pcie->io) &&
+	    mvebu_mbus_add_window_by_id(pcie->io_target, pcie->io_attr,
 					(phys_addr_t)pcie->io.start,
 					resource_size(&pcie->io))) {
-		printf("PCIe unable to add mbus window for IO at %08x+%08x\n",
+		printf("%s: unable to add mbus window for IO at %08x+%08x\n",
+		       pcie->name,
 		       (u32)pcie->io.start, (unsigned)resource_size(&pcie->io));
+		pcie->io.start = 0;
+		pcie->io.end = -1;
 	}
 
 	/* Setup windows and configure host bridge */
@@ -461,13 +526,23 @@
 	/* PCI memory space */
 	pci_set_region(hose->regions + 0, pcie->mem.start,
 		       pcie->mem.start, resource_size(&pcie->mem), PCI_REGION_MEM);
-	pci_set_region(hose->regions + 1,
-		       0, 0,
-		       gd->ram_size,
-		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
-	pci_set_region(hose->regions + 2, pcie->io.start,
-		       pcie->io.start, resource_size(&pcie->io), PCI_REGION_IO);
-	hose->region_count = 3;
+	hose->region_count = 1;
+
+	if (resource_size(&pcie->mem)) {
+		pci_set_region(hose->regions + hose->region_count,
+			       pcie->mem.start, pcie->mem.start,
+			       resource_size(&pcie->mem),
+			       PCI_REGION_MEM);
+		hose->region_count++;
+	}
+
+	if (resource_size(&pcie->io)) {
+		pci_set_region(hose->regions + hose->region_count,
+			       pcie->io.start, pcie->io.start,
+			       resource_size(&pcie->io),
+			       PCI_REGION_IO);
+		hose->region_count++;
+	}
 
 	/* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */
 	pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] =
@@ -475,21 +550,7 @@
 	pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] =
 		PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16);
 
-	return 0;
-}
-
-static int mvebu_pcie_port_parse_dt(ofnode node, struct mvebu_pcie *pcie)
-{
-	const u32 *addr;
-	int len;
-
-	addr = ofnode_get_property(node, "assigned-addresses", &len);
-	if (!addr) {
-		pr_err("property \"assigned-addresses\" not found");
-		return -FDT_ERR_NOTFOUND;
-	}
-
-	pcie->base = (void *)(fdt32_to_cpu(addr[2]) + SOC_REGS_PHY_BASE);
+	mvebu_pcie_wait_for_link(pcie);
 
 	return 0;
 }
@@ -554,31 +615,38 @@
 	return -ENOENT;
 }
 
-static int mvebu_pcie_of_to_plat(struct udevice *dev)
+static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pcie *pcie)
 {
-	struct mvebu_pcie *pcie = dev_get_plat(dev);
+	struct fdt_pci_addr pci_addr;
+	const u32 *addr;
+	u32 num_lanes;
 	int ret = 0;
+	int len;
 
 	/* Get port number, lane number and memory target / attr */
-	if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port",
+	if (ofnode_read_u32(node, "marvell,pcie-port",
 			    &pcie->port)) {
 		ret = -ENODEV;
 		goto err;
 	}
 
-	if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-lane", &pcie->lane))
+	if (ofnode_read_u32(node, "marvell,pcie-lane", &pcie->lane))
 		pcie->lane = 0;
 
 	sprintf(pcie->name, "pcie%d.%d", pcie->port, pcie->lane);
 
-	/* pci_get_devfn() returns devfn in bits 15..8, see PCI_DEV usage */
-	pcie->devfn = pci_get_devfn(dev);
-	if (pcie->devfn < 0) {
-		ret = -ENODEV;
+	if (!ofnode_read_u32(node, "num-lanes", &num_lanes) && num_lanes == 4)
+		pcie->is_x4 = true;
+
+	/* devfn is in bits [15:8], see PCI_DEV usage */
+	ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr);
+	if (ret < 0) {
+		printf("%s: property \"reg\" is invalid\n", pcie->name);
 		goto err;
 	}
+	pcie->devfn = pci_addr.phys_hi & 0xff00;
 
-	ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
+	ret = mvebu_get_tgt_attr(parent, pcie->devfn,
 				 IORESOURCE_MEM,
 				 &pcie->mem_target, &pcie->mem_attr);
 	if (ret < 0) {
@@ -586,7 +654,7 @@
 		goto err;
 	}
 
-	ret = mvebu_get_tgt_attr(dev_ofnode(dev->parent), pcie->devfn,
+	ret = mvebu_get_tgt_attr(parent, pcie->devfn,
 				 IORESOURCE_IO,
 				 &pcie->io_target, &pcie->io_attr);
 	if (ret < 0) {
@@ -595,9 +663,15 @@
 	}
 
 	/* Parse PCIe controller register base from DT */
-	ret = mvebu_pcie_port_parse_dt(dev_ofnode(dev), pcie);
-	if (ret < 0)
+	addr = ofnode_get_property(node, "assigned-addresses", &len);
+	if (!addr) {
+		printf("%s: property \"assigned-addresses\" not found\n", pcie->name);
+		ret = -FDT_ERR_NOTFOUND;
 		goto err;
+	}
+
+	pcie->base = (void *)(u32)ofnode_translate_address(node, addr);
+	pcie->intregs = (u32)pcie->base - fdt32_to_cpu(addr[2]);
 
 	return 0;
 
@@ -615,7 +689,6 @@
 	.id			= UCLASS_PCI,
 	.ops			= &mvebu_pcie_ops,
 	.probe			= mvebu_pcie_probe,
-	.of_to_plat	= mvebu_pcie_of_to_plat,
 	.plat_auto	= sizeof(struct mvebu_pcie),
 };
 
@@ -625,9 +698,14 @@
  */
 static int mvebu_pcie_bind(struct udevice *parent)
 {
+	struct mvebu_pcie **ports_pcie;
 	struct mvebu_pcie *pcie;
 	struct uclass_driver *drv;
 	struct udevice *dev;
+	struct resource mem;
+	struct resource io;
+	int ports_count, i;
+	ofnode *ports_nodes;
 	ofnode subnode;
 
 	/* Lookup pci driver */
@@ -637,19 +715,94 @@
 		return -ENOENT;
 	}
 
+	ports_count = ofnode_get_child_count(dev_ofnode(parent));
+	ports_pcie = calloc(ports_count, sizeof(*ports_pcie));
+	ports_nodes = calloc(ports_count, sizeof(*ports_nodes));
+	if (!ports_pcie || !ports_nodes) {
+		free(ports_pcie);
+		free(ports_nodes);
+		return -ENOMEM;
+	}
+	ports_count = 0;
+
+	mem.start = MBUS_PCI_MEM_BASE;
+	mem.end = MBUS_PCI_MEM_BASE + MBUS_PCI_MEM_SIZE - 1;
+	io.start = MBUS_PCI_IO_BASE;
+	io.end = MBUS_PCI_IO_BASE + MBUS_PCI_IO_SIZE - 1;
+
+	/* First phase: Fill mvebu_pcie struct for each port */
 	ofnode_for_each_subnode(subnode, dev_ofnode(parent)) {
 		if (!ofnode_is_available(subnode))
 			continue;
 
 		pcie = calloc(1, sizeof(*pcie));
 		if (!pcie)
-			return -ENOMEM;
+			continue;
+
+		if (mvebu_pcie_port_parse_dt(subnode, dev_ofnode(parent), pcie) < 0) {
+			free(pcie);
+			continue;
+		}
+
+		/*
+		 * MVEBU PCIe controller needs MEMORY and I/O BARs to be mapped
+		 * into SoCs address space. Each controller will map 128M of MEM
+		 * and 64K of I/O space when registered.
+		 */
+
+		if (resource_size(&mem) >= SZ_128M) {
+			pcie->mem.start = mem.start;
+			pcie->mem.end = mem.start + SZ_128M - 1;
+			mem.start += SZ_128M;
+		} else {
+			printf("%s: unable to assign mbus window for mem\n", pcie->name);
+			pcie->mem.start = 0;
+			pcie->mem.end = -1;
+		}
+
+		if (resource_size(&io) >= SZ_64K) {
+			pcie->io.start = io.start;
+			pcie->io.end = io.start + SZ_64K - 1;
+			io.start += SZ_64K;
+		} else {
+			printf("%s: unable to assign mbus window for io\n", pcie->name);
+			pcie->io.start = 0;
+			pcie->io.end = -1;
+		}
+
+		ports_pcie[ports_count] = pcie;
+		ports_nodes[ports_count] = subnode;
+		ports_count++;
+	}
+
+	/* Second phase: Setup all PCIe links (do not enable them yet) */
+	for (i = 0; i < ports_count; i++)
+		mvebu_pcie_setup_link(ports_pcie[i]);
+
+	/* Third phase: Enable all PCIe links and create for each UCLASS_PCI device */
+	for (i = 0; i < ports_count; i++) {
+		pcie = ports_pcie[i];
+		subnode = ports_nodes[i];
+
+		/*
+		 * PCIe link can be enabled only after all PCIe links were
+		 * properly configured. This is because more PCIe links shares
+		 * one enable bit and some PCIe links cannot be enabled
+		 * individually.
+		 */
+		if (mvebu_pcie_enable_link(pcie, subnode) < 0) {
+			free(pcie);
+			continue;
+		}
 
 		/* Create child device UCLASS_PCI and bind it */
 		device_bind(parent, &pcie_mvebu_drv, pcie->name, pcie, subnode,
 			    &dev);
 	}
 
+	free(ports_pcie);
+	free(ports_nodes);
+
 	return 0;
 }
 
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 59683a0..49e2ec2 100644
--- a/drivers/phy/phy-uclass.c
+++ b/drivers/phy/phy-uclass.c
@@ -11,19 +11,103 @@
 #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)
 {
 	debug("%s(phy=%p)\n", __func__, phy);
 
 	if (args->args_count > 1) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
@@ -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/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index 99b3f9a..9aea5fc 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -9,6 +9,15 @@
 	  domains). This may be used to save power. This API provides the
 	  means to control such power management hardware.
 
+config APPLE_PMGR_POWER_DOMAIN
+	bool "Enable the Apple PMGR power domain driver"
+	depends on POWER_DOMAIN
+	default y if ARCH_APPLE
+	help
+	  Enable support for manipulating power domains on Apple SoCs.
+	  This driver is needed to power on parts of the SoC that have
+	  not been powered on by previous boot stages.
+
 config BCM6328_POWER_DOMAIN
 	bool "Enable the BCM6328 power domain driver"
 	depends on POWER_DOMAIN && ARCH_BMIPS
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index 3d1e5f0..530ae35 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_$(SPL_)POWER_DOMAIN) += power-domain-uclass.o
+obj-$(CONFIG_APPLE_PMGR_POWER_DOMAIN) += apple-pmgr.o
 obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
 obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o
 obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o
diff --git a/drivers/power/domain/apple-pmgr.c b/drivers/power/domain/apple-pmgr.c
new file mode 100644
index 0000000..d25f136
--- /dev/null
+++ b/drivers/power/domain/apple-pmgr.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <linux/err.h>
+#include <linux/bitfield.h>
+#include <power-domain-uclass.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#define APPLE_PMGR_PS_TARGET	GENMASK(3, 0)
+#define APPLE_PMGR_PS_ACTUAL	GENMASK(7, 4)
+
+#define APPLE_PMGR_PS_ACTIVE	0xf
+#define APPLE_PMGR_PS_PWRGATE	0x0
+
+#define APPLE_PMGR_PS_SET_TIMEOUT_US	100
+
+struct apple_pmgr_priv {
+	struct regmap *regmap;
+	u32 offset;		/* offset within regmap for this domain */
+};
+
+static int apple_pmgr_request(struct power_domain *power_domain)
+{
+	return 0;
+}
+
+static int apple_pmgr_rfree(struct power_domain *power_domain)
+{
+	return 0;
+}
+
+static int apple_pmgr_ps_set(struct power_domain *power_domain, u32 pstate)
+{
+	struct apple_pmgr_priv *priv = dev_get_priv(power_domain->dev);
+	uint reg;
+
+	regmap_update_bits(priv->regmap, priv->offset, APPLE_PMGR_PS_TARGET,
+			   FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate));
+
+	return regmap_read_poll_timeout(
+		priv->regmap, priv->offset, reg,
+		(FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1,
+		APPLE_PMGR_PS_SET_TIMEOUT_US);
+}
+
+static int apple_pmgr_on(struct power_domain *power_domain)
+{
+	return apple_pmgr_ps_set(power_domain, APPLE_PMGR_PS_ACTIVE);
+}
+
+static int apple_pmgr_off(struct power_domain *power_domain)
+{
+	return 0;
+}
+
+static int apple_pmgr_of_xlate(struct power_domain *power_domain,
+			       struct ofnode_phandle_args *args)
+{
+	if (args->args_count != 0) {
+		debug("Invalid args_count: %d\n", args->args_count);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id apple_pmgr_ids[] = {
+	{ .compatible = "apple,pmgr-pwrstate" },
+	{ /* sentinel */ }
+};
+
+static int apple_pmgr_probe(struct udevice *dev)
+{
+	struct apple_pmgr_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = dev_power_domain_on(dev);
+	if (ret)
+		return ret;
+
+	priv->regmap = syscon_get_regmap(dev->parent);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	ret = dev_read_u32(dev, "reg", &priv->offset);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+struct power_domain_ops apple_pmgr_ops = {
+	.request = apple_pmgr_request,
+	.rfree = apple_pmgr_rfree,
+	.on = apple_pmgr_on,
+	.off = apple_pmgr_off,
+	.of_xlate = apple_pmgr_of_xlate,
+};
+
+U_BOOT_DRIVER(apple_pmgr) = {
+	.name = "apple_pmgr",
+	.id = UCLASS_POWER_DOMAIN,
+	.of_match = apple_pmgr_ids,
+	.ops = &apple_pmgr_ops,
+	.probe = apple_pmgr_probe,
+	.priv_auto = sizeof(struct apple_pmgr_priv),
+};
diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c
index c09c009..ca9f00a 100644
--- a/drivers/reset/reset-uclass.c
+++ b/drivers/reset/reset-uclass.c
@@ -26,7 +26,7 @@
 	debug("%s(reset_ctl=%p)\n", __func__, reset_ctl);
 
 	if (args->args_count != 1) {
-		debug("Invaild args_count: %d\n", args->args_count);
+		debug("Invalid args_count: %d\n", args->args_count);
 		return -EINVAL;
 	}
 
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 30d4421..96a1cb6 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -104,7 +104,8 @@
 			}
 		}
 	}
-	if (!SPL_BUILD || !CONFIG_IS_ENABLED(OF_CONTROL) || !blob) {
+	if (!IS_ENABLED(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(OF_CONTROL) ||
+	    !blob) {
 		/*
 		 * Try to use CONFIG_CONS_INDEX if available (it is numbered
 		 * from 1!).
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index fb10884..2748270 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -461,7 +461,7 @@
 	u32 max_hw_ep;
 	int pdata_hw_ep;
 
-	debug("Reseting OTG controller\n");
+	debug("Resetting OTG controller\n");
 
 	dflt_gusbcfg =
 		0<<15		/* PHY Low Power Clock sel*/
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
index b9510e3..2ffcb7c 100644
--- a/drivers/usb/musb/musb_udc.c
+++ b/drivers/usb/musb/musb_udc.c
@@ -269,7 +269,7 @@
 				      __PRETTY_FUNCTION__, udc_device->address);
 	} else {
 		if (debug_level > 0)
-			serial_printf("ERROR : %s Address missmatch "
+			serial_printf("ERROR : %s Address mismatch "
 				      "sw %d vs hw %d\n",
 				      __PRETTY_FUNCTION__,
 				      udc_device->address, faddr);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 1177f17..cabac29 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -81,6 +81,15 @@
 	  What exactly happens when the timer expires is up to a particular
 	  device/driver.
 
+config WDT_APPLE
+	bool "Apple watchdog timer support"
+	depends on WDT
+	default y if ARCH_APPLE
+	help
+	  Enable support for the watchdog timer on Apple SoCs.
+	  The watchdog will perform a full SoC reset resulting in a
+	  reboot of the entire system.
+
 config WDT_ARMADA_37XX
 	bool "Marvell Armada 37xx watchdog timer support"
 	depends on WDT && ARMADA_3700
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index fa7ce58..6d2b382 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -17,6 +17,7 @@
 obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
 obj-$(CONFIG_$(SPL_TPL_)WDT) += wdt-uclass.o
 obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
+obj-$(CONFIG_WDT_APPLE) += apple_wdt.o
 obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
 obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
 obj-$(CONFIG_WDT_AST2600) += ast2600_wdt.o
diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
new file mode 100644
index 0000000..c7307f4
--- /dev/null
+++ b/drivers/watchdog/apple_wdt.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org>
+ */
+
+#include <clk.h>
+#include <dm.h>
+#include <wdt.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#define APPLE_WDT_CUR_TIME		0x10
+#define APPLE_WDT_BARK_TIME		0x14
+#define APPLE_WDT_CTRL			0x1c
+#define  APPLE_WDT_CTRL_RESET_EN	BIT(2)
+
+struct apple_wdt_priv {
+	void *base;
+	ulong clk_rate;
+};
+
+static int apple_wdt_reset(struct udevice *dev)
+{
+	struct apple_wdt_priv *priv = dev_get_priv(dev);
+
+	writel(0, priv->base + APPLE_WDT_CUR_TIME);
+
+	return 0;
+}
+
+static int apple_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
+{
+	struct apple_wdt_priv *priv = dev_get_priv(dev);
+	u64 timeout;
+
+	timeout = (timeout_ms * priv->clk_rate) / 1000;
+	if (timeout > U32_MAX)
+		return -EINVAL;
+
+	writel(0, priv->base + APPLE_WDT_CUR_TIME);
+	writel(timeout, priv->base + APPLE_WDT_BARK_TIME);
+	writel(APPLE_WDT_CTRL_RESET_EN, priv->base + APPLE_WDT_CTRL);
+
+	return 0;
+}
+
+static int apple_wdt_stop(struct udevice *dev)
+{
+	struct apple_wdt_priv *priv = dev_get_priv(dev);
+
+	writel(0, priv->base + APPLE_WDT_CTRL);
+
+	return 0;
+}
+
+static int apple_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+	int ret;
+
+	ret = apple_wdt_start(dev, 0, flags);
+	if (ret)
+		return ret;
+
+	/*
+	 * It can take up to 25ms until the SoC actually resets, so
+	 * wait 50ms just to be sure.
+	 */
+	mdelay(50);
+
+	return 0;
+}
+
+static const struct wdt_ops apple_wdt_ops = {
+	.reset = apple_wdt_reset,
+	.start = apple_wdt_start,
+	.stop = apple_wdt_stop,
+	.expire_now = apple_wdt_expire_now,
+};
+
+static const struct udevice_id apple_wdt_ids[] = {
+	{ .compatible = "apple,wdt" },
+	{ /* sentinel */ }
+};
+
+static int apple_wdt_probe(struct udevice *dev)
+{
+	struct apple_wdt_priv *priv = dev_get_priv(dev);
+	struct clk clk;
+	int ret;
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (!priv->base)
+		return -EINVAL;
+
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(&clk);
+	if (ret)
+		return ret;
+
+	priv->clk_rate = clk_get_rate(&clk);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(apple_wdt) = {
+	.name = "apple_wdt",
+	.id = UCLASS_WDT,
+	.of_match = apple_wdt_ids,
+	.priv_auto = sizeof(struct apple_wdt_priv),
+	.probe = apple_wdt_probe,
+	.ops = &apple_wdt_ops,
+};
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/bloblist.h b/include/bloblist.h
index 9f007c7..173129b 100644
--- a/include/bloblist.h
+++ b/include/bloblist.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause */
 /*
  * This provides a standard way of passing information between boot phases
  * (TPL -> SPL -> U-Boot proper.)
@@ -13,6 +13,8 @@
 #ifndef __BLOBLIST_H
 #define __BLOBLIST_H
 
+#include <mapmem.h>
+
 enum {
 	BLOBLIST_VERSION	= 0,
 	BLOBLIST_MAGIC		= 0xb00757a3,
@@ -23,23 +25,57 @@
 enum bloblist_tag_t {
 	BLOBLISTT_NONE = 0,
 
-	/* Vendor-specific tags are permitted here */
-	BLOBLISTT_EC_HOSTEVENT,		/* Chromium OS EC host-event mask */
-	BLOBLISTT_SPL_HANDOFF,		/* Hand-off info from SPL */
-	BLOBLISTT_VBOOT_CTX,		/* Chromium OS verified boot context */
-	BLOBLISTT_VBOOT_HANDOFF,	/* Chromium OS internal handoff info */
+	/*
+	 * Standard area to allocate blobs used across firmware components, for
+	 * things that are very commonly used, particularly in multiple
+	 * projects.
+	 */
+	BLOBLISTT_AREA_FIRMWARE_TOP = 0x1,
+
+	/* Standard area to allocate blobs used across firmware components */
+	BLOBLISTT_AREA_FIRMWARE = 0x100,
 	/*
 	 * Advanced Configuration and Power Interface Global Non-Volatile
 	 * Sleeping table. This forms part of the ACPI tables passed to Linux.
 	 */
-	BLOBLISTT_ACPI_GNVS,
-	BLOBLISTT_INTEL_VBT,		/* Intel Video-BIOS table */
-	BLOBLISTT_TPM2_TCG_LOG,		/* TPM v2 log space */
-	BLOBLISTT_TCPA_LOG,		/* TPM log space */
-	BLOBLISTT_ACPI_TABLES,		/* ACPI tables for x86 */
-	BLOBLISTT_SMBIOS_TABLES,	/* SMBIOS tables for x86 */
+	BLOBLISTT_ACPI_GNVS = 0x100,
+	BLOBLISTT_INTEL_VBT = 0x101,	/* Intel Video-BIOS table */
+	BLOBLISTT_TPM2_TCG_LOG = 0x102,	/* TPM v2 log space */
+	BLOBLISTT_TCPA_LOG = 0x103,	/* TPM log space */
+	BLOBLISTT_ACPI_TABLES = 0x104,	/* ACPI tables for x86 */
+	BLOBLISTT_SMBIOS_TABLES = 0x105, /* SMBIOS tables for x86 */
+	BLOBLISTT_VBOOT_CTX = 0x106,	/* Chromium OS verified boot context */
 
-	BLOBLISTT_COUNT
+	/*
+	 * Project-specific tags are permitted here. Projects can be open source
+	 * or not, but the format of the data must be fuily documented in an
+	 * open source project, including all fields, bits, etc. Naming should
+	 * be: BLOBLISTT_<project>_<purpose_here>
+	 */
+	BLOBLISTT_PROJECT_AREA = 0x8000,
+	BLOBLISTT_U_BOOT_SPL_HANDOFF = 0x8000, /* Hand-off info from SPL */
+
+	/*
+	 * Vendor-specific tags are permitted here. Projects can be open source
+	 * or not, but the format of the data must be fuily documented in an
+	 * open source project, including all fields, bits, etc. Naming should
+	 * be BLOBLISTT_<vendor>_<purpose_here>
+	 */
+	BLOBLISTT_VENDOR_AREA = 0xc000,
+
+	/* Tags after this are not allocated for now */
+	BLOBLISTT_EXPANSION = 0x10000,
+
+	/*
+	 * Tags from here are on reserved for private use within a single
+	 * firmware binary (i.e. a single executable or phase of a project).
+	 * These tags can be passed between binaries within a local
+	 * implementation, but cannot be used in upstream code. Allocate a
+	 * tag in one of the areas above if you want that.
+	 *
+	 * This area may move in future.
+	 */
+	BLOBLISTT_PRIVATE_AREA = 0xffff0000,
 };
 
 /**
@@ -50,8 +86,8 @@
  * same place in memory as SPL and U-Boot execute, but it can be safely moved
  * around.
  *
- * None of the bloblist structures contain pointers but it is possible to put
- * pointers inside a bloblist record if desired. This is not encouraged,
+ * None of the bloblist headers themselves contain pointers but it is possible
+ * to put pointers inside a bloblist record if desired. This is not encouraged,
  * since it can make part of the bloblist inaccessible if the pointer is
  * no-longer valid. It is better to just store all the data inside a bloblist
  * record.
@@ -59,11 +95,11 @@
  * Each bloblist record is aligned to a 16-byte boundary and follows immediately
  * from the last.
  *
+ * @magic: BLOBLIST_MAGIC
  * @version: BLOBLIST_VERSION
  * @hdr_size: Size of this header, normally sizeof(struct bloblist_hdr). The
  *	first bloblist_rec starts at this offset from the start of the header
- * @flags: Space for BLOBLISTF_... flags (none yet)
- * @magic: BLOBLIST_MAGIC
+ * @flags: Space for BLOBLISTF... flags (none yet)
  * @size: Total size of the bloblist (non-zero if valid) including this header.
  *	The bloblist extends for this many bytes from the start of this header.
  *	When adding new records, the bloblist can grow up to this size.
@@ -74,14 +110,14 @@
  * @chksum: CRC32 for the entire bloblist allocated area. Since any of the
  *	blobs can be altered after being created, this checksum is only valid
  *	when the bloblist is finalised before jumping to the next stage of boot.
- *	Note: @chksum is last to make it easier to exclude it from the checksum
- *	calculation.
+ *	Note that chksum is last to make it easier to exclude it from the
+ *	checksum calculation.
  */
 struct bloblist_hdr {
+	u32 magic;
 	u32 version;
 	u32 hdr_size;
 	u32 flags;
-	u32 magic;
 
 	u32 size;
 	u32 alloced;
@@ -92,11 +128,11 @@
 /**
  * struct bloblist_rec - record for the bloblist
  *
- * NOTE: Only exported for testing purposes. Do not use this struct.
- *
  * The bloblist contains a number of records each consisting of this record
  * structure followed by the data contained. Each records is 16-byte aligned.
  *
+ * NOTE: Only exported for testing purposes. Do not use this struct.
+ *
  * @tag: Tag indicating what the record contains
  * @hdr_size: Size of this header, normally sizeof(struct bloblist_rec). The
  *	record's data starts at this offset from the start of the record
@@ -111,6 +147,35 @@
 	u32 spare;
 };
 
+/* access CONFIG_BLOBLIST_ADDR, dealing with it possibly not being defined */
+static inline ulong bloblist_addr(void)
+{
+#ifdef CONFIG_BLOBLIST_FIXED
+	return CONFIG_BLOBLIST_ADDR;
+#else
+	return 0;
+#endif
+}
+
+/**
+ * bloblist_check_magic() - return a bloblist if the magic matches
+ *
+ * @addr: Address to check
+ * Return: pointer to bloblist, if the magic matches, else NULL
+ */
+static inline void *bloblist_check_magic(ulong addr)
+{
+	u32 *ptr;
+
+	if (!addr)
+		return NULL;
+	ptr = map_sysmem(addr, 0);
+	if (*ptr != BLOBLIST_MAGIC)
+		return NULL;
+
+	return ptr;
+}
+
 /**
  * bloblist_find() - Find a blob
  *
@@ -118,8 +183,8 @@
  *
  * @tag:	Tag to search for (enum bloblist_tag_t)
  * @size:	Expected size of the blob, or 0 for any size
- * @return pointer to blob if found, or NULL if not found, or a blob was found
- *	but it is the wrong size
+ * Return: pointer to blob if found, or NULL if not found, or a blob was found
+ * but it is the wrong size
  */
 void *bloblist_find(uint tag, int size);
 
@@ -135,8 +200,8 @@
  * @tag:	Tag to add (enum bloblist_tag_t)
  * @size:	Size of the blob
  * @align:	Alignment of the blob (in bytes), 0 for default
- * @return pointer to the newly added block, or NULL if there is not enough
- *	space for the blob
+ * Return: pointer to the newly added block, or NULL if there is not enough
+ * space for the blob
  */
 void *bloblist_add(uint tag, int size, int align);
 
@@ -149,8 +214,8 @@
  * @size:	Size of the blob
  * @blobp:	Returns a pointer to blob on success
  * @align:	Alignment of the blob (in bytes), 0 for default
- * @return 0 if OK, -ENOSPC if it is missing and could not be added due to lack
- *	of space, or -ESPIPE it exists but has the wrong size
+ * Return: 0 if OK, -ENOSPC if it is missing and could not be added due to lack
+ * of space, or -ESPIPE it exists but has the wrong size
  */
 int bloblist_ensure_size(uint tag, int size, int align, void **blobp);
 
@@ -161,8 +226,8 @@
  *
  * @tag:	Tag to add (enum bloblist_tag_t)
  * @size:	Size of the blob
- * @return pointer to blob, or NULL if it is missing and could not be added due
- *	to lack of space, or it exists but has the wrong size
+ * Return: pointer to blob, or NULL if it is missing and could not be added due
+ * to lack of space, or it exists but has the wrong size
  */
 void *bloblist_ensure(uint tag, int size);
 
@@ -174,8 +239,8 @@
  * @tag:	Tag to add (enum bloblist_tag_t)
  * @sizep:	Size of the blob to create; returns size of actual blob
  * @blobp:	Returns a pointer to blob on success
- * @return 0 if OK, -ENOSPC if it is missing and could not be added due to lack
- *	of space
+ * Return: 0 if OK, -ENOSPC if it is missing and could not be added due to lack
+ * of space
  */
 int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp);
 
@@ -187,8 +252,8 @@
  *
  * @tag:	Tag to add (enum bloblist_tag_t)
  * @new_size:	New size of the blob (>0 to expand, <0 to contract)
- * @return 0 if OK, -ENOSPC if the bloblist does not have enough space, -ENOENT
- *	if the tag is not found
+ * Return: 0 if OK, -ENOSPC if the bloblist does not have enough space, -ENOENT
+ * if the tag is not found
  */
 int bloblist_resize(uint tag, int new_size);
 
@@ -198,8 +263,8 @@
  * @addr: Address of bloblist
  * @size: Initial size for bloblist
  * @flags: Flags to use for bloblist
- * @return 0 if OK, -EFAULT if addr is not aligned correctly, -ENOSPC is the
- *	area is not large enough
+ * Return: 0 if OK, -EFAULT if addr is not aligned correctly, -ENOSPC is the
+ * area is not large enough
  */
 int bloblist_new(ulong addr, uint size, uint flags);
 
@@ -208,11 +273,11 @@
  *
  * @addr: Address of bloblist
  * @size: Expected size of blobsize, or 0 to detect the size
- * @return 0 if OK, -ENOENT if the magic number doesn't match (indicating that
- *	there problem is no bloblist at the given address), -EPROTONOSUPPORT
- *	if the version does not match, -EIO if the checksum does not match,
- *	-EFBIG if the expected size does not match the detected size, -ENOSPC
- *	if the size is not large enough to hold the headers
+ * Return: 0 if OK, -ENOENT if the magic number doesn't match (indicating that
+ * there problem is no bloblist at the given address), -EPROTONOSUPPORT
+ * if the version does not match, -EIO if the checksum does not match,
+ * -EFBIG if the expected size does not match the detected size, -ENOSPC
+ * if the size is not large enough to hold the headers
  */
 int bloblist_check(ulong addr, uint size);
 
@@ -222,7 +287,7 @@
  * This sets the correct checksum for the bloblist. This ensures that the
  * bloblist will be detected correctly by the next phase of U-Boot.
  *
- * @return 0
+ * Return: 0
  */
 int bloblist_finish(void);
 
@@ -238,6 +303,20 @@
 void bloblist_get_stats(ulong *basep, ulong *sizep, ulong *allocedp);
 
 /**
+ * bloblist_get_base() - Get the base address of the bloblist
+ *
+ * Return: base address of bloblist
+ */
+ulong bloblist_get_base(void);
+
+/**
+ * bloblist_get_size() - Get the size of the bloblist
+ *
+ * Return: the size in bytes
+ */
+ulong bloblist_get_size(void);
+
+/**
  * bloblist_show_stats() - Show information about the bloblist
  *
  * This shows useful information about the bloblist on the console
@@ -255,7 +334,7 @@
  * bloblist_tag_name() - Get the name for a tag
  *
  * @tag: Tag to check
- * @return name of tag, or "invalid" if an invalid tag is provided
+ * Return: name of tag, or "invalid" if an invalid tag is provided
  */
 const char *bloblist_tag_name(enum bloblist_tag_t tag);
 
@@ -263,7 +342,7 @@
  * bloblist_reloc() - Relocate the bloblist and optionally resize it
  *
  * @to: Pointer to new bloblist location (must not overlap old location)
- * @to:size: New size for bloblist (must be larger than from_size)
+ * @to_size: New size for bloblist (must be larger than from_size)
  * @from: Pointer to bloblist to relocate
  * @from_size: Size of bloblist to relocate
  */
@@ -272,8 +351,19 @@
 /**
  * bloblist_init() - Init the bloblist system with a single bloblist
  *
- * This uses CONFIG_BLOBLIST_ADDR and CONFIG_BLOBLIST_SIZE to set up a bloblist
- * for use by U-Boot.
+ * This locates and sets up the blocklist for use.
+ *
+ * If CONFIG_BLOBLIST_FIXED is selected, it uses CONFIG_BLOBLIST_ADDR and
+ * CONFIG_BLOBLIST_SIZE to set up a bloblist for use by U-Boot.
+ *
+ * If CONFIG_BLOBLIST_ALLOC is selected, it allocates memory for a bloblist of
+ * size CONFIG_BLOBLIST_SIZE.
+ *
+ * If CONFIG_BLOBLIST_PASSAGE is selected, it uses the bloblist in the incoming
+ * standard passage. The size is detected automatically so CONFIG_BLOBLIST_SIZE
+ * can be 0.
+ *
+ * Return: 0 if OK, -ve on error
  */
 int bloblist_init(void);
 
diff --git a/include/configs/clearfog.h b/include/configs/clearfog.h
index a30bca5..c9af5a4 100644
--- a/include/configs/clearfog.h
+++ b/include/configs/clearfog.h
@@ -53,7 +53,7 @@
 
 /* Defines for SPL */
 #define CONFIG_SPL_SIZE			(140 << 10)
-#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - 0x0030)
+#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + CONFIG_SPL_SIZE)
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/db-88f6720.h b/include/configs/db-88f6720.h
index 19fc669..16c83a8 100644
--- a/include/configs/db-88f6720.h
+++ b/include/configs/db-88f6720.h
@@ -32,22 +32,9 @@
  */
 #include "mv-common.h"
 
-/*
- * Memory layout while starting into the bin_hdr via the
- * BootROM:
- *
- * 0x4000.4000 - 0x4003.4000	headers space (192KiB)
- * 0x4000.4030			bin_hdr start address
- * 0x4003.4000 - 0x4004.7c00	BootROM memory allocations (15KiB)
- * 0x4007.fffc			BootROM stack top
- *
- * The address space between 0x4007.fffc and 0x400f.fff is not locked in
- * L2 cache thus cannot be used.
- */
-
 /* SPL */
 /* Defines for SPL */
-#define CONFIG_SPL_MAX_SIZE		((128 << 10) - 0x4030)
+#define CONFIG_SPL_MAX_SIZE		((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + (128 << 10))
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/db-88f6820-amc.h b/include/configs/db-88f6820-amc.h
index 1f70c60..6538e66 100644
--- a/include/configs/db-88f6820-amc.h
+++ b/include/configs/db-88f6820-amc.h
@@ -41,7 +41,7 @@
 
 /* Defines for SPL */
 #define CONFIG_SPL_SIZE			(140 << 10)
-#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - 0x0030)
+#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + CONFIG_SPL_SIZE)
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/db-88f6820-gp.h b/include/configs/db-88f6820-gp.h
index 41dadfe..5f26119 100644
--- a/include/configs/db-88f6820-gp.h
+++ b/include/configs/db-88f6820-gp.h
@@ -50,7 +50,7 @@
 
 /* Defines for SPL */
 #define CONFIG_SPL_SIZE			(140 << 10)
-#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - 0x0030)
+#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + CONFIG_SPL_SIZE)
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/db-mv784mp-gp.h b/include/configs/db-mv784mp-gp.h
index dbbc33e..449a567 100644
--- a/include/configs/db-mv784mp-gp.h
+++ b/include/configs/db-mv784mp-gp.h
@@ -59,7 +59,7 @@
 
 /* SPL */
 /* Defines for SPL */
-#define CONFIG_SPL_MAX_SIZE		((128 << 10) - 0x4030)
+#define CONFIG_SPL_MAX_SIZE		((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + (128 << 10))
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/ds414.h b/include/configs/ds414.h
index 7fba2b4..dbccd46 100644
--- a/include/configs/ds414.h
+++ b/include/configs/ds414.h
@@ -45,7 +45,7 @@
 
 /* SPL */
 /* Defines for SPL */
-#define CONFIG_SPL_MAX_SIZE		((128 << 10) - 0x4030)
+#define CONFIG_SPL_MAX_SIZE		((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + (128 << 10))
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/helios4.h b/include/configs/helios4.h
index 56d35d6..de1ebbf 100644
--- a/include/configs/helios4.h
+++ b/include/configs/helios4.h
@@ -53,7 +53,7 @@
 
 /* Defines for SPL */
 #define CONFIG_SPL_SIZE			(140 << 10)
-#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - 0x0030)
+#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + CONFIG_SPL_SIZE)
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/maxbcm.h b/include/configs/maxbcm.h
index 53ba649..073c5a5 100644
--- a/include/configs/maxbcm.h
+++ b/include/configs/maxbcm.h
@@ -48,7 +48,7 @@
 
 /* SPL */
 /* Defines for SPL */
-#define CONFIG_SPL_MAX_SIZE		((128 << 10) - 0x4030)
+#define CONFIG_SPL_MAX_SIZE		((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + (128 << 10))
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
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/configs/theadorable.h b/include/configs/theadorable.h
index b43c03d..3c942cc 100644
--- a/include/configs/theadorable.h
+++ b/include/configs/theadorable.h
@@ -77,7 +77,7 @@
 
 /* SPL */
 /* Defines for SPL */
-#define CONFIG_SPL_MAX_SIZE		((128 << 10) - 0x4030)
+#define CONFIG_SPL_MAX_SIZE		((128 << 10) - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + (128 << 10))
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/turris_omnia.h b/include/configs/turris_omnia.h
index 9436a62..b35299b 100644
--- a/include/configs/turris_omnia.h
+++ b/include/configs/turris_omnia.h
@@ -28,7 +28,7 @@
 
 /* Defines for SPL */
 #define CONFIG_SPL_SIZE			(140 << 10)
-#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - 0x0030)
+#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + CONFIG_SPL_SIZE)
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/configs/x530.h b/include/configs/x530.h
index e78e249..67ff01d 100644
--- a/include/configs/x530.h
+++ b/include/configs/x530.h
@@ -68,7 +68,7 @@
 
 /* Defines for SPL */
 #define CONFIG_SPL_SIZE			(140 << 10)
-#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - 0x0030)
+#define CONFIG_SPL_MAX_SIZE		(CONFIG_SPL_SIZE - (CONFIG_SPL_TEXT_BASE - 0x40000000))
 
 #define CONFIG_SPL_BSS_START_ADDR	(0x40000000 + CONFIG_SPL_SIZE)
 #define CONFIG_SPL_BSS_MAX_SIZE		(16 << 10)
diff --git a/include/dm/device.h b/include/dm/device.h
index cf785f7..435a111 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -145,7 +145,7 @@
  * @uclass_node: Used by uclass to link its devices
  * @child_head: List of children of this device
  * @sibling_node: Next device in list of all devices
- * @flags_: Flags for this device DM_FLAG_... (do not access outside driver
+ * @flags_: Flags for this device `DM_FLAG_...` (do not access outside driver
  *	model)
  * @seq_: Allocated sequence number for this device (-1 = none). This is set up
  * when the device is bound and is unique within the device's uclass. If the
@@ -193,14 +193,14 @@
 };
 
 /**
- * udevice_rt - runtime information set up by U-Boot
+ * struct udevice_rt - runtime information set up by U-Boot
  *
  * This is only used with OF_PLATDATA_RT
  *
  * There is one of these for every udevice in the linker list, indexed by
  * the udevice_info idx value.
  *
- * @flags_: Flags for this device DM_FLAG_... (do not access outside driver
+ * @flags_: Flags for this device `DM_FLAG_...` (do not access outside driver
  *	model)
  */
 struct udevice_rt {
@@ -239,7 +239,7 @@
  * dev_ofnode() - get the DT node reference associated with a udevice
  *
  * @dev:	device to check
- * @return reference of the the device's DT node
+ * Return: reference of the device's DT node
  */
 static inline ofnode dev_ofnode(const struct udevice *dev)
 {
@@ -351,7 +351,7 @@
  * @ops: Driver-specific operations. This is typically a list of function
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
- * @flags: driver flags - see DM_FLAGS_...
+ * @flags: driver flags - see `DM_FLAGS_...`
  * @acpi_ops: Advanced Configuration and Power Interface (ACPI) operations,
  * allowing the device to add things to the ACPI tables passed to Linux
  */
@@ -378,11 +378,24 @@
 #endif
 };
 
-/* Declare a new U-Boot driver */
+/**
+ * U_BOOT_DRIVER() - Declare a new U-Boot driver
+ * @__name: name of the driver
+ */
 #define U_BOOT_DRIVER(__name)						\
 	ll_entry_declare(struct driver, __name, driver)
 
-/* Get a pointer to a given driver */
+/**
+ * DM_DRIVER_GET() - Get a pointer to a given driver
+ *
+ * This is useful in code for referencing a driver at build time.
+ * Before this is used, an extern U_BOOT_DRIVER() must have been
+ * declared.
+ *
+ * @__name:	Name of the driver. This must be a valid C identifier,
+ * used by the linker_list
+ * Return: struct driver * for the driver
+ */
 #define DM_DRIVER_GET(__name)						\
 	ll_entry_get(struct driver, __name, driver)
 
@@ -392,60 +405,69 @@
  * This is useful in data structures and code for referencing a driver at
  * build time. Before this is used, an extern U_BOOT_DRIVER() must have been
  * declared.
+ * This is like DM_DRIVER_GET, but without the extra code, so it is suitable
+ * for putting into data structures.
  *
- * For example:
+ * For example::
  *
- * extern U_BOOT_DRIVER(sandbox_fixed_clock);
+ *   extern U_BOOT_DRIVER(sandbox_fixed_clock);
+ *   struct driver *drvs[] = {
+ *       DM_DRIVER_REF(sandbox_fixed_clock),
+ *   };
  *
- * struct driver *drvs[] = {
- *	DM_DRIVER_REF(sandbox_fixed_clock),
- * };
- *
- * @_name: Name of the driver. This must be a valid C identifier, used by the
- *	linker_list
- * @returns struct driver * for the driver
+ * @_name:	Name of the driver. This must be a valid C identifier,
+ * used by the linker_list
+ * Return: struct driver * for the driver
  */
 #define DM_DRIVER_REF(_name)					\
 	ll_entry_ref(struct driver, _name, driver)
 
 /**
- * Declare a macro to state a alias for a driver name. This macro will
- * produce no code but its information will be parsed by tools like
- * dtoc
+ * DM_DRIVER_ALIAS() - Declare a macro to state an alias for a driver name
+ *
+ * This macro will produce no code but its information will be parsed by tools
+ * like dtoc
+ *
+ * @__name:	name of driver
+ * @__alias:	alias for the driver name
  */
 #define DM_DRIVER_ALIAS(__name, __alias)
 
 /**
- * Declare a macro to indicate which phase of U-Boot this driver is fore.
- *
+ * DM_PHASE() - Declare a macro to indicate which phase of U-Boot this driver is for.
  *
  * This macro produces no code but its information will be parsed by dtoc. The
  * macro can be only be used once in a driver. Put it within the U_BOOT_DRIVER()
- * declaration, e.g.:
+ * declaration, e.g.::
  *
- * U_BOOT_DRIVER(cpu) = {
- *	.name = ...
- *	...
- *	DM_PHASE(tpl)
- * };
+ *   U_BOOT_DRIVER(cpu) = {
+ *       .name = ...
+ *       ...
+ *       DM_PHASE(tpl)
+ *   };
+ *
+ * @_phase:	Associated phase of U-Boot ("spl", "tpl")
  */
 #define DM_PHASE(_phase)
 
 /**
- * Declare a macro to declare a header needed for a driver. Often the correct
- * header can be found automatically, but only for struct declarations. For
- * enums and #defines used in the driver declaration and declared in a different
- * header from the structs, this macro must be used.
+ * DM_HEADER() - Declare a macro to declare a header needed for a driver.
+ *
+ * Often the correct header can be found automatically, but only for struct
+ * declarations. For enums and #defines used in the driver declaration and
+ * declared in a different header from the structs, this macro must be used.
  *
  * This macro produces no code but its information will be parsed by dtoc. The
  * macro can be used multiple times with different headers, for the same driver.
- * Put it within the U_BOOT_DRIVER() declaration, e.g.:
+ * Put it within the U_BOOT_DRIVER() declaration, e.g.::
  *
- * U_BOOT_DRIVER(cpu) = {
- *	.name = ...
- *	...
- *	DM_HEADER(<asm/cpu.h>)
- * };
+ *   U_BOOT_DRIVER(cpu) = {
+ *       .name = ...
+ *       ...
+ *       DM_HEADER(<asm/cpu.h>)
+ *   };
+ *
+ * @_hdr:	header needed for a driver
  */
 #define DM_HEADER(_hdr)
 
@@ -454,8 +476,8 @@
  *
  * This checks that dev is not NULL, but no other checks for now
  *
- * @dev		Device to check
- * @return platform data, or NULL if none
+ * @dev:	Device to check
+ * Return: platform data, or NULL if none
  */
 void *dev_get_plat(const struct udevice *dev);
 
@@ -464,8 +486,8 @@
  *
  * This checks that dev is not NULL, but no other checks for now
  *
- * @dev		Device to check
- * @return parent's platform data, or NULL if none
+ * @dev:	Device to check
+ * Return: parent's platform data, or NULL if none
  */
 void *dev_get_parent_plat(const struct udevice *dev);
 
@@ -474,8 +496,8 @@
  *
  * This checks that dev is not NULL, but no other checks for now
  *
- * @dev		Device to check
- * @return uclass's platform data, or NULL if none
+ * @dev:	Device to check
+ * Return: uclass's platform data, or NULL if none
  */
 void *dev_get_uclass_plat(const struct udevice *dev);
 
@@ -484,8 +506,8 @@
  *
  * This checks that dev is not NULL, but no other checks for now
  *
- * @dev		Device to check
- * @return private data, or NULL if none
+ * @dev:	Device to check
+ * Return: private data, or NULL if none
  */
 void *dev_get_priv(const struct udevice *dev);
 
@@ -498,8 +520,8 @@
  *
  * This checks that dev is not NULL, but no other checks for now
  *
- * @dev		Device to check
- * @return parent data, or NULL if none
+ * @dev:	Device to check
+ * Return: parent data, or NULL if none
  */
 void *dev_get_parent_priv(const struct udevice *dev);
 
@@ -508,16 +530,16 @@
  *
  * This checks that dev is not NULL, but no other checks for now
  *
- * @dev		Device to check
- * @return private uclass data for this device, or NULL if none
+ * @dev:	Device to check
+ * Return: private uclass data for this device, or NULL if none
  */
 void *dev_get_uclass_priv(const struct udevice *dev);
 
 /**
- * struct dev_get_parent() - Get the parent of a device
+ * dev_get_parent() - Get the parent of a device
  *
  * @child:	Child to check
- * @return parent of child, or NULL if this is the root device
+ * Return: parent of child, or NULL if this is the root device
  */
 struct udevice *dev_get_parent(const struct udevice *child);
 
@@ -529,13 +551,14 @@
  * returns the associated data value for that compatible string. This is
  * the 'data' field in struct udevice_id.
  *
- * As an example, consider this structure:
- * static const struct udevice_id tegra_i2c_ids[] = {
- *	{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
- *	{ .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
- *	{ .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
- *	{ }
- * };
+ * As an example, consider this structure::
+ *
+ *  static const struct udevice_id tegra_i2c_ids[] = {
+ *      { .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
+ *      { .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
+ *      { .compatible = "nvidia,tegra20-i2c-dvc", .data = TYPE_DVC },
+ *      { }
+ *  };
  *
  * When driver model finds a driver for this it will store the 'data' value
  * corresponding to the compatible string it matches. This function returns
@@ -544,7 +567,7 @@
  * For USB devices, this is the driver_info field in struct usb_device_id.
  *
  * @dev:	Device to check
- * @return driver data (0 if none is provided)
+ * Return: driver data (0 if none is provided)
  */
 ulong dev_get_driver_data(const struct udevice *dev);
 
@@ -555,7 +578,7 @@
  * driver's operations.
  *
  * @dev:	Device to check
- * @return void pointer to driver's operations or NULL for NULL-dev or NULL-ops
+ * Return: void pointer to driver's operations or NULL for NULL-dev or NULL-ops
  */
 const void *dev_get_driver_ops(const struct udevice *dev);
 
@@ -563,7 +586,7 @@
  * device_get_uclass_id() - return the uclass ID of a device
  *
  * @dev:	Device to check
- * @return uclass ID for the device
+ * Return: uclass ID for the device
  */
 enum uclass_id device_get_uclass_id(const struct udevice *dev);
 
@@ -573,7 +596,7 @@
  * This checks that dev is not NULL.
  *
  * @dev:	Device to check
- * @return  pointer to the uclass name for the device
+ * Return:  pointer to the uclass name for the device
  */
 const char *dev_get_uclass_name(const struct udevice *dev);
 
@@ -583,11 +606,11 @@
  * Returns the numbered child, 0 being the first. This does not use
  * sequence numbers, only the natural order.
  *
- * @dev:	Parent device to check
+ * @parent:	Parent device to check
  * @index:	Child index
  * @devp:	Returns pointer to device
- * @return 0 if OK, -ENODEV if no such device, other error if the device fails
- *	   to probe
+ * Return:
+ * 0 if OK, -ENODEV if no such device, other error if the device fails to probe
  */
 int device_get_child(const struct udevice *parent, int index,
 		     struct udevice **devp);
@@ -619,7 +642,7 @@
  * @seq: Sequence number to find (0=first)
  * @devp: Returns pointer to device (there is only one per for each seq).
  * Set to NULL if none is found
- * @return 0 if OK, -ENODEV if not found
+ * Return: 0 if OK, -ENODEV if not found
  */
 int device_find_child_by_seq(const struct udevice *parent, int seq,
 			     struct udevice **devp);
@@ -637,7 +660,7 @@
  * @seq: Sequence number to find (0=first)
  * @devp: Returns pointer to device (there is only one per for each seq)
  * Set to NULL if none is found
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int device_get_child_by_seq(const struct udevice *parent, int seq,
 			    struct udevice **devp);
@@ -650,7 +673,7 @@
  * @parent: Parent device
  * @of_offset: Device tree offset to find
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int device_find_child_by_of_offset(const struct udevice *parent, int of_offset,
 				   struct udevice **devp);
@@ -665,7 +688,7 @@
  * @parent: Parent device
  * @of_offset: Device tree offset to find
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int device_get_child_by_of_offset(const struct udevice *parent, int of_offset,
 				  struct udevice **devp);
@@ -680,7 +703,7 @@
  *
  * @node: Device tree ofnode to find
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 
 int device_find_global_by_ofnode(ofnode node, struct udevice **devp);
@@ -695,7 +718,7 @@
  *
  * @node: Device tree ofnode to find
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int device_get_global_by_ofnode(ofnode node, struct udevice **devp);
 
@@ -715,7 +738,7 @@
  *
  * @idx: Index number of the driver_info/udevice structure (0=first)
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int device_get_by_ofplat_idx(uint idx, struct udevice **devp);
 
@@ -724,7 +747,7 @@
  *
  * @parent: Parent device to search
  * @devp: Returns first child device, or NULL if none
- * @return 0
+ * Return: 0
  */
 int device_find_first_child(const struct udevice *parent,
 			    struct udevice **devp);
@@ -734,7 +757,7 @@
  *
  * @devp: Pointer to previous child device on entry. Returns pointer to next
  *		child device, or NULL if none
- * @return 0
+ * Return: 0
  */
 int device_find_next_child(struct udevice **devp);
 
@@ -749,7 +772,7 @@
  * @parent:	Parent device to search
  * @uclass_id:	Uclass to look for
  * @devp:	Returns device found, if any, else NULL
- * @return 0 if found, else -ENODEV
+ * Return: 0 if found, else -ENODEV
  */
 int device_find_first_inactive_child(const struct udevice *parent,
 				     enum uclass_id uclass_id,
@@ -761,7 +784,7 @@
  * @parent: Parent device to search
  * @uclass_id:	Uclass to look for
  * @devp: Returns first child device in that uclass, if any, else NULL
- * @return 0 if found, else -ENODEV
+ * Return: 0 if found, else -ENODEV
  */
 int device_find_first_child_by_uclass(const struct udevice *parent,
 				      enum uclass_id uclass_id,
@@ -774,7 +797,7 @@
  * @name:	Name to look for
  * @len:	Length of the name
  * @devp:	Returns device found, if any
- * @return 0 if found, else -ENODEV
+ * Return: 0 if found, else -ENODEV
  */
 int device_find_child_by_namelen(const struct udevice *parent, const char *name,
 				 int len, struct udevice **devp);
@@ -785,7 +808,7 @@
  * @parent:	Parent device to search
  * @name:	Name to look for
  * @devp:	Returns device found, if any
- * @return 0 if found, else -ENODEV
+ * Return: 0 if found, else -ENODEV
  */
 int device_find_child_by_name(const struct udevice *parent, const char *name,
 			      struct udevice **devp);
@@ -798,7 +821,7 @@
  *
  * @parent: Parent to check
  * @devp: Returns child that was found, if any
- * @return 0 on success, -ENODEV if no children, other -ve on error
+ * Return: 0 on success, -ENODEV if no children, other -ve on error
  */
 int device_first_child_ofdata_err(struct udevice *parent,
 				  struct udevice **devp);
@@ -811,7 +834,7 @@
  *
  * @devp: On entry, points to the previous child; on exit returns the child that
  *	was found, if any
- * @return 0 on success, -ENODEV if no children, other -ve on error
+ * Return: 0 on success, -ENODEV if no children, other -ve on error
  */
 int device_next_child_ofdata_err(struct udevice **devp);
 
@@ -822,7 +845,7 @@
  *
  * @parent:	Parent device to search
  * @devp:	Returns device found, if any
- * @return 0 if found, -ENODEV if not, -ve error if device failed to probe
+ * Return: 0 if found, -ENODEV if not, -ve error if device failed to probe
  */
 int device_first_child_err(struct udevice *parent, struct udevice **devp);
 
@@ -833,7 +856,7 @@
  *
  * @devp: On entry, pointer to device to lookup. On exit, returns pointer
  * to the next sibling if no error occurred
- * @return 0 if found, -ENODEV if not, -ve error if device failed to probe
+ * Return: 0 if found, -ENODEV if not, -ve error if device failed to probe
  */
 int device_next_child_err(struct udevice **devp);
 
@@ -841,7 +864,7 @@
  * device_has_children() - check if a device has any children
  *
  * @dev:	Device to check
- * @return true if the device has one or more children
+ * Return: true if the device has one or more children
  */
 bool device_has_children(const struct udevice *dev);
 
@@ -849,7 +872,7 @@
  * device_has_active_children() - check if a device has any active children
  *
  * @dev:	Device to check
- * @return true if the device has one or more children and at least one of
+ * Return: true if the device has one or more children and at least one of
  * them is active (probed).
  */
 bool device_has_active_children(const struct udevice *dev);
@@ -862,7 +885,7 @@
  * view of devices is being displayed.
  *
  * @dev:	Device to check
- * @return true if there are no more siblings after this one - i.e. is it
+ * Return: true if there are no more siblings after this one - i.e. is it
  * last in the list.
  */
 bool device_is_last_sibling(const struct udevice *dev);
@@ -880,7 +903,7 @@
  * @dev:	Device to update
  * @name:	New name (this string is allocated new memory and attached to
  *		the device)
- * @return 0 if OK, -ENOMEM if there is not enough memory to allocate the
+ * Return: 0 if OK, -ENOMEM if there is not enough memory to allocate the
  * string
  */
 int device_set_name(struct udevice *dev, const char *name);
@@ -903,7 +926,7 @@
  * @dev:	udevice pointer for which compatible needs to be verified.
  * @compat:	Compatible string which needs to verified in the given
  *		device
- * @return true if OK, false if the compatible is not found
+ * Return: true if OK, false if the compatible is not found
  */
 bool device_is_compatible(const struct udevice *dev, const char *compat);
 
@@ -914,7 +937,7 @@
  * This allows to check whether the machine is comaptible with the compat.
  *
  * @compat:	Compatible string which needs to verified
- * @return true if OK, false if the compatible is not found
+ * Return: true if OK, false if the compatible is not found
  */
 bool of_machine_is_compatible(const char *compat);
 
@@ -922,7 +945,7 @@
  * dev_disable_by_path() - Disable a device given its device tree path
  *
  * @path:	The device tree path identifying the device to be disabled
- * @return 0 on success, -ve on error
+ * Return: 0 on success, -ve on error
  */
 int dev_disable_by_path(const char *path);
 
@@ -930,7 +953,7 @@
  * dev_enable_by_path() - Enable a device given its device tree path
  *
  * @path:	The device tree path identifying the device to be enabled
- * @return 0 on success, -ve on error
+ * Return: 0 on success, -ve on error
  */
 int dev_enable_by_path(const char *path);
 
@@ -938,7 +961,7 @@
  * device_is_on_pci_bus - Test if a device is on a PCI bus
  *
  * @dev:	device to test
- * @return:	true if it is on a PCI bus, false otherwise
+ * Return:	true if it is on a PCI bus, false otherwise
  */
 static inline bool device_is_on_pci_bus(const struct udevice *dev)
 {
@@ -971,7 +994,7 @@
  *
  * This stops when it gets an error, with @pos set to the device that failed to
  * read ofdata.
-
+ *
  * This creates a for() loop which works through the available children of
  * a device in order from start to end. Device ofdata is read by calling
  * device_of_to_plat() on each one. The devices are not probed.
@@ -1012,7 +1035,7 @@
  * be bound.
  *
  * @dev:	Device to scan
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_scan_fdt_dev(struct udevice *dev);
 
diff --git a/include/dm/devres.h b/include/dm/devres.h
index 17bb1ee..0ab277e 100644
--- a/include/dm/devres.h
+++ b/include/dm/devres.h
@@ -51,7 +51,7 @@
  * with @release.  The returned pointer can be passed to
  * other devres_*() functions.
  *
- * RETURNS:
+ * Return:
  * Pointer to allocated devres on success, NULL on failure.
  */
 #define devres_alloc(release, size, gfp) \
@@ -87,7 +87,7 @@
  * and for which @match returns 1.  If @match is NULL, it's considered
  * to match all.
  *
- * @return pointer to found devres, NULL if not found.
+ * Return: pointer to found devres, NULL if not found.
  */
 void *devres_find(struct udevice *dev, dr_release_t release,
 		  dr_match_t match, void *match_data);
@@ -103,7 +103,7 @@
  * as @new_res and for which @match return 1.  If found, @new_res is
  * freed; otherwise, @new_res is added atomically.
  *
- * @return ointer to found or added devres.
+ * Return: pointer to found or added devres.
  */
 void *devres_get(struct udevice *dev, void *new_res,
 		 dr_match_t match, void *match_data);
@@ -120,7 +120,7 @@
  * match all.  If found, the resource is removed atomically and
  * returned.
  *
- * @return ointer to removed devres on success, NULL if not found.
+ * Return: pointer to removed devres on success, NULL if not found.
  */
 void *devres_remove(struct udevice *dev, dr_release_t release,
 		    dr_match_t match, void *match_data);
@@ -140,7 +140,7 @@
  * only the devres-allocated data will be freed.  The caller becomes
  * responsible for freeing any other data.
  *
- * @return 0 if devres is found and freed, -ENOENT if not found.
+ * Return: 0 if devres is found and freed, -ENOENT if not found.
  */
 int devres_destroy(struct udevice *dev, dr_release_t release,
 		   dr_match_t match, void *match_data);
@@ -157,7 +157,7 @@
  * match all.  If found, the resource is removed atomically, the
  * release function called and the resource freed.
  *
- * @return 0 if devres is found and freed, -ENOENT if not found.
+ * Return: 0 if devres is found and freed, -ENOENT if not found.
  */
 int devres_release(struct udevice *dev, dr_release_t release,
 		   dr_match_t match, void *match_data);
@@ -173,7 +173,7 @@
  * automatically freed on driver detach.  Like all other devres
  * resources, guaranteed alignment is unsigned long long.
  *
- * @return pointer to allocated memory on success, NULL on failure.
+ * Return: pointer to allocated memory on success, NULL on failure.
  */
 void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp);
 static inline void *devm_kzalloc(struct udevice *dev, size_t size, gfp_t gfp)
diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h
index d2c1994..c9d2b27 100644
--- a/include/dm/fdtaddr.h
+++ b/include/dm/fdtaddr.h
@@ -19,7 +19,7 @@
  *
  * @dev: Pointer to a device
  *
- * @return addr
+ * Return: addr
  */
 fdt_addr_t devfdt_get_addr(const struct udevice *dev);
 
@@ -29,7 +29,7 @@
  *
  * @dev: Pointer to a device
  *
- * @return Pointer to addr, or NULL if there is no such property
+ * Return: Pointer to addr, or NULL if there is no such property
  */
 void *devfdt_get_addr_ptr(const struct udevice *dev);
 
@@ -39,7 +39,7 @@
  *
  * @dev: Pointer to a device
  *
- * @return Pointer to addr, or NULL if there is no such property
+ * Return: Pointer to addr, or NULL if there is no such property
  */
 void *devfdt_remap_addr(const struct udevice *dev);
 
@@ -51,7 +51,7 @@
  *
  * @dev: Pointer to a device
  *
- * @return Pointer to addr, or NULL if there is no such property
+ * Return: Pointer to addr, or NULL if there is no such property
  */
 void *devfdt_remap_addr_index(const struct udevice *dev, int index);
 
@@ -64,7 +64,7 @@
  *
  * @dev: Pointer to a device
  *
- * @return Pointer to addr, or NULL if there is no such property
+ * Return: Pointer to addr, or NULL if there is no such property
  */
 void *devfdt_remap_addr_name(const struct udevice *dev, const char *name);
 
@@ -76,8 +76,7 @@
  * @dev: Pointer to device
  * @size: size of the memory to map
  *
- * @return  mapped address, or NULL if the device does not have reg
- *          property.
+ * Return: mapped address, or NULL if the device does not have reg property.
  */
 void *devfdt_map_physmem(const struct udevice *dev, unsigned long size);
 
@@ -88,7 +87,7 @@
  * @index: the 'reg' property can hold a list of <addr, size> pairs
  *	   and @index is used to select which one is required
  *
- * @return addr
+ * Return: addr
  */
 fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index);
 
@@ -100,7 +99,7 @@
  * @index: the 'reg' property can hold a list of <addr, size> pairs
  *	   and @index is used to select which one is required
  *
- * @return Pointer to addr, or NULL if there is no such property
+ * Return: Pointer to addr, or NULL if there is no such property
  */
 void *devfdt_get_addr_index_ptr(const struct udevice *dev, int index);
 
@@ -115,7 +114,7 @@
  * @size: Pointer to size varible - this function returns the size
  *        specified in the 'reg' property here
  *
- * @return addr
+ * Return: addr
  */
 fdt_addr_t devfdt_get_addr_size_index(const struct udevice *dev, int index,
 				      fdt_size_t *size);
@@ -128,7 +127,7 @@
  *	  'reg-names' property providing named-based identification. @index
  *	  indicates the value to search for in 'reg-names'.
  *
- * @return addr
+ * Return: addr
  */
 fdt_addr_t devfdt_get_addr_name(const struct udevice *dev, const char *name);
 
@@ -145,7 +144,7 @@
  * @size: Pointer to size variable - this function returns the size
  *        specified in the 'reg' property here
  *
- * @return addr
+ * Return: addr
  */
 fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
 				     const char *name, fdt_size_t *size);
@@ -154,7 +153,7 @@
  * devfdt_get_addr_pci() - Read an address and handle PCI address translation
  *
  * @dev: Device to read from
- * @return address or FDT_ADDR_T_NONE if not found
+ * Return: address or FDT_ADDR_T_NONE if not found
  */
 fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev);
 
diff --git a/include/dm/lists.h b/include/dm/lists.h
index 5896ae3..fc3b4ae 100644
--- a/include/dm/lists.h
+++ b/include/dm/lists.h
@@ -19,13 +19,14 @@
  * for binding a driver given its name and plat.
  *
  * @name: Name of driver to look up
- * @return pointer to driver, or NULL if not found
+ * Return: pointer to driver, or NULL if not found
  */
 struct driver *lists_driver_lookup_name(const char *name);
 
 /**
  * lists_uclass_lookup() - Return uclass_driver based on ID of the class
- * id:		ID of the class
+ *
+ * @id:		ID of the class
  *
  * This function returns the pointer to uclass_driver, which is the class's
  * base structure based on the ID of the class. Returns NULL on error.
@@ -56,7 +57,8 @@
  * @drv: if non-NULL, force this driver to be bound
  * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
  * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
- * @return 0 if device was bound, -EINVAL if the device tree is invalid,
+ *
+ * Return: 0 if device was bound, -EINVAL if the device tree is invalid,
  * other -ve value on error
  */
 int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
diff --git a/include/dm/of.h b/include/dm/of.h
index 5cb6f44..9c9065b 100644
--- a/include/dm/of.h
+++ b/include/dm/of.h
@@ -58,14 +58,13 @@
  * struct of_phandle_args - structure to hold phandle and arguments
  *
  * This is used when decoding a phandle in a device tree property. Typically
- * these look like this:
+ * these look like this::
  *
- * wibble {
- *    phandle = <5>;
- * };
- *
- * ...
- * some-prop = <&wibble 1 2 3>
+ *   wibble {
+ *     phandle = <5>;
+ *   };
+ *   ...
+ *   some-prop = <&wibble 1 2 3>
  *
  * Here &node is the phandle of the node 'wibble', i.e. 5. There are three
  * arguments: 1, 2, 3.
diff --git a/include/dm/of_access.h b/include/dm/of_access.h
index cc382b1..ec6e6e2 100644
--- a/include/dm/of_access.h
+++ b/include/dm/of_access.h
@@ -44,7 +44,7 @@
  * which controls the given node.
  *
  * @np: Node pointer to check
- * @return number of address cells this node uses
+ * Return: number of address cells this node uses
  */
 int of_n_addr_cells(const struct device_node *np);
 
@@ -55,7 +55,7 @@
  * which controls the given node.
  *
  * @np: Node pointer to check
- * @return number of size cells this node uses
+ * Return: number of size cells this node uses
  */
 int of_n_size_cells(const struct device_node *np);
 
@@ -65,7 +65,7 @@
  * This function matches fdt_address_cells().
  *
  * @np: Node pointer to check
- * @return value of #address-cells property in this node, or 2 if none
+ * Return: value of #address-cells property in this node, or 2 if none
  */
 int of_simple_addr_cells(const struct device_node *np);
 
@@ -75,7 +75,7 @@
  * This function matches fdt_size_cells().
  *
  * @np: Node pointer to check
- * @return value of #size-cells property in this node, or 2 if none
+ * Return: value of #size-cells property in this node, or 2 if none
  */
 int of_simple_size_cells(const struct device_node *np);
 
@@ -85,7 +85,7 @@
  * @np: Pointer to device node holding property
  * @name: Name of property
  * @lenp: If non-NULL, returns length of property
- * @return pointer to property, or NULL if not found
+ * Return: pointer to property, or NULL if not found
  */
 struct property *of_find_property(const struct device_node *np,
 				  const char *name, int *lenp);
@@ -98,7 +98,7 @@
  * @np: Pointer to device node holding property
  * @name: Name of property
  * @lenp: If non-NULL, returns length of property
- * @return pointer to property value, or NULL if not found
+ * Return: pointer to property value, or NULL if not found
  */
 const void *of_get_property(const struct device_node *np, const char *name,
 			    int *lenp);
@@ -110,7 +110,7 @@
  * and read all the property with of_get_next_property_by_prop().
  *
  * @np: Pointer to device node
- * @return pointer to property or NULL if not found
+ * Return: pointer to property or NULL if not found
  */
 const struct property *of_get_first_property(const struct device_node *np);
 
@@ -122,7 +122,7 @@
  *
  * @np: Pointer to device node
  * @property: pointer of the current property
- * @return pointer to next property or NULL if not found
+ * Return: pointer to next property or NULL if not found
  */
 const struct property *of_get_next_property(const struct device_node *np,
 					    const struct property *property);
@@ -132,11 +132,11 @@
  *
  * Get value for the property identified by node and property pointer.
  *
- * @node: node to read
+ * @np: Pointer to device node
  * @property: pointer of the property to read
- * @propname: place to property name on success
+ * @name: place to property name on success
  * @lenp: place to put length on success
- * @return pointer to property value or NULL if error
+ * Return: pointer to property value or NULL if error
  */
 const void *of_get_property_by_prop(const struct device_node *np,
 				    const struct property *property,
@@ -145,7 +145,7 @@
 
 /**
  * of_device_is_compatible() - Check if the node matches given constraints
- * @device: pointer to node
+ * @np: Pointer to device node
  * @compat: required compatible string, NULL or "" for any match
  * @type: required device_type value, NULL or "" for any match
  * @name: required node name, NULL or "" for any match
@@ -154,7 +154,7 @@
  * properties of the given @device. A constraints can be skipped by
  * passing NULL or an empty string as the constraint.
  *
- * @return 0 for no match, and a positive integer on match. The return
+ * Return: 0 for no match, and a positive integer on match. The return
  * value is a relative score with larger values indicating better
  * matches. The score is weighted for the most specific compatible value
  * to get the highest score. Matching type is next, followed by matching
@@ -179,9 +179,9 @@
 /**
  * of_device_is_available() - check if a device is available for use
  *
- * @device: Node to check for availability
+ * @np: Pointer to device node to check for availability
  *
- * @return true if the status property is absent or set to "okay", false
+ * Return: true if the status property is absent or set to "okay", false
  * otherwise
  */
 bool of_device_is_available(const struct device_node *np);
@@ -189,8 +189,8 @@
 /**
  * of_get_parent() - Get a node's parent, if any
  *
- * @node: Node to check
- * @eturns a node pointer, or NULL if none
+ * @np: Pointer to device node  to check
+ * Return: a node pointer, or NULL if none
  */
 struct device_node *of_get_parent(const struct device_node *np);
 
@@ -208,7 +208,7 @@
  *	foo		Valid alias
  *	foo/bar		Valid alias + relative path
  *
- * @return a node pointer or NULL if not found
+ * Return: a node pointer or NULL if not found
  */
 struct device_node *of_find_node_opts_by_path(const char *path,
 					      const char **opts);
@@ -228,7 +228,7 @@
  * @type: The type string to match "device_type" or NULL to ignore
  * @compatible:	The string to match to one of the tokens in the device
  *	"compatible" list.
- * @return node pointer or NULL if not found
+ * Return: node pointer or NULL if not found
  */
 struct device_node *of_find_compatible_node(struct device_node *from,
 				const char *type, const char *compatible);
@@ -243,7 +243,7 @@
  * @propname: property name to check
  * @propval: property value to search for
  * @proplen: length of the value in propval
- * @return node pointer or NULL if not found
+ * Return: node pointer or NULL if not found
  */
 struct device_node *of_find_node_by_prop_value(struct device_node *from,
 					       const char *propname,
@@ -254,7 +254,7 @@
  *
  * @handle:	phandle of the node to find
  *
- * @return node pointer, or NULL if not found
+ * Return: node pointer, or NULL if not found
  */
 struct device_node *of_find_node_by_phandle(phandle handle);
 
@@ -268,7 +268,7 @@
  * @propname:	name of the property to be searched.
  * @outp:	pointer to return value, modified only if return value is 0.
  *
- * @return 0 on success, -EINVAL if the property does not exist,
+ * Return: 0 on success, -EINVAL if the property does not exist,
  * -ENODATA if property does not have a value, and -EOVERFLOW if the
  * property data isn't large enough.
  */
@@ -286,9 +286,10 @@
  * @index:	index of the u32 in the list of values
  * @outp:	pointer to return value, modified only if return value is 0.
  *
- * @return 0 on success, -EINVAL if the property does not exist,
- * -ENODATA if property does not have a value, and -EOVERFLOW if the
- * property data isn't large enough.
+ * Return:
+ *   0 on success, -EINVAL if the property does not exist,
+ *   -ENODATA if property does not have a value, and -EOVERFLOW if the
+ *   property data isn't large enough.
  */
 int of_read_u32_index(const struct device_node *np, const char *propname,
 		      int index, u32 *outp);
@@ -303,9 +304,10 @@
  * @propname:	name of the property to be searched.
  * @outp:	pointer to return value, modified only if return value is 0.
  *
- * @return 0 on success, -EINVAL if the property does not exist,
- * -ENODATA if property does not have a value, and -EOVERFLOW if the
- * property data isn't large enough.
+ * Return:
+ *   0 on success, -EINVAL if the property does not exist,
+ *   -ENODATA if property does not have a value, and -EOVERFLOW if the
+ *   property data isn't large enough.
  */
 int of_read_u64(const struct device_node *np, const char *propname, u64 *outp);
 
@@ -319,8 +321,9 @@
  * @propname:	name of the property to be searched.
  * @out_values:	pointer to return value, modified only if return value is 0.
  * @sz:		number of array elements to read
- * @return 0 on success, -EINVAL if the property does not exist, -ENODATA
- * if property does not have a value, and -EOVERFLOW is longer than sz.
+ * Return:
+ *   0 on success, -EINVAL if the property does not exist, -ENODATA
+ *   if property does not have a value, and -EOVERFLOW is longer than sz.
  */
 int of_read_u32_array(const struct device_node *np, const char *propname,
 		      u32 *out_values, size_t sz);
@@ -334,8 +337,9 @@
  * @np: pointer to node containing string list property
  * @propname: string list property name
  * @string: pointer to string to search for in string list
- * @return 0 on success, -EINVAL if the property does not exist, -ENODATA
- * if property does not have a value, and -EOVERFLOW is longer than sz.
+ * Return:
+ *   0 on success, -EINVAL if the property does not exist, -ENODATA
+ *   if property does not have a value, and -EOVERFLOW is longer than sz.
  */
 int of_property_match_string(const struct device_node *np, const char *propname,
 			     const char *string);
@@ -350,15 +354,17 @@
  * @np:		device node from which the property value is to be read.
  * @propname:	name of the property to be searched.
  * @index:	index of the string in the list of strings
- * @out_string:	pointer to null terminated return string, modified only if
+ * @output:	pointer to null terminated return string, modified only if
  *		return value is 0.
  *
  * Search for a property in a device tree node and retrieve a null
  * terminated string value (pointer to data, not a copy) in the list of strings
  * contained in that property.
- * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
- * property does not have a value, and -EILSEQ if the string is not
- * null-terminated within the length of the property data.
+ *
+ * Return:
+ *   0 on success, -EINVAL if the property does not exist, -ENODATA if
+ *   property does not have a value, and -EILSEQ if the string is not
+ *   null-terminated within the length of the property data.
  *
  * The out_string pointer is modified only if a valid string can be decoded.
  */
@@ -377,10 +383,12 @@
  * @propname:	name of the property to be searched.
  *
  * Search for a property in a device tree node and retrieve the number of null
- * terminated string contain in it. Returns the number of strings on
- * success, -EINVAL if the property does not exist, -ENODATA if property
- * does not have a value, and -EILSEQ if the string is not null-terminated
- * within the length of the property data.
+ * terminated string contain in it.
+ *
+ * Return:
+ *   the number of strings on success, -EINVAL if the property does not exist,
+ *   -ENODATA if property does not have a value, and -EILSEQ if the string is
+ *   not null-terminated within the length of the property data.
  */
 static inline int of_property_count_strings(const struct device_node *np,
 					    const char *propname)
@@ -395,8 +403,9 @@
  * @index: For properties holding a table of phandles, this is the index into
  *         the table
  *
- * Returns the device_node pointer with refcount incremented.  Use
- * of_node_put() on it when done.
+ * Return:
+ *   the device_node pointer with refcount incremented.  Use
+ *   of_node_put() on it when done.
  */
 struct device_node *of_parse_phandle(const struct device_node *np,
 				     const char *phandle_name, int index);
@@ -410,10 +419,11 @@
  * @cells_count: Cell count to use if @cells_name is NULL
  * @index:	index of a phandle to parse out
  * @out_args:	optional pointer to output arguments structure (will be filled)
- * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if
- *	@list_name does not exist, -EINVAL if a phandle was not found,
- *	@cells_name could not be found, the arguments were truncated or there
- *	were too many arguments.
+ * Return:
+ *   0 on success (with @out_args filled out if not NULL), -ENOENT if
+ *   @list_name does not exist, -EINVAL if a phandle was not found,
+ *   @cells_name could not be found, the arguments were truncated or there
+ *   were too many arguments.
  *
  * This function is useful to parse lists of phandles and their arguments.
  * Returns 0 on success and fills out_args, on error returns appropriate
@@ -424,17 +434,17 @@
  *
  * Example:
  *
- * phandle1: node1 {
- *	#list-cells = <2>;
- * }
+ * .. code-block::
  *
- * phandle2: node2 {
- *	#list-cells = <1>;
- * }
- *
- * node3 {
- *	list = <&phandle1 1 2 &phandle2 3>;
- * }
+ *   phandle1: node1 {
+ *       #list-cells = <2>;
+ *   };
+ *   phandle2: node2 {
+ *       #list-cells = <1>;
+ *   };
+ *   node3 {
+ *       list = <&phandle1 1 2 &phandle2 3>;
+ *   };
  *
  * To get a device_node of the `node2' node you may call this:
  * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
@@ -451,14 +461,13 @@
  * @list_name:	property name that contains a list
  * @cells_name:	property name that specifies phandles' arguments count
  * @cells_count: Cell count to use if @cells_name is NULL
- * @return number of phandle found, -ENOENT if
- *	@list_name does not exist, -EINVAL if a phandle was not found,
- *	@cells_name could not be found, the arguments were truncated or there
- *	were too many arguments.
+ * Return:
+ *   number of phandle found, -ENOENT if @list_name does not exist,
+ *   -EINVAL if a phandle was not found, @cells_name could not be found,
+ *   the arguments were truncated or there were too many arguments.
  *
  * Returns number of phandle found on success, on error returns appropriate
  * errno value.
- *
  */
 int of_count_phandle_with_args(const struct device_node *np,
 			       const char *list_name, const char *cells_name,
@@ -471,7 +480,7 @@
  * the lookup table with the properties.  It returns the number of alias
  * properties found, or an error code in case of failure.
  *
- * @return 9 if OK, -ENOMEM if not enough memory
+ * Return: 9 if OK, -ENOMEM if not enough memory
  */
 int of_alias_scan(void);
 
@@ -483,7 +492,7 @@
  *
  * @np:		Pointer to the given device_node
  * @stem:	Alias stem of the given device_node
- * @return alias ID, if found, else -ENODEV
+ * Return: alias ID, if found, else -ENODEV
  */
 int of_alias_get_id(const struct device_node *np, const char *stem);
 
@@ -493,14 +502,14 @@
  *
  * The function travels the lookup table to get the highest alias id for the
  * given alias stem.
- * @return alias ID, if found, else -1
+ * Return: alias ID, if found, else -1
  */
 int of_alias_get_highest_id(const char *stem);
 
 /**
  * of_get_stdout() - Get node to use for stdout
  *
- * @return node referred to by stdout-path alias, or NULL if none
+ * Return: node referred to by stdout-path alias, or NULL if none
  */
 struct device_node *of_get_stdout(void);
 
diff --git a/include/dm/of_addr.h b/include/dm/of_addr.h
index ee21d5c..e7f3a28 100644
--- a/include/dm/of_addr.h
+++ b/include/dm/of_addr.h
@@ -20,11 +20,11 @@
  * that can be mapped to a cpu physical address). This is not really specified
  * that way, but this is traditionally the way IBM at least do things
  *
- * @np: node to check
+ * @np: pointer to node to check
  * @in_addr: pointer to input address
- * @return translated address or OF_BAD_ADDR on error
+ * Return: translated address or OF_BAD_ADDR on error
  */
-u64 of_translate_address(const struct device_node *no, const __be32 *in_addr);
+u64 of_translate_address(const struct device_node *np, const __be32 *in_addr);
 
 /**
  * of_translate_dma_address() - translate a device-tree DMA address to a CPU
@@ -38,11 +38,11 @@
  * that can be mapped to a cpu physical address). This is not really specified
  * that way, but this is traditionally the way IBM at least do things
  *
- * @np: node to check
+ * @np: ne
  * @in_addr: pointer to input DMA address
- * @return translated DMA address or OF_BAD_ADDR on error
+ * Return: translated DMA address or OF_BAD_ADDR on error
  */
-u64 of_translate_dma_address(const struct device_node *no, const __be32 *in_addr);
+u64 of_translate_dma_address(const struct device_node *np, const __be32 *in_addr);
 
 
 /**
@@ -51,14 +51,13 @@
  * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
  * cpu->bus address translations
  *
- * @param blob		Pointer to device tree blob
- * @param node_offset	Node DT offset
- * @param cpu		Pointer to variable storing the range's cpu address
- * @param bus		Pointer to variable storing the range's bus address
- * @param size		Pointer to variable storing the range's size
- * @return translated DMA address or OF_BAD_ADDR on error
+ * @np:		Pointer to device tree blob
+ * @cpu:	Pointer to variable storing the range's cpu address
+ * @bus:	Pointer to variable storing the range's bus address
+ * @size:	Pointer to variable storing the range's size
+ * Return: translated DMA address or OF_BAD_ADDR on error
  */
-int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
+int of_get_dma_range(const struct device_node *np, phys_addr_t *cpu,
 		     dma_addr_t *bus, u64 *size);
 
 /**
@@ -72,9 +71,9 @@
  * @index: Index of address to read (0 = first)
  * @size: place to put size on success
  * @flags: place to put flags on success
- * @return pointer to address which can be read
+ * Return: pointer to address which can be read
  */
-const __be32 *of_get_address(const struct device_node *no, int index,
+const __be32 *of_get_address(const struct device_node *np, int index,
 			     u64 *size, unsigned int *flags);
 
 struct resource;
@@ -90,9 +89,9 @@
  * @np: node to check
  * @index: index of address to read (0 = first)
  * @r: place to put resource information
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
-int of_address_to_resource(const struct device_node *no, int index,
+int of_address_to_resource(const struct device_node *np, int index,
 			   struct resource *r);
 
 #endif
diff --git a/include/dm/of_extra.h b/include/dm/of_extra.h
index c2498aa..17e85a8 100644
--- a/include/dm/of_extra.h
+++ b/include/dm/of_extra.h
@@ -41,11 +41,11 @@
 };
 
 /**
- * Read a flash entry from the fdt
+ * ofnode_read_fmap_entry() - Read a flash entry from the fdt
  *
- * @param node		Reference to node to read
- * @param entry		Place to put offset and size of this node
- * @return 0 if ok, -ve on error
+ * @node:	Reference to node to read
+ * @entry:	Place to put offset and size of this node
+ * Return: 0 if ok, -ve on error
  */
 int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry);
 
@@ -58,11 +58,11 @@
  * The property must hold one address with a length. This is only tested on
  * 32-bit machines.
  *
- * @param node		ofnode to examine
- * @param prop_name	name of property to find
- * @param basep		Returns base address of region
- * @param size		Returns size of region
- * @return 0 if ok, -1 on error (property not found)
+ * @node:	ofnode to examine
+ * @prop_name:	name of property to find
+ * @basep:	Returns base address of region
+ * @sizep:	Returns size of region
+ * Return: 0 if ok, -1 on error (property not found)
  */
 int ofnode_decode_region(ofnode node, const char *prop_name, fdt_addr_t *basep,
 			 fdt_size_t *sizep);
@@ -81,14 +81,14 @@
  * The property value must have an offset and a size. The function checks
  * that the region is entirely within the memory bank.5
  *
- * @param node		ofnode containing the properties (-1 for /config)
- * @param mem_type	Type of memory to use, which is a name, such as
- *			"u-boot" or "kernel".
- * @param suffix	String to append to the memory/offset
- *			property names
- * @param basep		Returns base of region
- * @param sizep		Returns size of region
- * @return 0 if OK, -ive on error
+ * @config_node:	ofnode containing the properties (invalid for "/config")
+ * @mem_type:	Type of memory to use, which is a name, such as
+ *		"u-boot" or "kernel".
+ * @suffix:	String to append to the memory/offset
+ *		property names
+ * @basep:	Returns base of region
+ * @sizep:	Returns size of region
+ * Return: 0 if OK, -ive on error
  */
 int ofnode_decode_memory_region(ofnode config_node, const char *mem_type,
 				const char *suffix, fdt_addr_t *basep,
@@ -102,15 +102,15 @@
  *
  * This function supports the following two DT bindings:
  * - the new DT binding, where 'fixed-link' is a sub-node of the
- *   Ethernet device
+ * Ethernet device
  * - the old DT binding, where 'fixed-link' is a property with 5
- *   cells encoding various information about the fixed PHY
+ * cells encoding various information about the fixed PHY
  *
  * If both new and old bindings exist, the new one is preferred.
  *
- * @param eth_node	ofnode containing the fixed-link subnode/property
- * @param phy_node	if fixed-link PHY detected, containing the PHY ofnode
- * @return true if a fixed-link pseudo-PHY device exists, false otherwise
+ * @eth_node:	ofnode containing the fixed-link subnode/property
+ * @phy_node:	if fixed-link PHY detected, containing the PHY ofnode
+ * Return: true if a fixed-link pseudo-PHY device exists, false otherwise
  */
 bool ofnode_phy_is_fixed_link(ofnode eth_node, ofnode *phy_node);
 
@@ -123,8 +123,8 @@
  * is connected to an on-board PHY or an SFP cage, and is not relevant when it
  * has a fixed link (in that case, in-band autoneg should not be used).
  *
- * @param eth_node	ofnode belonging to the Ethernet controller
- * @return true if in-band autoneg should be used, false otherwise
+ * @eth_node:	ofnode belonging to the Ethernet controller
+ * Return: true if in-band autoneg should be used, false otherwise
  */
 bool ofnode_eth_uses_inband_aneg(ofnode eth_node);
 
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 6601bd8..0cb324c 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -19,7 +19,7 @@
 struct resource;
 
 /**
- * ofnode - reference to a device tree node
+ * typedef union ofnode_union ofnode - reference to a device tree node
  *
  * This union can hold either a straightforward pointer to a struct device_node
  * in the live device tree, or an offset within the flat device tree. In the
@@ -27,7 +27,7 @@
  *
  * Thus we can reference nodes in both the live tree (once available) and the
  * flat tree (until then). Functions are available to translate between an
- * ofnode and either an offset or a struct device_node *.
+ * ofnode and either an offset or a `struct device_node *`.
  *
  * The reference can also hold a null offset, in which case the pointer value
  * here is NULL. This corresponds to a struct device_node * value of
@@ -61,7 +61,7 @@
 };
 
 /**
- * ofprop - reference to a property of a device tree node
+ * struct ofprop - reference to a property of a device tree node
  *
  * This struct hold the reference on one property of one node,
  * using struct ofnode and an offset within the flat device tree or either
@@ -91,7 +91,7 @@
  * This cannot be called if the reference contains an offset.
  *
  * @node: Reference containing struct device_node * (possibly invalid)
- * @return pointer to device node (can be NULL)
+ * Return: pointer to device node (can be NULL)
  */
 static inline const struct device_node *ofnode_to_np(ofnode node)
 {
@@ -108,7 +108,7 @@
  * This cannot be called if the reference contains a node pointer.
  *
  * @node: Reference containing offset (possibly invalid)
- * @return DT offset (can be -1)
+ * Return: DT offset (can be -1)
  */
 static inline int ofnode_to_offset(ofnode node)
 {
@@ -122,7 +122,8 @@
 /**
  * ofnode_valid() - check if an ofnode is valid
  *
- * @return true if the reference contains a valid ofnode, false if it is NULL
+ * @node: Reference containing offset (possibly invalid)
+ * Return: true if the reference contains a valid ofnode, false if it is NULL
  */
 static inline bool ofnode_valid(ofnode node)
 {
@@ -136,7 +137,7 @@
  * offset_to_ofnode() - convert a DT offset to an ofnode
  *
  * @of_offset: DT offset (either valid, or -1)
- * @return reference to the associated DT offset
+ * Return: reference to the associated DT offset
  */
 static inline ofnode offset_to_ofnode(int of_offset)
 {
@@ -154,7 +155,7 @@
  * np_to_ofnode() - convert a node pointer to an ofnode
  *
  * @np: Live node pointer (can be NULL)
- * @return reference to the associated node pointer
+ * Return: reference to the associated node pointer
  */
 static inline ofnode np_to_ofnode(const struct device_node *np)
 {
@@ -173,7 +174,7 @@
  * is valid is not permitted.
  *
  * @node: reference to check (possibly invalid)
- * @return true if the reference is a live node pointer, false if it is a DT
+ * Return: true if the reference is a live node pointer, false if it is a DT
  * offset
  */
 static inline bool ofnode_is_np(ofnode node)
@@ -193,7 +194,9 @@
 /**
  * ofnode_equal() - check if two references are equal
  *
- * @return true if equal, else false
+ * @ref1: first reference to check (possibly invalid)
+ * @ref2: second reference to check (possibly invalid)
+ * Return: true if equal, else false
  */
 static inline bool ofnode_equal(ofnode ref1, ofnode ref2)
 {
@@ -237,28 +240,28 @@
  *
  * @node:	valid node reference that has to be compared
  * @name:	name that has to be compared with the node name
- * @return true if matches, false if it doesn't match
+ * Return: true if matches, false if it doesn't match
  */
 bool ofnode_name_eq(ofnode node, const char *name);
 
 /**
  * ofnode_read_u32() - Read a 32-bit integer from a property
  *
- * @ref:	valid node reference to read property from
+ * @node:	valid node reference to read property from
  * @propname:	name of the property to read from
  * @outp:	place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int ofnode_read_u32(ofnode node, const char *propname, u32 *outp);
 
 /**
  * ofnode_read_u32_index() - Read a 32-bit integer from a multi-value property
  *
- * @ref:	valid node reference to read property from
+ * @node:	valid node reference to read property from
  * @propname:	name of the property to read from
  * @index:	index of the integer to return
  * @outp:	place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int ofnode_read_u32_index(ofnode node, const char *propname, int index,
 			  u32 *outp);
@@ -266,47 +269,47 @@
 /**
  * ofnode_read_s32() - Read a 32-bit integer from a property
  *
- * @ref:	valid node reference to read property from
+ * @node:	valid node reference to read property from
  * @propname:	name of the property to read from
  * @outp:	place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 static inline int ofnode_read_s32(ofnode node, const char *propname,
-				  s32 *out_value)
+				  s32 *outp)
 {
-	return ofnode_read_u32(node, propname, (u32 *)out_value);
+	return ofnode_read_u32(node, propname, (u32 *)outp);
 }
 
 /**
  * ofnode_read_u32_default() - Read a 32-bit integer from a property
  *
- * @ref:	valid node reference to read property from
+ * @node:	valid node reference to read property from
  * @propname:	name of the property to read from
  * @def:	default value to return if the property has no value
- * @return property value, or @def if not found
+ * Return: property value, or @def if not found
  */
-u32 ofnode_read_u32_default(ofnode ref, const char *propname, u32 def);
+u32 ofnode_read_u32_default(ofnode node, const char *propname, u32 def);
 
 /**
  * ofnode_read_u32_index_default() - Read a 32-bit integer from a multi-value
  *                                   property
  *
- * @ref:	valid node reference to read property from
+ * @node:	valid node reference to read property from
  * @propname:	name of the property to read from
  * @index:	index of the integer to return
  * @def:	default value to return if the property has no value
- * @return property value, or @def if not found
+ * Return: property value, or @def if not found
  */
-u32 ofnode_read_u32_index_default(ofnode ref, const char *propname, int index,
+u32 ofnode_read_u32_index_default(ofnode node, const char *propname, int index,
 				  u32 def);
 
 /**
  * ofnode_read_s32_default() - Read a 32-bit integer from a property
  *
- * @ref:	valid node reference to read property from
+ * @node:	valid node reference to read property from
  * @propname:	name of the property to read from
  * @def:	default value to return if the property has no value
- * @return property value, or @def if not found
+ * Return: property value, or @def if not found
  */
 int ofnode_read_s32_default(ofnode node, const char *propname, s32 def);
 
@@ -316,17 +319,17 @@
  * @node:	valid node reference to read property from
  * @propname:	name of the property to read from
  * @outp:	place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int ofnode_read_u64(ofnode node, const char *propname, u64 *outp);
 
 /**
  * ofnode_read_u64_default() - Read a 64-bit integer from a property
  *
- * @ref:	valid node reference to read property from
+ * @node:	valid node reference to read property from
  * @propname:	name of the property to read from
  * @def:	default value to return if the property has no value
- * @return property value, or @def if not found
+ * Return: property value, or @def if not found
  */
 u64 ofnode_read_u64_default(ofnode node, const char *propname, u64 def);
 
@@ -336,8 +339,8 @@
  * @node:	valid node reference to read property from
  * @propname:	name of the property to read
  * @sizep:	if non-NULL, returns the size of the property, or an error code
-		if not found
- * @return property value, or NULL if there is no such property
+ *              if not found
+ * Return: property value, or NULL if there is no such property
  */
 const void *ofnode_read_prop(ofnode node, const char *propname, int *sizep);
 
@@ -346,7 +349,7 @@
  *
  * @node:	valid node reference to read property from
  * @propname:	name of the property to read
- * @return string from property value, or NULL if there is no such property
+ * Return: string from property value, or NULL if there is no such property
  */
 const char *ofnode_read_string(ofnode node, const char *propname);
 
@@ -357,7 +360,7 @@
  * @propname:	name of the property to read
  * @out_values:	pointer to return value, modified only if return value is 0
  * @sz:		number of array elements to read
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  *
  * Search for a property in a device node and read 32-bit value(s) from
  * it. Returns 0 on success, -EINVAL if the property does not exist,
@@ -374,7 +377,7 @@
  *
  * @node:	valid node reference to read property from
  * @propname:	name of property to read
- * @return true if property is present (meaning true), false if not present
+ * Return: true if property is present (meaning true), false if not present
  */
 bool ofnode_read_bool(ofnode node, const char *propname);
 
@@ -383,7 +386,7 @@
  *
  * @node:	valid reference to parent node
  * @subnode_name: name of subnode to find
- * @return reference to subnode (which can be invalid if there is no such
+ * Return: reference to subnode (which can be invalid if there is no such
  * subnode)
  */
 ofnode ofnode_find_subnode(ofnode node, const char *subnode_name);
@@ -429,7 +432,7 @@
  * by default.
  *
  * @node: node to examine
- * @return false (not enabled) or true (enabled)
+ * Return: false (not enabled) or true (enabled)
  */
 bool ofnode_is_enabled(ofnode node);
 
@@ -437,7 +440,7 @@
  * ofnode_first_subnode() - find the first subnode of a parent node
  *
  * @node:	valid reference to a valid parent node
- * @return reference to the first subnode (which can be invalid if the parent
+ * Return: reference to the first subnode (which can be invalid if the parent
  * node has no subnodes)
  */
 ofnode ofnode_first_subnode(ofnode node);
@@ -446,7 +449,7 @@
  * ofnode_next_subnode() - find the next sibling of a subnode
  *
  * @node:	valid reference to previous node (sibling)
- * @return reference to the next subnode (which can be invalid if the node
+ * Return: reference to the next subnode (which can be invalid if the node
  * has no more siblings)
  */
 ofnode ofnode_next_subnode(ofnode node);
@@ -456,7 +459,7 @@
  * ofnode_get_parent() - get the ofnode's parent (enclosing ofnode)
  *
  * @node: valid node to look up
- * @return ofnode reference of the parent node
+ * Return: ofnode reference of the parent node
  */
 ofnode ofnode_get_parent(ofnode node);
 
@@ -464,7 +467,7 @@
  * ofnode_get_name() - get the name of a node
  *
  * @node: valid node to look up
- * @return name of node
+ * Return: name of node
  */
 const char *ofnode_get_name(ofnode node);
 
@@ -474,7 +477,7 @@
  * @node: valid node to look up
  * @buf: buffer to write the node path into
  * @buflen: buffer size
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int ofnode_get_path(ofnode node, char *buf, int buflen);
 
@@ -482,7 +485,7 @@
  * ofnode_get_by_phandle() - get ofnode from phandle
  *
  * @phandle:	phandle to look up
- * @return ofnode reference to the phandle
+ * Return: ofnode reference to the phandle
  */
 ofnode ofnode_get_by_phandle(uint phandle);
 
@@ -491,7 +494,7 @@
  *
  * @node: node to check
  * @propname: property to check
- * @return size of property if present, or -EINVAL if not
+ * Return: size of property if present, or -EINVAL if not
  */
 int ofnode_read_size(ofnode node, const char *propname);
 
@@ -504,7 +507,7 @@
  * @node: node to read from
  * @index: Index of address to read (0 for first)
  * @size: Pointer to size of the address
- * @return address, or FDT_ADDR_T_NONE if not present or invalid
+ * Return: address, or FDT_ADDR_T_NONE if not present or invalid
  */
 phys_addr_t ofnode_get_addr_size_index(ofnode node, int index,
 				       fdt_size_t *size);
@@ -521,7 +524,7 @@
  * @node: node to read from
  * @index: Index of address to read (0 for first)
  * @size: Pointer to size of the address
- * @return address, or FDT_ADDR_T_NONE if not present or invalid
+ * Return: address, or FDT_ADDR_T_NONE if not present or invalid
  */
 phys_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
 					       fdt_size_t *size);
@@ -533,7 +536,7 @@
  *
  * @node: node to read from
  * @index: Index of address to read (0 for first)
- * @return address, or FDT_ADDR_T_NONE if not present or invalid
+ * Return: address, or FDT_ADDR_T_NONE if not present or invalid
  */
 phys_addr_t ofnode_get_addr_index(ofnode node, int index);
 
@@ -543,7 +546,7 @@
  * This reads the register address from a node
  *
  * @node: node to read from
- * @return address, or FDT_ADDR_T_NONE if not present or invalid
+ * Return: address, or FDT_ADDR_T_NONE if not present or invalid
  */
 phys_addr_t ofnode_get_addr(ofnode node);
 
@@ -553,7 +556,7 @@
  * This reads the register size from a node
  *
  * @node: node to read from
- * @return size of the address, or FDT_SIZE_T_NONE if not present or invalid
+ * Return: size of the address, or FDT_SIZE_T_NONE if not present or invalid
  */
 fdt_size_t ofnode_get_size(ofnode node);
 
@@ -570,7 +573,7 @@
  * @propname: name of the property containing the string list
  * @string: string to look up in the string list
  *
- * @return:
+ * Return:
  *   the index of the string in the list of strings
  *   -ENODATA if the property is not found
  *   -EINVAL on some other error
@@ -591,9 +594,9 @@
  * @node: node to check
  * @propname: name of the property containing the string list
  * @index: index of the string to return (cannot be negative)
- * @lenp: return location for the string length or an error code on failure
+ * @outp: return location for the string
  *
- * @return:
+ * Return:
  *   0 if found or -ve error value if not found
  */
 int ofnode_read_string_index(ofnode node, const char *propname, int index,
@@ -603,8 +606,8 @@
  * ofnode_read_string_count() - find the number of strings in a string list
  *
  * @node: node to check
- * @propname: name of the property containing the string list
- * @return:
+ * @property: name of the property containing the string list
+ * Return:
  *   number of strings in the list, or -ve error value if not found
  */
 int ofnode_read_string_count(ofnode node, const char *property);
@@ -620,11 +623,12 @@
  * changed as they point directly into the devicetree property.
  *
  * @node: node to check
+ * @property: name of the property containing the string list
  * @listp: returns an allocated, NULL-terminated list of strings if the return
  *	value is > 0, else is set to NULL
- * @return number of strings in list, 0 if none, -ENOMEM if out of memory,
- *	-EINVAL if no such property, -EENODATA if property is empty
- * @return: NULL-terminated list of strings (NULL if no property or empty)
+ * Return:
+ * number of strings in list, 0 if none, -ENOMEM if out of memory,
+ * -EINVAL if no such property, -EENODATA if property is empty
  */
 int ofnode_read_string_list(ofnode node, const char *property,
 			    const char ***listp);
@@ -641,17 +645,17 @@
  *
  * Example:
  *
- * phandle1: node1 {
- *	#list-cells = <2>;
- * }
+ * .. code-block::
  *
- * phandle2: node2 {
- *	#list-cells = <1>;
- * }
- *
- * node3 {
- *	list = <&phandle1 1 2 &phandle2 3>;
- * }
+ *   phandle1: node1 {
+ *       #list-cells = <2>;
+ *   };
+ *   phandle2: node2 {
+ *       #list-cells = <1>;
+ *   };
+ *   node3 {
+ *       list = <&phandle1 1 2 &phandle2 3>;
+ *   };
  *
  * To get a device_node of the `node2' node you may call this:
  * ofnode_parse_phandle_with_args(node3, "list", "#list-cells", 0, 1, &args);
@@ -659,13 +663,14 @@
  * @node:	device tree node containing a list
  * @list_name:	property name that contains a list
  * @cells_name:	property name that specifies phandles' arguments count
- * @cells_count: Cell count to use if @cells_name is NULL
+ * @cell_count: Cell count to use if @cells_name is NULL
  * @index:	index of a phandle to parse out
  * @out_args:	optional pointer to output arguments structure (will be filled)
- * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if
- *	@list_name does not exist, -EINVAL if a phandle was not found,
- *	@cells_name could not be found, the arguments were truncated or there
- *	were too many arguments.
+ * Return:
+ *   0 on success (with @out_args filled out if not NULL), -ENOENT if
+ *   @list_name does not exist, -EINVAL if a phandle was not found,
+ *   @cells_name could not be found, the arguments were truncated or there
+ *   were too many arguments.
  */
 int ofnode_parse_phandle_with_args(ofnode node, const char *list_name,
 				   const char *cells_name, int cell_count,
@@ -682,10 +687,10 @@
  * @node:	device tree node containing a list
  * @list_name:	property name that contains a list
  * @cells_name:	property name that specifies phandles' arguments count
- * @cells_count: Cell count to use if @cells_name is NULL
- * @return number of phandle on success, -ENOENT if @list_name does not
- *      exist, -EINVAL if a phandle was not found, @cells_name could not
- *      be found.
+ * @cell_count: Cell count to use if @cells_name is NULL
+ * Return:
+ *   number of phandle on success, -ENOENT if @list_name does not exist,
+ *   -EINVAL if a phandle was not found, @cells_name could not be found.
  */
 int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
 				   const char *cells_name, int cell_count);
@@ -694,7 +699,7 @@
  * ofnode_path() - find a node by full path
  *
  * @path: Full path to node, e.g. "/bus/spi@1"
- * @return reference to the node found. Use ofnode_valid() to check if it exists
+ * Return: reference to the node found. Use ofnode_valid() to check if it exists
  */
 ofnode ofnode_path(const char *path);
 
@@ -704,9 +709,9 @@
  * This looks for a property within the /chosen node and returns its value
  *
  * @propname: Property name to look for
- * @sizep: Returns size of property, or FDT_ERR_... error code if function
+ * @sizep: Returns size of property, or  `FDT_ERR_...` error code if function
  *	returns NULL
- * @return property value if found, else NULL
+ * Return: property value if found, else NULL
  */
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep);
 
@@ -717,7 +722,7 @@
  * checking that it is a valid nul-terminated string
  *
  * @propname: Property name to look for
- * @return string value if found, else NULL
+ * Return: string value if found, else NULL
  */
 const char *ofnode_read_chosen_string(const char *propname);
 
@@ -727,7 +732,8 @@
  * This looks up a named property in the chosen node and uses that as a path to
  * look up a code.
  *
- * @return the referenced node if present, else ofnode_null()
+ * @propname: Property name to look for
+ * Return: the referenced node if present, else ofnode_null()
  */
 ofnode ofnode_get_chosen_node(const char *propname);
 
@@ -737,9 +743,9 @@
  * This looks for a property within the /aliases node and returns its value
  *
  * @propname: Property name to look for
- * @sizep: Returns size of property, or FDT_ERR_... error code if function
+ * @sizep: Returns size of property, or `FDT_ERR_...` error code if function
  *	returns NULL
- * @return property value if found, else NULL
+ * Return: property value if found, else NULL
  */
 const void *ofnode_read_aliases_prop(const char *propname, int *sizep);
 
@@ -749,7 +755,8 @@
  * This looks up a named property in the aliases node and uses that as a path to
  * look up a code.
  *
- * @return the referenced node if present, else ofnode_null()
+ * @propname: Property name to look for
+ * Return: the referenced node if present, else ofnode_null()
  */
 ofnode ofnode_get_aliases_node(const char *propname);
 
@@ -761,10 +768,10 @@
  * See doc/device-tree-bindings/video/display-timing.txt for binding
  * information.
  *
- * @node	'display-timing' node containing the timing subnodes
- * @index	Index number to read (0=first timing subnode)
- * @config	Place to put timings
- * @return 0 if OK, -FDT_ERR_NOTFOUND if not found
+ * @node:	'display-timing' node containing the timing subnodes
+ * @index:	Index number to read (0=first timing subnode)
+ * @config:	Place to put timings
+ * Return: 0 if OK, -FDT_ERR_NOTFOUND if not found
  */
 int ofnode_decode_display_timing(ofnode node, int index,
 				 struct display_timing *config);
@@ -775,7 +782,7 @@
  * @node: node to read
  * @propname: property to read
  * @lenp: place to put length on success
- * @return pointer to property, or NULL if not found
+ * Return: pointer to property, or NULL if not found
  */
 const void *ofnode_get_property(ofnode node, const char *propname, int *lenp);
 
@@ -787,7 +794,7 @@
  *
  * @node: node to read
  * @prop: place to put argument reference
- * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
  */
 int ofnode_get_first_property(ofnode node, struct ofprop *prop);
 
@@ -798,7 +805,7 @@
  * and read all the property with ofnode_get_property_by_prop().
  *
  * @prop: reference of current argument and place to put reference of next one
- * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
  */
 int ofnode_get_next_property(struct ofprop *prop);
 
@@ -810,7 +817,7 @@
  * @prop: reference on property
  * @propname: If non-NULL, place to property name on success,
  * @lenp: If non-NULL, place to put length on success
- * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
  */
 const void *ofnode_get_property_by_prop(const struct ofprop *prop,
 					const char **propname, int *lenp);
@@ -819,7 +826,7 @@
  * ofnode_is_available() - check if a node is marked available
  *
  * @node: node to check
- * @return true if node's 'status' property is "okay" (or is missing)
+ * Return: true if node's 'status' property is "okay" (or is missing)
  */
 bool ofnode_is_available(ofnode node);
 
@@ -832,7 +839,7 @@
  * @node: node to read from
  * @propname: property to read
  * @sizep: place to put size value (on success)
- * @return address value, or FDT_ADDR_T_NONE on error
+ * Return: address value, or FDT_ADDR_T_NONE on error
  */
 phys_addr_t ofnode_get_addr_size(ofnode node, const char *propname,
 				 phys_size_t *sizep);
@@ -845,11 +852,12 @@
  * for the array (count bytes). It may have more, but this will be ignored.
  * The data is not copied.
  *
- * @node	node to examine
- * @propname	name of property to find
- * @sz		number of array elements
- * @return pointer to byte array if found, or NULL if the property is not
- *		found or there is not enough data
+ * @node:	node to examine
+ * @propname:	name of property to find
+ * @sz:		number of array elements
+ * Return:
+ * pointer to byte array if found, or NULL if the property is not found or
+ * there is not enough data
  */
 const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
 					size_t sz);
@@ -861,13 +869,14 @@
  * corresponds to the given type in the form of fdt_pci_addr.
  * The property must hold one fdt_pci_addr with a lengh.
  *
- * @node	node to examine
- * @type	pci address type (FDT_PCI_SPACE_xxx)
- * @propname	name of property to find
- * @addr	returns pci address in the form of fdt_pci_addr
- * @return 0 if ok, -ENOENT if the property did not exist, -EINVAL if the
- *		format of the property was invalid, -ENXIO if the requested
- *		address type was not found
+ * @node:	node to examine
+ * @type:	pci address type (FDT_PCI_SPACE_xxx)
+ * @propname:	name of property to find
+ * @addr:	returns pci address in the form of fdt_pci_addr
+ * Return:
+ * 0 if ok, -ENOENT if the property did not exist, -EINVAL if the
+ * format of the property was invalid, -ENXIO if the requested
+ * address type was not found
  */
 int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
 			 const char *propname, struct fdt_pci_addr *addr);
@@ -878,10 +887,10 @@
  * Look at the compatible property of a device node that represents a PCI
  * device and extract pci vendor id and device id from it.
  *
- * @param node		node to examine
- * @param vendor	vendor id of the pci device
- * @param device	device id of the pci device
- * @return 0 if ok, negative on error
+ * @node:	node to examine
+ * @vendor:	vendor id of the pci device
+ * @device:	device id of the pci device
+ * Return: 0 if ok, negative on error
  */
 int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device);
 
@@ -892,7 +901,7 @@
  * which controls the given node.
  *
  * @node: Node to check
- * @return number of address cells this node uses
+ * Return: number of address cells this node uses
  */
 int ofnode_read_addr_cells(ofnode node);
 
@@ -903,7 +912,7 @@
  * which controls the given node.
  *
  * @node: Node to check
- * @return number of size cells this node uses
+ * Return: number of size cells this node uses
  */
 int ofnode_read_size_cells(ofnode node);
 
@@ -912,8 +921,8 @@
  *
  * This function matches fdt_address_cells().
  *
- * @np: Node pointer to check
- * @return value of #address-cells property in this node, or 2 if none
+ * @node: Node to check
+ * Return: value of #address-cells property in this node, or 2 if none
  */
 int ofnode_read_simple_addr_cells(ofnode node);
 
@@ -922,8 +931,8 @@
  *
  * This function matches fdt_size_cells().
  *
- * @np: Node pointer to check
- * @return value of #size-cells property in this node, or 2 if none
+ * @node: Node to check
+ * Return: value of #size-cells property in this node, or 2 if none
  */
 int ofnode_read_simple_size_cells(ofnode node);
 
@@ -942,14 +951,13 @@
  * There are 4 settings currently in use
  * - u-boot,dm-pre-proper: U-Boot proper pre-relocation only
  * - u-boot,dm-pre-reloc: legacy and indicates any of TPL or SPL
- *   Existing platforms only use it to indicate nodes needed in
- *   SPL. Should probably be replaced by u-boot,dm-spl for
- *   new platforms.
+ * Existing platforms only use it to indicate nodes needed in
+ * SPL. Should probably be replaced by u-boot,dm-spl for new platforms.
  * - u-boot,dm-spl: SPL and U-Boot pre-relocation
  * - u-boot,dm-tpl: TPL and U-Boot pre-relocation
  *
  * @node: node to check
- * @return true if node is needed in SPL/TL, false otherwise
+ * Return: true if node is needed in SPL/TL, false otherwise
  */
 bool ofnode_pre_reloc(ofnode node);
 
@@ -961,7 +969,7 @@
  * @node: Node to read from
  * @index: Index of resource to read (0 = first)
  * @res: Returns resource that was read, on success
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int ofnode_read_resource(ofnode node, uint index, struct resource *res);
 
@@ -975,7 +983,7 @@
  * @node: Node to read from
  * @name: Name of resource to read
  * @res: Returns resource that was read, on success
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int ofnode_read_resource_byname(ofnode node, const char *name,
 				struct resource *res);
@@ -987,7 +995,7 @@
  *
  * @from: ofnode to start from (use ofnode_null() to start at the beginning)
  * @compat: Compatible string to match
- * @return ofnode found, or ofnode_null() if none
+ * Return: ofnode found, or ofnode_null() if none
  */
 ofnode ofnode_by_compatible(ofnode from, const char *compat);
 
@@ -998,9 +1006,11 @@
  * @propval and a length @proplen.
  *
  * @from: ofnode to start from (use ofnode_null() to start at the
- * beginning) @propname: property name to check @propval: property value to
- * search for @proplen: length of the value in propval @return ofnode
- * found, or ofnode_null() if none
+ * beginning)
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ * Return: ofnode found, or ofnode_null() if none
  */
 ofnode ofnode_by_prop_value(ofnode from, const char *propname,
 			    const void *propval, int proplen);
@@ -1011,14 +1021,13 @@
  * @node:       child node (ofnode, lvalue)
  * @parent:     parent node (ofnode)
  *
- * This is a wrapper around a for loop and is used like so:
+ * This is a wrapper around a for loop and is used like so::
  *
- *	ofnode node;
- *
- *	ofnode_for_each_subnode(node, parent) {
- *		Use node
- *		...
- *	}
+ *   ofnode node;
+ *   ofnode_for_each_subnode(node, parent) {
+ *       Use node
+ *       ...
+ *   }
  *
  * Note that this is implemented as a macro and @node is used as
  * iterator in the loop. The parent variable can be a constant or even a
@@ -1036,14 +1045,13 @@
  * @node:       child node (ofnode, lvalue)
  * @compat:     compatible string to match
  *
- * This is a wrapper around a for loop and is used like so:
+ * This is a wrapper around a for loop and is used like so::
  *
- *	ofnode node;
- *
- *	ofnode_for_each_compatible_node(node, parent, compatible) {
- *		Use node
- *		...
- *	}
+ *   ofnode node;
+ *   ofnode_for_each_compatible_node(node, parent, compatible) {
+ *      Use node
+ *      ...
+ *   }
  *
  * Note that this is implemented as a macro and @node is used as
  * iterator in the loop.
@@ -1056,8 +1064,8 @@
 /**
  * ofnode_get_child_count() - get the child count of a ofnode
  *
- * @node: valid node to get its child count
- * @return the number of subnodes
+ * @parent: valid node to get its child count
+ * Return: the number of subnodes
  */
 int ofnode_get_child_count(ofnode parent);
 
@@ -1068,10 +1076,9 @@
  * function walks up the tree and applies the various bus mappings along the
  * way.
  *
- * @ofnode: Device tree node giving the context in which to translate the
- *          address
+ * @node: Device tree node giving the context in which to translate the address
  * @in_addr: pointer to the address to translate
- * @return the translated address; OF_BAD_ADDR on error
+ * Return: the translated address; OF_BAD_ADDR on error
  */
 u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr);
 
@@ -1082,10 +1089,10 @@
  * This function walks up the tree and applies the various bus mappings along
  * the way.
  *
- * @ofnode: Device tree node giving the context in which to translate the
- *          DMA address
+ * @node: Device tree node giving the context in which to translate the
+ *        DMA address
  * @in_addr: pointer to the DMA address to translate
- * @return the translated DMA address; OF_BAD_ADDR on error
+ * Return: the translated DMA address; OF_BAD_ADDR on error
  */
 u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr);
 
@@ -1095,12 +1102,11 @@
  * Get DMA ranges for a specifc node, this is useful to perform bus->cpu and
  * cpu->bus address translations
  *
- * @param blob		Pointer to device tree blob
- * @param node_offset	Node DT offset
- * @param cpu		Pointer to variable storing the range's cpu address
- * @param bus		Pointer to variable storing the range's bus address
- * @param size		Pointer to variable storing the range's size
- * @return translated DMA address or OF_BAD_ADDR on error
+ * @node: Device tree node
+ * @cpu: Pointer to variable storing the range's cpu address
+ * @bus: Pointer to variable storing the range's bus address
+ * @size: Pointer to variable storing the range's size
+ * Return: translated DMA address or OF_BAD_ADDR on error
  */
 int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus,
 			 u64 *size);
@@ -1112,7 +1118,7 @@
  *
  * @node:	Device tree node for which compatible needs to be verified.
  * @compat:	Compatible string which needs to verified in the given node.
- * @return true if OK, false if the compatible is not found
+ * Return: true if OK, false if the compatible is not found
  */
 int ofnode_device_is_compatible(ofnode node, const char *compat);
 
@@ -1127,7 +1133,7 @@
  * @len:	The length of the new value of the property
  * @value:	The new value of the property (must be valid prior to calling
  *		the function)
- * @return 0 if successful, -ve on error
+ * Return: 0 if successful, -ve on error
  */
 int ofnode_write_prop(ofnode node, const char *propname, int len,
 		      const void *value);
@@ -1142,7 +1148,7 @@
  * @propname:	The name of the string property to set
  * @value:	The new value of the string property (must be valid prior to
  *		calling the function)
- * @return 0 if successful, -ve on error
+ * Return: 0 if successful, -ve on error
  */
 int ofnode_write_string(ofnode node, const char *propname, const char *value);
 
@@ -1157,7 +1163,7 @@
  * @node:	The node to enable
  * @value:	Flag that tells the function to either disable or enable the
  *		node
- * @return 0 if successful, -ve on error
+ * Return: 0 if successful, -ve on error
  */
 int ofnode_set_enabled(ofnode node, bool value);
 
@@ -1168,8 +1174,8 @@
  *
  * See doc/config.txt for bindings
  *
- * @prop_name	property name to look up
- * @return true, if it exists, false if not
+ * @prop_name:	property name to look up
+ * Return: true, if it exists, false if not
  */
 bool ofnode_conf_read_bool(const char *prop_name);
 
@@ -1182,7 +1188,7 @@
  *
  * @prop_name: property name to look up
  * @default_val: default value to return if the property is not found
- * @return integer value, if found, or @default_val if not
+ * Return: integer value, if found, or @default_val if not
  */
 int ofnode_conf_read_int(const char *prop_name, int default_val);
 
@@ -1194,7 +1200,7 @@
  * See doc/config.txt for bindings
  *
  * @prop_name: property name to look up
- * @return string value, if found, or NULL if not
+ * Return: string value, if found, or NULL if not
  */
 const char *ofnode_conf_read_str(const char *prop_name);
 
diff --git a/include/dm/platdata.h b/include/dm/platdata.h
index 4efb1df..47ba8aa 100644
--- a/include/dm/platdata.h
+++ b/include/dm/platdata.h
@@ -40,7 +40,7 @@
 #endif
 
 /**
- * driver_rt - runtime information set up by U-Boot
+ * struct driver_rt - runtime information set up by U-Boot
  *
  * There is one of these for every driver_info in the linker list, indexed by
  * the driver_info idx value.
@@ -51,7 +51,7 @@
 	struct udevice *dev;
 };
 
-/**
+/*
  * NOTE: Avoid using these except in extreme circumstances, where device tree
  * is not feasible (e.g. serial driver in SPL where <8KB of SRAM is
  * available). U-Boot's driver model uses device tree for configuration.
diff --git a/include/dm/read.h b/include/dm/read.h
index 75c6ad6..233af3c 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -37,7 +37,7 @@
  * @dev:	device to read DT property from
  * @propname:	name of the property to read from
  * @outp:	place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dev_read_u32(const struct udevice *dev, const char *propname, u32 *outp);
 
@@ -47,7 +47,7 @@
  * @dev:	device to read DT property from
  * @propname:	name of the property to read from
  * @def:	default value to return if the property has no value
- * @return property value, or @def if not found
+ * Return: property value, or @def if not found
  */
 int dev_read_u32_default(const struct udevice *dev, const char *propname,
 			 int def);
@@ -60,7 +60,7 @@
  * @propname:	name of the property to read from
  * @index:	index of the integer to return
  * @outp:	place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dev_read_u32_index(struct udevice *dev, const char *propname, int index,
 		       u32 *outp);
@@ -73,7 +73,7 @@
  * @propname:	name of the property to read from
  * @index:	index of the integer to return
  * @def:	default value to return if the property has no value
- * @return property value, or @def if not found
+ * Return: property value, or @def if not found
  */
 u32 dev_read_u32_index_default(struct udevice *dev, const char *propname,
 			       int index, u32 def);
@@ -84,7 +84,7 @@
  * @dev:	device to read DT property from
  * @propname:	name of the property to read from
  * @outp:	place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dev_read_s32(const struct udevice *dev, const char *propname, s32 *outp);
 
@@ -94,7 +94,7 @@
  * @dev:	device to read DT property from
  * @propname:	name of the property to read from
  * @def:	default value to return if the property has no value
- * @return property value, or @def if not found
+ * Return: property value, or @def if not found
  */
 int dev_read_s32_default(const struct udevice *dev, const char *propname,
 			 int def);
@@ -107,7 +107,7 @@
  * @dev:	device to read DT property from
  * @propname:	name of the property to read from
  * @outp:	place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dev_read_u32u(const struct udevice *dev, const char *propname, uint *outp);
 
@@ -117,7 +117,7 @@
  * @dev:        device to read DT property from
  * @propname:   name of the property to read from
  * @outp:       place to put value (if found)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dev_read_u64(const struct udevice *dev, const char *propname, u64 *outp);
 
@@ -127,7 +127,7 @@
  * @dev:        device to read DT property from
  * @propname:   name of the property to read from
  * @def:        default value to return if the property has no value
- * @return property value, or @def if not found
+ * Return: property value, or @def if not found
  */
 u64 dev_read_u64_default(const struct udevice *dev, const char *propname,
 			 u64 def);
@@ -137,7 +137,7 @@
  *
  * @dev:	device to read DT property from
  * @propname:	name of the property to read
- * @return string from property value, or NULL if there is no such property
+ * Return: string from property value, or NULL if there is no such property
  */
 const char *dev_read_string(const struct udevice *dev, const char *propname);
 
@@ -146,7 +146,7 @@
  *
  * @dev:	device to read DT property from
  * @propname:	name of property to read
- * @return true if property is present (meaning true), false if not present
+ * Return: true if property is present (meaning true), false if not present
  */
 bool dev_read_bool(const struct udevice *dev, const char *propname);
 
@@ -155,17 +155,17 @@
  *
  * @dev:	device whose DT node contains the subnode
  * @subnode_name: name of subnode to find
- * @return reference to subnode (which can be invalid if there is no such
+ * Return: reference to subnode (which can be invalid if there is no such
  * subnode)
  */
-ofnode dev_read_subnode(const struct udevice *dev, const char *subbnode_name);
+ofnode dev_read_subnode(const struct udevice *dev, const char *subnode_name);
 
 /**
  * dev_read_size() - read the size of a property
  *
  * @dev: device to check
  * @propname: property to check
- * @return size of property if present, or -EINVAL if not
+ * Return: size of property if present, or -EINVAL if not
  */
 int dev_read_size(const struct udevice *dev, const char *propname);
 
@@ -176,7 +176,7 @@
  * @index: the 'reg' property can hold a list of <addr, size> pairs
  *	   and @index is used to select which one is required
  *
- * @return address or FDT_ADDR_T_NONE if not found
+ * Return: address or FDT_ADDR_T_NONE if not found
  */
 fdt_addr_t dev_read_addr_index(const struct udevice *dev, int index);
 
@@ -188,7 +188,7 @@
  * @index: the 'reg' property can hold a list of <addr, size> pairs
  *	   and @index is used to select which one is required
  *
- * @return pointer or NULL if not found
+ * Return: pointer or NULL if not found
  */
 void *dev_read_addr_index_ptr(const struct udevice *dev, int index);
 
@@ -200,7 +200,7 @@
  *	   and @index is used to select which one is required
  * @size: place to put size value (on success)
  *
- * @return address or FDT_ADDR_T_NONE if not found
+ * Return: address or FDT_ADDR_T_NONE if not found
  */
 fdt_addr_t dev_read_addr_size_index(const struct udevice *dev, int index,
 				    fdt_size_t *size);
@@ -213,7 +213,7 @@
  * @index: the 'reg' property can hold a list of <addr, size> pairs
  *	   and @index is used to select which one is required
  *
- * @return pointer or NULL if not found
+ * Return: pointer or NULL if not found
  */
 void *dev_remap_addr_index(const struct udevice *dev, int index);
 
@@ -225,7 +225,7 @@
  *	  'reg-names' property providing named-based identification. @index
  *	  indicates the value to search for in 'reg-names'.
  *
- * @return address or FDT_ADDR_T_NONE if not found
+ * Return: address or FDT_ADDR_T_NONE if not found
  */
 fdt_addr_t dev_read_addr_name(const struct udevice *dev, const char *name);
 
@@ -238,7 +238,7 @@
  *	  indicates the value to search for in 'reg-names'.
  *  @size: place to put size value (on success)
  *
- * @return address or FDT_ADDR_T_NONE if not found
+ * Return: address or FDT_ADDR_T_NONE if not found
  */
 fdt_addr_t dev_read_addr_size_name(const struct udevice *dev, const char *name,
 				   fdt_size_t *size);
@@ -252,7 +252,7 @@
  *	  'reg-names' property providing named-based identification. @index
  *	  indicates the value to search for in 'reg-names'.
  *
- * @return pointer or NULL if not found
+ * Return: pointer or NULL if not found
  */
 void *dev_remap_addr_name(const struct udevice *dev, const char *name);
 
@@ -261,7 +261,7 @@
  *
  * @dev: Device to read from
  *
- * @return address or FDT_ADDR_T_NONE if not found
+ * Return: address or FDT_ADDR_T_NONE if not found
  */
 fdt_addr_t dev_read_addr(const struct udevice *dev);
 
@@ -271,7 +271,7 @@
  *
  * @dev: Device to read from
  *
- * @return pointer or NULL if not found
+ * Return: pointer or NULL if not found
  */
 void *dev_read_addr_ptr(const struct udevice *dev);
 
@@ -291,7 +291,7 @@
  *    fdtdec_get_addr() and friends.
  *
  * @dev: Device to read from
- * @return address or FDT_ADDR_T_NONE if not found
+ * Return: address or FDT_ADDR_T_NONE if not found
  */
 fdt_addr_t dev_read_addr_pci(const struct udevice *dev);
 
@@ -301,7 +301,7 @@
  *
  * @dev: Device to read from
  *
- * @return pointer or NULL if not found
+ * Return: pointer or NULL if not found
  */
 void *dev_remap_addr(const struct udevice *dev);
 
@@ -314,7 +314,7 @@
  * @dev: Device to read from
  * @propname: property to read
  * @sizep: place to put size value (on success)
- * @return address value, or FDT_ADDR_T_NONE on error
+ * Return: address value, or FDT_ADDR_T_NONE on error
  */
 fdt_addr_t dev_read_addr_size(const struct udevice *dev, const char *propname,
 			      fdt_size_t *sizep);
@@ -323,7 +323,7 @@
  * dev_read_name() - get the name of a device's node
  *
  * @dev: Device to read from
- * @return name of node
+ * Return: name of node
  */
 const char *dev_read_name(const struct udevice *dev);
 
@@ -340,12 +340,12 @@
  * @propname: name of the property containing the string list
  * @string: string to look up in the string list
  *
- * @return:
+ * Return:
  *   the index of the string in the list of strings
  *   -ENODATA if the property is not found
  *   -EINVAL on some other error
  */
-int dev_read_stringlist_search(const struct udevice *dev, const char *property,
+int dev_read_stringlist_search(const struct udevice *dev, const char *propname,
 			       const char *string);
 
 /**
@@ -354,9 +354,9 @@
  * @dev: device to examine
  * @propname: name of the property containing the string list
  * @index: index of the string to return
- * @out: return location for the string
+ * @outp: return location for the string
  *
- * @return:
+ * Return:
  *   length of string, if found or -ve error value if not found
  */
 int dev_read_string_index(const struct udevice *dev, const char *propname,
@@ -367,7 +367,7 @@
  *
  * @dev: device to examine
  * @propname: name of the property containing the string list
- * @return:
+ * Return:
  *   number of strings in the list, or -ve error value if not found
  */
 int dev_read_string_count(const struct udevice *dev, const char *propname);
@@ -386,8 +386,9 @@
  * @propname: name of the property containing the string list
  * @listp: returns an allocated, NULL-terminated list of strings if the return
  *	value is > 0, else is set to NULL
- * @return number of strings in list, 0 if none, -ENOMEM if out of memory,
- *	-ENOENT if no such property
+ * Return:
+ * number of strings in list, 0 if none, -ENOMEM if out of memory,
+ * -ENOENT if no such property
  */
 int dev_read_string_list(const struct udevice *dev, const char *propname,
 			 const char ***listp);
@@ -404,17 +405,17 @@
  *
  * Example:
  *
- * phandle1: node1 {
- *	#list-cells = <2>;
- * }
+ * .. code-block::
  *
- * phandle2: node2 {
- *	#list-cells = <1>;
- * }
- *
- * node3 {
- *	list = <&phandle1 1 2 &phandle2 3>;
- * }
+ *   phandle1: node1 {
+ *       #list-cells = <2>;
+ *   };
+ *   phandle2: node2 {
+ *       #list-cells = <1>;
+ *   };
+ *   node3 {
+ *       list = <&phandle1 1 2 &phandle2 3>;
+ *   };
  *
  * To get a device_node of the `node2' node you may call this:
  * dev_read_phandle_with_args(dev, "list", "#list-cells", 0, 1, &args);
@@ -422,10 +423,10 @@
  * @dev:	device whose node containing a list
  * @list_name:	property name that contains a list
  * @cells_name:	property name that specifies phandles' arguments count
- * @cells_count: Cell count to use if @cells_name is NULL
+ * @cell_count: Cell count to use if @cells_name is NULL
  * @index:	index of a phandle to parse out
  * @out_args:	optional pointer to output arguments structure (will be filled)
- * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if
+ * Return: 0 on success (with @out_args filled out if not NULL), -ENOENT if
  *	@list_name does not exist, -EINVAL if a phandle was not found,
  *	@cells_name could not be found, the arguments were truncated or there
  *	were too many arguments.
@@ -441,12 +442,11 @@
  * For example, this allows to allocate the right amount of memory to keep
  * clock's reference contained into the "clocks" property.
  *
- *
  * @dev:	device whose node containing a list
  * @list_name:	property name that contains a list
  * @cells_name:	property name that specifies phandles' arguments count
- * @cells_count: Cell count to use if @cells_name is NULL
- * @Returns number of phandle found on success, on error returns appropriate
+ * @cell_count: Cell count to use if @cells_name is NULL
+ * Return: number of phandle found on success, on error returns appropriate
  * errno value.
  */
 
@@ -461,7 +461,7 @@
  * which controls the given node.
  *
  * @dev: device to check
- * @return number of address cells this node uses
+ * Return: number of address cells this node uses
  */
 int dev_read_addr_cells(const struct udevice *dev);
 
@@ -472,7 +472,7 @@
  * which controls the given node.
  *
  * @dev: device to check
- * @return number of size cells this node uses
+ * Return: number of size cells this node uses
  */
 int dev_read_size_cells(const struct udevice *dev);
 
@@ -482,7 +482,7 @@
  * This function matches fdt_address_cells().
  *
  * @dev: device to check
- * @return number of address cells this node uses
+ * Return: number of address cells this node uses
  */
 int dev_read_simple_addr_cells(const struct udevice *dev);
 
@@ -492,7 +492,7 @@
  * This function matches fdt_size_cells().
  *
  * @dev: device to check
- * @return number of size cells this node uses
+ * Return: number of size cells this node uses
  */
 int dev_read_simple_size_cells(const struct udevice *dev);
 
@@ -500,7 +500,7 @@
  * dev_read_phandle() - Get the phandle from a device
  *
  * @dev: device to check
- * @return phandle (1 or greater), or 0 if no phandle or other error
+ * Return: phandle (1 or greater), or 0 if no phandle or other error
  */
 int dev_read_phandle(const struct udevice *dev);
 
@@ -510,7 +510,7 @@
  * @dev: device to check
  * @propname: property to read
  * @lenp: place to put length on success
- * @return pointer to property, or NULL if not found
+ * Return: pointer to property, or NULL if not found
  */
 const void *dev_read_prop(const struct udevice *dev, const char *propname,
 			  int *lenp);
@@ -523,7 +523,7 @@
  *
  * @dev: device to check
  * @prop: place to put argument reference
- * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
  */
 int dev_read_first_prop(const struct udevice *dev, struct ofprop *prop);
 
@@ -534,7 +534,7 @@
  * and read all the property with dev_read_prop_by_prop().
  *
  * @prop: reference of current argument and place to put reference of next one
- * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
  */
 int dev_read_next_prop(struct ofprop *prop);
 
@@ -546,7 +546,7 @@
  * @prop: reference on property
  * @propname: If non-NULL, place to property name on success,
  * @lenp: If non-NULL, place to put length on success
- * @return 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
+ * Return: 0 if OK, -ve on error. -FDT_ERR_NOTFOUND if not found
  */
 const void *dev_read_prop_by_prop(struct ofprop *prop,
 				  const char **propname, int *lenp);
@@ -560,7 +560,7 @@
  *
  * @dev: device to look up
  * @devnump: set to the sequence number if one is found
- * @return 0 if a sequence was found, -ve if not
+ * Return: 0 if a sequence was found, -ve if not
  */
 int dev_read_alias_seq(const struct udevice *dev, int *devnump);
 
@@ -576,7 +576,7 @@
  * @propname:	name of the property to read
  * @out_values:	pointer to return value, modified only if return value is 0
  * @sz:		number of array elements to read
- * @return 0 on success, -EINVAL if the property does not exist, -ENODATA if
+ * Return: 0 on success, -EINVAL if the property does not exist, -ENODATA if
  * property does not have a value, and -EOVERFLOW if the property data isn't
  * large enough.
  */
@@ -587,7 +587,7 @@
  * dev_read_first_subnode() - find the first subnode of a device's node
  *
  * @dev: device to look up
- * @return reference to the first subnode (which can be invalid if the device's
+ * Return: reference to the first subnode (which can be invalid if the device's
  * node has no subnodes)
  */
 ofnode dev_read_first_subnode(const struct udevice *dev);
@@ -596,7 +596,7 @@
  * ofnode_next_subnode() - find the next sibling of a subnode
  *
  * @node:	valid reference to previous node (sibling)
- * @return reference to the next subnode (which can be invalid if the node
+ * Return: reference to the next subnode (which can be invalid if the node
  * has no more siblings)
  */
 ofnode dev_read_next_subnode(ofnode node);
@@ -612,8 +612,9 @@
  * @dev: device to look up
  * @propname: name of property to find
  * @sz: number of array elements
- * @return pointer to byte array if found, or NULL if the property is not
- *		found or there is not enough data
+ * Return:
+ * pointer to byte array if found, or NULL if the property is not found or
+ * there is not enough data
  */
 const uint8_t *dev_read_u8_array_ptr(const struct udevice *dev,
 				     const char *propname, size_t sz);
@@ -627,7 +628,7 @@
  * by default.
  *
  * @dev: device to examine
- * @return integer value 0 (not enabled) or 1 (enabled)
+ * Return: integer value 0 (not enabled) or 1 (enabled)
  */
 int dev_read_enabled(const struct udevice *dev);
 
@@ -635,9 +636,9 @@
  * dev_read_resource() - obtain an indexed resource from a device.
  *
  * @dev: device to examine
- * @index index of the resource to retrieve (0 = first)
- * @res returns the resource
- * @return 0 if ok, negative on error
+ * @index: index of the resource to retrieve (0 = first)
+ * @res: returns the resource
+ * Return: 0 if ok, negative on error
  */
 int dev_read_resource(const struct udevice *dev, uint index,
 		      struct resource *res);
@@ -648,7 +649,7 @@
  * @dev: device to examine
  * @name: name of the resource to retrieve
  * @res: returns the resource
- * @return 0 if ok, negative on error
+ * Return: 0 if ok, negative on error
  */
 int dev_read_resource_byname(const struct udevice *dev, const char *name,
 			     struct resource *res);
@@ -662,7 +663,7 @@
  *
  * @dev: device giving the context in which to translate the address
  * @in_addr: pointer to the address to translate
- * @return the translated address; OF_BAD_ADDR on error
+ * Return: the translated address; OF_BAD_ADDR on error
  */
 u64 dev_translate_address(const struct udevice *dev, const fdt32_t *in_addr);
 
@@ -675,7 +676,7 @@
  *
  * @dev: device giving the context in which to translate the DMA address
  * @in_addr: pointer to the DMA address to translate
- * @return the translated DMA address; OF_BAD_ADDR on error
+ * Return: the translated DMA address; OF_BAD_ADDR on error
  */
 u64 dev_translate_dma_address(const struct udevice *dev,
 			      const fdt32_t *in_addr);
@@ -690,7 +691,7 @@
  * @cpu: base address for CPU's view of memory
  * @bus: base address for BUS's view of memory
  * @size: size of the address space
- * @return 0 if ok, negative on error
+ * Return: 0 if ok, negative on error
  */
 int dev_get_dma_range(const struct udevice *dev, phys_addr_t *cpu,
 		      dma_addr_t *bus, u64 *size);
@@ -701,15 +702,15 @@
  *
  * The function travels the lookup table to get the highest alias id for the
  * given alias stem.
- * @return alias ID, if found, else -1
+ * Return: alias ID, if found, else -1
  */
 int dev_read_alias_highest_id(const char *stem);
 
 /**
  * dev_get_child_count() - get the child count of a device
  *
- * @dev: device to use for interation (struct udevice *)
- * @return the count of child subnode
+ * @dev: device to use for interation (`struct udevice *`)
+ * Return: the count of child subnode
  */
 int dev_get_child_count(const struct udevice *dev);
 
@@ -720,8 +721,8 @@
  * range for this node.
  *
  * @dev: device to examine
- * @res returns the resource
- * @return 0 if ok, negative on error
+ * @res: returns the resource
+ * Return: 0 if ok, negative on error
  */
 int dev_read_pci_bus_range(const struct udevice *dev, struct resource *res);
 
@@ -737,7 +738,7 @@
  *       one or more display timing nodes.
  * @index: index number to read (0=first timing subnode)
  * @config: place to put timings
- * @return 0 if OK, -FDT_ERR_NOTFOUND if not found
+ * Return: 0 if OK, -FDT_ERR_NOTFOUND if not found
  */
 int dev_decode_display_timing(const struct udevice *dev, int index,
 			      struct display_timing *config);
@@ -1100,7 +1101,7 @@
  * device-tree node.
  *
  * @subnode: ofnode holding the current subnode
- * @dev: device to use for interation (struct udevice *)
+ * @dev: device to use for interation (`struct udevice *`)
  */
 #define dev_for_each_subnode(subnode, dev) \
 	for (subnode = dev_read_first_subnode(dev); \
@@ -1114,7 +1115,7 @@
  * device-tree node.
  *
  * @prop: struct ofprop holding the current property
- * @dev: device to use for interation (struct udevice *)
+ * @dev: device to use for interation (`struct udevice *`)
  */
 #define dev_for_each_property(prop, dev) \
 	for (int ret_prop = dev_read_first_prop(dev, &prop); \
diff --git a/include/dm/root.h b/include/dm/root.h
index 780f269..e888fb9 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -19,7 +19,7 @@
  *
  * This function returns pointer to the root node of the driver tree,
  *
- * @return pointer to root device, or NULL if not inited yet
+ * Return: pointer to root device, or NULL if not inited yet
  */
 struct udevice *dm_root(void);
 
@@ -27,6 +27,8 @@
 /**
  * dm_fixup_for_gd_move() - Handle global_data moving to a new place
  *
+ * @new_gd: Pointer to the new global data
+ *
  * The uclass list is part of global_data. Due to the way lists work, moving
  * the list will cause it to become invalid. This function fixes that up so
  * that the uclass list will work correctly.
@@ -40,7 +42,7 @@
  *
  * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC
  * flag. If false bind all drivers.
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_scan_plat(bool pre_reloc_only);
 
@@ -52,7 +54,7 @@
  *
  * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
  * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_scan_fdt(bool pre_reloc_only);
 
@@ -65,7 +67,7 @@
  *
  * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
  * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_extended_scan(bool pre_reloc_only);
 
@@ -79,7 +81,7 @@
  *
  * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
  * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_scan_other(bool pre_reloc_only);
 
@@ -92,7 +94,7 @@
  *
  * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
  * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_init_and_scan(bool pre_reloc_only);
 
@@ -103,7 +105,7 @@
  * This needs to be called before anything uses the DM
  *
  * @of_live:	Enable live device tree
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_init(bool of_live);
 
@@ -111,7 +113,7 @@
  * dm_uninit - Uninitialise Driver Model structures
  *
  * All devices will be removed and unbound
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_uninit(void);
 
@@ -124,7 +126,7 @@
  * All devices with the matching flags set will be removed
  *
  * @flags: Flags for selective device removal
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int dm_remove_devices_flags(uint flags);
 #else
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index f1fd2ba..7f33c34 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -84,7 +84,7 @@
  * its children. If non-zero this is the size of this data, to be allocated
  * in the child device's parent_plat pointer. This value is only used as
  * a fallback if this member is 0 in the driver.
- * @flags: Flags for this uclass (DM_UC_...)
+ * @flags: Flags for this uclass ``(DM_UC_...)``
  */
 struct uclass_driver {
 	const char *name;
@@ -127,17 +127,16 @@
  * build time. Before this is used, an extern UCLASS_DRIVER() must have been
  * declared.
  *
- * For example:
+ * For example::
  *
- * extern UCLASS_DRIVER(clk);
- *
- * struct uclass_driver *drvs[] = {
- *	DM_UCLASS_DRIVER_REF(clk),
- * };
+ *   extern UCLASS_DRIVER(clk);
+ *   struct uclass_driver *drvs[] = {
+ *       DM_UCLASS_DRIVER_REF(clk),
+ *   };
  *
  * @_name: Name of the uclass_driver. This must be a valid C identifier, used by
  *	the linker_list.
- * @returns struct uclass_driver * for the uclass driver
+ * Return: struct uclass_driver * for the uclass driver
  */
 #define DM_UCLASS_DRIVER_REF(_name)					\
 	ll_entry_ref(struct uclass_driver, _name, uclass_driver)
@@ -145,8 +144,8 @@
 /**
  * uclass_get_priv() - Get the private data for a uclass
  *
- * @uc		Uclass to check
- * @return private data, or NULL if none
+ * @uc:	Uclass to check
+ * Return: private data, or NULL if none
  */
 void *uclass_get_priv(const struct uclass *uc);
 
@@ -159,8 +158,9 @@
  *
  * @key: ID to look up
  * @ucp: Returns pointer to uclass (there is only one per ID)
- * @return 0 if OK, -EDEADLK if driver model is not yet inited, other -ve on
- *	other error
+ * Return:
+ * 0 if OK, -EDEADLK if driver model is not yet inited,
+ * other -ve on other error
  */
 int uclass_get(enum uclass_id key, struct uclass **ucp);
 
@@ -168,16 +168,16 @@
  * uclass_get_name() - Get the name of a uclass driver
  *
  * @id: ID to look up
- * @returns the name of the uclass driver for that ID, or NULL if none
+ * Return: the name of the uclass driver for that ID, or NULL if none
  */
 const char *uclass_get_name(enum uclass_id id);
 
 /**
- * uclass_get_by_name() - Look up a uclass by its driver name
+ * uclass_get_by_name_len() - Look up a uclass by its partial driver name
  *
  * @name: Name to look up
- * @len: Length of name
- * @returns the associated uclass ID, or UCLASS_INVALID if not found
+ * @len: Length of the partial name
+ * Return: the associated uclass ID, or UCLASS_INVALID if not found
  */
 enum uclass_id uclass_get_by_name_len(const char *name, int len);
 
@@ -185,7 +185,7 @@
  * uclass_get_by_name() - Look up a uclass by its driver name
  *
  * @name: Name to look up
- * @returns the associated uclass ID, or UCLASS_INVALID if not found
+ * Return: the associated uclass ID, or UCLASS_INVALID if not found
  */
 enum uclass_id uclass_get_by_name(const char *name);
 
@@ -197,7 +197,7 @@
  * @id: ID to look up
  * @index: Device number within that uclass (0=first)
  * @devp: Returns pointer to device (there is only one per for each ID)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int uclass_get_device(enum uclass_id id, int index, struct udevice **devp);
 
@@ -211,7 +211,7 @@
  * @id: ID to look up
  * @name: name of a device to get
  * @devp: Returns pointer to device (the first one with the name)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int uclass_get_device_by_name(enum uclass_id id, const char *name,
 			      struct udevice **devp);
@@ -228,7 +228,7 @@
  * @id: ID to look up
  * @seq: Sequence number to find (0=first)
  * @devp: Returns pointer to device (there is only one for each seq)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp);
 
@@ -243,7 +243,7 @@
  * @id: ID to look up
  * @node: Device tree offset to search for (if -ve then -ENODEV is returned)
  * @devp: Returns pointer to device (there is only one for each node)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int uclass_get_device_by_of_offset(enum uclass_id id, int node,
 				   struct udevice **devp);
@@ -257,9 +257,9 @@
  * The device is probed to activate it ready for use.
  *
  * @id: ID to look up
- * @np: Device tree node to search for (if NULL then -ENODEV is returned)
+ * @node: Device tree node to search for (if NULL then -ENODEV is returned)
  * @devp: Returns pointer to device (there is only one for each node)
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
 				struct udevice **devp);
@@ -271,12 +271,13 @@
  *
  * The device is probed to activate it ready for use.
  *
- * @id: uclass ID to look up
+ * @id:		uclass ID to look up
  * @phandle_id: the phandle id to look up
- * @devp: Returns pointer to device (there is only one for each node). NULL if
- *	there is no such device.
- * @return 0 if OK, -ENODEV if there is no device match the phandle, other
- *	-ve on error
+ * @devp:	Returns pointer to device (there is only one for each node).
+ *		NULL if there is no such device.
+ * Return:
+ * 0 if OK, -ENODEV if there is no device match the phandle,
+ * other -ve on error
  */
 int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
 				    struct udevice **devp);
@@ -292,8 +293,8 @@
  * @parent: Parent device containing the phandle pointer
  * @name: Name of property in the parent device node
  * @devp: Returns pointer to device (there is only one for each node)
- * @return 0 if OK, -ENOENT if there is no @name present in the node, other
- *	-ve on error
+ * Return: 0 if OK, -ENOENT if there is no @name present in the node, other
+ * -ve on error
  */
 int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
 				 const char *name, struct udevice **devp);
@@ -310,7 +311,7 @@
  * @id: ID to look up
  * @drv: Driver to look for
  * @devp: Returns pointer to the first device with that driver
- * @return 0 if OK, -ve on error
+ * Return: 0 if OK, -ve on error
  */
 int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv,
 				struct udevice **devp);
@@ -327,7 +328,7 @@
  * @devp: Returns pointer to the first device in that uclass if no error
  * occurred, or NULL if there is no first device, or an error occurred with
  * that device.
- * @return 0 if OK (found or not found), other -ve on error
+ * Return: 0 if OK (found or not found), other -ve on error
  */
 int uclass_first_device(enum uclass_id id, struct udevice **devp);
 
@@ -338,7 +339,7 @@
  *
  * @id: Uclass ID to look up
  * @devp: Returns pointer to the first device in that uclass, or NULL if none
- * @return 0 if found, -ENODEV if not found, other -ve on error
+ * Return: 0 if found, -ENODEV if not found, other -ve on error
  */
 int uclass_first_device_err(enum uclass_id id, struct udevice **devp);
 
@@ -353,7 +354,7 @@
  * @devp: On entry, pointer to device to lookup. On exit, returns pointer
  * to the next device in the uclass if no error occurred, or NULL if there is
  * no next device, or an error occurred with that next device.
- * @return 0 if OK (found or not found), other -ve on error
+ * Return: 0 if OK (found or not found), other -ve on error
  */
 int uclass_next_device(struct udevice **devp);
 
@@ -365,7 +366,7 @@
  * @devp: On entry, pointer to device to lookup. On exit, returns pointer
  * to the next device in the uclass if no error occurred, or NULL if
  * there is no next device.
- * @return 0 if found, -ENODEV if not found, other -ve on error
+ * Return: 0 if found, -ENODEV if not found, other -ve on error
  */
 int uclass_next_device_err(struct udevice **devp);
 
@@ -380,7 +381,7 @@
  * @id: Uclass ID to look up
  * @devp: Returns pointer to the first device in that uclass, or NULL if there
  * is no first device
- * @return 0 if OK (found or not found), other -ve on error. If an error occurs
+ * Return: 0 if OK (found or not found), other -ve on error. If an error occurs
  * it is still possible to move to the next device.
  */
 int uclass_first_device_check(enum uclass_id id, struct udevice **devp);
@@ -395,7 +396,7 @@
  *
  * @devp: On entry, pointer to device to lookup. On exit, returns pointer
  * to the next device in the uclass if any
- * @return 0 if OK (found or not found), other -ve on error. If an error occurs
+ * Return: 0 if OK (found or not found), other -ve on error. If an error occurs
  * it is still possible to move to the next device.
  */
 int uclass_next_device_check(struct udevice **devp);
@@ -409,7 +410,7 @@
  * @id: Uclass ID to check
  * @driver_data: Driver data to search for
  * @devp: Returns pointer to the first matching device in that uclass, if found
- * @return 0 if found, -ENODEV if not found, other -ve on error
+ * Return: 0 if found, -ENODEV if not found, other -ve on error
  */
 int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
 				struct udevice **devp);
@@ -421,7 +422,7 @@
  * looking for its ID.
  *
  * @id: uclass ID to look up
- * @return 0 if OK, other -ve on error
+ * Return: 0 if OK, other -ve on error
  */
 int uclass_probe_all(enum uclass_id id);
 
@@ -429,7 +430,7 @@
  * uclass_id_count() - Count the number of devices in a uclass
  *
  * @id: uclass ID to look up
- * @return number of devices in that uclass (0 if none)
+ * Return: number of devices in that uclass (0 if none)
  */
 int uclass_id_count(enum uclass_id id);
 
@@ -444,7 +445,7 @@
  * @id: enum uclass_id ID to use
  * @pos: struct udevice * to hold the current device. Set to NULL when there
  * are no more devices.
- * @uc: temporary uclass variable (struct uclass *)
+ * @uc: temporary uclass variable (``struct uclass *``)
  */
 #define uclass_id_foreach_dev(id, pos, uc) \
 	if (!uclass_get(id, &uc)) \
diff --git a/include/dt-bindings/net/ti-dp83869.h b/include/dt-bindings/net/ti-dp83869.h
new file mode 100644
index 0000000..b3a5ac4
--- /dev/null
+++ b/include/dt-bindings/net/ti-dp83869.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * TI DP83869 PHY drivers
+ *
+ */
+
+#ifndef _DT_BINDINGS_TI_DP83869_H
+#define _DT_BINDINGS_TI_DP83869_H
+
+/* PHY CTRL bits */
+#define DP83869_PHYCR_FIFO_DEPTH_3_B_NIB	0x00
+#define DP83869_PHYCR_FIFO_DEPTH_4_B_NIB	0x01
+#define DP83869_PHYCR_FIFO_DEPTH_6_B_NIB	0x02
+#define DP83869_PHYCR_FIFO_DEPTH_8_B_NIB	0x03
+
+/* RGMIIDCTL internal delay for rx and tx */
+#define DP83869_RGMIIDCTL_250_PS	0x0
+#define DP83869_RGMIIDCTL_500_PS	0x1
+#define DP83869_RGMIIDCTL_750_PS	0x2
+#define DP83869_RGMIIDCTL_1_NS		0x3
+#define DP83869_RGMIIDCTL_1_25_NS	0x4
+#define DP83869_RGMIIDCTL_1_50_NS	0x5
+#define DP83869_RGMIIDCTL_1_75_NS	0x6
+#define DP83869_RGMIIDCTL_2_00_NS	0x7
+#define DP83869_RGMIIDCTL_2_25_NS	0x8
+#define DP83869_RGMIIDCTL_2_50_NS	0x9
+#define DP83869_RGMIIDCTL_2_75_NS	0xa
+#define DP83869_RGMIIDCTL_3_00_NS	0xb
+#define DP83869_RGMIIDCTL_3_25_NS	0xc
+#define DP83869_RGMIIDCTL_3_50_NS	0xd
+#define DP83869_RGMIIDCTL_3_75_NS	0xe
+#define DP83869_RGMIIDCTL_4_00_NS	0xf
+
+/* IO_MUX_CFG - Clock output selection */
+#define DP83869_CLK_O_SEL_CHN_A_RCLK		0x0
+#define DP83869_CLK_O_SEL_CHN_B_RCLK		0x1
+#define DP83869_CLK_O_SEL_CHN_C_RCLK		0x2
+#define DP83869_CLK_O_SEL_CHN_D_RCLK		0x3
+#define DP83869_CLK_O_SEL_CHN_A_RCLK_DIV5	0x4
+#define DP83869_CLK_O_SEL_CHN_B_RCLK_DIV5	0x5
+#define DP83869_CLK_O_SEL_CHN_C_RCLK_DIV5	0x6
+#define DP83869_CLK_O_SEL_CHN_D_RCLK_DIV5	0x7
+#define DP83869_CLK_O_SEL_CHN_A_TCLK		0x8
+#define DP83869_CLK_O_SEL_CHN_B_TCLK		0x9
+#define DP83869_CLK_O_SEL_CHN_C_TCLK		0xA
+#define DP83869_CLK_O_SEL_CHN_D_TCLK		0xB
+#define DP83869_CLK_O_SEL_REF_CLK		0xC
+/* Special flag to indicate clock should be off */
+#define DP83869_CLK_O_SEL_OFF			0xFFFFFFFF
+
+/* OPMODE - Operation mode */
+#define DP83869_RGMII_COPPER_ETHERNET		0x00
+#define DP83869_RGMII_1000_BASE			0x01
+#define DP83869_RGMII_100_BASE			0x02
+#define DP83869_RGMII_SGMII_BRIDGE		0x03
+#define DP83869_1000M_MEDIA_CONVERT		0x04
+#define DP83869_100M_MEDIA_CONVERT		0x05
+#define DP83869_SGMII_COPPER_ETHERNET		0x06
+
+#endif
diff --git a/include/efi.h b/include/efi.h
index 877a2e5..6159f34 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -395,9 +395,9 @@
 };
 
 static inline struct efi_mem_desc *efi_get_next_mem_desc(
-		struct efi_entry_memmap *map, struct efi_mem_desc *desc)
+		struct efi_mem_desc *desc, int desc_size)
 {
-	return (struct efi_mem_desc *)((ulong)desc + map->desc_size);
+	return (struct efi_mem_desc *)((ulong)desc + desc_size);
 }
 
 /**
@@ -407,6 +407,12 @@
  * @sys_table: Pointer to system table
  * @boot: Pointer to boot-services table
  * @run: Pointer to runtime-services table
+ * @memmap_key: Key returned from get_memory_map()
+ * @memmap_desc: List of memory-map records
+ * @memmap_alloc: Amount of memory allocated for memory map list
+ * @memmap_size Size of memory-map list in bytes
+ * @memmap_desc_size: Size of an individual memory-map record, in bytes
+ * @memmap_version: Memory-map version
  *
  * @use_pool_for_malloc: true if all allocation should go through the EFI 'pool'
  *	methods allocate_pool() and free_pool(); false to use 'pages' methods
@@ -424,6 +430,12 @@
 	struct efi_system_table *sys_table;
 	struct efi_boot_services *boot;
 	struct efi_runtime_services *run;
+	efi_uintn_t memmap_key;
+	struct efi_mem_desc *memmap_desc;
+	efi_uintn_t memmap_alloc;
+	efi_uintn_t memmap_size;
+	efi_uintn_t memmap_desc_size;
+	u32 memmap_version;
 
 	/* app: */
 	bool use_pool_for_malloc;
@@ -498,14 +510,14 @@
 /**
  * efi_get_sys_table() - Get access to the main EFI system table
  *
- * @return pointer to EFI system table
+ * Returns: pointer to EFI system table
  */
 struct efi_system_table *efi_get_sys_table(void);
 
 /**
  * efi_get_boot() - Get access to the EFI boot services table
  *
- * @return pointer to EFI boot services table
+ * Returns: pointer to EFI boot services table
  */
 struct efi_boot_services *efi_get_boot(void);
 
@@ -514,7 +526,7 @@
  *
  * This is used when U-Boot is built as an EFI application.
  *
- * @return the base of RAM as known to U-Boot
+ * Returns: the base of RAM as known to U-Boot
  */
 unsigned long efi_get_ram_base(void);
 
@@ -525,6 +537,7 @@
  * @banner:	Banner to display when starting
  * @image:	The image handle passed to efi_main()
  * @sys_table:	The EFI system table pointer passed to efi_main()
+ * Return: 0 on succcess, EFI error code on failure
  */
 int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image,
 	     struct efi_system_table *sys_table);
@@ -535,7 +548,7 @@
  * @priv:	Pointer to private EFI structure
  * @size:	Number of bytes to allocate
  * @retp:	Return EFI status result
- * @return pointer to memory allocated, or NULL on error
+ * Returns: pointer to memory allocated, or NULL on error
  */
 void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp);
 
@@ -572,10 +585,45 @@
  *
  * @type:	Entry type to search for
  * @datap:	Returns pointer to entry data
- * @sizep:	Returns pointer to entry size
- * @return 0 if OK, -ENODATA if there is no table, -ENOENT if there is no entry
+ * @sizep:	Returns entry size
+ * Return: 0 if OK, -ENODATA if there is no table, -ENOENT if there is no entry
  * of the requested type, -EPROTONOSUPPORT if the table has the wrong version
  */
 int efi_info_get(enum efi_entry_t type, void **datap, int *sizep);
 
+/**
+ * efi_store_memory_map() - Collect the memory-map info from EFI
+ *
+ * Collect the memory info and store it for later use, e.g. in calling
+ * exit_boot_services()
+ *
+ * @priv:	Pointer to private EFI structure
+ * Returns: 0 if OK, non-zero on error
+ */
+int efi_store_memory_map(struct efi_priv *priv);
+
+/**
+ * efi_call_exit_boot_services() - Handle the exit-boot-service procedure
+ *
+ * Tell EFI we don't want their boot services anymore
+ *
+ * Return: 0 if OK, non-zero on error
+ */
+int efi_call_exit_boot_services(void);
+
+/**
+ * efi_get_mmap() - Get the memory map from EFI
+ *
+ * This is used in the app. The caller must free *@descp when done
+ *
+ * @descp:	Returns allocated pointer to EFI memory map table
+ * @sizep:	Returns size of table in bytes
+ * @keyp:	Returns memory-map key
+ * @desc_sizep:	Returns size of each @desc_base record
+ * @versionp:	Returns version number of memory map
+ * Returns: 0 on success, -ve on error
+ */
+int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp,
+		 int *desc_sizep, uint *versionp);
+
 #endif /* _LINUX_EFI_H */
diff --git a/include/efi_loader.h b/include/efi_loader.h
index f4860e8..f20d361 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -517,6 +517,8 @@
 					void **address);
 /* Carve out DT reserved memory ranges */
 void efi_carve_out_dt_rsv(void *fdt);
+/* Purge unused kaslr-seed */
+void efi_try_purge_kaslr_seed(void *fdt);
 /* Called by bootefi to make console interface available */
 efi_status_t efi_console_register(void);
 /* Called by bootefi to make all disk storage accessible as EFI objects */
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 09525ce..15f2d2b 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -49,12 +49,6 @@
 
 struct bd_info;
 
-#ifdef CONFIG_SPL_BUILD
-#define SPL_BUILD	1
-#else
-#define SPL_BUILD	0
-#endif
-
 /**
  * enum fdt_source_t - indicates where the devicetree came from
  *
diff --git a/include/fsl_memac.h b/include/fsl_memac.h
index d067f15..6ac1e55 100644
--- a/include/fsl_memac.h
+++ b/include/fsl_memac.h
@@ -254,7 +254,6 @@
 #define MDIO_CTL_READ		(1 << 15)
 
 #define MDIO_DATA(x)		(x & 0xffff)
-#define MDIO_DATA_BSY		(1 << 31)
 
 struct fsl_enet_mac;
 
diff --git a/include/linux/stddef.h b/include/linux/stddef.h
index c540f61..a7f546f 100644
--- a/include/linux/stddef.h
+++ b/include/linux/stddef.h
@@ -1,6 +1,8 @@
 #ifndef _LINUX_STDDEF_H
 #define _LINUX_STDDEF_H
 
+#include <linux/compiler_types.h>
+
 #undef NULL
 #if defined(__cplusplus)
 #define NULL 0
@@ -14,7 +16,11 @@
 
 #ifndef __CHECKER__
 #undef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#ifdef __compiler_offsetof
+#define offsetof(TYPE, MEMBER)	__compiler_offsetof(TYPE, MEMBER)
+#else
+#define offsetof(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)
+#endif
 #endif
 
 #endif
diff --git a/include/os.h b/include/os.h
index 4cbcbd9..10e198c 100644
--- a/include/os.h
+++ b/include/os.h
@@ -266,7 +266,7 @@
  * @size:	size of file is returned if no error
  * Return:	0 on success or -1 if an error ocurred
  */
-int os_get_filesize(const char *fname, loff_t *size);
+int os_get_filesize(const char *fname, long long *size);
 
 /**
  * os_putc() - write a character to the controlling OS terminal
diff --git a/include/part.h b/include/part.h
index b66b07a..b8d8e1f 100644
--- a/include/part.h
+++ b/include/part.h
@@ -50,7 +50,7 @@
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
-#define MAX_SEARCH_PARTITIONS 64
+#define MAX_SEARCH_PARTITIONS 128
 
 #define PART_BOOTABLE			((int)BIT(0))
 #define PART_EFI_SYSTEM_PARTITION	((int)BIT(1))
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/efi/efi.c b/lib/efi/efi.c
index cd6bf47..aa42f18 100644
--- a/lib/efi/efi.c
+++ b/lib/efi/efi.c
@@ -135,3 +135,75 @@
 
 	boot->free_pool(ptr);
 }
+
+int efi_store_memory_map(struct efi_priv *priv)
+{
+	struct efi_boot_services *boot = priv->sys_table->boottime;
+	efi_uintn_t size, desc_size;
+	efi_status_t ret;
+
+	/* Get the memory map so we can switch off EFI */
+	size = 0;
+	ret = boot->get_memory_map(&size, NULL, &priv->memmap_key,
+				   &priv->memmap_desc_size,
+				   &priv->memmap_version);
+	if (ret != EFI_BUFFER_TOO_SMALL) {
+		/*
+		 * Note this function avoids using printf() since it is not
+		 * available in the stub
+		 */
+		printhex2(EFI_BITS_PER_LONG);
+		putc(' ');
+		printhex2(ret);
+		puts(" No memory map\n");
+		return ret;
+	}
+	/*
+	 * Since doing a malloc() may change the memory map and also we want to
+	 * be able to read the memory map in efi_call_exit_boot_services()
+	 * below, after more changes have happened
+	 */
+	priv->memmap_alloc = size + 1024;
+	priv->memmap_size = priv->memmap_alloc;
+	priv->memmap_desc = efi_malloc(priv, size, &ret);
+	if (!priv->memmap_desc) {
+		printhex2(ret);
+		puts(" No memory for memory descriptor\n");
+		return ret;
+	}
+
+	ret = boot->get_memory_map(&priv->memmap_size, priv->memmap_desc,
+				   &priv->memmap_key, &desc_size,
+				   &priv->memmap_version);
+	if (ret) {
+		printhex2(ret);
+		puts(" Can't get memory map\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+int efi_call_exit_boot_services(void)
+{
+	struct efi_priv *priv = efi_get_priv();
+	const struct efi_boot_services *boot = priv->boot;
+	efi_uintn_t size;
+	u32 version;
+	efi_status_t ret;
+
+	size = priv->memmap_alloc;
+	ret = boot->get_memory_map(&size, priv->memmap_desc,
+				   &priv->memmap_key,
+				   &priv->memmap_desc_size, &version);
+	if (ret) {
+		printhex2(ret);
+		puts(" Can't get memory map\n");
+		return ret;
+	}
+	ret = boot->exit_boot_services(priv->parent_image, priv->memmap_key);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c
index d60f2f6..6980933 100644
--- a/lib/efi/efi_app.c
+++ b/lib/efi/efi_app.c
@@ -32,6 +32,39 @@
 	return -ENOSYS;
 }
 
+int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp,
+		 int *desc_sizep, uint *versionp)
+{
+	struct efi_priv *priv = efi_get_priv();
+	struct efi_boot_services *boot = priv->sys_table->boottime;
+	efi_uintn_t size, desc_size, key;
+	struct efi_mem_desc *desc;
+	efi_status_t ret;
+	u32 version;
+
+	/* Get the memory map so we can switch off EFI */
+	size = 0;
+	ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version);
+	if (ret != EFI_BUFFER_TOO_SMALL)
+		return log_msg_ret("get", -ENOMEM);
+
+	desc = malloc(size);
+	if (!desc)
+		return log_msg_ret("mem", -ENOMEM);
+
+	ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version);
+	if (ret)
+		return log_msg_ret("get", -EINVAL);
+
+	*descp = desc;
+	*sizep = size;
+	*desc_sizep = desc_size;
+	*versionp = version;
+	*keyp = key;
+
+	return 0;
+}
+
 /**
  * efi_bind_block() - bind a new block device to an EFI device
  *
@@ -321,6 +354,15 @@
 		return ret;
 	}
 
+	/*
+	 * We could store the EFI memory map here, but it changes all the time,
+	 * so this is only useful for debugging.
+	 *
+	 * ret = efi_store_memory_map(priv);
+	 * if (ret)
+	 *	return ret;
+	 */
+
 	printf("starting\n");
 
 	board_init_f(GD_FLG_SKIP_RELOC);
diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c
index c89ae7c..646cde3 100644
--- a/lib/efi/efi_stub.c
+++ b/lib/efi/efi_stub.c
@@ -304,15 +304,12 @@
 {
 	struct efi_priv local_priv, *priv = &local_priv;
 	struct efi_boot_services *boot = sys_table->boottime;
-	struct efi_mem_desc *desc;
 	struct efi_entry_memmap map;
 	struct efi_gop *gop;
 	struct efi_entry_gopmode mode;
 	struct efi_entry_systable table;
 	efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
-	efi_uintn_t key, desc_size, size;
 	efi_status_t ret;
-	u32 version;
 	int cs32;
 
 	ret = efi_init(priv, "Payload", image, sys_table);
@@ -327,24 +324,11 @@
 	if (cs32 < 0)
 		return EFI_UNSUPPORTED;
 
-	/* Get the memory map so we can switch off EFI */
-	size = 0;
-	ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version);
-	if (ret != EFI_BUFFER_TOO_SMALL) {
-		printhex2(EFI_BITS_PER_LONG);
-		putc(' ');
-		printhex2(ret);
-		puts(" No memory map\n");
+	ret = efi_store_memory_map(priv);
+	if (ret)
 		return ret;
-	}
-	size += 1024;	/* Since doing a malloc() may change the memory map! */
-	desc = efi_malloc(priv, size, &ret);
-	if (!desc) {
-		printhex2(ret);
-		puts(" No memory for memory descriptor\n");
-		return ret;
-	}
-	ret = setup_info_table(priv, size + 128);
+
+	ret = setup_info_table(priv, priv->memmap_size + 128);
 	if (ret)
 		return ret;
 
@@ -360,48 +344,20 @@
 			       sizeof(struct efi_gop_mode_info));
 	}
 
-	ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version);
-	if (ret) {
-		printhex2(ret);
-		puts(" Can't get memory map\n");
-		return ret;
-	}
-
 	table.sys_table = (ulong)sys_table;
 	add_entry_addr(priv, EFIET_SYS_TABLE, &table, sizeof(table), NULL, 0);
 
-	ret = boot->exit_boot_services(image, key);
-	if (ret) {
-		/*
-		 * Unfortunately it happens that we cannot exit boot services
-		 * the first time. But the second time it work. I don't know
-		 * why but this seems to be a repeatable problem. To get
-		 * around it, just try again.
-		 */
-		printhex2(ret);
-		puts(" Can't exit boot services\n");
-		size = sizeof(desc);
-		ret = boot->get_memory_map(&size, desc, &key, &desc_size,
-					   &version);
-		if (ret) {
-			printhex2(ret);
-			puts(" Can't get memory map\n");
-			return ret;
-		}
-		ret = boot->exit_boot_services(image, key);
-		if (ret) {
-			printhex2(ret);
-			puts(" Can't exit boot services 2\n");
-			return ret;
-		}
-	}
+	ret = efi_call_exit_boot_services();
+	if (ret)
+		return ret;
 
 	/* The EFI UART won't work now, switch to a debug one */
 	use_uart = true;
 
-	map.version = version;
-	map.desc_size = desc_size;
-	add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), desc, size);
+	map.version = priv->memmap_version;
+	map.desc_size = priv->memmap_desc_size;
+	add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map),
+		       priv->memmap_desc, priv->memmap_size);
 	add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0);
 
 	memcpy((void *)CONFIG_SYS_TEXT_BASE, _binary_u_boot_bin_start,
diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c
index b6fe5d2..d3923e5 100644
--- a/lib/efi_loader/efi_dt_fixup.c
+++ b/lib/efi_loader/efi_dt_fixup.c
@@ -8,6 +8,7 @@
 #include <common.h>
 #include <efi_dt_fixup.h>
 #include <efi_loader.h>
+#include <efi_rng.h>
 #include <fdtdec.h>
 #include <mapmem.h>
 
@@ -41,6 +42,38 @@
 }
 
 /**
+ * efi_try_purge_kaslr_seed() - Remove unused kaslr-seed
+ *
+ * Kernel's EFI STUB only relies on EFI_RNG_PROTOCOL for randomization
+ * and completely ignores the kaslr-seed for its own randomness needs
+ * (i.e the randomization of the physical placement of the kernel).
+ * Weed it out from the DTB we hand over, which would mess up our DTB
+ * TPM measurements as well.
+ *
+ * @fdt: Pointer to device tree
+ */
+void efi_try_purge_kaslr_seed(void *fdt)
+{
+	const efi_guid_t efi_guid_rng_protocol = EFI_RNG_PROTOCOL_GUID;
+	struct efi_handler *handler;
+	efi_status_t ret;
+	int nodeoff = 0;
+	int err = 0;
+
+	ret = efi_search_protocol(efi_root, &efi_guid_rng_protocol, &handler);
+	if (ret != EFI_SUCCESS)
+		return;
+
+	nodeoff = fdt_path_offset(fdt, "/chosen");
+	if (nodeoff < 0)
+		return;
+
+	err = fdt_delprop(fdt, nodeoff, "kaslr-seed");
+	if (err < 0 && err != -FDT_ERR_NOTFOUND)
+		log_err("Error deleting kaslr-seed\n");
+}
+
+/**
  * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
  *
  * The mem_rsv entries of the FDT are added to the memory map. Any failures are
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index a1b88db..519a472 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -128,8 +128,11 @@
 	size_t names_len, total_size;
 	int dfu_num, i;
 	u16 *name, *next;
+	int ret;
 
-	dfu_init_env_entities(NULL, NULL);
+	ret = dfu_init_env_entities(NULL, NULL);
+	if (ret)
+		return EFI_SUCCESS;
 
 	names_len = 0;
 	dfu_num = 0;
@@ -138,7 +141,7 @@
 		dfu_num++;
 	}
 	if (!dfu_num) {
-		log_warning("Probably dfu_alt_info not defined\n");
+		log_warning("No entities in dfu_alt_info\n");
 		*image_info_size = 0;
 		dfu_free_entities();
 
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/net/dsa-uclass.c b/net/dsa-uclass.c
index 606b153..9ff55a0 100644
--- a/net/dsa-uclass.c
+++ b/net/dsa-uclass.c
@@ -466,6 +466,8 @@
 {
 	struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
 	struct dsa_priv *priv = dev_get_uclass_priv(dev);
+	struct dsa_ops *ops = dsa_get_ops(dev);
+	int err;
 
 	priv->num_ports = pdata->num_ports;
 	priv->cpu_port = pdata->cpu_port;
@@ -477,6 +479,15 @@
 
 	uclass_find_device_by_ofnode(UCLASS_ETH, pdata->master_node,
 				     &priv->master_dev);
+
+	/* Simulate a probing event for the CPU port */
+	if (ops->port_probe) {
+		err = ops->port_probe(dev, priv->cpu_port,
+				      priv->cpu_port_fixed_phy);
+		if (err)
+			return err;
+	}
+
 	return 0;
 }
 
diff --git a/net/fastboot.c b/net/fastboot.c
index 7e7a601..139233b 100644
--- a/net/fastboot.c
+++ b/net/fastboot.c
@@ -9,9 +9,6 @@
 #include <net.h>
 #include <net/fastboot.h>
 
-/* Fastboot port # defined in spec */
-#define WELL_KNOWN_PORT 5554
-
 enum {
 	FASTBOOT_ERROR = 0,
 	FASTBOOT_QUERY = 1,
@@ -310,7 +307,7 @@
 	printf("Using %s device\n", eth_get_name());
 	printf("Listening for fastboot command on %pI4\n", &net_ip);
 
-	fastboot_our_port = WELL_KNOWN_PORT;
+	fastboot_our_port = CONFIG_UDP_FUNCTION_FASTBOOT_PORT;
 
 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
 	fastboot_set_progress_callback(fastboot_timed_send_info);
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/bloblist.c b/test/bloblist.c
index b48be38..720be7e 100644
--- a/test/bloblist.c
+++ b/test/bloblist.c
@@ -19,9 +19,9 @@
 		UNIT_TEST(_name, _flags, bloblist_test)
 
 enum {
-	TEST_TAG		= 1,
-	TEST_TAG2		= 2,
-	TEST_TAG_MISSING	= 3,
+	TEST_TAG		= BLOBLISTT_U_BOOT_SPL_HANDOFF,
+	TEST_TAG2		= BLOBLISTT_VBOOT_CTX,
+	TEST_TAG_MISSING	= 0x10000,
 
 	TEST_SIZE		= 10,
 	TEST_SIZE2		= 20,
@@ -71,7 +71,9 @@
 
 	hdr = clear_bloblist();
 	ut_asserteq(-ENOENT, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
+	ut_asserteq_ptr(NULL, bloblist_check_magic(TEST_ADDR));
 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
+	ut_asserteq_ptr(hdr, bloblist_check_magic(TEST_ADDR));
 	hdr->version++;
 	ut_asserteq(-EPROTONOSUPPORT, bloblist_check(TEST_ADDR,
 						     TEST_BLOBLIST_SIZE));
@@ -83,6 +85,11 @@
 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
 	ut_assertok(bloblist_finish());
 	ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
+
+	hdr->magic++;
+	ut_asserteq_ptr(NULL, bloblist_check_magic(TEST_ADDR));
+	hdr->magic--;
+
 	hdr->flags++;
 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
 
@@ -100,6 +107,8 @@
 	hdr = clear_bloblist();
 	ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
+	ut_asserteq(TEST_BLOBLIST_SIZE, bloblist_get_size());
+	ut_asserteq(TEST_ADDR, bloblist_get_base());
 	ut_asserteq(map_to_sysmem(hdr), TEST_ADDR);
 
 	/* Add a record and check that we can find it */
@@ -281,10 +290,10 @@
 	ut_silence_console(uts);
 	console_record_reset();
 	run_command("bloblist list", 0);
-	ut_assert_nextline("Address       Size  Tag Name");
-	ut_assert_nextline("%08lx  %8x    1 EC host event",
+	ut_assert_nextline("Address       Size   Tag Name");
+	ut_assert_nextline("%08lx  %8x  8000 SPL hand-off",
 			   (ulong)map_to_sysmem(data), TEST_SIZE);
-	ut_assert_nextline("%08lx  %8x    2 SPL hand-off",
+	ut_assert_nextline("%08lx  %8x   106 Chrome OS vboot context",
 			   (ulong)map_to_sysmem(data2), TEST_SIZE2);
 	ut_assert_console_end();
 	ut_unsilence_console(uts);
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):
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 4b3ce23..f4c1fd0 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -577,9 +577,11 @@
     faked_list = []
     image.CheckFakedBlobs(faked_list)
     if faked_list:
-        tout.Warning("Image '%s:%s' has faked external blobs and is non-functional: %s" %
-                     (image.name, image.image_name,
-                      ' '.join([e.GetDefaultFilename() for e in faked_list])))
+        tout.Warning(
+            "Image '%s:%s' has faked external blobs and is non-functional: %s" %
+            (image.name, image.image_name,
+             ' '.join([os.path.basename(e.GetDefaultFilename())
+                       for e in faked_list])))
     return bool(missing_list) or bool(faked_list)
 
 
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 54cc372..bac90bb 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -7,6 +7,7 @@
 from collections import namedtuple
 import importlib
 import os
+import pathlib
 import sys
 
 from dtoc import fdt_util
@@ -972,6 +973,25 @@
         if self.missing:
             missing_list.append(self)
 
+    def check_fake_fname(self, fname):
+        """If the file is missing and the entry allows fake blobs, fake it
+
+        Sets self.faked to True if faked
+
+        Args:
+            fname (str): Filename to check
+
+        Returns:
+            fname (str): Filename of faked file
+        """
+        if self.allow_fake and not pathlib.Path(fname).is_file():
+            outfname = tools.GetOutputFilename(os.path.basename(fname))
+            with open(outfname, "wb") as out:
+                out.truncate(1024)
+            self.faked = True
+            return outfname
+        return fname
+
     def CheckFakedBlobs(self, faked_blobs_list):
         """Check if any entries in this section have faked external blobs
 
diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py
index 65ebb2e..59728f3 100644
--- a/tools/binman/etype/blob.py
+++ b/tools/binman/etype/blob.py
@@ -5,8 +5,6 @@
 # Entry-type module for blobs, which are binary objects read from files
 #
 
-import pathlib
-
 from binman.entry import Entry
 from binman import state
 from dtoc import fdt_util
@@ -38,16 +36,12 @@
         self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
 
     def ObtainContents(self):
-        if self.allow_fake and not pathlib.Path(self._filename).is_file():
-            with open(self._filename, "wb") as out:
-                out.truncate(1024)
-            self.faked = True
-
         self._filename = self.GetDefaultFilename()
         self._pathname = tools.GetInputFilename(self._filename,
             self.external and self.section.GetAllowMissing())
         # Allow the file to be missing
         if not self._pathname:
+            self._pathname = self.check_fake_fname(self._filename)
             self.SetContents(b'')
             self.missing = True
             return True
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index a9b7880..f4ff7b6 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -4667,16 +4667,6 @@
             str(e.exception),
             "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
 
-    def testFakeBlob(self):
-        """Test handling of faking an external blob"""
-        with test_util.capture_sys_output() as (stdout, stderr):
-            self._DoTestFile('203_fake_blob.dts', allow_missing=True,
-                             allow_fake_blobs=True)
-        err = stderr.getvalue()
-        self.assertRegex(err,
-                         "Image '.*' has faked external blobs and is non-functional: .*")
-        os.remove('binman_faking_test_blob')
-
     def testVersion(self):
         """Test we can get the binman version"""
         version = '(unreleased)'
@@ -4965,5 +4955,16 @@
         # There should be a U-Boot after the final FIP
         self.assertEqual(U_BOOT_DATA, data[-4:])
 
+    def testFakeBlob(self):
+        """Test handling of faking an external blob"""
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self._DoTestFile('217_fake_blob.dts', allow_missing=True,
+                             allow_fake_blobs=True)
+        err = stderr.getvalue()
+        self.assertRegex(
+            err,
+            "Image '.*' has faked external blobs and is non-functional: .*")
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/203_fake_blob.dts b/tools/binman/test/217_fake_blob.dts
similarity index 100%
rename from tools/binman/test/203_fake_blob.dts
rename to tools/binman/test/217_fake_blob.dts
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile
index fb422e7..f19e618 100644
--- a/tools/docker/Dockerfile
+++ b/tools/docker/Dockerfile
@@ -2,7 +2,7 @@
 # This Dockerfile is used to build an image containing basic stuff to be used
 # to build U-Boot and run our test suites.
 
-FROM ubuntu:focal-20211006
+FROM ubuntu:focal-20220105
 MAINTAINER Tom Rini <trini@konsulko.com>
 LABEL Description=" This image is for building U-Boot inside a container"
 
diff --git a/tools/genboardscfg.py b/tools/genboardscfg.py
index 4ee7aa1..07bf681 100755
--- a/tools/genboardscfg.py
+++ b/tools/genboardscfg.py
@@ -430,7 +430,7 @@
     # Add options here
     parser.add_option('-f', '--force', action="store_true", default=False,
                       help='regenerate the output even if it is new')
-    parser.add_option('-j', '--jobs', type='int', default=cpu_count,
+    parser.add_option('-j', '--jobs', type='int', default=min(cpu_count, 240),
                       help='the number of jobs to run simultaneously')
     parser.add_option('-o', '--output', default=OUTPUT_FILE,
                       help='output file [default=%s]' % OUTPUT_FILE)
diff --git a/tools/kwbimage.c b/tools/kwbimage.c
index 224d815..9b63ce8 100644
--- a/tools/kwbimage.c
+++ b/tools/kwbimage.c
@@ -99,6 +99,7 @@
 	IMAGE_CFG_NAND_BADBLK_LOCATION,
 	IMAGE_CFG_NAND_ECC_MODE,
 	IMAGE_CFG_NAND_PAGESZ,
+	IMAGE_CFG_CPU,
 	IMAGE_CFG_BINARY,
 	IMAGE_CFG_DATA,
 	IMAGE_CFG_DATA_DELAY,
@@ -129,6 +130,7 @@
 	[IMAGE_CFG_NAND_BADBLK_LOCATION] = "NAND_BADBLK_LOCATION",
 	[IMAGE_CFG_NAND_ECC_MODE] = "NAND_ECC_MODE",
 	[IMAGE_CFG_NAND_PAGESZ] = "NAND_PAGE_SIZE",
+	[IMAGE_CFG_CPU] = "CPU",
 	[IMAGE_CFG_BINARY] = "BINARY",
 	[IMAGE_CFG_DATA] = "DATA",
 	[IMAGE_CFG_DATA_DELAY] = "DATA_DELAY",
@@ -152,9 +154,11 @@
 	enum image_cfg_type type;
 	union {
 		unsigned int version;
+		unsigned int cpu_sheeva;
 		unsigned int bootfrom;
 		struct {
 			const char *file;
+			unsigned int loadaddr;
 			unsigned int args[BINARY_MAX_ARGS];
 			unsigned int nargs;
 		} binary;
@@ -199,7 +203,7 @@
 	return NULL;
 }
 
-int image_boot_mode_id(const char *boot_mode_name)
+static int image_boot_mode_id(const char *boot_mode_name)
 {
 	int i;
 
@@ -210,7 +214,18 @@
 	return -1;
 }
 
-int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
+static const char *image_nand_ecc_mode_name(unsigned int id)
+{
+	int i;
+
+	for (i = 0; nand_ecc_modes[i].name; i++)
+		if (nand_ecc_modes[i].id == id)
+			return nand_ecc_modes[i].name;
+
+	return NULL;
+}
+
+static int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
 {
 	int i;
 
@@ -280,6 +295,17 @@
 	return e->bootfrom;
 }
 
+static int image_is_cpu_sheeva(void)
+{
+	struct image_cfg_element *e;
+
+	e = image_find_option(IMAGE_CFG_CPU);
+	if (!e)
+		return 0;
+
+	return e->cpu_sheeva;
+}
+
 /*
  * Compute a 8-bit checksum of a memory area. This algorithm follows
  * the requirements of the Marvell SoC BootROM specifications.
@@ -344,6 +370,29 @@
 	return csum;
 }
 
+static unsigned int options_to_baudrate(uint8_t options)
+{
+	switch (options & 0x7) {
+	case MAIN_HDR_V1_OPT_BAUD_2400:
+		return 2400;
+	case MAIN_HDR_V1_OPT_BAUD_4800:
+		return 4800;
+	case MAIN_HDR_V1_OPT_BAUD_9600:
+		return 9600;
+	case MAIN_HDR_V1_OPT_BAUD_19200:
+		return 19200;
+	case MAIN_HDR_V1_OPT_BAUD_38400:
+		return 38400;
+	case MAIN_HDR_V1_OPT_BAUD_57600:
+		return 57600;
+	case MAIN_HDR_V1_OPT_BAUD_115200:
+		return 115200;
+	case MAIN_HDR_V1_OPT_BAUD_DEFAULT:
+	default:
+		return 0;
+	}
+}
+
 static uint8_t baudrate_to_option(unsigned int baudrate)
 {
 	switch (baudrate) {
@@ -602,7 +651,8 @@
 	return 0;
 }
 
-int kwb_sign(RSA *key, void *data, int datasz, struct sig_v1 *sig, char *signame)
+static int kwb_sign(RSA *key, void *data, int datasz, struct sig_v1 *sig,
+		    char *signame)
 {
 	EVP_PKEY *evp_key;
 	EVP_MD_CTX *ctx;
@@ -662,8 +712,8 @@
 	return ret;
 }
 
-int kwb_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig,
-	       char *signame)
+static int kwb_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig,
+		      char *signame)
 {
 	EVP_PKEY *evp_key;
 	EVP_MD_CTX *ctx;
@@ -722,8 +772,8 @@
 	return ret;
 }
 
-int kwb_sign_and_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig,
-			char *signame)
+static int kwb_sign_and_verify(RSA *key, void *data, int datasz,
+			       struct sig_v1 *sig, char *signame)
 {
 	if (kwb_sign(key, data, datasz, sig, signame) < 0)
 		return -1;
@@ -735,7 +785,7 @@
 }
 
 
-int kwb_dump_fuse_cmds_38x(FILE *out, struct secure_hdr_v1 *sec_hdr)
+static int kwb_dump_fuse_cmds_38x(FILE *out, struct secure_hdr_v1 *sec_hdr)
 {
 	struct hash_v1 kak_pub_hash;
 	struct image_cfg_element *e;
@@ -992,10 +1042,13 @@
 
 static size_t image_headersz_v1(int *hasext)
 {
-	struct image_cfg_element *binarye;
+	struct image_cfg_element *e;
 	unsigned int count;
 	size_t headersz;
+	int cpu_sheeva;
+	struct stat s;
 	int cfgi;
+	int ret;
 
 	/*
 	 * Calculate the size of the header and the size of the
@@ -1009,19 +1062,25 @@
 			*hasext = 1;
 	}
 
-	count = image_count_options(IMAGE_CFG_DATA);
-	if (count > 0)
-		headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
+	cpu_sheeva = image_is_cpu_sheeva();
 
+	count = 0;
 	for (cfgi = 0; cfgi < cfgn; cfgi++) {
-		int ret;
-		struct stat s;
+		e = &image_cfg[cfgi];
 
-		binarye = &image_cfg[cfgi];
-		if (binarye->type != IMAGE_CFG_BINARY)
+		if (e->type == IMAGE_CFG_DATA)
+			count++;
+
+		if (e->type == IMAGE_CFG_DATA_DELAY ||
+		    (e->type == IMAGE_CFG_BINARY && count > 0)) {
+			headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
+			count = 0;
+		}
+
+		if (e->type != IMAGE_CFG_BINARY)
 			continue;
 
-		ret = stat(binarye->binary.file, &s);
+		ret = stat(e->binary.file, &s);
 		if (ret < 0) {
 			char cwd[PATH_MAX];
 			char *dir = cwd;
@@ -1036,30 +1095,74 @@
 				"Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
 				"This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
 				"image for your board. Use 'dumpimage -T kwbimage -p 0' to extract it from an existing image.\n",
-				binarye->binary.file, dir);
+				e->binary.file, dir);
 			return 0;
 		}
 
 		headersz += sizeof(struct opt_hdr_v1) + sizeof(uint32_t) +
-			(binarye->binary.nargs) * sizeof(uint32_t);
-		headersz = ALIGN(headersz, 16);
+			(e->binary.nargs) * sizeof(uint32_t);
+
+		if (e->binary.loadaddr) {
+			/*
+			 * BootROM loads kwbimage header (in which the
+			 * executable code is also stored) to address
+			 * 0x40004000 or 0x40000000. Thus there is
+			 * restriction for the load address of the N-th
+			 * BINARY image.
+			 */
+			unsigned int base_addr, low_addr, high_addr;
+
+			base_addr = cpu_sheeva ? 0x40004000 : 0x40000000;
+			low_addr = base_addr + headersz;
+			high_addr = low_addr +
+				    (BINARY_MAX_ARGS - e->binary.nargs) * sizeof(uint32_t);
+
+			if (cpu_sheeva && e->binary.loadaddr % 16) {
+				fprintf(stderr,
+					"Invalid LOAD_ADDRESS 0x%08x for BINARY %s with %d args.\n"
+					"Address for CPU SHEEVA must be 16-byte aligned.\n",
+					e->binary.loadaddr, e->binary.file, e->binary.nargs);
+				return 0;
+			}
+
+			if (e->binary.loadaddr % 4 || e->binary.loadaddr < low_addr ||
+			    e->binary.loadaddr > high_addr) {
+				fprintf(stderr,
+					"Invalid LOAD_ADDRESS 0x%08x for BINARY %s with %d args.\n"
+					"Address must be 4-byte aligned and in range 0x%08x-0x%08x.\n",
+					e->binary.loadaddr, e->binary.file,
+					e->binary.nargs, low_addr, high_addr);
+				return 0;
+			}
+			headersz = e->binary.loadaddr - base_addr;
+		} else if (cpu_sheeva) {
+			headersz = ALIGN(headersz, 16);
+		} else {
+			headersz = ALIGN(headersz, 4);
+		}
+
 		headersz += ALIGN(s.st_size, 4) + sizeof(uint32_t);
 		if (hasext)
 			*hasext = 1;
 	}
 
+	if (count > 0)
+		headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
+
 	return image_headersz_align(headersz, image_get_bootfrom());
 }
 
-int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
-			 struct image_cfg_element *binarye,
-			 struct main_hdr_v1 *main_hdr)
+static int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
+				struct image_cfg_element *binarye,
+				struct main_hdr_v1 *main_hdr)
 {
 	struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)*cur;
+	uint32_t base_addr;
 	uint32_t add_args;
 	uint32_t offset;
 	uint32_t *args;
 	size_t binhdrsz;
+	int cpu_sheeva;
 	struct stat s;
 	int argi;
 	FILE *bin;
@@ -1091,13 +1194,22 @@
 	*cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
 
 	/*
-	 * ARM executable code inside the BIN header on some mvebu platforms
-	 * (e.g. A370, AXP) must always be aligned with the 128-bit boundary.
+	 * ARM executable code inside the BIN header on platforms with Sheeva
+	 * CPU (A370 and AXP) must always be aligned with the 128-bit boundary.
+	 * In the case when this code is not position independent (e.g. ARM
+	 * SPL), it must be placed at fixed load and execute address.
 	 * This requirement can be met by inserting dummy arguments into
 	 * BIN header, if needed.
 	 */
+	cpu_sheeva = image_is_cpu_sheeva();
+	base_addr = cpu_sheeva ? 0x40004000 : 0x40000000;
 	offset = *cur - (uint8_t *)main_hdr;
-	add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t);
+	if (binarye->binary.loadaddr)
+		add_args = (binarye->binary.loadaddr - base_addr - offset) / sizeof(uint32_t);
+	else if (cpu_sheeva)
+		add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t);
+	else
+		add_args = 0;
 	if (add_args) {
 		*(args - 1) = cpu_to_le32(binarye->binary.nargs + add_args);
 		*cur += add_args * sizeof(uint32_t);
@@ -1135,7 +1247,7 @@
 	return -1;
 }
 
-int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr)
+static int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr)
 {
 	FILE *hashf;
 	int res;
@@ -1154,8 +1266,8 @@
 	return res < 0 ? 1 : 0;
 }
 
-int kwb_sign_csk_with_kak(struct image_tool_params *params,
-			  struct secure_hdr_v1 *secure_hdr, RSA *csk)
+static int kwb_sign_csk_with_kak(struct image_tool_params *params,
+				 struct secure_hdr_v1 *secure_hdr, RSA *csk)
 {
 	RSA *kak = NULL;
 	RSA *kak_pub = NULL;
@@ -1196,9 +1308,9 @@
 	return 0;
 }
 
-int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr,
-			 int payloadsz, size_t headersz, uint8_t *image,
-			 struct secure_hdr_v1 *secure_hdr)
+static int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr,
+				int payloadsz, size_t headersz, uint8_t *image,
+				struct secure_hdr_v1 *secure_hdr)
 {
 	struct image_cfg_element *e_jtagdelay;
 	struct image_cfg_element *e_boxid;
@@ -1248,6 +1360,22 @@
 	return 0;
 }
 
+static void finish_register_set_header_v1(uint8_t **cur, uint8_t **next_ext,
+					  struct register_set_hdr_v1 *register_set_hdr,
+					  int *datai, uint8_t delay)
+{
+	int size = sizeof(struct register_set_hdr_v1) + 8 * (*datai) + 4;
+
+	register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE;
+	register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF);
+	register_set_hdr->headersz_msb = size >> 16;
+	register_set_hdr->data[*datai].last_entry.delay = delay;
+	*cur += size;
+	**next_ext = 1;
+	*next_ext = &register_set_hdr->data[*datai].last_entry.next;
+	*datai = 0;
+}
+
 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
 			     uint8_t *ptr, int payloadsz)
 {
@@ -1260,7 +1388,8 @@
 	uint8_t *image, *cur;
 	int hasext = 0;
 	uint8_t *next_ext = NULL;
-	int cfgi, datai, size;
+	int cfgi, datai;
+	uint8_t delay;
 
 	/*
 	 * Calculate the size of the header and the size of the
@@ -1351,49 +1480,53 @@
 	}
 
 	datai = 0;
-	register_set_hdr = (struct register_set_hdr_v1 *)cur;
 	for (cfgi = 0; cfgi < cfgn; cfgi++) {
 		e = &image_cfg[cfgi];
 		if (e->type != IMAGE_CFG_DATA &&
-		    e->type != IMAGE_CFG_DATA_DELAY)
+		    e->type != IMAGE_CFG_DATA_DELAY &&
+		    e->type != IMAGE_CFG_BINARY)
 			continue;
-		if (e->type == IMAGE_CFG_DATA_DELAY) {
-			size = sizeof(struct register_set_hdr_v1) + 8 * datai + 4;
-			register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE;
-			register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF);
-			register_set_hdr->headersz_msb = size >> 16;
-			register_set_hdr->data[datai].last_entry.delay = e->regdata_delay;
-			cur += size;
-			*next_ext = 1;
-			next_ext = &register_set_hdr->data[datai].last_entry.next;
-			datai = 0;
-			continue;
+
+		if (datai == 0)
+			register_set_hdr = (struct register_set_hdr_v1 *)cur;
+
+		/* If delay is not specified, use the smallest possible value. */
+		if (e->type == IMAGE_CFG_DATA_DELAY)
+			delay = e->regdata_delay;
+		else
+			delay = REGISTER_SET_HDR_OPT_DELAY_MS(0);
+
+		/*
+		 * DATA_DELAY command is the last entry in the register set
+		 * header and BINARY command inserts new binary header.
+		 * Therefore BINARY command requires to finish register set
+		 * header if some DATA command was specified. And DATA_DELAY
+		 * command automatically finish register set header even when
+		 * there was no DATA command.
+		 */
+		if (e->type == IMAGE_CFG_DATA_DELAY ||
+		    (e->type == IMAGE_CFG_BINARY && datai != 0))
+			finish_register_set_header_v1(&cur, &next_ext, register_set_hdr,
+						      &datai, delay);
+
+		if (e->type == IMAGE_CFG_DATA) {
+			register_set_hdr->data[datai].entry.address =
+				cpu_to_le32(e->regdata.raddr);
+			register_set_hdr->data[datai].entry.value =
+				cpu_to_le32(e->regdata.rdata);
+			datai++;
 		}
-		register_set_hdr->data[datai].entry.address =
-			cpu_to_le32(e->regdata.raddr);
-		register_set_hdr->data[datai].entry.value =
-			cpu_to_le32(e->regdata.rdata);
-		datai++;
+
+		if (e->type == IMAGE_CFG_BINARY) {
+			if (add_binary_header_v1(&cur, &next_ext, e, main_hdr))
+				return NULL;
+		}
 	}
 	if (datai != 0) {
-		size = sizeof(struct register_set_hdr_v1) + 8 * datai + 4;
-		register_set_hdr->headertype = OPT_HDR_V1_REGISTER_TYPE;
-		register_set_hdr->headersz_lsb = cpu_to_le16(size & 0xFFFF);
-		register_set_hdr->headersz_msb = size >> 16;
-		/* Set delay to the smallest possible value 1ms. */
-		register_set_hdr->data[datai].last_entry.delay = 1;
-		cur += size;
-		*next_ext = 1;
-		next_ext = &register_set_hdr->data[datai].last_entry.next;
-	}
-
-	for (cfgi = 0; cfgi < cfgn; cfgi++) {
-		e = &image_cfg[cfgi];
-		if (e->type != IMAGE_CFG_BINARY)
-			continue;
-
-		if (add_binary_header_v1(&cur, &next_ext, e, main_hdr))
-			return NULL;
+		/* Set delay to the smallest possible value. */
+		delay = REGISTER_SET_HDR_OPT_DELAY_MS(0);
+		finish_register_set_header_v1(&cur, &next_ext, register_set_hdr,
+					      &datai, delay);
 	}
 
 	if (secure_hdr && add_secure_header_v1(params, ptr, payloadsz + headersz,
@@ -1415,7 +1548,7 @@
 	return image;
 }
 
-int recognize_keyword(char *keyword)
+static int recognize_keyword(char *keyword)
 {
 	int kw_id;
 
@@ -1455,6 +1588,18 @@
 	case IMAGE_CFG_VERSION:
 		el->version = atoi(value1);
 		break;
+	case IMAGE_CFG_CPU:
+		if (strcmp(value1, "FEROCEON") == 0)
+			el->cpu_sheeva = 0;
+		else if (strcmp(value1, "SHEEVA") == 0)
+			el->cpu_sheeva = 1;
+		else if (strcmp(value1, "A9") == 0)
+			el->cpu_sheeva = 0;
+		else {
+			fprintf(stderr, "Invalid CPU %s\n", value1);
+			return -1;
+		}
+		break;
 	case IMAGE_CFG_BOOT_FROM:
 		ret = image_boot_mode_id(value1);
 
@@ -1488,10 +1633,40 @@
 		el->binary.file = strdup(value1);
 		while (1) {
 			char *value = strtok_r(NULL, delimiters, &saveptr);
+			char *endptr;
 
 			if (!value)
 				break;
-			el->binary.args[argi] = strtoul(value, NULL, 16);
+
+			if (!strcmp(value, "LOAD_ADDRESS")) {
+				value = strtok_r(NULL, delimiters, &saveptr);
+				if (!value) {
+					fprintf(stderr,
+						"Missing address argument for BINARY LOAD_ADDRESS\n");
+					return -1;
+				}
+				el->binary.loadaddr = strtoul(value, &endptr, 16);
+				if (*endptr) {
+					fprintf(stderr,
+						"Invalid argument '%s' for BINARY LOAD_ADDRESS\n",
+						value);
+					return -1;
+				}
+				value = strtok_r(NULL, delimiters, &saveptr);
+				if (value) {
+					fprintf(stderr,
+						"Unexpected argument '%s' after BINARY LOAD_ADDRESS\n",
+						value);
+					return -1;
+				}
+				break;
+			}
+
+			el->binary.args[argi] = strtoul(value, &endptr, 16);
+			if (*endptr) {
+				fprintf(stderr, "Invalid argument '%s' for BINARY\n", value);
+				return -1;
+			}
 			argi++;
 			if (argi >= BINARY_MAX_ARGS) {
 				fprintf(stderr,
@@ -1518,6 +1693,10 @@
 			el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_SDRAM_SETUP;
 		else
 			el->regdata_delay = REGISTER_SET_HDR_OPT_DELAY_MS(strtoul(value1, NULL, 10));
+		if (el->regdata_delay > 255) {
+			fprintf(stderr, "Maximal DATA_DELAY is 255\n");
+			return -1;
+		}
 		break;
 	case IMAGE_CFG_BAUDRATE:
 		el->baudrate = strtoul(value1, NULL, 10);
@@ -1727,9 +1906,12 @@
 
 	for_each_opt_hdr_v1 (ohdr, mhdr) {
 		if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
-			printf("BIN Hdr Size: ");
+			printf("BIN Img Size: ");
 			genimg_print_size(opt_hdr_v1_size(ohdr) - 12 -
 					  4 * ohdr->data[0]);
+			printf("BIN Img Offs: %08x\n",
+				(unsigned)((uint8_t *)ohdr - (uint8_t *)mhdr) +
+				8 + 4 * ohdr->data[0]);
 		}
 	}
 
@@ -1766,7 +1948,7 @@
 	if (kwbimage_version(ptr) == 0) {
 		struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
 
-		if (mhdr->ext & 0x1) {
+		if (mhdr->ext) {
 			struct ext_hdr_v0 *ext_hdr = (void *)(mhdr + 1);
 
 			csum = image_checksum8(ext_hdr, sizeof(*ext_hdr) - 1);
@@ -1892,6 +2074,15 @@
 
 	case 1:
 		alloc_len = image_headersz_v1(NULL);
+		if (!alloc_len) {
+			free(image_cfg);
+			exit(EXIT_FAILURE);
+		}
+		if (alloc_len > 192*1024) {
+			fprintf(stderr, "Header is too big (%u bytes), maximal kwbimage header size is %u bytes\n", alloc_len, 192*1024);
+			free(image_cfg);
+			exit(EXIT_FAILURE);
+		}
 		break;
 
 	default:
@@ -1931,52 +2122,207 @@
 		return 4 + (4 - s.st_size % 4) % 4;
 }
 
+static int kwbimage_generate_config(void *ptr, struct image_tool_params *params)
+{
+	struct main_hdr_v0 *mhdr0 = (struct main_hdr_v0 *)ptr;
+	struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
+	size_t header_size = kwbheader_size(ptr);
+	struct register_set_hdr_v1 *regset_hdr;
+	struct ext_hdr_v0_reg *regdata;
+	struct ext_hdr_v0 *ehdr0;
+	struct opt_hdr_v1 *ohdr;
+	unsigned offset;
+	int cur_idx;
+	int version;
+	FILE *f;
+	int i;
+
+	f = fopen(params->outfile, "w");
+	if (!f) {
+		fprintf(stderr, "Can't open \"%s\": %s\n", params->outfile, strerror(errno));
+		return -1;
+	}
+
+	version = kwbimage_version(ptr);
+
+	if (version != 0)
+		fprintf(f, "VERSION %d\n", version);
+
+	fprintf(f, "BOOT_FROM %s\n", image_boot_mode_name(mhdr->blockid) ?: "<unknown>");
+
+	if (version == 0 && mhdr->blockid == IBR_HDR_NAND_ID)
+		fprintf(f, "NAND_ECC_MODE %s\n", image_nand_ecc_mode_name(mhdr0->nandeccmode));
+
+	if (mhdr->blockid == IBR_HDR_NAND_ID)
+		fprintf(f, "NAND_PAGE_SIZE 0x%x\n", (unsigned)mhdr->nandpagesize);
+
+	if (version != 0 && mhdr->blockid == IBR_HDR_NAND_ID) {
+		fprintf(f, "NAND_BLKSZ 0x%x\n", (unsigned)mhdr->nandblocksize);
+		fprintf(f, "NAND_BADBLK_LOCATION 0x%x\n", (unsigned)mhdr->nandbadblklocation);
+	}
+
+	if (version == 0 && mhdr->blockid == IBR_HDR_SATA_ID)
+		fprintf(f, "SATA_PIO_MODE %u\n", (unsigned)mhdr0->satapiomode);
+
+	/*
+	 * Addresses and sizes which are specified by mkimage command line
+	 * arguments and not in kwbimage config file
+	 */
+
+	if (version != 0)
+		fprintf(f, "#HEADER_SIZE 0x%x\n",
+			((unsigned)mhdr->headersz_msb << 8) | le16_to_cpu(mhdr->headersz_lsb));
+
+	fprintf(f, "#SRC_ADDRESS 0x%x\n", le32_to_cpu(mhdr->srcaddr));
+	fprintf(f, "#BLOCK_SIZE 0x%x\n", le32_to_cpu(mhdr->blocksize));
+	fprintf(f, "#DEST_ADDRESS 0x%08x\n", le32_to_cpu(mhdr->destaddr));
+	fprintf(f, "#EXEC_ADDRESS 0x%08x\n", le32_to_cpu(mhdr->execaddr));
+
+	if (version != 0) {
+		if (options_to_baudrate(mhdr->options))
+			fprintf(f, "BAUDRATE %u\n", options_to_baudrate(mhdr->options));
+		if (options_to_baudrate(mhdr->options) ||
+		    ((mhdr->options >> 3) & 0x3) || ((mhdr->options >> 5) & 0x7)) {
+			fprintf(f, "UART_PORT %u\n", (unsigned)((mhdr->options >> 3) & 0x3));
+			fprintf(f, "UART_MPP 0x%x\n", (unsigned)((mhdr->options >> 5) & 0x7));
+		}
+		if (mhdr->flags & 0x1)
+			fprintf(f, "DEBUG 1\n");
+	}
+
+	cur_idx = 1;
+	for_each_opt_hdr_v1(ohdr, ptr) {
+		if (ohdr->headertype == OPT_HDR_V1_SECURE_TYPE) {
+			fprintf(f, "#SECURE_HEADER\n");
+		} else if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
+			fprintf(f, "BINARY binary%d.bin", cur_idx);
+			for (i = 0; i < ohdr->data[0]; i++)
+				fprintf(f, " 0x%x", le32_to_cpu(((uint32_t *)ohdr->data)[i + 1]));
+			offset = (unsigned)((uint8_t *)ohdr - (uint8_t *)mhdr) + 8 + 4 * ohdr->data[0];
+			fprintf(f, " LOAD_ADDRESS 0x%08x\n", 0x40000000 + offset);
+			fprintf(f, " # for CPU SHEEVA: LOAD_ADDRESS 0x%08x\n", 0x40004000 + offset);
+			cur_idx++;
+		} else if (ohdr->headertype == OPT_HDR_V1_REGISTER_TYPE) {
+			regset_hdr = (struct register_set_hdr_v1 *)ohdr;
+			for (i = 0;
+			     i < opt_hdr_v1_size(ohdr) - sizeof(struct opt_hdr_v1) -
+				 sizeof(regset_hdr->data[0].last_entry);
+			     i++)
+				fprintf(f, "DATA 0x%08x 0x%08x\n",
+					le32_to_cpu(regset_hdr->data[i].entry.address),
+					le32_to_cpu(regset_hdr->data[i].entry.value));
+			if (opt_hdr_v1_size(ohdr) - sizeof(struct opt_hdr_v1) >=
+			    sizeof(regset_hdr->data[0].last_entry)) {
+				if (regset_hdr->data[0].last_entry.delay)
+					fprintf(f, "DATA_DELAY %u\n",
+						(unsigned)regset_hdr->data[0].last_entry.delay);
+				else
+					fprintf(f, "DATA_DELAY SDRAM_SETUP\n");
+			}
+		}
+	}
+
+	if (version == 0 && mhdr0->ext) {
+		ehdr0 = (struct ext_hdr_v0 *)(mhdr0 + 1);
+		if (ehdr0->offset) {
+			for (regdata = (struct ext_hdr_v0_reg *)((uint8_t *)ptr + ehdr0->offset);
+			     (uint8_t *)regdata < (uint8_t *)ptr + header_size && regdata->raddr &&
+			     regdata->rdata;
+			     regdata++)
+				fprintf(f, "DATA 0x%08x 0x%08x\n", le32_to_cpu(regdata->raddr),
+					le32_to_cpu(regdata->rdata));
+		}
+	}
+
+	if (version == 0 && le16_to_cpu(mhdr0->ddrinitdelay))
+		fprintf(f, "DDR_INIT_DELAY %u\n", (unsigned)le16_to_cpu(mhdr0->ddrinitdelay));
+
+	/* Undocumented reserved fields */
+
+	if (version == 0 && (mhdr0->rsvd1[0] || mhdr0->rsvd1[1] || mhdr0->rsvd1[2]))
+		fprintf(f, "#RSVD1 0x%x 0x%x 0x%x\n", (unsigned)mhdr0->rsvd1[0],
+			(unsigned)mhdr0->rsvd1[1], (unsigned)mhdr0->rsvd1[2]);
+
+	if (version == 0 && mhdr0->rsvd3)
+		fprintf(f, "#RSVD3 0x%x\n", (unsigned)mhdr0->rsvd3);
+
+	if (version == 0 && le16_to_cpu(mhdr0->rsvd2))
+		fprintf(f, "#RSVD2 0x%x\n", (unsigned)le16_to_cpu(mhdr0->rsvd2));
+
+	if (version != 0 && mhdr->reserved4)
+		fprintf(f, "#RESERVED4 0x%x\n", (unsigned)mhdr->reserved4);
+
+	if (version != 0 && mhdr->reserved5)
+		fprintf(f, "#RESERVED5 0x%x\n", (unsigned)le16_to_cpu(mhdr->reserved5));
+
+	fclose(f);
+
+	return 0;
+}
+
 static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params)
 {
 	struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
 	size_t header_size = kwbheader_size(ptr);
 	struct opt_hdr_v1 *ohdr;
 	int idx = params->pflag;
-	int cur_idx = 0;
+	int cur_idx;
 	uint32_t offset;
 	ulong image;
 	ulong size;
 
-	for_each_opt_hdr_v1 (ohdr, ptr) {
-		if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE)
-			continue;
+	/* Generate kwbimage config file when '-p -1' is specified */
+	if (idx == -1)
+		return kwbimage_generate_config(ptr, params);
 
-		if (idx == cur_idx) {
-			image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]];
-			size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0];
-			goto extract;
+	image = 0;
+	size = 0;
+
+	if (idx == 0) {
+		/* Extract data image when -p is not specified or when '-p 0' is specified */
+		offset = le32_to_cpu(mhdr->srcaddr);
+
+		if (mhdr->blockid == IBR_HDR_SATA_ID) {
+			offset -= 1;
+			offset *= 512;
 		}
 
-		++cur_idx;
+		if (mhdr->blockid == IBR_HDR_SDIO_ID)
+			offset *= 512;
+
+		if (mhdr->blockid == IBR_HDR_PEX_ID && offset == 0xFFFFFFFF)
+			offset = header_size;
+
+		image = (ulong)((uint8_t *)ptr + offset);
+		size = le32_to_cpu(mhdr->blocksize) - 4;
+	} else {
+		/* Extract N-th binary header executabe image when other '-p N' is specified */
+		cur_idx = 1;
+		for_each_opt_hdr_v1(ohdr, ptr) {
+			if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE)
+				continue;
+
+			if (idx == cur_idx) {
+				image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]];
+				size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0];
+				break;
+			}
+
+			++cur_idx;
+		}
+
+		if (!image) {
+			fprintf(stderr, "Argument -p %d is invalid\n", idx);
+			fprintf(stderr, "Available subimages:\n");
+			fprintf(stderr, " -p -1  - kwbimage config file\n");
+			fprintf(stderr, " -p 0   - data image\n");
+			if (cur_idx - 1 > 0)
+				fprintf(stderr, " -p N   - Nth binary header image (totally: %d)\n",
+					cur_idx - 1);
+			return -1;
+		}
 	}
 
-	if (idx != cur_idx) {
-		printf("Image %d is not present\n", idx);
-		return -1;
-	}
-
-	offset = le32_to_cpu(mhdr->srcaddr);
-
-	if (mhdr->blockid == IBR_HDR_SATA_ID) {
-		offset -= 1;
-		offset *= 512;
-	}
-
-	if (mhdr->blockid == IBR_HDR_SDIO_ID)
-		offset *= 512;
-
-	if (mhdr->blockid == IBR_HDR_PEX_ID && offset == 0xFFFFFFFF)
-		offset = header_size;
-
-	image = (ulong)((uint8_t *)ptr + offset);
-	size = le32_to_cpu(mhdr->blocksize) - 4;
-
-extract:
 	return imagetool_save_subimage(params->outfile, image, size);
 }
 
@@ -1985,7 +2331,8 @@
  */
 static int kwbimage_check_params(struct image_tool_params *params)
 {
-	if (!params->iflag && (!params->imagename || !strlen(params->imagename))) {
+	if (!params->lflag && !params->iflag &&
+	    (!params->imagename || !strlen(params->imagename))) {
 		char *msg = "Configuration file for kwbimage creation omitted";
 
 		fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
diff --git a/tools/kwbimage.h b/tools/kwbimage.h
index 8d37357..9ebc7d7 100644
--- a/tools/kwbimage.h
+++ b/tools/kwbimage.h
@@ -208,7 +208,7 @@
 		const struct main_hdr_v0 *hdr = header;
 
 		return sizeof(*hdr) +
-		       (hdr->ext & 0x1) ? sizeof(struct ext_hdr_v0) : 0;
+		       hdr->ext ? sizeof(struct ext_hdr_v0) : 0;
 	} else {
 		const struct main_hdr_v1 *hdr = header;
 
@@ -235,11 +235,11 @@
 {
 	uint32_t ohdr_size;
 
-	if ((void *)(ohdr + 1) > mhdr_end)
+	if ((const void *)(ohdr + 1) > mhdr_end)
 		return 0;
 
 	ohdr_size = opt_hdr_v1_size(ohdr);
-	if (ohdr_size < 8 || (void *)((uint8_t *)ohdr + ohdr_size) > mhdr_end)
+	if (ohdr_size < 8 || (const void *)((const uint8_t *)ohdr + ohdr_size) > mhdr_end)
 		return 0;
 
 	return 1;
@@ -252,7 +252,7 @@
 		return NULL;
 
 	mhdr = img;
-	if (mhdr->ext & 0x1)
+	if (mhdr->ext)
 		return (struct opt_hdr_v1 *)(mhdr + 1);
 	else
 		return NULL;
@@ -272,7 +272,7 @@
 
 static inline struct opt_hdr_v1 *opt_hdr_v1_next(struct opt_hdr_v1 *cur)
 {
-	if (*opt_hdr_v1_ext(cur) & 0x1)
+	if (*opt_hdr_v1_ext(cur))
 		return _opt_hdr_v1_next(cur);
 	else
 		return NULL;
diff --git a/tools/kwboot.c b/tools/kwboot.c
index d22e6ea..c3d8ab6 100644
--- a/tools/kwboot.c
+++ b/tools/kwboot.c
@@ -1398,7 +1398,7 @@
 	uint32_t ohdrsz;
 	uint8_t *prev_ext;
 
-	if (hdr->ext & 0x1) {
+	if (hdr->ext) {
 		for_each_opt_hdr_v1 (ohdr, img)
 			if (opt_hdr_v1_next(ohdr) == NULL)
 				break;
@@ -1422,7 +1422,7 @@
 	ohdrsz = sizeof(*ohdr) + 4 + 4 * num_args + binsz + 4;
 	kwboot_img_grow_hdr(hdr, size, ohdrsz);
 
-	*prev_ext |= 1;
+	*prev_ext = 1;
 
 	ohdr->headertype = OPT_HDR_V1_BINARY_TYPE;
 	ohdr->headersz_msb = ohdrsz >> 16;
diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py
index 5e4c112..e1ef96d 100644
--- a/tools/patman/gitutil.py
+++ b/tools/patman/gitutil.py
@@ -616,9 +616,14 @@
     """
     fname = command.OutputOneLine('git', 'config', 'sendemail.aliasesfile',
             raise_on_error=False)
-    if fname:
-        fname = os.path.join(GetTopLevel(), fname.strip())
-    return fname
+    if not fname:
+        return None
+
+    fname = os.path.expanduser(fname.strip())
+    if os.path.isabs(fname):
+        return fname
+
+    return os.path.join(GetTopLevel(), fname)
 
 def GetDefaultUserName():
     """Gets the user.name from .gitconfig file.