Merge tag 'fsl-qoriq-2023-7-13' of https://source.denx.de/u-boot/custodians/u-boot-fsl-qoriq

Enable DM_SERIAL for T2080RDB, T4240RDB, T1042D4RDB, T1024RDB
diff --git a/Makefile b/Makefile
index 1d551da..87f9fc7 100644
--- a/Makefile
+++ b/Makefile
@@ -2444,7 +2444,7 @@
 cmd_genenv = \
 	$(objtree)/tools/printinitialenv | \
 	sed -e '/^\s*$$/d' | \
-	sort --field-separator== -k1,1 --stable -o $@
+	sort --field-separator='=' -k1,1 --stable -o $@
 
 u-boot-initial-env: $(env_h) FORCE
 	$(Q)$(MAKE) $(build)=tools $(objtree)/tools/printinitialenv
diff --git a/README b/README
index bbf96e6..15a19ca 100644
--- a/README
+++ b/README
@@ -2430,27 +2430,6 @@
 	[q, b, e, ?] ## Application terminated, rc = 0x0
 
 
-Minicom warning:
-================
-
-Over time, many people have reported problems when trying to use the
-"minicom" terminal emulation program for serial download. I (wd)
-consider minicom to be broken, and recommend not to use it. Under
-Unix, I recommend to use C-Kermit for general purpose use (and
-especially for kermit binary protocol download ("loadb" command), and
-use "cu" for S-Record download ("loads" command).  See
-https://www.denx.de/wiki/view/DULG/SystemSetup#Section_4.3.
-for help with kermit.
-
-
-Nevertheless, if you absolutely want to use it try adding this
-configuration to your "File transfer protocols" section:
-
-	   Name	   Program			Name U/D FullScr IO-Red. Multi
-	X  kermit  /usr/bin/kermit -i -l %l -s	 Y    U	   Y	   N	  N
-	Y  kermit  /usr/bin/kermit -i -l %l -r	 N    D	   Y	   N	  N
-
-
 Implementation Internals:
 =========================
 
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 99264a6..b3115b0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -882,7 +882,7 @@
 	select SUPPORT_SPL
 	select GPIO_EXTRA_HEADER
 	select MISC
-	select IMX_SENTINEL
+	select IMX_ELE
 	imply CMD_DM
 
 config ARCH_IMX9
@@ -894,7 +894,7 @@
 	select SUPPORT_SPL
 	select GPIO_EXTRA_HEADER
 	select MISC
-	select IMX_SENTINEL
+	select IMX_ELE
 	imply CMD_DM
 
 config ARCH_IMXRT
@@ -912,14 +912,12 @@
 	select CPU_ARM926EJS
 	select GPIO_EXTRA_HEADER
 	select MACH_IMX
-	select PL011_SERIAL
 	select SUPPORT_SPL
 
 config ARCH_MX28
 	bool "NXP i.MX28 family"
 	select CPU_ARM926EJS
 	select GPIO_EXTRA_HEADER
-	select PL011_SERIAL
 	select MACH_IMX
 	select SUPPORT_SPL
 
diff --git a/arch/arm/cpu/arm926ejs/mxs/spl_boot.c b/arch/arm/cpu/arm926ejs/mxs/spl_boot.c
index 763d79e..5598c55 100644
--- a/arch/arm/cpu/arm926ejs/mxs/spl_boot.c
+++ b/arch/arm/cpu/arm926ejs/mxs/spl_boot.c
@@ -128,8 +128,10 @@
 
 	mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size);
 
-	mxs_spl_console_init();
-	debug("SPL: Serial Console Initialised\n");
+	if (!CONFIG_IS_ENABLED(DM_SERIAL)) {
+		mxs_spl_console_init();
+		debug("SPL: Serial Console Initialised\n");
+	}
 
 	mxs_power_init();
 
diff --git a/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c b/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c
index c33170f..7ea029e 100644
--- a/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c
+++ b/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c
@@ -41,6 +41,29 @@
 		&clkctrl_regs->hw_clkctrl_clkseq_set);
 }
 
+static void mxs_power_regs_dump(void)
+{
+	struct mxs_power_regs *power_regs =
+		(struct mxs_power_regs *)MXS_POWER_BASE;
+
+	debug("ctrl:\t\t 0x%x\n", readl(&power_regs->hw_power_ctrl));
+	debug("5vctrl:\t\t 0x%x\n", readl(&power_regs->hw_power_5vctrl));
+	debug("minpwr:\t\t 0x%x\n", readl(&power_regs->hw_power_minpwr));
+	debug("charge:\t\t 0x%x\n", readl(&power_regs->hw_power_charge));
+	debug("vddctrl:\t 0x%x\n", readl(&power_regs->hw_power_vdddctrl));
+	debug("vddactrl:\t 0x%x\n", readl(&power_regs->hw_power_vddactrl));
+	debug("vddioctrl:\t 0x%x\n", readl(&power_regs->hw_power_vddioctrl));
+	debug("vddmemctrl:\t 0x%x\n", readl(&power_regs->hw_power_vddmemctrl));
+	debug("dcdc4p2:\t 0x%x\n", readl(&power_regs->hw_power_dcdc4p2));
+	debug("misc:\t\t 0x%x\n", readl(&power_regs->hw_power_misc));
+	debug("dclimits:\t 0x%x\n", readl(&power_regs->hw_power_dclimits));
+	debug("loopctrl:\t 0x%x\n", readl(&power_regs->hw_power_loopctrl));
+	debug("sts:\t\t 0x%x\n", readl(&power_regs->hw_power_sts));
+	debug("speed:\t\t 0x%x\n", readl(&power_regs->hw_power_speed));
+	debug("battmonitor:\t 0x%x\n",
+	      readl(&power_regs->hw_power_battmonitor));
+}
+
 /**
  * mxs_power_clock2pll() - Switch CPU core clock source to PLL
  *
@@ -752,7 +775,19 @@
 		POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
 		0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET);
 
-	mxs_power_enable_4p2();
+	if (CONFIG_IS_ENABLED(MXS_PMU_MINIMAL_VDD5V_CURRENT))
+		setbits_le32(&power_regs->hw_power_5vctrl,
+			     POWER_5VCTRL_ILIMIT_EQ_ZERO);
+
+	if (CONFIG_IS_ENABLED(MXS_PMU_DISABLE_BATT_CHARGE)) {
+		writel(POWER_CHARGE_PWD_BATTCHRG,
+		       &power_regs->hw_power_charge_set);
+		writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
+		       &power_regs->hw_power_5vctrl_set);
+	}
+
+	if (CONFIG_IS_ENABLED(MXS_PMU_ENABLE_4P2_LINEAR_REGULATOR))
+		mxs_power_enable_4p2();
 }
 
 /**
@@ -1268,6 +1303,7 @@
 		POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr);
 
 	writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set);
+	mxs_power_regs_dump();
 
 	early_delay(1000);
 }
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 17f506a..07b26df 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -305,7 +305,8 @@
 	cn9132-db-B.dtb				\
 	cn9130-crb-A.dtb			\
 	cn9130-crb-B.dtb			\
-	ac5-98dx35xx-rd.dtb
+	ac5-98dx35xx-rd.dtb			\
+	ac5-98dx35xx-atl-x240.dtb
 endif
 
 dtb-$(CONFIG_ARCH_SYNQUACER) += synquacer-sc2a11-developerbox.dtb
@@ -1017,6 +1018,7 @@
 	imx8mp-phyboard-pollux-rdk.dtb \
 	imx8mp-venice.dtb \
 	imx8mp-venice-gw74xx.dtb \
+	imx8mp-venice-gw7905-2x.dtb \
 	imx8mp-verdin-wifi-dev.dtb \
 	imx8mq-pico-pi.dtb \
 	imx8mq-kontron-pitx-imx8m.dtb \
diff --git a/arch/arm/dts/ac5-98dx25xx.dtsi b/arch/arm/dts/ac5-98dx25xx.dtsi
index 3c68355..f53b478 100644
--- a/arch/arm/dts/ac5-98dx25xx.dtsi
+++ b/arch/arm/dts/ac5-98dx25xx.dtsi
@@ -251,6 +251,15 @@
 			status = "disabled";
 		};
 
+		nand: nand-controller@805b0000 {
+			compatible = "marvell,mvebu-ac5-pxa3xx-nand";
+			reg = <0x0 0x805b0000 0x0 0x54>;
+			#address-cells = <0x00000001>;
+			marvell,nand-enable-arbiter;
+			num-cs = <0x00000001>;
+			status = "disabled";
+		};
+
 		gic: interrupt-controller@80600000 {
 			compatible = "arm,gic-v3";
 			#interrupt-cells = <3>;
diff --git a/arch/arm/dts/ac5-98dx35xx-atl-x240.dts b/arch/arm/dts/ac5-98dx35xx-atl-x240.dts
new file mode 100644
index 0000000..820ec18
--- /dev/null
+++ b/arch/arm/dts/ac5-98dx35xx-atl-x240.dts
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "ac5-98dx35xx.dtsi"
+
+/ {
+	model = "Allied Telesis x240";
+	compatible = "alliedtelesis,x240", "marvell,ac5x", "marvell,ac5";
+
+	aliases {
+		serial0 = &uart0;
+		spiflash0 = &spiflash0;
+		gpio0 = &gpio0;
+		gpio1 = &gpio1;
+		spi0 = &spi0;
+		i2c0 = &i2c0;
+		usb0 = &usb0;
+		pinctrl0 = &pinctrl0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	boot-board {
+		compatible = "atl,boot-board";
+		present-gpio = <&gpio1 6 GPIO_ACTIVE_HIGH>;
+		override-gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		fault {
+			label = "fault:red";
+			gpios = <&system_gpio 11 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+	};
+};
+
+&nand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&nand_pins>;
+
+	nand-ecc-strength = <4>;
+	nand-ecc-step-size = <512>;
+	status = "okay";
+
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		partition@user {
+			reg = <0x00000000 0x10000000>;
+			label = "user";
+		};
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&usb0 {
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+
+	mux@71 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "nxp,pca9546";
+		reg = <0x71>;
+		i2c-mux-idle-disconnect;
+		reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;               /* MPP36 */
+		status = "okay";
+
+		i2c@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			hwmon@2e {
+				compatible = "adi,adt7476";
+				reg = <0x2e>;
+			};
+
+			rtc@68 {
+				compatible = "adi,max31331";
+				reg = <0x68>;
+			};
+
+			system_gpio: gpio@27 {
+				compatible = "nxp,pca9555";
+				gpio-controller;
+				#gpio-cells= <2>;
+				reg = <0x27>;
+				interrupt-parent = <&gpio0>;
+				interrupts = <25 IRQ_TYPE_LEVEL_LOW>;   /* MPP25 */
+			};
+		};
+	};
+};
+
+&spi0 {
+	status = "okay";
+	spiflash0: flash@0 {
+		compatible = "jedec,spi-nor";
+		spi-max-frequency = <50000000>;
+		spi-tx-bus-width = <1>; /* 1-single, 2-dual, 4-quad */
+		spi-rx-bus-width = <1>; /* 1-single, 2-dual, 4-quad */
+		reg = <0>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+	};
+};
+
+&gpio0 {
+	phy-reset {
+		gpio-hog;
+		gpios = <19 GPIO_ACTIVE_LOW>;
+		output-high;
+		line-name = "phy-reset";
+	};
+
+	usb-en {
+		gpio-hog;
+		gpios = <28 GPIO_ACTIVE_HIGH>;
+		output-high;
+		line-name = "usb-en";
+	};
+
+	led-oe-n {
+		gpio-hog;
+		gpios = <23 GPIO_ACTIVE_LOW>;
+		output-low;
+		line-name = "led-oe-n";
+	};
+};
+
+&gpio1 {
+	nand-protect {
+		gpio-hog;
+		gpios = <8 GPIO_ACTIVE_LOW>;
+		output-low;
+		line-name = "nand-protect";
+	};
+};
+
+&pinctrl0 {
+	/*
+	 * MPP Bus:              MPP#
+	 * NF_IO                 [0-7]
+	 * NF_Wen                [8]
+	 * NF_ALE                [9]
+	 * NF_CLE                [10]
+	 * NF_Cen                [11]
+	 * QSPI_SCK/SPI0_SCK     [12]
+	 * QSPI_CSn/SPI0_CSn     [13]
+	 * QSPI_DIO[0]/SPI0_MOSI [14]
+	 * QSPI_DIO[1]/SPI0_MISO [15]
+	 * NF_Ren                [16]
+	 * NF_RBn                [17]
+	 * WD_INTn               [18]
+	 * B_B_OVRIDE_N          [19]
+	 * GREEN_SW_N            [20]
+	 * PHY_INT_N[0]          [21]
+	 * SPI_WPn               [22]
+	 * LED_OE_N              [23]
+	 * USB_PWR_FLT_N         [24]
+	 * SFP_INT_N             [25]
+	 * I2C0_SCL              [26]
+	 * I2C0_SDA              [27]
+	 * USB_EN                [28]
+	 * MONITOR_INT_N         [29]
+	 * XM1_MDC               [30]
+	 * XM1_MDIO              [31]
+	 * UA0_RXD               [32]
+	 * UA0_TXD               [33]
+	 * PHY_RST0n             [34]
+	 * TPM_INT_N             [35]
+	 * I2CMUX_RESET_N        [36]
+	 * SPI_SRAM_SEL_N        [37]
+	 * B_B_PRESENT           [38]
+	 * SPI_FLASH_SEL_N       [39]
+	 * NF_WP_N               [40]
+	 * POE_INT_N             [41]
+	 * PoE_RST_N             [42]
+	 * LED0_CLK              [43]
+	 * LED0_STB              [44]
+	 * LED0_DATA             [45]
+	 */
+	/*	     0    1    2    3    4    5    6    7    8    9 */
+	pin-func = < 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
+		     0xff 0xff 1    1    1    1    0xff 0xff 0    0
+		     0    0    0    0    0    0    1    1    0    0
+		     1    1    1    1    0    0    0    0    0    0
+		     0    0    0    1    1    1    >;
+
+	nand_pins: nand-pins {
+		marvell,pins = <0 1 2 3 4 5 6 7 8 9 10 11 16 17>;
+		marvell,function = <2>;
+	};
+};
diff --git a/arch/arm/dts/ac5-98dx35xx-rd.dts b/arch/arm/dts/ac5-98dx35xx-rd.dts
index d9f217c..1dc85bb 100644
--- a/arch/arm/dts/ac5-98dx35xx-rd.dts
+++ b/arch/arm/dts/ac5-98dx35xx-rd.dts
@@ -31,7 +31,6 @@
 		usb0 = &usb0;
 		usb1 = &usb1;
 		pinctrl0 = &pinctrl0;
-		sar-reg0 = "/config-space/sar-reg";
 	};
 
 	usb1phy: usb-phy {
diff --git a/arch/arm/dts/armada-385-thecus-n2350.dts b/arch/arm/dts/armada-385-thecus-n2350.dts
index fc29c4d..253cf01 100644
--- a/arch/arm/dts/armada-385-thecus-n2350.dts
+++ b/arch/arm/dts/armada-385-thecus-n2350.dts
@@ -23,7 +23,7 @@
 		stdout-path = "serial0:115200n8";
 	};
 
-	memory {
+	memory@0 {
 		device_type = "memory";
 		reg = <0x00000000 0x40000000>; /* 1GB */
 	};
@@ -37,43 +37,43 @@
 
 	};
 
-	usb3_0_phy: usb3_0_phy {
+	usb3_0_phy: usb-phy {
 		compatible = "usb-nop-xceiv";
 		vcc-supply = <&usb3_0_power>;
+		 #phy-cells = <0>;
 	};
 
-	usb3_1_phy: usb3_1_phy {
+	usb3_1_phy: usb-phy {
 		compatible = "usb-nop-xceiv";
 		vcc-supply = <&usb3_1_power>;
+		 #phy-cells = <0>;
 	};
 
-	gpio-keys {
+	keys {
 		compatible = "gpio-keys";
-		#address-cells = <1>;
-		#size-cells = <0>;
 		pinctrl-0 = <&pmx_power_button &pmx_copy_button &pmx_reset_button>;
 		pinctrl-names = "default";
 
-		button@1 {
+		button-1 {
 			label = "Power Button";
 			linux,code = <KEY_POWER>;
 			gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
 		};
 
-		button@2 {
+		button-2 {
 			label = "Copy Button";
 			linux,code = <KEY_COPY>;
 			gpios = <&gpio1 20 GPIO_ACTIVE_HIGH>;
 		};
 
-		button@3 {
+		button-3 {
 			label = "Reset Button";
 			linux,code = <KEY_RESTART>;
 			gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
-	gpio-leds {
+	leds {
 		compatible = "gpio-leds";
 		pinctrl-0 = <&pmx_sata1_white_led
 				&pmx_sata1_red_led
@@ -88,142 +88,142 @@
 
 		pinctrl-names = "default";
 
-		white_sata1 {
+		led-1 {
 			label = "n2350:white:sata1";
 			gpios = <&gpio0 20 GPIO_ACTIVE_HIGH>;
-			linux,default-trigger = "ide-disk1";
 		};
 
-		red_sata1 {
+		led-2 {
 			label = "n2350:red:sata1";
 			gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
 		};
 
-		white-sata2 {
+		led-3 {
 			label = "n2350:white:sata2";
 			gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>;
 		};
 
-		red-sata2 {
+		led-4 {
 			label = "n2350:red:sata2";
 			gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
 		};
 
-		white-sys {
+		led-5 {
 			label = "n2350:white:sys";
 			gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>;
 			linux,default-trigger = "default-on";
 		};
 
-		red-sys {
+		led-6 {
 			label = "n2350:red:sys";
 			gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>;
 		};
 
-		blue-pwr {
+		led-7 {
 			label = "n2350:blue:pwr";
 			gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
 		};
 
-		red-pwr {
+		led-8 {
 			label = "n2350:red:pwr";
 			gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>;
 		};
 
-		white-usb {
+		led-9 {
 			label = "n2350:white:usb";
 			gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
 		};
 
-		red-usb {
+		led-10 {
 			label = "n2350:red:usb";
 			gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>;
 		};
 	};
 
-	regulators {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		usb3_0_power: regulator@1 {
-			compatible = "regulator-fixed";
-			reg = <1>;
-			regulator-name = "USB3_0_Power";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			enable-active-high;
-			regulator-always-on;
-			regulator-boot-on;
-			gpio = <&gpio0 21 GPIO_ACTIVE_HIGH>;
-		};
+	fan {
+		compatible = "gpio-fan";
+		gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>;
+		gpio-fan,speed-map = <	  0  0
+					600  1
+					3000 2 >;
+		pinctrl-0 = <&pmx_fan>;
+		pinctrl-names = "default";
+	};
 
-		usb3_1_power: regulator@2 {
-			compatible = "regulator-fixed";
-			reg = <1>;
-			regulator-name = "USB3_1_Power";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			enable-active-high;
-			regulator-always-on;
-			regulator-boot-on;
-			gpio = <&gpio0 24 GPIO_ACTIVE_HIGH>;
-		};
+	usb3_0_power: v5-vbus0 {
+		compatible = "regulator-fixed";
+		regulator-name = "USB3_0_Power";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		regulator-always-on;
+		regulator-boot-on;
+		gpio = <&gpio0 21 GPIO_ACTIVE_HIGH>;
+	};
 
-		reg_sata0: regulator@3 {
-			compatible = "regulator-fixed";
-			regulator-name = "pwr_en_sata0";
-			regulator-min-microvolt = <12000000>;
-			regulator-max-microvolt = <12000000>;
-			enable-active-high;
-			regulator-always-on;
-			regulator-boot-on;
-			gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
-		};
+	usb3_1_power: v5-vbus1 {
+		compatible = "regulator-fixed";
+		regulator-name = "USB3_1_Power";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		enable-active-high;
+		regulator-always-on;
+		regulator-boot-on;
+		gpio = <&gpio0 24 GPIO_ACTIVE_HIGH>;
+	};
 
-		reg_5v_sata0: v5-sata0 {
-			compatible = "regulator-fixed";
-			regulator-name = "v5.0-sata0";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			vin-supply = <&reg_sata0>;
-		};
+	reg_sata0: pwr-sata0 {
+		compatible = "regulator-fixed";
+		regulator-name = "pwr_en_sata0";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		enable-active-high;
+		regulator-always-on;
+		regulator-boot-on;
+		gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+	};
 
-		reg_12v_sata0: v12-sata0 {
-			compatible = "regulator-fixed";
-			regulator-name = "v12.0-sata0";
-			regulator-min-microvolt = <12000000>;
-			regulator-max-microvolt = <12000000>;
-			vin-supply = <&reg_sata0>;
-		};
+	reg_5v_sata0: v5-sata0 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-sata0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&reg_sata0>;
+	};
 
-		reg_sata1: regulator@4 {
-			regulator-name = "pwr_en_sata1";
-			compatible = "regulator-fixed";
-			regulator-min-microvolt = <12000000>;
-			regulator-max-microvolt = <12000000>;
-			enable-active-high;
-			regulator-always-on;
-			regulator-boot-on;
-			gpio = <&gpio1 13 GPIO_ACTIVE_HIGH>;
-		};
+	reg_12v_sata0: v12-sata0 {
+		compatible = "regulator-fixed";
+		regulator-name = "v12.0-sata0";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		vin-supply = <&reg_sata0>;
+	};
 
-		reg_5v_sata1: v5-sata1 {
-			compatible = "regulator-fixed";
-			regulator-name = "v5.0-sata1";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			vin-supply = <&reg_sata1>;
-		};
+	reg_sata1: pwr-sata0 {
+		regulator-name = "pwr_en_sata1";
+		compatible = "regulator-fixed";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		enable-active-high;
+		regulator-always-on;
+		regulator-boot-on;
+		gpio = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+	};
 
-		reg_12v_sata1: v12-sata1 {
-			compatible = "regulator-fixed";
-			regulator-name = "v12.0-sata1";
-			regulator-min-microvolt = <12000000>;
-			regulator-max-microvolt = <12000000>;
-			vin-supply = <&reg_sata1>;
-		};
+	reg_5v_sata1: v5-sata1 {
+		compatible = "regulator-fixed";
+		regulator-name = "v5.0-sata1";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&reg_sata1>;
+	};
 
+	reg_12v_sata1: v12-sata1 {
+		compatible = "regulator-fixed";
+		regulator-name = "v12.0-sata1";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		vin-supply = <&reg_sata1>;
 	};
 
 	gpio-poweroff {
@@ -267,7 +267,7 @@
 };
 
 &mdio {
-	phy0: ethernet-phy@0 {
+	phy0: ethernet-phy@1 {
 		reg = <1>;
 	};
 };
@@ -301,20 +301,16 @@
 
 &pciec {
 	status = "okay";
-	/*
-	 * The two PCIe units are accessible through
-	 * standard PCIe slots on the board.
-	 */
-	pcie@1,0 {
-		/* Port 0, Lane 0 */
-		status = "okay";
-	};
-	pcie@2,0 {
-		/* Port 1, Lane 0 */
-		status = "okay";
-	};
 };
 
+&pcie1 {
+	status = "okay";
+};
+
+&pcie2 {
+	status = "okay";
+};
+
 &pinctrl {
 	pinctrl-names = "default";
 
@@ -392,6 +388,11 @@
 		marvell,pins = "mpp17";
 		marvell,function = "gpio";
 	};
+
+	pmx_fan: pmx-fan {
+		marvell,pins = "mpp48";
+		marvell,function = "gpio";
+	};
 };
 
 &sdhci {
@@ -408,10 +409,10 @@
 	status = "okay";
 
 	/* spi: 4M Flash Macronix MX25L3205D */
-	spi-flash@0 {
+	flash@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
-		compatible = "macronix,mx25l3205d", "jedec,spi-nor";
+		compatible = "jedec,spi-nor";
 		reg = <0>;
 
 		spi-max-frequency = <108000000>;
diff --git a/arch/arm/dts/imx28-xea-u-boot.dtsi b/arch/arm/dts/imx28-xea-u-boot.dtsi
index f648815..bdbeca5 100644
--- a/arch/arm/dts/imx28-xea-u-boot.dtsi
+++ b/arch/arm/dts/imx28-xea-u-boot.dtsi
@@ -12,6 +12,11 @@
  */
 #include "imx28-u-boot.dtsi"
 / {
+	aliases {
+		/delete-property/ spi1;
+		/delete-property/ usbphy0;
+		/delete-property/ usbphy1;
+	};
 	apb@80000000 {
 		bootph-pre-ram;
 
@@ -27,16 +32,47 @@
 
 &clks {
 	bootph-pre-ram;
+	status = "disable";
+};
+
+&duart {
+	/delete-property/ clocks;
+	bootph-pre-ram;
+	type = <1>; /* TYPE_PL011 */
 };
 
 &gpio0 {
 	bootph-pre-ram;
 };
 
+&mac0 {
+	phy-mode = "rmii";
+	pinctrl-names = "default";
+	pinctrl-0 = <&mac0_pins_a>;
+	phy-supply = <&reg_fec_3v3>;
+	phy-reset-gpios = <&gpio2 13 GPIO_ACTIVE_LOW>;
+	phy-reset-duration = <1>;
+	phy-reset-post-delay = <1>;
+	status = "okay";
+
+	fixed-link {
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &pinctrl {
+	/delete-property/ pinctrl-names;
+	/delete-property/ pinctrl-0;
 	bootph-pre-ram;
 };
 
+&reg_fec_3v3 {
+	gpio = <&gpio0 0 GPIO_ACTIVE_HIGH>;
+	enable-active-high;
+	regulator-boot-on;
+};
+
 &ssp0 {
 	bootph-pre-ram;
 };
@@ -46,3 +82,12 @@
 	spi-max-frequency = <40000000>;
 	bootph-pre-ram;
 };
+
+/delete-node/ &ssp2;
+/delete-node/ &usb0;
+/delete-node/ &usbphy0;
+/delete-node/ &usb1;
+/delete-node/ &usbphy1;
+/delete-node/ &hog_pins_a;
+/delete-node/ &hog_pins_tiva;
+/delete-node/ &hog_pins_coding;
diff --git a/arch/arm/dts/imx8mm-beacon-kit-u-boot.dtsi b/arch/arm/dts/imx8mm-beacon-kit-u-boot.dtsi
index fd0061f..00abbeb 100644
--- a/arch/arm/dts/imx8mm-beacon-kit-u-boot.dtsi
+++ b/arch/arm/dts/imx8mm-beacon-kit-u-boot.dtsi
@@ -6,6 +6,10 @@
 #include "imx8mm-u-boot.dtsi"
 
 / {
+	aliases {
+		spi0 = &flexspi;
+	};
+
 	wdt-reboot {
 		compatible = "wdt-reboot";
 		wdt = <&wdog1>;
diff --git a/arch/arm/dts/imx8mm-mx8menlo.dts b/arch/arm/dts/imx8mm-mx8menlo.dts
index 32f6f2f..0b123a8 100644
--- a/arch/arm/dts/imx8mm-mx8menlo.dts
+++ b/arch/arm/dts/imx8mm-mx8menlo.dts
@@ -10,6 +10,7 @@
 / {
 	model = "MENLO MX8MM EMBEDDED DEVICE";
 	compatible = "menlo,mx8menlo",
+		     "toradex,verdin-imx8mm-nonwifi",
 		     "toradex,verdin-imx8mm",
 		     "fsl,imx8mm";
 
@@ -250,21 +251,21 @@
 		/* SODIMM 96 */
 		MX8MM_IOMUXC_SAI1_RXD2_GPIO4_IO4			0x1c4
 		/* CPLD_D[7] */
-		MX8MM_IOMUXC_SAI1_RXD3_GPIO4_IO5			0x1c4
+		MX8MM_IOMUXC_SAI1_RXD3_GPIO4_IO5			0x184
 		/* CPLD_D[6] */
-		MX8MM_IOMUXC_SAI1_RXFS_GPIO4_IO0			0x1c4
+		MX8MM_IOMUXC_SAI1_RXFS_GPIO4_IO0			0x184
 		/* CPLD_D[5] */
-		MX8MM_IOMUXC_SAI1_TXC_GPIO4_IO11			0x1c4
+		MX8MM_IOMUXC_SAI1_TXC_GPIO4_IO11			0x184
 		/* CPLD_D[4] */
-		MX8MM_IOMUXC_SAI1_TXD0_GPIO4_IO12			0x1c4
+		MX8MM_IOMUXC_SAI1_TXD0_GPIO4_IO12			0x184
 		/* CPLD_D[3] */
-		MX8MM_IOMUXC_SAI1_TXD1_GPIO4_IO13			0x1c4
+		MX8MM_IOMUXC_SAI1_TXD1_GPIO4_IO13			0x184
 		/* CPLD_D[2] */
-		MX8MM_IOMUXC_SAI1_TXD2_GPIO4_IO14			0x1c4
+		MX8MM_IOMUXC_SAI1_TXD2_GPIO4_IO14			0x184
 		/* CPLD_D[1] */
-		MX8MM_IOMUXC_SAI1_TXD3_GPIO4_IO15			0x1c4
+		MX8MM_IOMUXC_SAI1_TXD3_GPIO4_IO15			0x184
 		/* CPLD_D[0] */
-		MX8MM_IOMUXC_SAI1_TXD4_GPIO4_IO16			0x1c4
+		MX8MM_IOMUXC_SAI1_TXD4_GPIO4_IO16			0x184
 		/* KBD_intK */
 		MX8MM_IOMUXC_SAI2_MCLK_GPIO4_IO27			0x1c4
 		/* DISP_reset */
diff --git a/arch/arm/dts/imx8mm-verdin-dahlia.dtsi b/arch/arm/dts/imx8mm-verdin-dahlia.dtsi
deleted file mode 100644
index c2a5c2f..0000000
--- a/arch/arm/dts/imx8mm-verdin-dahlia.dtsi
+++ /dev/null
@@ -1,150 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/*
- * Copyright 2022 Toradex
- */
-
-/ {
-	sound_card: sound-card {
-		compatible = "simple-audio-card";
-		simple-audio-card,bitclock-master = <&dailink_master>;
-		simple-audio-card,format = "i2s";
-		simple-audio-card,frame-master = <&dailink_master>;
-		simple-audio-card,name = "imx8mm-wm8904";
-		simple-audio-card,routing =
-			"Headphone Jack", "HPOUTL",
-			"Headphone Jack", "HPOUTR",
-			"IN2L", "Line In Jack",
-			"IN2R", "Line In Jack",
-			"Headphone Jack", "MICBIAS",
-			"IN1L", "Headphone Jack";
-		simple-audio-card,widgets =
-			"Microphone", "Headphone Jack",
-			"Headphone", "Headphone Jack",
-			"Line", "Line In Jack";
-
-		dailink_master: simple-audio-card,codec {
-			clocks = <&clk IMX8MM_CLK_SAI2_ROOT>;
-			sound-dai = <&wm8904_1a>;
-		};
-
-		simple-audio-card,cpu {
-			sound-dai = <&sai2>;
-		};
-	};
-};
-
-/* Verdin SPI_1 */
-&ecspi2 {
-	status = "okay";
-};
-
-/* EEPROM on display adapter boards */
-&eeprom_display_adapter {
-	status = "okay";
-};
-
-/* EEPROM on Verdin Development board */
-&eeprom_carrier_board {
-	status = "okay";
-};
-
-&fec1 {
-	status = "okay";
-};
-
-/* Verdin QSPI_1 */
-&flexspi {
-	status = "okay";
-};
-
-/* Current measurement into module VCC */
-&hwmon {
-	status = "okay";
-};
-
-&hwmon_temp {
-	vs-supply = <&reg_1p8v>;
-	status = "okay";
-};
-
-&i2c3 {
-	status = "okay";
-};
-
-/* Verdin I2C_1 */
-&i2c4 {
-	status = "okay";
-
-	/* Audio Codec */
-	wm8904_1a: audio-codec@1a {
-		compatible = "wlf,wm8904";
-		AVDD-supply = <&reg_3p3v>;
-		clocks = <&clk IMX8MM_CLK_SAI2_ROOT>;
-		clock-names = "mclk";
-		CPVDD-supply = <&reg_3p3v>;
-		DBVDD-supply = <&reg_3p3v>;
-		DCVDD-supply = <&reg_3p3v>;
-		MICVDD-supply = <&reg_3p3v>;
-		reg = <0x1a>;
-		#sound-dai-cells = <0>;
-	};
-};
-
-/* Verdin PCIE_1 */
-&pcie0 {
-	status = "okay";
-};
-
-&pcie_phy {
-	status = "okay";
-};
-
-/* Verdin PWM_3_DSI */
-&pwm1 {
-	status = "okay";
-};
-
-/* Verdin PWM_1 */
-&pwm2 {
-	status = "okay";
-};
-
-/* Verdin PWM_2 */
-&pwm3 {
-	status = "okay";
-};
-
-/* Verdin I2S_1 */
-&sai2 {
-	status = "okay";
-};
-
-/* Verdin UART_3 */
-&uart1 {
-	status = "okay";
-};
-
-/* Verdin UART_1 */
-&uart2 {
-	status = "okay";
-};
-
-/* Verdin UART_2 */
-&uart3 {
-	status = "okay";
-};
-
-/* Verdin USB_1 */
-&usbotg1 {
-	status = "okay";
-};
-
-/* Verdin USB_2 */
-&usbotg2 {
-	status = "okay";
-};
-
-/* Verdin SD_1 */
-&usdhc2 {
-	status = "okay";
-};
diff --git a/arch/arm/dts/imx8mm-verdin-dev.dtsi b/arch/arm/dts/imx8mm-verdin-dev.dtsi
index 73cc3fa..3c4b8ca 100644
--- a/arch/arm/dts/imx8mm-verdin-dev.dtsi
+++ b/arch/arm/dts/imx8mm-verdin-dev.dtsi
@@ -3,14 +3,13 @@
  * Copyright 2022 Toradex
  */
 
-#include "imx8mm-verdin-dahlia.dtsi"
-
 / {
 	sound_card: sound-card {
 		compatible = "simple-audio-card";
 		simple-audio-card,bitclock-master = <&dailink_master>;
 		simple-audio-card,format = "i2s";
 		simple-audio-card,frame-master = <&dailink_master>;
+		simple-audio-card,mclk-fs = <256>;
 		simple-audio-card,name = "imx8mm-nau8822";
 		simple-audio-card,routing =
 			"Headphones", "LHP",
@@ -41,27 +40,121 @@
 	};
 };
 
+/* Verdin SPI_1 */
+&ecspi2 {
+	status = "okay";
+};
+
+/* EEPROM on display adapter boards */
+&eeprom_display_adapter {
+	status = "okay";
+};
+
+/* EEPROM on Verdin Development board */
+&eeprom_carrier_board {
+	status = "okay";
+};
+
+&fec1 {
+	status = "okay";
+};
+
+/* Verdin QSPI_1 */
+&flexspi {
+	status = "okay";
+};
+
+/* Current measurement into module VCC */
+&hwmon {
+	status = "okay";
+};
+
+&hwmon_temp {
+	vs-supply = <&reg_1p8v>;
+	status = "okay";
+};
+
+&i2c3 {
+	status = "okay";
+};
+
 &gpio_expander_21 {
 	status = "okay";
 };
 
 /* Verdin I2C_1 */
 &i2c4 {
+	status = "okay";
+
 	/* Audio Codec */
 	nau8822_1a: audio-codec@1a {
 		compatible = "nuvoton,nau8822";
 		reg = <0x1a>;
+		#sound-dai-cells = <0>;
 	};
 };
 
+/* Verdin PCIE_1 */
+&pcie0 {
+	status = "okay";
+};
+
+&pcie_phy {
+	status = "okay";
+};
+
+/* Verdin PWM_3_DSI */
+&pwm1 {
+	status = "okay";
+};
+
+/* Verdin PWM_1 */
+&pwm2 {
+	status = "okay";
+};
+
+/* Verdin PWM_2 */
+&pwm3 {
+	status = "okay";
+};
+
+/* Verdin I2S_1 */
+&sai2 {
+	status = "okay";
+};
+
+/* Verdin UART_3 */
+&uart1 {
+	status = "okay";
+};
+
 /* Verdin UART_1, connector X50 through RS485 transceiver */
 &uart2 {
 	linux,rs485-enabled-at-boot-time;
 	rs485-rts-active-low;
 	rs485-rx-during-tx;
+	status = "okay";
+};
+
+/* Verdin UART_2 */
+&uart3 {
+	status = "okay";
 };
 
+/* Verdin USB_1 */
+&usbotg1 {
+	disable-over-current;
+	status = "okay";
+};
+
+/* Verdin USB_2 */
+&usbotg2 {
+	disable-over-current;
+	status = "okay";
+};
+
 /* Limit frequency on dev board due to long traces and bad signal integrity */
 &usdhc2 {
 	max-frequency = <100000000>;
+	status = "okay";
 };
diff --git a/arch/arm/dts/imx8mm-verdin-wifi-dev-u-boot.dtsi b/arch/arm/dts/imx8mm-verdin-wifi-dev-u-boot.dtsi
index 494229e..2b268f5 100644
--- a/arch/arm/dts/imx8mm-verdin-wifi-dev-u-boot.dtsi
+++ b/arch/arm/dts/imx8mm-verdin-wifi-dev-u-boot.dtsi
@@ -56,6 +56,10 @@
 
 &gpio5 {
 	bootph-pre-ram;
+
+	ctrl-sleep-moci-hog {
+		bootph-pre-ram;
+	};
 };
 
 &i2c1 {
@@ -88,6 +92,10 @@
 	};
 };
 
+&pinctrl_ctrl_sleep_moci {
+	bootph-pre-ram;
+};
+
 &pinctrl_i2c1 {
 	bootph-pre-ram;
 };
diff --git a/arch/arm/dts/imx8mm-verdin.dtsi b/arch/arm/dts/imx8mm-verdin.dtsi
index bcab830..6f08115 100644
--- a/arch/arm/dts/imx8mm-verdin.dtsi
+++ b/arch/arm/dts/imx8mm-verdin.dtsi
@@ -3,8 +3,8 @@
  * Copyright 2022 Toradex
  */
 
-#include "dt-bindings/phy/phy-imx8-pcie.h"
-#include "dt-bindings/pwm/pwm.h"
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+#include <dt-bindings/pwm/pwm.h>
 #include "imx8mm.dtsi"
 
 / {
@@ -56,7 +56,11 @@
 	hdmi_connector: hdmi-connector {
 		compatible = "hdmi-connector";
 		ddc-i2c-bus = <&i2c2>;
+		/* Verdin PWM_3_DSI (SODIMM 19) */
+		hpd-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>;
 		label = "hdmi";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pwm_3_dsi_hpd_gpio>;
 		type = "a";
 		status = "disabled";
 	};
@@ -95,9 +99,10 @@
 		compatible = "regulator-fixed";
 		enable-active-high;
 		gpio = <&gpio2 20 GPIO_ACTIVE_HIGH>; /* PMIC_EN_ETH */
-		off-on-delay = <500000>;
+		off-on-delay-us = <500000>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_reg_eth>;
+		regulator-always-on;
 		regulator-boot-on;
 		regulator-max-microvolt = <3300000>;
 		regulator-min-microvolt = <3300000>;
@@ -134,7 +139,7 @@
 		enable-active-high;
 		/* Verdin SD_1_PWR_EN (SODIMM 76) */
 		gpio = <&gpio3 5 GPIO_ACTIVE_HIGH>;
-		off-on-delay = <100000>;
+		off-on-delay-us = <100000>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_usdhc2_pwr_en>;
 		regulator-max-microvolt = <3300000>;
@@ -183,15 +188,15 @@
 	ddrc_opp_table: opp-table {
 		compatible = "operating-points-v2";
 
-		opp-25M {
+		opp-25000000 {
 			opp-hz = /bits/ 64 <25000000>;
 		};
 
-		opp-100M {
+		opp-100000000 {
 			opp-hz = /bits/ 64 <100000000>;
 		};
 
-		opp-750M {
+		opp-750000000 {
 			opp-hz = /bits/ 64 <750000000>;
 		};
 	};
@@ -358,7 +363,6 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_pmic>;
 		reg = <0x25>;
-		sd-vsel-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
 
 		/*
 		 * The bootloader is expected to switch on the I2C level shifter for the TLA2024 ADC
@@ -598,7 +602,7 @@
 	hdmi_lontium_lt8912: hdmi@48 {
 		compatible = "lontium,lt8912b";
 		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_gpio_10_dsi>, <&pinctrl_pwm_3_dsi_hpd_gpio>;
+		pinctrl-0 = <&pinctrl_gpio_10_dsi>;
 		reg = <0x48>;
 		/* Verdin GPIO_9_DSI (LT8912 INT, SODIMM 17, unused) */
 		/* Verdin GPIO_10_DSI (SODIMM 21) */
@@ -610,7 +614,7 @@
 		compatible = "atmel,maxtouch";
 		/*
 		 * Verdin GPIO_9_DSI
-		 * (TOUCH_INT#, SODIMM 17, also routed to SN65DSI83 IRQ albeit currently unused)
+		 * (TOUCH_INT#, SODIMM 17, also routed to SN65DSI84 IRQ albeit currently unused)
 		 */
 		interrupt-parent = <&gpio3>;
 		interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
@@ -653,9 +657,6 @@
 	assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_50M>,
 				 <&clk IMX8MM_SYS_PLL2_250M>;
 	assigned-clock-rates = <10000000>, <250000000>;
-	clocks = <&clk IMX8MM_CLK_PCIE1_ROOT>, <&clk IMX8MM_CLK_PCIE1_AUX>,
-		 <&clk IMX8MM_CLK_PCIE1_PHY>;
-	clock-names = "pcie", "pcie_aux", "pcie_bus";
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_pcie0>;
 	/* PCIE_1_RESET# (SODIMM 244) */
@@ -664,6 +665,7 @@
 
 &pcie_phy {
 	clocks = <&clk IMX8MM_CLK_PCIE1_PHY>;
+	clock-names = "ref";
 	fsl,clkreq-unsupported;
 	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
 	fsl,tx-deemph-gen1 = <0x2d>;
@@ -739,7 +741,6 @@
 	adp-disable;
 	dr_mode = "otg";
 	hnp-disable;
-	over-current-active-low;
 	samsung,picophy-dc-vol-level-adjust = <7>;
 	samsung,picophy-pre-emp-curr-control = <3>;
 	srp-disable;
@@ -749,7 +750,6 @@
 /* Verdin USB_2 */
 &usbotg2 {
 	dr_mode = "host";
-	over-current-active-low;
 	samsung,picophy-dc-vol-level-adjust = <7>;
 	samsung,picophy-pre-emp-curr-control = <3>;
 	vbus-supply = <&reg_usb_otg2_vbus>;
diff --git a/arch/arm/dts/imx8mn-var-som-symphony-u-boot.dtsi b/arch/arm/dts/imx8mn-var-som-symphony-u-boot.dtsi
index af80aae..e0caf31 100644
--- a/arch/arm/dts/imx8mn-var-som-symphony-u-boot.dtsi
+++ b/arch/arm/dts/imx8mn-var-som-symphony-u-boot.dtsi
@@ -13,6 +13,19 @@
 	bootph-pre-ram;
 };
 
+&eeprom_som {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	eth_mac_address: eth-mac-address@19 {
+		reg = <0x19 0x06>;
+	};
+};
+
+&fec1 {
+	nvmem-cells = <&eth_mac_address>;
+	nvmem-cell-names = "mac-address";
+};
+
 &gpio1 {
 	bootph-pre-ram;
 };
@@ -68,3 +81,7 @@
 &usdhc3 {
 	bootph-pre-ram;
 };
+
+&eeprom_som {
+	bootph-pre-ram;
+};
diff --git a/arch/arm/dts/imx8mn-var-som-symphony.dts b/arch/arm/dts/imx8mn-var-som-symphony.dts
index 3ed7021..5c8e4e8 100644
--- a/arch/arm/dts/imx8mn-var-som-symphony.dts
+++ b/arch/arm/dts/imx8mn-var-som-symphony.dts
@@ -56,10 +56,6 @@
 	};
 };
 
-&ethphy {
-	reset-gpios = <&pca9534 5 GPIO_ACTIVE_HIGH>;
-};
-
 &i2c2 {
 	clock-frequency = <400000>;
 	pinctrl-names = "default";
diff --git a/arch/arm/dts/imx8mn-var-som.dtsi b/arch/arm/dts/imx8mn-var-som.dtsi
index 87b5e23..4eb578a 100644
--- a/arch/arm/dts/imx8mn-var-som.dtsi
+++ b/arch/arm/dts/imx8mn-var-som.dtsi
@@ -11,6 +11,10 @@
 	model = "Variscite VAR-SOM-MX8MN module";
 	compatible = "variscite,var-som-mx8mn", "fsl,imx8mn";
 
+	aliases {
+		eeprom-som = &eeprom_som;
+	};
+
 	chosen {
 		stdout-path = &uart4;
 	};
@@ -98,11 +102,17 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 
-		ethphy: ethernet-phy@4 {
+		ethphy: ethernet-phy@4 { /* AR8033 or ADIN1300 */
 			compatible = "ethernet-phy-ieee802.3-c22";
 			reg = <4>;
 			reset-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
 			reset-assert-us = <10000>;
+			/*
+			 * Deassert delay:
+			 * ADIN1300 requires 5ms.
+			 * AR8033   requires 1ms.
+			 */
+			reset-deassert-us = <20000>;
 		};
 	};
 };
@@ -222,6 +232,12 @@
 			};
 		};
 	};
+
+	eeprom_som: eeprom@52 {
+		compatible = "atmel,24c04";
+		reg = <0x52>;
+		pagesize = <16>;
+	};
 };
 
 &i2c3 {
diff --git a/arch/arm/dts/imx8mp-beacon-kit-u-boot.dtsi b/arch/arm/dts/imx8mp-beacon-kit-u-boot.dtsi
index 5ca631e..b56f3a2 100644
--- a/arch/arm/dts/imx8mp-beacon-kit-u-boot.dtsi
+++ b/arch/arm/dts/imx8mp-beacon-kit-u-boot.dtsi
@@ -185,12 +185,10 @@
 
 &usb3_0 {
 	dma-ranges = <0x40000000 0x40000000 0xc0000000>;
-	/delete-property/ power-domains;
 };
 
 &usb3_1 {
 	dma-ranges = <0x40000000 0x40000000 0xc0000000>;
-	/delete-property/ power-domains;
 };
 
 &usb_dwc3_0 {
diff --git a/arch/arm/dts/imx8mp-u-boot.dtsi b/arch/arm/dts/imx8mp-u-boot.dtsi
index 68cd0e1..36e7444 100644
--- a/arch/arm/dts/imx8mp-u-boot.dtsi
+++ b/arch/arm/dts/imx8mp-u-boot.dtsi
@@ -44,6 +44,9 @@
 
 &aips3 {
 	bootph-pre-ram;
+	spba-bus@30800000 {
+		bootph-pre-ram;
+	};
 };
 
 &iomuxc {
diff --git a/arch/arm/dts/imx8mp-venice-gw702x-u-boot.dtsi b/arch/arm/dts/imx8mp-venice-gw702x-u-boot.dtsi
new file mode 100644
index 0000000..b9e3db7
--- /dev/null
+++ b/arch/arm/dts/imx8mp-venice-gw702x-u-boot.dtsi
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2023 Gateworks Corporation
+ */
+
+#include "imx8mp-venice-u-boot.dtsi"
+
+&eqos {
+	/delete-property/ assigned-clocks;
+	/delete-property/ assigned-clock-parents;
+	/delete-property/ assigned-clock-rates;
+};
diff --git a/arch/arm/dts/imx8mp-venice-gw702x.dtsi b/arch/arm/dts/imx8mp-venice-gw702x.dtsi
new file mode 100644
index 0000000..560c68e
--- /dev/null
+++ b/arch/arm/dts/imx8mp-venice-gw702x.dtsi
@@ -0,0 +1,587 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2023 Gateworks Corporation
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/net/ti-dp83867.h>
+
+/ {
+	aliases {
+		ethernet0 = &eqos;
+	};
+
+	memory@40000000 {
+		device_type = "memory";
+		reg = <0x0 0x40000000 0 0x80000000>;
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		key-user-pb {
+			label = "user_pb";
+			gpios = <&gpio 2 GPIO_ACTIVE_LOW>;
+			linux,code = <BTN_0>;
+		};
+
+		key-user-pb1x {
+			label = "user_pb1x";
+			linux,code = <BTN_1>;
+			interrupt-parent = <&gsc>;
+			interrupts = <0>;
+		};
+
+		key-erased {
+			label = "key_erased";
+			linux,code = <BTN_2>;
+			interrupt-parent = <&gsc>;
+			interrupts = <1>;
+		};
+
+		key-eeprom-wp {
+			label = "eeprom_wp";
+			linux,code = <BTN_3>;
+			interrupt-parent = <&gsc>;
+			interrupts = <2>;
+		};
+
+		key-tamper {
+			label = "tamper";
+			linux,code = <BTN_4>;
+			interrupt-parent = <&gsc>;
+			interrupts = <5>;
+		};
+
+		switch-hold {
+			label = "switch_hold";
+			linux,code = <BTN_5>;
+			interrupt-parent = <&gsc>;
+			interrupts = <7>;
+		};
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck3_reg>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck3_reg>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck3_reg>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck3_reg>;
+};
+
+&eqos {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_eqos>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			pinctrl-0 = <&pinctrl_ethphy0>;
+			pinctrl-names = "default";
+			reg = <0x0>;
+			interrupt-parent = <&gpio3>;
+			interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
+			ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+			ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
+			tx-fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+			rx-fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	pinctrl-1 = <&pinctrl_i2c1_gpio>;
+	scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	status = "okay";
+
+	gsc: gsc@20 {
+		compatible = "gw,gsc";
+		reg = <0x20>;
+		pinctrl-0 = <&pinctrl_gsc>;
+		interrupt-parent = <&gpio2>;
+		interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		adc {
+			compatible = "gw,gsc-adc";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			channel@6 {
+				gw,mode = <0>;
+				reg = <0x06>;
+				label = "temp";
+			};
+
+			channel@8 {
+				gw,mode = <3>;
+				reg = <0x08>;
+				label = "vdd_bat";
+			};
+
+			channel@16 {
+				gw,mode = <4>;
+				reg = <0x16>;
+				label = "fan_tach";
+			};
+
+			channel@82 {
+				gw,mode = <2>;
+				reg = <0x82>;
+				label = "vdd_vin";
+				gw,voltage-divider-ohms = <22100 1000>;
+			};
+
+			channel@84 {
+				gw,mode = <2>;
+				reg = <0x84>;
+				label = "vdd_adc1";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@86 {
+				gw,mode = <2>;
+				reg = <0x86>;
+				label = "vdd_adc2";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@88 {
+				gw,mode = <2>;
+				reg = <0x88>;
+				label = "vdd_1p0";
+			};
+
+			channel@8c {
+				gw,mode = <2>;
+				reg = <0x8c>;
+				label = "vdd_1p8";
+			};
+
+			channel@8e {
+				gw,mode = <2>;
+				reg = <0x8e>;
+				label = "vdd_2p5";
+			};
+
+			channel@90 {
+				gw,mode = <2>;
+				reg = <0x90>;
+				label = "vdd_3p3";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+
+			channel@92 {
+				gw,mode = <2>;
+				reg = <0x92>;
+				label = "vdd_dram";
+			};
+
+			channel@98 {
+				gw,mode = <2>;
+				reg = <0x98>;
+				label = "vdd_soc";
+			};
+
+			channel@9a {
+				gw,mode = <2>;
+				reg = <0x9a>;
+				label = "vdd_arm";
+			};
+
+			channel@a2 {
+				gw,mode = <2>;
+				reg = <0xa2>;
+				label = "vdd_gsc";
+				gw,voltage-divider-ohms = <10000 10000>;
+			};
+		};
+
+		fan-controller@0 {
+			compatible = "gw,gsc-fan";
+			reg = <0x0a>;
+		};
+	};
+
+	gpio: gpio@23 {
+		compatible = "nxp,pca9555";
+		reg = <0x23>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-parent = <&gsc>;
+		interrupts = <4>;
+	};
+
+	eeprom@50 {
+		compatible = "atmel,24c02";
+		reg = <0x50>;
+		pagesize = <16>;
+	};
+
+	eeprom@51 {
+		compatible = "atmel,24c02";
+		reg = <0x51>;
+		pagesize = <16>;
+	};
+
+	eeprom@52 {
+		compatible = "atmel,24c02";
+		reg = <0x52>;
+		pagesize = <16>;
+	};
+
+	eeprom@53 {
+		compatible = "atmel,24c02";
+		reg = <0x53>;
+		pagesize = <16>;
+	};
+
+	rtc@68 {
+		compatible = "dallas,ds1672";
+		reg = <0x68>;
+	};
+
+	pmic@69 {
+		compatible = "mps,mp5416";
+		reg = <0x69>;
+
+		regulators {
+			/* vdd_soc */
+			buck1 {
+				regulator-name = "buck1";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			/* vdd_dram */
+			buck2 {
+				regulator-name = "buck2";
+				regulator-min-microvolt = <1100000>;
+				regulator-max-microvolt = <1100000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			/* vdd_arm */
+			buck3_reg: buck3 {
+				regulator-name = "buck3";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			/* vdd_1p8 */
+			buck4 {
+				regulator-name = "buck4";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			/* OUT2: nvcc_snvs_1p8 */
+			ldo1 {
+				regulator-name = "ldo1";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			/* OUT3: vdd_1p0 */
+			ldo2 {
+				regulator-name = "ldo2";
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			/* OUT4: vdd_2p5 */
+			ldo3 {
+				regulator-name = "ldo3";
+				regulator-min-microvolt = <2500000>;
+				regulator-max-microvolt = <2500000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+
+			/* OUT5: vdd_3p3 */
+			ldo4 {
+				regulator-name = "ldo4";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+				regulator-boot-on;
+			};
+		};
+	};
+};
+
+/* off-board header */
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	pinctrl-1 = <&pinctrl_i2c2_gpio>;
+	scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	status = "okay";
+
+	eeprom@52 {
+		compatible = "atmel,24c32";
+		reg = <0x52>;
+		pagesize = <32>;
+	};
+};
+
+/* off-board header */
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default", "gpio";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	pinctrl-1 = <&pinctrl_i2c3_gpio>;
+	scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+	status = "okay";
+};
+
+/* off-board header */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+/* console */
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+/* off-board header */
+&uart3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart3>;
+	status = "okay";
+};
+
+/* off-board */
+&usdhc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usdhc1>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+};
+
+/* eMMC */
+&usdhc3 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC			0x2
+			MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO			0x2
+			MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0		0x90
+			MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1		0x90
+			MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2		0x90
+			MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3		0x90
+			MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK	0x90
+			MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL		0x90
+			MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0		0x16
+			MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1		0x16
+			MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2		0x16
+			MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3		0x16
+			MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL		0x16
+			MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x16
+		>;
+	};
+
+	pinctrl_ethphy0: ethphy0grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14	0x140 /* RST# */
+			MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16	0x150 /* IRQ# */
+		>;
+	};
+
+	pinctrl_gsc: gscgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_DATA4__GPIO2_IO06	0x150 /* IRQ# */
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL		0x400001c2
+			MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA		0x400001c2
+		>;
+	};
+
+	pinctrl_i2c1_gpio: i2c1gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C1_SCL__GPIO5_IO14	0x400001c2
+			MX8MP_IOMUXC_I2C1_SDA__GPIO5_IO15	0x400001c2
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL		0x400001c2
+			MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA		0x400001c2
+		>;
+	};
+
+	pinctrl_i2c2_gpio: i2c2gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16	0x400001c2
+			MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17	0x400001c2
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL		0x400001c2
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA		0x400001c2
+		>;
+	};
+
+	pinctrl_i2c3_gpio: i2c3gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__GPIO5_IO18	0x400001c2
+			MX8MP_IOMUXC_I2C3_SDA__GPIO5_IO19	0x400001c2
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX	0x140
+			MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX	0x140
+			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_uart3: uart3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART3_RXD__UART3_DCE_RX	0x140
+			MX8MP_IOMUXC_UART3_TXD__UART3_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_usdhc1: usdhc1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK	0x190
+			MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD	0x1d0
+			MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0	0x1d0
+			MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1	0x1d0
+			MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2	0x1d0
+			MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3	0x1d0
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x190
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d0
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d0
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d0
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d0
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d0
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d0
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d0
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d0
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d0
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x190
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x194
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d4
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d4
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d4
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d4
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d4
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d4
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d4
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d4
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d4
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x194
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x196
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD	0x1d6
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0	0x1d6
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1	0x1d6
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2	0x1d6
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3	0x1d6
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4	0x1d6
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5	0x1d6
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6	0x1d6
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7	0x1d6
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE	0x196
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B	0x166
+		>;
+	};
+};
diff --git a/arch/arm/dts/imx8mp-venice-gw7905-2x-u-boot.dtsi b/arch/arm/dts/imx8mp-venice-gw7905-2x-u-boot.dtsi
new file mode 100644
index 0000000..981841c
--- /dev/null
+++ b/arch/arm/dts/imx8mp-venice-gw7905-2x-u-boot.dtsi
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2023 Gateworks Corporation
+ */
+#include "imx8mp-venice-gw702x-u-boot.dtsi"
+
+&gpio1 {
+	app_gpioa {
+		gpio-hog;
+		input;
+		gpios = <13 GPIO_ACTIVE_HIGH>;
+		line-name = "gpioa";
+	};
+};
+
+&gpio4 {
+	app_gpiod {
+		gpio-hog;
+		input;
+		gpios = <1 GPIO_ACTIVE_HIGH>;
+		line-name = "gpiod";
+	};
+
+	app_gpiob {
+		gpio-hog;
+		input;
+		gpios = <4 GPIO_ACTIVE_HIGH>;
+		line-name = "gpiob";
+	};
+
+	app_gpioc {
+		gpio-hog;
+		input;
+		gpios = <5 GPIO_ACTIVE_HIGH>;
+		line-name = "gpioc";
+	};
+
+	pci_usb_sel {
+		gpio-hog;
+		output-low;
+		gpios = <26 GPIO_ACTIVE_HIGH>;
+		line-name = "pci_usb_sel";
+	};
+
+	pci_wdis {
+		gpio-hog;
+		output-high;
+		gpios = <28 GPIO_ACTIVE_HIGH>;
+		line-name = "pci_wdis#";
+	};
+};
diff --git a/arch/arm/dts/imx8mp-venice-gw7905-2x.dts b/arch/arm/dts/imx8mp-venice-gw7905-2x.dts
new file mode 100644
index 0000000..4a1bbbb
--- /dev/null
+++ b/arch/arm/dts/imx8mp-venice-gw7905-2x.dts
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2023 Gateworks Corporation
+ */
+
+/dts-v1/;
+
+#include "imx8mp.dtsi"
+#include "imx8mp-venice-gw702x.dtsi"
+#include "imx8mp-venice-gw7905.dtsi"
+
+/ {
+	model = "Gateworks Venice GW7905-2x i.MX8MP Development Kit";
+	compatible = "gateworks,imx8mp-gw7905-2x", "fsl,imx8mp";
+
+	chosen {
+		stdout-path = &uart2;
+	};
+};
+
+/* Disable SOM interfaces not used on baseboard */
+&eqos {
+	status = "disabled";
+};
+
+&usdhc1 {
+	status = "disabled";
+};
diff --git a/arch/arm/dts/imx8mp-venice-gw7905.dtsi b/arch/arm/dts/imx8mp-venice-gw7905.dtsi
new file mode 100644
index 0000000..0d40cb0
--- /dev/null
+++ b/arch/arm/dts/imx8mp-venice-gw7905.dtsi
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2023 Gateworks Corporation
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+
+/ {
+	led-controller {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_leds>;
+
+		led-0 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_GREEN>;
+			gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+			linux,default-trigger = "heartbeat";
+		};
+
+		led-1 {
+			function = LED_FUNCTION_STATUS;
+			color = <LED_COLOR_ID_RED>;
+			gpios = <&gpio4 27 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+	};
+
+	pcie0_refclk: pcie0-refclk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <100000000>;
+	};
+
+	pps {
+		compatible = "pps-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pps>;
+		gpios = <&gpio4 21 GPIO_ACTIVE_HIGH>;
+		status = "okay";
+	};
+
+	reg_usb2_vbus: regulator-usb2-vbus {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usb2_en>;
+		compatible = "regulator-fixed";
+		regulator-name = "usb2_vbus";
+		gpio = <&gpio4 12 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		compatible = "regulator-fixed";
+		regulator-name = "SD2_3P3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+};
+
+/* off-board header */
+&ecspi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi2>;
+	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&gpio4 {
+	gpio-line-names =
+		"", "", "", "",
+		"", "", "", "",
+		"", "", "", "",
+		"", "gpioa", "", "",
+		"", "", "", "",
+		"", "", "", "",
+		"", "", "", "",
+		"", "", "", "";
+};
+
+&gpio4 {
+	gpio-line-names =
+		"", "gpiod", "", "",
+		"gpiob", "gpioc", "", "",
+		"", "", "", "",
+		"", "", "", "",
+		"", "", "", "",
+		"", "", "", "",
+		"", "", "pci_usb_sel", "",
+		"pci_wdis#", "", "", "";
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	eeprom@52 {
+		compatible = "atmel,24c32";
+		reg = <0x52>;
+		pagesize = <32>;
+	};
+};
+
+/* off-board header */
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+};
+
+&pcie_phy {
+	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_INPUT>;
+	fsl,clkreq-unsupported;
+	clocks = <&pcie0_refclk>;
+	clock-names = "ref";
+	status = "okay";
+};
+
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie0>;
+	reset-gpio = <&gpio4 29 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+/* GPS */
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart1>;
+	status = "okay";
+};
+
+/* USB1 - Type C front panel SINK port J14 */
+&usb3_0 {
+	status = "okay";
+};
+
+&usb3_phy0 {
+	status = "okay";
+};
+
+&usb_dwc3_0 {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
+/* USB2 4-port USB3.0 HUB:
+ *  P1 - USBC connector (host only)
+ *  P2 - USB2 test connector
+ *  P3 - miniPCIe full card
+ *  P4 - miniPCIe half card
+ */
+&usb3_phy1 {
+	vbus-supply = <&reg_usb2_vbus>;
+	status = "okay";
+};
+
+&usb3_1 {
+	fsl,permanently-attached;
+	fsl,disable-port-power-control;
+	status = "okay";
+};
+
+&usb_dwc3_1 {
+	dr_mode = "host";
+	status = "okay";
+};
+
+/* microSD */
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_hog>;
+
+	pinctrl_hog: hoggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13	0x40000040 /* GPIOA */
+			MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01	0x40000040 /* GPIOD */
+			MX8MP_IOMUXC_SAI1_RXD2__GPIO4_IO04	0x40000040 /* GPIOB */
+			MX8MP_IOMUXC_SAI1_RXD3__GPIO4_IO05	0x40000040 /* GPIOC */
+			MX8MP_IOMUXC_SAI2_TXD0__GPIO4_IO26	0x40000106 /* PCI_USBSEL */
+			MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28	0x40000106 /* PCI_WDIS# */
+		>;
+	};
+
+	pinctrl_gpio_leds: gpioledgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22	0x6	/* LEDG */
+			MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27	0x6	/* LEDR */
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL		0x400001c2
+			MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA		0x400001c2
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL		0x400001c2
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA		0x400001c2
+		>;
+	};
+
+	pinctrl_pcie0: pciegrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29	0x106
+		>;
+	};
+
+	pinctrl_pps: ppsgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI2_RXFS__GPIO4_IO21	0x106
+		>;
+	};
+
+	pinctrl_reg_usb2_en: regusb2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SAI1_TXD0__GPIO4_IO12	0x6 /* USBHUB_RST# (ext p/u) */
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19	0x40
+		>;
+	};
+
+	pinctrl_spi2: spi2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK	0x140
+			MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI	0x140
+			MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO	0x140
+			MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13	0x140
+		>;
+	};
+
+	pinctrl_uart1: uart1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX	0x140
+			MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX	0x140
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d0
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0xc0
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d4
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0xc0
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK		0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD		0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0		0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1		0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2		0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3		0x1d6
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT		0xc0
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12		0x1c4
+		>;
+	};
+};
diff --git a/arch/arm/dts/imx8mp-verdin-dahlia.dtsi b/arch/arm/dts/imx8mp-verdin-dahlia.dtsi
deleted file mode 100644
index 4b8f86f..0000000
--- a/arch/arm/dts/imx8mp-verdin-dahlia.dtsi
+++ /dev/null
@@ -1,129 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/*
- * Copyright 2022 Toradex
- */
-
-/* TODO: Audio Codec */
-
-&backlight {
-	power-supply = <&reg_3p3v>;
-};
-
-/* Verdin SPI_1 */
-&ecspi1 {
-	status = "okay";
-};
-
-/* EEPROM on display adapter boards */
-&eeprom_display_adapter {
-	status = "okay";
-};
-
-/* EEPROM on Verdin Development board */
-&eeprom_carrier_board {
-	status = "okay";
-};
-
-&eqos {
-	status = "okay";
-};
-
-&flexcan1 {
-	status = "okay";
-};
-
-&flexcan2 {
-	status = "okay";
-};
-
-/* Verdin QSPI_1 */
-&flexspi {
-	status = "okay";
-};
-
-/* Current measurement into module VCC */
-&hwmon {
-	status = "okay";
-};
-
-&hwmon_temp {
-	vs-supply = <&reg_1p8v>;
-	status = "okay";
-};
-
-/* Verdin I2C_2_DSI */
-&i2c2 {
-	status = "okay";
-};
-
-&i2c3 {
-	status = "okay";
-};
-
-/* Verdin I2C_1 */
-&i2c4 {
-	status = "okay";
-
-	/* TODO: Audio Codec */
-};
-
-/* TODO: Verdin PCIE_1 */
-
-/* Verdin PWM_1 */
-&pwm1 {
-	status = "okay";
-};
-
-/* Verdin PWM_2 */
-&pwm2 {
-	status = "okay";
-};
-
-/* Verdin PWM_3_DSI */
-&pwm3 {
-	status = "okay";
-};
-
-&reg_usdhc2_vmmc {
-	vin-supply = <&reg_3p3v>;
-};
-
-/* TODO: Verdin I2S_1 */
-
-/* Verdin UART_1 */
-&uart1 {
-	status = "okay";
-};
-
-/* Verdin UART_2 */
-&uart2 {
-	status = "okay";
-};
-
-/* Verdin UART_3, used as the Linux Console */
-&uart3 {
-	status = "okay";
-};
-
-/* Verdin USB_1 */
-&usb3_0 {
-	status = "okay";
-};
-
-&usb3_phy0 {
-	status = "okay";
-};
-
-/* Verdin USB_2 */
-&usb3_1 {
-	status = "okay";
-};
-
-&usb3_phy1 {
-	status = "okay";
-};
-
-/* Verdin SD_1 */
-&usdhc2 {
-	status = "okay";
-};
diff --git a/arch/arm/dts/imx8mp-verdin-dev.dtsi b/arch/arm/dts/imx8mp-verdin-dev.dtsi
index cefabe6..bdfdd4c 100644
--- a/arch/arm/dts/imx8mp-verdin-dev.dtsi
+++ b/arch/arm/dts/imx8mp-verdin-dev.dtsi
@@ -3,8 +3,6 @@
  * Copyright 2022 Toradex
  */
 
-#include "imx8mp-verdin-dahlia.dtsi"
-
 / {
 	/* TODO: Audio Codec */
 
@@ -12,7 +10,7 @@
 		compatible = "regulator-fixed";
 		enable-active-high;
 		gpio = <&gpio_expander_21 4 GPIO_ACTIVE_HIGH>; /* ETH_PWR_EN */
-		off-on-delay = <500000>;
+		off-on-delay-us = <500000>;
 		regulator-max-microvolt = <3300000>;
 		regulator-min-microvolt = <3300000>;
 		regulator-name = "+V3.3_ETH";
@@ -21,16 +19,106 @@
 	};
 };
 
+&backlight {
+	power-supply = <&reg_3p3v>;
+};
+
+/* Verdin SPI_1 */
+&ecspi1 {
+	status = "okay";
+};
+
+/* EEPROM on display adapter boards */
+&eeprom_display_adapter {
+	status = "okay";
+};
+
+/* EEPROM on Verdin Development board */
+&eeprom_carrier_board {
+	status = "okay";
+};
+
+&eqos {
+	status = "okay";
+};
+
 &fec {
 	phy-supply = <&reg_eth2phy>;
 	status = "okay";
 };
 
+&flexcan1 {
+	status = "okay";
+};
+
+&flexcan2 {
+	status = "okay";
+};
+
+/* Verdin QSPI_1 */
+&flexspi {
+	status = "okay";
+};
+
 &gpio_expander_21 {
 	status = "okay";
 	vcc-supply = <&reg_1p8v>;
 };
 
+/* Current measurement into module VCC */
+&hwmon {
+	status = "okay";
+};
+
+&hwmon_temp {
+	vs-supply = <&reg_1p8v>;
+	status = "okay";
+};
+
+/* Verdin I2C_2_DSI */
+&i2c2 {
+	status = "okay";
+};
+
+&i2c3 {
+	status = "okay";
+};
+
+/* Verdin I2C_1 */
+&i2c4 {
+	status = "okay";
+
+	/* TODO: Audio Codec */
+};
+
+/* Verdin PCIE_1 */
+&pcie {
+	status = "okay";
+};
+
+&pcie_phy {
+	status = "okay";
+};
+
+/* Verdin PWM_1 */
+&pwm1 {
+	status = "okay";
+};
+
+/* Verdin PWM_2 */
+&pwm2 {
+	status = "okay";
+};
+
+/* Verdin PWM_3_DSI */
+&pwm3 {
+	status = "okay";
+};
+
+&reg_usdhc2_vmmc {
+	vin-supply = <&reg_3p3v>;
+};
+
 /* TODO: Verdin I2C_1 with Audio Codec */
 
 /* Verdin UART_1, connector X50 through RS485 transceiver */
@@ -38,9 +126,40 @@
 	linux,rs485-enabled-at-boot-time;
 	rs485-rts-active-low;
 	rs485-rx-during-tx;
+	status = "okay";
 };
 
+/* Verdin UART_2 */
+&uart2 {
+	status = "okay";
+};
+
+/* Verdin UART_3, used as the Linux Console */
+&uart3 {
+	status = "okay";
+};
+
+/* Verdin USB_1 */
+&usb3_0 {
+	status = "okay";
+};
+
+&usb3_phy0 {
+	status = "okay";
+};
+
+/* Verdin USB_2 */
+&usb3_1 {
+	fsl,permanently-attached;
+	status = "okay";
+};
+
+&usb3_phy1 {
+	status = "okay";
+};
+
 /* Limit frequency on dev board due to long traces and bad signal integrity */
 &usdhc2 {
 	max-frequency = <100000000>;
+	status = "okay";
 };
diff --git a/arch/arm/dts/imx8mp-verdin-wifi-dev-u-boot.dtsi b/arch/arm/dts/imx8mp-verdin-wifi-dev-u-boot.dtsi
index 9c6c417..0162f9b 100644
--- a/arch/arm/dts/imx8mp-verdin-wifi-dev-u-boot.dtsi
+++ b/arch/arm/dts/imx8mp-verdin-wifi-dev-u-boot.dtsi
@@ -62,6 +62,10 @@
 
 &gpio4 {
 	bootph-pre-ram;
+
+	ctrl-sleep-moci-hog {
+		bootph-pre-ram;
+	};
 };
 
 &gpio5 {
@@ -106,6 +110,10 @@
 	bootph-pre-ram;
 };
 
+&pinctrl_ctrl_sleep_moci {
+	bootph-pre-ram;
+};
+
 &pinctrl_i2c1 {
 	bootph-pre-ram;
 };
diff --git a/arch/arm/dts/imx8mp-verdin-wifi.dtsi b/arch/arm/dts/imx8mp-verdin-wifi.dtsi
index 36289c1..ef94f9a 100644
--- a/arch/arm/dts/imx8mp-verdin-wifi.dtsi
+++ b/arch/arm/dts/imx8mp-verdin-wifi.dtsi
@@ -65,6 +65,11 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_bt_uart>;
 	status = "okay";
+
+	bluetooth {
+		compatible = "mrvl,88w8997";
+		max-speed = <921600>;
+	};
 };
 
 /* On-module Wi-Fi */
diff --git a/arch/arm/dts/imx8mp-verdin.dtsi b/arch/arm/dts/imx8mp-verdin.dtsi
index 7b712d1..e9e4fcb 100644
--- a/arch/arm/dts/imx8mp-verdin.dtsi
+++ b/arch/arm/dts/imx8mp-verdin.dtsi
@@ -3,7 +3,8 @@
  * Copyright 2022 Toradex
  */
 
-#include "dt-bindings/pwm/pwm.h"
+#include <dt-bindings/phy/phy-imx8-pcie.h>
+#include <dt-bindings/pwm/pwm.h>
 #include "imx8mp.dtsi"
 
 / {
@@ -49,7 +50,7 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_gpio_keys>;
 
-		button-wakeup {
+		key-wakeup {
 			debounce-interval = <10>;
 			/* Verdin CTRL_WAKE1_MICO# (SODIMM 252) */
 			gpios = <&gpio4 0 GPIO_ACTIVE_LOW>;
@@ -86,7 +87,7 @@
 		compatible = "regulator-fixed";
 		enable-active-high;
 		gpio = <&gpio2 20 GPIO_ACTIVE_HIGH>; /* PMIC_EN_ETH */
-		off-on-delay = <500000>;
+		off-on-delay-us = <500000>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_reg_eth>;
 		regulator-always-on;
@@ -127,7 +128,7 @@
 		enable-active-high;
 		/* Verdin SD_1_PWR_EN (SODIMM 76) */
 		gpio = <&gpio4 22 GPIO_ACTIVE_HIGH>;
-		off-on-delay = <100000>;
+		off-on-delay-us = <100000>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_usdhc2_pwr_en>;
 		regulator-max-microvolt = <3300000>;
@@ -354,16 +355,6 @@
 			  "SODIMM_82",
 			  "SODIMM_70",
 			  "SODIMM_72";
-
-	ctrl-sleep-moci-hog {
-		gpio-hog;
-		/* Verdin CTRL_SLEEP_MOCI# (SODIMM 256) */
-		gpios = <29 GPIO_ACTIVE_HIGH>;
-		line-name = "CTRL_SLEEP_MOCI#";
-		output-high;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_ctrl_sleep_moci>;
-	};
 };
 
 &gpio3 {
@@ -432,6 +423,16 @@
 			  "SODIMM_256",
 			  "SODIMM_48",
 			  "SODIMM_44";
+
+	ctrl-sleep-moci-hog {
+		gpio-hog;
+		/* Verdin CTRL_SLEEP_MOCI# (SODIMM 256) */
+		gpios = <29 GPIO_ACTIVE_HIGH>;
+		line-name = "CTRL_SLEEP_MOCI#";
+		output-high;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_ctrl_sleep_moci>;
+	};
 };
 
 /* On-module I2C */
@@ -452,7 +453,6 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&pinctrl_pmic>;
 		reg = <0x25>;
-		sd-vsel-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
 
 		/*
 		 * The bootloader is expected to switch on LDO4 for the on-module +V3.3_ADC and the
@@ -678,8 +678,8 @@
 		status = "disabled";
 	};
 
-	lvds_ti_sn65dsi83: bridge@2c {
-		compatible = "ti,sn65dsi83";
+	lvds_ti_sn65dsi84: bridge@2c {
+		compatible = "ti,sn65dsi84";
 		/* Verdin GPIO_9_DSI (SN65DSI84 IRQ, SODIMM 17, unused) */
 		/* Verdin GPIO_10_DSI (SODIMM 21) */
 		enable-gpios = <&gpio4 28 GPIO_ACTIVE_HIGH>;
@@ -712,7 +712,7 @@
 		compatible = "atmel,maxtouch";
 		/*
 		 * Verdin GPIO_9_DSI
-		 * (TOUCH_INT#, SODIMM 17, also routed to SN65DSI83 IRQ albeit currently unused)
+		 * (TOUCH_INT#, SODIMM 17, also routed to SN65DSI84 IRQ albeit currently unused)
 		 */
 		interrupt-parent = <&gpio4>;
 		interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
@@ -748,7 +748,20 @@
 	};
 };
 
-/* TODO: Verdin PCIE_1 */
+/* Verdin PCIE_1 */
+&pcie {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pcie>;
+	/* PCIE_1_RESET# (SODIMM 244) */
+	reset-gpio = <&gpio4 19 GPIO_ACTIVE_LOW>;
+};
+
+&pcie_phy {
+	clocks = <&hsio_blk_ctrl>;
+	clock-names = "ref";
+	fsl,clkreq-unsupported;
+	fsl,refclk-pad-mode = <IMX8_PCIE_REFCLK_PAD_OUTPUT>;
+};
 
 /* Verdin PWM_1 */
 &pwm1 {
@@ -806,28 +819,45 @@
 };
 
 /* Verdin USB_1 */
-&usb3_phy0 {
-	vbus-supply = <&reg_usb1_vbus>;
+&usb3_0 {
+	fsl,disable-port-power-control;
+	fsl,over-current-active-low;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_usb_1_oc_n>;
 };
 
 &usb_dwc3_0 {
+	/* dual role only, not full featured OTG */
 	adp-disable;
 	dr_mode = "otg";
 	hnp-disable;
 	maximum-speed = "high-speed";
-	over-current-active-low;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_usb_1_id>;
+	role-switch-default-mode = "peripheral";
 	srp-disable;
+	usb-role-switch;
+
+	connector {
+		compatible = "gpio-usb-b-connector", "usb-b-connector";
+		id-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+		label = "Type-C";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb_1_id>;
+		self-powered;
+		type = "micro";
+		vbus-supply = <&reg_usb1_vbus>;
+	};
 };
 
 /* Verdin USB_2 */
+&usb3_1 {
+	fsl,disable-port-power-control;
+};
+
 &usb3_phy1 {
 	vbus-supply = <&reg_usb2_vbus>;
 };
 
 &usb_dwc3_1 {
-	disable-over-current;
 	dr_mode = "host";
 };
 
@@ -1045,7 +1075,6 @@
 
 	pinctrl_gpio_hog3: gpiohog3grp {
 		fsl,pins =
-			<MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13		0x1c4>,	/* SODIMM 157 */
 			/* CSI_1_MCLK */
 			<MX8MP_IOMUXC_GPIO1_IO15__GPIO1_IO15		0x1c4>;	/* SODIMM 91 */
 	};
@@ -1220,7 +1249,7 @@
 
 	pinctrl_usb1_vbus: usb1vbusgrp {
 		fsl,pins =
-			<MX8MP_IOMUXC_GPIO1_IO12__USB1_OTG_PWR		0x19>;	/* SODIMM 155 */
+			<MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12		0x106>;	/* SODIMM 155 */
 	};
 
 	/* USB_1_ID */
@@ -1229,9 +1258,15 @@
 			<MX8MP_IOMUXC_SD1_RESET_B__GPIO2_IO10		0x1c4>;	/* SODIMM 161 */
 	};
 
+	/* USB_1_OC# */
+	pinctrl_usb_1_oc_n: usb1ocngrp {
+		fsl,pins =
+			<MX8MP_IOMUXC_GPIO1_IO13__USB1_OTG_OC		0x1c4>;	/* SODIMM 157 */
+	};
+
 	pinctrl_usb2_vbus: usb2vbusgrp {
 		fsl,pins =
-			<MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR		0x19>;	/* SODIMM 185 */
+			<MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14		0x106>;	/* SODIMM 185 */
 	};
 
 	/* On-module Wi-Fi */
diff --git a/arch/arm/dts/imx8mp.dtsi b/arch/arm/dts/imx8mp.dtsi
index bb916a0..428c604 100644
--- a/arch/arm/dts/imx8mp.dtsi
+++ b/arch/arm/dts/imx8mp.dtsi
@@ -123,6 +123,7 @@
 
 		A53_L2: l2-cache0 {
 			compatible = "cache";
+			cache-unified;
 			cache-level = <2>;
 			cache-size = <0x80000>;
 			cache-line-size = <64>;
@@ -379,6 +380,8 @@
 				compatible = "fsl,imx8mp-tmu";
 				reg = <0x30260000 0x10000>;
 				clocks = <&clk IMX8MP_CLK_TSENSOR_ROOT>;
+				nvmem-cells = <&tmu_calib>;
+				nvmem-cell-names = "calib";
 				#thermal-sensor-cells = <1>;
 			};
 
@@ -406,12 +409,36 @@
 				status = "disabled";
 			};
 
+			gpt1: timer@302d0000 {
+				compatible = "fsl,imx8mp-gpt", "fsl,imx6dl-gpt";
+				reg = <0x302d0000 0x10000>;
+				interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPT1_ROOT>, <&clk IMX8MP_CLK_GPT1>;
+				clock-names = "ipg", "per";
+			};
+
+			gpt2: timer@302e0000 {
+				compatible = "fsl,imx8mp-gpt", "fsl,imx6dl-gpt";
+				reg = <0x302e0000 0x10000>;
+				interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPT2_ROOT>, <&clk IMX8MP_CLK_GPT2>;
+				clock-names = "ipg", "per";
+			};
+
+			gpt3: timer@302f0000 {
+				compatible = "fsl,imx8mp-gpt", "fsl,imx6dl-gpt";
+				reg = <0x302f0000 0x10000>;
+				interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPT3_ROOT>, <&clk IMX8MP_CLK_GPT3>;
+				clock-names = "ipg", "per";
+			};
+
 			iomuxc: pinctrl@30330000 {
 				compatible = "fsl,imx8mp-iomuxc";
 				reg = <0x30330000 0x10000>;
 			};
 
-			gpr: iomuxc-gpr@30340000 {
+			gpr: syscon@30340000 {
 				compatible = "fsl,imx8mp-iomuxc-gpr", "syscon";
 				reg = <0x30340000 0x10000>;
 			};
@@ -424,27 +451,44 @@
 				#address-cells = <1>;
 				#size-cells = <1>;
 
-				imx8mp_uid: unique-id@420 {
+				/*
+				 * The register address below maps to the MX8M
+				 * Fusemap Description Table entries this way.
+				 * Assuming
+				 *   reg = <ADDR SIZE>;
+				 * then
+				 *   Fuse Address = (ADDR * 4) + 0x400
+				 * Note that if SIZE is greater than 4, then
+				 * each subsequent fuse is located at offset
+				 * +0x10 in Fusemap Description Table (e.g.
+				 * reg = <0x8 0x8> describes fuses 0x420 and
+				 * 0x430).
+				 */
+				imx8mp_uid: unique-id@8 { /* 0x420-0x430 */
 					reg = <0x8 0x8>;
 				};
 
-				cpu_speed_grade: speed-grade@10 {
+				cpu_speed_grade: speed-grade@10 { /* 0x440 */
 					reg = <0x10 4>;
 				};
 
-				eth_mac1: mac-address@90 {
+				eth_mac1: mac-address@90 { /* 0x640 */
 					reg = <0x90 6>;
 				};
 
-				eth_mac2: mac-address@96 {
+				eth_mac2: mac-address@96 { /* 0x658 */
 					reg = <0x96 6>;
 				};
+
+				tmu_calib: calib@264 { /* 0xd90-0xdc0 */
+					reg = <0x264 0x10>;
+				};
 			};
 
-			anatop: anatop@30360000 {
-				compatible = "fsl,imx8mp-anatop", "fsl,imx8mm-anatop",
-					     "syscon";
+			anatop: clock-controller@30360000 {
+				compatible = "fsl,imx8mp-anatop", "fsl,imx8mm-anatop";
 				reg = <0x30360000 0x10000>;
+				#clock-cells = <1>;
 			};
 
 			snvs: snvs@30370000 {
@@ -523,6 +567,7 @@
 				compatible = "fsl,imx8mp-gpc";
 				reg = <0x303a0000 0x1000>;
 				interrupt-parent = <&gic>;
+				interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
 				interrupt-controller;
 				#interrupt-cells = <3>;
 
@@ -589,7 +634,7 @@
 						reg = <IMX8MP_POWER_DOMAIN_MIPI_PHY2>;
 					};
 
-					pgc_hsiomix: power-domains@17 {
+					pgc_hsiomix: power-domain@17 {
 						#power-domain-cells = <0>;
 						reg = <IMX8MP_POWER_DOMAIN_HSIOMIX>;
 						clocks = <&clk IMX8MP_CLK_HSIO_AXI>,
@@ -631,6 +676,14 @@
 						reg = <IMX8MP_POWER_DOMAIN_VPU_VC8000E>;
 						clocks = <&clk IMX8MP_CLK_VPU_VC8KE_ROOT>;
 					};
+
+					pgc_mlmix: power-domain@24 {
+						#power-domain-cells = <0>;
+						reg = <IMX8MP_POWER_DOMAIN_MLMIX>;
+						clocks = <&clk IMX8MP_CLK_ML_AXI>,
+							 <&clk IMX8MP_CLK_ML_AHB>,
+							 <&clk IMX8MP_CLK_NPU_ROOT>;
+					};
 				};
 			};
 		};
@@ -693,6 +746,30 @@
 				clocks = <&osc_24m>;
 				clock-names = "per";
 			};
+
+			gpt6: timer@306e0000 {
+				compatible = "fsl,imx8mp-gpt", "fsl,imx6dl-gpt";
+				reg = <0x306e0000 0x10000>;
+				interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPT6_ROOT>, <&clk IMX8MP_CLK_GPT6>;
+				clock-names = "ipg", "per";
+			};
+
+			gpt5: timer@306f0000 {
+				compatible = "fsl,imx8mp-gpt", "fsl,imx6dl-gpt";
+				reg = <0x306f0000 0x10000>;
+				interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPT5_ROOT>, <&clk IMX8MP_CLK_GPT5>;
+				clock-names = "ipg", "per";
+			};
+
+			gpt4: timer@30700000 {
+				compatible = "fsl,imx8mp-gpt", "fsl,imx6dl-gpt";
+				reg = <0x30700000 0x10000>;
+				interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_GPT4_ROOT>, <&clk IMX8MP_CLK_GPT4>;
+				clock-names = "ipg", "per";
+			};
 		};
 
 		aips3: bus@30800000 {
@@ -702,112 +779,129 @@
 			#size-cells = <1>;
 			ranges;
 
-			ecspi1: spi@30820000 {
+			spba-bus@30800000 {
+				compatible = "fsl,spba-bus", "simple-bus";
+				reg = <0x30800000 0x100000>;
 				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
-				reg = <0x30820000 0x10000>;
-				interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MP_CLK_ECSPI1_ROOT>,
-					 <&clk IMX8MP_CLK_ECSPI1_ROOT>;
-				clock-names = "ipg", "per";
-				dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
+				#size-cells = <1>;
+				ranges;
 
-			ecspi2: spi@30830000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
-				reg = <0x30830000 0x10000>;
-				interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MP_CLK_ECSPI2_ROOT>,
-					 <&clk IMX8MP_CLK_ECSPI2_ROOT>;
-				clock-names = "ipg", "per";
-				dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
+				ecspi1: spi@30820000 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,imx8mp-ecspi", "fsl,imx6ul-ecspi";
+					reg = <0x30820000 0x10000>;
+					interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_ECSPI1_ROOT>,
+						 <&clk IMX8MP_CLK_ECSPI1_ROOT>;
+					clock-names = "ipg", "per";
+					assigned-clock-rates = <80000000>;
+					assigned-clocks = <&clk IMX8MP_CLK_ECSPI1>;
+					assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>;
+					dmas = <&sdma1 0 7 1>, <&sdma1 1 7 2>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
 
-			ecspi3: spi@30840000 {
-				#address-cells = <1>;
-				#size-cells = <0>;
-				compatible = "fsl,imx8mp-ecspi", "fsl,imx51-ecspi";
-				reg = <0x30840000 0x10000>;
-				interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MP_CLK_ECSPI3_ROOT>,
-					 <&clk IMX8MP_CLK_ECSPI3_ROOT>;
-				clock-names = "ipg", "per";
-				dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
+				ecspi2: spi@30830000 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,imx8mp-ecspi", "fsl,imx6ul-ecspi";
+					reg = <0x30830000 0x10000>;
+					interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_ECSPI2_ROOT>,
+						 <&clk IMX8MP_CLK_ECSPI2_ROOT>;
+					clock-names = "ipg", "per";
+					assigned-clock-rates = <80000000>;
+					assigned-clocks = <&clk IMX8MP_CLK_ECSPI2>;
+					assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>;
+					dmas = <&sdma1 2 7 1>, <&sdma1 3 7 2>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
 
-			uart1: serial@30860000 {
-				compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
-				reg = <0x30860000 0x10000>;
-				interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MP_CLK_UART1_ROOT>,
-					 <&clk IMX8MP_CLK_UART1_ROOT>;
-				clock-names = "ipg", "per";
-				dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
+				ecspi3: spi@30840000 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,imx8mp-ecspi", "fsl,imx6ul-ecspi";
+					reg = <0x30840000 0x10000>;
+					interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_ECSPI3_ROOT>,
+						 <&clk IMX8MP_CLK_ECSPI3_ROOT>;
+					clock-names = "ipg", "per";
+					assigned-clock-rates = <80000000>;
+					assigned-clocks = <&clk IMX8MP_CLK_ECSPI3>;
+					assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>;
+					dmas = <&sdma1 4 7 1>, <&sdma1 5 7 2>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
 
-			uart3: serial@30880000 {
-				compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
-				reg = <0x30880000 0x10000>;
-				interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MP_CLK_UART3_ROOT>,
-					 <&clk IMX8MP_CLK_UART3_ROOT>;
-				clock-names = "ipg", "per";
-				dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
+				uart1: serial@30860000 {
+					compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
+					reg = <0x30860000 0x10000>;
+					interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_UART1_ROOT>,
+						 <&clk IMX8MP_CLK_UART1_ROOT>;
+					clock-names = "ipg", "per";
+					dmas = <&sdma1 22 4 0>, <&sdma1 23 4 0>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
 
-			uart2: serial@30890000 {
-				compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
-				reg = <0x30890000 0x10000>;
-				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MP_CLK_UART2_ROOT>,
-					 <&clk IMX8MP_CLK_UART2_ROOT>;
-				clock-names = "ipg", "per";
-				dmas = <&sdma1 24 4 0>, <&sdma1 25 4 0>;
-				dma-names = "rx", "tx";
-				status = "disabled";
-			};
+				uart3: serial@30880000 {
+					compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
+					reg = <0x30880000 0x10000>;
+					interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_UART3_ROOT>,
+						 <&clk IMX8MP_CLK_UART3_ROOT>;
+					clock-names = "ipg", "per";
+					dmas = <&sdma1 26 4 0>, <&sdma1 27 4 0>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
 
-			flexcan1: can@308c0000 {
-				compatible = "fsl,imx8mp-flexcan";
-				reg = <0x308c0000 0x10000>;
-				interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
-					 <&clk IMX8MP_CLK_CAN1_ROOT>;
-				clock-names = "ipg", "per";
-				assigned-clocks = <&clk IMX8MP_CLK_CAN1>;
-				assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_40M>;
-				assigned-clock-rates = <40000000>;
-				fsl,clk-source = /bits/ 8 <0>;
-				fsl,stop-mode = <&gpr 0x10 4>;
-				status = "disabled";
-			};
+				uart2: serial@30890000 {
+					compatible = "fsl,imx8mp-uart", "fsl,imx6q-uart";
+					reg = <0x30890000 0x10000>;
+					interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_UART2_ROOT>,
+						 <&clk IMX8MP_CLK_UART2_ROOT>;
+					clock-names = "ipg", "per";
+					dmas = <&sdma1 24 4 0>, <&sdma1 25 4 0>;
+					dma-names = "rx", "tx";
+					status = "disabled";
+				};
 
-			flexcan2: can@308d0000 {
-				compatible = "fsl,imx8mp-flexcan";
-				reg = <0x308d0000 0x10000>;
-				interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
-				clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
-					 <&clk IMX8MP_CLK_CAN2_ROOT>;
-				clock-names = "ipg", "per";
-				assigned-clocks = <&clk IMX8MP_CLK_CAN2>;
-				assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_40M>;
-				assigned-clock-rates = <40000000>;
-				fsl,clk-source = /bits/ 8 <0>;
-				fsl,stop-mode = <&gpr 0x10 5>;
-				status = "disabled";
+				flexcan1: can@308c0000 {
+					compatible = "fsl,imx8mp-flexcan";
+					reg = <0x308c0000 0x10000>;
+					interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
+						 <&clk IMX8MP_CLK_CAN1_ROOT>;
+					clock-names = "ipg", "per";
+					assigned-clocks = <&clk IMX8MP_CLK_CAN1>;
+					assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_40M>;
+					assigned-clock-rates = <40000000>;
+					fsl,clk-source = /bits/ 8 <0>;
+					fsl,stop-mode = <&gpr 0x10 4>;
+					status = "disabled";
+				};
+
+				flexcan2: can@308d0000 {
+					compatible = "fsl,imx8mp-flexcan";
+					reg = <0x308d0000 0x10000>;
+					interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+					clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
+						 <&clk IMX8MP_CLK_CAN2_ROOT>;
+					clock-names = "ipg", "per";
+					assigned-clocks = <&clk IMX8MP_CLK_CAN2>;
+					assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_40M>;
+					assigned-clock-rates = <40000000>;
+					fsl,clk-source = /bits/ 8 <0>;
+					fsl,stop-mode = <&gpr 0x10 5>;
+					status = "disabled";
+				};
 			};
 
 			crypto: crypto@30900000 {
@@ -1063,11 +1157,11 @@
 			noc_opp_table: opp-table {
 				compatible = "operating-points-v2";
 
-				opp-200M {
+				opp-200000000 {
 					opp-hz = /bits/ 64 <200000000>;
 				};
 
-				opp-1000M {
+				opp-1000000000 {
 					opp-hz = /bits/ 64 <1000000000>;
 				};
 			};
@@ -1080,10 +1174,78 @@
 			#size-cells = <1>;
 			ranges;
 
+			mipi_dsi: dsi@32e60000 {
+				compatible = "fsl,imx8mp-mipi-dsim";
+				reg = <0x32e60000 0x400>;
+				clocks = <&clk IMX8MP_CLK_MEDIA_APB_ROOT>,
+					 <&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF>;
+				clock-names = "bus_clk", "sclk_mipi";
+				assigned-clocks = <&clk IMX8MP_CLK_MEDIA_APB>,
+						  <&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF>;
+				assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>,
+							 <&clk IMX8MP_CLK_24M>;
+				assigned-clock-rates = <200000000>, <24000000>;
+				samsung,pll-clock-frequency = <24000000>;
+				interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
+				power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_MIPI_DSI_1>;
+				status = "disabled";
+
+				ports {
+					#address-cells = <1>;
+					#size-cells = <0>;
+
+					port@0 {
+						reg = <0>;
+
+						dsim_from_lcdif1: endpoint {
+							remote-endpoint = <&lcdif1_to_dsim>;
+						};
+					};
+				};
+			};
+
+			lcdif1: display-controller@32e80000 {
+				compatible = "fsl,imx8mp-lcdif";
+				reg = <0x32e80000 0x10000>;
+				clocks = <&clk IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT>,
+					 <&clk IMX8MP_CLK_MEDIA_APB_ROOT>,
+					 <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>;
+				clock-names = "pix", "axi", "disp_axi";
+				interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+				power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_LCDIF_1>;
+				status = "disabled";
+
+				port {
+					lcdif1_to_dsim: endpoint {
+						remote-endpoint = <&dsim_from_lcdif1>;
+					};
+				};
+			};
+
+			lcdif2: display-controller@32e90000 {
+				compatible = "fsl,imx8mp-lcdif";
+				reg = <0x32e90000 0x10000>;
+				interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&clk IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT>,
+					 <&clk IMX8MP_CLK_MEDIA_APB_ROOT>,
+					 <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>;
+				clock-names = "pix", "axi", "disp_axi";
+				power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_LCDIF_2>;
+				status = "disabled";
+
+				port {
+					lcdif2_to_ldb: endpoint {
+						remote-endpoint = <&ldb_from_lcdif2>;
+					};
+				};
+			};
+
 			media_blk_ctrl: blk-ctrl@32ec0000 {
 				compatible = "fsl,imx8mp-media-blk-ctrl",
 					     "syscon";
 				reg = <0x32ec0000 0x10000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
 				power-domains = <&pgc_mediamix>,
 						<&pgc_mipi_phy1>,
 						<&pgc_mipi_phy1>,
@@ -1122,12 +1284,55 @@
 					      "disp1", "disp2", "isp", "phy";
 
 				assigned-clocks = <&clk IMX8MP_CLK_MEDIA_AXI>,
-						  <&clk IMX8MP_CLK_MEDIA_APB>;
+						  <&clk IMX8MP_CLK_MEDIA_APB>,
+						  <&clk IMX8MP_CLK_MEDIA_DISP1_PIX>,
+						  <&clk IMX8MP_CLK_MEDIA_DISP2_PIX>,
+						  <&clk IMX8MP_VIDEO_PLL1>;
 				assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>,
-							 <&clk IMX8MP_SYS_PLL1_800M>;
-				assigned-clock-rates = <500000000>, <200000000>;
-
+							 <&clk IMX8MP_SYS_PLL1_800M>,
+							 <&clk IMX8MP_VIDEO_PLL1_OUT>,
+							 <&clk IMX8MP_VIDEO_PLL1_OUT>;
+				assigned-clock-rates = <500000000>, <200000000>,
+						       <0>, <0>, <1039500000>;
 				#power-domain-cells = <1>;
+
+				lvds_bridge: bridge@5c {
+					compatible = "fsl,imx8mp-ldb";
+					reg = <0x5c 0x4>, <0x128 0x4>;
+					reg-names = "ldb", "lvds";
+					clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
+					clock-names = "ldb";
+					assigned-clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
+					assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>;
+					status = "disabled";
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0>;
+
+							ldb_from_lcdif2: endpoint {
+								remote-endpoint = <&lcdif2_to_ldb>;
+							};
+						};
+
+						port@1 {
+							reg = <1>;
+
+							ldb_lvds_ch0: endpoint {
+							};
+						};
+
+						port@2 {
+							reg = <2>;
+
+							ldb_lvds_ch1: endpoint {
+							};
+						};
+					};
+				};
 			};
 
 			pcie_phy: pcie-phy@32f00000 {
@@ -1158,6 +1363,7 @@
 						<&noc IMX8MP_ICM_PCIE &noc IMX8MP_ICN_HSIO>;
 				interconnect-names = "noc-pcie", "usb1", "usb2", "pcie";
 				#power-domain-cells = <1>;
+				#clock-cells = <0>;
 			};
 		};
 
@@ -1165,6 +1371,13 @@
 			compatible = "fsl,imx8mp-pcie";
 			reg = <0x33800000 0x400000>, <0x1ff00000 0x80000>;
 			reg-names = "dbi", "config";
+			clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
+				 <&clk IMX8MP_CLK_HSIO_AXI>,
+				 <&clk IMX8MP_CLK_PCIE_ROOT>;
+			clock-names = "pcie", "pcie_bus", "pcie_aux";
+			assigned-clocks = <&clk IMX8MP_CLK_PCIE_AUX>;
+			assigned-clock-rates = <10000000>;
+			assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_50M>;
 			#address-cells = <3>;
 			#size-cells = <2>;
 			device_type = "pci";
@@ -1192,6 +1405,32 @@
 			status = "disabled";
 		};
 
+		pcie_ep: pcie-ep@33800000 {
+			compatible = "fsl,imx8mp-pcie-ep";
+			reg = <0x33800000 0x000400000>, <0x18000000 0x08000000>;
+			reg-names = "dbi", "addr_space";
+			clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
+				 <&clk IMX8MP_CLK_HSIO_AXI>,
+				 <&clk IMX8MP_CLK_PCIE_ROOT>;
+			clock-names = "pcie", "pcie_bus", "pcie_aux";
+			assigned-clocks = <&clk IMX8MP_CLK_PCIE_AUX>;
+			assigned-clock-rates = <10000000>;
+			assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_50M>;
+			num-lanes = <1>;
+			interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>; /* eDMA */
+			interrupt-names = "dma";
+			fsl,max-link-speed = <3>;
+			power-domains = <&hsio_blk_ctrl IMX8MP_HSIOBLK_PD_PCIE>;
+			resets = <&src IMX8MP_RESET_PCIE_CTRL_APPS_EN>,
+				 <&src IMX8MP_RESET_PCIE_CTRL_APPS_TURNOFF>;
+			reset-names = "apps", "turnoff";
+			phys = <&pcie_phy>;
+			phy-names = "pcie-phy";
+			num-ib-windows = <4>;
+			num-ob-windows = <4>;
+			status = "disabled";
+		};
+
 		gpu3d: gpu@38000000 {
 			compatible = "vivante,gc";
 			reg = <0x38000000 0x8000>;
@@ -1223,6 +1462,28 @@
 			power-domains = <&pgc_gpu2d>;
 		};
 
+		vpu_g1: video-codec@38300000 {
+			compatible = "nxp,imx8mm-vpu-g1";
+			reg = <0x38300000 0x10000>;
+			interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX8MP_CLK_VPU_G1_ROOT>;
+			assigned-clocks = <&clk IMX8MP_CLK_VPU_G1>;
+			assigned-clock-parents = <&clk IMX8MP_VPU_PLL_OUT>;
+			assigned-clock-rates = <600000000>;
+			power-domains = <&vpumix_blk_ctrl IMX8MP_VPUBLK_PD_G1>;
+		};
+
+		vpu_g2: video-codec@38310000 {
+			compatible = "nxp,imx8mq-vpu-g2";
+			reg = <0x38310000 0x10000>;
+			interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&clk IMX8MP_CLK_VPU_G2_ROOT>;
+			assigned-clocks = <&clk IMX8MP_CLK_VPU_G2>;
+			assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>;
+			assigned-clock-rates = <500000000>;
+			power-domains = <&vpumix_blk_ctrl IMX8MP_VPUBLK_PD_G2>;
+		};
+
 		vpumix_blk_ctrl: blk-ctrl@38330000 {
 			compatible = "fsl,imx8mp-vpu-blk-ctrl", "syscon";
 			reg = <0x38330000 0x100>;
@@ -1234,6 +1495,9 @@
 				 <&clk IMX8MP_CLK_VPU_G2_ROOT>,
 				 <&clk IMX8MP_CLK_VPU_VC8KE_ROOT>;
 			clock-names = "g1", "g2", "vc8000e";
+			assigned-clocks = <&clk IMX8MP_CLK_VPU_BUS>, <&clk IMX8MP_VPU_PLL>;
+			assigned-clock-parents = <&clk IMX8MP_VPU_PLL_OUT>;
+			assigned-clock-rates = <600000000>, <600000000>;
 			interconnects = <&noc IMX8MP_ICM_VPU_G1 &noc IMX8MP_ICN_VIDEO>,
 					<&noc IMX8MP_ICM_VPU_G2 &noc IMX8MP_ICN_VIDEO>,
 					<&noc IMX8MP_ICM_VPU_H1 &noc IMX8MP_ICN_VIDEO>;
@@ -1279,7 +1543,7 @@
 			reg = <0x32f10100 0x8>,
 			      <0x381f0000 0x20>;
 			clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
-				 <&clk IMX8MP_CLK_USB_ROOT>;
+				 <&clk IMX8MP_CLK_USB_SUSP>;
 			clock-names = "hsio", "suspend";
 			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
 			power-domains = <&hsio_blk_ctrl IMX8MP_HSIOBLK_PD_USB>;
@@ -1292,9 +1556,9 @@
 			usb_dwc3_0: usb@38100000 {
 				compatible = "snps,dwc3";
 				reg = <0x38100000 0x10000>;
-				clocks = <&clk IMX8MP_CLK_HSIO_AXI>,
+				clocks = <&clk IMX8MP_CLK_USB_ROOT>,
 					 <&clk IMX8MP_CLK_USB_CORE_REF>,
-					 <&clk IMX8MP_CLK_USB_ROOT>;
+					 <&clk IMX8MP_CLK_USB_SUSP>;
 				clock-names = "bus_early", "ref", "suspend";
 				interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
 				phys = <&usb3_phy0>, <&usb3_phy0>;
@@ -1321,7 +1585,7 @@
 			reg = <0x32f10108 0x8>,
 			      <0x382f0000 0x20>;
 			clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
-				 <&clk IMX8MP_CLK_USB_ROOT>;
+				 <&clk IMX8MP_CLK_USB_SUSP>;
 			clock-names = "hsio", "suspend";
 			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
 			power-domains = <&hsio_blk_ctrl IMX8MP_HSIOBLK_PD_USB>;
@@ -1334,9 +1598,9 @@
 			usb_dwc3_1: usb@38200000 {
 				compatible = "snps,dwc3";
 				reg = <0x38200000 0x10000>;
-				clocks = <&clk IMX8MP_CLK_HSIO_AXI>,
+				clocks = <&clk IMX8MP_CLK_USB_ROOT>,
 					 <&clk IMX8MP_CLK_USB_CORE_REF>,
-					 <&clk IMX8MP_CLK_USB_ROOT>;
+					 <&clk IMX8MP_CLK_USB_SUSP>;
 				clock-names = "bus_early", "ref", "suspend";
 				interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 				phys = <&usb3_phy1>, <&usb3_phy1>;
diff --git a/arch/arm/dts/nuvoton-npcm8xx-u-boot.dtsi b/arch/arm/dts/nuvoton-npcm8xx-u-boot.dtsi
index be2ad0c..e49e564 100644
--- a/arch/arm/dts/nuvoton-npcm8xx-u-boot.dtsi
+++ b/arch/arm/dts/nuvoton-npcm8xx-u-boot.dtsi
@@ -289,6 +289,23 @@
 			status = "disable";
 		};
 
+		aes: aes@f0858000 {
+			compatible = "nuvoton,npcm845-aes";
+			reg = <0x0 0xf0858000 0x0 0x1000>,
+			      <0x0 0xf0851000 0x0 0x1000>;
+			status = "disabled";
+			clocks = <&clk NPCM8XX_CLK_AHB>;
+			clock-names = "clk_ahb";
+		};
+
+		sha:sha@f085a000 {
+			compatible = "nuvoton,npcm845-sha";
+			reg = <0x0 0xf085a000 0x0 0x1000>;
+			status = "disabled";
+			clocks = <&clk NPCM8XX_CLK_AHB>;
+			clock-names = "clk_ahb";
+		};
+
 		apb {
 			serial0: serial@0 {
 				compatible = "nuvoton,npcm845-uart";
@@ -417,22 +434,6 @@
 				status = "disabled";
 			};
 
-			aes: aes@f0858000 {
-				compatible = "nuvoton,npcm845-aes";
-				reg = <0x0 0xf0858000 0x0 0x1000>,
-				<0x0 0xf0851000 0x0 0x1000>;
-				status = "disabled";
-				clocks = <&clk NPCM8XX_CLK_AHB>;
-				clock-names = "clk_ahb";
-			};
-
-			sha:sha@f085a000 {
-				compatible = "nuvoton,npcm845-sha";
-				reg = <0x0 0xf085a000 0x0 0x1000>;
-				status = "disabled";
-				clocks = <&clk NPCM8XX_CLK_AHB>;
-				clock-names = "clk_ahb";
-			};
 		};
 	};
 	pinctrl: pinctrl@f0800000 {
diff --git a/arch/arm/include/asm/arch-imx8m/imx-regs.h b/arch/arm/include/asm/arch-imx8m/imx-regs.h
index 6e2fc82..f1b7526 100644
--- a/arch/arm/include/asm/arch-imx8m/imx-regs.h
+++ b/arch/arm/include/asm/arch-imx8m/imx-regs.h
@@ -13,7 +13,7 @@
 #define ROM_VERSION_A0		IS_ENABLED(CONFIG_IMX8MQ) ? 0x800 : 0x800
 #define ROM_VERSION_B0		IS_ENABLED(CONFIG_IMX8MQ) ? 0x83C : 0x800
 
-#define M4_BOOTROM_BASE_ADDR   0x007E0000
+#define MCU_BOOTROM_BASE_ADDR   0x007E0000
 
 #define GPIO1_BASE_ADDR		0X30200000
 #define GPIO2_BASE_ADDR		0x30210000
@@ -40,6 +40,7 @@
 #define UART1_BASE_ADDR		0x30860000
 #define UART3_BASE_ADDR		0x30880000
 #define UART2_BASE_ADDR		0x30890000
+#define CAAM_BASE_ADDR		0x30900000
 #define I2C1_BASE_ADDR		0x30A20000
 #define I2C2_BASE_ADDR		0x30A30000
 #define I2C3_BASE_ADDR		0x30A40000
diff --git a/arch/arm/include/asm/arch-imx9/ccm_regs.h b/arch/arm/include/asm/arch-imx9/ccm_regs.h
index d326a6e..f6ec8fd 100644
--- a/arch/arm/include/asm/arch-imx9/ccm_regs.h
+++ b/arch/arm/include/asm/arch-imx9/ccm_regs.h
@@ -12,7 +12,7 @@
 #define ARM_A55_MTR_BUS_CLK_ROOT	1
 #define ARM_A55_CLK_ROOT		2
 #define M33_CLK_ROOT			3
-#define SENTINEL_CLK_ROOT		4
+#define ELE_CLK_ROOT			4
 #define BUS_WAKEUP_CLK_ROOT		5
 #define BUS_AON_CLK_ROOT		6
 #define WAKEUP_AXI_CLK_ROOT		7
diff --git a/arch/arm/include/asm/arch-mx6/imx-regs.h b/arch/arm/include/asm/arch-mx6/imx-regs.h
index 72944af..8fd3dd2 100644
--- a/arch/arm/include/asm/arch-mx6/imx-regs.h
+++ b/arch/arm/include/asm/arch-mx6/imx-regs.h
@@ -23,7 +23,7 @@
 #define GPU_ARB_END_ADDR                0x01803FFF
 #define APBH_DMA_ARB_BASE_ADDR          0x01804000
 #define APBH_DMA_ARB_END_ADDR           0x0180BFFF
-#define M4_BOOTROM_BASE_ADDR			0x007F8000
+#define MCU_BOOTROM_BASE_ADDR			0x007F8000
 
 #elif !defined(CONFIG_MX6SLL)
 #define CAAM_ARB_BASE_ADDR              0x00100000
diff --git a/arch/arm/include/asm/arch-mx7/imx-regs.h b/arch/arm/include/asm/arch-mx7/imx-regs.h
index c863cd9..6f5ae51 100644
--- a/arch/arm/include/asm/arch-mx7/imx-regs.h
+++ b/arch/arm/include/asm/arch-mx7/imx-regs.h
@@ -18,7 +18,7 @@
 #define GIC400_ARB_END_ADDR             0x31007FFF
 #define APBH_DMA_ARB_BASE_ADDR          0x33000000
 #define APBH_DMA_ARB_END_ADDR           0x33007FFF
-#define M4_BOOTROM_BASE_ADDR            0x00180000
+#define MCU_BOOTROM_BASE_ADDR            0x00180000
 
 #define MXS_APBH_BASE			APBH_DMA_ARB_BASE_ADDR
 #define MXS_GPMI_BASE			(APBH_DMA_ARB_BASE_ADDR + 0x02000)
diff --git a/arch/arm/include/asm/arch-npcm8xx/gcr.h b/arch/arm/include/asm/arch-npcm8xx/gcr.h
index ee6677a..20230d6 100644
--- a/arch/arm/include/asm/arch-npcm8xx/gcr.h
+++ b/arch/arm/include/asm/arch-npcm8xx/gcr.h
@@ -12,6 +12,7 @@
 /* On-Chip ARBEL NPCM8XX VERSIONS */
 #define ARBEL_Z1			0x00A35850
 #define ARBEL_A1			0x04a35850
+#define ARBEL_A2			0x08a35850
 #define ARBEL_NPCM845			0x00000000
 #define ARBEL_NPCM830			0x00300395
 #define ARBEL_NPCM810			0x00000220
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 0c13075..2a222c5 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -92,8 +92,8 @@
 	struct udevice *scu_dev;
 #endif
 
-#ifdef CONFIG_IMX_SENTINEL
-	struct udevice *s400_dev;
+#ifdef CONFIG_IMX_ELE
+	struct udevice *ele_dev;
 	u32 soc_rev;
 	u32 lifecycle;
 	u32 uid[4];
diff --git a/arch/arm/include/asm/mach-imx/ahab.h b/arch/arm/include/asm/mach-imx/ahab.h
new file mode 100644
index 0000000..4222e3d
--- /dev/null
+++ b/arch/arm/include/asm/mach-imx/ahab.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 NXP
+ */
+
+#ifndef __IMX_AHAB_H__
+#define __IMX_AHAB_H__
+
+#include <asm/mach-imx/image.h>
+
+int ahab_auth_cntr_hdr(struct container_hdr *container, u16 length);
+int ahab_auth_release(void);
+int ahab_verify_cntr_image(struct boot_img_t *img, int image_index);
+
+#endif
diff --git a/arch/arm/include/asm/mach-imx/s400_api.h b/arch/arm/include/asm/mach-imx/ele_api.h
similarity index 74%
rename from arch/arm/include/asm/mach-imx/s400_api.h
rename to arch/arm/include/asm/mach-imx/ele_api.h
index 5582ff1..cfd4ece 100644
--- a/arch/arm/include/asm/mach-imx/s400_api.h
+++ b/arch/arm/include/asm/mach-imx/ele_api.h
@@ -3,12 +3,12 @@
  * Copyright 2021 NXP
  */
 
-#ifndef __S400_API_H__
-#define __S400_API_H__
+#ifndef __ELE_API_H__
+#define __ELE_API_H__
 
-#define AHAB_VERSION    0x6
-#define AHAB_CMD_TAG    0x17
-#define AHAB_RESP_TAG   0xe1
+#define ELE_VERSION    0x6
+#define ELE_CMD_TAG    0x17
+#define ELE_RESP_TAG   0xe1
 
 /* ELE commands */
 #define ELE_PING_REQ (0x01)
@@ -24,6 +24,8 @@
 #define ELE_GET_FW_VERSION_REQ (0x9D)
 #define ELE_RET_LIFECYCLE_UP_REQ (0xA0)
 #define ELE_GET_EVENTS_REQ (0xA2)
+#define ELE_START_RNG (0xA3)
+#define ELE_GENERATE_DEK_BLOB (0xAF)
 #define ELE_ENABLE_PATCH_REQ (0xC3)
 #define ELE_RELEASE_RDC_REQ (0xC4)
 #define ELE_GET_FW_STATUS_REQ (0xC5)
@@ -109,17 +111,17 @@
 #define ELE_SUCCESS_IND (0xD6)
 #define ELE_FAILURE_IND (0x29)
 
-#define S400_MAX_MSG          255U
+#define ELE_MAX_MSG          255U
 
-struct sentinel_msg {
+struct ele_msg {
 	u8 version;
 	u8 size;
 	u8 command;
 	u8 tag;
-	u32 data[(S400_MAX_MSG - 1U)];
+	u32 data[(ELE_MAX_MSG - 1U)];
 };
 
-struct sentinel_get_info_data {
+struct ele_get_info_data {
 	u32 hdr;
 	u32 soc;
 	u32 lc;
@@ -130,19 +132,22 @@
 	u32 state;
 };
 
-int ahab_release_rdc(u8 core_id, u8 xrdc, u32 *response);
-int ahab_auth_oem_ctnr(ulong ctnr_addr, u32 *response);
-int ahab_release_container(u32 *response);
-int ahab_verify_image(u32 img_id, u32 *response);
-int ahab_forward_lifecycle(u16 life_cycle, u32 *response);
-int ahab_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response);
-int ahab_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *response);
-int ahab_release_caam(u32 core_did, u32 *response);
-int ahab_get_fw_version(u32 *fw_version, u32 *sha1, u32 *response);
-int ahab_dump_buffer(u32 *buffer, u32 buffer_length);
-int ahab_get_info(struct sentinel_get_info_data *info, u32 *response);
-int ahab_get_fw_status(u32 *status, u32 *response);
-int ahab_release_m33_trout(void);
-int ahab_get_events(u32 *events, u32 *events_cnt, u32 *response);
-
+int ele_release_rdc(u8 core_id, u8 xrdc, u32 *response);
+int ele_auth_oem_ctnr(ulong ctnr_addr, u32 *response);
+int ele_release_container(u32 *response);
+int ele_verify_image(u32 img_id, u32 *response);
+int ele_forward_lifecycle(u16 life_cycle, u32 *response);
+int ele_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response);
+int ele_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *response);
+int ele_release_caam(u32 core_did, u32 *response);
+int ele_get_fw_version(u32 *fw_version, u32 *sha1, u32 *response);
+int ele_get_events(u32 *events, u32 *events_cnt, u32 *response);
+int ele_generate_dek_blob(u32 key_id, u32 src_paddr, u32 dst_paddr, u32 max_output_size);
+int ele_dump_buffer(u32 *buffer, u32 buffer_length);
+int ele_get_info(struct ele_get_info_data *info, u32 *response);
+int ele_get_fw_status(u32 *status, u32 *response);
+int ele_release_m33_trout(void);
+int ele_write_secure_fuse(ulong signed_msg_blk, u32 *response);
+int ele_return_lifecycle_update(ulong signed_msg_blk, u32 *response);
+int ele_start_rng(void);
 #endif
diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h
index 85d9ca6..31ae179 100644
--- a/arch/arm/include/asm/mach-imx/sys_proto.h
+++ b/arch/arm/include/asm/mach-imx/sys_proto.h
@@ -236,6 +236,7 @@
 			  u64 *phys_sdram_2_start,
 			  u64 *phys_sdram_2_size);
 
+int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data);
 int arch_auxiliary_core_check_up(u32 core_id);
 
 int board_mmc_get_env_dev(int devno);
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 3266545..d94b582 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -31,7 +31,7 @@
 
 config IMX_BOOTAUX
 	bool "Support boot auxiliary core"
-	depends on ARCH_MX7 || ARCH_MX6 || ARCH_VF610 || ARCH_IMX8M
+	depends on ARCH_MX7 || ARCH_MX6 || ARCH_VF610 || ARCH_IMX8 || ARCH_IMX8M
 	help
 	  bootaux [addr] to boot auxiliary core.
 
@@ -86,6 +86,7 @@
 	select IMX_CAAM_DEK_ENCAP if ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP
 	select IMX_OPTEE_DEK_ENCAP if ARCH_IMX8M
 	select IMX_SECO_DEK_ENCAP if ARCH_IMX8
+	select IMX_ELE_DEK_ENCAP if ARCH_IMX8ULP || ARCH_IMX9
 	help
 	  This enables the 'dek_blob' command which is used with the
 	  Freescale secure boot mechanism. This command encapsulates and
@@ -113,6 +114,12 @@
 	  This enabled the DEK blob encapsulation with the SECO API. This option
 	  is only available on imx8.
 
+config IMX_ELE_DEK_ENCAP
+	bool "Support the DEK blob encapsulation with ELE"
+	help
+	  This enabled the DEK blob encapsulation with the ELE API. This option
+	  is only available on imx8ulp and imx9.
+
 config CMD_PRIBLOB
 	bool "Support the set_priblob_bitfield command"
 	depends on HAS_CAAM && IMX_HAB
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 00d6ad8..aebfa65 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -66,6 +66,11 @@
 obj-y += ddrmc-vf610.o
 obj-$(CONFIG_DDRMC_VF610_CALIBRATION) += ddrmc-vf610-calibration.o
 endif
+ifeq ($(SOC),$(filter $(SOC),imx8))
+ifneq ($(CONFIG_SPL_BUILD),y)
+obj-$(CONFIG_IMX_BOOTAUX) += imx_bootaux.o
+endif
+endif
 ifneq ($(CONFIG_SPL_BUILD),y)
 obj-$(CONFIG_CMD_BMODE) += cmd_bmode.o
 obj-$(CONFIG_CMD_HDMIDETECT) += cmd_hdmidet.o
diff --git a/arch/arm/mach-imx/cmd_dek.c b/arch/arm/mach-imx/cmd_dek.c
index 69ed575..6fa5b41 100644
--- a/arch/arm/mach-imx/cmd_dek.c
+++ b/arch/arm/mach-imx/cmd_dek.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright 2008-2015 Freescale Semiconductor, Inc.
+ * Copyright 2022 NXP
  *
  * Command for encapsulating DEK blob
  */
@@ -20,6 +21,11 @@
 #include <firmware/imx/sci/sci.h>
 #include <asm/mach-imx/image.h>
 #endif
+#ifdef CONFIG_IMX_ELE_DEK_ENCAP
+#include <asm/mach-imx/ele_api.h>
+#include <asm/mach-imx/image.h>
+#endif
+
 #include <cpu_func.h>
 
 /**
@@ -101,6 +107,7 @@
 			       0x0, &shm_output);
 	if (ret < 0) {
 		printf("Cannot register output shared memory 0x%X\n", ret);
+		tee_shm_free(shm_input);
 		goto error;
 	}
 
@@ -122,11 +129,11 @@
 	if (ret < 0)
 		printf("Cannot generate Blob with PTA DEK Blob 0x%X\n", ret);
 
-error:
 	/* Free shared memory */
 	tee_shm_free(shm_input);
 	tee_shm_free(shm_output);
 
+error:
 	/* Close session */
 	ret = tee_close_session(dev, arg.session);
 	if (ret < 0)
@@ -154,7 +161,7 @@
 
 static int blob_encap_dek(u32 src_addr, u32 dst_addr, u32 len)
 {
-	sc_err_t err;
+	int err;
 	sc_rm_mr_t mr_input, mr_output;
 	struct generate_key_blob_hdr hdr;
 	u8 in_size, out_size;
@@ -283,6 +290,84 @@
 }
 #endif /* CONFIG_IMX_SECO_DEK_ENCAP */
 
+#ifdef CONFIG_IMX_ELE_DEK_ENCAP
+
+#define DEK_BLOB_HDR_SIZE 8
+#define AHAB_PRIVATE_KEY 0x81
+#define AHAB_DEK_BLOB	 0x01
+#define AHAB_ALG_AES	 0x03
+#define AHAB_128_AES_KEY 0x10
+#define AHAB_192_AES_KEY 0x18
+#define AHAB_256_AES_KEY 0x20
+
+static int blob_encap_dek(u32 src_addr, u32 dst_addr, u32 len)
+{
+	u8 in_size, out_size;
+	u8 *src_ptr, *dst_ptr;
+	struct generate_key_blob_hdr hdr;
+
+	/* Set sizes */
+	in_size = sizeof(struct generate_key_blob_hdr) + len / 8;
+	out_size = BLOB_SIZE(len / 8) + DEK_BLOB_HDR_SIZE;
+
+	/* Get src and dst virtual addresses */
+	src_ptr = map_sysmem(src_addr, in_size);
+	dst_ptr = map_sysmem(dst_addr, out_size);
+
+	/* Check addr input */
+	if (!(src_ptr && dst_ptr)) {
+		debug("src_addr or dst_addr invalid\n");
+		return -1;
+	}
+
+	/* Build key header */
+	hdr.version = 0x0;
+	hdr.length_lsb = in_size;
+	hdr.length_msb = 0x00;
+	hdr.tag = AHAB_PRIVATE_KEY;
+	hdr.flags = AHAB_DEK_BLOB;
+	hdr.algorithm = AHAB_ALG_AES;
+	hdr.mode = 0x0; /* Not used by the ELE */
+
+	switch (len) {
+	case 128:
+		hdr.size = AHAB_128_AES_KEY;
+		break;
+	case 192:
+		hdr.size = AHAB_192_AES_KEY;
+		break;
+	case 256:
+		hdr.size = AHAB_256_AES_KEY;
+		break;
+	default:
+		/* Not supported */
+		debug("Invalid DEK size. Valid sizes are 128, 192 and 256b\n");
+		return -1;
+	}
+
+	/* Move input key and append blob header */
+	memmove((void *)(src_ptr + sizeof(struct generate_key_blob_hdr)),
+		(void *)src_ptr, len / 8);
+	memcpy((void *)src_ptr, (void *)&hdr,
+	       sizeof(struct generate_key_blob_hdr));
+
+	/* Flush the cache */
+	flush_dcache_range(src_addr, src_addr + in_size);
+	flush_dcache_range((ulong)dst_ptr, (ulong)(dst_ptr +
+			roundup(out_size, ARCH_DMA_MINALIGN)));
+
+	/* Call ELE */
+	if (ele_generate_dek_blob(0x00, src_addr, dst_addr, out_size))
+		return -1;
+
+	/* Invalidate output buffer */
+	invalidate_dcache_range((ulong)dst_ptr, (ulong)(dst_ptr +
+			roundup(out_size, ARCH_DMA_MINALIGN)));
+
+	return 0;
+}
+#endif /* CONFIG_IMX_ELE_DEK_ENCAP */
+
 /**
  * do_dek_blob() - Handle the "dek_blob" command-line command
  * @cmdtp:  Command data struct pointer
diff --git a/arch/arm/mach-imx/ele_ahab.c b/arch/arm/mach-imx/ele_ahab.c
index 99fc540..785b0d6 100644
--- a/arch/arm/mach-imx/ele_ahab.c
+++ b/arch/arm/mach-imx/ele_ahab.c
@@ -7,14 +7,13 @@
 #include <command.h>
 #include <errno.h>
 #include <asm/io.h>
-#include <asm/mach-imx/s400_api.h>
+#include <asm/mach-imx/ele_api.h>
 #include <asm/mach-imx/sys_proto.h>
 #include <asm/arch-imx/cpu.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/mach-imx/image.h>
 #include <console.h>
 #include <cpu_func.h>
-#include <asm/mach-imx/ahab.h>
 #include <asm/global_data.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -267,7 +266,7 @@
 	flush_dcache_range(IMG_CONTAINER_BASE,
 			   IMG_CONTAINER_BASE + ALIGN(length, CONFIG_SYS_CACHELINE_SIZE) - 1);
 
-	err = ahab_auth_oem_ctnr(IMG_CONTAINER_BASE, &resp);
+	err = ele_auth_oem_ctnr(IMG_CONTAINER_BASE, &resp);
 	if (err) {
 		printf("Authenticate container hdr failed, return %d, resp 0x%x\n",
 		       err, resp);
@@ -282,7 +281,7 @@
 	int err;
 	u32 resp;
 
-	err = ahab_release_container(&resp);
+	err = ele_release_container(&resp);
 	if (err) {
 		printf("Error: release container failed, resp 0x%x!\n", resp);
 		display_ahab_auth_ind(resp);
@@ -296,7 +295,7 @@
 	int err;
 	u32 resp;
 
-	err = ahab_verify_image(image_index, &resp);
+	err = ele_verify_image(image_index, &resp);
 	if (err) {
 		printf("Authenticate img %d failed, return %d, resp 0x%x\n",
 		       image_index, err, resp);
@@ -403,7 +402,7 @@
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
-	addr = simple_strtoul(argv[1], NULL, 16);
+	addr = hextoul(argv[1], NULL);
 
 	printf("Authenticate OS container at 0x%lx\n", addr);
 
@@ -485,7 +484,7 @@
 		return -EPERM;
 	}
 
-	err = ahab_forward_lifecycle(8, &resp);
+	err = ele_forward_lifecycle(8, &resp);
 	if (err != 0) {
 		printf("Error in forward lifecycle to OEM closed\n");
 		return -EIO;
@@ -502,7 +501,7 @@
 	int ret, i = 0;
 
 	do {
-		ret = ahab_dump_buffer(buffer, 32);
+		ret = ele_dump_buffer(buffer, 32);
 		if (ret < 0) {
 			printf("Error in dump AHAB log\n");
 			return -EIO;
@@ -547,7 +546,7 @@
 
 	display_life_cycle(lc);
 
-	ret = ahab_get_events(events, &cnt, NULL);
+	ret = ele_get_events(events, &cnt, NULL);
 	if (ret) {
 		printf("Get ELE EVENTS error %d\n", ret);
 		return CMD_RET_FAILURE;
@@ -564,6 +563,68 @@
 	return 0;
 }
 
+static int do_sec_fuse_prog(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	ulong addr;
+	u32 header, response;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	addr = hextoul(argv[1], NULL);
+	header = *(u32 *)addr;
+
+	if ((header & 0xff0000ff) != 0x89000000) {
+		printf("Wrong Signed message block format, header 0x%x\n", header);
+		return CMD_RET_FAILURE;
+	}
+
+	header = (header & 0xffff00) >> 8;
+
+	printf("Signed Message block at 0x%lx, size 0x%x\n", addr, header);
+	flush_dcache_range(addr, addr + header - 1);
+
+	if (ele_write_secure_fuse(addr, &response)) {
+		printf("Program secure fuse failed, response 0x%x\n", response);
+		return CMD_RET_FAILURE;
+	}
+
+	printf("Program secure fuse completed, response 0x%x\n", response);
+
+	return CMD_RET_SUCCESS;
+}
+
+static int do_ahab_return_lifecycle(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	ulong addr;
+	u32 header, response;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	addr = hextoul(argv[1], NULL);
+	header = *(u32 *)addr;
+
+	if ((header & 0xff0000ff) != 0x89000000) {
+		printf("Wrong Signed message block format, header 0x%x\n", header);
+		return CMD_RET_FAILURE;
+	}
+
+	header = (header & 0xffff00) >> 8;
+
+	printf("Signed Message block at 0x%lx, size 0x%x\n", addr, header);
+	flush_dcache_range(addr, addr + header - 1);
+
+	if (ele_return_lifecycle_update(addr, &response)) {
+		printf("Return lifecycle failed, response 0x%x\n", response);
+		return CMD_RET_FAILURE;
+	}
+
+	printf("Return lifecycle completed, response 0x%x\n", response);
+
+	return CMD_RET_SUCCESS;
+}
+
 U_BOOT_CMD(auth_cntr, CONFIG_SYS_MAXARGS, 1, do_authenticate,
 	   "autenticate OS container via AHAB",
 	   "addr\n"
@@ -584,3 +645,15 @@
 	   "display AHAB lifecycle only",
 	   ""
 );
+
+U_BOOT_CMD(ahab_sec_fuse_prog, CONFIG_SYS_MAXARGS, 1, do_sec_fuse_prog,
+	   "Program secure fuse via signed message block",
+	   "addr\n"
+	   "addr - Signed message block for secure fuse\n"
+);
+
+U_BOOT_CMD(ahab_return_lifecycle, CONFIG_SYS_MAXARGS, 1, do_ahab_return_lifecycle,
+	   "Return lifecycle to OEM field return via signed message block",
+	   "addr\n"
+	   "addr - Return lifecycle message block signed by OEM SRK\n"
+);
diff --git a/arch/arm/mach-imx/hab.c b/arch/arm/mach-imx/hab.c
index 439cdaf..b3ef36c 100644
--- a/arch/arm/mach-imx/hab.c
+++ b/arch/arm/mach-imx/hab.c
@@ -289,9 +289,10 @@
 };
 
 static char *sts_str[] = {
-			  "STS = HAB_SUCCESS (0xF0)\n",
+			  "STS = HAB_STS_ANY (0x00)\n",
 			  "STS = HAB_FAILURE (0x33)\n",
 			  "STS = HAB_WARNING (0x69)\n",
+			  "STS = HAB_SUCCESS (0xF0)\n",
 			  "STS = INVALID\n",
 			  NULL
 };
@@ -336,8 +337,7 @@
 	HAB_STS_ANY,
 	HAB_FAILURE,
 	HAB_WARNING,
-	HAB_SUCCESS,
-	-1
+	HAB_SUCCESS
 };
 
 static uint8_t hab_reasons[26] = {
@@ -365,8 +365,7 @@
 	HAB_UNS_ITEM,
 	HAB_UNS_KEY,
 	HAB_UNS_PROTOCOL,
-	HAB_UNS_STATE,
-	-1
+	HAB_UNS_STATE
 };
 
 static uint8_t hab_contexts[12] = {
@@ -380,8 +379,7 @@
 	HAB_CTX_COMMAND,
 	HAB_CTX_AUT_DAT,
 	HAB_CTX_ASSERT,
-	HAB_CTX_EXIT,
-	-1
+	HAB_CTX_EXIT
 };
 
 static uint8_t hab_engines[16] = {
@@ -399,30 +397,35 @@
 	HAB_ENG_ROM,
 	HAB_ENG_HDCP,
 	HAB_ENG_RTL,
-	HAB_ENG_SW,
-	-1
+	HAB_ENG_SW
 };
 
-static inline uint8_t get_idx(uint8_t *list, uint8_t tgt)
+static inline u32 get_idx(u8 *list, u8 tgt, u32 size)
 {
-	uint8_t idx = 0;
-	uint8_t element = list[idx];
-	while (element != -1) {
+	u32 idx = 0;
+	u8 element;
+
+	while (idx < size) {
+		element = list[idx];
 		if (element == tgt)
 			return idx;
-		element = list[++idx];
+		++idx;
 	}
-	return -1;
+	return idx;
 }
 
 static void process_event_record(uint8_t *event_data, size_t bytes)
 {
 	struct record *rec = (struct record *)event_data;
 
-	printf("\n\n%s", sts_str[get_idx(hab_statuses, rec->contents[0])]);
-	printf("%s", rsn_str[get_idx(hab_reasons, rec->contents[1])]);
-	printf("%s", ctx_str[get_idx(hab_contexts, rec->contents[2])]);
-	printf("%s", eng_str[get_idx(hab_engines, rec->contents[3])]);
+	printf("\n\n%s", sts_str[get_idx(hab_statuses, rec->contents[0],
+	       ARRAY_SIZE(hab_statuses))]);
+	printf("%s", rsn_str[get_idx(hab_reasons, rec->contents[1],
+	       ARRAY_SIZE(hab_reasons))]);
+	printf("%s", ctx_str[get_idx(hab_contexts, rec->contents[2],
+	       ARRAY_SIZE(hab_contexts))]);
+	printf("%s", eng_str[get_idx(hab_engines, rec->contents[3],
+	       ARRAY_SIZE(hab_engines))]);
 }
 
 static void display_event(uint8_t *event_data, size_t bytes)
diff --git a/arch/arm/mach-imx/image-container.c b/arch/arm/mach-imx/image-container.c
index 5b059a6..5f188ab 100644
--- a/arch/arm/mach-imx/image-container.c
+++ b/arch/arm/mach-imx/image-container.c
@@ -22,6 +22,25 @@
 #define QSPI_NOR_DEV	3
 #define ROM_API_DEV	4
 
+/* The unit of second image offset number which provision by the fuse bits */
+#define SND_IMG_OFF_UNIT    (0x100000UL)
+
+/*
+ * If num = 0, off = (2 ^ 2) * 1MB
+ * else If num = 2, off = (2 ^ 0) * 1MB
+ * else off = (2 ^ num) * 1MB
+ */
+#define SND_IMG_NUM_TO_OFF(num) \
+	((1UL << ((0 == (num)) ? 2 : (2 == (num)) ? 0 : (num))) * SND_IMG_OFF_UNIT)
+
+#define GET_SND_IMG_NUM(fuse) (((fuse) >> 24) & 0x1F)
+
+#if defined(CONFIG_IMX8QM)
+#define FUSE_IMG_SET_OFF_WORD 464
+#elif defined(CONFIG_IMX8QXP)
+#define FUSE_IMG_SET_OFF_WORD 720
+#endif
+
 int get_container_size(ulong addr, u16 *header_length)
 {
 	struct container_hdr *phdr;
@@ -31,7 +50,7 @@
 	u32 max_offset = 0, img_end;
 
 	phdr = (struct container_hdr *)addr;
-	if (phdr->tag != 0x87 && phdr->version != 0x0) {
+	if (phdr->tag != 0x87 || phdr->version != 0x0) {
 		debug("Wrong container header\n");
 		return -EFAULT;
 	}
@@ -136,15 +155,53 @@
 	return ret;
 }
 
+static bool check_secondary_cnt_set(unsigned long *set_off)
+{
+#if IS_ENABLED(CONFIG_ARCH_IMX8)
+	int ret;
+	u8 set_id = 1;
+	u32 fuse_val = 0;
+
+	if (!(is_imx8qxp() && is_soc_rev(CHIP_REV_B))) {
+		ret = sc_misc_get_boot_container(-1, &set_id);
+		if (ret)
+			return false;
+		/* Secondary boot */
+		if (set_id == 2) {
+			ret = sc_misc_otp_fuse_read(-1, FUSE_IMG_SET_OFF_WORD, &fuse_val);
+			if (!ret) {
+				if (set_off)
+					*set_off = SND_IMG_NUM_TO_OFF(GET_SND_IMG_NUM(fuse_val));
+				return true;
+			}
+		}
+	}
+#endif
+
+	return false;
+}
+
 static unsigned long get_boot_device_offset(void *dev, int dev_type)
 {
-	unsigned long offset = 0;
+	unsigned long offset = 0, sec_set_off = 0;
+	bool sec_boot = false;
+
+	if (dev_type == ROM_API_DEV) {
+		offset = (unsigned long)dev;
+		return offset;
+	}
+
+	sec_boot = check_secondary_cnt_set(&sec_set_off);
+	if (sec_boot)
+		printf("Secondary set selected\n");
+	else
+		printf("Primary set selected\n");
 
 	if (dev_type == MMC_DEV) {
 		struct mmc *mmc = (struct mmc *)dev;
 
 		if (IS_SD(mmc) || mmc->part_config == MMCPART_NOAVAILABLE) {
-			offset = CONTAINER_HDR_MMCSD_OFFSET;
+			offset = sec_boot ? sec_set_off : CONTAINER_HDR_MMCSD_OFFSET;
 		} else {
 			u8 part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
 
@@ -154,19 +211,23 @@
 				else
 					offset = CONTAINER_HDR_EMMC_OFFSET;
 			} else {
-				offset = CONTAINER_HDR_MMCSD_OFFSET;
+				offset = sec_boot ? sec_set_off : CONTAINER_HDR_MMCSD_OFFSET;
 			}
 		}
 	} else if (dev_type == QSPI_DEV) {
-		offset = CONTAINER_HDR_QSPI_OFFSET;
+		offset = sec_boot ? (sec_set_off + CONTAINER_HDR_QSPI_OFFSET) :
+			CONTAINER_HDR_QSPI_OFFSET;
 	} else if (dev_type == NAND_DEV) {
-		offset = CONTAINER_HDR_NAND_OFFSET;
+		offset = sec_boot ? (sec_set_off + CONTAINER_HDR_NAND_OFFSET) :
+			CONTAINER_HDR_NAND_OFFSET;
 	} else if (dev_type == QSPI_NOR_DEV) {
 		offset = CONTAINER_HDR_QSPI_OFFSET + 0x08000000;
-	} else if (dev_type == ROM_API_DEV) {
-		offset = (unsigned long)dev;
+	} else {
+		printf("Not supported dev_type: %d\n", dev_type);
 	}
 
+	debug("container set offset 0x%lx\n", offset);
+
 	return offset;
 }
 
@@ -227,6 +288,25 @@
 
 	return end / mmc->read_bl_len;
 }
+
+int spl_mmc_emmc_boot_partition(struct mmc *mmc)
+{
+	int part;
+
+	part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
+	if (part == 1 || part == 2) {
+		unsigned long sec_set_off = 0;
+		bool sec_boot = false;
+
+		sec_boot = check_secondary_cnt_set(&sec_set_off);
+		if (sec_boot)
+			part = (part == 1) ? 2 : 1;
+	} else if (part == 7) {
+		part = 0;
+	}
+
+	return part;
+}
 #endif
 
 #ifdef CONFIG_SPL_NAND_SUPPORT
diff --git a/arch/arm/mach-imx/imx8/ahab.c b/arch/arm/mach-imx/imx8/ahab.c
index 9addb82..b58b14c 100644
--- a/arch/arm/mach-imx/imx8/ahab.c
+++ b/arch/arm/mach-imx/imx8/ahab.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright 2018-2019 NXP
+ * Copyright 2018-2019, 2022 NXP
  */
 
 #include <common.h>
@@ -16,6 +16,8 @@
 #include <asm/mach-imx/image.h>
 #include <console.h>
 #include <cpu_func.h>
+#include "u-boot/sha256.h"
+#include <asm/mach-imx/ahab.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -24,6 +26,86 @@
 #define SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE  (0x60000000UL)
 
 #define SECO_PT                 2U
+#define AHAB_HASH_TYPE_MASK	0x00000700
+#define AHAB_HASH_TYPE_SHA256	0
+
+int ahab_auth_cntr_hdr(struct container_hdr *container, u16 length)
+{
+	int err;
+
+	memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)container,
+	       ALIGN(length, CONFIG_SYS_CACHELINE_SIZE));
+
+	err = sc_seco_authenticate(-1, SC_SECO_AUTH_CONTAINER,
+				   SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE);
+	if (err)
+		printf("Authenticate container hdr failed, return %d\n", err);
+
+	return err;
+}
+
+int ahab_auth_release(void)
+{
+	int err;
+
+	err = sc_seco_authenticate(-1, SC_SECO_REL_CONTAINER, 0);
+	if (err)
+		printf("Error: release container failed!\n");
+
+	return err;
+}
+
+int ahab_verify_cntr_image(struct boot_img_t *img, int image_index)
+{
+	sc_faddr_t start, end;
+	sc_rm_mr_t mr;
+	int err;
+	int ret = 0;
+
+	debug("img %d, dst 0x%llx, src 0x%x, size 0x%x\n",
+	      image_index, img->dst, img->offset, img->size);
+
+	/* Find the memreg and set permission for seco pt */
+	err = sc_rm_find_memreg(-1, &mr,
+				img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1),
+				ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE) - 1);
+
+	if (err) {
+		printf("Error: can't find memreg for image load address 0x%llx, error %d\n",
+		       img->dst, err);
+		return -ENOMEM;
+	}
+
+	err = sc_rm_get_memreg_info(-1, mr, &start, &end);
+	if (!err)
+		debug("memreg %u 0x%llx -- 0x%llx\n", mr, start, end);
+
+	err = sc_rm_set_memreg_permissions(-1, mr,
+					   SECO_PT, SC_RM_PERM_FULL);
+	if (err) {
+		printf("Set permission failed for img %d, error %d\n",
+		       image_index, err);
+		return -EPERM;
+	}
+
+	err = sc_seco_authenticate(-1, SC_SECO_VERIFY_IMAGE,
+				   1 << image_index);
+	if (err) {
+		printf("Authenticate img %d failed, return %d\n",
+		       image_index, err);
+		ret = -EIO;
+	}
+
+	err = sc_rm_set_memreg_permissions(-1, mr,
+					   SECO_PT, SC_RM_PERM_NONE);
+	if (err) {
+		printf("Remove permission failed for img %d, error %d\n",
+		       image_index, err);
+		ret = -EPERM;
+	}
+
+	return ret;
+}
 
 static inline bool check_in_dram(ulong addr)
 {
@@ -46,11 +128,12 @@
 	struct container_hdr *phdr;
 	int i, ret = 0;
 	int err;
-	sc_rm_mr_t mr;
-	sc_faddr_t start, end;
 	u16 length;
 	struct boot_img_t *img;
 	unsigned long s, e;
+#ifdef CONFIG_ARMV8_CE_SHA256
+	u8 hash_value[SHA256_SUM_LEN];
+#endif
 
 	if (addr % 4) {
 		puts("Error: Image's address is not 4 byte aligned\n");
@@ -76,14 +159,9 @@
 	length = phdr->length_lsb + (phdr->length_msb << 8);
 
 	debug("container length %u\n", length);
-	memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)addr,
-	       ALIGN(length, CONFIG_SYS_CACHELINE_SIZE));
 
-	err = sc_seco_authenticate(-1, SC_SECO_AUTH_CONTAINER,
-				   SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE);
+	err = ahab_auth_cntr_hdr(phdr, length);
 	if (err) {
-		printf("Authenticate container hdr failed, return %d\n",
-		       err);
 		ret = -EIO;
 		goto exit;
 	}
@@ -105,50 +183,27 @@
 
 		flush_dcache_range(s, e);
 
-		/* Find the memreg and set permission for seco pt */
-		err = sc_rm_find_memreg(-1, &mr, s, e);
-		if (err) {
-			printf("Error: can't find memreg for image load address 0x%llx, error %d\n", img->dst, err);
-			ret = -ENOMEM;
-			goto exit;
-		}
-
-		err = sc_rm_get_memreg_info(-1, mr, &start, &end);
-		if (!err)
-			debug("memreg %u 0x%llx -- 0x%llx\n", mr, start, end);
-
-		err = sc_rm_set_memreg_permissions(-1, mr, SECO_PT,
-						   SC_RM_PERM_FULL);
-		if (err) {
-			printf("Set permission failed for img %d, error %d\n",
-			       i, err);
-			ret = -EPERM;
-			goto exit;
-		}
-
-		err = sc_seco_authenticate(-1, SC_SECO_VERIFY_IMAGE,
-					   (1 << i));
-		if (err) {
-			printf("Authenticate img %d failed, return %d\n",
-			       i, err);
-			ret = -EIO;
+#ifdef CONFIG_ARMV8_CE_SHA256
+		if (((img->hab_flags & AHAB_HASH_TYPE_MASK) >> 8) == AHAB_HASH_TYPE_SHA256) {
+			sha256_csum_wd((void *)img->dst, img->size, hash_value, CHUNKSZ_SHA256);
+			err = memcmp(&img->hash, &hash_value, SHA256_SUM_LEN);
+			if (err) {
+				printf("img %d hash comparison failed, error %d\n", i, err);
+				ret = -EIO;
+				goto exit;
+			}
+		} else {
+#endif
+			ret = ahab_verify_cntr_image(img, i);
+			if (ret)
+				goto exit;
+#ifdef CONFIG_ARMV8_CE_SHA256
 		}
-
-		err = sc_rm_set_memreg_permissions(-1, mr, SECO_PT,
-						   SC_RM_PERM_NONE);
-		if (err) {
-			printf("Remove permission failed for img %d, err %d\n",
-			       i, err);
-			ret = -EPERM;
-		}
-
-		if (ret)
-			goto exit;
+#endif
 	}
 
 exit:
-	if (sc_seco_authenticate(-1, SC_SECO_REL_CONTAINER, 0) != SC_ERR_NONE)
-		printf("Error: release container failed!\n");
+	ahab_auth_release();
 
 	return ret;
 }
@@ -263,7 +318,7 @@
 	u16 lc;
 
 	err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL);
-	if (err != SC_ERR_NONE) {
+	if (err) {
 		printf("Error in get lifecycle\n");
 		return -EIO;
 	}
@@ -271,7 +326,7 @@
 	display_life_cycle(lc);
 
 	err = sc_seco_get_event(-1, idx, &event);
-	while (err == SC_ERR_NONE) {
+	while (!err) {
 		printf("SECO Event[%u] = 0x%08X\n", idx, event);
 		display_ahab_auth_event(event);
 
@@ -312,7 +367,7 @@
 		return -EACCES;
 
 	err = sc_seco_chip_info(-1, &lc, NULL, NULL, NULL);
-	if (err != SC_ERR_NONE) {
+	if (err) {
 		printf("Error in get lifecycle\n");
 		return -EIO;
 	}
@@ -324,7 +379,7 @@
 	}
 
 	err = sc_seco_forward_lifecycle(-1, 16);
-	if (err != SC_ERR_NONE) {
+	if (err) {
 		printf("Error in forward lifecycle to OEM closed\n");
 		return -EIO;
 	}
diff --git a/arch/arm/mach-imx/imx8/cpu.c b/arch/arm/mach-imx/imx8/cpu.c
index 7b292c07..c623570 100644
--- a/arch/arm/mach-imx/imx8/cpu.c
+++ b/arch/arm/mach-imx/imx8/cpu.c
@@ -26,6 +26,8 @@
 #include <asm/armv8/mmu.h>
 #include <asm/setup.h>
 #include <asm/mach-imx/boot_mode.h>
+#include <power-domain.h>
+#include <elf.h>
 #include <spl.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -107,6 +109,178 @@
 }
 #endif
 
+#ifdef CONFIG_IMX_BOOTAUX
+
+#ifdef CONFIG_IMX8QM
+int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
+{
+	sc_rsrc_t core_rsrc, mu_rsrc;
+	sc_faddr_t tcml_addr;
+	u32 tcml_size = SZ_128K;
+	ulong addr;
+
+	switch (core_id) {
+	case 0:
+		core_rsrc = SC_R_M4_0_PID0;
+		tcml_addr = 0x34FE0000;
+		mu_rsrc = SC_R_M4_0_MU_1A;
+		break;
+	case 1:
+		core_rsrc = SC_R_M4_1_PID0;
+		tcml_addr = 0x38FE0000;
+		mu_rsrc = SC_R_M4_1_MU_1A;
+		break;
+	default:
+		printf("Not support this core boot up, ID:%u\n", core_id);
+		return -EINVAL;
+	}
+
+	addr = (sc_faddr_t)boot_private_data;
+
+	if (addr >= tcml_addr && addr <= tcml_addr + tcml_size) {
+		printf("Wrong image address 0x%lx, should not in TCML\n",
+		       addr);
+		return -EINVAL;
+	}
+
+	printf("Power on M4 and MU\n");
+
+	if (sc_pm_set_resource_power_mode(-1, core_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE)
+		return -EIO;
+
+	if (sc_pm_set_resource_power_mode(-1, mu_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE)
+		return -EIO;
+
+	printf("Copy M4 image from 0x%lx to TCML 0x%lx\n", addr, (ulong)tcml_addr);
+
+	if (addr != tcml_addr)
+		memcpy((void *)tcml_addr, (void *)addr, tcml_size);
+
+	printf("Start M4 %u\n", core_id);
+	if (sc_pm_cpu_start(-1, core_rsrc, true, tcml_addr) != SC_ERR_NONE)
+		return -EIO;
+
+	printf("bootaux complete\n");
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_IMX8QXP
+int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
+{
+	sc_rsrc_t core_rsrc, mu_rsrc = SC_R_NONE;
+	sc_faddr_t aux_core_ram;
+	u32 size;
+	ulong addr;
+
+	switch (core_id) {
+	case 0:
+		core_rsrc = SC_R_M4_0_PID0;
+		aux_core_ram = 0x34FE0000;
+		mu_rsrc = SC_R_M4_0_MU_1A;
+		size = SZ_128K;
+		break;
+	case 1:
+		core_rsrc = SC_R_DSP;
+		aux_core_ram = 0x596f8000;
+		size = SZ_2K;
+		break;
+	default:
+		printf("Not support this core boot up, ID:%u\n", core_id);
+		return -EINVAL;
+	}
+
+	addr = (sc_faddr_t)boot_private_data;
+
+	if (addr >= aux_core_ram && addr <= aux_core_ram + size) {
+		printf("Wrong image address 0x%lx, should not in aux core ram\n",
+		       addr);
+		return -EINVAL;
+	}
+
+	printf("Power on aux core %d\n", core_id);
+
+	if (sc_pm_set_resource_power_mode(-1, core_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE)
+		return -EIO;
+
+	if (mu_rsrc != SC_R_NONE) {
+		if (sc_pm_set_resource_power_mode(-1, mu_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE)
+			return -EIO;
+	}
+
+	if (core_id == 1) {
+		struct power_domain pd;
+
+		if (sc_pm_clock_enable(-1, core_rsrc, SC_PM_CLK_PER, true, false) != SC_ERR_NONE) {
+			printf("Error enable clock\n");
+			return -EIO;
+		}
+
+		if (!power_domain_lookup_name("audio_sai0", &pd)) {
+			if (power_domain_on(&pd)) {
+				printf("Error power on SAI0\n");
+				return -EIO;
+			}
+		}
+
+		if (!power_domain_lookup_name("audio_ocram", &pd)) {
+			if (power_domain_on(&pd)) {
+				printf("Error power on HIFI RAM\n");
+				return -EIO;
+			}
+		}
+	}
+
+	printf("Copy image from 0x%lx to 0x%lx\n", addr, (ulong)aux_core_ram);
+	if (core_id == 0) {
+		/* M4 use bin file */
+		memcpy((void *)aux_core_ram, (void *)addr, size);
+	} else {
+		/* HIFI use elf file */
+		if (!valid_elf_image(addr))
+			return -1;
+		addr = load_elf_image_shdr(addr);
+	}
+
+	printf("Start %s\n", core_id == 0 ? "M4" : "HIFI");
+
+	if (sc_pm_cpu_start(-1, core_rsrc, true, aux_core_ram) != SC_ERR_NONE)
+		return -EIO;
+
+	printf("bootaux complete\n");
+	return 0;
+}
+#endif
+
+int arch_auxiliary_core_check_up(u32 core_id)
+{
+	sc_rsrc_t core_rsrc;
+	sc_pm_power_mode_t power_mode;
+
+	switch (core_id) {
+	case 0:
+		core_rsrc = SC_R_M4_0_PID0;
+		break;
+#ifdef CONFIG_IMX8QM
+	case 1:
+		core_rsrc = SC_R_M4_1_PID0;
+		break;
+#endif
+	default:
+		printf("Not support this core, ID:%u\n", core_id);
+		return 0;
+	}
+
+	if (sc_pm_get_resource_power_mode(-1, core_rsrc, &power_mode) != SC_ERR_NONE)
+		return 0;
+
+	if (power_mode != SC_PM_PW_MODE_OFF)
+		return 1;
+
+	return 0;
+}
+#endif
+
 int print_bootinfo(void)
 {
 	enum boot_device bt_dev = get_boot_device();
@@ -195,7 +369,7 @@
 #define FUSE_UNIQUE_ID_WORD1 17
 void get_board_serial(struct tag_serialnr *serialnr)
 {
-	sc_err_t err;
+	int err;
 	u32 val1 = 0, val2 = 0;
 	u32 word1, word2;
 
@@ -206,13 +380,13 @@
 	word2 = FUSE_UNIQUE_ID_WORD1;
 
 	err = sc_misc_otp_fuse_read(-1, word1, &val1);
-	if (err != SC_ERR_NONE) {
+	if (err) {
 		printf("%s fuse %d read error: %d\n", __func__, word1, err);
 		return;
 	}
 
 	err = sc_misc_otp_fuse_read(-1, word2, &val2);
-	if (err != SC_ERR_NONE) {
+	if (err) {
 		printf("%s fuse %d read error: %d\n", __func__, word2, err);
 		return;
 	}
diff --git a/arch/arm/mach-imx/imx8/fdt.c b/arch/arm/mach-imx/imx8/fdt.c
index 02b3ee5..491c8bb 100644
--- a/arch/arm/mach-imx/imx8/fdt.c
+++ b/arch/arm/mach-imx/imx8/fdt.c
@@ -110,7 +110,7 @@
 
 	err = sc_rm_set_master_sid(-1, rsrc, sid);
 	debug("set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err);
-	if (err != SC_ERR_NONE) {
+	if (err) {
 		if (!check_owned_resource(rsrc)) {
 			printf("%s rsrc[%d] not owned\n", __func__, rsrc);
 			return -1;
diff --git a/arch/arm/mach-imx/imx8/snvs_security_sc.c b/arch/arm/mach-imx/imx8/snvs_security_sc.c
index d7b20a1..1eaa68f 100644
--- a/arch/arm/mach-imx/imx8/snvs_security_sc.c
+++ b/arch/arm/mach-imx/imx8/snvs_security_sc.c
@@ -286,16 +286,15 @@
 				     u32 *_p3, u32 *_p4, u32 *_p5,
 				     u32 _cnt)
 {
-	int scierr = 0;
+	int err;
 	u32 d1 = ptr_value(_p1);
 	u32 d2 = ptr_value(_p2);
 	u32 d3 = ptr_value(_p3);
 	u32 d4 = ptr_value(_p4);
 	u32 d5 = ptr_value(_p5);
 
-	scierr = sc_seco_secvio_config(-1, id, SC_WRITE_CONF, &d1, &d2, &d3,
-				       &d4, &d4, _cnt);
-	if (scierr != SC_ERR_NONE) {
+	err = sc_seco_secvio_config(-1, id, SC_WRITE_CONF, &d1, &d2, &d3, &d4, &d4, _cnt);
+	if (err) {
 		printf("Failed to set secvio configuration\n");
 		debug("Failed to set conf id 0x%x with values ", id);
 		debug("0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x (cnt: %d)\n",
@@ -315,7 +314,7 @@
 		*(u32 *)_p5 = d5;
 
 exit:
-	return scierr;
+	return err;
 }
 
 #define SC_CHECK_WRITE1(id, _p1) \
@@ -323,7 +322,7 @@
 
 static int apply_snvs_config(struct snvs_security_sc_conf *cnf)
 {
-	int scierr = 0;
+	int err = 0;
 
 	debug("%s\n", __func__);
 
@@ -365,92 +364,88 @@
 			cnf->lp.act_tamper_routing_ctl1,
 			cnf->lp.act_tamper_routing_ctl2);
 
-	scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_filt_cfg),
-					   &cnf->lp.tamper_filt_cfg,
-					   &cnf->lp.tamper_filt1_cfg,
-					   &cnf->lp.tamper_filt2_cfg, NULL,
-					   NULL, 3);
-	if (scierr != SC_ERR_NONE)
+	err = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_filt_cfg),
+					&cnf->lp.tamper_filt_cfg,
+					&cnf->lp.tamper_filt1_cfg,
+					&cnf->lp.tamper_filt2_cfg,
+					NULL, NULL, 3);
+	if (err)
 		goto exit;
 
 	/* Configure AT */
-	scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.act_tamper1_cfg),
-					   &cnf->lp.act_tamper1_cfg,
-					   &cnf->lp.act_tamper2_cfg,
-					   &cnf->lp.act_tamper2_cfg,
-					   &cnf->lp.act_tamper2_cfg,
-					   &cnf->lp.act_tamper2_cfg, 5);
-	if (scierr != SC_ERR_NONE)
+	err = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.act_tamper1_cfg),
+					&cnf->lp.act_tamper1_cfg,
+					&cnf->lp.act_tamper2_cfg,
+					&cnf->lp.act_tamper2_cfg,
+					&cnf->lp.act_tamper2_cfg,
+					&cnf->lp.act_tamper2_cfg, 5);
+	if (err)
 		goto exit;
 
 	/* Configure AT routing */
-	scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.act_tamper_routing_ctl1),
-					   &cnf->lp.act_tamper_routing_ctl1,
-					   &cnf->lp.act_tamper_routing_ctl2,
-					   NULL, NULL, NULL, 2);
-	if (scierr != SC_ERR_NONE)
+	err = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.act_tamper_routing_ctl1),
+					&cnf->lp.act_tamper_routing_ctl1,
+					&cnf->lp.act_tamper_routing_ctl2,
+					NULL, NULL, NULL, 2);
+	if (err)
 		goto exit;
 
 	/* Configure AT frequency */
-	scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.act_tamper_clk_ctl),
-				 &cnf->lp.act_tamper_clk_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.act_tamper_clk_ctl),
+			      &cnf->lp.act_tamper_clk_ctl);
+	if (err)
 		goto exit;
 
 	/* Activate the ATs */
-	scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.act_tamper_ctl),
-				 &cnf->lp.act_tamper_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.act_tamper_ctl), &cnf->lp.act_tamper_ctl);
+	if (err)
 		goto exit;
 
 	/* Activate the detectors */
-	scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_det_cfg),
-					   &cnf->lp.tamper_det_cfg,
-					   &cnf->lp.tamper_det_cfg2, NULL, NULL,
-					   NULL, 2);
-	if (scierr != SC_ERR_NONE)
+	err = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_det_cfg),
+					&cnf->lp.tamper_det_cfg,
+					&cnf->lp.tamper_det_cfg2, NULL, NULL, NULL, 2);
+	if (err)
 		goto exit;
 
 	/* Configure LP secvio */
-	scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.secvio_ctl),
-				 &cnf->lp.secvio_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.secvio_ctl), &cnf->lp.secvio_ctl);
+	if (err)
 		goto exit;
 
 	/* Configure HP secvio */
-	scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(hp.secvio_ctl),
-				 &cnf->hp.secvio_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(hp.secvio_ctl), &cnf->hp.secvio_ctl);
+	if (err)
 		goto exit;
 
 	/* Lock access */
-	scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(hp.lock), &cnf->hp.lock);
-	if (scierr != SC_ERR_NONE)
+	err = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(hp.lock), &cnf->hp.lock);
+	if (err)
 		goto exit;
 
-	scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.lock), &cnf->lp.lock);
-	if (scierr != SC_ERR_NONE)
+	err = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.lock), &cnf->lp.lock);
+	if (err)
 		goto exit;
 
 exit:
-	return (scierr == SC_ERR_NONE) ? 0 : -EIO;
+	return err;
 }
 
 static int dgo_write(u32 _id, u8 _access, u32 *_pdata)
 {
-	int scierr = sc_seco_secvio_dgo_config(-1, _id, _access, _pdata);
+	int err = sc_seco_secvio_dgo_config(-1, _id, _access, _pdata);
 
-	if (scierr != SC_ERR_NONE) {
+	if (err) {
 		printf("Failed to set dgo configuration\n");
 		debug("Failed to set conf id 0x%x : 0x%.8x", _id, *_pdata);
 	}
 
-	return scierr;
+	return err;
 }
 
 static int apply_snvs_dgo_config(struct snvs_dgo_conf *cnf)
 {
-	int scierr = 0;
+	int err;
 
 	debug("%s\n", __func__);
 
@@ -468,50 +463,50 @@
 			cnf->tamper_misc_ctl,
 			cnf->tamper_core_volt_mon_ctl);
 
-	dgo_write(0x04, 1, &cnf->tamper_offset_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = dgo_write(0x04, 1, &cnf->tamper_offset_ctl);
+	if (err)
 		goto exit;
 
-	dgo_write(0x14, 1, &cnf->tamper_pull_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = dgo_write(0x14, 1, &cnf->tamper_pull_ctl);
+	if (err)
 		goto exit;
 
-	dgo_write(0x24, 1, &cnf->tamper_ana_test_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = dgo_write(0x24, 1, &cnf->tamper_ana_test_ctl);
+	if (err)
 		goto exit;
 
-	dgo_write(0x34, 1, &cnf->tamper_sensor_trim_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = dgo_write(0x34, 1, &cnf->tamper_sensor_trim_ctl);
+	if (err)
 		goto exit;
 
-	dgo_write(0x54, 1, &cnf->tamper_core_volt_mon_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = dgo_write(0x54, 1, &cnf->tamper_core_volt_mon_ctl);
+	if (err)
 		goto exit;
 
 	/* Last as it could lock the writes */
-	dgo_write(0x44, 1, &cnf->tamper_misc_ctl);
-	if (scierr != SC_ERR_NONE)
+	err = dgo_write(0x44, 1, &cnf->tamper_misc_ctl);
+	if (err)
 		goto exit;
 
 exit:
-	return (scierr == SC_ERR_NONE) ? 0 : -EIO;
+	return err;
 }
 
 static int pad_write(u32 _pad, u32 _value)
 {
-	int scierr = sc_pad_set(-1, _pad, _value);
+	int err = sc_pad_set(-1, _pad, _value);
 
-	if (scierr != SC_ERR_NONE) {
+	if (err) {
 		printf("Failed to set pad configuration\n");
 		debug("Failed to set conf pad 0x%x : 0x%.8x", _pad, _value);
 	}
 
-	return scierr;
+	return err;
 }
 
 static int apply_tamper_pin_list_config(struct tamper_pin_cfg *confs, u32 size)
 {
-	int scierr = 0;
+	int err = 0;
 	u32 idx;
 
 	debug("%s\n", __func__);
@@ -519,13 +514,13 @@
 	for (idx = 0; idx < size; idx++) {
 		debug("\t idx %d: pad %d: 0x%.8x\n", idx, confs[idx].pad,
 		      confs[idx].mux_conf);
-		pad_write(confs[idx].pad, 3 << 30 | confs[idx].mux_conf);
-		if (scierr != SC_ERR_NONE)
+		err = pad_write(confs[idx].pad, 3 << 30 | confs[idx].mux_conf);
+		if (err)
 			goto exit;
 	}
 
 exit:
-	return (scierr == SC_ERR_NONE) ? 0 : -EIO;
+	return err;
 }
 
 int examples(void)
@@ -753,7 +748,7 @@
 static int do_snvs_clear_status(struct cmd_tbl *cmdtp, int flag, int argc,
 				char *const argv[])
 {
-	int scierr = 0;
+	int err;
 	u32 idx = 0;
 
 	struct snvs_security_sc_conf conf = {0};
@@ -764,20 +759,18 @@
 	conf.lp.status = hextoul(argv[++idx], NULL);
 	conf.lp.tamper_det_status = hextoul(argv[++idx], NULL);
 
-	scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.status),
-					   &conf.lp.status, NULL, NULL, NULL,
-					   NULL, 1);
-	if (scierr != SC_ERR_NONE)
+	err = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.status),
+					&conf.lp.status, NULL, NULL, NULL, NULL, 1);
+	if (err)
 		goto exit;
 
-	scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_det_status),
-					   &conf.lp.tamper_det_status, NULL,
-					   NULL, NULL, NULL, 1);
-	if (scierr != SC_ERR_NONE)
+	err = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_det_status),
+					&conf.lp.tamper_det_status, NULL, NULL, NULL, NULL, 1);
+	if (err)
 		goto exit;
 
 exit:
-	return (scierr == SC_ERR_NONE) ? 0 : 1;
+	return err;
 }
 
 U_BOOT_CMD(snvs_clear_status,
@@ -793,7 +786,7 @@
 static int do_snvs_sec_status(struct cmd_tbl *cmdtp, int flag, int argc,
 			      char *const argv[])
 {
-	int scierr;
+	int err;
 	u32 idx;
 
 	u32 data[5];
@@ -864,8 +857,8 @@
 	for (idx = 0; idx < ARRAY_SIZE(pads); idx++) {
 		u8 pad_id = pads[idx];
 
-		scierr = sc_pad_get(-1, pad_id, &data[0]);
-		if (scierr == 0)
+		err = sc_pad_get(-1, pad_id, &data[0]);
+		if (!err)
 			printf("\t- Pin %d: %.8x\n", pad_id, data[0]);
 		else
 			printf("Failed to read Pin %d\n", pad_id);
@@ -876,8 +869,8 @@
 	for (idx = 0; idx < ARRAY_SIZE(fuses); idx++) {
 		u32 fuse_id = fuses[idx];
 
-		scierr = sc_misc_otp_fuse_read(-1, fuse_id, &data[0]);
-		if (scierr == 0)
+		err = sc_misc_otp_fuse_read(-1, fuse_id, &data[0]);
+		if (!err)
 			printf("\t- Fuse %d: %.8x\n", fuse_id, data[0]);
 		else
 			printf("Failed to read Fuse %d\n", fuse_id);
@@ -888,10 +881,10 @@
 	for (idx = 0; idx < ARRAY_SIZE(snvs); idx++) {
 		struct snvs_reg *reg = &snvs[idx];
 
-		scierr = sc_seco_secvio_config(-1, reg->id, 0, &data[0],
-					       &data[1], &data[2], &data[3],
-					       &data[4], reg->nb);
-		if (scierr == 0) {
+		err = sc_seco_secvio_config(-1, reg->id, 0, &data[0],
+					    &data[1], &data[2], &data[3],
+					    &data[4], reg->nb);
+		if (!err) {
 			int subidx;
 
 			printf("\t- SNVS %.2x(%d):", reg->id, reg->nb);
@@ -908,8 +901,8 @@
 	for (idx = 0; idx < ARRAY_SIZE(dgo); idx++) {
 		u8 dgo_id = dgo[idx];
 
-		scierr = sc_seco_secvio_dgo_config(-1, dgo_id, 0, &data[0]);
-		if (scierr == 0)
+		err = sc_seco_secvio_dgo_config(-1, dgo_id, 0, &data[0]);
+		if (!err)
 			printf("\t- DGO %.2x: %.8x\n", dgo_id, data[0]);
 		else
 			printf("Failed to read DGO %d\n", dgo_id);
diff --git a/arch/arm/mach-imx/imx8m/Kconfig b/arch/arm/mach-imx/imx8m/Kconfig
index 7639439..3d62d70 100644
--- a/arch/arm/mach-imx/imx8m/Kconfig
+++ b/arch/arm/mach-imx/imx8m/Kconfig
@@ -124,6 +124,9 @@
 	select IMX8M_LPDDR4
 	select GATEWORKS_SC
 	select MISC
+	select FSL_CAAM
+	select ARCH_MISC_INIT
+	select SPL_CRYPTO if SPL
 
 config TARGET_KONTRON_MX8MM
 	bool "Kontron Electronics N80xx"
@@ -175,6 +178,9 @@
 	select IMX8M_LPDDR4
 	select GATEWORKS_SC
 	select MISC
+	select FSL_CAAM
+	select ARCH_MISC_INIT
+	select SPL_CRYPTO if SPL
 
 config TARGET_IMX8MP_DATA_MODUL_EDM_SBC
 	bool "Data Modul eDM SBC i.MX8M Plus"
@@ -232,6 +238,9 @@
 	select IMX8M_LPDDR4
 	select GATEWORKS_SC
 	select MISC
+	select FSL_CAAM
+	select ARCH_MISC_INIT
+	select SPL_CRYPTO if SPL
 
 config TARGET_PICO_IMX8MQ
 	bool "Support Technexion Pico iMX8MQ"
@@ -245,6 +254,10 @@
 	select IMX8MN
 	select SUPPORT_SPL
 	select IMX8M_DDR4
+	select MISC
+	select I2C_EEPROM
+	select DM_ETH_PHY
+	select NVMEM
 
 config TARGET_KONTRON_PITX_IMX8M
 	bool "Support Kontron pITX-imx8m"
diff --git a/arch/arm/mach-imx/imx8m/clock_imx8mm.c b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
index 31c34b6..9868707 100644
--- a/arch/arm/mach-imx/imx8m/clock_imx8mm.c
+++ b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
@@ -90,7 +90,6 @@
 	case ANATOP_DRAM_PLL:
 		setbits_le32(GPC_BASE_ADDR + 0xEC, 1 << 7);
 		setbits_le32(GPC_BASE_ADDR + 0xF8, 1 << 5);
-		writel(SRC_DDR1_ENABLE_MASK, SRC_BASE_ADDR + 0x1004);
 
 		pll_base = &ana_pll->dram_pll_gnrl_ctl;
 		break;
diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c
index 5ffdcab..d525488 100644
--- a/arch/arm/mach-imx/imx8m/soc.c
+++ b/arch/arm/mach-imx/imx8m/soc.c
@@ -737,7 +737,7 @@
 		if (nodeoff < 0)
 			continue; /* Not found, skip it */
 
-		printf("Found %s node\n", nodes_path[i]);
+		debug("Found %s node\n", nodes_path[i]);
 
 add_status:
 		rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1);
@@ -1266,7 +1266,7 @@
 		if (nodeoff >= 0) {
 			const char *speed = "high-speed";
 
-			printf("Found %s node\n", usb_dwc3_path[v]);
+			debug("Found %s node\n", usb_dwc3_path[v]);
 
 usb_modify_speed:
 
diff --git a/arch/arm/mach-imx/imx8ulp/Makefile b/arch/arm/mach-imx/imx8ulp/Makefile
index f7692cf..2c9938f 100644
--- a/arch/arm/mach-imx/imx8ulp/Makefile
+++ b/arch/arm/mach-imx/imx8ulp/Makefile
@@ -5,7 +5,6 @@
 
 obj-y += lowlevel_init.o
 obj-y += soc.o clock.o iomux.o pcc.o cgc.o rdc.o
-obj-$(CONFIG_AHAB_BOOT) += ahab.o
 
 ifeq ($(CONFIG_SPL_BUILD),y)
 obj-y += upower/
diff --git a/arch/arm/mach-imx/imx8ulp/rdc.c b/arch/arm/mach-imx/imx8ulp/rdc.c
index 50b097b..cfc09e7 100644
--- a/arch/arm/mach-imx/imx8ulp/rdc.c
+++ b/arch/arm/mach-imx/imx8ulp/rdc.c
@@ -9,7 +9,7 @@
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/mach-imx/mu_hal.h>
-#include <asm/mach-imx/s400_api.h>
+#include <asm/mach-imx/ele_api.h>
 #include <asm/arch/rdc.h>
 #include <div64.h>
 
@@ -203,12 +203,12 @@
 int release_rdc(enum rdc_type type)
 {
 	ulong s_mu_base = 0x27020000UL;
-	struct sentinel_msg msg;
+	struct ele_msg msg;
 	int ret;
 	u32 rdc_id = (type == RDC_XRDC) ? 0x78 : 0x74;
 
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
 	msg.size = 2;
 	msg.command = ELE_RELEASE_RDC_REQ;
 	msg.data[0] = (rdc_id << 8) | 0x2; /* A35 XRDC */
@@ -266,7 +266,7 @@
 				mrgd[4] |= ((access & 0xFFF) << 16);
 			}
 
-			/* not handle other cases, since S400 only set ACCESS1 and 2 */
+			/* not handle other cases, since ELE only set ACCESS1 and 2 */
 			writel(mrgd[4], xrdc_base + off + 0x10);
 			return;
 		}
@@ -295,7 +295,7 @@
 
 void xrdc_init_mrc(void)
 {
-	/* Re-config MRC3 for SRAM0 in case protected by S400 */
+	/* Re-config MRC3 for SRAM0 in case protected by ELE */
 	xrdc_config_mrc_w0_w1(3, 0, 0x22010000, 0x10000);
 	xrdc_config_mrc_dx_perm(3, 0, 0, 1);
 	xrdc_config_mrc_dx_perm(3, 0, 1, 1);
@@ -320,7 +320,7 @@
 	xrdc_config_mrc_dx_perm(5, 0, 1, 1);
 	xrdc_config_mrc_w3_w4(5, 0, 0x0, 0x80000FFF);
 
-	/* Set MRC6 for DDR access from Sentinel */
+	/* Set MRC6 for DDR access from ELE */
 	xrdc_config_mrc_w0_w1(6, 0, CFG_SYS_SDRAM_BASE, PHYS_SDRAM_SIZE);
 	xrdc_config_mrc_dx_perm(6, 0, 4, 1);
 	xrdc_config_mrc_w3_w4(6, 0, 0x0, 0x80000FFF);
@@ -404,7 +404,7 @@
 	val &= ~(0xFU << offset);
 
 	/* MBC0-3
-	 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
+	 *  Global 0, 0x7777 secure pri/user read/write/execute, ELE has already set it.
 	 *  So select MBC0_MEMN_GLBAC0
 	 */
 	if (sec_access) {
@@ -445,7 +445,7 @@
 			continue;
 
 		/* MRC0,1
-		 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
+		 *  Global 0, 0x7777 secure pri/user read/write/execute, ELE has already set it.
 		 *  So select MRCx_MEMN_GLBAC0
 		 */
 		if (sec_access) {
diff --git a/arch/arm/mach-imx/imx8ulp/soc.c b/arch/arm/mach-imx/imx8ulp/soc.c
index 81eae02..e23cf60 100644
--- a/arch/arm/mach-imx/imx8ulp/soc.c
+++ b/arch/arm/mach-imx/imx8ulp/soc.c
@@ -14,7 +14,7 @@
 #include <event.h>
 #include <spl.h>
 #include <asm/arch/rdc.h>
-#include <asm/mach-imx/s400_api.h>
+#include <asm/mach-imx/ele_api.h>
 #include <asm/mach-imx/mu_hal.h>
 #include <cpu_func.h>
 #include <asm/setup.h>
@@ -70,7 +70,7 @@
 }
 #endif
 
-static void set_cpu_info(struct sentinel_get_info_data *info)
+static void set_cpu_info(struct ele_get_info_data *info)
 {
 	gd->arch.soc_rev = info->soc;
 	gd->arch.lifecycle = info->lc;
@@ -582,9 +582,9 @@
 	u32 res;
 	int ret;
 
-	ret = ahab_read_common_fuse(1, uid, 4, &res);
+	ret = ele_read_common_fuse(1, uid, 4, &res);
 	if (ret)
-		printf("ahab read fuse failed %d, 0x%x\n", ret, res);
+		printf("ele read fuse failed %d, 0x%x\n", ret, res);
 	else
 		printf("UID 0x%x,0x%x,0x%x,0x%x\n", uid[0], uid[1], uid[2], uid[3]);
 
@@ -783,7 +783,7 @@
 	struct udevice *devp;
 	int ret;
 	u32 res;
-	struct sentinel_get_info_data *info = (struct sentinel_get_info_data *)SRAM0_BASE;
+	struct ele_get_info_data *info = (struct ele_get_info_data *)SRAM0_BASE;
 
 	ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(imx8ulp_mu), &devp);
 	if (ret) {
@@ -791,11 +791,11 @@
 		return ret;
 	}
 
-	ret = ahab_get_info(info, &res);
+	ret = ele_get_info(info, &res);
 	if (ret) {
-		printf("ahab_get_info failed %d\n", ret);
+		printf("ele_get_info failed %d\n", ret);
 		/* fallback to A0.1 revision */
-		memset((void *)info, 0, sizeof(struct sentinel_get_info_data));
+		memset((void *)info, 0, sizeof(struct ele_get_info_data));
 		info->soc = 0xa000084d;
 	}
 
diff --git a/arch/arm/mach-imx/imx8ulp/upower/upower_hal.c b/arch/arm/mach-imx/imx8ulp/upower/upower_hal.c
index fcb02ed..b471a75 100644
--- a/arch/arm/mach-imx/imx8ulp/upower/upower_hal.c
+++ b/arch/arm/mach-imx/imx8ulp/upower/upower_hal.c
@@ -217,8 +217,8 @@
 	 * CM33 Cache
 	 * PowerQuad RAM
 	 * ETF RAM
-	 * Sentinel PKC, Data RAM1, Inst RAM0/1
-	 * Sentinel ROM
+	 * ELE PKC, Data RAM1, Inst RAM0/1
+	 * ELE ROM
 	 * uPower IRAM/DRAM
 	 * uPower ROM
 	 * CM33 ROM
@@ -230,7 +230,7 @@
 	 * SSRAM Partition 7_a(128KB)
 	 * SSRAM Partition 7_b(64KB)
 	 * SSRAM Partition 7_c(64KB)
-	 * Sentinel Data RAM0, Inst RAM2
+	 * ELE Data RAM0, Inst RAM2
 	 */
 	/* MIPI-CSI FIFO BIT28 not set */
 	memon = 0x3FFFFFEFFFFFFCUL;
diff --git a/arch/arm/mach-imx/imx9/clock.c b/arch/arm/mach-imx/imx9/clock.c
index a7eccca..766a881 100644
--- a/arch/arm/mach-imx/imx9/clock.c
+++ b/arch/arm/mach-imx/imx9/clock.c
@@ -709,8 +709,8 @@
 	/* Set A55 mtr bus to 133M */
 	{ARM_A55_MTR_BUS_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
 
-	/* Sentinel to 133M */
-	{SENTINEL_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
+	/* ELE to 133M */
+	{ELE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
 	/* Bus_wakeup to 133M */
 	{BUS_WAKEUP_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
 	/* Bus_AON to 133M */
@@ -740,8 +740,8 @@
 	{ARM_A55_PERIPH_CLK_ROOT, SYS_PLL_PFD0, 3},
 	/* Set A55 mtr bus to 133M */
 	{ARM_A55_MTR_BUS_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
-	/* Sentinel to 200M */
-	{SENTINEL_CLK_ROOT, SYS_PLL_PFD1_DIV2, 2},
+	/* ELE to 200M */
+	{ELE_CLK_ROOT, SYS_PLL_PFD1_DIV2, 2},
 	/* Bus_wakeup to 133M */
 	{BUS_WAKEUP_CLK_ROOT, SYS_PLL_PFD1_DIV2, 3},
 	/* Bus_AON to 133M */
diff --git a/arch/arm/mach-imx/imx9/clock_root.c b/arch/arm/mach-imx/imx9/clock_root.c
index 06b93f6..7d7ae86 100644
--- a/arch/arm/mach-imx/imx9/clock_root.c
+++ b/arch/arm/mach-imx/imx9/clock_root.c
@@ -34,7 +34,7 @@
 	{ ARM_A55_MTR_BUS_CLK_ROOT,	2 },
 	{ ARM_A55_CLK_ROOT,		0 },
 	{ M33_CLK_ROOT,			2 },
-	{ SENTINEL_CLK_ROOT,		2 },
+	{ ELE_CLK_ROOT,			2 },
 	{ BUS_WAKEUP_CLK_ROOT,		2 },
 	{ BUS_AON_CLK_ROOT,		2 },
 	{ WAKEUP_AXI_CLK_ROOT,		0 },
diff --git a/arch/arm/mach-imx/imx9/imx_bootaux.c b/arch/arm/mach-imx/imx9/imx_bootaux.c
index 256e6fa..6afb59e 100644
--- a/arch/arm/mach-imx/imx9/imx_bootaux.c
+++ b/arch/arm/mach-imx/imx9/imx_bootaux.c
@@ -13,7 +13,7 @@
 {
 	struct arm_smccc_res res;
 
-	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M4_STARTED, 0, 0,
+	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_STARTED, 0, 0,
 		      0, 0, 0, 0, &res);
 
 	return res.a0;
@@ -25,7 +25,7 @@
 
 	printf("## Stopping auxiliary core\n");
 
-	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M4_STOP, 0, 0,
+	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_STOP, 0, 0,
 		      0, 0, 0, 0, &res);
 
 	return 0;
@@ -40,7 +40,7 @@
 
 	printf("## Starting auxiliary core addr = 0x%08lX...\n", addr);
 
-	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, addr, 0,
+	arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_START, addr, 0,
 		      0, 0, 0, 0, &res);
 
 	return 0;
diff --git a/arch/arm/mach-imx/imx9/soc.c b/arch/arm/mach-imx/imx9/soc.c
index 64e8ac6..f43b73a 100644
--- a/arch/arm/mach-imx/imx9/soc.c
+++ b/arch/arm/mach-imx/imx9/soc.c
@@ -34,7 +34,7 @@
 #include <asm/setup.h>
 #include <asm/bootm.h>
 #include <asm/arch-imx/cpu.h>
-#include <asm/mach-imx/s400_api.h>
+#include <asm/mach-imx/ele_api.h>
 #include <fuse.h>
 #include <asm/arch/ddr.h>
 
@@ -151,7 +151,7 @@
 	return val;
 }
 
-static void set_cpu_info(struct sentinel_get_info_data *info)
+static void set_cpu_info(struct ele_get_info_data *info)
 {
 	gd->arch.soc_rev = info->soc;
 	gd->arch.lifecycle = info->lc;
@@ -557,7 +557,7 @@
 	struct udevice *devp;
 	int node, ret;
 	u32 res;
-	struct sentinel_get_info_data info;
+	struct ele_get_info_data info;
 
 	node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx93-mu-s4");
 
@@ -568,7 +568,7 @@
 	if (gd->flags & GD_FLG_RELOC)
 		return 0;
 
-	ret = ahab_get_info(&info, &res);
+	ret = ele_get_info(&info, &res);
 	if (ret)
 		return ret;
 
@@ -600,35 +600,31 @@
 enum env_location env_get_location(enum env_operation op, int prio)
 {
 	enum boot_device dev = get_boot_device();
-	enum env_location env_loc = ENVL_UNKNOWN;
 
 	if (prio)
-		return env_loc;
+		return ENVL_UNKNOWN;
 
 	switch (dev) {
-#if defined(CONFIG_ENV_IS_IN_SPI_FLASH)
 	case QSPI_BOOT:
-		env_loc = ENVL_SPI_FLASH;
-		break;
-#endif
-#if defined(CONFIG_ENV_IS_IN_MMC)
+		if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
+			return ENVL_SPI_FLASH;
+		return ENVL_NOWHERE;
 	case SD1_BOOT:
 	case SD2_BOOT:
 	case SD3_BOOT:
 	case MMC1_BOOT:
 	case MMC2_BOOT:
 	case MMC3_BOOT:
-		env_loc =  ENVL_MMC;
-		break;
-#endif
+		if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
+			return ENVL_MMC;
+		else if (CONFIG_IS_ENABLED(ENV_IS_IN_EXT4))
+			return ENVL_EXT4;
+		else if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
+			return ENVL_FAT;
+		return ENVL_NOWHERE;
 	default:
-#if defined(CONFIG_ENV_IS_NOWHERE)
-		env_loc = ENVL_NOWHERE;
-#endif
-		break;
+		return ENVL_NOWHERE;
 	}
-
-	return env_loc;
 }
 
 static int mix_power_init(enum mix_power_domain pd)
@@ -646,7 +642,7 @@
 		mem_id = SRC_MEM_MEDIA;
 		scr = BIT(5);
 
-		/* Enable S400 handshake */
+		/* Enable ELE handshake */
 		struct blk_ctrl_s_aonmix_regs *s_regs =
 			(struct blk_ctrl_s_aonmix_regs *)BLK_CTRL_S_ANOMIX_BASE_ADDR;
 
@@ -763,8 +759,8 @@
 	while (!(val & SRC_MIX_SLICE_FUNC_STAT_RST_STAT))
 		val = readl(&mix_regs->func_stat);
 
-	/* Release Sentinel TROUT */
-	ahab_release_m33_trout();
+	/* Release ELE TROUT */
+	ele_release_m33_trout();
 
 	/* Mask WDOG1 IRQ from A55, we use it for M33 reset */
 	setbits_le32(&s_regs->ca55_irq_mask[1], BIT(6));
@@ -772,7 +768,7 @@
 	/* Turn on WDOG1 clock */
 	ccm_lpcg_on(CCGR_WDG1, 1);
 
-	/* Set sentinel LP handshake for M33 reset */
+	/* Set ELE LP handshake for M33 reset */
 	setbits_le32(&s_regs->lp_handshake[0], BIT(6));
 
 	/* Clear M33 TCM for ECC */
diff --git a/arch/arm/mach-imx/imx9/trdc.c b/arch/arm/mach-imx/imx9/trdc.c
index e05c704..d0f855b 100644
--- a/arch/arm/mach-imx/imx9/trdc.c
+++ b/arch/arm/mach-imx/imx9/trdc.c
@@ -10,7 +10,7 @@
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/sys_proto.h>
 #include <div64.h>
-#include <asm/mach-imx/s400_api.h>
+#include <asm/mach-imx/ele_api.h>
 #include <asm/mach-imx/mu_hal.h>
 
 #define DID_NUM 16
@@ -196,7 +196,7 @@
 	val &= ~(0xFU << offset);
 
 	/* MBC0-3
-	 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
+	 *  Global 0, 0x7777 secure pri/user read/write/execute, ELE has already set it.
 	 *  So select MBC0_MEMN_GLBAC0
 	 */
 	if (sec_access) {
@@ -266,7 +266,7 @@
 			continue;
 
 		/* MRC0,1
-		 *  Global 0, 0x7777 secure pri/user read/write/execute, S400 has already set it.
+		 *  Global 0, 0x7777 secure pri/user read/write/execute, ELE has already set it.
 		 *  So select MRCx_MEMN_GLBAC0
 		 */
 		if (sec_access) {
@@ -315,7 +315,7 @@
 int release_rdc(u8 xrdc)
 {
 	ulong s_mu_base = 0x47520000UL;
-	struct sentinel_msg msg;
+	struct ele_msg msg;
 	int ret;
 	u32 rdc_id;
 
@@ -336,8 +336,8 @@
 		return -EINVAL;
 	}
 
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
 	msg.size = 2;
 	msg.command = ELE_RELEASE_RDC_REQ;
 	msg.data[0] = (rdc_id << 8) | 0x2; /* A55 */
@@ -394,7 +394,7 @@
 		/* DDR */
 		trdc_mrc_set_control(0x49010000, 0, 0, 0x7777);
 
-		/* S400*/
+		/* ELE */
 		trdc_mrc_region_config(0x49010000, 0, 0, 0x80000000, 0xFFFFFFFF, false, 0);
 
 		/* MTR */
diff --git a/arch/arm/mach-imx/imx_bootaux.c b/arch/arm/mach-imx/imx_bootaux.c
index 888c53d..f7b14ca 100644
--- a/arch/arm/mach-imx/imx_bootaux.c
+++ b/arch/arm/mach-imx/imx_bootaux.c
@@ -14,6 +14,7 @@
 #include <linux/compiler.h>
 #include <cpu_func.h>
 
+#ifndef CONFIG_IMX8
 /* Just to avoid build error */
 #if IS_ENABLED(CONFIG_IMX8M)
 #define SRC_M4C_NON_SCLR_RST_MASK	BIT(0)
@@ -45,7 +46,7 @@
  * is valid, returns the entry point address.
  * Translates load addresses in the elf file to the U-Boot address space.
  */
-static unsigned long load_elf_image_m_core_phdr(unsigned long addr, ulong *stack)
+static u32 load_elf_image_m_core_phdr(unsigned long addr, u32 *stack)
 {
 	Elf32_Ehdr *ehdr; /* ELF header structure pointer */
 	Elf32_Phdr *phdr; /* Program header structure pointer */
@@ -95,7 +96,7 @@
 
 int arch_auxiliary_core_up(u32 core_id, ulong addr)
 {
-	ulong stack, pc;
+	u32 stack, pc;
 
 	if (!addr)
 		return -EINVAL;
@@ -121,18 +122,18 @@
 		pc = *(u32 *)(addr + 4);
 	}
 
-	printf("## Starting auxiliary core stack = 0x%08lX, pc = 0x%08lX...\n",
+	printf("## Starting auxiliary core stack = 0x%08X, pc = 0x%08X...\n",
 	       stack, pc);
 
-	/* Set the stack and pc to M4 bootROM */
-	writel(stack, M4_BOOTROM_BASE_ADDR);
-	writel(pc, M4_BOOTROM_BASE_ADDR + 4);
+	/* Set the stack and pc to MCU bootROM */
+	writel(stack, MCU_BOOTROM_BASE_ADDR);
+	writel(pc, MCU_BOOTROM_BASE_ADDR + 4);
 
 	flush_dcache_all();
 
-	/* Enable M4 */
+	/* Enable MCU */
 	if (IS_ENABLED(CONFIG_IMX8M)) {
-		arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M4_START, 0, 0, 0, 0, 0, 0, NULL);
+		arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_START, 0, 0, 0, 0, 0, 0, NULL);
 	} else {
 		clrsetbits_le32(SRC_BASE_ADDR + SRC_M4_REG_OFFSET,
 				SRC_M4C_NON_SCLR_RST_MASK, SRC_M4_ENABLE_MASK);
@@ -147,7 +148,7 @@
 	unsigned int val;
 
 	if (IS_ENABLED(CONFIG_IMX8M)) {
-		arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M4_STARTED, 0, 0, 0, 0, 0, 0, &res);
+		arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_MCU_STARTED, 0, 0, 0, 0, 0, 0, &res);
 		return res.a0;
 	}
 
@@ -158,30 +159,34 @@
 
 	return 1;
 }
-
+#endif
 /*
  * To i.MX6SX and i.MX7D, the image supported by bootaux needs
  * the reset vector at the head for the image, with SP and PC
  * as the first two words.
  *
- * Per the cortex-M reference manual, the reset vector of M4 needs
- * to exist at 0x0 (TCMUL). The PC and SP are the first two addresses
- * of that vector.  So to boot M4, the A core must build the M4's reset
+ * Per the cortex-M reference manual, the reset vector of M4/M7 needs
+ * to exist at 0x0 (TCMUL/IDTCM). The PC and SP are the first two addresses
+ * of that vector.  So to boot M4/M7, the A core must build the M4/M7's reset
  * vector with getting the PC and SP from image and filling them to
- * TCMUL. When M4 is kicked, it will load the PC and SP by itself.
- * The TCMUL is mapped to (M4_BOOTROM_BASE_ADDR) at A core side for
- * accessing the M4 TCMUL.
+ * TCMUL/IDTCM. When M4/M7 is kicked, it will load the PC and SP by itself.
+ * The TCMUL/IDTCM is mapped to (MCU_BOOTROM_BASE_ADDR) at A core side for
+ * accessing the M4/M7 TCMUL/IDTCM.
  */
 static int do_bootaux(struct cmd_tbl *cmdtp, int flag, int argc,
 		      char *const argv[])
 {
 	ulong addr;
 	int ret, up;
+	u32 core = 0;
 
 	if (argc < 2)
 		return CMD_RET_USAGE;
 
-	up = arch_auxiliary_core_check_up(0);
+	if (argc > 2)
+		core = simple_strtoul(argv[2], NULL, 10);
+
+	up = arch_auxiliary_core_check_up(core);
 	if (up) {
 		printf("## Auxiliary core is already up\n");
 		return CMD_RET_SUCCESS;
@@ -192,7 +197,7 @@
 	if (!addr)
 		return CMD_RET_FAILURE;
 
-	ret = arch_auxiliary_core_up(0, addr);
+	ret = arch_auxiliary_core_up(core, addr);
 	if (ret)
 		return CMD_RET_FAILURE;
 
@@ -202,5 +207,7 @@
 U_BOOT_CMD(
 	bootaux, CONFIG_SYS_MAXARGS, 1,	do_bootaux,
 	"Start auxiliary core",
-	""
+	"<address> [<core>]\n"
+	"   - start auxiliary core [<core>] (default 0),\n"
+	"     at address <address>\n"
 );
diff --git a/arch/arm/mach-imx/mx6/module_fuse.c b/arch/arm/mach-imx/mx6/module_fuse.c
index 0f4565e..b58f11c 100644
--- a/arch/arm/mach-imx/mx6/module_fuse.c
+++ b/arch/arm/mach-imx/mx6/module_fuse.c
@@ -206,7 +206,7 @@
 			if (off < 0)
 				continue; /* Not found, skip it */
 add_status:
-			rc = fdt_setprop(blob, nodeoff, "status", status,
+			rc = fdt_setprop(blob, off, "status", status,
 					 strlen(status) + 1);
 			if (rc) {
 				if (rc == -FDT_ERR_NOSPACE) {
diff --git a/arch/arm/mach-imx/mxs/Kconfig b/arch/arm/mach-imx/mxs/Kconfig
index b2026a3..d3233d8 100644
--- a/arch/arm/mach-imx/mxs/Kconfig
+++ b/arch/arm/mach-imx/mxs/Kconfig
@@ -10,10 +10,12 @@
 
 config TARGET_MX23_OLINUXINO
 	bool "Support mx23_olinuxino"
+	select PL01X_SERIAL
 	select BOARD_EARLY_INIT_F
 
 config TARGET_MX23EVK
 	bool "Support mx23evk"
+	select PL01X_SERIAL
 	select BOARD_EARLY_INIT_F
 
 config TARGET_XFI3
@@ -41,16 +43,37 @@
 
 config TARGET_MX28EVK
 	bool "Support mx28evk"
+	select PL01X_SERIAL
 	select BOARD_EARLY_INIT_F
 
 config TARGET_XEA
 	bool "Support XEA"
+	select PL01X_SERIAL
 
 endchoice
 
 config SYS_SOC
 	default "mxs"
 
+config SPL_MXS_PMU_MINIMAL_VDD5V_CURRENT
+	bool "Force minimal current draw from VDD5V by MX28 PMU"
+	default n
+	help
+	  After setting this option, the current drawn from VDD5V
+	  by the PMU is reduced to zero - the DCDC_BATT is used as
+	  the main power source for PMU.
+
+config SPL_MXS_PMU_DISABLE_BATT_CHARGE
+	bool "Disable Battery Charging in MX28 PMU"
+	default n
+
+config SPL_MXS_PMU_ENABLE_4P2_LINEAR_REGULATOR
+	bool "Enable the 4P2 linear regulator in MX28 PMU"
+	default y
+	help
+	  This option enables the 4P2 linear regulator (derived
+	  from VDD5V) - so the VDD4P2 power source is operational.
+
 source "board/freescale/mx28evk/Kconfig"
 source "board/liebherr/xea/Kconfig"
 
diff --git a/arch/arm/mach-imx/parse-container.c b/arch/arm/mach-imx/parse-container.c
index f758282..e2a9e2b 100644
--- a/arch/arm/mach-imx/parse-container.c
+++ b/arch/arm/mach-imx/parse-container.c
@@ -1,77 +1,18 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright 2018-2019 NXP
+ * Copyright 2018-2021 NXP
  */
 
 #include <common.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <log.h>
 #include <spl.h>
 #include <asm/mach-imx/image.h>
 #ifdef CONFIG_AHAB_BOOT
-#include <firmware/imx/sci/sci.h>
+#include <asm/mach-imx/ahab.h>
 #endif
 
-#define SEC_SECURE_RAM_BASE		0x31800000UL
-#define SEC_SECURE_RAM_END_BASE		(SEC_SECURE_RAM_BASE + 0xFFFFUL)
-#define SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE	0x60000000UL
-
-#define SECO_PT         2U
-
-#ifdef CONFIG_AHAB_BOOT
-static int authenticate_image(struct boot_img_t *img, int image_index)
-{
-	sc_faddr_t start, end;
-	sc_rm_mr_t mr;
-	int err;
-	int ret = 0;
-
-	debug("img %d, dst 0x%x, src 0x%x, size 0x%x\n",
-	      image_index, (uint32_t)img->dst, img->offset, img->size);
-
-	/* Find the memreg and set permission for seco pt */
-	err = sc_rm_find_memreg(-1, &mr,
-				img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1),
-				ALIGN(img->dst + img->size, CONFIG_SYS_CACHELINE_SIZE) - 1);
-
-	if (err) {
-		printf("can't find memreg for image %d load address 0x%x, error %d\n",
-		       image_index, img->dst & ~(CONFIG_SYS_CACHELINE_SIZE - 1), err);
-		return -ENOMEM;
-	}
-
-	err = sc_rm_get_memreg_info(-1, mr, &start, &end);
-	if (!err)
-		debug("memreg %u 0x%x -- 0x%x\n", mr, start, end);
-
-	err = sc_rm_set_memreg_permissions(-1, mr,
-					   SECO_PT, SC_RM_PERM_FULL);
-	if (err) {
-		printf("set permission failed for img %d, error %d\n",
-		       image_index, err);
-		return -EPERM;
-	}
-
-	err = sc_seco_authenticate(-1, SC_SECO_VERIFY_IMAGE,
-				   1 << image_index);
-	if (err) {
-		printf("authenticate img %d failed, return %d\n",
-		       image_index, err);
-		ret = -EIO;
-	}
-
-	err = sc_rm_set_memreg_permissions(-1, mr,
-					   SECO_PT, SC_RM_PERM_NONE);
-	if (err) {
-		printf("remove permission failed for img %d, error %d\n",
-		       image_index, err);
-		ret = -EPERM;
-	}
-
-	return ret;
-}
-#endif
-
 static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image,
 					  struct spl_load_info *info,
 					  struct container_hdr *container,
@@ -110,10 +51,8 @@
 	}
 
 #ifdef CONFIG_AHAB_BOOT
-	if (authenticate_image(&images[image_index], image_index)) {
-		printf("Failed to authenticate image %d\n", image_index);
+	if (ahab_verify_cntr_image(&images[image_index], image_index))
 		return NULL;
-	}
 #endif
 
 	return &images[image_index];
@@ -134,21 +73,27 @@
 	 * It will not override the ATF code, so safe to use it here,
 	 * no need malloc
 	 */
-	container = (struct container_hdr *)spl_get_load_buffer(-size, size);
+	container = malloc(size);
+	if (!container)
+		return -ENOMEM;
 
 	debug("%s: container: %p sector: %lu sectors: %u\n", __func__,
 	      container, sector, sectors);
-	if (info->read(info, sector, sectors, container) != sectors)
-		return -EIO;
+	if (info->read(info, sector, sectors, container) != sectors) {
+		ret = -EIO;
+		goto end;
+	}
 
 	if (container->tag != 0x87 && container->version != 0x0) {
-		printf("Wrong container header\n");
-		return -ENOENT;
+		printf("Wrong container header");
+		ret = -ENOENT;
+		goto end;
 	}
 
 	if (!container->num_images) {
-		printf("Wrong container, no image found\n");
-		return -ENOENT;
+		printf("Wrong container, no image found");
+		ret = -ENOENT;
+		goto end;
 	}
 
 	length = container->length_lsb + (container->length_msb << 8);
@@ -158,25 +103,24 @@
 		size = roundup(length, info->bl_len);
 		sectors = size / info->bl_len;
 
-		container = (struct container_hdr *)spl_get_load_buffer(-size, size);
+		free(container);
+		container = malloc(size);
+		if (!container)
+			return -ENOMEM;
 
 		debug("%s: container: %p sector: %lu sectors: %u\n",
 		      __func__, container, sector, sectors);
 		if (info->read(info, sector, sectors, container) !=
-		    sectors)
-			return -EIO;
+		    sectors) {
+			ret = -EIO;
+			goto end;
+		}
 	}
 
 #ifdef CONFIG_AHAB_BOOT
-	memcpy((void *)SEC_SECURE_RAM_BASE, (const void *)container,
-	       ALIGN(length, CONFIG_SYS_CACHELINE_SIZE));
-
-	ret = sc_seco_authenticate(-1, SC_SECO_AUTH_CONTAINER,
-				   SECO_LOCAL_SEC_SEC_SECURE_RAM_BASE);
-	if (ret) {
-		printf("authenticate container hdr failed, return %d\n", ret);
-		return ret;
-	}
+	ret = ahab_auth_cntr_hdr(container, length);
+	if (ret)
+		goto end_auth;
 #endif
 
 	for (i = 0; i < container->num_images; i++) {
@@ -197,9 +141,12 @@
 
 end_auth:
 #ifdef CONFIG_AHAB_BOOT
-	if (sc_seco_authenticate(-1, SC_SECO_REL_CONTAINER, 0))
-		printf("Error: release container failed!\n");
+	ahab_auth_release();
 #endif
+
+end:
+	free(container);
+
 	return ret;
 }
 
diff --git a/arch/arm/mach-imx/priblob.c b/arch/arm/mach-imx/priblob.c
index 9b92eae..5b022d5 100644
--- a/arch/arm/mach-imx/priblob.c
+++ b/arch/arm/mach-imx/priblob.c
@@ -13,12 +13,16 @@
 #include <asm/io.h>
 #include <common.h>
 #include <command.h>
-#include "../drivers/crypto/fsl_caam_internal.h"
+#include <fsl_sec.h>
 
 int do_priblob_write(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
 {
-	writel((readl(CAAM_SCFGR) & 0xFFFFFFFC) | 3, CAAM_SCFGR);
-	printf("New priblob setting = 0x%x\n", readl(CAAM_SCFGR) & 0x3);
+	ccsr_sec_t *sec_regs = (ccsr_sec_t *)CAAM_BASE_ADDR;
+	u32 scfgr = sec_in32(&sec_regs->scfgr);
+
+	scfgr |= 0x3;
+	sec_out32(&sec_regs->scfgr, scfgr);
+	printf("New priblob setting = 0x%x\n", sec_in32(&sec_regs->scfgr) & 0x3);
 
 	return 0;
 }
diff --git a/arch/arm/mach-imx/spl_imx_romapi.c b/arch/arm/mach-imx/spl_imx_romapi.c
index 9164045..4af4169 100644
--- a/arch/arm/mach-imx/spl_imx_romapi.c
+++ b/arch/arm/mach-imx/spl_imx_romapi.c
@@ -76,13 +76,16 @@
 	u32 image_offset;
 
 	ret = rom_api_query_boot_infor(QUERY_IVT_OFF, &offset);
-	ret |= rom_api_query_boot_infor(QUERY_PAGE_SZ, &pagesize);
-	ret |= rom_api_query_boot_infor(QUERY_IMG_OFF, &image_offset);
+	if (ret != ROM_API_OKAY)
+		goto err;
 
-	if (ret != ROM_API_OKAY) {
-		puts("ROMAPI: Failure query boot infor pagesize/offset\n");
-		return -1;
-	}
+	ret = rom_api_query_boot_infor(QUERY_PAGE_SZ, &pagesize);
+	if (ret != ROM_API_OKAY)
+		goto err;
+
+	ret = rom_api_query_boot_infor(QUERY_IMG_OFF, &image_offset);
+	if (ret != ROM_API_OKAY)
+		goto err;
 
 	header = (struct legacy_img_hdr *)(CONFIG_SPL_IMX_ROMAPI_LOADADDR);
 
@@ -124,6 +127,10 @@
 	}
 
 	return 0;
+
+err:
+	puts("ROMAPI: Failure query boot infor pagesize/offset\n");
+	return -1;
 }
 
 static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector,
@@ -344,12 +351,12 @@
 	u32 boot, bstage;
 
 	ret = rom_api_query_boot_infor(QUERY_BT_DEV, &boot);
-	ret |= rom_api_query_boot_infor(QUERY_BT_STAGE, &bstage);
+	if (ret != ROM_API_OKAY)
+		goto err;
 
-	if (ret != ROM_API_OKAY) {
-		puts("ROMAPI: failure at query_boot_info\n");
-		return -1;
-	}
+	ret = rom_api_query_boot_infor(QUERY_BT_STAGE, &bstage);
+	if (ret != ROM_API_OKAY)
+		goto err;
 
 	printf("Boot Stage: ");
 
@@ -374,4 +381,7 @@
 		return spl_romapi_load_image_stream(spl_image, bootdev);
 
 	return spl_romapi_load_image_seekable(spl_image, bootdev, boot);
+err:
+	puts("ROMAPI: failure at query_boot_info\n");
+	return -1;
 }
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index ac484c7..5c7f4bf 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -202,6 +202,10 @@
 	bool "Support Allied Telesis x530"
 	select 88F6820
 
+config TARGET_X240
+	bool "Support Allied Telesis x240"
+	select ALLEYCAT_5
+
 config TARGET_DB_XC3_24G4XG
 	bool "Support DB-XC3-24G4XG"
 	select 98DX3336
@@ -274,6 +278,7 @@
 	default "theadorable" if TARGET_THEADORABLE
 	default "a38x" if TARGET_CONTROLCENTERDC
 	default "x530" if TARGET_X530
+	default "x240" if TARGET_X240
 	default "db-xc3-24g4xg" if TARGET_DB_XC3_24G4XG
 	default "crs3xx-98dx3236" if TARGET_CRS3XX_98DX3236
 	default "mvebu_alleycat-5" if TARGET_MVEBU_ALLEYCAT5
@@ -297,6 +302,7 @@
 	default "turris_mox" if TARGET_TURRIS_MOX
 	default "controlcenterdc" if TARGET_CONTROLCENTERDC
 	default "x530" if TARGET_X530
+	default "x240" if TARGET_X240
 	default "db-xc3-24g4xg" if TARGET_DB_XC3_24G4XG
 	default "crs3xx-98dx3236" if TARGET_CRS3XX_98DX3236
 	default "mvebu_alleycat-5" if TARGET_MVEBU_ALLEYCAT5
@@ -320,6 +326,7 @@
 	default "CZ.NIC" if TARGET_TURRIS_MOX
 	default "gdsys" if TARGET_CONTROLCENTERDC
 	default "alliedtelesis" if TARGET_X530
+	default "alliedtelesis" if TARGET_X240
 	default "mikrotik" if TARGET_CRS3XX_98DX3236
 	default "Marvell" if TARGET_MVEBU_ALLEYCAT5
 
diff --git a/arch/arm/mach-mvebu/alleycat5/soc.c b/arch/arm/mach-mvebu/alleycat5/soc.c
index dc69f46..734b0a8 100644
--- a/arch/arm/mach-mvebu/alleycat5/soc.c
+++ b/arch/arm/mach-mvebu/alleycat5/soc.c
@@ -255,6 +255,12 @@
 	printf("\tMSS     %4d MHz\n", 200);
 }
 
+/* Return NAND clock in Hz */
+u32 mvebu_get_nand_clock(void)
+{
+	return 400 * 1000000;
+}
+
 /*
  * Override of __weak int mach_cpu_init(void) :
  * SoC/machine dependent CPU setup
diff --git a/arch/arm/mach-npcm/npcm8xx/cpu.c b/arch/arm/mach-npcm/npcm8xx/cpu.c
index 2d839cf..af59452 100644
--- a/arch/arm/mach-npcm/npcm8xx/cpu.c
+++ b/arch/arm/mach-npcm/npcm8xx/cpu.c
@@ -68,6 +68,9 @@
 	case ARBEL_A1:
 		printf("A1 @ ");
 		break;
+	case ARBEL_A2:
+		printf("A2 @ ");
+		break;
 	default:
 		printf("Unknown\n");
 		break;
@@ -92,7 +95,7 @@
 	return 0;
 }
 
-static struct mm_region npcm_mem_map[1 + CONFIG_NR_DRAM_BANKS + 1] = {
+static struct mm_region npcm_mem_map[] = {
 	{
 		/* DRAM */
 		.phys = 0x0UL,
@@ -110,6 +113,13 @@
 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
 	},
 	{
+		.phys = 0x100000000UL,
+		.virt = 0x100000000UL,
+		.size = 0x80000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_INNER_SHARE
+	},
+	{
 		/* List terminator */
 		0,
 	}
diff --git a/arch/powerpc/lib/Kconfig b/arch/powerpc/lib/Kconfig
index b30b5ed..d38ba45 100644
--- a/arch/powerpc/lib/Kconfig
+++ b/arch/powerpc/lib/Kconfig
@@ -1,9 +1,9 @@
 config CACHE_FLUSH_WATCHDOG_THRESHOLD
-	int "Bytes to flush between WATCHDOG_RESET calls"
-	default 0
+	int "Bytes to flush between schedule() calls"
+	default 4096
 	help
 	  The flush_cache() function periodically, and by default for
-	  every cache line, calls WATCHDOG_RESET(). When flushing a
-	  large area, that may add a significant amount of
+	  every 4k block, calls schedule() to reset watchdog. When
+	  flushing a large area, that may add a significant amount of
 	  overhead. This option allows you to set a threshold for how
-	  many bytes to flush between each WATCHDOG_RESET call.
+	  many bytes to flush between each schedule() call.
diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c
index 2c570ed..590e406 100644
--- a/arch/sandbox/cpu/sdl.c
+++ b/arch/sandbox/cpu/sdl.c
@@ -6,6 +6,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <stdbool.h>
+#include <sysreset.h>
 #include <linux/input.h>
 #include <SDL2/SDL.h>
 #include <asm/state.h>
@@ -81,7 +82,7 @@
 		switch (event.type) {
 		case SDL_QUIT:
 			puts("LCD window closed - quitting\n");
-			reset_cpu();
+			sysreset_walk(SYSRESET_POWER_OFF);
 			break;
 		}
 	}
diff --git a/arch/sandbox/dts/cedit.dtsi b/arch/sandbox/dts/cedit.dtsi
new file mode 100644
index 0000000..a9eb4c2
--- /dev/null
+++ b/arch/sandbox/dts/cedit.dtsi
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Expo definition for the configuration editor
+ *
+ * This used for testing building an expo from a data file. This devicetree
+ * provides a description of the objects to be created.
+ */
+
+#include <test/cedit-test.h>
+
+&cedit {
+	dynamic-start = <ID_DYNAMIC_START>;
+
+	scenes {
+		main {
+			id = <ID_SCENE1>;
+
+			/* value refers to the matching id in /strings */
+			title-id = <ID_SCENE1_TITLE>;
+
+			/* simple string is used as it is */
+			prompt = "UP and DOWN to choose, ENTER to select";
+
+			/* defines a menu within the scene */
+			cpu-speed {
+				type = "menu";
+				id = <ID_CPU_SPEED>;
+
+				/*
+				 * has both string and ID. The string is ignored
+				 * if the ID is present and points to a string
+				 */
+				title = "CPU speed";
+				title-id = <ID_CPU_SPEED_TITLE>;
+
+				/* menu items as simple strings */
+				item-label = "2 GHz", "2.5 GHz", "3 GHz";
+
+				/* IDs for the menu items */
+				item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
+					ID_CPU_SPEED_3>;
+			};
+
+			power-loss {
+				type = "menu";
+				id = <ID_POWER_LOSS>;
+
+				title = "AC Power";
+				item-label = "Always Off", "Always On",
+					"Memory";
+
+				item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
+			};
+		};
+	};
+
+	strings {
+		title {
+			id = <ID_SCENE1_TITLE>;
+			value = "Test Configuration";
+			value-es = "configuración de prueba";
+		};
+	};
+};
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index 30a305c..f0ee0b3 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -16,6 +16,12 @@
 		stdout-path = "/serial";
 	};
 
+	cedit-theme {
+		font-size = <30>;
+		menu-inset = <3>;
+		menuitem-gap-y = <1>;
+	};
+
 	alarm_wdt: alarm-wdt {
 		compatible = "sandbox,alarm-wdt";
 		timeout-sec = <5>;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index ff9f922..b5509ee 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -96,6 +96,8 @@
 
 		theme {
 			font-size = <30>;
+			menu-inset = <3>;
+			menuitem-gap-y = <1>;
 		};
 
 		/*
@@ -139,6 +141,15 @@
 		};
 	};
 
+	cedit: cedit {
+	};
+
+	cedit-theme {
+		font-size = <30>;
+		menu-inset = <3>;
+		menuitem-gap-y = <1>;
+	};
+
 	fuzzing-engine {
 		compatible = "sandbox,fuzzing-engine";
 	};
@@ -1828,3 +1839,5 @@
 #ifdef CONFIG_SANDBOX_VPL
 #include "sandbox_vpl.dtsi"
 #endif
+
+#include "cedit.dtsi"
diff --git a/arch/sandbox/include/asm/global_data.h b/arch/sandbox/include/asm/global_data.h
index f4ce72d..f0ab3ba 100644
--- a/arch/sandbox/include/asm/global_data.h
+++ b/arch/sandbox/include/asm/global_data.h
@@ -13,6 +13,10 @@
 struct arch_global_data {
 	uint8_t		*ram_buf;	/* emulated RAM buffer */
 	void		*text_base;	/* pointer to base of text region */
+	ulong table_start;		/* Start address of x86 tables */
+	ulong table_end;		/* End address of x86 tables */
+	ulong table_start_high;		/* Start address of high x86 tables */
+	ulong table_end_high;		/* End address of high x86 tables */
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/x86/cpu/i386/interrupt.c b/arch/x86/cpu/i386/interrupt.c
index fae2544..f3f3527 100644
--- a/arch/x86/cpu/i386/interrupt.c
+++ b/arch/x86/cpu/i386/interrupt.c
@@ -266,6 +266,10 @@
 	struct udevice *dev;
 	int ret;
 
+	/*
+	 * When running as an EFI application we are not in control of
+	 * interrupts and should leave them alone.
+	 */
 	if (!ll_boot_init())
 		return 0;
 
@@ -274,11 +278,6 @@
 	if (ret && ret != -ENODEV)
 		return ret;
 
-	/*
-	 * When running as an EFI application we are not in control of
-	 * interrupts and should leave them alone.
-	 */
-#ifndef CONFIG_EFI_APP
 	/* Just in case... */
 	disable_interrupts();
 
@@ -294,14 +293,8 @@
 	/* Initialize core interrupt and exception functionality of CPU */
 	cpu_init_interrupts();
 
-	/*
-	 * It is now safe to enable interrupts.
-	 *
-	 * TODO(sjg@chromium.org): But we don't handle these correctly when
-	 * booted from EFI.
-	 */
+	/* It is now safe to enable interrupts */
 	enable_interrupts();
-#endif
 
 	return 0;
 }
diff --git a/arch/x86/cpu/intel_common/mrc.c b/arch/x86/cpu/intel_common/mrc.c
index 69405d7..56cc253 100644
--- a/arch/x86/cpu/intel_common/mrc.c
+++ b/arch/x86/cpu/intel_common/mrc.c
@@ -3,6 +3,8 @@
  * Copyright (c) 2016 Google, Inc
  */
 
+#define LOG_CATEGORY	UCLASS_RAM
+
 #include <common.h>
 #include <dm.h>
 #include <init.h>
@@ -144,12 +146,10 @@
 
 	ret = gpio_request_list_by_name(dev, "board-id-gpios", desc,
 					ARRAY_SIZE(desc), GPIOD_IS_IN);
-	if (ret < 0) {
-		debug("%s: gpio ret=%d\n", __func__, ret);
-		return ret;
-	}
+	if (ret < 0)
+		return log_msg_ret("gpio", ret);
 	spd_index = dm_gpio_get_values_as_int(desc, ret);
-	debug("spd index %d\n", spd_index);
+	log_debug("spd index %d\n", spd_index);
 
 	node = fdt_first_subnode(blob, dev_of_offset(dev));
 	if (node < 0)
diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c
index 1a0ec43..0718aef 100644
--- a/arch/x86/cpu/ivybridge/sdram.c
+++ b/arch/x86/cpu/ivybridge/sdram.c
@@ -9,6 +9,8 @@
  * Copyright (C) 2011 Google Inc.
  */
 
+#define LOG_CATEGORY	UCLASS_RAM
+
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
@@ -213,7 +215,7 @@
 
 	ret = mrc_locate_spd(dev, sizeof(peid->spd_data[0]), &data);
 	if (ret) {
-		debug("%s: Could not locate SPD (ret=%d)\n", __func__, ret);
+		log_debug("Could not locate SPD (err=%d)\n", ret);
 		return ret;
 	}
 
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c
index e69dfb5..d57fcfa 100644
--- a/arch/x86/cpu/mtrr.c
+++ b/arch/x86/cpu/mtrr.c
@@ -30,6 +30,16 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static const char *const mtrr_type_name[MTRR_TYPE_COUNT] = {
+	"Uncacheable",
+	"Combine",
+	"2",
+	"3",
+	"Through",
+	"Protect",
+	"Back",
+};
+
 /* Prepare to adjust MTRRs */
 void mtrr_open(struct mtrr_state *state, bool do_caches)
 {
@@ -320,3 +330,54 @@
 
 	return mtrr_start_op(cpu_select, &oper);
 }
+
+static void read_mtrrs_(void *arg)
+{
+	struct mtrr_info *info = arg;
+
+	mtrr_read_all(info);
+}
+
+int mtrr_list(int reg_count, int cpu_select)
+{
+	struct mtrr_info info;
+	int ret;
+	int i;
+
+	printf("Reg Valid Write-type   %-16s %-16s %-16s\n", "Base   ||",
+	       "Mask   ||", "Size   ||");
+	memset(&info, '\0', sizeof(info));
+	ret = mp_run_on_cpus(cpu_select, read_mtrrs_, &info);
+	if (ret)
+		return log_msg_ret("run", ret);
+	for (i = 0; i < reg_count; i++) {
+		const char *type = "Invalid";
+		u64 base, mask, size;
+		bool valid;
+
+		base = info.mtrr[i].base;
+		mask = info.mtrr[i].mask;
+		size = ~mask & ((1ULL << CONFIG_CPU_ADDR_BITS) - 1);
+		size |= (1 << 12) - 1;
+		size += 1;
+		valid = mask & MTRR_PHYS_MASK_VALID;
+		type = mtrr_type_name[base & MTRR_BASE_TYPE_MASK];
+		printf("%d   %-5s %-12s %016llx %016llx %016llx\n", i,
+		       valid ? "Y" : "N", type, base & ~MTRR_BASE_TYPE_MASK,
+		       mask & ~MTRR_PHYS_MASK_VALID, size);
+	}
+
+	return 0;
+}
+
+int mtrr_get_type_by_name(const char *typename)
+{
+	int i;
+
+	for (i = 0; i < MTRR_TYPE_COUNT; i++) {
+		if (*typename == *mtrr_type_name[i])
+			return i;
+	}
+
+	return -EINVAL;
+};
diff --git a/arch/x86/cpu/qemu/Kconfig b/arch/x86/cpu/qemu/Kconfig
index f8f2f64..aa329b0 100644
--- a/arch/x86/cpu/qemu/Kconfig
+++ b/arch/x86/cpu/qemu/Kconfig
@@ -12,7 +12,7 @@
 	imply SYS_NS16550
 	imply USB
 	imply USB_EHCI_HCD
-	imply VIDEO_VESA
+	imply VIDEO_BOCHS
 
 if QEMU
 
diff --git a/arch/x86/cpu/start64.S b/arch/x86/cpu/start64.S
index 7be8347..78e894d 100644
--- a/arch/x86/cpu/start64.S
+++ b/arch/x86/cpu/start64.S
@@ -26,3 +26,22 @@
 
 	/* Should not return here */
 	jmp	.
+
+.globl board_init_f_r_trampoline64
+.type board_init_f_r_trampoline64, @function
+board_init_f_r_trampoline64:
+	/*
+	 * SDRAM has been initialised, U-Boot code has been copied into
+	 * RAM, BSS has been cleared and relocation adjustments have been
+	 * made. It is now time to jump into the in-RAM copy of U-Boot
+	 *
+	 * %eax = Address of top of new stack
+	 */
+
+	/* Stack grows down from top of SDRAM */
+	movq	%rsi, %rsp
+
+	/* New gd is in rdi */
+
+	/* Re-enter U-Boot by calling board_init_f_r() */
+	call	board_init_f_r
diff --git a/arch/x86/dts/chromebook_link.dts b/arch/x86/dts/chromebook_link.dts
index 36956f4..c904b7d 100644
--- a/arch/x86/dts/chromebook_link.dts
+++ b/arch/x86/dts/chromebook_link.dts
@@ -314,6 +314,7 @@
 						00 00 00 00 00 00 00 00];
 					};
 				micron_4Gb_1600_1.35v_x16 {
+					bootph-all;
 					reg = <2>;
 					data = [92 11 0b 03 04 19 02 02
 						03 11 01 08 0a 00 fe 00
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index 22d103d..ea58259 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -123,6 +123,10 @@
 #endif
 	void *itss_priv;		/* Private ITSS data pointer */
 	ulong coreboot_table;		/* Address of coreboot table */
+	ulong table_start;		/* Start address of x86 tables */
+	ulong table_end;		/* End address of x86 tables */
+	ulong table_start_high;		/* Start address of high x86 tables */
+	ulong table_end_high;		/* End address of high x86 tables */
 };
 
 #endif
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
index ca2edc7..2e995f5 100644
--- a/arch/x86/include/asm/mtrr.h
+++ b/arch/x86/include/asm/mtrr.h
@@ -190,6 +190,26 @@
  */
 int mtrr_get_var_count(void);
 
+/**
+ * mtrr_list() - List the MTRRs
+ *
+ * Shows a list of all the MTRRs including their values
+ *
+ * @reg_count: Number of registers to show. You can use mtrr_get_var_count() for
+ * this
+ * @cpu_select: CPU to use. Use MP_SELECT_BSP for the boot CPU
+ * Returns: 0 if OK, -ve if the CPU was not found
+ */
+int mtrr_list(int reg_count, int cpu_select);
+
+/**
+ * mtrr_get_type_by_name() - Get the type of an MTRR given its type name
+ *
+ * @typename: Name to check
+ * Returns: MTRR type (MTRR_TYPE_...) or -EINVAL if invalid
+ */
+int mtrr_get_type_by_name(const char *typename);
+
 #endif
 
 #if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0)
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index 8f38c2d..02a8b0f 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -102,8 +102,31 @@
  */
 int fsp_save_s3_stack(void);
 
-void	board_init_f_r_trampoline(ulong) __attribute__ ((noreturn));
-void	board_init_f_r(void) __attribute__ ((noreturn));
+/**
+ * board_init_f_r_trampoline() - jump to relocated address with new stack
+ *
+ * @sp: New stack pointer to use
+ */
+void __noreturn board_init_f_r_trampoline(ulong sp);
+
+/**
+ * board_init_f_r() - jump to relocated U-Boot
+ *
+ * This is used to jump from pre-relocation to post-relocation U-Boot. It
+ * enables the cache and jump to the new location.
+ */
+void __noreturn board_init_f_r(void);
+
+/*
+ * board_init_f_r_trampoline64() - jump to relocated address with new stack
+ *
+ * This is the 64-bit version
+ *
+ * @new_gd: New global_data pointer to use
+ * @sp: New stack pointer to pass on to board_init_r()
+ */
+void __noreturn board_init_f_r_trampoline64(struct global_data *new_gd,
+					    ulong sp);
 
 int arch_misc_init(void);
 
diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h
index 000b38e..9ad74dc 100644
--- a/arch/x86/include/asm/zimage.h
+++ b/arch/x86/include/asm/zimage.h
@@ -72,4 +72,31 @@
  */
 void zimage_dump(struct boot_params *base_ptr);
 
+/**
+ * zboot_start() - Boot a zimage
+ *
+ * Boot a zimage, given the component parts
+ *
+ * @addr: Address where the bzImage is moved before booting, either
+ *	BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR
+ * @base: Pointer to the boot parameters, typically at address
+ *	DEFAULT_SETUP_BASE
+ * @initrd: Address of the initial ramdisk, or 0 if none
+ * @initrd_size: Size of the initial ramdisk, or 0 if none
+ * @cmdline: Command line to use for booting
+ * Return: -EFAULT on error (normally it does not return)
+ */
+int zboot_start(ulong addr, ulong size, ulong initrd, ulong initrd_size,
+		ulong base, char *cmdline);
+
+/*
+ * zimage_get_kernel_version() - Get the version string from a kernel
+ *
+ * @params: boot_params pointer
+ * @kernel_base: base address of kernel
+ * Return: Kernel version as a NUL-terminated string
+ */
+const char *zimage_get_kernel_version(struct boot_params *params,
+				      void *kernel_base);
+
 #endif
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index b0612ae..90a7618 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -4,16 +4,17 @@
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
 obj-y	+= bdinfo.o
-ifndef CONFIG_X86_64
-ifndef CONFIG_TPL_BUILD
+
+ifndef CONFIG_$(SPL_TPL_)X86_64
 obj-y += bios.o
 obj-y += bios_asm.o
 obj-y += bios_interrupts.o
 endif
-endif
+
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_X86_32BIT_INIT) += string.o
 endif
+
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_CMD_BOOTM) += bootm.o
 endif
diff --git a/arch/x86/lib/bdinfo.c b/arch/x86/lib/bdinfo.c
index 1539007..1240584 100644
--- a/arch/x86/lib/bdinfo.c
+++ b/arch/x86/lib/bdinfo.c
@@ -22,6 +22,11 @@
 	bdinfo_print_num_l("vendor", gd->arch.x86_vendor);
 	bdinfo_print_str(" name", cpu_vendor_name(gd->arch.x86_vendor));
 	bdinfo_print_num_l("model", gd->arch.x86_model);
+	bdinfo_print_num_l("phys_addr in bits", cpu_phys_address_size());
+	bdinfo_print_num_l("table start", gd->arch.table_start);
+	bdinfo_print_num_l("table end", gd->arch.table_end);
+	bdinfo_print_num_l(" high start", gd->arch.table_start_high);
+	bdinfo_print_num_l(" high end", gd->arch.table_end_high);
 
 	if (IS_ENABLED(CONFIG_EFI_STUB))
 		efi_show_bdinfo();
diff --git a/arch/x86/lib/bios.c b/arch/x86/lib/bios.c
index 94349ba..e29cae7 100644
--- a/arch/x86/lib/bios.c
+++ b/arch/x86/lib/bios.c
@@ -23,7 +23,7 @@
 static int (*int_handler[256])(void);
 
 /* to have a common register file for interrupt handlers */
-#ifndef CONFIG_BIOSEMU
+#if !CONFIG_IS_ENABLED(BIOSEMU)
 X86EMU_sysEnv _X86EMU_env;
 #endif
 
@@ -78,7 +78,7 @@
 	};
 	struct eregs *regs = &reg_info;
 
-	debug("Oops, exception %d while executing option rom\n", regs->vector);
+	log_err("Exception %d while executing option rom\n", regs->vector);
 	cpu_hlt();
 
 	return 0;
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index 61cb7bc..3196f9d 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -258,7 +258,7 @@
 	ulong ret;
 
 #if CONFIG_IS_ENABLED(X86_64)
-	ret = gd->start_addr_sp;
+	asm("mov %%rsp, %0" : "=r"(ret) : );
 #else
 	asm("mov %%esp, %0" : "=r"(ret) : );
 #endif
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c
index 2f6f688..6494b8d 100644
--- a/arch/x86/lib/mrccache.c
+++ b/arch/x86/lib/mrccache.c
@@ -6,6 +6,8 @@
  * Copyright (C) 2015 Bin Meng <bmeng.cn@gmail.com>
  */
 
+#define LOG_CATEGORY	UCLASS_RAM
+
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
@@ -197,8 +199,8 @@
 	cache->signature = MRC_DATA_SIGNATURE;
 	cache->data_size = mrc->len;
 	checksum = compute_ip_checksum(mrc->buf, cache->data_size);
-	debug("Saving %d bytes for MRC output data, checksum %04x\n",
-	      cache->data_size, checksum);
+	log_debug("Saving %d bytes for MRC output data, checksum %04x\n",
+		  cache->data_size, checksum);
 	cache->checksum = checksum;
 	cache->reserved = 0;
 	memcpy(cache->data, mrc->buf, cache->data_size);
diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c
index ca1645f..b6812bb 100644
--- a/arch/x86/lib/spl.c
+++ b/arch/x86/lib/spl.c
@@ -3,6 +3,8 @@
  * Copyright (c) 2016 Google, Inc
  */
 
+#define LOG_CATEGORY	LOGC_BOOT
+
 #include <common.h>
 #include <cpu_func.h>
 #include <debug_uart.h>
@@ -15,10 +17,12 @@
 #include <malloc.h>
 #include <spl.h>
 #include <syscon.h>
+#include <vesa.h>
 #include <asm/cpu.h>
 #include <asm/cpu_common.h>
 #include <asm/fsp2/fsp_api.h>
 #include <asm/global_data.h>
+#include <asm/mp.h>
 #include <asm/mrccache.h>
 #include <asm/mtrr.h>
 #include <asm/pci.h>
@@ -61,6 +65,8 @@
 
 static int x86_spl_init(void)
 {
+	struct udevice *dev;
+
 #ifndef CONFIG_TPL
 	/*
 	 * TODO(sjg@chromium.org): We use this area of RAM for the stack
@@ -74,49 +80,64 @@
 #endif
 	int ret;
 
-	debug("%s starting\n", __func__);
+	log_debug("x86 spl starting\n");
 	if (IS_ENABLED(TPL))
 		ret = x86_cpu_reinit_f();
 	else
 		ret = x86_cpu_init_f();
 	ret = spl_init();
 	if (ret) {
-		debug("%s: spl_init() failed\n", __func__);
+		log_debug("spl_init() failed (err=%d)\n", ret);
 		return ret;
 	}
 	ret = arch_cpu_init();
 	if (ret) {
-		debug("%s: arch_cpu_init() failed\n", __func__);
+		log_debug("arch_cpu_init() failed (err=%d)\n", ret);
 		return ret;
 	}
 #ifndef CONFIG_TPL
 	ret = fsp_setup_pinctrl(NULL, NULL);
 	if (ret) {
-		debug("%s: fsp_setup_pinctrl() failed\n", __func__);
+		log_debug("fsp_setup_pinctrl() failed (err=%d)\n", ret);
 		return ret;
 	}
 #endif
-	preloader_console_init();
+	/*
+	 * spl_board_init() below sets up the console if enabled. If it isn't,
+	 * do it here. We cannot call this twice since it results in a double
+	 * banner and CI tests fail.
+	 */
+	if (!IS_ENABLED(CONFIG_SPL_BOARD_INIT))
+		preloader_console_init();
 #if !defined(CONFIG_TPL) && !CONFIG_IS_ENABLED(CPU)
 	ret = print_cpuinfo();
 	if (ret) {
-		debug("%s: print_cpuinfo() failed\n", __func__);
+		log_debug("print_cpuinfo() failed (err=%d)\n", ret);
 		return ret;
 	}
 #endif
+	/* probe the LPC so we get the GPIO_BASE set up correctly */
+	ret = uclass_first_device_err(UCLASS_LPC, &dev);
+	if (ret && ret != -ENODEV) {
+		log_debug("lpc probe failed\n");
+		return ret;
+	}
+
 	ret = dram_init();
 	if (ret) {
-		debug("%s: dram_init() failed\n", __func__);
+		log_debug("dram_init() failed (err=%d)\n", ret);
 		return ret;
 	}
+	log_debug("mrc\n");
 	if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) {
 		ret = mrccache_spl_save();
 		if (ret)
-			debug("%s: Failed to write to mrccache (err=%d)\n",
-			      __func__, ret);
+			log_debug("Failed to write to mrccache (err=%d)\n",
+				  ret);
 	}
 
 #ifndef CONFIG_SYS_COREBOOT
+	log_debug("bss\n");
 	debug("BSS clear from %lx to %lx len %lx\n", (ulong)&__bss_start,
 	      (ulong)&__bss_end, (ulong)&__bss_end - (ulong)&__bss_start);
 	memset(&__bss_start, 0, (ulong)&__bss_end - (ulong)&__bss_start);
@@ -136,9 +157,29 @@
 	 */
 	gd->new_gd = (struct global_data *)ptr;
 	memcpy(gd->new_gd, gd, sizeof(*gd));
+
+	log_debug("logging\n");
+	/*
+	 * Make sure logging is disabled when we switch, since the log system
+	 * list head will move
+	 */
+	gd->new_gd->flags &= ~GD_FLG_LOG_READY;
 	arch_setup_gd(gd->new_gd);
 	gd->start_addr_sp = (ulong)ptr;
 
+	/* start up logging again, with the new list-head location */
+	ret = log_init();
+	if (ret) {
+		log_debug("Log setup failed (err=%d)\n", ret);
+		return ret;
+	}
+
+	if (_LOG_DEBUG) {
+		ret = mtrr_list(mtrr_get_var_count(), MP_SELECT_BSP);
+		if (ret)
+			printf("mtrr_list failed\n");
+	}
+
 	/* Cache the SPI flash. Otherwise copying the code to RAM takes ages */
 	ret = mtrr_add_request(MTRR_TYPE_WRBACK,
 			       (1ULL << 32) - CONFIG_XIP_ROM_SIZE,
@@ -157,6 +198,7 @@
 		debug("Failed to set CPU frequency (err=%d)\n", ret);
 # endif
 #endif
+	log_debug("done\n");
 
 	return 0;
 }
@@ -250,4 +292,12 @@
 #ifndef CONFIG_TPL
 	preloader_console_init();
 #endif
+
+	if (CONFIG_IS_ENABLED(VIDEO)) {
+		struct udevice *dev;
+
+		/* Set up PCI video in SPL if required */
+		uclass_first_device_err(UCLASS_PCI, &dev);
+		uclass_first_device_err(UCLASS_VIDEO, &dev);
+	}
 }
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c
index ea834a5..67bc0a7 100644
--- a/arch/x86/lib/tables.c
+++ b/arch/x86/lib/tables.c
@@ -3,7 +3,7 @@
  * Copyright (C) 2015, Bin Meng <bmeng.cn@gmail.com>
  */
 
-#define LOG_CATEGORY LOGC_BOARD
+#define LOG_CATEGORY LOGC_ACPI
 
 #include <common.h>
 #include <bloblist.h>
@@ -54,6 +54,10 @@
 #ifdef CONFIG_GENERATE_MP_TABLE
 	{ "mp", write_mp_table, },
 #endif
+	/*
+	 * tables which can go in the bloblist must be last in this list, so
+	 * that the calculation of gd->table_end works properly
+	 */
 #ifdef CONFIG_GENERATE_ACPI_TABLE
 	{ "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, 0x10000, 0x1000},
 #endif
@@ -78,33 +82,42 @@
 
 int write_tables(void)
 {
-	u32 rom_table_start;
-	u32 rom_table_end;
 	u32 high_table, table_size;
 	struct memory_area cfg_tables[ARRAY_SIZE(table_list) + 1];
+	bool use_high = false;
+	u32 rom_addr;
 	int i;
 
-	rom_table_start = ROM_TABLE_ADDR;
+	gd->arch.table_start = ROM_TABLE_ADDR;
+	rom_addr = gd->arch.table_start;
 
-	debug("Writing tables to %x:\n", rom_table_start);
+	debug("Writing tables to %x:\n", rom_addr);
 	for (i = 0; i < ARRAY_SIZE(table_list); i++) {
 		const struct table_info *table = &table_list[i];
 		int size = table->size ? : CONFIG_ROM_TABLE_SIZE;
+		u32 rom_table_end;
 
 		if (IS_ENABLED(CONFIG_BLOBLIST_TABLES) && table->tag) {
-			rom_table_start = (ulong)bloblist_add(table->tag, size,
-							      table->align);
-			if (!rom_table_start)
+			if (!gd->arch.table_end)
+				gd->arch.table_end = rom_addr;
+			rom_addr = (ulong)bloblist_add(table->tag, size,
+						       table->align);
+			if (!rom_addr)
 				return log_msg_ret("bloblist", -ENOBUFS);
+
+			/* the bloblist is always in high memory */
+			use_high = true;
+			if (!gd->arch.table_start_high)
+				gd->arch.table_start_high = rom_addr;
 		}
-		rom_table_end = table->write(rom_table_start);
+		rom_table_end = table->write(rom_addr);
 		if (!rom_table_end) {
 			log_err("Can't create configuration table %d\n", i);
 			return -EINTR;
 		}
 
 		if (IS_ENABLED(CONFIG_SEABIOS)) {
-			table_size = rom_table_end - rom_table_start;
+			table_size = rom_table_end - rom_addr;
 			high_table = (u32)(ulong)high_table_malloc(table_size);
 			if (high_table) {
 				if (!table->write(high_table)) {
@@ -123,15 +136,20 @@
 		}
 
 		debug("- wrote '%s' to %x, end %x\n", table->name,
-		      rom_table_start, rom_table_end);
-		if (rom_table_end - rom_table_start > size) {
+		      rom_addr, rom_table_end);
+		if (rom_table_end - rom_addr > size) {
 			log_err("Out of space for configuration tables: need %x, have %x\n",
-				rom_table_end - rom_table_start, size);
+				rom_table_end - rom_addr, size);
 			return log_msg_ret("bloblist", -ENOSPC);
 		}
-		rom_table_start = rom_table_end;
+		rom_addr = rom_table_end;
 	}
 
+	if (use_high)
+		gd->arch.table_end_high = rom_addr;
+	else
+		gd->arch.table_end = rom_addr;
+
 	if (IS_ENABLED(CONFIG_SEABIOS)) {
 		/* make sure the last item is zero */
 		cfg_tables[i].size = 0;
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index e5ea512..062e3d3 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -22,6 +22,7 @@
 #include <irq_func.h>
 #include <log.h>
 #include <malloc.h>
+#include <mapmem.h>
 #include <acpi/acpi_table.h>
 #include <asm/io.h>
 #include <asm/ptrace.h>
@@ -180,7 +181,7 @@
 	return 0;
 }
 
-static const char *get_kernel_version(struct boot_params *params,
+const char *zimage_get_kernel_version(struct boot_params *params,
 				      void *kernel_base)
 {
 	struct setup_header *hdr = &params->hdr;
@@ -188,10 +189,14 @@
 	const char *s, *end;
 
 	bootproto = get_boot_protocol(hdr, false);
+	log_debug("bootproto %x, hdr->setup_sects %x\n", bootproto,
+		  hdr->setup_sects);
 	if (bootproto < 0x0200 || hdr->setup_sects < 15)
 		return NULL;
 
 	/* sanity-check the kernel version in case it is missing */
+	log_debug("hdr->kernel_version %x, str at %p\n", hdr->kernel_version,
+		  kernel_base + hdr->kernel_version + 0x200);
 	for (s = kernel_base + hdr->kernel_version + 0x200, end = s + 0x100; *s;
 	     s++) {
 		if (!isprint(*s))
@@ -238,7 +243,7 @@
 	log_debug("Using boot protocol version %x.%02x\n",
 		  (bootproto & 0xff00) >> 8, bootproto & 0xff);
 
-	version = get_kernel_version(params, image);
+	version = zimage_get_kernel_version(params, image);
 	if (version)
 		printf("Linux kernel version %s\n", version);
 	else
@@ -442,8 +447,7 @@
 	return 0;
 }
 
-static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc,
-			 char *const argv[])
+static int zboot_load(void)
 {
 	struct boot_params *base_ptr;
 
@@ -460,31 +464,51 @@
 				       &state.load_address);
 		if (!base_ptr) {
 			puts("## Kernel loading failed ...\n");
-			return CMD_RET_FAILURE;
+			return -EINVAL;
 		}
 	}
 	state.base_ptr = base_ptr;
-	if (env_set_hex("zbootbase", (ulong)base_ptr) ||
+
+	return 0;
+}
+
+static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	if (zboot_load())
+		return CMD_RET_FAILURE;
+
+	if (env_set_hex("zbootbase", map_to_sysmem(state.base_ptr)) ||
 	    env_set_hex("zbootaddr", state.load_address))
 		return CMD_RET_FAILURE;
 
 	return 0;
 }
 
+static int zboot_setup(void)
+{
+	struct boot_params *base_ptr = state.base_ptr;
+	int ret;
+
+	ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
+			   0, state.initrd_addr, state.initrd_size,
+			   (ulong)state.cmdline);
+	if (ret)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc,
 			  char *const argv[])
 {
 	struct boot_params *base_ptr = state.base_ptr;
-	int ret;
 
 	if (!base_ptr) {
 		printf("base is not set: use 'zboot load' first\n");
 		return CMD_RET_FAILURE;
 	}
-	ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
-			   0, state.initrd_addr, state.initrd_size,
-			   (ulong)state.cmdline);
-	if (ret) {
+	if (zboot_setup()) {
 		puts("Setting up boot parameters failed ...\n");
 		return CMD_RET_FAILURE;
 	}
@@ -501,8 +525,7 @@
 	return 0;
 }
 
-static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
-		       char *const argv[])
+static int zboot_go(void)
 {
 	struct boot_params *params = state.base_ptr;
 	struct setup_header *hdr = &params->hdr;
@@ -522,11 +545,52 @@
 
 	/* we assume that the kernel is in place */
 	ret = boot_linux_kernel((ulong)state.base_ptr, entry, image_64bit);
+
+	return ret;
+}
+
+static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
+		       char *const argv[])
+{
+	int ret;
+
+	ret = zboot_go();
 	printf("Kernel returned! (err=%d)\n", ret);
 
 	return CMD_RET_FAILURE;
 }
 
+int zboot_start(ulong addr, ulong size, ulong initrd, ulong initrd_size,
+		ulong base, char *cmdline)
+{
+	int ret;
+
+	memset(&state, '\0', sizeof(state));
+
+	if (base) {
+		state.base_ptr = map_sysmem(base, 0);
+		state.load_address = addr;
+	} else {
+		state.bzimage_addr = addr;
+	}
+	state.bzimage_size = size;
+	state.initrd_addr = initrd;
+	state.initrd_size = initrd_size;
+	state.cmdline = cmdline;
+
+	ret = zboot_load();
+	if (ret)
+		return log_msg_ret("ld", ret);
+	ret = zboot_setup();
+	if (ret)
+		return log_msg_ret("set", ret);
+	ret = zboot_go();
+	if (ret)
+		return log_msg_ret("set", ret);
+
+	return -EFAULT;
+}
+
 static void print_num(const char *name, ulong value)
 {
 	printf("%-20s: %lx\n", name, value);
@@ -668,7 +732,8 @@
 	print_num("Real mode switch", hdr->realmode_swtch);
 	print_num("Start sys seg", hdr->start_sys_seg);
 	print_num("Kernel version", hdr->kernel_version);
-	version = get_kernel_version(base_ptr, (void *)state.bzimage_addr);
+	version = zimage_get_kernel_version(base_ptr,
+					    (void *)state.bzimage_addr);
 	if (version)
 		printf("   @%p: %s\n", version, version);
 	print_num("Type of loader", hdr->type_of_loader);
diff --git a/board/advantech/imx8qm_dmsse20_a1/spl.c b/board/advantech/imx8qm_dmsse20_a1/spl.c
index 7f2e972..f36caec 100644
--- a/board/advantech/imx8qm_dmsse20_a1/spl.c
+++ b/board/advantech/imx8qm_dmsse20_a1/spl.c
@@ -111,7 +111,7 @@
 		switch (i) {
 		case 0:
 			ret = sc_pm_set_resource_power_mode(-1, SC_R_SDHC_0, SC_PM_PW_MODE_ON);
-			if (ret != SC_ERR_NONE)
+			if (ret)
 				return ret;
 
 			imx8_iomux_setup_multiple_pads(emmc0, ARRAY_SIZE(emmc0));
@@ -120,10 +120,10 @@
 			break;
 		case 1:
 			ret = sc_pm_set_resource_power_mode(-1, SC_R_SDHC_2, SC_PM_PW_MODE_ON);
-			if (ret != SC_ERR_NONE)
+			if (ret)
 				return ret;
 			ret = sc_pm_set_resource_power_mode(-1, SC_R_GPIO_4, SC_PM_PW_MODE_ON);
-			if (ret != SC_ERR_NONE)
+			if (ret)
 				return ret;
 
 			imx8_iomux_setup_multiple_pads(usdhc2_sd, ARRAY_SIZE(usdhc2_sd));
diff --git a/board/advantech/imx8qm_rom7720_a1/spl.c b/board/advantech/imx8qm_rom7720_a1/spl.c
index b602437..922bb0b 100644
--- a/board/advantech/imx8qm_rom7720_a1/spl.c
+++ b/board/advantech/imx8qm_rom7720_a1/spl.c
@@ -112,7 +112,7 @@
 		switch (i) {
 		case 0:
 			ret = sc_pm_set_resource_power_mode(-1, SC_R_SDHC_0, SC_PM_PW_MODE_ON);
-			if (ret != SC_ERR_NONE)
+			if (ret)
 				return ret;
 
 			imx8_iomux_setup_multiple_pads(emmc0, ARRAY_SIZE(emmc0));
@@ -121,10 +121,10 @@
 			break;
 		case 1:
 			ret = sc_pm_set_resource_power_mode(-1, SC_R_SDHC_2, SC_PM_PW_MODE_ON);
-			if (ret != SC_ERR_NONE)
+			if (ret)
 				return ret;
 			ret = sc_pm_set_resource_power_mode(-1, SC_R_GPIO_4, SC_PM_PW_MODE_ON);
-			if (ret != SC_ERR_NONE)
+			if (ret)
 				return ret;
 
 			imx8_iomux_setup_multiple_pads(usdhc2_sd, ARRAY_SIZE(usdhc2_sd));
diff --git a/board/alliedtelesis/x240/MAINTAINERS b/board/alliedtelesis/x240/MAINTAINERS
new file mode 100644
index 0000000..f1f78d9
--- /dev/null
+++ b/board/alliedtelesis/x240/MAINTAINERS
@@ -0,0 +1,7 @@
+X240 BOARD
+M:	Chris Packham <chris.packham@alliedtelesis.co.nz>
+S:	Maintained
+F:	board/alliedtelesis/x240/
+F:	arch/arm/dts/ac5-98dx35xx-rd.dts
+F:	include/configs/x240.h
+F:	configs/x240_defconfig
diff --git a/board/alliedtelesis/x240/Makefile b/board/alliedtelesis/x240/Makefile
new file mode 100644
index 0000000..7f20a47
--- /dev/null
+++ b/board/alliedtelesis/x240/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2022 Allied Telesis
+#
+
+obj-y	+= x240.o
diff --git a/board/alliedtelesis/x240/x240.c b/board/alliedtelesis/x240/x240.c
new file mode 100644
index 0000000..0c4f8e0
--- /dev/null
+++ b/board/alliedtelesis/x240/x240.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int board_init(void)
+{
+	gd->bd->bi_boot_params = CFG_SYS_SDRAM_BASE + 0x100;
+
+	return 0;
+}
diff --git a/board/beacon/imx8mm/MAINTAINERS b/board/beacon/imx8mm/MAINTAINERS
index e887db2..d48ba86 100644
--- a/board/beacon/imx8mm/MAINTAINERS
+++ b/board/beacon/imx8mm/MAINTAINERS
@@ -5,3 +5,4 @@
 F:	board/beacon/imx8mm/
 F:	include/configs/imx8mm_beacon.h
 F:	configs/imx8mm_beacon_defconfig
+F:	doc/board/beacon/
diff --git a/board/beacon/imx8mm/README b/board/beacon/imx8mm/README
deleted file mode 100644
index 32b24bc..0000000
--- a/board/beacon/imx8mm/README
+++ /dev/null
@@ -1,37 +0,0 @@
-U-Boot for the Beacon EmbeddedWorks Devkit
-
-Quick Start
-===========
-- Build the ARM Trusted firmware binary
-- Get ddr firmware
-- Build U-Boot
-- Boot
-
-Get and Build the ARM Trusted firmware
-======================================
-Note: $(srctree) is U-Boot source directory
-
-$ git clone https://github.com/nxp-imx/imx-atf
-$ git lf-5.10.72-2.2.0
-$ make PLAT=imx8mm bl31 CROSS_COMPILE=aarch64-linux-gnu-
-$ cp build/imx8mm/release/bl31.bin $(srctree)
-
-Get the DDR firmware
-====================
-$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.9.bin
-$ chmod +x firmware-imx-8.9.bin
-$ ./firmware-imx-8.9
-$ cp firmware-imx-8.9/firmware/ddr/synopsys/lpddr4*.bin $(srctree)
-
-Build U-Boot
-============
-$ make imx8mm_beacon_defconfig
-$ make CROSS_COMPILE=aarch64-linux-gnu-
-
-Burn U-Boot to microSD Card
-===========================
-$ sudo dd if=flash.bin of=/dev/sd[x] bs=1024 seek=33
-
-Boot
-====
-Set Boot switch to SD boot
diff --git a/board/beacon/imx8mm/imx8mm_beacon.env b/board/beacon/imx8mm/imx8mm_beacon.env
new file mode 100644
index 0000000..00bf67e
--- /dev/null
+++ b/board/beacon/imx8mm/imx8mm_beacon.env
@@ -0,0 +1,19 @@
+boot_fit=try
+bootscript=echo Running bootscript from mmc ...; source
+console=ttymxc1
+fdt_addr=0x45000000
+fdt_file=imx8mm-beacon-kit.dtb
+finduuid=part uuid mmc ${mmcdev}:2 uuid
+image=Image
+initrd_addr=0x46000000
+loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
+loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}
+loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
+mmcargs=setenv bootargs console=${console},${baudrate} root=PARTUUID=${uuid} rootwait rw ${mtdparts} ${optargs}
+mmcautodetect=yes
+mmcboot=echo Booting from mmc ...; run finduuid; run mmcargs; if run loadfdt; then booti ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi;
+netargs=setenv bootargs console=${console},${baudrate} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp
+mmcdev=1
+mmcpart=1
+netboot=echo Booting from net ...; run netargs;  if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; ${get_cmd} ${loadaddr} ${image}; if test ${boot_fit} = yes || test ${boot_fit} = try; then bootm ${loadaddr}; else if ${get_cmd} ${fdt_addr} ${fdt_file}; then booti ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi; fi;
+script=boot.scr
diff --git a/board/beacon/imx8mm/spl.c b/board/beacon/imx8mm/spl.c
index a5f337a..b2830c5 100644
--- a/board/beacon/imx8mm/spl.c
+++ b/board/beacon/imx8mm/spl.c
@@ -36,6 +36,8 @@
 		return BOOT_DEVICE_MMC2;
 	case USB_BOOT:
 		return BOOT_DEVICE_BOARD;
+	case QSPI_BOOT:
+		return BOOT_DEVICE_NOR;
 	default:
 		return BOOT_DEVICE_NONE;
 	}
@@ -46,6 +48,11 @@
 	ddr_init(&dram_timing);
 }
 
+void spl_board_init(void)
+{
+	arch_misc_init();
+}
+
 #ifdef CONFIG_SPL_LOAD_FIT
 int board_fit_config_name_match(const char *name)
 {
diff --git a/board/beacon/imx8mn/README b/board/beacon/imx8mn/README
deleted file mode 100644
index 49da03c..0000000
--- a/board/beacon/imx8mn/README
+++ /dev/null
@@ -1,38 +0,0 @@
-U-Boot for the Beacon EmbeddedWorks i.MX8M Nano Devkit
-
-Quick Start
-===========
-- Build the ARM Trusted firmware binary
-- Get ddr firmware
-- Build U-Boot
-- Boot
-
-Get and Build the ARM Trusted firmware
-======================================
-Note: $(srctree) is U-Boot source directory
-
-$ git clone https://github.com/nxp-imx/imx-atf
-$ git lf-5.10.72-2.2.0
-$ make PLAT=imx8mn bl31 CROSS_COMPILE=aarch64-linux-gnu-
-$ cp build/imx8mn/release/bl31.bin $(srctree)
-
-Get the DDR firmware
-====================
-$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.9.bin
-$ chmod +x firmware-imx-8.9.bin
-$ ./firmware-imx-8.9
-$ cp firmware-imx-8.9/firmware/ddr/synopsys/lpddr4*.bin $(srctree)
-
-Build U-Boot
-============
-$ make imx8mn_beacon_defconfig
-$ make CROSS_COMPILE=aarch64-linux-gnu-
-
-Burn U-Boot to microSD Card
-===========================
-$ sudo dd if=flash.bin of=/dev/sd[x] bs=1024 seek=32
-
-Boot
-====
-Set baseboard DIP switch:
-S17: 1100XXXX
diff --git a/board/beacon/imx8mn/imx8mn_beacon.env b/board/beacon/imx8mn/imx8mn_beacon.env
new file mode 100644
index 0000000..ca90053
--- /dev/null
+++ b/board/beacon/imx8mn/imx8mn_beacon.env
@@ -0,0 +1,25 @@
+boot_fdt=try
+bootdelay=2
+bootscript=echo Running bootscript from mmc ...; source
+console=ttymxc1
+fdt_addr=0x45000000
+fdt_file=imx8mn-beacon-kit.dtb
+finduuid=part uuid mmc ${mmcdev}:2 uuid
+image=Image
+initrd_addr=0x46000000
+loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
+loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}
+loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
+loadramdisk=load mmc ${mmcdev} ${ramdisk_addr} ${ramdiskimage}
+mmcargs=setenv bootargs console=${console},${baudrate}  root=PARTUUID=${uuid} rootwait rw ${mtdparts} ${optargs}
+mmcautodetect=yes
+mmcboot=echo Booting from mmc ...; run finduuid; run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then booti ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi; else echo wait for boot; fi;
+mmcdev=1
+mmcpart=1
+netargs=setenv bootargs console=${console},${baudrate}  root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp
+netboot=echo Booting from net ...; run netargs;  if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; ${get_cmd} ${loadaddr} ${image}; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if ${get_cmd} ${fdt_addr} ${fdt_file}; then booti ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi; else booti; fi;
+ramargs=setenv bootargs console=${console},${baudrate}  root=/dev/ram rw  ${optargs}
+ramboot=echo Booting from RAMdisk...; run loadimage; run loadfdt; fdt addr $fdt_addr; run loadramdisk; run ramargs; booti ${loadaddr} ${ramdisk_addr} ${fdt_addr} ${optargs}
+ramdisk_addr=0x46000000
+ramdiskimage=rootfs.cpio.uboot
+script=boot.scr
diff --git a/board/congatec/cgtqmx8/cgtqmx8.c b/board/congatec/cgtqmx8/cgtqmx8.c
index bedd1e0..26189ff 100644
--- a/board/congatec/cgtqmx8/cgtqmx8.c
+++ b/board/congatec/cgtqmx8/cgtqmx8.c
@@ -79,7 +79,7 @@
 int board_early_init_f(void)
 {
 	/* sc_ipc_t ipcHndl = 0; */
-	sc_err_t scierr = 0;
+	int scierr;
 
 	/* When start u-boot in XEN VM, directly return */
 	/* if (IS_ENABLED(CONFIG_XEN)) */
@@ -89,19 +89,19 @@
 
 	/* Power up UART0, this is very early while power domain is not working */
 	scierr = sc_pm_set_resource_power_mode(-1, SC_R_UART_0, SC_PM_PW_MODE_ON);
-	if (scierr != SC_ERR_NONE)
+	if (scierr)
 		return 0;
 
 	/* Set UART0 clock root to 80 MHz */
 	sc_pm_clock_rate_t rate = 80000000;
 
 	scierr = sc_pm_set_clock_rate(-1, SC_R_UART_0, 2, &rate);
-	if (scierr != SC_ERR_NONE)
+	if (scierr)
 		return 0;
 
 	/* Enable UART0 clock root */
 	scierr = sc_pm_clock_enable(-1, SC_R_UART_0, 2, true, false);
-	if (scierr != SC_ERR_NONE)
+	if (scierr)
 		return 0;
 
 	setup_iomux_uart();
diff --git a/board/data_modul/imx8mp_edm_sbc/spl.c b/board/data_modul/imx8mp_edm_sbc/spl.c
index c30185e..2fdd95a 100644
--- a/board/data_modul/imx8mp_edm_sbc/spl.c
+++ b/board/data_modul/imx8mp_edm_sbc/spl.c
@@ -107,6 +107,20 @@
 	spl_boot_list[4] = BOOT_DEVICE_NONE;
 }
 
+unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, unsigned long sect)
+{
+	const u32 boot_dev = spl_boot_device();
+	int part;
+
+	if (boot_dev == BOOT_DEVICE_MMC2) {	/* eMMC */
+		part = spl_mmc_emmc_boot_partition(mmc);
+		if (part == 1 || part == 2)	/* eMMC BOOT1/BOOT2 HW partitions */
+			return sect - 0x40;
+	}
+
+	return sect;
+}
+
 static struct dram_timing_info *dram_timing_info[8] = {
 	&dmo_imx8mp_sbc_dram_timing_32_32,	/* 32 Gbit x32 */
 	NULL,					/* 32 Gbit x16 */
diff --git a/board/freescale/imx8ulp_evk/spl.c b/board/freescale/imx8ulp_evk/spl.c
index a0dad5f..66d0f68 100644
--- a/board/freescale/imx8ulp_evk/spl.c
+++ b/board/freescale/imx8ulp_evk/spl.c
@@ -19,7 +19,7 @@
 #include <asm/arch/ddr.h>
 #include <asm/arch/rdc.h>
 #include <asm/arch/upower.h>
-#include <asm/mach-imx/s400_api.h>
+#include <asm/mach-imx/ele_api.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -63,9 +63,9 @@
 	u32 fw_version, sha1, res;
 	int ret;
 
-	ret = ahab_get_fw_version(&fw_version, &sha1, &res);
+	ret = ele_get_fw_version(&fw_version, &sha1, &res);
 	if (ret) {
-		printf("ahab get firmware version failed %d, 0x%x\n", ret, res);
+		printf("ele get firmware version failed %d, 0x%x\n", ret, res);
 	} else {
 		printf("ELE firmware version %u.%u.%u-%x",
 		       (fw_version & (0x00ff0000)) >> 16,
@@ -120,9 +120,19 @@
 	set_lpav_qos();
 
 	/* Enable A35 access to the CAAM */
-	ret = ahab_release_caam(0x7, &res);
+	ret = ele_release_caam(0x7, &res);
 	if (ret)
-		printf("ahab release caam failed %d, 0x%x\n", ret, res);
+		printf("ele release caam failed %d, 0x%x\n", ret, res);
+
+	/*
+	 * RNG start only available on the A1 soc revision.
+	 * Check some JTAG register for the SoC revision.
+	 */
+	if (!is_soc_rev(CHIP_REV_1_0)) {
+		ret = ele_start_rng();
+		if (ret)
+			printf("Fail to start RNG: %d\n", ret);
+	}
 }
 
 void board_init_f(ulong dummy)
diff --git a/board/freescale/imx93_evk/spl.c b/board/freescale/imx93_evk/spl.c
index 352ad79..63883b3 100644
--- a/board/freescale/imx93_evk/spl.c
+++ b/board/freescale/imx93_evk/spl.c
@@ -20,7 +20,6 @@
 #include <asm/mach-imx/mxc_i2c.h>
 #include <asm/arch-mx7ulp/gpio.h>
 #include <asm/mach-imx/syscounter.h>
-#include <asm/mach-imx/s400_api.h>
 #include <dm/uclass.h>
 #include <dm/device.h>
 #include <dm/uclass-internal.h>
diff --git a/board/freescale/mx7dsabresd/mx7dsabresd.c b/board/freescale/mx7dsabresd/mx7dsabresd.c
index 2777ae1..cff2e6a 100644
--- a/board/freescale/mx7dsabresd/mx7dsabresd.c
+++ b/board/freescale/mx7dsabresd/mx7dsabresd.c
@@ -292,6 +292,7 @@
 int board_late_init(void)
 {
 	struct wdog_regs *wdog = (struct wdog_regs *)WDOG1_BASE_ADDR;
+	unsigned char eth1addr[6];
 
 	imx_iomux_v3_setup_multiple_pads(wdog_pads, ARRAY_SIZE(wdog_pads));
 
@@ -303,6 +304,11 @@
 	 */
 	clrsetbits_le16(&wdog->wcr, 0, 0x10);
 
+	/* Get the second MAC address */
+	imx_get_mac_from_fuse(1, eth1addr);
+	if (!env_get("eth1addr") && is_valid_ethaddr(eth1addr))
+		eth_env_set_enetaddr("eth1addr", eth1addr);
+
 	return 0;
 }
 
diff --git a/board/gateworks/venice/eeprom.c b/board/gateworks/venice/eeprom.c
index 6aea60a..241be4e 100644
--- a/board/gateworks/venice/eeprom.c
+++ b/board/gateworks/venice/eeprom.c
@@ -218,6 +218,11 @@
 		int rev_base_bom = get_bom_rev(base_info.model);
 
 		snprintf(buf, sz, "%s%2dxx-%dx", pre, base, som);
+		/* GW79xx baseboards have no build options */
+		if (base == 79) {
+			base = (int)strtoul(base_info.model + 2, NULL, 10);
+			snprintf(buf, sz, "%s%4d-%dx", pre, base, som);
+		}
 		switch (level) {
 		case 0: /* full model (ie gw73xx-0x-a1a1) */
 			if (rev_base_bom)
diff --git a/board/gateworks/venice/lpddr4_timing.h b/board/gateworks/venice/lpddr4_timing.h
index 62b8606..d19902f 100644
--- a/board/gateworks/venice/lpddr4_timing.h
+++ b/board/gateworks/venice/lpddr4_timing.h
@@ -16,6 +16,7 @@
 extern struct dram_timing_info dram_timing_2gb_single_die;
 extern struct dram_timing_info dram_timing_2gb_dual_die;
 #elif CONFIG_IMX8MP
+extern struct dram_timing_info dram_timing_1gb_single_die;
 extern struct dram_timing_info dram_timing_4gb_dual_die;
 #endif
 
diff --git a/board/gateworks/venice/lpddr4_timing_imx8mp.c b/board/gateworks/venice/lpddr4_timing_imx8mp.c
index 2e96332..7bfd1b5 100644
--- a/board/gateworks/venice/lpddr4_timing_imx8mp.c
+++ b/board/gateworks/venice/lpddr4_timing_imx8mp.c
@@ -1315,6 +1315,538 @@
 };
 
 /*
+ * Generated code from MX8M_DDR_tool v3.30 using MX8MP Plus RPAv9
+ * - 1GiB: ixm8mp-gw7020 1x Micron MT53E256M32D2DS 2-ch single-die per channel
+ */
+struct dram_cfg_param ddr_ddrc_cfg_1gb_single_die[] = {
+	/** Initialize DDRC registers **/
+	{ 0x3d400304, 0x1 },
+	{ 0x3d400030, 0x1 },
+	{ 0x3d400000, 0xa1080020 },
+	{ 0x3d400020, 0x1203 },
+	{ 0x3d400024, 0x16e3600 },
+	{ 0x3d400064, 0x5b0087 },
+	{ 0x3d400070, 0x7027f90 },
+	{ 0x3d400074, 0x790 },
+	{ 0x3d4000d0, 0xc00305ba },
+	{ 0x3d4000d4, 0x940000 },
+	{ 0x3d4000dc, 0xd4002d },
+	{ 0x3d4000e0, 0x310000 },
+	{ 0x3d4000e8, 0x660048 },
+	{ 0x3d4000ec, 0x160048 },
+	{ 0x3d400100, 0x191e1920 },
+	{ 0x3d400104, 0x60630 },
+	{ 0x3d40010c, 0xb0b000 },
+	{ 0x3d400110, 0xe04080e },
+	{ 0x3d400114, 0x2040c0c },
+	{ 0x3d400118, 0x1010007 },
+	{ 0x3d40011c, 0x402 },
+	{ 0x3d400130, 0x20600 },
+	{ 0x3d400134, 0xc100002 },
+	{ 0x3d400138, 0x8d },
+	{ 0x3d400144, 0x96004b },
+	{ 0x3d400180, 0x2ee0017 },
+	{ 0x3d400184, 0x2605b8e },
+	{ 0x3d400188, 0x0 },
+	{ 0x3d400190, 0x497820a },
+	{ 0x3d400194, 0x80303 },
+	{ 0x3d4001b4, 0x170a },
+	{ 0x3d4001a0, 0xe0400018 },
+	{ 0x3d4001a4, 0xdf00e4 },
+	{ 0x3d4001a8, 0x80000000 },
+	{ 0x3d4001b0, 0x11 },
+	{ 0x3d4001c0, 0x1 },
+	{ 0x3d4001c4, 0x1 },
+	{ 0x3d4000f4, 0x699 },
+	{ 0x3d400108, 0x70e1617 },
+	{ 0x3d400200, 0x1f },
+	{ 0x3d400208, 0x0 },
+	{ 0x3d40020c, 0x0 },
+	{ 0x3d400210, 0x1f1f },
+	{ 0x3d400204, 0x80808 },
+	{ 0x3d400214, 0x7070707 },
+	{ 0x3d400218, 0xf070707 },
+	{ 0x3d40021c, 0xf0f },
+	{ 0x3d400250, 0x1705 },
+	{ 0x3d400254, 0x2c },
+	{ 0x3d40025c, 0x4000030 },
+	{ 0x3d400264, 0x900093e7 },
+	{ 0x3d40026c, 0x2005574 },
+	{ 0x3d400400, 0x111 },
+	{ 0x3d400404, 0x72ff },
+	{ 0x3d400408, 0x72ff },
+	{ 0x3d400494, 0x2100e07 },
+	{ 0x3d400498, 0x620096 },
+	{ 0x3d40049c, 0x1100e07 },
+	{ 0x3d4004a0, 0xc8012c },
+	{ 0x3d402020, 0x1001 },
+	{ 0x3d402024, 0x30d400 },
+	{ 0x3d402050, 0x20d000 },
+	{ 0x3d402064, 0xc0012 },
+	{ 0x3d4020dc, 0x840000 },
+	{ 0x3d4020e0, 0x330000 },
+	{ 0x3d4020e8, 0x660048 },
+	{ 0x3d4020ec, 0x160048 },
+	{ 0x3d402100, 0xa040305 },
+	{ 0x3d402104, 0x30407 },
+	{ 0x3d402108, 0x203060b },
+	{ 0x3d40210c, 0x505000 },
+	{ 0x3d402110, 0x2040202 },
+	{ 0x3d402114, 0x2030202 },
+	{ 0x3d402118, 0x1010004 },
+	{ 0x3d40211c, 0x302 },
+	{ 0x3d402130, 0x20300 },
+	{ 0x3d402134, 0xa100002 },
+	{ 0x3d402138, 0x13 },
+	{ 0x3d402144, 0x14000a },
+	{ 0x3d402180, 0x640004 },
+	{ 0x3d402190, 0x3818200 },
+	{ 0x3d402194, 0x80303 },
+	{ 0x3d4021b4, 0x100 },
+	{ 0x3d4020f4, 0x599 },
+	{ 0x3d403020, 0x1001 },
+	{ 0x3d403024, 0xc3500 },
+	{ 0x3d403050, 0x20d000 },
+	{ 0x3d403064, 0x30005 },
+	{ 0x3d4030dc, 0x840000 },
+	{ 0x3d4030e0, 0x330000 },
+	{ 0x3d4030e8, 0x660048 },
+	{ 0x3d4030ec, 0x160048 },
+	{ 0x3d403100, 0xa010102 },
+	{ 0x3d403104, 0x30404 },
+	{ 0x3d403108, 0x203060b },
+	{ 0x3d40310c, 0x505000 },
+	{ 0x3d403110, 0x2040202 },
+	{ 0x3d403114, 0x2030202 },
+	{ 0x3d403118, 0x1010004 },
+	{ 0x3d40311c, 0x302 },
+	{ 0x3d403130, 0x20300 },
+	{ 0x3d403134, 0xa100002 },
+	{ 0x3d403138, 0x5 },
+	{ 0x3d403144, 0x50003 },
+	{ 0x3d403180, 0x190004 },
+	{ 0x3d403190, 0x3818200 },
+	{ 0x3d403194, 0x80303 },
+	{ 0x3d4031b4, 0x100 },
+	{ 0x3d4030f4, 0x599 },
+	{ 0x3d400028, 0x0 },
+};
+
+/* PHY Initialize Configuration */
+struct dram_cfg_param ddr_ddrphy_cfg_1gb_single_die[] = {
+	{ 0x100a0, 0x0 },
+	{ 0x100a1, 0x1 },
+	{ 0x100a2, 0x3 },
+	{ 0x100a3, 0x2 },
+	{ 0x100a4, 0x5 },
+	{ 0x100a5, 0x4 },
+	{ 0x100a6, 0x7 },
+	{ 0x100a7, 0x6 },
+	{ 0x110a0, 0x0 },
+	{ 0x110a1, 0x1 },
+	{ 0x110a2, 0x2 },
+	{ 0x110a3, 0x3 },
+	{ 0x110a4, 0x4 },
+	{ 0x110a5, 0x5 },
+	{ 0x110a6, 0x6 },
+	{ 0x110a7, 0x7 },
+	{ 0x120a0, 0x0 },
+	{ 0x120a1, 0x1 },
+	{ 0x120a2, 0x2 },
+	{ 0x120a3, 0x3 },
+	{ 0x120a4, 0x4 },
+	{ 0x120a5, 0x5 },
+	{ 0x120a6, 0x6 },
+	{ 0x120a7, 0x7 },
+	{ 0x130a0, 0x0 },
+	{ 0x130a1, 0x1 },
+	{ 0x130a2, 0x3 },
+	{ 0x130a3, 0x4 },
+	{ 0x130a4, 0x5 },
+	{ 0x130a5, 0x2 },
+	{ 0x130a6, 0x7 },
+	{ 0x130a7, 0x6 },
+	{ 0x1005f, 0x1ff },
+	{ 0x1015f, 0x1ff },
+	{ 0x1105f, 0x1ff },
+	{ 0x1115f, 0x1ff },
+	{ 0x1205f, 0x1ff },
+	{ 0x1215f, 0x1ff },
+	{ 0x1305f, 0x1ff },
+	{ 0x1315f, 0x1ff },
+	{ 0x11005f, 0x1ff },
+	{ 0x11015f, 0x1ff },
+	{ 0x11105f, 0x1ff },
+	{ 0x11115f, 0x1ff },
+	{ 0x11205f, 0x1ff },
+	{ 0x11215f, 0x1ff },
+	{ 0x11305f, 0x1ff },
+	{ 0x11315f, 0x1ff },
+	{ 0x21005f, 0x1ff },
+	{ 0x21015f, 0x1ff },
+	{ 0x21105f, 0x1ff },
+	{ 0x21115f, 0x1ff },
+	{ 0x21205f, 0x1ff },
+	{ 0x21215f, 0x1ff },
+	{ 0x21305f, 0x1ff },
+	{ 0x21315f, 0x1ff },
+	{ 0x55, 0x1ff },
+	{ 0x1055, 0x1ff },
+	{ 0x2055, 0x1ff },
+	{ 0x3055, 0x1ff },
+	{ 0x4055, 0x1ff },
+	{ 0x5055, 0x1ff },
+	{ 0x6055, 0x1ff },
+	{ 0x7055, 0x1ff },
+	{ 0x8055, 0x1ff },
+	{ 0x9055, 0x1ff },
+	{ 0x200c5, 0x19 },
+	{ 0x1200c5, 0x7 },
+	{ 0x2200c5, 0x7 },
+	{ 0x2002e, 0x2 },
+	{ 0x12002e, 0x2 },
+	{ 0x22002e, 0x2 },
+	{ 0x90204, 0x0 },
+	{ 0x190204, 0x0 },
+	{ 0x290204, 0x0 },
+	{ 0x20024, 0x1a3 },
+	{ 0x2003a, 0x2 },
+	{ 0x120024, 0x1a3 },
+	{ 0x2003a, 0x2 },
+	{ 0x220024, 0x1a3 },
+	{ 0x2003a, 0x2 },
+	{ 0x20056, 0x3 },
+	{ 0x120056, 0x3 },
+	{ 0x220056, 0x3 },
+	{ 0x1004d, 0xe00 },
+	{ 0x1014d, 0xe00 },
+	{ 0x1104d, 0xe00 },
+	{ 0x1114d, 0xe00 },
+	{ 0x1204d, 0xe00 },
+	{ 0x1214d, 0xe00 },
+	{ 0x1304d, 0xe00 },
+	{ 0x1314d, 0xe00 },
+	{ 0x11004d, 0xe00 },
+	{ 0x11014d, 0xe00 },
+	{ 0x11104d, 0xe00 },
+	{ 0x11114d, 0xe00 },
+	{ 0x11204d, 0xe00 },
+	{ 0x11214d, 0xe00 },
+	{ 0x11304d, 0xe00 },
+	{ 0x11314d, 0xe00 },
+	{ 0x21004d, 0xe00 },
+	{ 0x21014d, 0xe00 },
+	{ 0x21104d, 0xe00 },
+	{ 0x21114d, 0xe00 },
+	{ 0x21204d, 0xe00 },
+	{ 0x21214d, 0xe00 },
+	{ 0x21304d, 0xe00 },
+	{ 0x21314d, 0xe00 },
+	{ 0x10049, 0xeba },
+	{ 0x10149, 0xeba },
+	{ 0x11049, 0xeba },
+	{ 0x11149, 0xeba },
+	{ 0x12049, 0xeba },
+	{ 0x12149, 0xeba },
+	{ 0x13049, 0xeba },
+	{ 0x13149, 0xeba },
+	{ 0x110049, 0xeba },
+	{ 0x110149, 0xeba },
+	{ 0x111049, 0xeba },
+	{ 0x111149, 0xeba },
+	{ 0x112049, 0xeba },
+	{ 0x112149, 0xeba },
+	{ 0x113049, 0xeba },
+	{ 0x113149, 0xeba },
+	{ 0x210049, 0xeba },
+	{ 0x210149, 0xeba },
+	{ 0x211049, 0xeba },
+	{ 0x211149, 0xeba },
+	{ 0x212049, 0xeba },
+	{ 0x212149, 0xeba },
+	{ 0x213049, 0xeba },
+	{ 0x213149, 0xeba },
+	{ 0x43, 0x63 },
+	{ 0x1043, 0x63 },
+	{ 0x2043, 0x63 },
+	{ 0x3043, 0x63 },
+	{ 0x4043, 0x63 },
+	{ 0x5043, 0x63 },
+	{ 0x6043, 0x63 },
+	{ 0x7043, 0x63 },
+	{ 0x8043, 0x63 },
+	{ 0x9043, 0x63 },
+	{ 0x20018, 0x3 },
+	{ 0x20075, 0x4 },
+	{ 0x20050, 0x0 },
+	{ 0x20008, 0x2ee },
+	{ 0x120008, 0x64 },
+	{ 0x220008, 0x19 },
+	{ 0x20088, 0x9 },
+	{ 0x200b2, 0x104 },
+	{ 0x10043, 0x5a1 },
+	{ 0x10143, 0x5a1 },
+	{ 0x11043, 0x5a1 },
+	{ 0x11143, 0x5a1 },
+	{ 0x12043, 0x5a1 },
+	{ 0x12143, 0x5a1 },
+	{ 0x13043, 0x5a1 },
+	{ 0x13143, 0x5a1 },
+	{ 0x1200b2, 0x104 },
+	{ 0x110043, 0x5a1 },
+	{ 0x110143, 0x5a1 },
+	{ 0x111043, 0x5a1 },
+	{ 0x111143, 0x5a1 },
+	{ 0x112043, 0x5a1 },
+	{ 0x112143, 0x5a1 },
+	{ 0x113043, 0x5a1 },
+	{ 0x113143, 0x5a1 },
+	{ 0x2200b2, 0x104 },
+	{ 0x210043, 0x5a1 },
+	{ 0x210143, 0x5a1 },
+	{ 0x211043, 0x5a1 },
+	{ 0x211143, 0x5a1 },
+	{ 0x212043, 0x5a1 },
+	{ 0x212143, 0x5a1 },
+	{ 0x213043, 0x5a1 },
+	{ 0x213143, 0x5a1 },
+	{ 0x200fa, 0x1 },
+	{ 0x1200fa, 0x1 },
+	{ 0x2200fa, 0x1 },
+	{ 0x20019, 0x1 },
+	{ 0x120019, 0x1 },
+	{ 0x220019, 0x1 },
+	{ 0x200f0, 0x660 },
+	{ 0x200f1, 0x0 },
+	{ 0x200f2, 0x4444 },
+	{ 0x200f3, 0x8888 },
+	{ 0x200f4, 0x5665 },
+	{ 0x200f5, 0x0 },
+	{ 0x200f6, 0x0 },
+	{ 0x200f7, 0xf000 },
+	{ 0x20025, 0x0 },
+	{ 0x2002d, 0x0 },
+	{ 0x12002d, 0x0 },
+	{ 0x22002d, 0x0 },
+	{ 0x2007d, 0x212 },
+	{ 0x12007d, 0x212 },
+	{ 0x22007d, 0x212 },
+	{ 0x2007c, 0x61 },
+	{ 0x12007c, 0x61 },
+	{ 0x22007c, 0x61 },
+	{ 0x1004a, 0x500 },
+	{ 0x1104a, 0x500 },
+	{ 0x1204a, 0x500 },
+	{ 0x1304a, 0x500 },
+	{ 0x2002c, 0x0 },
+};
+
+/* P0 message block paremeter for training firmware */
+struct dram_cfg_param ddr_fsp0_cfg_1gb_single_die[] = {
+	{ 0xd0000, 0x0 },
+	{ 0x54003, 0xbb8 },
+	{ 0x54004, 0x2 },
+	{ 0x54005, 0x2228 },
+	{ 0x54006, 0x14 },
+	{ 0x54008, 0x131f },
+	{ 0x54009, 0xc8 },
+	{ 0x5400b, 0x2 },
+	{ 0x5400f, 0x100 },
+	{ 0x54012, 0x110 },
+	{ 0x54019, 0x2dd4 },
+	{ 0x5401a, 0x31 },
+	{ 0x5401b, 0x4866 },
+	{ 0x5401c, 0x4800 },
+	{ 0x5401e, 0x16 },
+	{ 0x5401f, 0x2dd4 },
+	{ 0x54020, 0x31 },
+	{ 0x54021, 0x4866 },
+	{ 0x54022, 0x4800 },
+	{ 0x54024, 0x16 },
+	{ 0x5402b, 0x1000 },
+	{ 0x5402c, 0x1 },
+	{ 0x54032, 0xd400 },
+	{ 0x54033, 0x312d },
+	{ 0x54034, 0x6600 },
+	{ 0x54035, 0x48 },
+	{ 0x54036, 0x48 },
+	{ 0x54037, 0x1600 },
+	{ 0x54038, 0xd400 },
+	{ 0x54039, 0x312d },
+	{ 0x5403a, 0x6600 },
+	{ 0x5403b, 0x48 },
+	{ 0x5403c, 0x48 },
+	{ 0x5403d, 0x1600 },
+	{ 0xd0000, 0x1 },
+};
+
+/* P1 message block paremeter for training firmware */
+struct dram_cfg_param ddr_fsp1_cfg_1gb_single_die[] = {
+	{ 0xd0000, 0x0 },
+	{ 0x54002, 0x101 },
+	{ 0x54003, 0x190 },
+	{ 0x54004, 0x2 },
+	{ 0x54005, 0x2228 },
+	{ 0x54006, 0x14 },
+	{ 0x54008, 0x121f },
+	{ 0x54009, 0xc8 },
+	{ 0x5400b, 0x2 },
+	{ 0x5400f, 0x100 },
+	{ 0x54012, 0x110 },
+	{ 0x54019, 0x84 },
+	{ 0x5401a, 0x33 },
+	{ 0x5401b, 0x4866 },
+	{ 0x5401c, 0x4800 },
+	{ 0x5401e, 0x16 },
+	{ 0x5401f, 0x84 },
+	{ 0x54020, 0x33 },
+	{ 0x54021, 0x4866 },
+	{ 0x54022, 0x4800 },
+	{ 0x54024, 0x16 },
+	{ 0x5402b, 0x1000 },
+	{ 0x5402c, 0x1 },
+	{ 0x54032, 0x8400 },
+	{ 0x54033, 0x3300 },
+	{ 0x54034, 0x6600 },
+	{ 0x54035, 0x48 },
+	{ 0x54036, 0x48 },
+	{ 0x54037, 0x1600 },
+	{ 0x54038, 0x8400 },
+	{ 0x54039, 0x3300 },
+	{ 0x5403a, 0x6600 },
+	{ 0x5403b, 0x48 },
+	{ 0x5403c, 0x48 },
+	{ 0x5403d, 0x1600 },
+	{ 0xd0000, 0x1 },
+};
+
+/* P2 message block paremeter for training firmware */
+struct dram_cfg_param ddr_fsp2_cfg_1gb_single_die[] = {
+	{ 0xd0000, 0x0 },
+	{ 0x54002, 0x102 },
+	{ 0x54003, 0x64 },
+	{ 0x54004, 0x2 },
+	{ 0x54005, 0x2228 },
+	{ 0x54006, 0x14 },
+	{ 0x54008, 0x121f },
+	{ 0x54009, 0xc8 },
+	{ 0x5400b, 0x2 },
+	{ 0x5400f, 0x100 },
+	{ 0x54012, 0x110 },
+	{ 0x54019, 0x84 },
+	{ 0x5401a, 0x33 },
+	{ 0x5401b, 0x4866 },
+	{ 0x5401c, 0x4800 },
+	{ 0x5401e, 0x16 },
+	{ 0x5401f, 0x84 },
+	{ 0x54020, 0x33 },
+	{ 0x54021, 0x4866 },
+	{ 0x54022, 0x4800 },
+	{ 0x54024, 0x16 },
+	{ 0x5402b, 0x1000 },
+	{ 0x5402c, 0x1 },
+	{ 0x54032, 0x8400 },
+	{ 0x54033, 0x3300 },
+	{ 0x54034, 0x6600 },
+	{ 0x54035, 0x48 },
+	{ 0x54036, 0x48 },
+	{ 0x54037, 0x1600 },
+	{ 0x54038, 0x8400 },
+	{ 0x54039, 0x3300 },
+	{ 0x5403a, 0x6600 },
+	{ 0x5403b, 0x48 },
+	{ 0x5403c, 0x48 },
+	{ 0x5403d, 0x1600 },
+	{ 0xd0000, 0x1 },
+};
+
+/* P0 2D message block paremeter for training firmware */
+struct dram_cfg_param ddr_fsp0_2d_cfg_1gb_single_die[] = {
+	{ 0xd0000, 0x0 },
+	{ 0x54003, 0xbb8 },
+	{ 0x54004, 0x2 },
+	{ 0x54005, 0x2228 },
+	{ 0x54006, 0x14 },
+	{ 0x54008, 0x61 },
+	{ 0x54009, 0xc8 },
+	{ 0x5400b, 0x2 },
+	{ 0x5400f, 0x100 },
+	{ 0x54010, 0x1f7f },
+	{ 0x54012, 0x110 },
+	{ 0x54019, 0x2dd4 },
+	{ 0x5401a, 0x31 },
+	{ 0x5401b, 0x4866 },
+	{ 0x5401c, 0x4800 },
+	{ 0x5401e, 0x16 },
+	{ 0x5401f, 0x2dd4 },
+	{ 0x54020, 0x31 },
+	{ 0x54021, 0x4866 },
+	{ 0x54022, 0x4800 },
+	{ 0x54024, 0x16 },
+	{ 0x5402b, 0x1000 },
+	{ 0x5402c, 0x1 },
+	{ 0x54032, 0xd400 },
+	{ 0x54033, 0x312d },
+	{ 0x54034, 0x6600 },
+	{ 0x54035, 0x48 },
+	{ 0x54036, 0x48 },
+	{ 0x54037, 0x1600 },
+	{ 0x54038, 0xd400 },
+	{ 0x54039, 0x312d },
+	{ 0x5403a, 0x6600 },
+	{ 0x5403b, 0x48 },
+	{ 0x5403c, 0x48 },
+	{ 0x5403d, 0x1600 },
+	{ 0xd0000, 0x1 },
+};
+
+struct dram_fsp_msg ddr_dram_fsp_msg_1gb_single_die[] = {
+	{
+		/* P0 3000mts 1D */
+		.drate = 3000,
+		.fw_type = FW_1D_IMAGE,
+		.fsp_cfg = ddr_fsp0_cfg_1gb_single_die,
+		.fsp_cfg_num = ARRAY_SIZE(ddr_fsp0_cfg_1gb_single_die),
+	},
+	{
+		/* P1 400mts 1D */
+		.drate = 400,
+		.fw_type = FW_1D_IMAGE,
+		.fsp_cfg = ddr_fsp1_cfg_1gb_single_die,
+		.fsp_cfg_num = ARRAY_SIZE(ddr_fsp1_cfg_1gb_single_die),
+	},
+	{
+		/* P2 100mts 1D */
+		.drate = 100,
+		.fw_type = FW_1D_IMAGE,
+		.fsp_cfg = ddr_fsp2_cfg_1gb_single_die,
+		.fsp_cfg_num = ARRAY_SIZE(ddr_fsp2_cfg_1gb_single_die),
+	},
+	{
+		/* P0 3000mts 2D */
+		.drate = 3000,
+		.fw_type = FW_2D_IMAGE,
+		.fsp_cfg = ddr_fsp0_2d_cfg_1gb_single_die,
+		.fsp_cfg_num = ARRAY_SIZE(ddr_fsp0_2d_cfg_1gb_single_die),
+	},
+};
+
+/* ddr timing config params */
+struct dram_timing_info dram_timing_1gb_single_die = {
+	.ddrc_cfg = ddr_ddrc_cfg_1gb_single_die,
+	.ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_1gb_single_die),
+	.ddrphy_cfg = ddr_ddrphy_cfg_1gb_single_die,
+	.ddrphy_cfg_num = ARRAY_SIZE(ddr_ddrphy_cfg_1gb_single_die),
+	.fsp_msg = ddr_dram_fsp_msg_1gb_single_die,
+	.fsp_msg_num = ARRAY_SIZE(ddr_dram_fsp_msg_1gb_single_die),
+	.ddrphy_trained_csr = ddr_ddrphy_trained_csr,
+	.ddrphy_trained_csr_num = ARRAY_SIZE(ddr_ddrphy_trained_csr),
+	.ddrphy_pie = ddr_phy_pie,
+	.ddrphy_pie_num = ARRAY_SIZE(ddr_phy_pie),
+	.fsp_table = { 3000, 400, 100, },
+};
+
+/*
  * Generated code from MX8M_DDR_tool v3.30 using MX8M Plus RPAv7
  * - 4GiB: imx8mp-gw7401 1x Micron MT53D1024M32D4DT 2-ch dual-die per channel
  */
diff --git a/board/gateworks/venice/spl.c b/board/gateworks/venice/spl.c
index 4eb7bdf..5aa2095 100644
--- a/board/gateworks/venice/spl.c
+++ b/board/gateworks/venice/spl.c
@@ -71,6 +71,9 @@
 		dram_timing = &dram_timing_2gb_dual_die;
 		size = 2048;
 #elif CONFIG_IMX8MP
+	case 1024:
+		dram_timing = &dram_timing_1gb_single_die;
+		break;
 	case 4096:
 		dram_timing = &dram_timing_4gb_dual_die;
 		break;
@@ -83,9 +86,12 @@
 
 	printf("DRAM    : LPDDR4 ");
 	if (size > 512)
-		printf("%d GiB\n", size / 1024);
+		printf("%d GiB", size / 1024);
 	else
-		printf("%d MiB\n", size);
+		printf("%d MiB", size);
+	printf(" %dMT/s %dMHz\n",
+	       dram_timing->fsp_msg[0].drate,
+	       dram_timing->fsp_msg[0].drate / 2);
 	ddr_init(dram_timing);
 }
 
@@ -121,7 +127,8 @@
 
 	if ((!strncmp(model, "GW71", 4)) ||
 	    (!strncmp(model, "GW72", 4)) ||
-	    (!strncmp(model, "GW73", 4))) {
+	    (!strncmp(model, "GW73", 4)) ||
+	    (!strncmp(model, "GW7905", 6))) {
 		ret = uclass_get_device_by_seq(UCLASS_I2C, 0, &bus);
 		if (ret) {
 			printf("PMIC    : failed I2C1 probe: %d\n", ret);
@@ -132,11 +139,22 @@
 			printf("PMIC    : failed probe: %d\n", ret);
 			return ret;
 		}
-		puts("PMIC    : MP5416\n");
+#ifdef CONFIG_IMX8MM
+		puts("PMIC    : MP5416 (IMX8MM)\n");
 
 		/* set VDD_ARM SW3 to 0.92V for 1.6GHz */
 		dm_i2c_reg_write(dev, MP5416_VSET_SW3,
 				 BIT(7) | MP5416_VSET_SW3_SVAL(920000));
+#elif CONFIG_IMX8MP
+		puts("PMIC    : MP5416 (IMX8MP)\n");
+
+		/* set VDD_ARM SW3 to 0.95V for 1.6GHz */
+		dm_i2c_reg_write(dev, MP5416_VSET_SW3,
+				 BIT(7) | MP5416_VSET_SW3_SVAL(950000));
+		/* set VDD_SOC SW1 to 0.95V for 1.6GHz */
+		dm_i2c_reg_write(dev, MP5416_VSET_SW1,
+				 BIT(7) | MP5416_VSET_SW1_SVAL(950000));
+#endif
 	}
 
 	else if (!strncmp(model, "GW74", 4)) {
@@ -327,6 +345,21 @@
 	}
 }
 
+unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc, unsigned long raw_sect)
+{
+	if (!IS_SD(mmc)) {
+		switch (EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config)) {
+		case 1:
+		case 2:
+			if (IS_ENABLED(CONFIG_IMX8MN) || IS_ENABLED(CONFIG_IMX8MP))
+				raw_sect -= 32 * 2;
+			break;
+		}
+	}
+
+	return raw_sect;
+}
+
 const char *spl_board_loader_name(u32 boot_device)
 {
 	switch (boot_device) {
@@ -340,3 +373,8 @@
 		return NULL;
 	}
 }
+
+void spl_board_init(void)
+{
+	arch_misc_init();
+}
diff --git a/board/gateworks/venice/venice.c b/board/gateworks/venice/venice.c
index ca62f0b..a39ae58 100644
--- a/board/gateworks/venice/venice.c
+++ b/board/gateworks/venice/venice.c
@@ -6,9 +6,12 @@
 #include <fdt_support.h>
 #include <init.h>
 #include <led.h>
+#include <mmc.h>
 #include <miiphy.h>
+#include <mmc.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/sys_proto.h>
+#include <asm/mach-imx/boot_mode.h>
 
 #include "eeprom.h"
 
@@ -17,7 +20,7 @@
 	if (!size)
 		return -EINVAL;
 
-	*size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE);
+	*size = get_ram_size((void *)PHYS_SDRAM, (long)PHYS_SDRAM_SIZE + (long)PHYS_SDRAM_2_SIZE);
 
 	return 0;
 }
@@ -93,10 +96,12 @@
 int board_late_init(void)
 {
 	const char *str;
+	struct mmc *mmc = NULL;
 	char env[32];
 	int ret, i;
 	u8 enetaddr[6];
 	char fdt[64];
+	int bootdev;
 
 	/* Set board serial/model */
 	if (!env_get("serial#"))
@@ -131,6 +136,74 @@
 		i++;
 	} while (!ret);
 
+	/*
+	 * set bootdev/bootblk/bootpart (used in firmware_update script)
+	 * dynamically depending on boot device and SoC
+	 */
+	bootdev = -1;
+	switch (get_boot_device()) {
+	case SD1_BOOT:
+	case MMC1_BOOT: /* SDHC1 */
+		bootdev = 0;
+		break;
+	case SD2_BOOT:
+	case MMC2_BOOT: /* SDHC2 */
+		bootdev = 1;
+		break;
+	case SD3_BOOT:
+	case MMC3_BOOT: /* SDHC3 */
+		bootdev = 2;
+		break;
+	default:
+		bootdev = 2; /* assume SDHC3 (eMMC) if booting over SDP */
+		break;
+	}
+	if (bootdev != -1)
+		mmc = find_mmc_device(bootdev);
+	if (mmc) {
+		int bootblk;
+
+		if (IS_ENABLED(CONFIG_IMX8MN) || IS_ENABLED(CONFIG_IMX8MP))
+			bootblk = 32 * SZ_1K / 512;
+		else
+			bootblk = 33 * SZ_1K / 512;
+		mmc_init(mmc);
+		if (!IS_SD(mmc)) {
+			int bootpart;
+
+			switch (EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config)) {
+			case 1: /* boot0 */
+				bootpart = 1;
+				break;
+			case 2: /* boot1 */
+				bootpart = 2;
+				break;
+			case 7: /* user */
+			default:
+				bootpart = 0;
+				break;
+			}
+			/* IMX8MP/IMX8MN BOOTROM v2 uses offset=0 for boot parts */
+			if ((IS_ENABLED(CONFIG_IMX8MN) || IS_ENABLED(CONFIG_IMX8MP)) &&
+			    (bootpart == 1 || bootpart == 2))
+				bootblk = 0;
+			env_set_hex("bootpart", bootpart);
+			env_set_hex("bootblk", bootblk);
+		} else { /* SD */
+			env_set("bootpart", "");
+			env_set_hex("bootblk", bootblk);
+		}
+		env_set_hex("dev", bootdev);
+	}
+
+	/* override soc=imx8m to provide a more specific soc name */
+	if (IS_ENABLED(CONFIG_IMX8MN))
+		env_set("soc", "imx8mn");
+	else if (IS_ENABLED(CONFIG_IMX8MP))
+		env_set("soc", "imx8mp");
+	else if (IS_ENABLED(CONFIG_IMX8MM))
+		env_set("soc", "imx8mm");
+
 	return 0;
 }
 
@@ -139,6 +212,20 @@
 	return devno;
 }
 
+uint mmc_get_env_part(struct mmc *mmc)
+{
+	if (!IS_SD(mmc)) {
+		switch (EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config)) {
+		case 1:
+			return 1;
+		case 2:
+			return 2;
+		}
+	}
+
+	return 0;
+}
+
 int ft_board_setup(void *fdt, struct bd_info *bd)
 {
 	const char *base_model = eeprom_get_baseboard_model();
diff --git a/board/gateworks/venice/venice.env b/board/gateworks/venice/venice.env
index f81804c..a0d6c43 100644
--- a/board/gateworks/venice/venice.env
+++ b/board/gateworks/venice/venice.env
@@ -8,11 +8,11 @@
 dev=2
 preboot=gsc wd-disable
 console=ttymxc1,115200
-update_firmware=tftpboot $loadaddr $image &&
+update_firmware=tftpboot $loadaddr $dir/venice-$soc-flash.bin &&
 	setexpr blkcnt $filesize + 0x1ff &&
 	setexpr blkcnt $blkcnt / 0x200 &&
-	mmc dev $dev &&
-	mmc write $loadaddr $splblk $blkcnt
+	mmc dev $dev $bootpart &&
+	mmc write $loadaddr $bootblk $blkcnt
 loadfdt=if $fsload $fdt_addr_r $dir/$fdt_file1;
 	then echo loaded $fdt_file1;
 	elif $fsload $fdt_addr_r $dir/$fdt_file2;
@@ -31,4 +31,3 @@
 	gzwrite mmc $dev $loadaddr $filesize 100000 1000000
 update_all=tftpboot $loadaddr $image &&
 	gzwrite mmc $dev $loadaddr $filesize
-erase_env=mmc dev $dev; mmc erase 0x7f08 0x40
diff --git a/board/google/Kconfig b/board/google/Kconfig
index a0f1a60..e4f9b5b 100644
--- a/board/google/Kconfig
+++ b/board/google/Kconfig
@@ -4,13 +4,6 @@
 
 if VENDOR_GOOGLE
 
-config BIOSEMU
-	bool
-	select X86EMU_RAW_IO
-
-config X86EMU_RAW_IO
-	bool
-
 choice
 	prompt "Mainboard model"
 	optional
diff --git a/board/kontron/sl-mx8mm/sl-mx8mm.c b/board/kontron/sl-mx8mm/sl-mx8mm.c
index ddb509e..8dcc2ea 100644
--- a/board/kontron/sl-mx8mm/sl-mx8mm.c
+++ b/board/kontron/sl-mx8mm/sl-mx8mm.c
@@ -37,7 +37,7 @@
 
 int board_phys_sdram_size(phys_size_t *size)
 {
-	u32 ddr_size = readl(M4_BOOTROM_BASE_ADDR);
+	u32 ddr_size = readl(MCU_BOOTROM_BASE_ADDR);
 
 	if (ddr_size == 4) {
 		*size = 0x100000000;
diff --git a/board/kontron/sl-mx8mm/spl.c b/board/kontron/sl-mx8mm/spl.c
index 3a919d0..b493734 100644
--- a/board/kontron/sl-mx8mm/spl.c
+++ b/board/kontron/sl-mx8mm/spl.c
@@ -106,7 +106,7 @@
 	}
 
 	gd->ram_size = size;
-	writel(size, M4_BOOTROM_BASE_ADDR);
+	writel(size, MCU_BOOTROM_BASE_ADDR);
 }
 
 int do_board_detect(void)
diff --git a/board/liebherr/xea/xea.c b/board/liebherr/xea/xea.c
index 38e841c..e4d2eb6 100644
--- a/board/liebherr/xea/xea.c
+++ b/board/liebherr/xea/xea.c
@@ -62,6 +62,7 @@
 void board_init_f(ulong arg)
 {
 	init_clocks();
+	spl_early_init();
 	preloader_console_init();
 }
 
@@ -203,5 +204,22 @@
 	return 0;
 }
 #endif
+/*
+ * NOTE:
+ *
+ * IMX28 clock "stub" DM driver!
+ *
+ * Only used for SPL stage, which is NOT using DM; serial and
+ * eMMC configuration.
+ */
+static const struct udevice_id imx28_clk_ids[] = {
+	{ .compatible = "fsl,imx28-clkctrl", },
+	{ }
+};
 
+U_BOOT_DRIVER(fsl_imx28_clkctrl) = {
+	.name           = "fsl_imx28_clkctrl",
+	.id             = UCLASS_CLK,
+	.of_match       = imx28_clk_ids,
+};
 #endif	/* CONFIG_SPL_BUILD */
diff --git a/board/nuvoton/arbel_evb/Kconfig b/board/nuvoton/arbel_evb/Kconfig
index efe8597..33c589f 100644
--- a/board/nuvoton/arbel_evb/Kconfig
+++ b/board/nuvoton/arbel_evb/Kconfig
@@ -11,8 +11,8 @@
 
 config SYS_MEM_TOP_HIDE
 	hex "Reserved TOP memory"
-	default 0xB000000
+	default 0x0
 	help
-	  Reserve memory for ECC/GFX/VCD/ECE.
+	  Reserve memory for ECC/GFX/OPTEE/TIP/CP.
 
 endif
diff --git a/board/nuvoton/arbel_evb/arbel_evb.c b/board/nuvoton/arbel_evb/arbel_evb.c
index cd12ce3..e52e0a5 100644
--- a/board/nuvoton/arbel_evb/arbel_evb.c
+++ b/board/nuvoton/arbel_evb/arbel_evb.c
@@ -8,6 +8,17 @@
 #include <asm/io.h>
 #include <asm/arch/gcr.h>
 
+#define SR_MII_CTRL_SWR_BIT15	15
+
+#define DRAM_512MB_ECC_SIZE	0x1C000000ULL
+#define DRAM_512MB_SIZE		0x20000000ULL
+#define DRAM_1GB_ECC_SIZE	0x38000000ULL
+#define DRAM_1GB_SIZE		0x40000000ULL
+#define DRAM_2GB_ECC_SIZE	0x70000000ULL
+#define DRAM_2GB_SIZE		0x80000000ULL
+#define DRAM_4GB_ECC_SIZE	0xE00000000ULL
+#define DRAM_4GB_SIZE		0x100000000ULL
+
 DECLARE_GLOBAL_DATA_PTR;
 
 int board_init(void)
@@ -18,12 +29,65 @@
 int dram_init(void)
 {
 	struct npcm_gcr *gcr = (struct npcm_gcr *)NPCM_GCR_BA;
+	uint64_t delta = 0ULL;
 
 	/*
-	 * Get dram size from bootblock.
-	 * The value is stored in scrpad_02 register.
+	 * get dram active size value from bootblock.
+	 * Value sent using scrpad_03 register.
+	 * feature available in bootblock 0.0.6 and above.
 	 */
-	gd->ram_size = readl(&gcr->scrpad_b);
+
+	gd->ram_size = readl(&gcr->scrpad_c);
+	debug("%s: scrpad_c: %llx ", __func__, gd->ram_size);
+
+	if (gd->ram_size == 0) {
+		gd->ram_size = readl(&gcr->scrpad_b);
+		debug("%s: scrpad_b: %llx ", __func__, gd->ram_size);
+	} else {
+		gd->ram_size *= 0x100000ULL;
+	}
+
+	gd->bd->bi_dram[0].start = 0;
+	debug("ram_size: %llx ", gd->ram_size);
+
+	switch (gd->ram_size) {
+	case DRAM_512MB_ECC_SIZE:
+	case DRAM_512MB_SIZE:
+	case DRAM_1GB_ECC_SIZE:
+	case DRAM_1GB_SIZE:
+	case DRAM_2GB_ECC_SIZE:
+	case DRAM_2GB_SIZE:
+		gd->bd->bi_dram[0].size = gd->ram_size;
+		gd->bd->bi_dram[1].start = 0;
+		gd->bd->bi_dram[1].size = 0;
+		break;
+	case DRAM_4GB_ECC_SIZE:
+		gd->bd->bi_dram[0].size = DRAM_2GB_ECC_SIZE;
+		gd->bd->bi_dram[1].start = DRAM_4GB_SIZE;
+		gd->bd->bi_dram[1].size = DRAM_2GB_SIZE;
+		delta = DRAM_4GB_SIZE - DRAM_2GB_ECC_SIZE;
+		break;
+	case DRAM_4GB_SIZE:
+		gd->bd->bi_dram[0].size = DRAM_2GB_SIZE;
+		gd->bd->bi_dram[1].start = DRAM_4GB_SIZE;
+		gd->bd->bi_dram[1].size = DRAM_2GB_SIZE;
+		delta = DRAM_4GB_SIZE - DRAM_2GB_SIZE;
+		break;
+	default:
+		gd->bd->bi_dram[0].size = DRAM_1GB_SIZE;
+		gd->bd->bi_dram[1].start = 0;
+		gd->bd->bi_dram[1].size = 0;
+		break;
+	}
+
+	gd->ram_size -= delta;
+
+	return 0;
+}
+
+int dram_init_banksize(void)
+{
+	dram_init();
 
 	return 0;
 }
diff --git a/board/nuvoton/poleg_evb/poleg_evb.c b/board/nuvoton/poleg_evb/poleg_evb.c
index aef142a..2052af6 100644
--- a/board/nuvoton/poleg_evb/poleg_evb.c
+++ b/board/nuvoton/poleg_evb/poleg_evb.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <env.h>
 #include <asm/io.h>
 #include <asm/arch/gcr.h>
 #include <asm/mach-types.h>
@@ -19,6 +20,7 @@
 
 int dram_init(void)
 {
+	char value[32];
 	struct npcm_gcr *gcr = (struct npcm_gcr *)NPCM_GCR_BA;
 
 	int ramsize = (readl(&gcr->intcr3) >> 8) & 0x7;
@@ -44,5 +46,10 @@
 	break;
 	}
 
+	if (gd->ram_size > 0) {
+                sprintf(value, "%ldM", (gd->ram_size / 0x100000));
+                env_set("mem", value);
+        }
+
 	return 0;
 }
diff --git a/board/phytec/phycore_imx8mm/lpddr4_timing.c b/board/phytec/phycore_imx8mm/lpddr4_timing.c
index 811ac26..f5a2f32 100644
--- a/board/phytec/phycore_imx8mm/lpddr4_timing.c
+++ b/board/phytec/phycore_imx8mm/lpddr4_timing.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Copyright (C) 2020 PHYTEC Messtechnik GmbH
+ * Copyright 2019 NXP
+ * Copyright (C) 2023 PHYTEC Messtechnik GmbH
  *
  * Generated code from MX8M_DDR_tool
  */
@@ -13,22 +14,22 @@
 	{0x3d400304, 0x1},
 	{0x3d400030, 0x1},
 	{0x3d400000, 0xa1080020},
-	{0x3d400020, 0x223},
+	{0x3d400020, 0x222},
 	{0x3d400024, 0x3a980},
-	{0x3d400064, 0x5b00d2},
+	{0x3d400064, 0x2d00d2},
 	{0x3d4000d0, 0xc00305ba},
 	{0x3d4000d4, 0x940000},
 	{0x3d4000dc, 0xd4002d},
 	{0x3d4000e0, 0x310000},
 	{0x3d4000e8, 0x66004d},
 	{0x3d4000ec, 0x16004d},
-	{0x3d400100, 0x191e1920},
+	{0x3d400100, 0x191e0c20},
 	{0x3d400104, 0x60630},
 	{0x3d40010c, 0xb0b000},
 	{0x3d400110, 0xe04080e},
 	{0x3d400114, 0x2040c0c},
 	{0x3d400118, 0x1010007},
-	{0x3d40011c, 0x401},
+	{0x3d40011c, 0x402},
 	{0x3d400130, 0x20600},
 	{0x3d400134, 0xc100002},
 	{0x3d400138, 0xd8},
@@ -45,7 +46,7 @@
 	{0x3d4001b0, 0x11},
 	{0x3d4001c0, 0x1},
 	{0x3d4001c4, 0x1},
-	{0x3d4000f4, 0xc99},
+	{0x3d4000f4, 0x699},
 	{0x3d400108, 0x70e1617},
 	{0x3d400200, 0x1f},
 	{0x3d40020c, 0x0},
@@ -53,6 +54,7 @@
 	{0x3d400204, 0x80808},
 	{0x3d400214, 0x7070707},
 	{0x3d400218, 0x7070707},
+	{0x3d40021c, 0xf0f},
 	{0x3d400250, 0x29001701},
 	{0x3d400254, 0x2c},
 	{0x3d40025c, 0x4000030},
@@ -64,22 +66,22 @@
 	{0x3d400498, 0x620096},
 	{0x3d40049c, 0x1100e07},
 	{0x3d4004a0, 0xc8012c},
-	{0x3d402020, 0x21},
+	{0x3d402020, 0x20},
 	{0x3d402024, 0x7d00},
 	{0x3d402050, 0x20d040},
-	{0x3d402064, 0xc001c},
+	{0x3d402064, 0x6001c},
 	{0x3d4020dc, 0x840000},
 	{0x3d4020e0, 0x310000},
 	{0x3d4020e8, 0x66004d},
 	{0x3d4020ec, 0x16004d},
-	{0x3d402100, 0xa040305},
+	{0x3d402100, 0xa040105},
 	{0x3d402104, 0x30407},
 	{0x3d402108, 0x203060b},
 	{0x3d40210c, 0x505000},
 	{0x3d402110, 0x2040202},
 	{0x3d402114, 0x2030202},
 	{0x3d402118, 0x1010004},
-	{0x3d40211c, 0x301},
+	{0x3d40211c, 0x302},
 	{0x3d402130, 0x20300},
 	{0x3d402134, 0xa100002},
 	{0x3d402138, 0x1d},
@@ -88,8 +90,8 @@
 	{0x3d402190, 0x3818200},
 	{0x3d402194, 0x80303},
 	{0x3d4021b4, 0x100},
-	{0x3d4020f4, 0xc99},
-	{0x3d403020, 0x21},
+	{0x3d4020f4, 0x599},
+	{0x3d403020, 0x20},
 	{0x3d403024, 0x1f40},
 	{0x3d403050, 0x20d040},
 	{0x3d403064, 0x30007},
@@ -104,7 +106,7 @@
 	{0x3d403110, 0x2040202},
 	{0x3d403114, 0x2030202},
 	{0x3d403118, 0x1010004},
-	{0x3d40311c, 0x301},
+	{0x3d40311c, 0x302},
 	{0x3d403130, 0x20300},
 	{0x3d403134, 0xa100002},
 	{0x3d403138, 0x8},
@@ -113,7 +115,7 @@
 	{0x3d403190, 0x3818200},
 	{0x3d403194, 0x80303},
 	{0x3d4031b4, 0x100},
-	{0x3d4030f4, 0xc99},
+	{0x3d4030f4, 0x599},
 	{0x3d400028, 0x0},
 };
 
@@ -201,8 +203,8 @@
 	{0x220024, 0x1ab},
 	{0x2003a, 0x0},
 	{0x20056, 0x3},
-	{0x120056, 0xa},
-	{0x220056, 0xa},
+	{0x120056, 0x3},
+	{0x220056, 0x3},
 	{0x1004d, 0xe00},
 	{0x1014d, 0xe00},
 	{0x1104d, 0xe00},
@@ -323,727 +325,726 @@
 
 /* ddr phy trained csr */
 static struct dram_cfg_param ddr_ddrphy_trained_csr[] = {
-	{ 0x200b2, 0x0 },
-	{ 0x1200b2, 0x0 },
-	{ 0x2200b2, 0x0 },
-	{ 0x200cb, 0x0 },
-	{ 0x10043, 0x0 },
-	{ 0x110043, 0x0 },
-	{ 0x210043, 0x0 },
-	{ 0x10143, 0x0 },
-	{ 0x110143, 0x0 },
-	{ 0x210143, 0x0 },
-	{ 0x11043, 0x0 },
-	{ 0x111043, 0x0 },
-	{ 0x211043, 0x0 },
-	{ 0x11143, 0x0 },
-	{ 0x111143, 0x0 },
-	{ 0x211143, 0x0 },
-	{ 0x12043, 0x0 },
-	{ 0x112043, 0x0 },
-	{ 0x212043, 0x0 },
-	{ 0x12143, 0x0 },
-	{ 0x112143, 0x0 },
-	{ 0x212143, 0x0 },
-	{ 0x13043, 0x0 },
-	{ 0x113043, 0x0 },
-	{ 0x213043, 0x0 },
-	{ 0x13143, 0x0 },
-	{ 0x113143, 0x0 },
-	{ 0x213143, 0x0 },
-	{ 0x80, 0x0 },
-	{ 0x100080, 0x0 },
-	{ 0x200080, 0x0 },
-	{ 0x1080, 0x0 },
-	{ 0x101080, 0x0 },
-	{ 0x201080, 0x0 },
-	{ 0x2080, 0x0 },
-	{ 0x102080, 0x0 },
-	{ 0x202080, 0x0 },
-	{ 0x3080, 0x0 },
-	{ 0x103080, 0x0 },
-	{ 0x203080, 0x0 },
-	{ 0x4080, 0x0 },
-	{ 0x104080, 0x0 },
-	{ 0x204080, 0x0 },
-	{ 0x5080, 0x0 },
-	{ 0x105080, 0x0 },
-	{ 0x205080, 0x0 },
-	{ 0x6080, 0x0 },
-	{ 0x106080, 0x0 },
-	{ 0x206080, 0x0 },
-	{ 0x7080, 0x0 },
-	{ 0x107080, 0x0 },
-	{ 0x207080, 0x0 },
-	{ 0x8080, 0x0 },
-	{ 0x108080, 0x0 },
-	{ 0x208080, 0x0 },
-	{ 0x9080, 0x0 },
-	{ 0x109080, 0x0 },
-	{ 0x209080, 0x0 },
-	{ 0x10080, 0x0 },
-	{ 0x110080, 0x0 },
-	{ 0x210080, 0x0 },
-	{ 0x10180, 0x0 },
-	{ 0x110180, 0x0 },
-	{ 0x210180, 0x0 },
-	{ 0x11080, 0x0 },
-	{ 0x111080, 0x0 },
-	{ 0x211080, 0x0 },
-	{ 0x11180, 0x0 },
-	{ 0x111180, 0x0 },
-	{ 0x211180, 0x0 },
-	{ 0x12080, 0x0 },
-	{ 0x112080, 0x0 },
-	{ 0x212080, 0x0 },
-	{ 0x12180, 0x0 },
-	{ 0x112180, 0x0 },
-	{ 0x212180, 0x0 },
-	{ 0x13080, 0x0 },
-	{ 0x113080, 0x0 },
-	{ 0x213080, 0x0 },
-	{ 0x13180, 0x0 },
-	{ 0x113180, 0x0 },
-	{ 0x213180, 0x0 },
-	{ 0x10081, 0x0 },
-	{ 0x110081, 0x0 },
-	{ 0x210081, 0x0 },
-	{ 0x10181, 0x0 },
-	{ 0x110181, 0x0 },
-	{ 0x210181, 0x0 },
-	{ 0x11081, 0x0 },
-	{ 0x111081, 0x0 },
-	{ 0x211081, 0x0 },
-	{ 0x11181, 0x0 },
-	{ 0x111181, 0x0 },
-	{ 0x211181, 0x0 },
-	{ 0x12081, 0x0 },
-	{ 0x112081, 0x0 },
-	{ 0x212081, 0x0 },
-	{ 0x12181, 0x0 },
-	{ 0x112181, 0x0 },
-	{ 0x212181, 0x0 },
-	{ 0x13081, 0x0 },
-	{ 0x113081, 0x0 },
-	{ 0x213081, 0x0 },
-	{ 0x13181, 0x0 },
-	{ 0x113181, 0x0 },
-	{ 0x213181, 0x0 },
-	{ 0x100d0, 0x0 },
-	{ 0x1100d0, 0x0 },
-	{ 0x2100d0, 0x0 },
-	{ 0x101d0, 0x0 },
-	{ 0x1101d0, 0x0 },
-	{ 0x2101d0, 0x0 },
-	{ 0x110d0, 0x0 },
-	{ 0x1110d0, 0x0 },
-	{ 0x2110d0, 0x0 },
-	{ 0x111d0, 0x0 },
-	{ 0x1111d0, 0x0 },
-	{ 0x2111d0, 0x0 },
-	{ 0x120d0, 0x0 },
-	{ 0x1120d0, 0x0 },
-	{ 0x2120d0, 0x0 },
-	{ 0x121d0, 0x0 },
-	{ 0x1121d0, 0x0 },
-	{ 0x2121d0, 0x0 },
-	{ 0x130d0, 0x0 },
-	{ 0x1130d0, 0x0 },
-	{ 0x2130d0, 0x0 },
-	{ 0x131d0, 0x0 },
-	{ 0x1131d0, 0x0 },
-	{ 0x2131d0, 0x0 },
-	{ 0x100d1, 0x0 },
-	{ 0x1100d1, 0x0 },
-	{ 0x2100d1, 0x0 },
-	{ 0x101d1, 0x0 },
-	{ 0x1101d1, 0x0 },
-	{ 0x2101d1, 0x0 },
-	{ 0x110d1, 0x0 },
-	{ 0x1110d1, 0x0 },
-	{ 0x2110d1, 0x0 },
-	{ 0x111d1, 0x0 },
-	{ 0x1111d1, 0x0 },
-	{ 0x2111d1, 0x0 },
-	{ 0x120d1, 0x0 },
-	{ 0x1120d1, 0x0 },
-	{ 0x2120d1, 0x0 },
-	{ 0x121d1, 0x0 },
-	{ 0x1121d1, 0x0 },
-	{ 0x2121d1, 0x0 },
-	{ 0x130d1, 0x0 },
-	{ 0x1130d1, 0x0 },
-	{ 0x2130d1, 0x0 },
-	{ 0x131d1, 0x0 },
-	{ 0x1131d1, 0x0 },
-	{ 0x2131d1, 0x0 },
-	{ 0x10068, 0x0 },
-	{ 0x10168, 0x0 },
-	{ 0x10268, 0x0 },
-	{ 0x10368, 0x0 },
-	{ 0x10468, 0x0 },
-	{ 0x10568, 0x0 },
-	{ 0x10668, 0x0 },
-	{ 0x10768, 0x0 },
-	{ 0x10868, 0x0 },
-	{ 0x11068, 0x0 },
-	{ 0x11168, 0x0 },
-	{ 0x11268, 0x0 },
-	{ 0x11368, 0x0 },
-	{ 0x11468, 0x0 },
-	{ 0x11568, 0x0 },
-	{ 0x11668, 0x0 },
-	{ 0x11768, 0x0 },
-	{ 0x11868, 0x0 },
-	{ 0x12068, 0x0 },
-	{ 0x12168, 0x0 },
-	{ 0x12268, 0x0 },
-	{ 0x12368, 0x0 },
-	{ 0x12468, 0x0 },
-	{ 0x12568, 0x0 },
-	{ 0x12668, 0x0 },
-	{ 0x12768, 0x0 },
-	{ 0x12868, 0x0 },
-	{ 0x13068, 0x0 },
-	{ 0x13168, 0x0 },
-	{ 0x13268, 0x0 },
-	{ 0x13368, 0x0 },
-	{ 0x13468, 0x0 },
-	{ 0x13568, 0x0 },
-	{ 0x13668, 0x0 },
-	{ 0x13768, 0x0 },
-	{ 0x13868, 0x0 },
-	{ 0x10069, 0x0 },
-	{ 0x10169, 0x0 },
-	{ 0x10269, 0x0 },
-	{ 0x10369, 0x0 },
-	{ 0x10469, 0x0 },
-	{ 0x10569, 0x0 },
-	{ 0x10669, 0x0 },
-	{ 0x10769, 0x0 },
-	{ 0x10869, 0x0 },
-	{ 0x11069, 0x0 },
-	{ 0x11169, 0x0 },
-	{ 0x11269, 0x0 },
-	{ 0x11369, 0x0 },
-	{ 0x11469, 0x0 },
-	{ 0x11569, 0x0 },
-	{ 0x11669, 0x0 },
-	{ 0x11769, 0x0 },
-	{ 0x11869, 0x0 },
-	{ 0x12069, 0x0 },
-	{ 0x12169, 0x0 },
-	{ 0x12269, 0x0 },
-	{ 0x12369, 0x0 },
-	{ 0x12469, 0x0 },
-	{ 0x12569, 0x0 },
-	{ 0x12669, 0x0 },
-	{ 0x12769, 0x0 },
-	{ 0x12869, 0x0 },
-	{ 0x13069, 0x0 },
-	{ 0x13169, 0x0 },
-	{ 0x13269, 0x0 },
-	{ 0x13369, 0x0 },
-	{ 0x13469, 0x0 },
-	{ 0x13569, 0x0 },
-	{ 0x13669, 0x0 },
-	{ 0x13769, 0x0 },
-	{ 0x13869, 0x0 },
-	{ 0x1008c, 0x0 },
-	{ 0x11008c, 0x0 },
-	{ 0x21008c, 0x0 },
-	{ 0x1018c, 0x0 },
-	{ 0x11018c, 0x0 },
-	{ 0x21018c, 0x0 },
-	{ 0x1108c, 0x0 },
-	{ 0x11108c, 0x0 },
-	{ 0x21108c, 0x0 },
-	{ 0x1118c, 0x0 },
-	{ 0x11118c, 0x0 },
-	{ 0x21118c, 0x0 },
-	{ 0x1208c, 0x0 },
-	{ 0x11208c, 0x0 },
-	{ 0x21208c, 0x0 },
-	{ 0x1218c, 0x0 },
-	{ 0x11218c, 0x0 },
-	{ 0x21218c, 0x0 },
-	{ 0x1308c, 0x0 },
-	{ 0x11308c, 0x0 },
-	{ 0x21308c, 0x0 },
-	{ 0x1318c, 0x0 },
-	{ 0x11318c, 0x0 },
-	{ 0x21318c, 0x0 },
-	{ 0x1008d, 0x0 },
-	{ 0x11008d, 0x0 },
-	{ 0x21008d, 0x0 },
-	{ 0x1018d, 0x0 },
-	{ 0x11018d, 0x0 },
-	{ 0x21018d, 0x0 },
-	{ 0x1108d, 0x0 },
-	{ 0x11108d, 0x0 },
-	{ 0x21108d, 0x0 },
-	{ 0x1118d, 0x0 },
-	{ 0x11118d, 0x0 },
-	{ 0x21118d, 0x0 },
-	{ 0x1208d, 0x0 },
-	{ 0x11208d, 0x0 },
-	{ 0x21208d, 0x0 },
-	{ 0x1218d, 0x0 },
-	{ 0x11218d, 0x0 },
-	{ 0x21218d, 0x0 },
-	{ 0x1308d, 0x0 },
-	{ 0x11308d, 0x0 },
-	{ 0x21308d, 0x0 },
-	{ 0x1318d, 0x0 },
-	{ 0x11318d, 0x0 },
-	{ 0x21318d, 0x0 },
-	{ 0x100c0, 0x0 },
-	{ 0x1100c0, 0x0 },
-	{ 0x2100c0, 0x0 },
-	{ 0x101c0, 0x0 },
-	{ 0x1101c0, 0x0 },
-	{ 0x2101c0, 0x0 },
-	{ 0x102c0, 0x0 },
-	{ 0x1102c0, 0x0 },
-	{ 0x2102c0, 0x0 },
-	{ 0x103c0, 0x0 },
-	{ 0x1103c0, 0x0 },
-	{ 0x2103c0, 0x0 },
-	{ 0x104c0, 0x0 },
-	{ 0x1104c0, 0x0 },
-	{ 0x2104c0, 0x0 },
-	{ 0x105c0, 0x0 },
-	{ 0x1105c0, 0x0 },
-	{ 0x2105c0, 0x0 },
-	{ 0x106c0, 0x0 },
-	{ 0x1106c0, 0x0 },
-	{ 0x2106c0, 0x0 },
-	{ 0x107c0, 0x0 },
-	{ 0x1107c0, 0x0 },
-	{ 0x2107c0, 0x0 },
-	{ 0x108c0, 0x0 },
-	{ 0x1108c0, 0x0 },
-	{ 0x2108c0, 0x0 },
-	{ 0x110c0, 0x0 },
-	{ 0x1110c0, 0x0 },
-	{ 0x2110c0, 0x0 },
-	{ 0x111c0, 0x0 },
-	{ 0x1111c0, 0x0 },
-	{ 0x2111c0, 0x0 },
-	{ 0x112c0, 0x0 },
-	{ 0x1112c0, 0x0 },
-	{ 0x2112c0, 0x0 },
-	{ 0x113c0, 0x0 },
-	{ 0x1113c0, 0x0 },
-	{ 0x2113c0, 0x0 },
-	{ 0x114c0, 0x0 },
-	{ 0x1114c0, 0x0 },
-	{ 0x2114c0, 0x0 },
-	{ 0x115c0, 0x0 },
-	{ 0x1115c0, 0x0 },
-	{ 0x2115c0, 0x0 },
-	{ 0x116c0, 0x0 },
-	{ 0x1116c0, 0x0 },
-	{ 0x2116c0, 0x0 },
-	{ 0x117c0, 0x0 },
-	{ 0x1117c0, 0x0 },
-	{ 0x2117c0, 0x0 },
-	{ 0x118c0, 0x0 },
-	{ 0x1118c0, 0x0 },
-	{ 0x2118c0, 0x0 },
-	{ 0x120c0, 0x0 },
-	{ 0x1120c0, 0x0 },
-	{ 0x2120c0, 0x0 },
-	{ 0x121c0, 0x0 },
-	{ 0x1121c0, 0x0 },
-	{ 0x2121c0, 0x0 },
-	{ 0x122c0, 0x0 },
-	{ 0x1122c0, 0x0 },
-	{ 0x2122c0, 0x0 },
-	{ 0x123c0, 0x0 },
-	{ 0x1123c0, 0x0 },
-	{ 0x2123c0, 0x0 },
-	{ 0x124c0, 0x0 },
-	{ 0x1124c0, 0x0 },
-	{ 0x2124c0, 0x0 },
-	{ 0x125c0, 0x0 },
-	{ 0x1125c0, 0x0 },
-	{ 0x2125c0, 0x0 },
-	{ 0x126c0, 0x0 },
-	{ 0x1126c0, 0x0 },
-	{ 0x2126c0, 0x0 },
-	{ 0x127c0, 0x0 },
-	{ 0x1127c0, 0x0 },
-	{ 0x2127c0, 0x0 },
-	{ 0x128c0, 0x0 },
-	{ 0x1128c0, 0x0 },
-	{ 0x2128c0, 0x0 },
-	{ 0x130c0, 0x0 },
-	{ 0x1130c0, 0x0 },
-	{ 0x2130c0, 0x0 },
-	{ 0x131c0, 0x0 },
-	{ 0x1131c0, 0x0 },
-	{ 0x2131c0, 0x0 },
-	{ 0x132c0, 0x0 },
-	{ 0x1132c0, 0x0 },
-	{ 0x2132c0, 0x0 },
-	{ 0x133c0, 0x0 },
-	{ 0x1133c0, 0x0 },
-	{ 0x2133c0, 0x0 },
-	{ 0x134c0, 0x0 },
-	{ 0x1134c0, 0x0 },
-	{ 0x2134c0, 0x0 },
-	{ 0x135c0, 0x0 },
-	{ 0x1135c0, 0x0 },
-	{ 0x2135c0, 0x0 },
-	{ 0x136c0, 0x0 },
-	{ 0x1136c0, 0x0 },
-	{ 0x2136c0, 0x0 },
-	{ 0x137c0, 0x0 },
-	{ 0x1137c0, 0x0 },
-	{ 0x2137c0, 0x0 },
-	{ 0x138c0, 0x0 },
-	{ 0x1138c0, 0x0 },
-	{ 0x2138c0, 0x0 },
-	{ 0x100c1, 0x0 },
-	{ 0x1100c1, 0x0 },
-	{ 0x2100c1, 0x0 },
-	{ 0x101c1, 0x0 },
-	{ 0x1101c1, 0x0 },
-	{ 0x2101c1, 0x0 },
-	{ 0x102c1, 0x0 },
-	{ 0x1102c1, 0x0 },
-	{ 0x2102c1, 0x0 },
-	{ 0x103c1, 0x0 },
-	{ 0x1103c1, 0x0 },
-	{ 0x2103c1, 0x0 },
-	{ 0x104c1, 0x0 },
-	{ 0x1104c1, 0x0 },
-	{ 0x2104c1, 0x0 },
-	{ 0x105c1, 0x0 },
-	{ 0x1105c1, 0x0 },
-	{ 0x2105c1, 0x0 },
-	{ 0x106c1, 0x0 },
-	{ 0x1106c1, 0x0 },
-	{ 0x2106c1, 0x0 },
-	{ 0x107c1, 0x0 },
-	{ 0x1107c1, 0x0 },
-	{ 0x2107c1, 0x0 },
-	{ 0x108c1, 0x0 },
-	{ 0x1108c1, 0x0 },
-	{ 0x2108c1, 0x0 },
-	{ 0x110c1, 0x0 },
-	{ 0x1110c1, 0x0 },
-	{ 0x2110c1, 0x0 },
-	{ 0x111c1, 0x0 },
-	{ 0x1111c1, 0x0 },
-	{ 0x2111c1, 0x0 },
-	{ 0x112c1, 0x0 },
-	{ 0x1112c1, 0x0 },
-	{ 0x2112c1, 0x0 },
-	{ 0x113c1, 0x0 },
-	{ 0x1113c1, 0x0 },
-	{ 0x2113c1, 0x0 },
-	{ 0x114c1, 0x0 },
-	{ 0x1114c1, 0x0 },
-	{ 0x2114c1, 0x0 },
-	{ 0x115c1, 0x0 },
-	{ 0x1115c1, 0x0 },
-	{ 0x2115c1, 0x0 },
-	{ 0x116c1, 0x0 },
-	{ 0x1116c1, 0x0 },
-	{ 0x2116c1, 0x0 },
-	{ 0x117c1, 0x0 },
-	{ 0x1117c1, 0x0 },
-	{ 0x2117c1, 0x0 },
-	{ 0x118c1, 0x0 },
-	{ 0x1118c1, 0x0 },
-	{ 0x2118c1, 0x0 },
-	{ 0x120c1, 0x0 },
-	{ 0x1120c1, 0x0 },
-	{ 0x2120c1, 0x0 },
-	{ 0x121c1, 0x0 },
-	{ 0x1121c1, 0x0 },
-	{ 0x2121c1, 0x0 },
-	{ 0x122c1, 0x0 },
-	{ 0x1122c1, 0x0 },
-	{ 0x2122c1, 0x0 },
-	{ 0x123c1, 0x0 },
-	{ 0x1123c1, 0x0 },
-	{ 0x2123c1, 0x0 },
-	{ 0x124c1, 0x0 },
-	{ 0x1124c1, 0x0 },
-	{ 0x2124c1, 0x0 },
-	{ 0x125c1, 0x0 },
-	{ 0x1125c1, 0x0 },
-	{ 0x2125c1, 0x0 },
-	{ 0x126c1, 0x0 },
-	{ 0x1126c1, 0x0 },
-	{ 0x2126c1, 0x0 },
-	{ 0x127c1, 0x0 },
-	{ 0x1127c1, 0x0 },
-	{ 0x2127c1, 0x0 },
-	{ 0x128c1, 0x0 },
-	{ 0x1128c1, 0x0 },
-	{ 0x2128c1, 0x0 },
-	{ 0x130c1, 0x0 },
-	{ 0x1130c1, 0x0 },
-	{ 0x2130c1, 0x0 },
-	{ 0x131c1, 0x0 },
-	{ 0x1131c1, 0x0 },
-	{ 0x2131c1, 0x0 },
-	{ 0x132c1, 0x0 },
-	{ 0x1132c1, 0x0 },
-	{ 0x2132c1, 0x0 },
-	{ 0x133c1, 0x0 },
-	{ 0x1133c1, 0x0 },
-	{ 0x2133c1, 0x0 },
-	{ 0x134c1, 0x0 },
-	{ 0x1134c1, 0x0 },
-	{ 0x2134c1, 0x0 },
-	{ 0x135c1, 0x0 },
-	{ 0x1135c1, 0x0 },
-	{ 0x2135c1, 0x0 },
-	{ 0x136c1, 0x0 },
-	{ 0x1136c1, 0x0 },
-	{ 0x2136c1, 0x0 },
-	{ 0x137c1, 0x0 },
-	{ 0x1137c1, 0x0 },
-	{ 0x2137c1, 0x0 },
-	{ 0x138c1, 0x0 },
-	{ 0x1138c1, 0x0 },
-	{ 0x2138c1, 0x0 },
-	{ 0x10020, 0x0 },
-	{ 0x110020, 0x0 },
-	{ 0x210020, 0x0 },
-	{ 0x11020, 0x0 },
-	{ 0x111020, 0x0 },
-	{ 0x211020, 0x0 },
-	{ 0x12020, 0x0 },
-	{ 0x112020, 0x0 },
-	{ 0x212020, 0x0 },
-	{ 0x13020, 0x0 },
-	{ 0x113020, 0x0 },
-	{ 0x213020, 0x0 },
-	{ 0x20072, 0x0 },
-	{ 0x20073, 0x0 },
-	{ 0x20074, 0x0 },
-	{ 0x100aa, 0x0 },
-	{ 0x110aa, 0x0 },
-	{ 0x120aa, 0x0 },
-	{ 0x130aa, 0x0 },
-	{ 0x20010, 0x0 },
-	{ 0x120010, 0x0 },
-	{ 0x220010, 0x0 },
-	{ 0x20011, 0x0 },
-	{ 0x120011, 0x0 },
-	{ 0x220011, 0x0 },
-	{ 0x100ae, 0x0 },
-	{ 0x1100ae, 0x0 },
-	{ 0x2100ae, 0x0 },
-	{ 0x100af, 0x0 },
-	{ 0x1100af, 0x0 },
-	{ 0x2100af, 0x0 },
-	{ 0x110ae, 0x0 },
-	{ 0x1110ae, 0x0 },
-	{ 0x2110ae, 0x0 },
-	{ 0x110af, 0x0 },
-	{ 0x1110af, 0x0 },
-	{ 0x2110af, 0x0 },
-	{ 0x120ae, 0x0 },
-	{ 0x1120ae, 0x0 },
-	{ 0x2120ae, 0x0 },
-	{ 0x120af, 0x0 },
-	{ 0x1120af, 0x0 },
-	{ 0x2120af, 0x0 },
-	{ 0x130ae, 0x0 },
-	{ 0x1130ae, 0x0 },
-	{ 0x2130ae, 0x0 },
-	{ 0x130af, 0x0 },
-	{ 0x1130af, 0x0 },
-	{ 0x2130af, 0x0 },
-	{ 0x20020, 0x0 },
-	{ 0x120020, 0x0 },
-	{ 0x220020, 0x0 },
-	{ 0x100a0, 0x0 },
-	{ 0x100a1, 0x0 },
-	{ 0x100a2, 0x0 },
-	{ 0x100a3, 0x0 },
-	{ 0x100a4, 0x0 },
-	{ 0x100a5, 0x0 },
-	{ 0x100a6, 0x0 },
-	{ 0x100a7, 0x0 },
-	{ 0x110a0, 0x0 },
-	{ 0x110a1, 0x0 },
-	{ 0x110a2, 0x0 },
-	{ 0x110a3, 0x0 },
-	{ 0x110a4, 0x0 },
-	{ 0x110a5, 0x0 },
-	{ 0x110a6, 0x0 },
-	{ 0x110a7, 0x0 },
-	{ 0x120a0, 0x0 },
-	{ 0x120a1, 0x0 },
-	{ 0x120a2, 0x0 },
-	{ 0x120a3, 0x0 },
-	{ 0x120a4, 0x0 },
-	{ 0x120a5, 0x0 },
-	{ 0x120a6, 0x0 },
-	{ 0x120a7, 0x0 },
-	{ 0x130a0, 0x0 },
-	{ 0x130a1, 0x0 },
-	{ 0x130a2, 0x0 },
-	{ 0x130a3, 0x0 },
-	{ 0x130a4, 0x0 },
-	{ 0x130a5, 0x0 },
-	{ 0x130a6, 0x0 },
-	{ 0x130a7, 0x0 },
-	{ 0x2007c, 0x0 },
-	{ 0x12007c, 0x0 },
-	{ 0x22007c, 0x0 },
-	{ 0x2007d, 0x0 },
-	{ 0x12007d, 0x0 },
-	{ 0x22007d, 0x0 },
-	{ 0x400fd, 0x0 },
-	{ 0x400c0, 0x0 },
-	{ 0x90201, 0x0 },
-	{ 0x190201, 0x0 },
-	{ 0x290201, 0x0 },
-	{ 0x90202, 0x0 },
-	{ 0x190202, 0x0 },
-	{ 0x290202, 0x0 },
-	{ 0x90203, 0x0 },
-	{ 0x190203, 0x0 },
-	{ 0x290203, 0x0 },
-	{ 0x90204, 0x0 },
-	{ 0x190204, 0x0 },
-	{ 0x290204, 0x0 },
-	{ 0x90205, 0x0 },
-	{ 0x190205, 0x0 },
-	{ 0x290205, 0x0 },
-	{ 0x90206, 0x0 },
-	{ 0x190206, 0x0 },
-	{ 0x290206, 0x0 },
-	{ 0x90207, 0x0 },
-	{ 0x190207, 0x0 },
-	{ 0x290207, 0x0 },
-	{ 0x90208, 0x0 },
-	{ 0x190208, 0x0 },
-	{ 0x290208, 0x0 },
-	{ 0x10062, 0x0 },
-	{ 0x10162, 0x0 },
-	{ 0x10262, 0x0 },
-	{ 0x10362, 0x0 },
-	{ 0x10462, 0x0 },
-	{ 0x10562, 0x0 },
-	{ 0x10662, 0x0 },
-	{ 0x10762, 0x0 },
-	{ 0x10862, 0x0 },
-	{ 0x11062, 0x0 },
-	{ 0x11162, 0x0 },
-	{ 0x11262, 0x0 },
-	{ 0x11362, 0x0 },
-	{ 0x11462, 0x0 },
-	{ 0x11562, 0x0 },
-	{ 0x11662, 0x0 },
-	{ 0x11762, 0x0 },
-	{ 0x11862, 0x0 },
-	{ 0x12062, 0x0 },
-	{ 0x12162, 0x0 },
-	{ 0x12262, 0x0 },
-	{ 0x12362, 0x0 },
-	{ 0x12462, 0x0 },
-	{ 0x12562, 0x0 },
-	{ 0x12662, 0x0 },
-	{ 0x12762, 0x0 },
-	{ 0x12862, 0x0 },
-	{ 0x13062, 0x0 },
-	{ 0x13162, 0x0 },
-	{ 0x13262, 0x0 },
-	{ 0x13362, 0x0 },
-	{ 0x13462, 0x0 },
-	{ 0x13562, 0x0 },
-	{ 0x13662, 0x0 },
-	{ 0x13762, 0x0 },
-	{ 0x13862, 0x0 },
-	{ 0x20077, 0x0 },
-	{ 0x10001, 0x0 },
-	{ 0x11001, 0x0 },
-	{ 0x12001, 0x0 },
-	{ 0x13001, 0x0 },
-	{ 0x10040, 0x0 },
-	{ 0x10140, 0x0 },
-	{ 0x10240, 0x0 },
-	{ 0x10340, 0x0 },
-	{ 0x10440, 0x0 },
-	{ 0x10540, 0x0 },
-	{ 0x10640, 0x0 },
-	{ 0x10740, 0x0 },
-	{ 0x10840, 0x0 },
-	{ 0x10030, 0x0 },
-	{ 0x10130, 0x0 },
-	{ 0x10230, 0x0 },
-	{ 0x10330, 0x0 },
-	{ 0x10430, 0x0 },
-	{ 0x10530, 0x0 },
-	{ 0x10630, 0x0 },
-	{ 0x10730, 0x0 },
-	{ 0x10830, 0x0 },
-	{ 0x11040, 0x0 },
-	{ 0x11140, 0x0 },
-	{ 0x11240, 0x0 },
-	{ 0x11340, 0x0 },
-	{ 0x11440, 0x0 },
-	{ 0x11540, 0x0 },
-	{ 0x11640, 0x0 },
-	{ 0x11740, 0x0 },
-	{ 0x11840, 0x0 },
-	{ 0x11030, 0x0 },
-	{ 0x11130, 0x0 },
-	{ 0x11230, 0x0 },
-	{ 0x11330, 0x0 },
-	{ 0x11430, 0x0 },
-	{ 0x11530, 0x0 },
-	{ 0x11630, 0x0 },
-	{ 0x11730, 0x0 },
-	{ 0x11830, 0x0 },
-	{ 0x12040, 0x0 },
-	{ 0x12140, 0x0 },
-	{ 0x12240, 0x0 },
-	{ 0x12340, 0x0 },
-	{ 0x12440, 0x0 },
-	{ 0x12540, 0x0 },
-	{ 0x12640, 0x0 },
-	{ 0x12740, 0x0 },
-	{ 0x12840, 0x0 },
-	{ 0x12030, 0x0 },
-	{ 0x12130, 0x0 },
-	{ 0x12230, 0x0 },
-	{ 0x12330, 0x0 },
-	{ 0x12430, 0x0 },
-	{ 0x12530, 0x0 },
-	{ 0x12630, 0x0 },
-	{ 0x12730, 0x0 },
-	{ 0x12830, 0x0 },
-	{ 0x13040, 0x0 },
-	{ 0x13140, 0x0 },
-	{ 0x13240, 0x0 },
-	{ 0x13340, 0x0 },
-	{ 0x13440, 0x0 },
-	{ 0x13540, 0x0 },
-	{ 0x13640, 0x0 },
-	{ 0x13740, 0x0 },
-	{ 0x13840, 0x0 },
-	{ 0x13030, 0x0 },
-	{ 0x13130, 0x0 },
-	{ 0x13230, 0x0 },
-	{ 0x13330, 0x0 },
-	{ 0x13430, 0x0 },
-	{ 0x13530, 0x0 },
-	{ 0x13630, 0x0 },
-	{ 0x13730, 0x0 },
-	{ 0x13830, 0x0 },
+	{0x200b2, 0x0},
+	{0x1200b2, 0x0},
+	{0x2200b2, 0x0},
+	{0x200cb, 0x0},
+	{0x10043, 0x0},
+	{0x110043, 0x0},
+	{0x210043, 0x0},
+	{0x10143, 0x0},
+	{0x110143, 0x0},
+	{0x210143, 0x0},
+	{0x11043, 0x0},
+	{0x111043, 0x0},
+	{0x211043, 0x0},
+	{0x11143, 0x0},
+	{0x111143, 0x0},
+	{0x211143, 0x0},
+	{0x12043, 0x0},
+	{0x112043, 0x0},
+	{0x212043, 0x0},
+	{0x12143, 0x0},
+	{0x112143, 0x0},
+	{0x212143, 0x0},
+	{0x13043, 0x0},
+	{0x113043, 0x0},
+	{0x213043, 0x0},
+	{0x13143, 0x0},
+	{0x113143, 0x0},
+	{0x213143, 0x0},
+	{0x80, 0x0},
+	{0x100080, 0x0},
+	{0x200080, 0x0},
+	{0x1080, 0x0},
+	{0x101080, 0x0},
+	{0x201080, 0x0},
+	{0x2080, 0x0},
+	{0x102080, 0x0},
+	{0x202080, 0x0},
+	{0x3080, 0x0},
+	{0x103080, 0x0},
+	{0x203080, 0x0},
+	{0x4080, 0x0},
+	{0x104080, 0x0},
+	{0x204080, 0x0},
+	{0x5080, 0x0},
+	{0x105080, 0x0},
+	{0x205080, 0x0},
+	{0x6080, 0x0},
+	{0x106080, 0x0},
+	{0x206080, 0x0},
+	{0x7080, 0x0},
+	{0x107080, 0x0},
+	{0x207080, 0x0},
+	{0x8080, 0x0},
+	{0x108080, 0x0},
+	{0x208080, 0x0},
+	{0x9080, 0x0},
+	{0x109080, 0x0},
+	{0x209080, 0x0},
+	{0x10080, 0x0},
+	{0x110080, 0x0},
+	{0x210080, 0x0},
+	{0x10180, 0x0},
+	{0x110180, 0x0},
+	{0x210180, 0x0},
+	{0x11080, 0x0},
+	{0x111080, 0x0},
+	{0x211080, 0x0},
+	{0x11180, 0x0},
+	{0x111180, 0x0},
+	{0x211180, 0x0},
+	{0x12080, 0x0},
+	{0x112080, 0x0},
+	{0x212080, 0x0},
+	{0x12180, 0x0},
+	{0x112180, 0x0},
+	{0x212180, 0x0},
+	{0x13080, 0x0},
+	{0x113080, 0x0},
+	{0x213080, 0x0},
+	{0x13180, 0x0},
+	{0x113180, 0x0},
+	{0x213180, 0x0},
+	{0x10081, 0x0},
+	{0x110081, 0x0},
+	{0x210081, 0x0},
+	{0x10181, 0x0},
+	{0x110181, 0x0},
+	{0x210181, 0x0},
+	{0x11081, 0x0},
+	{0x111081, 0x0},
+	{0x211081, 0x0},
+	{0x11181, 0x0},
+	{0x111181, 0x0},
+	{0x211181, 0x0},
+	{0x12081, 0x0},
+	{0x112081, 0x0},
+	{0x212081, 0x0},
+	{0x12181, 0x0},
+	{0x112181, 0x0},
+	{0x212181, 0x0},
+	{0x13081, 0x0},
+	{0x113081, 0x0},
+	{0x213081, 0x0},
+	{0x13181, 0x0},
+	{0x113181, 0x0},
+	{0x213181, 0x0},
+	{0x100d0, 0x0},
+	{0x1100d0, 0x0},
+	{0x2100d0, 0x0},
+	{0x101d0, 0x0},
+	{0x1101d0, 0x0},
+	{0x2101d0, 0x0},
+	{0x110d0, 0x0},
+	{0x1110d0, 0x0},
+	{0x2110d0, 0x0},
+	{0x111d0, 0x0},
+	{0x1111d0, 0x0},
+	{0x2111d0, 0x0},
+	{0x120d0, 0x0},
+	{0x1120d0, 0x0},
+	{0x2120d0, 0x0},
+	{0x121d0, 0x0},
+	{0x1121d0, 0x0},
+	{0x2121d0, 0x0},
+	{0x130d0, 0x0},
+	{0x1130d0, 0x0},
+	{0x2130d0, 0x0},
+	{0x131d0, 0x0},
+	{0x1131d0, 0x0},
+	{0x2131d0, 0x0},
+	{0x100d1, 0x0},
+	{0x1100d1, 0x0},
+	{0x2100d1, 0x0},
+	{0x101d1, 0x0},
+	{0x1101d1, 0x0},
+	{0x2101d1, 0x0},
+	{0x110d1, 0x0},
+	{0x1110d1, 0x0},
+	{0x2110d1, 0x0},
+	{0x111d1, 0x0},
+	{0x1111d1, 0x0},
+	{0x2111d1, 0x0},
+	{0x120d1, 0x0},
+	{0x1120d1, 0x0},
+	{0x2120d1, 0x0},
+	{0x121d1, 0x0},
+	{0x1121d1, 0x0},
+	{0x2121d1, 0x0},
+	{0x130d1, 0x0},
+	{0x1130d1, 0x0},
+	{0x2130d1, 0x0},
+	{0x131d1, 0x0},
+	{0x1131d1, 0x0},
+	{0x2131d1, 0x0},
+	{0x10068, 0x0},
+	{0x10168, 0x0},
+	{0x10268, 0x0},
+	{0x10368, 0x0},
+	{0x10468, 0x0},
+	{0x10568, 0x0},
+	{0x10668, 0x0},
+	{0x10768, 0x0},
+	{0x10868, 0x0},
+	{0x11068, 0x0},
+	{0x11168, 0x0},
+	{0x11268, 0x0},
+	{0x11368, 0x0},
+	{0x11468, 0x0},
+	{0x11568, 0x0},
+	{0x11668, 0x0},
+	{0x11768, 0x0},
+	{0x11868, 0x0},
+	{0x12068, 0x0},
+	{0x12168, 0x0},
+	{0x12268, 0x0},
+	{0x12368, 0x0},
+	{0x12468, 0x0},
+	{0x12568, 0x0},
+	{0x12668, 0x0},
+	{0x12768, 0x0},
+	{0x12868, 0x0},
+	{0x13068, 0x0},
+	{0x13168, 0x0},
+	{0x13268, 0x0},
+	{0x13368, 0x0},
+	{0x13468, 0x0},
+	{0x13568, 0x0},
+	{0x13668, 0x0},
+	{0x13768, 0x0},
+	{0x13868, 0x0},
+	{0x10069, 0x0},
+	{0x10169, 0x0},
+	{0x10269, 0x0},
+	{0x10369, 0x0},
+	{0x10469, 0x0},
+	{0x10569, 0x0},
+	{0x10669, 0x0},
+	{0x10769, 0x0},
+	{0x10869, 0x0},
+	{0x11069, 0x0},
+	{0x11169, 0x0},
+	{0x11269, 0x0},
+	{0x11369, 0x0},
+	{0x11469, 0x0},
+	{0x11569, 0x0},
+	{0x11669, 0x0},
+	{0x11769, 0x0},
+	{0x11869, 0x0},
+	{0x12069, 0x0},
+	{0x12169, 0x0},
+	{0x12269, 0x0},
+	{0x12369, 0x0},
+	{0x12469, 0x0},
+	{0x12569, 0x0},
+	{0x12669, 0x0},
+	{0x12769, 0x0},
+	{0x12869, 0x0},
+	{0x13069, 0x0},
+	{0x13169, 0x0},
+	{0x13269, 0x0},
+	{0x13369, 0x0},
+	{0x13469, 0x0},
+	{0x13569, 0x0},
+	{0x13669, 0x0},
+	{0x13769, 0x0},
+	{0x13869, 0x0},
+	{0x1008c, 0x0},
+	{0x11008c, 0x0},
+	{0x21008c, 0x0},
+	{0x1018c, 0x0},
+	{0x11018c, 0x0},
+	{0x21018c, 0x0},
+	{0x1108c, 0x0},
+	{0x11108c, 0x0},
+	{0x21108c, 0x0},
+	{0x1118c, 0x0},
+	{0x11118c, 0x0},
+	{0x21118c, 0x0},
+	{0x1208c, 0x0},
+	{0x11208c, 0x0},
+	{0x21208c, 0x0},
+	{0x1218c, 0x0},
+	{0x11218c, 0x0},
+	{0x21218c, 0x0},
+	{0x1308c, 0x0},
+	{0x11308c, 0x0},
+	{0x21308c, 0x0},
+	{0x1318c, 0x0},
+	{0x11318c, 0x0},
+	{0x21318c, 0x0},
+	{0x1008d, 0x0},
+	{0x11008d, 0x0},
+	{0x21008d, 0x0},
+	{0x1018d, 0x0},
+	{0x11018d, 0x0},
+	{0x21018d, 0x0},
+	{0x1108d, 0x0},
+	{0x11108d, 0x0},
+	{0x21108d, 0x0},
+	{0x1118d, 0x0},
+	{0x11118d, 0x0},
+	{0x21118d, 0x0},
+	{0x1208d, 0x0},
+	{0x11208d, 0x0},
+	{0x21208d, 0x0},
+	{0x1218d, 0x0},
+	{0x11218d, 0x0},
+	{0x21218d, 0x0},
+	{0x1308d, 0x0},
+	{0x11308d, 0x0},
+	{0x21308d, 0x0},
+	{0x1318d, 0x0},
+	{0x11318d, 0x0},
+	{0x21318d, 0x0},
+	{0x100c0, 0x0},
+	{0x1100c0, 0x0},
+	{0x2100c0, 0x0},
+	{0x101c0, 0x0},
+	{0x1101c0, 0x0},
+	{0x2101c0, 0x0},
+	{0x102c0, 0x0},
+	{0x1102c0, 0x0},
+	{0x2102c0, 0x0},
+	{0x103c0, 0x0},
+	{0x1103c0, 0x0},
+	{0x2103c0, 0x0},
+	{0x104c0, 0x0},
+	{0x1104c0, 0x0},
+	{0x2104c0, 0x0},
+	{0x105c0, 0x0},
+	{0x1105c0, 0x0},
+	{0x2105c0, 0x0},
+	{0x106c0, 0x0},
+	{0x1106c0, 0x0},
+	{0x2106c0, 0x0},
+	{0x107c0, 0x0},
+	{0x1107c0, 0x0},
+	{0x2107c0, 0x0},
+	{0x108c0, 0x0},
+	{0x1108c0, 0x0},
+	{0x2108c0, 0x0},
+	{0x110c0, 0x0},
+	{0x1110c0, 0x0},
+	{0x2110c0, 0x0},
+	{0x111c0, 0x0},
+	{0x1111c0, 0x0},
+	{0x2111c0, 0x0},
+	{0x112c0, 0x0},
+	{0x1112c0, 0x0},
+	{0x2112c0, 0x0},
+	{0x113c0, 0x0},
+	{0x1113c0, 0x0},
+	{0x2113c0, 0x0},
+	{0x114c0, 0x0},
+	{0x1114c0, 0x0},
+	{0x2114c0, 0x0},
+	{0x115c0, 0x0},
+	{0x1115c0, 0x0},
+	{0x2115c0, 0x0},
+	{0x116c0, 0x0},
+	{0x1116c0, 0x0},
+	{0x2116c0, 0x0},
+	{0x117c0, 0x0},
+	{0x1117c0, 0x0},
+	{0x2117c0, 0x0},
+	{0x118c0, 0x0},
+	{0x1118c0, 0x0},
+	{0x2118c0, 0x0},
+	{0x120c0, 0x0},
+	{0x1120c0, 0x0},
+	{0x2120c0, 0x0},
+	{0x121c0, 0x0},
+	{0x1121c0, 0x0},
+	{0x2121c0, 0x0},
+	{0x122c0, 0x0},
+	{0x1122c0, 0x0},
+	{0x2122c0, 0x0},
+	{0x123c0, 0x0},
+	{0x1123c0, 0x0},
+	{0x2123c0, 0x0},
+	{0x124c0, 0x0},
+	{0x1124c0, 0x0},
+	{0x2124c0, 0x0},
+	{0x125c0, 0x0},
+	{0x1125c0, 0x0},
+	{0x2125c0, 0x0},
+	{0x126c0, 0x0},
+	{0x1126c0, 0x0},
+	{0x2126c0, 0x0},
+	{0x127c0, 0x0},
+	{0x1127c0, 0x0},
+	{0x2127c0, 0x0},
+	{0x128c0, 0x0},
+	{0x1128c0, 0x0},
+	{0x2128c0, 0x0},
+	{0x130c0, 0x0},
+	{0x1130c0, 0x0},
+	{0x2130c0, 0x0},
+	{0x131c0, 0x0},
+	{0x1131c0, 0x0},
+	{0x2131c0, 0x0},
+	{0x132c0, 0x0},
+	{0x1132c0, 0x0},
+	{0x2132c0, 0x0},
+	{0x133c0, 0x0},
+	{0x1133c0, 0x0},
+	{0x2133c0, 0x0},
+	{0x134c0, 0x0},
+	{0x1134c0, 0x0},
+	{0x2134c0, 0x0},
+	{0x135c0, 0x0},
+	{0x1135c0, 0x0},
+	{0x2135c0, 0x0},
+	{0x136c0, 0x0},
+	{0x1136c0, 0x0},
+	{0x2136c0, 0x0},
+	{0x137c0, 0x0},
+	{0x1137c0, 0x0},
+	{0x2137c0, 0x0},
+	{0x138c0, 0x0},
+	{0x1138c0, 0x0},
+	{0x2138c0, 0x0},
+	{0x100c1, 0x0},
+	{0x1100c1, 0x0},
+	{0x2100c1, 0x0},
+	{0x101c1, 0x0},
+	{0x1101c1, 0x0},
+	{0x2101c1, 0x0},
+	{0x102c1, 0x0},
+	{0x1102c1, 0x0},
+	{0x2102c1, 0x0},
+	{0x103c1, 0x0},
+	{0x1103c1, 0x0},
+	{0x2103c1, 0x0},
+	{0x104c1, 0x0},
+	{0x1104c1, 0x0},
+	{0x2104c1, 0x0},
+	{0x105c1, 0x0},
+	{0x1105c1, 0x0},
+	{0x2105c1, 0x0},
+	{0x106c1, 0x0},
+	{0x1106c1, 0x0},
+	{0x2106c1, 0x0},
+	{0x107c1, 0x0},
+	{0x1107c1, 0x0},
+	{0x2107c1, 0x0},
+	{0x108c1, 0x0},
+	{0x1108c1, 0x0},
+	{0x2108c1, 0x0},
+	{0x110c1, 0x0},
+	{0x1110c1, 0x0},
+	{0x2110c1, 0x0},
+	{0x111c1, 0x0},
+	{0x1111c1, 0x0},
+	{0x2111c1, 0x0},
+	{0x112c1, 0x0},
+	{0x1112c1, 0x0},
+	{0x2112c1, 0x0},
+	{0x113c1, 0x0},
+	{0x1113c1, 0x0},
+	{0x2113c1, 0x0},
+	{0x114c1, 0x0},
+	{0x1114c1, 0x0},
+	{0x2114c1, 0x0},
+	{0x115c1, 0x0},
+	{0x1115c1, 0x0},
+	{0x2115c1, 0x0},
+	{0x116c1, 0x0},
+	{0x1116c1, 0x0},
+	{0x2116c1, 0x0},
+	{0x117c1, 0x0},
+	{0x1117c1, 0x0},
+	{0x2117c1, 0x0},
+	{0x118c1, 0x0},
+	{0x1118c1, 0x0},
+	{0x2118c1, 0x0},
+	{0x120c1, 0x0},
+	{0x1120c1, 0x0},
+	{0x2120c1, 0x0},
+	{0x121c1, 0x0},
+	{0x1121c1, 0x0},
+	{0x2121c1, 0x0},
+	{0x122c1, 0x0},
+	{0x1122c1, 0x0},
+	{0x2122c1, 0x0},
+	{0x123c1, 0x0},
+	{0x1123c1, 0x0},
+	{0x2123c1, 0x0},
+	{0x124c1, 0x0},
+	{0x1124c1, 0x0},
+	{0x2124c1, 0x0},
+	{0x125c1, 0x0},
+	{0x1125c1, 0x0},
+	{0x2125c1, 0x0},
+	{0x126c1, 0x0},
+	{0x1126c1, 0x0},
+	{0x2126c1, 0x0},
+	{0x127c1, 0x0},
+	{0x1127c1, 0x0},
+	{0x2127c1, 0x0},
+	{0x128c1, 0x0},
+	{0x1128c1, 0x0},
+	{0x2128c1, 0x0},
+	{0x130c1, 0x0},
+	{0x1130c1, 0x0},
+	{0x2130c1, 0x0},
+	{0x131c1, 0x0},
+	{0x1131c1, 0x0},
+	{0x2131c1, 0x0},
+	{0x132c1, 0x0},
+	{0x1132c1, 0x0},
+	{0x2132c1, 0x0},
+	{0x133c1, 0x0},
+	{0x1133c1, 0x0},
+	{0x2133c1, 0x0},
+	{0x134c1, 0x0},
+	{0x1134c1, 0x0},
+	{0x2134c1, 0x0},
+	{0x135c1, 0x0},
+	{0x1135c1, 0x0},
+	{0x2135c1, 0x0},
+	{0x136c1, 0x0},
+	{0x1136c1, 0x0},
+	{0x2136c1, 0x0},
+	{0x137c1, 0x0},
+	{0x1137c1, 0x0},
+	{0x2137c1, 0x0},
+	{0x138c1, 0x0},
+	{0x1138c1, 0x0},
+	{0x2138c1, 0x0},
+	{0x10020, 0x0},
+	{0x110020, 0x0},
+	{0x210020, 0x0},
+	{0x11020, 0x0},
+	{0x111020, 0x0},
+	{0x211020, 0x0},
+	{0x12020, 0x0},
+	{0x112020, 0x0},
+	{0x212020, 0x0},
+	{0x13020, 0x0},
+	{0x113020, 0x0},
+	{0x213020, 0x0},
+	{0x20072, 0x0},
+	{0x20073, 0x0},
+	{0x20074, 0x0},
+	{0x100aa, 0x0},
+	{0x110aa, 0x0},
+	{0x120aa, 0x0},
+	{0x130aa, 0x0},
+	{0x20010, 0x0},
+	{0x120010, 0x0},
+	{0x220010, 0x0},
+	{0x20011, 0x0},
+	{0x120011, 0x0},
+	{0x220011, 0x0},
+	{0x100ae, 0x0},
+	{0x1100ae, 0x0},
+	{0x2100ae, 0x0},
+	{0x100af, 0x0},
+	{0x1100af, 0x0},
+	{0x2100af, 0x0},
+	{0x110ae, 0x0},
+	{0x1110ae, 0x0},
+	{0x2110ae, 0x0},
+	{0x110af, 0x0},
+	{0x1110af, 0x0},
+	{0x2110af, 0x0},
+	{0x120ae, 0x0},
+	{0x1120ae, 0x0},
+	{0x2120ae, 0x0},
+	{0x120af, 0x0},
+	{0x1120af, 0x0},
+	{0x2120af, 0x0},
+	{0x130ae, 0x0},
+	{0x1130ae, 0x0},
+	{0x2130ae, 0x0},
+	{0x130af, 0x0},
+	{0x1130af, 0x0},
+	{0x2130af, 0x0},
+	{0x20020, 0x0},
+	{0x120020, 0x0},
+	{0x220020, 0x0},
+	{0x100a0, 0x0},
+	{0x100a1, 0x0},
+	{0x100a2, 0x0},
+	{0x100a3, 0x0},
+	{0x100a4, 0x0},
+	{0x100a5, 0x0},
+	{0x100a6, 0x0},
+	{0x100a7, 0x0},
+	{0x110a0, 0x0},
+	{0x110a1, 0x0},
+	{0x110a2, 0x0},
+	{0x110a3, 0x0},
+	{0x110a4, 0x0},
+	{0x110a5, 0x0},
+	{0x110a6, 0x0},
+	{0x110a7, 0x0},
+	{0x120a0, 0x0},
+	{0x120a1, 0x0},
+	{0x120a2, 0x0},
+	{0x120a3, 0x0},
+	{0x120a4, 0x0},
+	{0x120a5, 0x0},
+	{0x120a6, 0x0},
+	{0x120a7, 0x0},
+	{0x130a0, 0x0},
+	{0x130a1, 0x0},
+	{0x130a2, 0x0},
+	{0x130a3, 0x0},
+	{0x130a4, 0x0},
+	{0x130a5, 0x0},
+	{0x130a6, 0x0},
+	{0x130a7, 0x0},
+	{0x2007c, 0x0},
+	{0x12007c, 0x0},
+	{0x22007c, 0x0},
+	{0x2007d, 0x0},
+	{0x12007d, 0x0},
+	{0x22007d, 0x0},
+	{0x400fd, 0x0},
+	{0x400c0, 0x0},
+	{0x90201, 0x0},
+	{0x190201, 0x0},
+	{0x290201, 0x0},
+	{0x90202, 0x0},
+	{0x190202, 0x0},
+	{0x290202, 0x0},
+	{0x90203, 0x0},
+	{0x190203, 0x0},
+	{0x290203, 0x0},
+	{0x90204, 0x0},
+	{0x190204, 0x0},
+	{0x290204, 0x0},
+	{0x90205, 0x0},
+	{0x190205, 0x0},
+	{0x290205, 0x0},
+	{0x90206, 0x0},
+	{0x190206, 0x0},
+	{0x290206, 0x0},
+	{0x90207, 0x0},
+	{0x190207, 0x0},
+	{0x290207, 0x0},
+	{0x90208, 0x0},
+	{0x190208, 0x0},
+	{0x290208, 0x0},
+	{0x10062, 0x0},
+	{0x10162, 0x0},
+	{0x10262, 0x0},
+	{0x10362, 0x0},
+	{0x10462, 0x0},
+	{0x10562, 0x0},
+	{0x10662, 0x0},
+	{0x10762, 0x0},
+	{0x10862, 0x0},
+	{0x11062, 0x0},
+	{0x11162, 0x0},
+	{0x11262, 0x0},
+	{0x11362, 0x0},
+	{0x11462, 0x0},
+	{0x11562, 0x0},
+	{0x11662, 0x0},
+	{0x11762, 0x0},
+	{0x11862, 0x0},
+	{0x12062, 0x0},
+	{0x12162, 0x0},
+	{0x12262, 0x0},
+	{0x12362, 0x0},
+	{0x12462, 0x0},
+	{0x12562, 0x0},
+	{0x12662, 0x0},
+	{0x12762, 0x0},
+	{0x12862, 0x0},
+	{0x13062, 0x0},
+	{0x13162, 0x0},
+	{0x13262, 0x0},
+	{0x13362, 0x0},
+	{0x13462, 0x0},
+	{0x13562, 0x0},
+	{0x13662, 0x0},
+	{0x13762, 0x0},
+	{0x13862, 0x0},
+	{0x20077, 0x0},
+	{0x10001, 0x0},
+	{0x11001, 0x0},
+	{0x12001, 0x0},
+	{0x13001, 0x0},
+	{0x10040, 0x0},
+	{0x10140, 0x0},
+	{0x10240, 0x0},
+	{0x10340, 0x0},
+	{0x10440, 0x0},
+	{0x10540, 0x0},
+	{0x10640, 0x0},
+	{0x10740, 0x0},
+	{0x10840, 0x0},
+	{0x10030, 0x0},
+	{0x10130, 0x0},
+	{0x10230, 0x0},
+	{0x10330, 0x0},
+	{0x10430, 0x0},
+	{0x10530, 0x0},
+	{0x10630, 0x0},
+	{0x10730, 0x0},
+	{0x10830, 0x0},
+	{0x11040, 0x0},
+	{0x11140, 0x0},
+	{0x11240, 0x0},
+	{0x11340, 0x0},
+	{0x11440, 0x0},
+	{0x11540, 0x0},
+	{0x11640, 0x0},
+	{0x11740, 0x0},
+	{0x11840, 0x0},
+	{0x11030, 0x0},
+	{0x11130, 0x0},
+	{0x11230, 0x0},
+	{0x11330, 0x0},
+	{0x11430, 0x0},
+	{0x11530, 0x0},
+	{0x11630, 0x0},
+	{0x11730, 0x0},
+	{0x11830, 0x0},
+	{0x12040, 0x0},
+	{0x12140, 0x0},
+	{0x12240, 0x0},
+	{0x12340, 0x0},
+	{0x12440, 0x0},
+	{0x12540, 0x0},
+	{0x12640, 0x0},
+	{0x12740, 0x0},
+	{0x12840, 0x0},
+	{0x12030, 0x0},
+	{0x12130, 0x0},
+	{0x12230, 0x0},
+	{0x12330, 0x0},
+	{0x12430, 0x0},
+	{0x12530, 0x0},
+	{0x12630, 0x0},
+	{0x12730, 0x0},
+	{0x12830, 0x0},
+	{0x13040, 0x0},
+	{0x13140, 0x0},
+	{0x13240, 0x0},
+	{0x13340, 0x0},
+	{0x13440, 0x0},
+	{0x13540, 0x0},
+	{0x13640, 0x0},
+	{0x13740, 0x0},
+	{0x13840, 0x0},
+	{0x13030, 0x0},
+	{0x13130, 0x0},
+	{0x13230, 0x0},
+	{0x13330, 0x0},
+	{0x13430, 0x0},
+	{0x13530, 0x0},
+	{0x13630, 0x0},
+	{0x13730, 0x0},
+	{0x13830, 0x0},
 };
-
 /* P0 message block paremeter for training firmware */
 struct dram_cfg_param ddr_fsp0_cfg[] = {
 	{0xd0000, 0x0},
@@ -1054,7 +1055,6 @@
 	{0x54008, 0x131f},
 	{0x54009, 0xc8},
 	{0x5400b, 0x2},
-	{0x5400d, 0x100},
 	{0x54012, 0x110},
 	{0x54019, 0x2dd4},
 	{0x5401a, 0x31},
@@ -1094,7 +1094,6 @@
 	{0x54008, 0x121f},
 	{0x54009, 0xc8},
 	{0x5400b, 0x2},
-	{0x5400d, 0x100},
 	{0x54012, 0x110},
 	{0x54019, 0x84},
 	{0x5401a, 0x31},
@@ -1134,7 +1133,6 @@
 	{0x54008, 0x121f},
 	{0x54009, 0xc8},
 	{0x5400b, 0x2},
-	{0x5400d, 0x100},
 	{0x54012, 0x110},
 	{0x54019, 0x84},
 	{0x5401a, 0x31},
@@ -1200,7 +1198,7 @@
 	{0x5403b, 0x4d},
 	{0x5403c, 0x4d},
 	{0x5403d, 0x1600},
-	{ 0xd0000, 0x1 },
+	{0xd0000, 0x1},
 };
 
 /* DRAM PHY init engine image */
@@ -1693,15 +1691,15 @@
 	{0x400d6, 0x20a},
 	{0x400d7, 0x20b},
 	{0x2003a, 0x2},
-	{0x2000b, 0x5d},
+	{0x2000b, 0x34b},
 	{0x2000c, 0xbb},
 	{0x2000d, 0x753},
 	{0x2000e, 0x2c},
-	{0x12000b, 0xc},
+	{0x12000b, 0x70},
 	{0x12000c, 0x19},
 	{0x12000d, 0xfa},
 	{0x12000e, 0x10},
-	{0x22000b, 0x3},
+	{0x22000b, 0x1c},
 	{0x22000c, 0x6},
 	{0x22000d, 0x3e},
 	{0x22000e, 0x10},
@@ -1842,5 +1840,5 @@
 	.ddrphy_trained_csr_num = ARRAY_SIZE(ddr_ddrphy_trained_csr),
 	.ddrphy_pie = ddr_phy_pie,
 	.ddrphy_pie_num = ARRAY_SIZE(ddr_phy_pie),
-	.fsp_table = { 3000, 400, 100, },
+	.fsp_table = { 3000, 400, 100,},
 };
diff --git a/board/sandbox/sandbox.c b/board/sandbox/sandbox.c
index c7b6cb7..9d58860 100644
--- a/board/sandbox/sandbox.c
+++ b/board/sandbox/sandbox.c
@@ -11,16 +11,18 @@
 #include <efi.h>
 #include <efi_loader.h>
 #include <env_internal.h>
+#include <extension_board.h>
 #include <init.h>
 #include <led.h>
+#include <malloc.h>
+#include <mapmem.h>
 #include <os.h>
+#include <acpi/acpi_table.h>
 #include <asm/global_data.h>
 #include <asm/test.h>
 #include <asm/u-boot-sandbox.h>
 #include <linux/kernel.h>
-#include <malloc.h>
-
-#include <extension_board.h>
+#include <linux/sizes.h>
 
 /*
  * Pointer to initial global data area
@@ -154,6 +156,8 @@
 int board_late_init(void)
 {
 	struct udevice *dev;
+	ulong addr, end;
+	void *ptr;
 	int ret;
 
 	ret = uclass_first_device_err(UCLASS_CROS_EC, &dev);
@@ -166,6 +170,18 @@
 		panic("Cannot init cros-ec device");
 		return -1;
 	}
+
+	if (IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) {
+		/* Reserve 64K for ACPI tables, aligned to a 4K boundary */
+		ptr = memalign(SZ_4K, SZ_64K);
+		addr = map_to_sysmem(ptr);
+
+		/* Generate ACPI tables */
+		end = write_acpi_tables(addr);
+		gd->arch.table_start = addr;
+		gd->arch.table_end = addr;
+	}
+
 	return 0;
 }
 #endif
diff --git a/board/siemens/capricorn/board.c b/board/siemens/capricorn/board.c
index a0c62e0..924c88e 100644
--- a/board/siemens/capricorn/board.c
+++ b/board/siemens/capricorn/board.c
@@ -147,7 +147,7 @@
 int setup_gpr_fec(void)
 {
 	sc_ipc_t ipc_handle = -1;
-	sc_err_t err = 0;
+	int err = 0;
 	unsigned int test;
 
 	/*
@@ -175,35 +175,35 @@
 	 */
 
 	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, 1);
-	if (err != SC_ERR_NONE)
+	if (err)
 		printf("Error in setting up SC_C %d\n\r", SC_C_TXCLK);
 
 	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
 	debug("TEST SC_C %d-->%d\n\r", SC_C_TXCLK, test);
 
 	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_CLKDIV, 0);
-	if (err != SC_ERR_NONE)
+	if (err)
 		printf("Error in setting up SC_C %d\n\r", SC_C_CLKDIV);
 
 	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_CLKDIV, &test);
 	debug("TEST SC_C %d-->%d\n\r", SC_C_CLKDIV, test);
 
 	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_DISABLE_50, 0);
-	if (err != SC_ERR_NONE)
+	if (err)
 		printf("Error in setting up SC_C %d\n\r", SC_C_DISABLE_50);
 
 	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
 	debug("TEST SC_C %d-->%d\n\r", SC_C_DISABLE_50, test);
 
 	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_DISABLE_125, 1);
-	if (err != SC_ERR_NONE)
+	if (err)
 		printf("Error in setting up SC_C %d\n\r", SC_C_DISABLE_125);
 
 	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_TXCLK, &test);
 	debug("TEST SC_C %d-->%d\n\r", SC_C_DISABLE_125, test);
 
 	err = sc_misc_set_control(ipc_handle, SC_R_ENET_1, SC_C_SEL_125, 1);
-	if (err != SC_ERR_NONE)
+	if (err)
 		printf("Error in setting up SC_C %d\n\r", SC_C_SEL_125);
 
 	sc_misc_get_control(ipc_handle, SC_R_ENET_1, SC_C_SEL_125, &test);
diff --git a/board/technexion/pico-imx8mq/pico-imx8mq.c b/board/technexion/pico-imx8mq/pico-imx8mq.c
index 951e3e1..2be3206 100644
--- a/board/technexion/pico-imx8mq/pico-imx8mq.c
+++ b/board/technexion/pico-imx8mq/pico-imx8mq.c
@@ -54,7 +54,7 @@
 
 int board_phys_sdram_size(phys_size_t *size)
 {
-	int ddr_size = readl(M4_BOOTROM_BASE_ADDR);
+	int ddr_size = readl(MCU_BOOTROM_BASE_ADDR);
 
 	if (ddr_size == 0x4) {
 		*size = 0x100000000;
diff --git a/board/technexion/pico-imx8mq/spl.c b/board/technexion/pico-imx8mq/spl.c
index 8b853a9..2afb4d3 100644
--- a/board/technexion/pico-imx8mq/spl.c
+++ b/board/technexion/pico-imx8mq/spl.c
@@ -89,7 +89,7 @@
 
 	printf("%s: LPDDR4 %d GiB\n", __func__, size);
 	ddr_init(dram_timing);
-	writel(size, M4_BOOTROM_BASE_ADDR);
+	writel(size, MCU_BOOTROM_BASE_ADDR);
 }
 
 #define USDHC2_CD_GPIO	IMX_GPIO_NR(2, 12)
diff --git a/board/thecus/n2350/n2350.c b/board/thecus/n2350/n2350.c
index fd8f95f..05b125f 100644
--- a/board/thecus/n2350/n2350.c
+++ b/board/thecus/n2350/n2350.c
@@ -25,7 +25,7 @@
 #define N2350_GPP_OUT_ENA_LOW	(~(BIT(20) | BIT(21) | BIT(24)))
 #define N2350_GPP_OUT_ENA_MID	(~(BIT(12) | BIT(13) | BIT(16) | BIT(19) | BIT(22)))
 #define N2350_GPP_OUT_VAL_LOW	(BIT(21) | BIT(24))
-#define N2350_GPP_OUT_VAL_MID	(BIT(0) | BIT(12) | BIT(13))
+#define N2350_GPP_OUT_VAL_MID	(BIT(0) | BIT(12) | BIT(13) | BIT(16))
 #define N2350_GPP_POL_LOW	0x0
 #define N2350_GPP_POL_MID	0x0
 
diff --git a/board/toradex/apalis-imx8/apalis-imx8.c b/board/toradex/apalis-imx8/apalis-imx8.c
index aa76c48..e2bbaba 100644
--- a/board/toradex/apalis-imx8/apalis-imx8.c
+++ b/board/toradex/apalis-imx8/apalis-imx8.c
@@ -85,18 +85,18 @@
 
 static uint32_t do_get_tdx_user_fuse(int a, int b)
 {
-	sc_err_t sciErr;
+	int sciErr;
 	u32 val_a = 0;
 	u32 val_b = 0;
 
 	sciErr = sc_misc_otp_fuse_read(-1, a, &val_a);
-	if (sciErr != SC_ERR_NONE) {
+	if (sciErr) {
 		printf("Error reading out user fuse %d\n", a);
 		return 0;
 	}
 
 	sciErr = sc_misc_otp_fuse_read(-1, b, &val_b);
-	if (sciErr != SC_ERR_NONE) {
+	if (sciErr) {
 		printf("Error reading out user fuse %d\n", b);
 		return 0;
 	}
@@ -131,9 +131,9 @@
 {
 	u32 is_quadplus = 0, val = 0;
 	struct tdx_user_fuses tdxramfuses;
-	sc_err_t scierr = sc_misc_otp_fuse_read(-1, 6, &val);
+	int scierr = sc_misc_otp_fuse_read(-1, 6, &val);
 
-	if (scierr == SC_ERR_NONE) {
+	if (scierr) {
 		/* QP has one A72 core disabled */
 		is_quadplus = ((val >> 4) & 0x3) != 0x0;
 	}
diff --git a/board/toradex/colibri-imx8x/colibri-imx8x.c b/board/toradex/colibri-imx8x/colibri-imx8x.c
index 52fc7a3..6c0b097 100644
--- a/board/toradex/colibri-imx8x/colibri-imx8x.c
+++ b/board/toradex/colibri-imx8x/colibri-imx8x.c
@@ -12,6 +12,7 @@
 #include <asm/arch/imx8-pins.h>
 #include <asm/arch/iomux.h>
 #include <firmware/imx/sci/sci.h>
+#include <asm/arch/snvs_security_sc.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
@@ -43,9 +44,9 @@
 static int is_imx8dx(void)
 {
 	u32 val = 0;
-	sc_err_t sc_err = sc_misc_otp_fuse_read(-1, 6, &val);
+	int sc_err = sc_misc_otp_fuse_read(-1, 6, &val);
 
-	if (sc_err == SC_ERR_NONE) {
+	if (sc_err) {
 		/* DX has two A35 cores disabled */
 		return (val & 0xf) != 0x0;
 	}
@@ -70,7 +71,7 @@
 int board_early_init_f(void)
 {
 	sc_pm_clock_rate_t rate;
-	sc_err_t err = 0;
+	int err;
 
 	/*
 	 * This works around that having only UART3 up the baudrate is 1.2M
@@ -78,13 +79,13 @@
 	 */
 	rate = 80000000;
 	err = sc_pm_set_clock_rate(-1, SC_R_UART_0, SC_PM_CLK_PER, &rate);
-	if (err != SC_ERR_NONE)
+	if (err)
 		return 0;
 
 	/* Set UART3 clock root to 80 MHz and enable it */
 	rate = SC_80MHZ;
 	err = sc_pm_setup_uart(SC_R_UART_3, rate);
-	if (err != SC_ERR_NONE)
+	if (err)
 		return 0;
 
 	setup_iomux_uart();
@@ -139,6 +140,13 @@
 {
 	board_gpio_init();
 
+	if (IS_ENABLED(CONFIG_IMX_SNVS_SEC_SC_AUTO)) {
+		int ret = snvs_security_sc_init();
+
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
@@ -170,6 +178,8 @@
 	env_set("board_rev", "v1.0");
 #endif
 
+	build_info();
+
 	select_dt_from_module_version();
 
 	return 0;
diff --git a/board/toradex/colibri_imx6/colibri_imx6.c b/board/toradex/colibri_imx6/colibri_imx6.c
index 65e0e9a..677caa4 100644
--- a/board/toradex/colibri_imx6/colibri_imx6.c
+++ b/board/toradex/colibri_imx6/colibri_imx6.c
@@ -767,8 +767,7 @@
 /*
  * MDMISC	mirroring	interleaved (row/bank/col)
  */
-/* TODO: check what the RALAT field does */
-MX6_MMDC_P0_MDMISC, 0x00081740,
+MX6_MMDC_P0_MDMISC, 0x000b17c0,
 
 /*
  * MDSCR	con_req
@@ -900,8 +899,7 @@
 /*
  * MDMISC	mirroring	interleaved (row/bank/col)
  */
-/* TODO: check what the RALAT field does */
-MX6_MMDC_P0_MDMISC, 0x00081740,
+MX6_MMDC_P0_MDMISC, 0x000b17c0,
 
 /*
  * MDSCR	con_req
diff --git a/board/toradex/common/tdx-cfg-block.c b/board/toradex/common/tdx-cfg-block.c
index 11f4d5e..e513f4a 100644
--- a/board/toradex/common/tdx-cfg-block.c
+++ b/board/toradex/common/tdx-cfg-block.c
@@ -139,6 +139,7 @@
 	[66] = { "Verdin iMX8M Plus Quad 8GB WB",        TARGET_IS_ENABLED(VERDIN_IMX8MP)   },
 	[67] = { "Apalis iMX8QM 8GB WB IT",              TARGET_IS_ENABLED(APALIS_IMX8)     },
 	[68] = { "Verdin iMX8M Mini Quad 2GB WB IT",     TARGET_IS_ENABLED(VERDIN_IMX8MM)   },
+	[70] = { "Verdin iMX8M Plus Quad 8GB WB IT",     TARGET_IS_ENABLED(VERDIN_IMX8MP)   },
 };
 
 const char * const toradex_carrier_boards[] = {
diff --git a/board/toradex/common/tdx-cfg-block.h b/board/toradex/common/tdx-cfg-block.h
index 32e4c6f..45fa04c 100644
--- a/board/toradex/common/tdx-cfg-block.h
+++ b/board/toradex/common/tdx-cfg-block.h
@@ -94,6 +94,8 @@
 	VERDIN_IMX8MPQ_8GB_WIFI_BT,
 	APALIS_IMX8QM_8GB_WIFI_BT_IT,
 	VERDIN_IMX8MMQ_WIFI_BT_IT_NO_CAN,
+	/* 69 */
+	VERDIN_IMX8MPQ_8GB_WIFI_BT_IT = 70, /* 70 */
 };
 
 enum {
diff --git a/board/toradex/verdin-imx8mm/MAINTAINERS b/board/toradex/verdin-imx8mm/MAINTAINERS
index 974b3a1..b0f4329 100644
--- a/board/toradex/verdin-imx8mm/MAINTAINERS
+++ b/board/toradex/verdin-imx8mm/MAINTAINERS
@@ -3,7 +3,6 @@
 W:	https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-mini
 S:	Maintained
 F:	arch/arm/dts/imx8mm-verdin.dtsi
-F:	arch/arm/dts/imx8mm-verdin-dahlia.dtsi
 F:	arch/arm/dts/imx8mm-verdin-dev.dtsi
 F:	arch/arm/dts/imx8mm-verdin-wifi.dtsi
 F:	arch/arm/dts/imx8mm-verdin-wifi-dev.dts
diff --git a/board/toradex/verdin-imx8mp/MAINTAINERS b/board/toradex/verdin-imx8mp/MAINTAINERS
index cff3c50..ea04a83 100644
--- a/board/toradex/verdin-imx8mp/MAINTAINERS
+++ b/board/toradex/verdin-imx8mp/MAINTAINERS
@@ -1,6 +1,5 @@
 Verdin iMX8M Plus
 F:	arch/arm/dts/imx8mp-verdin.dtsi
-F:	arch/arm/dts/imx8mp-verdin-dahlia.dtsi
 F:	arch/arm/dts/imx8mp-verdin-dev.dtsi
 F:	arch/arm/dts/imx8mp-verdin-wifi.dtsi
 F:	arch/arm/dts/imx8mp-verdin-wifi-dev.dts
diff --git a/board/toradex/verdin-imx8mp/verdin-imx8mp.c b/board/toradex/verdin-imx8mp/verdin-imx8mp.c
index 5490d3e..e16a771 100644
--- a/board/toradex/verdin-imx8mp/verdin-imx8mp.c
+++ b/board/toradex/verdin-imx8mp/verdin-imx8mp.c
@@ -81,7 +81,8 @@
 		 */
 		is_wifi = (tdx_hw_tag.prodid == VERDIN_IMX8MPQ_WIFI_BT_IT) ||
 			  (tdx_hw_tag.prodid == VERDIN_IMX8MPQ_2GB_WIFI_BT_IT) ||
-			  (tdx_hw_tag.prodid == VERDIN_IMX8MPQ_8GB_WIFI_BT);
+			  (tdx_hw_tag.prodid == VERDIN_IMX8MPQ_8GB_WIFI_BT) ||
+			  (tdx_hw_tag.prodid == VERDIN_IMX8MPQ_8GB_WIFI_BT_IT);
 	}
 
 	if (is_wifi)
diff --git a/board/variscite/imx8mn_var_som/imx8mn_var_som.c b/board/variscite/imx8mn_var_som/imx8mn_var_som.c
index d40f4d0..61b9455 100644
--- a/board/variscite/imx8mn_var_som/imx8mn_var_som.c
+++ b/board/variscite/imx8mn_var_som/imx8mn_var_som.c
@@ -1,11 +1,50 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright 2021 Collabora Ltd.
+ * Copyright 2018-2020 Variscite Ltd.
+ * Copyright 2023 DimOnOff Inc.
  */
 
 #include <common.h>
+#include <dm.h>
 #include <env.h>
+#include <fdtdec.h>
+#include <fdt_support.h>
+#include <i2c_eeprom.h>
+#include <malloc.h>
 #include <asm/io.h>
+#include <asm/global_data.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <linux/libfdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Optional SOM features flags. */
+#define VAR_EEPROM_F_WIFI		BIT(0)
+#define VAR_EEPROM_F_ETH		BIT(1) /* Ethernet PHY on SOM. */
+#define VAR_EEPROM_F_AUDIO		BIT(2)
+#define VAR_EEPROM_F_MX8M_LVDS		BIT(3) /* i.MX8MM, i.MX8MN, i.MX8MQ only */
+#define VAR_EEPROM_F_MX8Q_SOC_ID	BIT(3) /* 0 = i.MX8QM, 1 = i.MX8QP */
+#define VAR_EEPROM_F_NAND		BIT(4)
+
+#define VAR_IMX8_EEPROM_MAGIC	0x384D /* "8M" */
+
+/* Number of DRAM adjustment tables. */
+#define DRAM_TABLES_NUM 7
+
+struct var_imx8_eeprom_info {
+	u16 magic;
+	u8 partnumber[3];         /* Part number */
+	u8 assembly[10];          /* Assembly number */
+	u8 date[9];               /* Build date */
+	u8 mac[6];                /* MAC address */
+	u8 somrev;
+	u8 eeprom_version;
+	u8 features;              /* SOM features */
+	u8 dramsize;              /* DRAM size */
+	u8 off[DRAM_TABLES_NUM + 1]; /* DRAM table offsets */
+	u8 partnumber2[5];        /* Part number 2 */
+} __packed;
 
 static void setup_fec(void)
 {
@@ -28,3 +67,178 @@
 {
 	return devno;
 }
+
+#if !defined(CONFIG_SPL_BUILD)
+
+#if defined(CONFIG_DISPLAY_BOARDINFO)
+
+static void display_som_infos(struct var_imx8_eeprom_info *info)
+{
+	char partnumber[sizeof(info->partnumber) +
+			sizeof(info->partnumber2) + 1];
+	char assembly[sizeof(info->assembly) + 1];
+	char date[sizeof(info->date) + 1];
+
+	/* Read first part of P/N. */
+	memcpy(partnumber, info->partnumber, sizeof(info->partnumber));
+
+	/* Read second part of P/N. */
+	if (info->eeprom_version >= 3)
+		memcpy(partnumber + sizeof(info->partnumber), info->partnumber2,
+		       sizeof(info->partnumber2));
+
+	memcpy(assembly, info->assembly, sizeof(info->assembly));
+	memcpy(date, info->date, sizeof(info->date));
+
+	/* Make sure strings are null terminated. */
+	partnumber[sizeof(partnumber) - 1] = '\0';
+	assembly[sizeof(assembly) - 1] = '\0';
+	date[sizeof(date) - 1] = '\0';
+
+	printf("SOM board: P/N: %s, Assy: %s, Date: %s\n"
+	       "           Wifi: %s, EthPhy: %s, Rev: %d\n",
+	       partnumber, assembly, date,
+	       info->features & VAR_EEPROM_F_WIFI ? "yes" : "no",
+	       info->features & VAR_EEPROM_F_ETH ? "yes" : "no",
+	       info->somrev);
+}
+
+static int var_read_som_eeprom(struct var_imx8_eeprom_info *info)
+{
+	const char *path = "eeprom-som";
+	struct udevice *dev;
+	int ret, off;
+
+	off = fdt_path_offset(gd->fdt_blob, path);
+	if (off < 0) {
+		pr_err("%s: fdt_path_offset() failed: %d\n", __func__, off);
+		return off;
+	}
+
+	ret = uclass_get_device_by_of_offset(UCLASS_I2C_EEPROM, off, &dev);
+	if (ret) {
+		pr_err("%s: uclass_get_device_by_of_offset() failed: %d\n",
+		       __func__, ret);
+		return ret;
+	}
+
+	ret = i2c_eeprom_read(dev, 0, (uint8_t *)info,
+			      sizeof(struct var_imx8_eeprom_info));
+	if (ret) {
+		pr_err("%s: i2c_eeprom_read() failed: %d\n", __func__, ret);
+		return ret;
+	}
+
+	if (htons(info->magic) != VAR_IMX8_EEPROM_MAGIC) {
+		/* Do not fail if the content is invalid */
+		pr_err("Board: Invalid board info magic: 0x%08x, expected 0x%08x\n",
+		       htons(info->magic), VAR_IMX8_EEPROM_MAGIC);
+	}
+
+	return 0;
+}
+
+int checkboard(void)
+{
+	int rc;
+	struct var_imx8_eeprom_info *info;
+
+	info = malloc(sizeof(struct var_imx8_eeprom_info));
+	if (!info)
+		return -ENOMEM;
+
+	rc = var_read_som_eeprom(info);
+	if (rc)
+		return rc;
+
+	display_som_infos(info);
+
+#if defined(CONFIG_BOARD_TYPES)
+	gd->board_type = info->features;
+#endif /* CONFIG_BOARD_TYPES */
+
+	return 0;
+}
+
+#endif /* CONFIG_DISPLAY_BOARDINFO */
+
+static int insert_gpios_prop(void *blob, int node, const char *prop,
+			     unsigned int phandle, u32 gpio, u32 flags)
+{
+	fdt32_t val[3] = { cpu_to_fdt32(phandle), cpu_to_fdt32(gpio),
+			   cpu_to_fdt32(flags) };
+	return fdt_setprop(blob, node, prop, &val, sizeof(val));
+}
+
+static int configure_phy_reset_gpios(void *blob)
+{
+	int node;
+	int phynode;
+	int ret;
+	u32 handle;
+	u32 gpio;
+	u32 flags;
+	char path[1024];
+	const char *eth_alias = "ethernet0";
+
+	snprintf(path, sizeof(path), "%s/mdio/ethernet-phy@4",
+		 fdt_get_alias(blob, eth_alias));
+
+	phynode = fdt_path_offset(blob, path);
+	if (phynode < 0) {
+		pr_err("%s(): unable to locate PHY node: %s\n", __func__, path);
+		return 0;
+	}
+
+	if (gd_board_type() & VAR_EEPROM_F_ETH) {
+		snprintf(path, sizeof(path), "%s",
+			 fdt_get_alias(blob, "gpio0")); /* Alias to gpio1 */
+		gpio = 9;
+		flags = GPIO_ACTIVE_LOW;
+	} else {
+		snprintf(path, sizeof(path), "%s/gpio@20",
+			 fdt_get_alias(blob, "i2c1")); /* Alias to i2c2 */
+		gpio = 5;
+		flags = GPIO_ACTIVE_HIGH;
+	}
+
+	node = fdt_path_offset(blob, path);
+	if (node < 0) {
+		pr_err("%s(): unable to locate GPIO node: %s\n", __func__,
+		       path);
+		return 0;
+	}
+
+	handle = fdt_get_phandle(blob, node);
+	if (handle < 0) {
+		pr_err("%s(): unable to locate GPIO controller handle: %s\n",
+		       __func__, path);
+	}
+
+	ret = insert_gpios_prop(blob, phynode, "reset-gpios",
+				handle, gpio, flags);
+	if (ret < 0) {
+		pr_err("%s(): failed to set reset-gpios property\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_OF_BOARD_FIXUP)
+int board_fix_fdt(void *blob)
+{
+	/* Fix U-Boot device tree: */
+	return configure_phy_reset_gpios(blob);
+}
+#endif /* CONFIG_OF_BOARD_FIXUP */
+
+#if defined(CONFIG_OF_BOARD_SETUP)
+int ft_board_setup(void *blob, struct bd_info *bd)
+{
+	/* Fix kernel device tree: */
+	return configure_phy_reset_gpios(blob);
+}
+#endif /* CONFIG_OF_BOARD_SETUP */
+
+#endif /* CONFIG_SPL_BUILD */
diff --git a/boot/Kconfig b/boot/Kconfig
index a643a3d..b424265 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -463,6 +463,17 @@
 	  EFI bootmgr, since they take full control over which bootdevs are
 	  selected to boot.
 
+config BOOTMETH_CROS
+	bool "Bootdev support for Chromium OS"
+	depends on X86 || SANDBOX
+	default y
+	help
+	  Enables support for booting Chromium OS using bootdevs. This uses the
+	  kernel A slot and obtains the kernel command line from the parameters
+	  provided there.
+
+	  Note that only x86 devices are supported at present.
+
 config BOOTMETH_EXTLINUX
 	bool "Bootdev support for extlinux boot"
 	select PXE_UTILS
@@ -1630,4 +1641,18 @@
 	  If no initramfs was provided by previous bootloader, no env variables
 	  will be created.
 
+menu "Configuration editor"
+
+config CEDIT
+	bool "Configuration editor"
+	depends on BOOTSTD
+	help
+	  Provides a way to deal with board configuration and present it to
+	  the user for adjustment.
+
+	  This is intended to provide both graphical and text-based user
+	  interfaces, but only graphical is support at present.
+
+endmenu		# Configuration editor
+
 endmenu		# Booting
diff --git a/boot/Makefile b/boot/Makefile
index f94c31d..10f0157 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -27,12 +27,14 @@
 obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_EXTLINUX) += bootmeth_extlinux.o
 obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_EXTLINUX_PXE) += bootmeth_pxe.o
 obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_EFILOADER) += bootmeth_efi.o
+obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_CROS) += bootmeth_cros.o
 obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_SANDBOX) += bootmeth_sandbox.o
 obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_SCRIPT) += bootmeth_script.o
 ifdef CONFIG_$(SPL_TPL_)BOOTSTD_FULL
 obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += bootmeth_efi_mgr.o
 obj-$(CONFIG_$(SPL_TPL_)EXPO) += bootflow_menu.o
 obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootflow_menu.o
+obj-$(CONFIG_$(SPL_TPL_)CEDIT) += cedit.o
 endif
 
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
@@ -50,7 +52,7 @@
 obj-$(CONFIG_SPL_LOAD_FIT) += common_fit.o
 endif
 
-obj-$(CONFIG_$(SPL_TPL_)EXPO) += expo.o scene.o scene_menu.o
+obj-$(CONFIG_$(SPL_TPL_)EXPO) += expo.o scene.o scene_menu.o expo_build.o
 
 obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE) += vbe.o
 obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE_REQUEST) += vbe_request.o
diff --git a/boot/android_ab.c b/boot/android_ab.c
index 2d7b392..73b55c1 100644
--- a/boot/android_ab.c
+++ b/boot/android_ab.c
@@ -85,11 +85,13 @@
  */
 static int ab_control_create_from_disk(struct blk_desc *dev_desc,
 				       const struct disk_partition *part_info,
-				       struct bootloader_control **abc)
+				       struct bootloader_control **abc,
+				       ulong offset)
 {
 	ulong abc_offset, abc_blocks, ret;
 
-	abc_offset = offsetof(struct bootloader_message_ab, slot_suffix);
+	abc_offset = offset +
+		     offsetof(struct bootloader_message_ab, slot_suffix);
 	if (abc_offset % part_info->blksz) {
 		log_err("ANDROID: Boot control block not block aligned.\n");
 		return -EINVAL;
@@ -135,11 +137,12 @@
  */
 static int ab_control_store(struct blk_desc *dev_desc,
 			    const struct disk_partition *part_info,
-			    struct bootloader_control *abc)
+			    struct bootloader_control *abc, ulong offset)
 {
 	ulong abc_offset, abc_blocks, ret;
 
-	abc_offset = offsetof(struct bootloader_message_ab, slot_suffix) /
+	abc_offset = offset +
+		     offsetof(struct bootloader_message_ab, slot_suffix) /
 		     part_info->blksz;
 	abc_blocks = DIV_ROUND_UP(sizeof(struct bootloader_control),
 				  part_info->blksz);
@@ -181,15 +184,19 @@
 	return 0;
 }
 
-int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info)
+int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info,
+		   bool dec_tries)
 {
 	struct bootloader_control *abc = NULL;
 	u32 crc32_le;
 	int slot, i, ret;
 	bool store_needed = false;
 	char slot_suffix[4];
+#if ANDROID_AB_BACKUP_OFFSET
+	struct bootloader_control *backup_abc = NULL;
+#endif
 
-	ret = ab_control_create_from_disk(dev_desc, part_info, &abc);
+	ret = ab_control_create_from_disk(dev_desc, part_info, &abc, 0);
 	if (ret < 0) {
 		/*
 		 * This condition represents an actual problem with the code or
@@ -199,22 +206,53 @@
 		return ret;
 	}
 
+#if ANDROID_AB_BACKUP_OFFSET
+	ret = ab_control_create_from_disk(dev_desc, part_info, &backup_abc,
+					  ANDROID_AB_BACKUP_OFFSET);
+	if (ret < 0) {
+		free(abc);
+		return ret;
+	}
+#endif
+
 	crc32_le = ab_control_compute_crc(abc);
 	if (abc->crc32_le != crc32_le) {
 		log_err("ANDROID: Invalid CRC-32 (expected %.8x, found %.8x),",
 			crc32_le, abc->crc32_le);
-		log_err("re-initializing A/B metadata.\n");
+#if ANDROID_AB_BACKUP_OFFSET
+		crc32_le = ab_control_compute_crc(backup_abc);
+		if (backup_abc->crc32_le != crc32_le) {
+			log_err("ANDROID: Invalid backup CRC-32 ")
+			log_err("expected %.8x, found %.8x),",
+				crc32_le, backup_abc->crc32_le);
+#endif
 
-		ret = ab_control_default(abc);
-		if (ret < 0) {
-			free(abc);
-			return -ENODATA;
+			log_err("re-initializing A/B metadata.\n");
+
+			ret = ab_control_default(abc);
+			if (ret < 0) {
+#if ANDROID_AB_BACKUP_OFFSET
+				free(backup_abc);
+#endif
+				free(abc);
+				return -ENODATA;
+			}
+#if ANDROID_AB_BACKUP_OFFSET
+		} else {
+			/*
+			 * Backup is valid. Copy it to the primary
+			 */
+			memcpy(abc, backup_abc, sizeof(*abc));
 		}
+#endif
 		store_needed = true;
 	}
 
 	if (abc->magic != BOOT_CTRL_MAGIC) {
 		log_err("ANDROID: Unknown A/B metadata: %.8x\n", abc->magic);
+#if ANDROID_AB_BACKUP_OFFSET
+		free(backup_abc);
+#endif
 		free(abc);
 		return -ENODATA;
 	}
@@ -222,6 +260,9 @@
 	if (abc->version > BOOT_CTRL_VERSION) {
 		log_err("ANDROID: Unsupported A/B metadata version: %.8x\n",
 			abc->version);
+#if ANDROID_AB_BACKUP_OFFSET
+		free(backup_abc);
+#endif
 		free(abc);
 		return -ENODATA;
 	}
@@ -272,8 +313,10 @@
 		log_err("ANDROID: Attempting slot %c, tries remaining %d\n",
 			BOOT_SLOT_NAME(slot),
 			abc->slot_info[slot].tries_remaining);
-		abc->slot_info[slot].tries_remaining--;
-		store_needed = true;
+		if (dec_tries) {
+			abc->slot_info[slot].tries_remaining--;
+			store_needed = true;
+		}
 	}
 
 	if (slot >= 0) {
@@ -294,8 +337,21 @@
 
 	if (store_needed) {
 		abc->crc32_le = ab_control_compute_crc(abc);
-		ab_control_store(dev_desc, part_info, abc);
+		ab_control_store(dev_desc, part_info, abc, 0);
 	}
+
+#if ANDROID_AB_BACKUP_OFFSET
+	/*
+	 * If the backup doesn't match the primary, write the primary
+	 * to the backup offset
+	 */
+	if (memcmp(backup_abc, abc, sizeof(*abc)) != 0) {
+		ab_control_store(dev_desc, part_info, abc,
+				 ANDROID_AB_BACKUP_OFFSET);
+	}
+	free(backup_abc);
+#endif
+
 	free(abc);
 
 	if (slot < 0)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 8f2cb87..81b5829 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -12,7 +12,9 @@
 #include <bootmeth.h>
 #include <bootstd.h>
 #include <dm.h>
+#include <env_internal.h>
 #include <malloc.h>
+#include <serial.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
 
@@ -315,14 +317,14 @@
 
 	/* If we got a valid bootflow, return it */
 	if (!ret) {
-		log_debug("Bootdevice '%s' part %d method '%s': Found bootflow\n",
+		log_debug("Bootdev '%s' part %d method '%s': Found bootflow\n",
 			  dev->name, iter->part, iter->method->name);
 		return 0;
 	}
 
 	/* Unless there is nothing more to try, move to the next device */
 	else if (ret != BF_NO_MORE_PARTS && ret != -ENOSYS) {
-		log_debug("Bootdevice '%s' part %d method '%s': Error %d\n",
+		log_debug("Bootdev '%s' part %d method '%s': Error %d\n",
 			  dev->name, iter->part, iter->method->name, ret);
 		/*
 		 * For 'all' we return all bootflows, even
@@ -552,3 +554,336 @@
 
 	return -ENOTSUPP;
 }
+
+/**
+ * bootflow_cmdline_set() - Set the command line for a bootflow
+ *
+ * @value: New command-line string
+ * Returns 0 if OK, -ENOENT if no current bootflow, -ENOMEM if out of memory
+ */
+int bootflow_cmdline_set(struct bootflow *bflow, const char *value)
+{
+	char *cmdline = NULL;
+
+	if (value) {
+		cmdline = strdup(value);
+		if (!cmdline)
+			return -ENOMEM;
+	}
+
+	free(bflow->cmdline);
+	bflow->cmdline = cmdline;
+
+	return 0;
+}
+
+#ifdef CONFIG_BOOTSTD_FULL
+/**
+ * on_bootargs() - Update the cmdline of a bootflow
+ */
+static int on_bootargs(const char *name, const char *value, enum env_op op,
+		       int flags)
+{
+	struct bootstd_priv *std;
+	struct bootflow *bflow;
+	int ret;
+
+	ret = bootstd_get_priv(&std);
+	if (ret)
+		return 0;
+	bflow = std->cur_bootflow;
+	if (!bflow)
+		return 0;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		ret = bootflow_cmdline_set(bflow, value);
+		if (ret && ret != ENOENT)
+			return 1;
+		return 0;
+	case env_op_delete:
+		bootflow_cmdline_set(bflow, NULL);
+		fallthrough;
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(bootargs, on_bootargs);
+#endif
+
+/**
+ * copy_in() - Copy a string into a cmdline buffer
+ *
+ * @buf: Buffer to copy into
+ * @end: End of buffer (pointer to char after the end)
+ * @arg: String to copy from
+ * @len: Number of chars to copy from @arg (note that this is not usually the
+ * sane as strlen(arg) since the string may contain following arguments)
+ * @new_val: Value to put after arg, or BOOTFLOWCL_EMPTY to use an empty value
+ * with no '=' sign
+ * Returns: Number of chars written to @buf
+ */
+static int copy_in(char *buf, char *end, const char *arg, int len,
+		   const char *new_val)
+{
+	char *to = buf;
+
+	/* copy the arg name */
+	if (to + len >= end)
+		return -E2BIG;
+	memcpy(to, arg, len);
+	to += len;
+
+	if (new_val == BOOTFLOWCL_EMPTY) {
+		/* no value */
+	} else {
+		bool need_quote = strchr(new_val, ' ');
+		len = strlen(new_val);
+
+		/* need space for value, equals sign and maybe two quotes */
+		if (to + 1 + (need_quote ? 2 : 0) + len >= end)
+			return -E2BIG;
+		*to++ = '=';
+		if (need_quote)
+			*to++ = '"';
+		memcpy(to, new_val, len);
+		to += len;
+		if (need_quote)
+			*to++ = '"';
+	}
+
+	return to - buf;
+}
+
+int cmdline_set_arg(char *buf, int maxlen, const char *cmdline,
+		    const char *set_arg, const char *new_val, int *posp)
+{
+	bool found_arg = false;
+	const char *from;
+	char *to, *end;
+	int set_arg_len;
+	char empty = '\0';
+	int ret;
+
+	from = cmdline ?: &empty;
+
+	/* check if the value has quotes inside */
+	if (new_val && new_val != BOOTFLOWCL_EMPTY && strchr(new_val, '"'))
+		return -EBADF;
+
+	set_arg_len = strlen(set_arg);
+	for (to = buf, end = buf + maxlen; *from;) {
+		const char *val, *arg_end, *val_end, *p;
+		bool in_quote;
+
+		if (to >= end)
+			return -E2BIG;
+		while (*from == ' ')
+			from++;
+		if (!*from)
+			break;
+
+		/* find the end of this arg */
+		val = NULL;
+		arg_end = NULL;
+		val_end = NULL;
+		in_quote = false;
+		for (p = from;; p++) {
+			if (in_quote) {
+				if (!*p)
+					return -EINVAL;
+				if (*p == '"')
+					in_quote = false;
+				continue;
+			}
+			if (*p == '=') {
+				arg_end = p;
+				val = p + 1;
+			} else if (*p == '"') {
+				in_quote = true;
+			} else if (!*p || *p == ' ') {
+				val_end = p;
+				if (!arg_end)
+					arg_end = p;
+				break;
+			}
+		}
+		/*
+		 * At this point val_end points to the end of the value, or the
+		 * last char after the arg name, if there is no label.
+		 * arg_end is the char after the arg name
+		 * val points to the value, or NULL if there is none
+		 * char after the value.
+		 *
+		 *        fred=1234
+		 *        ^   ^^   ^
+		 *      from  ||   |
+		 *           / \    \
+		 *    arg_end  val   val_end
+		 */
+		log_debug("from %s arg_end %ld val %ld val_end %ld\n", from,
+			  (long)(arg_end - from), (long)(val - from),
+			  (long)(val_end - from));
+
+		if (to != buf) {
+			if (to >= end)
+				return -E2BIG;
+			*to++ = ' ';
+		}
+
+		/* if this is the target arg, update it */
+		if (!strncmp(from, set_arg, arg_end - from)) {
+			if (!buf) {
+				bool has_quote = val_end[-1] == '"';
+
+				/*
+				 * exclude any start/end quotes from
+				 * calculations
+				 */
+				if (!val)
+					val = val_end;
+				*posp = val - cmdline + has_quote;
+				return val_end - val - 2 * has_quote;
+			}
+			found_arg = true;
+			if (!new_val) {
+				/* delete this arg */
+				from = val_end + (*val_end == ' ');
+				log_debug("delete from: %s\n", from);
+				if (to != buf)
+					to--; /* drop the space we added */
+				continue;
+			}
+
+			ret = copy_in(to, end, from, arg_end - from, new_val);
+			if (ret < 0)
+				return ret;
+			to += ret;
+
+		/* if not the target arg, copy it unchanged */
+		} else if (to) {
+			int len;
+
+			len = val_end - from;
+			if (to + len >= end)
+				return -E2BIG;
+			memcpy(to, from, len);
+			to += len;
+		}
+		from = val_end;
+	}
+
+	/* If we didn't find the arg, add it */
+	if (!found_arg) {
+		/* trying to delete something that is not there */
+		if (!new_val || !buf)
+			return -ENOENT;
+		if (to >= end)
+			return -E2BIG;
+
+		/* add a space to separate it from the previous arg */
+		if (to != buf && to[-1] != ' ')
+			*to++ = ' ';
+		ret = copy_in(to, end, set_arg, set_arg_len, new_val);
+		log_debug("ret=%d, to: %s buf: %s\n", ret, to, buf);
+		if (ret < 0)
+			return ret;
+		to += ret;
+	}
+
+	/* delete any trailing space */
+	if (to > buf && to[-1] == ' ')
+		to--;
+
+	if (to >= end)
+		return -E2BIG;
+	*to++ = '\0';
+
+	return to - buf;
+}
+
+int bootflow_cmdline_set_arg(struct bootflow *bflow, const char *set_arg,
+			     const char *new_val, bool set_env)
+{
+	char buf[2048];
+	char *cmd = NULL;
+	int ret;
+
+	ret = cmdline_set_arg(buf, sizeof(buf), bflow->cmdline, set_arg,
+			      new_val, NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = bootflow_cmdline_set(bflow, buf);
+	if (*buf) {
+		cmd = strdup(buf);
+		if (!cmd)
+			return -ENOMEM;
+	}
+	free(bflow->cmdline);
+	bflow->cmdline = cmd;
+
+	if (set_env) {
+		ret = env_set("bootargs", bflow->cmdline);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int cmdline_get_arg(const char *cmdline, const char *arg, int *posp)
+{
+	int ret;
+
+	ret = cmdline_set_arg(NULL, 1, cmdline, arg, NULL, posp);
+
+	return ret;
+}
+
+int bootflow_cmdline_get_arg(struct bootflow *bflow, const char *arg,
+			     const char **val)
+{
+	int ret;
+	int pos;
+
+	ret = cmdline_get_arg(bflow->cmdline, arg, &pos);
+	if (ret < 0)
+		return ret;
+	*val = bflow->cmdline + pos;
+
+	return ret;
+}
+
+int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg)
+{
+	struct serial_device_info info;
+	char buf[50];
+	int ret;
+
+	ret = serial_getinfo(gd->cur_serial_dev, &info);
+	if (ret)
+		return ret;
+
+	*buf = '\0';
+	if (!strcmp("earlycon", arg)) {
+		snprintf(buf, sizeof(buf),
+			 "uart8250,mmio32,%#lx,%dn8", info.addr,
+			 info.baudrate);
+	} else if (!strcmp("console", arg)) {
+		snprintf(buf, sizeof(buf),
+			 "ttyS0,%dn8", info.baudrate);
+	}
+
+	if (!*buf) {
+		printf("Unknown param '%s\n", arg);
+		return -ENOENT;
+	}
+
+	ret = bootflow_cmdline_set_arg(bflow, arg, buf, true);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/boot/bootflow_menu.c b/boot/bootflow_menu.c
index 7f06dac..7c1abe5 100644
--- a/boot/bootflow_menu.c
+++ b/boot/bootflow_menu.c
@@ -124,6 +124,10 @@
 		priv->num_bootflows++;
 	}
 
+	ret = scene_arrange(scn);
+	if (ret)
+		return log_msg_ret("arr", ret);
+
 	*expp = exp;
 
 	return 0;
@@ -205,7 +209,7 @@
 		return log_msg_ret("scn", ret);
 
 	if (text_mode)
-		exp_set_text_mode(exp, text_mode);
+		expo_set_text_mode(exp, text_mode);
 
 	done = false;
 	do {
diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c
index 3b3e061..eeded08 100644
--- a/boot/bootmeth-uclass.c
+++ b/boot/bootmeth-uclass.c
@@ -301,32 +301,6 @@
 	return 0;
 }
 
-static int alloc_file(const char *fname, uint size, void **bufp)
-{
-	loff_t bytes_read;
-	ulong addr;
-	char *buf;
-	int ret;
-
-	buf = malloc(size + 1);
-	if (!buf)
-		return log_msg_ret("buf", -ENOMEM);
-	addr = map_to_sysmem(buf);
-
-	ret = fs_read(fname, addr, 0, size, &bytes_read);
-	if (ret) {
-		free(buf);
-		return log_msg_ret("read", ret);
-	}
-	if (size != bytes_read)
-		return log_msg_ret("bread", -EIO);
-	buf[size] = '\0';
-
-	*bufp = buf;
-
-	return 0;
-}
-
 int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align)
 {
 	void *buf;
@@ -338,7 +312,7 @@
 	if (size > size_limit)
 		return log_msg_ret("chk", -E2BIG);
 
-	ret = alloc_file(bflow->fname, bflow->size, &buf);
+	ret = fs_read_alloc(bflow->fname, bflow->size, align, &buf);
 	if (ret)
 		return log_msg_ret("all", ret);
 
@@ -374,7 +348,7 @@
 	if (ret)
 		return log_msg_ret("fs", ret);
 
-	ret = alloc_file(path, size, &buf);
+	ret = fs_read_alloc(path, size, 0, &buf);
 	if (ret)
 		return log_msg_ret("all", ret);
 
@@ -421,7 +395,7 @@
 /**
  * on_bootmeths() - Update the bootmeth order
  *
- * This will check for a valid baudrate and only apply it if valid.
+ * This will check for a valid list of bootmeths and only apply it if valid.
  */
 static int on_bootmeths(const char *name, const char *value, enum env_op op,
 			int flags)
diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c
new file mode 100644
index 0000000..aa19ae0
--- /dev/null
+++ b/boot/bootmeth_cros.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Bootmethod for ChromiumOS
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY UCLASS_BOOTSTD
+
+#include <common.h>
+#include <blk.h>
+#include <bootdev.h>
+#include <bootflow.h>
+#include <bootmeth.h>
+#include <dm.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <part.h>
+#ifdef CONFIG_X86
+#include <asm/zimage.h>
+#endif
+#include <linux/sizes.h>
+
+enum {
+	/* Offsets in the kernel-partition header */
+	KERN_START	= 0x4f0,
+	KERN_SIZE	= 0x518,
+
+	SETUP_OFFSET	= 0x1000,	/* bytes before base */
+	CMDLINE_OFFSET	= 0x2000,	/* bytes before base */
+	OFFSET_BASE	= 0x100000,	/* assumed kernel load-address */
+};
+
+static int cros_check(struct udevice *dev, struct bootflow_iter *iter)
+{
+	/* This only works on block and network devices */
+	if (bootflow_iter_check_blk(iter))
+		return log_msg_ret("blk", -ENOTSUPP);
+
+	return 0;
+}
+
+static int copy_cmdline(const char *from, const char *uuid, char **bufp)
+{
+	const int maxlen = 2048;
+	char buf[maxlen];
+	char *cmd, *to, *end;
+	int len;
+
+	/* Allow space for cmdline + UUID */
+	len = strnlen(from, sizeof(buf));
+	if (len >= maxlen)
+		return -E2BIG;
+
+	log_debug("uuid %d %s\n", uuid ? (int)strlen(uuid) : 0, uuid);
+	for (to = buf, end = buf + maxlen - UUID_STR_LEN - 1; *from; from++) {
+		if (to >= end)
+			return -E2BIG;
+		if (from[0] == '%' && from[1] == 'U' && uuid &&
+		    strlen(uuid) == UUID_STR_LEN) {
+			strcpy(to, uuid);
+			to += UUID_STR_LEN;
+			from++;
+		} else {
+			*to++ = *from;
+		}
+	}
+	*to = '\0';
+	len = to - buf;
+	cmd = strdup(buf);
+	if (!cmd)
+		return -ENOMEM;
+	free(*bufp);
+	*bufp = cmd;
+
+	return 0;
+}
+
+static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow)
+{
+	struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
+	ulong base, start, size, setup, cmdline, num_blks, kern_base;
+	struct disk_partition info;
+	const char *uuid = NULL;
+	void *buf, *hdr;
+	int ret;
+
+	log_debug("starting, part=%d\n", bflow->part);
+
+	/* We consider the whole disk, not any one partition */
+	if (bflow->part)
+		return log_msg_ret("max", -ENOENT);
+
+	/* Check partition 2 */
+	ret = part_get_info(desc, 2, &info);
+	if (ret)
+		return log_msg_ret("part", ret);
+
+	/* Make a buffer for the header information */
+	num_blks = SZ_4K >> desc->log2blksz;
+	log_debug("Reading header, blk=%s, start=%lx, blocks=%lx\n",
+		  bflow->blk->name, (ulong)info.start, num_blks);
+	hdr = memalign(SZ_1K, SZ_4K);
+	if (!hdr)
+		return log_msg_ret("hdr", -ENOMEM);
+	ret = blk_read(bflow->blk, info.start, num_blks, hdr);
+	if (ret != num_blks)
+		return log_msg_ret("inf", ret);
+
+	if (memcmp("CHROMEOS", hdr, 8))
+		return -ENOENT;
+
+	log_info("Header at %lx\n", (ulong)map_to_sysmem(hdr));
+	start = *(u32 *)(hdr + KERN_START);
+	size = ALIGN(*(u32 *)(hdr + KERN_SIZE), desc->blksz);
+	log_debug("Reading start %lx size %lx\n", start, size);
+	bflow->size = size;
+
+	buf = memalign(SZ_1K, size);
+	if (!buf)
+		return log_msg_ret("buf", -ENOMEM);
+	num_blks = size >> desc->log2blksz;
+	log_debug("Reading data, blk=%s, start=%lx, blocks=%lx\n",
+		  bflow->blk->name, (ulong)info.start, num_blks);
+	ret = blk_read(bflow->blk, (ulong)info.start + 0x80, num_blks, buf);
+	if (ret != num_blks)
+		return log_msg_ret("inf", ret);
+	base = map_to_sysmem(buf);
+
+	setup = base + start - OFFSET_BASE - SETUP_OFFSET;
+	cmdline = base + start - OFFSET_BASE - CMDLINE_OFFSET;
+	kern_base = base + start - OFFSET_BASE + SZ_16K;
+	log_debug("base %lx setup %lx, cmdline %lx, kern_base %lx\n", base,
+		  setup, cmdline, kern_base);
+
+#ifdef CONFIG_X86
+	const char *version;
+
+	version = zimage_get_kernel_version(map_sysmem(setup, 0),
+					    map_sysmem(kern_base, 0));
+	log_debug("version %s\n", version);
+	if (version)
+		bflow->name = strdup(version);
+#endif
+	if (!bflow->name)
+		bflow->name = strdup("ChromeOS");
+	if (!bflow->name)
+		return log_msg_ret("nam", -ENOMEM);
+	bflow->os_name = strdup("ChromeOS");
+	if (!bflow->os_name)
+		return log_msg_ret("os", -ENOMEM);
+
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+	uuid = info.uuid;
+#endif
+	ret = copy_cmdline(map_sysmem(cmdline, 0), uuid, &bflow->cmdline);
+	if (ret)
+		return log_msg_ret("cmd", ret);
+
+	bflow->state = BOOTFLOWST_READY;
+	bflow->buf = buf;
+	bflow->x86_setup = map_sysmem(setup, 0);
+
+	return 0;
+}
+
+static int cros_read_file(struct udevice *dev, struct bootflow *bflow,
+			 const char *file_path, ulong addr, ulong *sizep)
+{
+	return -ENOSYS;
+}
+
+static int cros_boot(struct udevice *dev, struct bootflow *bflow)
+{
+#ifdef CONFIG_X86
+	zboot_start(map_to_sysmem(bflow->buf), bflow->size, 0, 0,
+		    map_to_sysmem(bflow->x86_setup),
+		    bflow->cmdline);
+#endif
+
+	return log_msg_ret("go", -EFAULT);
+}
+
+static int cros_bootmeth_bind(struct udevice *dev)
+{
+	struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
+
+	plat->desc = "ChromiumOS boot";
+
+	return 0;
+}
+
+static struct bootmeth_ops cros_bootmeth_ops = {
+	.check		= cros_check,
+	.read_bootflow	= cros_read_bootflow,
+	.read_file	= cros_read_file,
+	.boot		= cros_boot,
+};
+
+static const struct udevice_id cros_bootmeth_ids[] = {
+	{ .compatible = "u-boot,cros" },
+	{ }
+};
+
+U_BOOT_DRIVER(bootmeth_cros) = {
+	.name		= "bootmeth_cros",
+	.id		= UCLASS_BOOTMETH,
+	.of_match	= cros_bootmeth_ids,
+	.ops		= &cros_bootmeth_ops,
+	.bind		= cros_bootmeth_bind,
+};
diff --git a/boot/bootmeth_qfw.c b/boot/bootmeth_qfw.c
index ecd4b08..8ebbc3e 100644
--- a/boot/bootmeth_qfw.c
+++ b/boot/bootmeth_qfw.c
@@ -76,7 +76,7 @@
 {
 	struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
 
-	plat->desc = "Sandbox boot for testing";
+	plat->desc = "QEMU boot using firmware interface";
 
 	return 0;
 }
diff --git a/boot/cedit.c b/boot/cedit.c
new file mode 100644
index 0000000..ee24658
--- /dev/null
+++ b/boot/cedit.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Implementation of configuration editor
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <cli.h>
+#include <dm.h>
+#include <expo.h>
+#include <menu.h>
+#include <video.h>
+#include <linux/delay.h>
+#include "scene_internal.h"
+
+int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
+{
+	struct scene_obj_txt *txt;
+	struct scene_obj *obj;
+	struct scene *scn;
+	int y;
+
+	scn = expo_lookup_scene_id(exp, scene_id);
+	if (!scn)
+		return log_msg_ret("scn", -ENOENT);
+
+	txt = scene_obj_find_by_name(scn, "prompt");
+	if (txt)
+		scene_obj_set_pos(scn, txt->obj.id, 0, vpriv->ysize - 50);
+
+	txt = scene_obj_find_by_name(scn, "title");
+	if (txt)
+		scene_obj_set_pos(scn, txt->obj.id, 200, 10);
+
+	y = 100;
+	list_for_each_entry(obj, &scn->obj_head, sibling) {
+		if (obj->type == SCENEOBJT_MENU) {
+			scene_obj_set_pos(scn, obj->id, 50, y);
+			scene_menu_arrange(scn, (struct scene_obj_menu *)obj);
+			y += 50;
+		}
+	}
+
+	return 0;
+}
+
+int cedit_run(struct expo *exp)
+{
+	struct cli_ch_state s_cch, *cch = &s_cch;
+	struct video_priv *vid_priv;
+	uint scene_id;
+	struct udevice *dev;
+	struct scene *scn;
+	bool done;
+	int ret;
+
+	cli_ch_init(cch);
+
+	/* For now we only support a video console */
+	ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
+	if (ret)
+		return log_msg_ret("vid", ret);
+	ret = expo_set_display(exp, dev);
+	if (ret)
+		return log_msg_ret("dis", ret);
+
+	ret = expo_first_scene_id(exp);
+	if (ret < 0)
+		return log_msg_ret("scn", ret);
+	scene_id = ret;
+
+	ret = expo_set_scene_id(exp, scene_id);
+	if (ret)
+		return log_msg_ret("sid", ret);
+
+	exp->popup = true;
+
+	/* This is not supported for now */
+	if (0)
+		expo_set_text_mode(exp, true);
+
+	vid_priv = dev_get_uclass_priv(dev);
+
+	scn = expo_lookup_scene_id(exp, scene_id);
+	scene_highlight_first(scn);
+
+	cedit_arange(exp, vid_priv, scene_id);
+
+	ret = expo_calc_dims(exp);
+	if (ret)
+		return log_msg_ret("dim", ret);
+
+	done = false;
+	do {
+		struct expo_action act;
+		int ichar, key;
+
+		ret = expo_render(exp);
+		if (ret)
+			break;
+
+		ichar = cli_ch_process(cch, 0);
+		if (!ichar) {
+			while (!ichar && !tstc()) {
+				schedule();
+				mdelay(2);
+				ichar = cli_ch_process(cch, -ETIMEDOUT);
+			}
+			if (!ichar) {
+				ichar = getchar();
+				ichar = cli_ch_process(cch, ichar);
+			}
+		}
+
+		key = 0;
+		if (ichar) {
+			key = bootmenu_conv_key(ichar);
+			if (key == BKEY_NONE)
+				key = ichar;
+		}
+		if (!key)
+			continue;
+
+		ret = expo_send_key(exp, key);
+		if (ret)
+			break;
+
+		ret = expo_action_get(exp, &act);
+		if (!ret) {
+			switch (act.type) {
+			case EXPOACT_POINT_OBJ:
+				scene_set_highlight_id(scn, act.select.id);
+				cedit_arange(exp, vid_priv, scene_id);
+				break;
+			case EXPOACT_OPEN:
+				scene_set_open(scn, act.select.id, true);
+				cedit_arange(exp, vid_priv, scene_id);
+				break;
+			case EXPOACT_CLOSE:
+				scene_set_open(scn, act.select.id, false);
+				cedit_arange(exp, vid_priv, scene_id);
+				break;
+			case EXPOACT_SELECT:
+				scene_set_open(scn, scn->highlight_id, false);
+				cedit_arange(exp, vid_priv, scene_id);
+				break;
+			case EXPOACT_QUIT:
+				log_debug("quitting\n");
+				done = true;
+				break;
+			default:
+				break;
+			}
+		}
+	} while (!done);
+
+	if (ret)
+		return log_msg_ret("end", ret);
+
+	return 0;
+}
diff --git a/boot/expo.c b/boot/expo.c
index 05950a1..db837f7 100644
--- a/boot/expo.c
+++ b/boot/expo.c
@@ -6,6 +6,8 @@
  * Written by Simon Glass <sjg@chromium.org>
  */
 
+#define LOG_CATEGORY	LOGC_EXPO
+
 #include <common.h>
 #include <dm.h>
 #include <expo.h>
@@ -54,6 +56,22 @@
 	free(exp);
 }
 
+uint resolve_id(struct expo *exp, uint id)
+{
+	log_debug("resolve id %d\n", id);
+	if (!id)
+		id = exp->next_id++;
+	else if (id >= exp->next_id)
+		exp->next_id = id + 1;
+
+	return id;
+}
+
+void expo_set_dynamic_start(struct expo *exp, uint dyn_start)
+{
+	exp->next_id = dyn_start;
+}
+
 int expo_str(struct expo *exp, const char *name, uint id, const char *str)
 {
 	struct expo_string *estr;
@@ -83,12 +101,45 @@
 
 int expo_set_display(struct expo *exp, struct udevice *dev)
 {
+	struct udevice *cons;
+	int ret;
+
+	ret = device_find_first_child_by_uclass(dev, UCLASS_VIDEO_CONSOLE,
+						&cons);
+	if (ret)
+		return log_msg_ret("con", ret);
+
 	exp->display = dev;
+	exp->cons = cons;
+
+	return 0;
+}
+
+int expo_calc_dims(struct expo *exp)
+{
+	struct scene *scn;
+	int ret;
+
+	if (!exp->cons)
+		return log_msg_ret("dim", -ENOTSUPP);
+
+	list_for_each_entry(scn, &exp->scene_head, sibling) {
+		/*
+		 * Do the menus last so that all the menus' text objects
+		 * are dimensioned
+		 */
+		ret = scene_calc_dims(scn, false);
+		if (ret)
+			return log_msg_ret("scn", ret);
+		ret = scene_calc_dims(scn, true);
+		if (ret)
+			return log_msg_ret("scn", ret);
+	}
 
 	return 0;
 }
 
-void exp_set_text_mode(struct expo *exp, bool text_mode)
+void expo_set_text_mode(struct expo *exp, bool text_mode)
 {
 	exp->text_mode = text_mode;
 }
@@ -107,13 +158,33 @@
 
 int expo_set_scene_id(struct expo *exp, uint scene_id)
 {
-	if (!expo_lookup_scene_id(exp, scene_id))
+	struct scene *scn;
+	int ret;
+
+	scn = expo_lookup_scene_id(exp, scene_id);
+	if (!scn)
 		return log_msg_ret("id", -ENOENT);
+	ret = scene_arrange(scn);
+	if (ret)
+		return log_msg_ret("arr", ret);
+
 	exp->scene_id = scene_id;
 
 	return 0;
 }
 
+int expo_first_scene_id(struct expo *exp)
+{
+	struct scene *scn;
+
+	if (list_empty(&exp->scene_head))
+		return -ENOENT;
+
+	scn = list_first_entry(&exp->scene_head, struct scene, sibling);
+
+	return scn->id;
+}
+
 int expo_render(struct expo *exp)
 {
 	struct udevice *dev = exp->display;
@@ -156,6 +227,11 @@
 		ret = scene_send_key(scn, key, &exp->action);
 		if (ret)
 			return log_msg_ret("key", ret);
+
+		/* arrange it to get any changes */
+		ret = scene_arrange(scn);
+		if (ret)
+			return log_msg_ret("arr", ret);
 	}
 
 	return scn ? 0 : -ECHILD;
@@ -168,3 +244,25 @@
 
 	return act->type == EXPOACT_NONE ? -EAGAIN : 0;
 }
+
+int expo_apply_theme(struct expo *exp, ofnode node)
+{
+	struct scene *scn;
+	struct expo_theme *theme = &exp->theme;
+	int ret;
+
+	log_debug("Applying theme %s\n", ofnode_get_name(node));
+
+	memset(theme, '\0', sizeof(struct expo_theme));
+	ofnode_read_u32(node, "font-size", &theme->font_size);
+	ofnode_read_u32(node, "menu-inset", &theme->menu_inset);
+	ofnode_read_u32(node, "menuitem-gap-y", &theme->menuitem_gap_y);
+
+	list_for_each_entry(scn, &exp->scene_head, sibling) {
+		ret = scene_apply_theme(scn, theme);
+		if (ret)
+			return log_msg_ret("app", ret);
+	}
+
+	return 0;
+}
diff --git a/boot/expo_build.c b/boot/expo_build.c
new file mode 100644
index 0000000..22f62eb
--- /dev/null
+++ b/boot/expo_build.c
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Building an expo from an FDT description
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY	LOGC_EXPO
+
+#include <common.h>
+#include <expo.h>
+#include <fdtdec.h>
+#include <log.h>
+#include <malloc.h>
+#include <dm/ofnode.h>
+#include <linux/libfdt.h>
+
+/**
+ * struct build_info - Information to use when building
+ *
+ * @str_for_id: String for each ID in use, NULL if empty. The string is NULL
+ *	if there is nothing for this ID. Since ID 0 is never used, the first
+ *	element of this array is always NULL
+ * @str_count: Number of entries in @str_for_id
+ */
+struct build_info {
+	const char **str_for_id;
+	int str_count;
+};
+
+/**
+ * add_txt_str - Add a string or lookup its ID, then add to expo
+ *
+ * @info: Build information
+ * @node: Node describing scene
+ * @scn: Scene to add to
+ * @find_name: Name to look for (e.g. "title"). This will find a property called
+ * "title" if it exists, else will look up the string for "title-id"
+ * Return: ID of added string, or -ve on error
+ */
+int add_txt_str(struct build_info *info, ofnode node, struct scene *scn,
+		const char *find_name, uint obj_id)
+{
+	const char *text;
+	uint str_id;
+	int ret;
+
+	text = ofnode_read_string(node, find_name);
+	if (!text) {
+		char name[40];
+		u32 id;
+
+		snprintf(name, sizeof(name), "%s-id", find_name);
+		ret = ofnode_read_u32(node, name, &id);
+		if (ret)
+			return log_msg_ret("id", -EINVAL);
+
+		if (id >= info->str_count)
+			return log_msg_ret("id", -E2BIG);
+		text = info->str_for_id[id];
+		if (!text)
+			return log_msg_ret("id", -EINVAL);
+	}
+
+	ret = expo_str(scn->expo, find_name, 0, text);
+	if (ret < 0)
+		return log_msg_ret("add", ret);
+	str_id = ret;
+
+	ret = scene_txt_str(scn, find_name, obj_id, str_id, text, NULL);
+	if (ret < 0)
+		return log_msg_ret("add", ret);
+
+	return ret;
+}
+
+/**
+ * add_txt_str_list - Add a list string or lookup its ID, then add to expo
+ *
+ * @info: Build information
+ * @node: Node describing scene
+ * @scn: Scene to add to
+ * @find_name: Name to look for (e.g. "title"). This will find a string-list
+ * property called "title" if it exists, else will look up the string in the
+ * "title-id" string list.
+ * Return: ID of added string, or -ve on error
+ */
+int add_txt_str_list(struct build_info *info, ofnode node, struct scene *scn,
+		     const char *find_name, int index, uint obj_id)
+{
+	const char *text;
+	uint str_id;
+	int ret;
+
+	ret = ofnode_read_string_index(node, find_name, index, &text);
+	if (ret) {
+		char name[40];
+		u32 id;
+
+		snprintf(name, sizeof(name), "%s-id", find_name);
+		ret = ofnode_read_u32_index(node, name, index, &id);
+		if (ret)
+			return log_msg_ret("id", -ENOENT);
+
+		if (id >= info->str_count)
+			return log_msg_ret("id", -E2BIG);
+		text = info->str_for_id[id];
+		if (!text)
+			return log_msg_ret("id", -EINVAL);
+	}
+
+	ret = expo_str(scn->expo, find_name, 0, text);
+	if (ret < 0)
+		return log_msg_ret("add", ret);
+	str_id = ret;
+
+	ret = scene_txt_str(scn, find_name, obj_id, str_id, text, NULL);
+	if (ret < 0)
+		return log_msg_ret("add", ret);
+
+	return ret;
+}
+
+/*
+ * build_element() - Handle creating a text object from a label
+ *
+ * Look up a property called @label or @label-id and create a string for it
+ */
+int build_element(void *ldtb, int node, const char *label)
+{
+	return 0;
+}
+
+/**
+ * read_strings() - Read in the list of strings
+ *
+ * Read the strings into an ID-indexed list, so they can be used for building
+ * an expo. The strings are in a /strings node and each has its own subnode
+ * containing the ID and the string itself:
+ *
+ * example {
+ *    id = <123>;
+ *    value = "This is a test";
+ * };
+ *
+ * Future work may add support for unicode and multiple languages
+ *
+ * @info: Build information
+ * @root: Root node to read from
+ * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
+ * error
+ */
+static int read_strings(struct build_info *info, ofnode root)
+{
+	ofnode strings, node;
+
+	strings = ofnode_find_subnode(root, "strings");
+	if (!ofnode_valid(strings))
+		return log_msg_ret("str", -EINVAL);
+
+	ofnode_for_each_subnode(node, strings) {
+		const char *val;
+		int ret;
+		u32 id;
+
+		ret = ofnode_read_u32(node, "id", &id);
+		if (ret)
+			return log_msg_ret("id", -EINVAL);
+		val = ofnode_read_string(node, "value");
+		if (!val)
+			return log_msg_ret("val", -EINVAL);
+
+		if (id >= info->str_count) {
+			int new_count = info->str_count + 20;
+			void *new_arr;
+
+			new_arr = realloc(info->str_for_id,
+					  new_count * sizeof(char *));
+			if (!new_arr)
+				return log_msg_ret("id", -ENOMEM);
+			memset(new_arr + info->str_count, '\0',
+			       (new_count - info->str_count) * sizeof(char *));
+			info->str_for_id = new_arr;
+			info->str_count = new_count;
+		}
+
+		info->str_for_id[id] = val;
+	}
+
+	return 0;
+}
+
+/**
+ * list_strings() - List the available strings with their IDs
+ *
+ * @info: Build information
+ */
+static void list_strings(struct build_info *info)
+{
+	int i;
+
+	for (i = 0; i < info->str_count; i++) {
+		if (info->str_for_id[i])
+			printf("%3d %s\n", i, info->str_for_id[i]);
+	}
+}
+
+/**
+ * menu_build() - Build a menu and add it to a scene
+ *
+ * See doc/developer/expo.rst for a description of the format
+ *
+ * @info: Build information
+ * @node: Node containing the menu description
+ * @scn: Scene to add the menu to
+ * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
+ * error, -ENOENT if there is a references to a non-existent string
+ */
+static int menu_build(struct build_info *info, ofnode node, struct scene *scn)
+{
+	struct scene_obj_menu *menu;
+	uint title_id, menu_id;
+	const u32 *item_ids;
+	int ret, size, i;
+	const char *name;
+	u32 id;
+
+	name = ofnode_get_name(node);
+	ret = ofnode_read_u32(node, "id", &id);
+	if (ret)
+		return log_msg_ret("id", -EINVAL);
+
+	ret = scene_menu(scn, name, id, &menu);
+	if (ret < 0)
+		return log_msg_ret("men", ret);
+	menu_id = ret;
+
+	/* Set the title */
+	ret = add_txt_str(info, node, scn, "title", 0);
+	if (ret < 0)
+		return log_msg_ret("tit", ret);
+	title_id = ret;
+	ret = scene_menu_set_title(scn, menu_id, title_id);
+
+	item_ids = ofnode_read_prop(node, "item-id", &size);
+	if (!item_ids)
+		return log_msg_ret("itm", -EINVAL);
+	if (!size || size % sizeof(u32))
+		return log_msg_ret("isz", -EINVAL);
+	size /= sizeof(u32);
+
+	for (i = 0; i < size; i++) {
+		struct scene_menitem *item;
+		uint label, key, desc;
+
+		ret = add_txt_str_list(info, node, scn, "item-label", i, 0);
+		if (ret < 0 && ret != -ENOENT)
+			return log_msg_ret("lab", ret);
+		label = max(0, ret);
+
+		ret = add_txt_str_list(info, node, scn, "key-label", i, 0);
+		if (ret < 0 && ret != -ENOENT)
+			return log_msg_ret("key", ret);
+		key = max(0, ret);
+
+		ret = add_txt_str_list(info, node, scn, "desc-label", i, 0);
+		if (ret < 0  && ret != -ENOENT)
+			return log_msg_ret("lab", ret);
+		desc = max(0, ret);
+
+		ret = scene_menuitem(scn, menu_id, simple_xtoa(i),
+				     fdt32_to_cpu(item_ids[i]), key, label,
+				     desc, 0, 0, &item);
+		if (ret < 0)
+			return log_msg_ret("mi", ret);
+	}
+
+	return 0;
+}
+
+/**
+ * menu_build() - Build an expo object and add it to a scene
+ *
+ * See doc/developer/expo.rst for a description of the format
+ *
+ * @info: Build information
+ * @node: Node containing the object description
+ * @scn: Scene to add the object to
+ * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
+ * error, -ENOENT if there is a references to a non-existent string
+ */
+static int obj_build(struct build_info *info, ofnode node, struct scene *scn)
+{
+	const char *type;
+	u32 id;
+	int ret;
+
+	log_debug("- object %s\n", ofnode_get_name(node));
+	ret = ofnode_read_u32(node, "id", &id);
+	if (ret)
+		return log_msg_ret("id", -EINVAL);
+
+	type = ofnode_read_string(node, "type");
+	if (!type)
+		return log_msg_ret("typ", -EINVAL);
+
+	if (!strcmp("menu", type))
+		ret = menu_build(info, node, scn);
+	 else
+		ret = -EINVAL;
+	if (ret)
+		return log_msg_ret("bld", ret);
+
+	return 0;
+}
+
+/**
+ * scene_build() - Build a scene and all its objects
+ *
+ * See doc/developer/expo.rst for a description of the format
+ *
+ * @info: Build information
+ * @node: Node containing the scene description
+ * @scn: Scene to add the object to
+ * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
+ * error, -ENOENT if there is a references to a non-existent string
+ */
+static int scene_build(struct build_info *info, ofnode scn_node,
+		       struct expo *exp)
+{
+	const char *name;
+	struct scene *scn;
+	uint id, title_id;
+	ofnode node;
+	int ret;
+
+	name = ofnode_get_name(scn_node);
+	log_debug("Building scene %s\n", name);
+	ret = ofnode_read_u32(scn_node, "id", &id);
+	if (ret)
+		return log_msg_ret("id", -EINVAL);
+
+	ret = scene_new(exp, name, id, &scn);
+	if (ret < 0)
+		return log_msg_ret("scn", ret);
+
+	ret = add_txt_str(info, scn_node, scn, "title", 0);
+	if (ret < 0)
+		return log_msg_ret("tit", ret);
+	title_id = ret;
+	scene_title_set(scn, title_id);
+
+	ret = add_txt_str(info, scn_node, scn, "prompt", 0);
+	if (ret < 0)
+		return log_msg_ret("pr", ret);
+
+	ofnode_for_each_subnode(node, scn_node) {
+		ret = obj_build(info, node, scn);
+		if (ret < 0)
+			return log_msg_ret("mit", ret);
+	}
+
+	return 0;
+}
+
+int expo_build(ofnode root, struct expo **expp)
+{
+	struct build_info info;
+	ofnode scenes, node;
+	struct expo *exp;
+	u32 dyn_start;
+	int ret;
+
+	memset(&info, '\0', sizeof(info));
+	ret = read_strings(&info, root);
+	if (ret)
+		return log_msg_ret("str", ret);
+	if (_DEBUG)
+		list_strings(&info);
+
+	ret = expo_new("name", NULL, &exp);
+	if (ret)
+		return log_msg_ret("exp", ret);
+
+	if (!ofnode_read_u32(root, "dynamic-start", &dyn_start))
+		expo_set_dynamic_start(exp, dyn_start);
+
+	scenes = ofnode_find_subnode(root, "scenes");
+	if (!ofnode_valid(scenes))
+		return log_msg_ret("sno", -EINVAL);
+
+	ofnode_for_each_subnode(node, scenes) {
+		ret = scene_build(&info, node, exp);
+		if (ret < 0)
+			return log_msg_ret("scn", ret);
+	}
+	*expp = exp;
+
+	return 0;
+}
diff --git a/boot/scene.c b/boot/scene.c
index 030f6aa..e523333 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -6,26 +6,19 @@
  * Written by Simon Glass <sjg@chromium.org>
  */
 
+#define LOG_CATEGORY	LOGC_EXPO
+
 #include <common.h>
 #include <dm.h>
 #include <expo.h>
 #include <malloc.h>
 #include <mapmem.h>
+#include <menu.h>
 #include <video.h>
 #include <video_console.h>
 #include <linux/input.h>
 #include "scene_internal.h"
 
-uint resolve_id(struct expo *exp, uint id)
-{
-	if (!id)
-		id = exp->next_id++;
-	else if (id >= exp->next_id)
-		exp->next_id = id + 1;
-
-	return id;
-}
-
 int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp)
 {
 	struct scene *scn;
@@ -65,16 +58,12 @@
 		scene_obj_destroy(obj);
 
 	free(scn->name);
-	free(scn->title);
 	free(scn);
 }
 
-int scene_title_set(struct scene *scn, const char *title)
+int scene_title_set(struct scene *scn, uint id)
 {
-	free(scn->title);
-	scn->title = strdup(title);
-	if (!scn->title)
-		return log_msg_ret("tit", -ENOMEM);
+	scn->title_id = id;
 
 	return 0;
 }
@@ -103,6 +92,18 @@
 	return NULL;
 }
 
+void *scene_obj_find_by_name(struct scene *scn, const char *name)
+{
+	struct scene_obj *obj;
+
+	list_for_each_entry(obj, &scn->obj_head, sibling) {
+		if (!strcmp(name, obj->name))
+			return obj;
+	}
+
+	return NULL;
+}
+
 int scene_obj_add(struct scene *scn, const char *name, uint id,
 		  enum scene_obj_t type, uint size, struct scene_obj **objp)
 {
@@ -213,22 +214,46 @@
 	obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
 	if (!obj)
 		return log_msg_ret("find", -ENOENT);
-	obj->x = x;
-	obj->y = y;
-	if (obj->type == SCENEOBJT_MENU)
-		scene_menu_arrange(scn, (struct scene_obj_menu *)obj);
+	obj->dim.x = x;
+	obj->dim.y = y;
 
 	return 0;
 }
 
+int scene_obj_set_size(struct scene *scn, uint id, int w, int h)
+{
+	struct scene_obj *obj;
+
+	obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
+	if (!obj)
+		return log_msg_ret("find", -ENOENT);
+	obj->dim.w = w;
+	obj->dim.h = h;
+
+	return 0;
+}
+
 int scene_obj_set_hide(struct scene *scn, uint id, bool hide)
 {
+	int ret;
+
+	ret = scene_obj_flag_clrset(scn, id, SCENEOF_HIDE,
+				    hide ? SCENEOF_HIDE : 0);
+	if (ret)
+		return log_msg_ret("flg", ret);
+
+	return 0;
+}
+
+int scene_obj_flag_clrset(struct scene *scn, uint id, uint clr, uint set)
+{
 	struct scene_obj *obj;
 
 	obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
 	if (!obj)
 		return log_msg_ret("find", -ENOENT);
-	obj->hide = hide;
+	obj->flags &= ~clr;
+	obj->flags |= set;
 
 	return 0;
 }
@@ -258,16 +283,30 @@
 	case SCENEOBJT_TEXT: {
 		struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
 		struct expo *exp = scn->expo;
+		struct vidconsole_bbox bbox;
+		const char *str;
+		int len, ret;
 
+		str = expo_get_str(exp, txt->str_id);
+		if (!str)
+			return log_msg_ret("str", -ENOENT);
+		len = strlen(str);
+
+		/* if there is no console, make it up */
+		if (!exp->cons) {
+			if (widthp)
+				*widthp = 8 * len;
+			return 16;
+		}
+
+		ret = vidconsole_measure(scn->expo->cons, txt->font_name,
+					 txt->font_size, str, &bbox);
+		if (ret)
+			return log_msg_ret("mea", ret);
 		if (widthp)
-			*widthp = 16; /* fake value for now */
-		if (txt->font_size)
-			return txt->font_size;
-		if (exp->display)
-			return video_default_font_height(exp->display);
+			*widthp = bbox.x1;
 
-		/* use a sensible default */
-		return 16;
+		return bbox.y1;
 	}
 	}
 
@@ -282,18 +321,13 @@
 {
 	struct scene *scn = obj->scene;
 	struct expo *exp = scn->expo;
-	struct udevice *cons, *dev = exp->display;
+	const struct expo_theme *theme = &exp->theme;
+	struct udevice *dev = exp->display;
+	struct udevice *cons = text_mode ? NULL : exp->cons;
 	int x, y, ret;
 
-	cons = NULL;
-	if (!text_mode) {
-		ret = device_find_first_child_by_uclass(dev,
-							UCLASS_VIDEO_CONSOLE,
-							&cons);
-	}
-
-	x = obj->x;
-	y = obj->y;
+	x = obj->dim.x;
+	y = obj->dim.y;
 
 	switch (obj->type) {
 	case SCENEOBJT_NONE:
@@ -325,14 +359,45 @@
 		}
 		if (ret && ret != -ENOSYS)
 			return log_msg_ret("font", ret);
-		vidconsole_set_cursor_pos(cons, x, y);
 		str = expo_get_str(exp, txt->str_id);
-		if (str)
+		if (str) {
+			struct video_priv *vid_priv;
+			struct vidconsole_colour old;
+			enum colour_idx fore, back;
+
+			if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
+				fore = VID_BLACK;
+				back = VID_WHITE;
+			} else {
+				fore = VID_LIGHT_GRAY;
+				back = VID_BLACK;
+			}
+
+			vid_priv = dev_get_uclass_priv(dev);
+			if (obj->flags & SCENEOF_POINT) {
+				vidconsole_push_colour(cons, fore, back, &old);
+				video_fill_part(dev, x - theme->menu_inset, y,
+						x + obj->dim.w,
+						y + obj->dim.h,
+						vid_priv->colour_bg);
+			}
+			vidconsole_set_cursor_pos(cons, x, y);
 			vidconsole_put_string(cons, str);
+			if (obj->flags & SCENEOF_POINT)
+				vidconsole_pop_colour(cons, &old);
+		}
 		break;
 	}
 	case SCENEOBJT_MENU: {
 		struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
+
+		if (exp->popup && (obj->flags & SCENEOF_OPEN)) {
+			if (!cons)
+				return -ENOTSUPP;
+
+			/* draw a background behind the menu items */
+			scene_menu_render(menu);
+		}
 		/*
 		 * With a vidconsole, the text and item pointer are rendered as
 		 * normal objects so we don't need to do anything here. The menu
@@ -371,6 +436,30 @@
 	return 0;
 }
 
+int scene_render_deps(struct scene *scn, uint id)
+{
+	struct scene_obj *obj;
+	int ret;
+
+	if (!id)
+		return 0;
+	obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
+	if (!obj)
+		return log_msg_ret("obj", -ENOENT);
+
+	if (!(obj->flags & SCENEOF_HIDE)) {
+		ret = scene_obj_render(obj, false);
+		if (ret && ret != -ENOTSUPP)
+			return log_msg_ret("ren", ret);
+
+		if (obj->type == SCENEOBJT_MENU)
+			scene_menu_render_deps(scn,
+					       (struct scene_obj_menu *)obj);
+	}
+
+	return 0;
+}
+
 int scene_render(struct scene *scn)
 {
 	struct expo *exp = scn->expo;
@@ -378,21 +467,107 @@
 	int ret;
 
 	list_for_each_entry(obj, &scn->obj_head, sibling) {
-		if (!obj->hide) {
+		if (!(obj->flags & SCENEOF_HIDE)) {
 			ret = scene_obj_render(obj, exp->text_mode);
 			if (ret && ret != -ENOTSUPP)
 				return log_msg_ret("ren", ret);
 		}
 	}
 
+	/* render any highlighted object on top of the others */
+	if (scn->highlight_id && !exp->text_mode) {
+		ret = scene_render_deps(scn, scn->highlight_id);
+		if (ret && ret != -ENOTSUPP)
+			return log_msg_ret("dep", ret);
+	}
+
 	return 0;
 }
 
+/**
+ * send_key_obj() - Handle a keypress for moving between objects
+ *
+ * @scn: Scene to receive the key
+ * @key: Key to send (KEYCODE_UP)
+ * @event: Returns resulting event from this keypress
+ * Returns: 0 if OK, -ve on error
+ */
+static void send_key_obj(struct scene *scn, struct scene_obj *obj, int key,
+			 struct expo_action *event)
+{
+	switch (key) {
+	case BKEY_UP:
+		while (obj != list_first_entry(&scn->obj_head, struct scene_obj,
+					       sibling)) {
+			obj = list_entry(obj->sibling.prev,
+					 struct scene_obj, sibling);
+			if (obj->type == SCENEOBJT_MENU) {
+				event->type = EXPOACT_POINT_OBJ;
+				event->select.id = obj->id;
+				log_debug("up to obj %d\n", event->select.id);
+				break;
+			}
+		}
+		break;
+	case BKEY_DOWN:
+		while (!list_is_last(&obj->sibling, &scn->obj_head)) {
+			obj = list_entry(obj->sibling.next, struct scene_obj,
+					 sibling);
+			if (obj->type == SCENEOBJT_MENU) {
+				event->type = EXPOACT_POINT_OBJ;
+				event->select.id = obj->id;
+				log_debug("down to obj %d\n", event->select.id);
+				break;
+			}
+		}
+		break;
+	case BKEY_SELECT:
+		if (obj->type == SCENEOBJT_MENU) {
+			event->type = EXPOACT_OPEN;
+			event->select.id = obj->id;
+			log_debug("open obj %d\n", event->select.id);
+		}
+		break;
+	case BKEY_QUIT:
+		event->type = EXPOACT_QUIT;
+		log_debug("obj quit\n");
+		break;
+	}
+}
+
 int scene_send_key(struct scene *scn, int key, struct expo_action *event)
 {
+	struct scene_obj_menu *menu;
 	struct scene_obj *obj;
 	int ret;
 
+	event->type = EXPOACT_NONE;
+
+	/*
+	 * In 'popup' mode, arrow keys move betwen objects, unless a menu is
+	 * opened
+	 */
+	if (scn->expo->popup) {
+		obj = NULL;
+		if (scn->highlight_id) {
+			obj = scene_obj_find(scn, scn->highlight_id,
+					     SCENEOBJT_NONE);
+		}
+		if (!obj)
+			return 0;
+
+		if (!(obj->flags & SCENEOF_OPEN)) {
+			send_key_obj(scn, obj, key, event);
+			return 0;
+		}
+
+		menu = (struct scene_obj_menu *)obj,
+		ret = scene_menu_send_key(scn, menu, key, event);
+		if (ret)
+			return log_msg_ret("key", ret);
+		return 0;
+	}
+
 	list_for_each_entry(obj, &scn->obj_head, sibling) {
 		if (obj->type == SCENEOBJT_MENU) {
 			struct scene_obj_menu *menu;
@@ -401,14 +576,108 @@
 			ret = scene_menu_send_key(scn, menu, key, event);
 			if (ret)
 				return log_msg_ret("key", ret);
+			break;
+		}
+	}
 
-			/* only allow one menu */
-			ret = scene_menu_arrange(scn, menu);
-			if (ret)
-				return log_msg_ret("arr", ret);
+	return 0;
+}
+
+int scene_calc_dims(struct scene *scn, bool do_menus)
+{
+	struct scene_obj *obj;
+	int ret;
+
+	list_for_each_entry(obj, &scn->obj_head, sibling) {
+		switch (obj->type) {
+		case SCENEOBJT_NONE:
+		case SCENEOBJT_TEXT:
+		case SCENEOBJT_IMAGE: {
+			int width;
+
+			if (!do_menus) {
+				ret = scene_obj_get_hw(scn, obj->id, &width);
+				if (ret < 0)
+					return log_msg_ret("get", ret);
+				obj->dim.w = width;
+				obj->dim.h = ret;
+			}
+			break;
+		}
+		case SCENEOBJT_MENU: {
+			struct scene_obj_menu *menu;
+
+			if (do_menus) {
+				menu = (struct scene_obj_menu *)obj;
+
+				ret = scene_menu_calc_dims(menu);
+				if (ret)
+					return log_msg_ret("men", ret);
+			}
 			break;
 		}
+		}
+	}
+
+	return 0;
+}
+
+int scene_apply_theme(struct scene *scn, struct expo_theme *theme)
+{
+	struct scene_obj *obj;
+	int ret;
+
+	/* Avoid error-checking optional items */
+	scene_txt_set_font(scn, scn->title_id, NULL, theme->font_size);
+
+	list_for_each_entry(obj, &scn->obj_head, sibling) {
+		switch (obj->type) {
+		case SCENEOBJT_NONE:
+		case SCENEOBJT_IMAGE:
+		case SCENEOBJT_MENU:
+			break;
+		case SCENEOBJT_TEXT:
+			scene_txt_set_font(scn, obj->id, NULL,
+					   theme->font_size);
+			break;
+		}
 	}
 
+	ret = scene_arrange(scn);
+	if (ret)
+		return log_msg_ret("arr", ret);
+
+	return 0;
+}
+
+void scene_set_highlight_id(struct scene *scn, uint id)
+{
+	scn->highlight_id = id;
+}
+
+void scene_highlight_first(struct scene *scn)
+{
+	struct scene_obj *obj;
+
+	list_for_each_entry(obj, &scn->obj_head, sibling) {
+		switch (obj->type) {
+		case SCENEOBJT_MENU:
+			scene_set_highlight_id(scn, obj->id);
+			return;
+		default:
+			break;
+		}
+	}
+}
+
+int scene_set_open(struct scene *scn, uint id, bool open)
+{
+	int ret;
+
+	ret = scene_obj_flag_clrset(scn, id, SCENEOF_OPEN,
+				    open ? SCENEOF_OPEN : 0);
+	if (ret)
+		return log_msg_ret("flg", ret);
+
 	return 0;
 }
diff --git a/boot/scene_internal.h b/boot/scene_internal.h
index e8fd765..fb1ea55 100644
--- a/boot/scene_internal.h
+++ b/boot/scene_internal.h
@@ -23,7 +23,7 @@
  *
  * @exp: Expo to use
  * @id: ID to use, or 0 to auto-allocate one
- * @return: Either @id, or the auto-allocated ID
+ * Returns: Either @id, or the auto-allocated ID
  */
 uint resolve_id(struct expo *exp, uint id);
 
@@ -36,10 +36,19 @@
  * @scn: Scene to search
  * @id: ID of object to find
  * @type: Type of the object, or SCENEOBJT_NONE to match any type
+ * Returns: Object found, or NULL if not found
  */
 void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type);
 
 /**
+ * scene_obj_find_by_name() - Find an object in a scene by name
+ *
+ * @scn: Scene to search
+ * @name: Name to search for
+ */
+void *scene_obj_find_by_name(struct scene *scn, const char *name);
+
+/**
  * scene_obj_add() - Add a new object to a scene
  *
  * @scn: Scene to update
@@ -54,6 +63,28 @@
 		  enum scene_obj_t type, uint size, struct scene_obj **objp);
 
 /**
+ * scene_obj_flag_clrset() - Adjust object flags
+ *
+ * @scn: Scene to update
+ * @id: ID of object to update
+ * @clr: Bits to clear in the object's flags
+ * @set: Bits to set in the object's flags
+ * Returns 0 if OK, -ENOENT if the object was not found
+ */
+int scene_obj_flag_clrset(struct scene *scn, uint id, uint clr, uint set);
+
+/**
+ * scene_calc_dims() - Calculate the dimensions of the scene objects
+ *
+ * Updates the width and height of all objects based on their contents
+ *
+ * @scn: Scene to update
+ * @do_menus: true to calculate only menus, false to calculate everything else
+ * Returns 0 if OK, -ENOTSUPP if there is no graphical console
+ */
+int scene_calc_dims(struct scene *scn, bool do_menus);
+
+/**
  * scene_menu_arrange() - Set the position of things in the menu
  *
  * This updates any items associated with a menu to make sure they are
@@ -62,17 +93,27 @@
  *
  * @scn: Scene to update
  * @menu: Menu to process
+ * Returns: 0 if OK, -ve on error
  */
 int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu);
 
 /**
+ * scene_apply_theme() - Apply a theme to a scene
+ *
+ * @scn: Scene to update
+ * @theme: Theme to apply
+ * Returns: 0 if OK, -ve on error
+ */
+int scene_apply_theme(struct scene *scn, struct expo_theme *theme);
+
+/**
  * scene_menu_send_key() - Send a key to a menu for processing
  *
  * @scn: Scene to use
  * @menu: Menu to use
  * @key: Key code to send (KEY_...)
  * @event: Place to put any event which is generated by the key
- * @return 0 if OK, -ENOTTY if there is no current menu item, other -ve on other
+ * Returns: 0 if OK, -ENOTTY if there is no current menu item, other -ve on other
  *	error
  */
 int scene_menu_send_key(struct scene *scn, struct scene_obj_menu *menu, int key,
@@ -89,7 +130,7 @@
  * scene_menu_display() - Display a menu as text
  *
  * @menu: Menu to display
- * @return 0 if OK, -ENOENT if @id is invalid
+ * Returns: 0 if OK, -ENOENT if @id is invalid
  */
 int scene_menu_display(struct scene_obj_menu *menu);
 
@@ -120,4 +161,41 @@
  */
 int scene_send_key(struct scene *scn, int key, struct expo_action *event);
 
+/**
+ * scene_menu_render() - Render the background behind a menu
+ *
+ * @menu: Menu to render
+ */
+void scene_menu_render(struct scene_obj_menu *menu);
+
+/**
+ * scene_render_deps() - Render an object and its dependencies
+ *
+ * @scn: Scene to render
+ * @id: Object ID to render (or 0 for none)
+ * Returns: 0 if OK, -ve on error
+ */
+int scene_render_deps(struct scene *scn, uint id);
+
+/**
+ * scene_menu_render_deps() - Render a menu and its dependencies
+ *
+ * Renders the menu and all of its attached objects
+ *
+ * @scn: Scene to render
+ * @menu: Menu render
+ * Returns: 0 if OK, -ve on error
+ */
+int scene_menu_render_deps(struct scene *scn, struct scene_obj_menu *menu);
+
+/**
+ * scene_menu_calc_dims() - Calculate the dimensions of a menu
+ *
+ * Updates the width and height of the menu based on its contents
+ *
+ * @menu: Menu to update
+ * Returns 0 if OK, -ENOTSUPP if there is no graphical console
+ */
+int scene_menu_calc_dims(struct scene_obj_menu *menu);
+
 #endif /* __SCENE_INTERNAL_H */
diff --git a/boot/scene_menu.c b/boot/scene_menu.c
index 18998e8..8a355f8 100644
--- a/boot/scene_menu.c
+++ b/boot/scene_menu.c
@@ -6,7 +6,7 @@
  * Written by Simon Glass <sjg@chromium.org>
  */
 
-#define LOG_CATEGORY	LOGC_BOOT
+#define LOG_CATEGORY	LOGC_EXPO
 
 #include <common.h>
 #include <dm.h>
@@ -33,6 +33,58 @@
 		scene_menuitem_destroy(item);
 }
 
+static struct scene_menitem *scene_menuitem_find(struct scene_obj_menu *menu,
+						 int id)
+{
+	struct scene_menitem *item;
+
+	list_for_each_entry(item, &menu->item_head, sibling) {
+		if (item->id == id)
+			return item;
+	}
+
+	return NULL;
+}
+
+/**
+ * update_pointers() - Update the pointer object and handle highlights
+ *
+ * @menu: Menu to update
+ * @id: ID of menu item to select/deselect
+ * @point: true if @id is being selected, false if it is being deselected
+ */
+static int update_pointers(struct scene_obj_menu *menu, uint id, bool point)
+{
+	struct scene *scn = menu->obj.scene;
+	const bool stack = scn->expo->popup;
+	const struct scene_menitem *item;
+	int ret;
+
+	item = scene_menuitem_find(menu, id);
+	if (!item)
+		return log_msg_ret("itm", -ENOENT);
+
+	/* adjust the pointer object to point to the selected item */
+	if (menu->pointer_id && item && point) {
+		struct scene_obj *label;
+
+		label = scene_obj_find(scn, item->label_id, SCENEOBJT_NONE);
+
+		ret = scene_obj_set_pos(scn, menu->pointer_id,
+					menu->obj.dim.x + 200, label->dim.y);
+		if (ret < 0)
+			return log_msg_ret("ptr", ret);
+	}
+
+	if (stack) {
+		point &= scn->highlight_id == menu->obj.id;
+		scene_obj_flag_clrset(scn, item->label_id, SCENEOF_POINT,
+				      point ? SCENEOF_POINT : 0);
+	}
+
+	return 0;
+}
+
 /**
  * menu_point_to_item() - Point to a particular menu item
  *
@@ -40,18 +92,115 @@
  */
 static void menu_point_to_item(struct scene_obj_menu *menu, uint item_id)
 {
+	if (menu->cur_item_id)
+		update_pointers(menu, menu->cur_item_id, false);
 	menu->cur_item_id = item_id;
+	update_pointers(menu, item_id, true);
+}
+
+static int scene_bbox_union(struct scene *scn, uint id, int inset,
+			    struct vidconsole_bbox *bbox)
+{
+	struct scene_obj *obj;
+
+	if (!id)
+		return 0;
+	obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
+	if (!obj)
+		return log_msg_ret("obj", -ENOENT);
+	if (bbox->valid) {
+		bbox->x0 = min(bbox->x0, obj->dim.x - inset);
+		bbox->y0 = min(bbox->y0, obj->dim.y);
+		bbox->x1 = max(bbox->x1, obj->dim.x + obj->dim.w + inset);
+		bbox->y1 = max(bbox->y1, obj->dim.y + obj->dim.h);
+	} else {
+		bbox->x0 = obj->dim.x - inset;
+		bbox->y0 = obj->dim.y;
+		bbox->x1 = obj->dim.x + obj->dim.w + inset;
+		bbox->y1 = obj->dim.y + obj->dim.h;
+		bbox->valid = true;
+	}
+
+	return 0;
 }
 
+/**
+ * scene_menu_calc_bbox() - Calculate bounding boxes for the menu
+ *
+ * @menu: Menu to process
+ * @bbox: Returns bounding box of menu including prompts
+ * @label_bbox: Returns bounding box of labels
+ */
+static void scene_menu_calc_bbox(struct scene_obj_menu *menu,
+				 struct vidconsole_bbox *bbox,
+				 struct vidconsole_bbox *label_bbox)
+{
+	const struct expo_theme *theme = &menu->obj.scene->expo->theme;
+	const struct scene_menitem *item;
+
+	bbox->valid = false;
+	scene_bbox_union(menu->obj.scene, menu->title_id, 0, bbox);
+
+	label_bbox->valid = false;
+
+	list_for_each_entry(item, &menu->item_head, sibling) {
+		scene_bbox_union(menu->obj.scene, item->label_id,
+				 theme->menu_inset, bbox);
+		scene_bbox_union(menu->obj.scene, item->key_id, 0, bbox);
+		scene_bbox_union(menu->obj.scene, item->desc_id, 0, bbox);
+		scene_bbox_union(menu->obj.scene, item->preview_id, 0, bbox);
+
+		/* Get the bounding box of all labels */
+		scene_bbox_union(menu->obj.scene, item->label_id,
+				 theme->menu_inset, label_bbox);
+	}
+
+	/*
+	 * subtract the final menuitem's gap to keep the insert the same top
+	 * and bottom
+	 */
+	label_bbox->y1 -= theme->menuitem_gap_y;
+}
+
+int scene_menu_calc_dims(struct scene_obj_menu *menu)
+{
+	struct vidconsole_bbox bbox, label_bbox;
+	const struct scene_menitem *item;
+
+	scene_menu_calc_bbox(menu, &bbox, &label_bbox);
+
+	/* Make all labels the same size */
+	if (label_bbox.valid) {
+		list_for_each_entry(item, &menu->item_head, sibling) {
+			scene_obj_set_size(menu->obj.scene, item->label_id,
+					   label_bbox.x1 - label_bbox.x0,
+					   label_bbox.y1 - label_bbox.y0);
+		}
+	}
+
+	if (bbox.valid) {
+		menu->obj.dim.w = bbox.x1 - bbox.x0;
+		menu->obj.dim.h = bbox.y1 - bbox.y0;
+	}
+
+	return 0;
+}
+
 int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu)
 {
+	const bool open = menu->obj.flags & SCENEOF_OPEN;
+	struct expo *exp = scn->expo;
+	const bool stack = exp->popup;
+	const struct expo_theme *theme = &exp->theme;
 	struct scene_menitem *item;
-	int y, cur_y;
+	uint sel_id;
+	int x, y;
 	int ret;
 
-	y = menu->obj.y;
+	x = menu->obj.dim.x;
+	y = menu->obj.dim.y;
 	if (menu->title_id) {
-		ret = scene_obj_set_pos(scn, menu->title_id, menu->obj.x, y);
+		ret = scene_obj_set_pos(scn, menu->title_id, menu->obj.dim.x, y);
 		if (ret < 0)
 			return log_msg_ret("tit", ret);
 
@@ -59,7 +208,10 @@
 		if (ret < 0)
 			return log_msg_ret("hei", ret);
 
-		y += ret * 2;
+		if (stack)
+			x += 200;
+		else
+			y += ret * 2;
 	}
 
 	/*
@@ -68,11 +220,12 @@
 	 * small. This can be updated once text measuring is supported in
 	 * vidconsole
 	 */
-	cur_y = -1;
+	sel_id = menu->cur_item_id;
 	list_for_each_entry(item, &menu->item_head, sibling) {
+		bool selected;
 		int height;
 
-		ret = scene_obj_get_hw(scn, item->desc_id, NULL);
+		ret = scene_obj_get_hw(scn, item->label_id, NULL);
 		if (ret < 0)
 			return log_msg_ret("get", ret);
 		height = ret;
@@ -81,32 +234,33 @@
 			y += height;
 
 		/* select an item if not done already */
-		if (!menu->cur_item_id)
-			menu_point_to_item(menu, item->id);
+		if (!sel_id)
+			sel_id = item->id;
+
+		selected = sel_id == item->id;
 
 		/*
 		 * Put the label on the left, then leave a space for the
 		 * pointer, then the key and the description
 		 */
-		if (item->label_id) {
-			ret = scene_obj_set_pos(scn, item->label_id, menu->obj.x,
-						y);
-			if (ret < 0)
-				return log_msg_ret("nam", ret);
-		}
-
-		ret = scene_obj_set_pos(scn, item->key_id, menu->obj.x + 230,
-					y);
+		ret = scene_obj_set_pos(scn, item->label_id,
+					x + theme->menu_inset, y);
 		if (ret < 0)
-			return log_msg_ret("key", ret);
+			return log_msg_ret("nam", ret);
+		scene_obj_set_hide(scn, item->label_id,
+				   stack && !open && !selected);
 
-		ret = scene_obj_set_pos(scn, item->desc_id, menu->obj.x + 280,
-					y);
-		if (ret < 0)
-			return log_msg_ret("des", ret);
+		if (item->key_id) {
+			ret = scene_obj_set_pos(scn, item->key_id, x + 230, y);
+			if (ret < 0)
+				return log_msg_ret("key", ret);
+		}
 
-		if (menu->cur_item_id == item->id)
-			cur_y = y;
+		if (item->desc_id) {
+			ret = scene_obj_set_pos(scn, item->desc_id, x + 280, y);
+			if (ret < 0)
+				return log_msg_ret("des", ret);
+		}
 
 		if (item->preview_id) {
 			bool hide;
@@ -125,19 +279,12 @@
 				return log_msg_ret("hid", ret);
 		}
 
-		y += height;
+		if (!stack || open)
+			y += height + theme->menuitem_gap_y;
 	}
 
-	if (menu->pointer_id && cur_y != -1) {
-		/*
-		 * put the pointer to the right of and level with the item it
-		 * points to
-		 */
-		ret = scene_obj_set_pos(scn, menu->pointer_id,
-					menu->obj.x + 200, cur_y);
-		if (ret < 0)
-			return log_msg_ret("ptr", ret);
-	}
+	if (sel_id)
+		menu_point_to_item(menu, sel_id);
 
 	return 0;
 }
@@ -158,10 +305,6 @@
 		*menup = menu;
 	INIT_LIST_HEAD(&menu->item_head);
 
-	ret = scene_menu_arrange(scn, menu);
-	if (ret)
-		return log_msg_ret("pos", ret);
-
 	return menu->obj.id;
 }
 
@@ -191,6 +334,7 @@
 int scene_menu_send_key(struct scene *scn, struct scene_obj_menu *menu, int key,
 			struct expo_action *event)
 {
+	const bool open = menu->obj.flags & SCENEOF_OPEN;
 	struct scene_menitem *item, *cur, *key_item;
 
 	cur = NULL;
@@ -215,7 +359,7 @@
 					     struct scene_menitem, sibling)) {
 			item = list_entry(item->sibling.prev,
 					  struct scene_menitem, sibling);
-			event->type = EXPOACT_POINT;
+			event->type = EXPOACT_POINT_ITEM;
 			event->select.id = item->id;
 			log_debug("up to item %d\n", event->select.id);
 		}
@@ -224,7 +368,7 @@
 		if (!list_is_last(&item->sibling, &menu->item_head)) {
 			item = list_entry(item->sibling.next,
 					  struct scene_menitem, sibling);
-			event->type = EXPOACT_POINT;
+			event->type = EXPOACT_POINT_ITEM;
 			event->select.id = item->id;
 			log_debug("down to item %d\n", event->select.id);
 		}
@@ -235,8 +379,13 @@
 		log_debug("select item %d\n", event->select.id);
 		break;
 	case BKEY_QUIT:
-		event->type = EXPOACT_QUIT;
-		log_debug("quit\n");
+		if (scn->expo->popup && open) {
+			event->type = EXPOACT_CLOSE;
+			event->select.id = menu->obj.id;
+		} else {
+			event->type = EXPOACT_QUIT;
+			log_debug("menu quit\n");
+		}
 		break;
 	case '0'...'9':
 		key_item = scene_menu_find_key(scn, menu, key);
@@ -258,14 +407,13 @@
 {
 	struct scene_obj_menu *menu;
 	struct scene_menitem *item;
-	int ret;
 
 	menu = scene_obj_find(scn, menu_id, SCENEOBJT_MENU);
 	if (!menu)
 		return log_msg_ret("find", -ENOENT);
 
 	/* Check that the text ID is valid */
-	if (!scene_obj_find(scn, desc_id, SCENEOBJT_TEXT))
+	if (!scene_obj_find(scn, label_id, SCENEOBJT_TEXT))
 		return log_msg_ret("txt", -EINVAL);
 
 	item = calloc(1, sizeof(struct scene_obj_menu));
@@ -285,10 +433,6 @@
 	item->flags = flags;
 	list_add_tail(&item->sibling, &menu->item_head);
 
-	ret = scene_menu_arrange(scn, menu);
-	if (ret)
-		return log_msg_ret("pos", ret);
-
 	if (itemp)
 		*itemp = item;
 
@@ -388,3 +532,49 @@
 
 	return -ENOTSUPP;
 }
+
+void scene_menu_render(struct scene_obj_menu *menu)
+{
+	struct expo *exp = menu->obj.scene->expo;
+	const struct expo_theme *theme = &exp->theme;
+	struct vidconsole_bbox bbox, label_bbox;
+	struct udevice *dev = exp->display;
+	struct video_priv *vid_priv;
+	struct udevice *cons = exp->cons;
+	struct vidconsole_colour old;
+	enum colour_idx fore, back;
+
+	if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
+		fore = VID_BLACK;
+		back = VID_WHITE;
+	} else {
+		fore = VID_LIGHT_GRAY;
+		back = VID_BLACK;
+	}
+
+	scene_menu_calc_bbox(menu, &bbox, &label_bbox);
+	vidconsole_push_colour(cons, fore, back, &old);
+	vid_priv = dev_get_uclass_priv(dev);
+	video_fill_part(dev, label_bbox.x0 - theme->menu_inset,
+			label_bbox.y0 - theme->menu_inset,
+			label_bbox.x1, label_bbox.y1 + theme->menu_inset,
+			vid_priv->colour_fg);
+	vidconsole_pop_colour(cons, &old);
+}
+
+int scene_menu_render_deps(struct scene *scn, struct scene_obj_menu *menu)
+{
+	struct scene_menitem *item;
+
+	scene_render_deps(scn, menu->title_id);
+	scene_render_deps(scn, menu->cur_item_id);
+	scene_render_deps(scn, menu->pointer_id);
+
+	list_for_each_entry(item, &menu->item_head, sibling) {
+		scene_render_deps(scn, item->key_id);
+		scene_render_deps(scn, item->label_id);
+		scene_render_deps(scn, item->desc_id);
+	}
+
+	return 0;
+}
diff --git a/cmd/Kconfig b/cmd/Kconfig
index c194184..ecfd575 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -135,6 +135,14 @@
 	help
 	  Print board info
 
+config CMD_BDINFO_EXTRA
+	bool "bdinfo extra features"
+	default y if SANDBOX || X86
+	help
+	  Show additional information about the board. This uses a little more
+	  code space but provides more options, particularly those useful for
+	  bringup, development and debugging.
+
 config CMD_CONFIG
 	bool "config"
 	default SANDBOX
@@ -428,6 +436,15 @@
 
 	  See doc/android/boot-image.rst for details.
 
+config CMD_CEDIT
+	bool "cedit - Configuration editor"
+	depends on CEDIT
+	default y
+	help
+	  Provides a command to allow editing of board configuration and
+	  providing a UI for the user to adjust settings. Subcommands allow
+	  loading and saving of configuration as well as showing an editor.
+
 config CMD_ELF
 	bool "bootelf, bootvx"
 	default y
@@ -1850,7 +1867,6 @@
 
 config CMD_NFS
 	bool "nfs"
-	default y
 	help
 	  Boot image via network using NFS protocol.
 
diff --git a/cmd/Makefile b/cmd/Makefile
index 6c37521..9f8c0b0 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -43,6 +43,7 @@
 obj-$(CONFIG_CMD_CAT) += cat.o
 obj-$(CONFIG_CMD_CACHE) += cache.o
 obj-$(CONFIG_CMD_CBFS) += cbfs.o
+obj-$(CONFIG_CMD_CEDIT) += cedit.o
 obj-$(CONFIG_CMD_CLK) += clk.o
 obj-$(CONFIG_CMD_CLS) += cls.o
 obj-$(CONFIG_CMD_CONFIG) += config.o
diff --git a/cmd/ab_select.c b/cmd/ab_select.c
index 3e46663..bfb67b8 100644
--- a/cmd/ab_select.c
+++ b/cmd/ab_select.c
@@ -16,10 +16,19 @@
 	struct blk_desc *dev_desc;
 	struct disk_partition part_info;
 	char slot[2];
+	bool dec_tries = true;
 
-	if (argc != 4)
+	if (argc < 4)
 		return CMD_RET_USAGE;
 
+	for (int i = 4; i < argc; i++) {
+		if (strcmp(argv[i], "--no-dec") == 0) {
+			dec_tries = false;
+		} else {
+			return CMD_RET_USAGE;
+		}
+	}
+
 	/* Lookup the "misc" partition from argv[2] and argv[3] */
 	if (part_get_info_by_dev_and_name_or_num(argv[2], argv[3],
 						 &dev_desc, &part_info,
@@ -27,7 +36,8 @@
 		return CMD_RET_FAILURE;
 	}
 
-	ret = ab_select_slot(dev_desc, &part_info);
+
+	ret = ab_select_slot(dev_desc, &part_info, dec_tries);
 	if (ret < 0) {
 		printf("Android boot failed, error %d.\n", ret);
 		return CMD_RET_FAILURE;
@@ -41,9 +51,9 @@
 	return CMD_RET_SUCCESS;
 }
 
-U_BOOT_CMD(ab_select, 4, 0, do_ab_select,
+U_BOOT_CMD(ab_select, 5, 0, do_ab_select,
 	   "Select the slot used to boot from and register the boot attempt.",
-	   "<slot_var_name> <interface> <dev[:part|#part_name]>\n"
+	   "<slot_var_name> <interface> <dev[:part|#part_name]> [--no-dec]\n"
 	   "    - Load the slot metadata from the partition 'part' on\n"
 	   "      device type 'interface' instance 'dev' and store the active\n"
 	   "      slot in the 'slot_var_name' variable. This also updates the\n"
@@ -53,4 +63,6 @@
 	   "    - If 'part_name' is passed, preceded with a # instead of :, the\n"
 	   "      partition name whose label is 'part_name' will be looked up in\n"
 	   "      the partition table. This is commonly the \"misc\" partition.\n"
+           "    - If '--no-dec' is set, the number of tries remaining will not\n"
+           "      decremented for the selected boot slot\n"
 );
diff --git a/cmd/acpi.c b/cmd/acpi.c
index e70913e..ede9c8c 100644
--- a/cmd/acpi.c
+++ b/cmd/acpi.c
@@ -118,6 +118,22 @@
 	return 0;
 }
 
+static int do_acpi_set(struct cmd_tbl *cmdtp, int flag, int argc,
+		       char *const argv[])
+{
+	ulong val;
+
+	if (argc < 2) {
+		printf("ACPI pointer: %lx\n", gd_acpi_start());
+	} else {
+		val = hextoul(argv[1], NULL);
+		printf("Setting ACPI pointer to %lx\n", val);
+		gd_set_acpi_start(val);
+	}
+
+	return 0;
+}
+
 static int do_acpi_items(struct cmd_tbl *cmdtp, int flag, int argc,
 			 char *const argv[])
 {
@@ -157,12 +173,14 @@
 
 #ifdef CONFIG_SYS_LONGHELP
 static char acpi_help_text[] =
-	"list - list ACPI tables\n"
-	"acpi items [-d]  - List/dump each piece of ACPI data from devices\n"
-	"acpi dump <name> - Dump ACPI table";
+	"list  - list ACPI tables\n"
+	"acpi items [-d]   - List/dump each piece of ACPI data from devices\n"
+	"acpi set [<addr>] - Set or show address of ACPI tables\n"
+	"acpi dump <name>  - Dump ACPI table";
 #endif
 
 U_BOOT_CMD_WITH_SUBCMDS(acpi, "ACPI tables", acpi_help_text,
 	U_BOOT_SUBCMD_MKENT(list, 1, 1, do_acpi_list),
 	U_BOOT_SUBCMD_MKENT(items, 2, 1, do_acpi_items),
+	U_BOOT_SUBCMD_MKENT(set, 2, 1, do_acpi_set),
 	U_BOOT_SUBCMD_MKENT(dump, 2, 1, do_acpi_dump));
diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c
index 365357c..1fe13ca 100644
--- a/cmd/bdinfo.c
+++ b/cmd/bdinfo.c
@@ -13,6 +13,7 @@
 #include <lmb.h>
 #include <mapmem.h>
 #include <net.h>
+#include <serial.h>
 #include <video.h>
 #include <vsprintf.h>
 #include <asm/cache.h>
@@ -113,6 +114,25 @@
 	}
 }
 
+static void print_serial(struct udevice *dev)
+{
+	struct serial_device_info info;
+	int ret;
+
+	if (!dev || !IS_ENABLED(CONFIG_DM_SERIAL))
+		return;
+
+	ret = serial_getinfo(dev, &info);
+	if (ret)
+		return;
+
+	bdinfo_print_num_l("serial addr", info.addr);
+	bdinfo_print_num_l(" width", info.reg_width);
+	bdinfo_print_num_l(" shift", info.reg_shift);
+	bdinfo_print_num_l(" offset", info.reg_offset);
+	bdinfo_print_num_l(" clock", info.clock);
+}
+
 int do_bdinfo(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	struct bd_info *bd = gd->bd;
@@ -151,6 +171,13 @@
 		if (IS_ENABLED(CONFIG_OF_REAL))
 			printf("devicetree  = %s\n", fdtdec_get_srcname());
 	}
+	print_serial(gd->cur_serial_dev);
+
+	if (IS_ENABLED(CONFIG_CMD_BDINFO_EXTRA)) {
+		bdinfo_print_num_ll("stack ptr", (ulong)&bd);
+		bdinfo_print_num_ll("ram_top ptr", (ulong)gd->ram_top);
+		bdinfo_print_num_l("malloc base", gd_malloc_start());
+	}
 
 	arch_print_bdinfo();
 
diff --git a/cmd/bootflow.c b/cmd/bootflow.c
index 5c61286..c0aa4f8 100644
--- a/cmd/bootflow.c
+++ b/cmd/bootflow.c
@@ -288,6 +288,12 @@
 		return CMD_RET_FAILURE;
 	}
 	std->cur_bootflow = found;
+	if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
+		if (env_set("bootargs", found->cmdline)) {
+			printf("Cannot set bootargs\n");
+			return CMD_RET_FAILURE;
+		}
+	}
 
 	return 0;
 }
@@ -324,6 +330,14 @@
 	printf("Buffer:    %lx\n", (ulong)map_to_sysmem(bflow->buf));
 	printf("Size:      %x (%d bytes)\n", bflow->size, bflow->size);
 	printf("OS:        %s\n", bflow->os_name ? bflow->os_name : "(none)");
+	printf("Cmdline:   ");
+	if (bflow->cmdline)
+		puts(bflow->cmdline);
+	else
+		puts("(none)");
+	putc('\n');
+	if (bflow->x86_setup)
+		printf("X86 setup: %p\n", bflow->x86_setup);
 	printf("Logo:      %s\n", bflow->logo ?
 	       simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)");
 	if (bflow->logo) {
@@ -417,6 +431,75 @@
 
 	return 0;
 }
+
+static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
+			       char *const argv[])
+{
+	struct bootstd_priv *std;
+	struct bootflow *bflow;
+	const char *op, *arg, *val = NULL;
+	int ret;
+
+	if (argc < 3)
+		return CMD_RET_USAGE;
+
+	ret = bootstd_get_priv(&std);
+	if (ret)
+		return CMD_RET_FAILURE;
+
+	bflow = std->cur_bootflow;
+	if (!bflow) {
+		printf("No bootflow selected\n");
+		return CMD_RET_FAILURE;
+	}
+
+	op = argv[1];
+	arg = argv[2];
+	if (*op == 's') {
+		if (argc < 4)
+			return CMD_RET_USAGE;
+		val = argv[3];
+	}
+
+	switch (*op) {
+	case 'c':	/* clear */
+		val = "";
+		fallthrough;
+	case 's':	/* set */
+	case 'd':	/* delete */
+		ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
+		break;
+	case 'g':	/* get */
+		ret = bootflow_cmdline_get_arg(bflow, arg, &val);
+		if (ret >= 0)
+			printf("%.*s\n", ret, val);
+		break;
+	case 'a':	/* auto */
+		ret = bootflow_cmdline_auto(bflow, arg);
+		break;
+	}
+	switch (ret) {
+	case -E2BIG:
+		printf("Argument too long\n");
+		break;
+	case -ENOENT:
+		printf("Argument not found\n");
+		break;
+	case -EINVAL:
+		printf("Mismatched quotes\n");
+		break;
+	case -EBADF:
+		printf("Value must be quoted\n");
+		break;
+	default:
+		if (ret < 0)
+			printf("Unknown error: %dE\n", ret);
+	}
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	return 0;
+}
 #endif /* CONFIG_CMD_BOOTFLOW_FULL */
 
 #ifdef CONFIG_SYS_LONGHELP
@@ -427,7 +510,8 @@
 	"bootflow select [<num>|<name>] - select a bootflow\n"
 	"bootflow info [-d]             - show info on current bootflow (-d dump bootflow)\n"
 	"bootflow boot                  - boot current bootflow (or first available if none selected)\n"
-	"bootflow menu [-t]             - show a menu of available bootflows";
+	"bootflow menu [-t]             - show a menu of available bootflows\n"
+	"bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline";
 #else
 	"scan - boot first available bootflow\n";
 #endif
@@ -441,5 +525,6 @@
 	U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
 	U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
 	U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
+	U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),
 #endif
 );
diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c
index 6baeedc..987b168 100644
--- a/cmd/bootmenu.c
+++ b/cmd/bootmenu.c
@@ -351,8 +351,8 @@
 		 * UEFI specification requires booting from removal media using
 		 * a architecture-specific default image name such as BOOTAA64.EFI.
 		 */
-		efi_ret = eficonfig_generate_media_device_boot_option();
-		if (efi_ret != EFI_SUCCESS && efi_ret != EFI_NOT_FOUND)
+		efi_ret = efi_bootmgr_update_media_device_boot_option();
+		if (efi_ret != EFI_SUCCESS)
 			goto cleanup;
 
 		ret = prepare_uefi_bootorder_entry(menu, &iter, &i);
diff --git a/cmd/cat.c b/cmd/cat.c
index 1273a26..b059080 100644
--- a/cmd/cat.c
+++ b/cmd/cat.c
@@ -17,8 +17,8 @@
 	char *dev;
 	char *file;
 	char *buffer;
-	phys_addr_t addr;
-	loff_t file_size;
+	ulong file_size;
+	int ret;
 
 	if (argc < 4)
 		return CMD_RET_USAGE;
@@ -27,40 +27,27 @@
 	dev = argv[2];
 	file = argv[3];
 
+	ret = fs_load_alloc(ifname, dev, file, 0, 0, (void **)&buffer,
+			    &file_size);
+
 	// check file exists
-	if (fs_set_blk_dev(ifname, dev, FS_TYPE_ANY))
+	switch (ret) {
+	case 0:
+		break;
+	case -ENOMEDIUM:
 		return CMD_RET_FAILURE;
-
-	if (!fs_exists(file)) {
+	case -ENOENT:
 		log_err("File does not exist: ifname=%s dev=%s file=%s\n", ifname, dev, file);
 		return CMD_RET_FAILURE;
-	}
-
-	// get file size
-	if (fs_set_blk_dev(ifname, dev, FS_TYPE_ANY))
-		return CMD_RET_FAILURE;
-
-	if (fs_size(file, &file_size)) {
-		log_err("Cannot read file size: ifname=%s dev=%s file=%s\n", ifname, dev, file);
-		return CMD_RET_FAILURE;
-	}
-
-	// allocate memory for file content
-	buffer = calloc(sizeof(char), file_size + 1);
-	if (!buffer) {
-		log_err("Out of memory\n");
+	case -E2BIG:
+		log_err("File is too large: ifname=%s dev=%s file=%s\n", ifname, dev, file);
 		return CMD_RET_FAILURE;
-	}
-
-	// map pointer to system memory
-	addr = map_to_sysmem(buffer);
-
-	// read file to memory
-	if (fs_set_blk_dev(ifname, dev, FS_TYPE_ANY))
+	case -ENOMEM:
+		log_err("Not enough memory: ifname=%s dev=%s file=%s\n", ifname, dev, file);
 		return CMD_RET_FAILURE;
-
-	if (fs_read(file, addr, 0, 0, &file_size)) {
-		log_err("Cannot read file: ifname=%s dev=%s file=%s\n", ifname, dev, file);
+	default:
+	case -EIO:
+		log_err("File-read failed: ifname=%s dev=%s file=%s\n", ifname, dev, file);
 		return CMD_RET_FAILURE;
 	}
 
diff --git a/cmd/cedit.c b/cmd/cedit.c
new file mode 100644
index 0000000..0cae304
--- /dev/null
+++ b/cmd/cedit.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * 'cedit' command
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <expo.h>
+#include <fs.h>
+#include <dm/ofnode.h>
+#include <linux/sizes.h>
+
+struct expo *cur_exp;
+
+static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	const char *fname;
+	struct expo *exp;
+	oftree tree;
+	ulong size;
+	void *buf;
+	int ret;
+
+	if (argc < 4)
+		return CMD_RET_USAGE;
+	fname = argv[3];
+
+	ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size);
+	if (ret) {
+		printf("File not found\n");
+		return CMD_RET_FAILURE;
+	}
+
+	tree = oftree_from_fdt(buf);
+	if (!oftree_valid(tree)) {
+		printf("Cannot create oftree\n");
+		return CMD_RET_FAILURE;
+	}
+
+	ret = expo_build(oftree_root(tree), &exp);
+	oftree_dispose(tree);
+	if (ret) {
+		printf("Failed to build expo: %dE\n", ret);
+		return CMD_RET_FAILURE;
+	}
+
+	cur_exp = exp;
+
+	return 0;
+}
+
+static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[])
+{
+	ofnode node;
+	int ret;
+
+	if (!cur_exp) {
+		printf("No expo loaded\n");
+		return CMD_RET_FAILURE;
+	}
+
+	node = ofnode_path("/cedit-theme");
+	if (ofnode_valid(node)) {
+		ret = expo_apply_theme(cur_exp, node);
+		if (ret)
+			return CMD_RET_FAILURE;
+	} else {
+		log_warning("No theme found\n");
+	}
+	ret = cedit_run(cur_exp);
+	if (ret) {
+		log_err("Failed (err=%dE)\n", ret);
+		return CMD_RET_FAILURE;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char cedit_help_text[] =
+	"load <interface> <dev[:part]> <filename>   - load config editor\n"
+	"cedit run                                        - run config editor";
+#endif /* CONFIG_SYS_LONGHELP */
+
+U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text,
+	U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load),
+	U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run),
+);
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
index 720f52b..e6e8a0a 100644
--- a/cmd/eficonfig.c
+++ b/cmd/eficonfig.c
@@ -1135,43 +1135,6 @@
 }
 
 /**
- * eficonfig_get_unused_bootoption() - get unused "Boot####" index
- *
- * @buf:	pointer to the buffer to store boot option variable name
- * @buf_size:	buffer size
- * @index:	pointer to store the index in the BootOrder variable
- * Return:	status code
- */
-efi_status_t eficonfig_get_unused_bootoption(u16 *buf, efi_uintn_t buf_size,
-					     unsigned int *index)
-{
-	u32 i;
-	efi_status_t ret;
-	efi_uintn_t size;
-
-	if (buf_size < u16_strsize(u"Boot####"))
-		return EFI_BUFFER_TOO_SMALL;
-
-	for (i = 0; i <= 0xFFFF; i++) {
-		size = 0;
-		efi_create_indexed_name(buf, buf_size, "Boot", i);
-		ret = efi_get_variable_int(buf, &efi_global_variable_guid,
-					   NULL, &size, NULL, NULL);
-		if (ret == EFI_BUFFER_TOO_SMALL)
-			continue;
-		else
-			break;
-	}
-
-	if (i > 0xFFFF)
-		return EFI_OUT_OF_RESOURCES;
-
-	*index = i;
-
-	return EFI_SUCCESS;
-}
-
-/**
  * eficonfig_set_boot_option() - set boot option
  *
  * @varname:		pointer to variable name
@@ -1209,46 +1172,6 @@
 }
 
 /**
- * eficonfig_append_bootorder() - append new boot option in BootOrder variable
- *
- * @index:	"Boot####" index to append to BootOrder variable
- * Return:	status code
- */
-efi_status_t eficonfig_append_bootorder(u16 index)
-{
-	u16 *bootorder;
-	efi_status_t ret;
-	u16 *new_bootorder = NULL;
-	efi_uintn_t last, size, new_size;
-
-	/* append new boot option */
-	bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
-	last = size / sizeof(u16);
-	new_size = size + sizeof(u16);
-	new_bootorder = calloc(1, new_size);
-	if (!new_bootorder) {
-		ret = EFI_OUT_OF_RESOURCES;
-		goto out;
-	}
-	memcpy(new_bootorder, bootorder, size);
-	new_bootorder[last] = index;
-
-	ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
-				   EFI_VARIABLE_NON_VOLATILE |
-				   EFI_VARIABLE_BOOTSERVICE_ACCESS |
-				   EFI_VARIABLE_RUNTIME_ACCESS,
-				   new_size, new_bootorder, false);
-	if (ret != EFI_SUCCESS)
-		goto out;
-
-out:
-	free(bootorder);
-	free(new_bootorder);
-
-	return ret;
-}
-
-/**
  * create_boot_option_entry() - create boot option entry
  *
  * @efi_menu:	pointer to the efimenu structure
@@ -1619,7 +1542,7 @@
 	if (!bo)
 		return EFI_OUT_OF_RESOURCES;
 
-	ret = eficonfig_get_unused_bootoption(varname, sizeof(varname), &bo->boot_index);
+	ret = efi_bootmgr_get_unused_bootoption(varname, sizeof(varname), &bo->boot_index);
 	if (ret != EFI_SUCCESS)
 		return ret;
 
@@ -1627,7 +1550,7 @@
 	if (ret != EFI_SUCCESS)
 		goto out;
 
-	ret = eficonfig_append_bootorder((u16)bo->boot_index);
+	ret = efi_bootmgr_append_bootorder((u16)bo->boot_index);
 	if (ret != EFI_SUCCESS)
 		goto out;
 
@@ -1657,31 +1580,6 @@
 }
 
 /**
- * search_bootorder() - search the boot option index in BootOrder
- *
- * @bootorder:	pointer to the BootOrder variable
- * @num:	number of BootOrder entry
- * @target:	target boot option index to search
- * @index:	pointer to store the index of BootOrder variable
- * Return:	true if exists, false otherwise
- */
-static bool search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index)
-{
-	u32 i;
-
-	for (i = 0; i < num; i++) {
-		if (target == bootorder[i]) {
-			if (index)
-				*index = i;
-
-			return true;
-		}
-	}
-
-	return false;
-}
-
-/**
  * eficonfig_add_boot_selection_entry() - add boot option menu entry
  *
  * @efi_menu:	pointer to store the efimenu structure
@@ -1805,7 +1703,7 @@
 
 		if (efi_varname_is_load_option(var_name16, &index)) {
 			/* If the index is included in the BootOrder, skip it */
-			if (search_bootorder(bootorder, num, index, NULL))
+			if (efi_search_bootorder(bootorder, num, index, NULL))
 				continue;
 
 			ret = eficonfig_add_boot_selection_entry(efi_menu, index, selected);
@@ -2202,7 +2100,7 @@
 
 		if (efi_varname_is_load_option(var_name16, &index)) {
 			/* If the index is included in the BootOrder, skip it */
-			if (search_bootorder(bootorder, num, index, NULL))
+			if (efi_search_bootorder(bootorder, num, index, NULL))
 				continue;
 
 			ret = eficonfig_add_change_boot_order_entry(efi_menu, index, false);
@@ -2305,50 +2203,6 @@
 }
 
 /**
- * delete_boot_option() - delete selected boot option
- *
- * @boot_index:	boot option index to delete
- * Return:	status code
- */
-static efi_status_t delete_boot_option(u16 boot_index)
-{
-	u16 *bootorder;
-	u16 varname[9];
-	efi_status_t ret;
-	unsigned int index;
-	efi_uintn_t num, size;
-
-	efi_create_indexed_name(varname, sizeof(varname),
-				"Boot", boot_index);
-	ret = efi_set_variable_int(varname, &efi_global_variable_guid,
-				   0, 0, NULL, false);
-	if (ret != EFI_SUCCESS) {
-		log_err("delete boot option(%ls) failed\n", varname);
-		return ret;
-	}
-
-	/* update BootOrder if necessary */
-	bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
-	if (!bootorder)
-		return EFI_SUCCESS;
-
-	num = size / sizeof(u16);
-	if (!search_bootorder(bootorder, num, boot_index, &index))
-		return EFI_SUCCESS;
-
-	memmove(&bootorder[index], &bootorder[index + 1],
-		(num - index - 1) * sizeof(u16));
-	size -= sizeof(u16);
-	ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
-				   EFI_VARIABLE_NON_VOLATILE |
-				   EFI_VARIABLE_BOOTSERVICE_ACCESS |
-				   EFI_VARIABLE_RUNTIME_ACCESS,
-				   size, bootorder, false);
-
-	return ret;
-}
-
-/**
  * eficonfig_process_delete_boot_option() - handler to delete boot option
  *
  * @data:	pointer to the data for each entry
@@ -2362,7 +2216,7 @@
 	while (1) {
 		ret = eficonfig_show_boot_selection(&selected);
 		if (ret == EFI_SUCCESS)
-			ret = delete_boot_option(selected);
+			ret = efi_bootmgr_delete_boot_option(selected);
 
 		if (ret != EFI_SUCCESS)
 			break;
@@ -2375,256 +2229,6 @@
 }
 
 /**
- * eficonfig_enumerate_boot_option() - enumerate the possible bootable media
- *
- * @opt:		pointer to the media boot option structure
- * @volume_handles:	pointer to the efi handles
- * @count:		number of efi handle
- * Return:		status code
- */
-efi_status_t eficonfig_enumerate_boot_option(struct eficonfig_media_boot_option *opt,
-					     efi_handle_t *volume_handles, efi_status_t count)
-{
-	u32 i;
-	struct efi_handler *handler;
-	efi_status_t ret = EFI_SUCCESS;
-
-	for (i = 0; i < count; i++) {
-		u16 *p;
-		u16 dev_name[BOOTMENU_DEVICE_NAME_MAX];
-		char *optional_data;
-		struct efi_load_option lo;
-		char buf[BOOTMENU_DEVICE_NAME_MAX];
-		struct efi_device_path *device_path;
-
-		ret = efi_search_protocol(volume_handles[i], &efi_guid_device_path, &handler);
-		if (ret != EFI_SUCCESS)
-			continue;
-		ret = efi_protocol_open(handler, (void **)&device_path,
-					efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-		if (ret != EFI_SUCCESS)
-			continue;
-
-		ret = efi_disk_get_device_name(volume_handles[i], buf, BOOTMENU_DEVICE_NAME_MAX);
-		if (ret != EFI_SUCCESS)
-			continue;
-
-		p = dev_name;
-		utf8_utf16_strncpy(&p, buf, strlen(buf));
-
-		lo.label = dev_name;
-		lo.attributes = LOAD_OPTION_ACTIVE;
-		lo.file_path = device_path;
-		lo.file_path_length = efi_dp_size(device_path) + sizeof(END);
-		/*
-		 * Set the dedicated guid to optional_data, it is used to identify
-		 * the boot option that automatically generated by the bootmenu.
-		 * efi_serialize_load_option() expects optional_data is null-terminated
-		 * utf8 string, so set the "1234567" string to allocate enough space
-		 * to store guid, instead of realloc the load_option.
-		 */
-		lo.optional_data = "1234567";
-		opt[i].size = efi_serialize_load_option(&lo, (u8 **)&opt[i].lo);
-		if (!opt[i].size) {
-			ret = EFI_OUT_OF_RESOURCES;
-			goto out;
-		}
-		/* set the guid */
-		optional_data = (char *)opt[i].lo + (opt[i].size - u16_strsize(u"1234567"));
-		memcpy(optional_data, &efi_guid_bootmenu_auto_generated, sizeof(efi_guid_t));
-	}
-
-out:
-	return ret;
-}
-
-/**
- * eficonfig_delete_invalid_boot_option() - delete non-existing boot option
- *
- * @opt:		pointer to the media boot option structure
- * @count:		number of media boot option structure
- * Return:		status code
- */
-efi_status_t eficonfig_delete_invalid_boot_option(struct eficonfig_media_boot_option *opt,
-						  efi_status_t count)
-{
-	efi_uintn_t size;
-	void *load_option;
-	u32 i, list_size = 0;
-	struct efi_load_option lo;
-	u16 *var_name16 = NULL;
-	u16 varname[] = u"Boot####";
-	efi_status_t ret = EFI_SUCCESS;
-	u16 *delete_index_list = NULL, *p;
-	efi_uintn_t buf_size;
-
-	buf_size = 128;
-	var_name16 = malloc(buf_size);
-	if (!var_name16)
-		return EFI_OUT_OF_RESOURCES;
-
-	var_name16[0] = 0;
-	for (;;) {
-		int index;
-		efi_guid_t guid;
-		efi_uintn_t tmp;
-
-		ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
-		if (ret == EFI_NOT_FOUND) {
-			/*
-			 * EFI_NOT_FOUND indicates we retrieved all EFI variables.
-			 * This should be treated as success.
-			 */
-			ret = EFI_SUCCESS;
-			break;
-		}
-		if (ret != EFI_SUCCESS)
-			goto out;
-
-		if (!efi_varname_is_load_option(var_name16, &index))
-			continue;
-
-		efi_create_indexed_name(varname, sizeof(varname), "Boot", index);
-		load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
-		if (!load_option)
-			continue;
-
-		tmp = size;
-		ret = efi_deserialize_load_option(&lo, load_option, &size);
-		if (ret != EFI_SUCCESS)
-			goto next;
-
-		if (size >= sizeof(efi_guid_bootmenu_auto_generated) &&
-		    !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) {
-			for (i = 0; i < count; i++) {
-				if (opt[i].size == tmp &&
-				    memcmp(opt[i].lo, load_option, tmp) == 0) {
-					opt[i].exist = true;
-					break;
-				}
-			}
-
-			/*
-			 * The entire list of variables must be retrieved by
-			 * efi_get_next_variable_name_int() before deleting the invalid
-			 * boot option, just save the index here.
-			 */
-			if (i == count) {
-				p = realloc(delete_index_list, sizeof(u32) *
-					    (list_size + 1));
-				if (!p) {
-					ret = EFI_OUT_OF_RESOURCES;
-					goto out;
-				}
-				delete_index_list = p;
-				delete_index_list[list_size++] = index;
-			}
-		}
-next:
-		free(load_option);
-	}
-
-	/* delete all invalid boot options */
-	for (i = 0; i < list_size; i++) {
-		ret = delete_boot_option(delete_index_list[i]);
-		if (ret != EFI_SUCCESS)
-			goto out;
-	}
-
-out:
-	free(var_name16);
-	free(delete_index_list);
-
-	return ret;
-}
-
-/**
- * eficonfig_generate_media_device_boot_option() - generate the media device boot option
- *
- * This function enumerates all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
- * and generate the bootmenu entries.
- * This function also provide the BOOT#### variable maintenance for
- * the media device entries.
- *   - Automatically create the BOOT#### variable for the newly detected device,
- *     this BOOT#### variable is distinguished by the special GUID
- *     stored in the EFI_LOAD_OPTION.optional_data
- *   - If the device is not attached to the system, the associated BOOT#### variable
- *     is automatically deleted.
- *
- * Return:	status code
- */
-efi_status_t eficonfig_generate_media_device_boot_option(void)
-{
-	u32 i;
-	efi_status_t ret;
-	efi_uintn_t count;
-	efi_handle_t *volume_handles = NULL;
-	struct eficonfig_media_boot_option *opt = NULL;
-
-	ret = efi_locate_handle_buffer_int(BY_PROTOCOL, &efi_simple_file_system_protocol_guid,
-					   NULL, &count, (efi_handle_t **)&volume_handles);
-	if (ret != EFI_SUCCESS)
-		return ret;
-
-	opt = calloc(count, sizeof(struct eficonfig_media_boot_option));
-	if (!opt)
-		goto out;
-
-	/* enumerate all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL */
-	ret = eficonfig_enumerate_boot_option(opt, volume_handles, count);
-	if (ret != EFI_SUCCESS)
-		goto out;
-
-	/*
-	 * System hardware configuration may vary depending on the user setup.
-	 * The boot option is automatically added by the bootmenu.
-	 * If the device is not attached to the system, the boot option needs
-	 * to be deleted.
-	 */
-	ret = eficonfig_delete_invalid_boot_option(opt, count);
-	if (ret != EFI_SUCCESS)
-		goto out;
-
-	/* add non-existent boot option */
-	for (i = 0; i < count; i++) {
-		u32 boot_index;
-		u16 var_name[9];
-
-		if (!opt[i].exist) {
-			ret = eficonfig_get_unused_bootoption(var_name, sizeof(var_name),
-							      &boot_index);
-			if (ret != EFI_SUCCESS)
-				goto out;
-
-			ret = efi_set_variable_int(var_name, &efi_global_variable_guid,
-						   EFI_VARIABLE_NON_VOLATILE |
-						   EFI_VARIABLE_BOOTSERVICE_ACCESS |
-						   EFI_VARIABLE_RUNTIME_ACCESS,
-						   opt[i].size, opt[i].lo, false);
-			if (ret != EFI_SUCCESS)
-				goto out;
-
-			ret = eficonfig_append_bootorder(boot_index);
-			if (ret != EFI_SUCCESS) {
-				efi_set_variable_int(var_name, &efi_global_variable_guid,
-						     0, 0, NULL, false);
-				goto out;
-			}
-		}
-	}
-
-out:
-	if (opt) {
-		for (i = 0; i < count; i++)
-			free(opt[i].lo);
-	}
-	free(opt);
-	efi_free_pool(volume_handles);
-
-	return ret;
-}
-
-/**
  * eficonfig_init() - do required initialization for eficonfig command
  *
  * Return:	status code
@@ -2709,8 +2313,8 @@
 	if (ret != EFI_SUCCESS)
 		return CMD_RET_FAILURE;
 
-	ret = eficonfig_generate_media_device_boot_option();
-	if (ret != EFI_SUCCESS && ret != EFI_NOT_FOUND)
+	ret = efi_bootmgr_update_media_device_boot_option();
+	if (ret != EFI_SUCCESS)
 		return ret;
 
 	while (1) {
diff --git a/cmd/mbr.c b/cmd/mbr.c
index c269833..ec99b66 100644
--- a/cmd/mbr.c
+++ b/cmd/mbr.c
@@ -244,7 +244,7 @@
 	for (i = 0; i < count; i++) {
 		struct disk_partition p;
 
-		if (part_get_info(dev, i + 1, &p))
+		if (part_get_info_by_type(dev, i + 1, PART_TYPE_DOS, &p))
 			goto fail;
 
 		if ((partitions[i].size && p.size != partitions[i].size) ||
diff --git a/cmd/part.c b/cmd/part.c
index 28f2b7f..0ce1900 100644
--- a/cmd/part.c
+++ b/cmd/part.c
@@ -182,6 +182,36 @@
 	return do_part_info(argc, argv, CMD_PART_INFO_NUMBER);
 }
 
+static int do_part_set(int argc, char *const argv[])
+{
+	const char *devname, *partstr, *typestr;
+	struct blk_desc *desc;
+	int dev;
+
+	if (argc < 3)
+		return CMD_RET_USAGE;
+
+	/* Look up the device */
+	devname = argv[0];
+	partstr = argv[1];
+	typestr = argv[2];
+	dev = blk_get_device_by_str(devname, partstr, &desc);
+	if (dev < 0) {
+		printf("** Bad device specification %s %s **\n", devname,
+		       partstr);
+		return CMD_RET_FAILURE;
+	}
+
+	desc->part_type = part_get_type_by_name(typestr);
+	if (!desc->part_type) {
+		printf("Unknown partition type '%s'\n", typestr);
+		return CMD_RET_FAILURE;
+	}
+	part_print(desc);
+
+	return 0;
+}
+
 #ifdef CONFIG_PARTITION_TYPE_GUID
 static int do_part_type(int argc, char *const argv[])
 {
@@ -245,6 +275,8 @@
 		return do_part_number(argc - 2, argv + 2);
 	else if (!strcmp(argv[1], "types"))
 		return do_part_types(argc - 2, argv + 2);
+	else if (!strcmp(argv[1], "set"))
+		return do_part_set(argc - 2, argv + 2);
 #ifdef CONFIG_PARTITION_TYPE_GUID
 	else if (!strcmp(argv[1], "type"))
 		return do_part_type(argc - 2, argv + 2);
@@ -279,6 +311,8 @@
 #endif
 	"part type <interface> <dev>:<part> <varname>\n"
 	"    - set environment variable to partition type\n"
+	"part set <interface> <dev> type\n"
+	"    - set partition type for a device\n"
 	"part types\n"
 	"    - list supported partition table types"
 );
diff --git a/cmd/qfw.c b/cmd/qfw.c
index ae3c6a7..d6ecfa6 100644
--- a/cmd/qfw.c
+++ b/cmd/qfw.c
@@ -26,7 +26,7 @@
 	for (file = qfw_file_iter_init(qfw_dev, &iter);
 	     !qfw_file_iter_end(&iter);
 	     file = qfw_file_iter_next(&iter)) {
-		printf("%-56s\n", file->cfg.name);
+		printf("%08lx %-56s\n", file->addr, file->cfg.name);
 	}
 
 	return 0;
diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c
index b1691d8..6ad7a12 100644
--- a/cmd/x86/mtrr.c
+++ b/cmd/x86/mtrr.c
@@ -10,71 +10,19 @@
 #include <asm/mp.h>
 #include <asm/mtrr.h>
 
-static const char *const mtrr_type_name[MTRR_TYPE_COUNT] = {
-	"Uncacheable",
-	"Combine",
-	"2",
-	"3",
-	"Through",
-	"Protect",
-	"Back",
-};
-
-static void read_mtrrs(void *arg)
-{
-	struct mtrr_info *info = arg;
-
-	mtrr_read_all(info);
-}
-
-static int do_mtrr_list(int reg_count, int cpu_select)
-{
-	struct mtrr_info info;
-	int ret;
-	int i;
-
-	printf("Reg Valid Write-type   %-16s %-16s %-16s\n", "Base   ||",
-	       "Mask   ||", "Size   ||");
-	memset(&info, '\0', sizeof(info));
-	ret = mp_run_on_cpus(cpu_select, read_mtrrs, &info);
-	if (ret)
-		return log_msg_ret("run", ret);
-	for (i = 0; i < reg_count; i++) {
-		const char *type = "Invalid";
-		uint64_t base, mask, size;
-		bool valid;
-
-		base = info.mtrr[i].base;
-		mask = info.mtrr[i].mask;
-		size = ~mask & ((1ULL << CONFIG_CPU_ADDR_BITS) - 1);
-		size |= (1 << 12) - 1;
-		size += 1;
-		valid = mask & MTRR_PHYS_MASK_VALID;
-		type = mtrr_type_name[base & MTRR_BASE_TYPE_MASK];
-		printf("%d   %-5s %-12s %016llx %016llx %016llx\n", i,
-		       valid ? "Y" : "N", type, base & ~MTRR_BASE_TYPE_MASK,
-		       mask & ~MTRR_PHYS_MASK_VALID, size);
-	}
-
-	return 0;
-}
-
 static int do_mtrr_set(int cpu_select, uint reg, int argc, char *const argv[])
 {
 	const char *typename = argv[0];
 	uint32_t start, size;
 	uint64_t base, mask;
-	int i, type = -1;
+	int type = -1;
 	bool valid;
 	int ret;
 
 	if (argc < 3)
 		return CMD_RET_USAGE;
-	for (i = 0; i < MTRR_TYPE_COUNT; i++) {
-		if (*typename == *mtrr_type_name[i])
-			type = i;
-	}
-	if (type == -1) {
+	type = mtrr_get_type_by_name(typename);
+	if (type < 0) {
 		printf("Invalid type name %s\n", typename);
 		return CMD_RET_USAGE;
 	}
@@ -146,7 +94,7 @@
 			if (!first)
 				printf("\n");
 			printf("CPU %d:\n", i);
-			ret = do_mtrr_list(reg_count, i);
+			ret = mtrr_list(reg_count, i);
 			if (ret) {
 				printf("Failed to read CPU %s (err=%d)\n",
 				       i < MP_SELECT_ALL ? simple_itoa(i) : "",
diff --git a/common/Kconfig b/common/Kconfig
index 42baca2..f5ad63c 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -936,6 +936,15 @@
 	  allows a bootloader to try a new version of the system but roll back
 	  to previous version if the new one didn't boot all the way.
 
+config ANDROID_AB_BACKUP_OFFSET
+	hex "Offset of backup bootloader control"
+	depends on ANDROID_AB
+	default 0x0
+	help
+	  If non-zero, a backup bootloader message starting at this offset in
+	  the partition will tried in the event that the primary one (starting
+	  at offset 0) fails its checksum.
+
 endmenu
 
 menu "Blob list"
diff --git a/common/bloblist.c b/common/bloblist.c
index 0d63b6e..2144b10 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -51,6 +51,7 @@
 
 	/* BLOBLISTT_PROJECT_AREA */
 	{ BLOBLISTT_U_BOOT_SPL_HANDOFF, "SPL hand-off" },
+	{ BLOBLISTT_U_BOOT_VIDEO, "SPL video handoff" },
 
 	/* BLOBLISTT_VENDOR_AREA */
 };
diff --git a/common/board_f.c b/common/board_f.c
index 1688e27..e5969ec 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -633,8 +633,6 @@
 static int reloc_fdt(void)
 {
 	if (!IS_ENABLED(CONFIG_OF_EMBED)) {
-		if (gd->flags & GD_FLG_SKIP_RELOC)
-			return 0;
 		if (gd->new_fdt) {
 			memcpy(gd->new_fdt, gd->fdt_blob,
 			       fdt_totalsize(gd->fdt_blob));
@@ -731,8 +729,7 @@
 #endif
 
 /* ARM calls relocate_code from its crt0.S */
-#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
-		!CONFIG_IS_ENABLED(X86_64)
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
 
 static int jump_to_copy(void)
 {
@@ -754,7 +751,11 @@
 	 * (CPU cache)
 	 */
 	arch_setup_gd(gd->new_gd);
-	board_init_f_r_trampoline(gd->start_addr_sp);
+# if CONFIG_IS_ENABLED(X86_64)
+		board_init_f_r_trampoline64(gd->new_gd, gd->start_addr_sp);
+# else
+		board_init_f_r_trampoline(gd->start_addr_sp);
+# endif
 #else
 	relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);
 #endif
@@ -969,8 +970,7 @@
 	 * watchdog device is not serviced is as small as possible.
 	 */
 	cyclic_unregister_all,
-#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
-		!CONFIG_IS_ENABLED(X86_64)
+#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
 	jump_to_copy,
 #endif
 	NULL,
diff --git a/common/board_r.c b/common/board_r.c
index d798c00..4aaa894 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -196,7 +196,7 @@
 
 static int initr_malloc(void)
 {
-	ulong malloc_start;
+	ulong start;
 
 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
 	debug("Pre-reloc malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
@@ -207,8 +207,9 @@
 	 * This value MUST match the value of gd->start_addr_sp in board_f.c:
 	 * reserve_noncached().
 	 */
-	malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
-	mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN),
+	start = gd->relocaddr - TOTAL_MALLOC_LEN;
+	gd_set_malloc_start(start);
+	mem_malloc_init((ulong)map_sysmem(start, TOTAL_MALLOC_LEN),
 			TOTAL_MALLOC_LEN);
 	return 0;
 }
diff --git a/common/hash.c b/common/hash.c
index 9a52d60..cbffdfd 100644
--- a/common/hash.c
+++ b/common/hash.c
@@ -586,6 +586,8 @@
 
 		output = memalign(ARCH_DMA_MINALIGN,
 				  sizeof(uint32_t) * HASH_MAX_DIGEST_SIZE);
+		if (!output)
+			return CMD_RET_FAILURE;
 
 		buf = map_sysmem(addr, len);
 		algo->hash_func_ws(buf, len, output, algo->chunk_size);
@@ -602,6 +604,7 @@
 					flags & HASH_FLAG_ENV)) {
 				printf("ERROR: %s does not contain a valid "
 					"%s sum\n", *argv, algo->name);
+				free(output);
 				return 1;
 			}
 			if (memcmp(output, vsum, algo->digest_size) != 0) {
@@ -612,6 +615,7 @@
 				for (i = 0; i < algo->digest_size; i++)
 					printf("%02x", vsum[i]);
 				puts(" ** ERROR **\n");
+				free(output);
 				return 1;
 			}
 		} else {
@@ -622,10 +626,10 @@
 				store_result(algo, output, *argv,
 					flags & HASH_FLAG_ENV);
 			}
-		unmap_sysmem(output);
-
 		}
 
+		free(output);
+
 	/* Horrible code size hack for boards that just want crc32 */
 	} else {
 		ulong crc;
diff --git a/common/log.c b/common/log.c
index 7cfc49b..b2de57f 100644
--- a/common/log.c
+++ b/common/log.c
@@ -31,6 +31,7 @@
 	"boot",
 	"event",
 	"fs",
+	"expo",
 };
 
 _Static_assert(ARRAY_SIZE(log_cat_name) == LOGC_COUNT - LOGC_NONE,
@@ -436,7 +437,7 @@
 	/*
 	 * We cannot add runtime data to the driver since it is likely stored
 	 * in rodata. Instead, set up a 'device' corresponding to each driver.
-	 * We only support having a single device.
+	 * We only support having a single device for each driver.
 	 */
 	INIT_LIST_HEAD((struct list_head *)&gd->log_head);
 	while (drv < end) {
diff --git a/common/log_console.c b/common/log_console.c
index f1dcc04..bb091ce 100644
--- a/common/log_console.c
+++ b/common/log_console.c
@@ -37,8 +37,14 @@
 			printf("%s:", rec->file);
 		if (fmt & BIT(LOGF_LINE))
 			printf("%d-", rec->line);
-		if (fmt & BIT(LOGF_FUNC))
-			printf("%*s()", CONFIG_LOGF_FUNC_PAD, rec->func);
+		if (fmt & BIT(LOGF_FUNC)) {
+			if (CONFIG_IS_ENABLED(USE_TINY_PRINTF)) {
+				printf("%s()", rec->func);
+			} else {
+				printf("%*s()", CONFIG_LOGF_FUNC_PAD,
+				       rec->func);
+			}
+		}
 	}
 	if (fmt & BIT(LOGF_MSG))
 		printf("%s%s", add_space ? " " : "", rec->msg);
diff --git a/configs/10m50_defconfig b/configs/10m50_defconfig
index 54a67c5..b76f31b 100644
--- a/configs/10m50_defconfig
+++ b/configs/10m50_defconfig
@@ -26,7 +26,6 @@
 # CONFIG_CMD_ITEST is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 CONFIG_ENV_OVERWRITE=y
diff --git a/configs/3c120_defconfig b/configs/3c120_defconfig
index fc73c06..13da353 100644
--- a/configs/3c120_defconfig
+++ b/configs/3c120_defconfig
@@ -26,7 +26,6 @@
 # CONFIG_CMD_ITEST is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 CONFIG_ENV_OVERWRITE=y
diff --git a/configs/CMPC885_defconfig b/configs/CMPC885_defconfig
index f5bc6d6..54873da 100644
--- a/configs/CMPC885_defconfig
+++ b/configs/CMPC885_defconfig
@@ -51,7 +51,6 @@
 CONFIG_CMD_MTD=y
 CONFIG_CMD_NAND=y
 CONFIG_CMD_DHCP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_MII_INIT=y
 CONFIG_CMD_PING=y
diff --git a/configs/CMPCPRO_defconfig b/configs/CMPCPRO_defconfig
index 80913e6..d817274 100644
--- a/configs/CMPCPRO_defconfig
+++ b/configs/CMPCPRO_defconfig
@@ -136,7 +136,6 @@
 CONFIG_CMD_NAND=y
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 # CONFIG_CMD_SLEEP is not set
diff --git a/configs/apalis-tk1_defconfig b/configs/apalis-tk1_defconfig
index 36d28a2..fda85c2 100644
--- a/configs/apalis-tk1_defconfig
+++ b/configs/apalis-tk1_defconfig
@@ -43,7 +43,6 @@
 CONFIG_CMD_PCI=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
diff --git a/configs/apalis_imx6_defconfig b/configs/apalis_imx6_defconfig
index dcee517..5f0f781 100644
--- a/configs/apalis_imx6_defconfig
+++ b/configs/apalis_imx6_defconfig
@@ -62,7 +62,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_SDP=y
 CONFIG_CMD_USB_MASS_STORAGE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_BOOTCOUNT=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
diff --git a/configs/apalis_t30_defconfig b/configs/apalis_t30_defconfig
index 5165525..83aab24 100644
--- a/configs/apalis_t30_defconfig
+++ b/configs/apalis_t30_defconfig
@@ -38,7 +38,6 @@
 CONFIG_CMD_PCI=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/arbel_evb_defconfig b/configs/arbel_evb_defconfig
index 29c4c18..c27a7cd 100644
--- a/configs/arbel_evb_defconfig
+++ b/configs/arbel_evb_defconfig
@@ -2,7 +2,8 @@
 CONFIG_ARCH_NPCM=y
 CONFIG_SYS_MALLOC_LEN=0x240000
 CONFIG_SYS_MALLOC_F_LEN=0x1000
-CONFIG_NR_DRAM_BANKS=1
+CONFIG_TEXT_BASE=0x06208000
+CONFIG_NR_DRAM_BANKS=2
 CONFIG_ENV_SIZE=0x40000
 CONFIG_ENV_OFFSET=0x3C0000
 CONFIG_ENV_SECT_SIZE=0x1000
@@ -22,6 +23,8 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_MAXARGS=32
 CONFIG_SYS_BOOTM_LEN=0x1400000
+CONFIG_SYS_LOAD_ADDR=0x06208000
+CONFIG_SYS_INIT_SP_ADDR=0x06208000
 CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
@@ -86,3 +89,13 @@
 CONFIG_LIB_HW_RAND=y
 CONFIG_SHA_HW_ACCEL=y
 # CONFIG_EFI_LOADER is not set
+CONFIG_TEE=y
+CONFIG_OPTEE=y
+CONFIG_TPM=y
+CONFIG_TPM_V2=y
+CONFIG_TPM2_FTPM_TEE=y
+CONFIG_CMD_TPM=y
+CONFIG_SUPPORT_EMMC_RPMB=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_PART=y
diff --git a/configs/bayleybay_defconfig b/configs/bayleybay_defconfig
index 4e59d51..a44c9b7 100644
--- a/configs/bayleybay_defconfig
+++ b/configs/bayleybay_defconfig
@@ -37,7 +37,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_BOOTSTAGE=y
diff --git a/configs/beaver_defconfig b/configs/beaver_defconfig
index 3820a33..0d8a74b 100644
--- a/configs/beaver_defconfig
+++ b/configs/beaver_defconfig
@@ -38,7 +38,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/bitmain_antminer_s9_defconfig b/configs/bitmain_antminer_s9_defconfig
index c38ba15..3995d41 100644
--- a/configs/bitmain_antminer_s9_defconfig
+++ b/configs/bitmain_antminer_s9_defconfig
@@ -55,7 +55,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_MAY_FAIL=y
-# CONFIG_CMD_NFS is not set
 CONFIG_SYS_DISABLE_AUTOLOAD=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
diff --git a/configs/brppt1_mmc_defconfig b/configs/brppt1_mmc_defconfig
index 2c9b066..6536202 100644
--- a/configs/brppt1_mmc_defconfig
+++ b/configs/brppt1_mmc_defconfig
@@ -64,7 +64,6 @@
 # CONFIG_CMD_ITEST is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_MAY_FAIL=y
-# CONFIG_CMD_NFS is not set
 CONFIG_SYS_DISABLE_AUTOLOAD=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
diff --git a/configs/brppt2_defconfig b/configs/brppt2_defconfig
index 00ef3d9..05ee4c5 100644
--- a/configs/brppt2_defconfig
+++ b/configs/brppt2_defconfig
@@ -56,7 +56,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_MAY_FAIL=y
-# CONFIG_CMD_NFS is not set
 CONFIG_SYS_DISABLE_AUTOLOAD=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_CACHE=y
diff --git a/configs/brsmarc1_defconfig b/configs/brsmarc1_defconfig
index 1e55ed7..94943fc 100644
--- a/configs/brsmarc1_defconfig
+++ b/configs/brsmarc1_defconfig
@@ -73,7 +73,6 @@
 # CONFIG_CMD_ITEST is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_MAY_FAIL=y
-# CONFIG_CMD_NFS is not set
 CONFIG_SYS_DISABLE_AUTOLOAD=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
diff --git a/configs/brxre1_defconfig b/configs/brxre1_defconfig
index 1c437e9..b50aef0 100644
--- a/configs/brxre1_defconfig
+++ b/configs/brxre1_defconfig
@@ -63,7 +63,6 @@
 # CONFIG_CMD_ITEST is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_MAY_FAIL=y
-# CONFIG_CMD_NFS is not set
 CONFIG_SYS_DISABLE_AUTOLOAD=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
diff --git a/configs/cardhu_defconfig b/configs/cardhu_defconfig
index 00fea793..4fe4621 100644
--- a/configs/cardhu_defconfig
+++ b/configs/cardhu_defconfig
@@ -35,7 +35,6 @@
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/cei-tk1-som_defconfig b/configs/cei-tk1-som_defconfig
index c00e6be..b920ac2 100644
--- a/configs/cei-tk1-som_defconfig
+++ b/configs/cei-tk1-som_defconfig
@@ -41,7 +41,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/cherryhill_defconfig b/configs/cherryhill_defconfig
index 4137b1c..0079971 100644
--- a/configs/cherryhill_defconfig
+++ b/configs/cherryhill_defconfig
@@ -28,7 +28,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT2=y
diff --git a/configs/chromebook_coral_defconfig b/configs/chromebook_coral_defconfig
index f5995f2..fe61153 100644
--- a/configs/chromebook_coral_defconfig
+++ b/configs/chromebook_coral_defconfig
@@ -1,5 +1,6 @@
 CONFIG_X86=y
 CONFIG_TEXT_BASE=0x1110000
+CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_SYS_MALLOC_F_LEN=0x3d00
 CONFIG_NR_DRAM_BANKS=8
 CONFIG_MAX_CPUS=8
@@ -22,6 +23,7 @@
 CONFIG_X86_OFFSET_SPL=0xffe80000
 CONFIG_INTEL_ACPIGEN=y
 CONFIG_INTEL_GENERIC_WIFI=y
+CONFIG_BOOTSTD_FULL=y
 CONFIG_SYS_MONITOR_BASE=0x01110000
 CONFIG_CHROMEOS=y
 CONFIG_BOOTSTAGE=y
@@ -33,8 +35,10 @@
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS_SUBST=y
 CONFIG_USE_BOOTCOMMAND=y
-CONFIG_BOOTCOMMAND="tpm init; tpm startup TPM2_SU_CLEAR; read mmc 0:2 100000 0 80; setexpr loader *001004f0; setexpr size *00100518; setexpr blocks $size / 200; read mmc 0:2 100000 80 $blocks; setexpr setup $loader - 1000; setexpr cmdline_ptr $loader - 2000; setexpr.s cmdline *$cmdline_ptr; setexpr cmdline gsub %U \\\\${uuid}; if part uuid mmc 0:2 uuid; then zboot start 100000 0 0 0 $setup cmdline; zboot load; zboot setup; zboot dump; zboot go;fi"
+CONFIG_BOOTCOMMAND="tpm init; tpm startup TPM2_SU_CLEAR; bootflow scan -lb"
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_LOG=y
+CONFIG_LOGF_FUNC=y
 CONFIG_DISPLAY_BOARDINFO_LATE=y
 CONFIG_LAST_STAGE_INIT=y
 CONFIG_BLOBLIST=y
@@ -52,9 +56,11 @@
 CONFIG_TPL_SYS_MALLOC_SIMPLE=y
 CONFIG_TPL_POWER=y
 CONFIG_HUSH_PARSER=y
-CONFIG_SYS_PBSIZE=532
+CONFIG_SYS_CBSIZE=1024
+CONFIG_SYS_PBSIZE=1024
 CONFIG_CMD_CPU=y
 CONFIG_CMD_PMC=y
+CONFIG_CMD_MEM_SEARCH=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_PART=y
diff --git a/configs/chromebook_link64_defconfig b/configs/chromebook_link64_defconfig
index 8c75d65..558609e 100644
--- a/configs/chromebook_link64_defconfig
+++ b/configs/chromebook_link64_defconfig
@@ -50,7 +50,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_BOOTSTAGE=y
diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig
index 3098857..96c26f1 100644
--- a/configs/chromebook_link_defconfig
+++ b/configs/chromebook_link_defconfig
@@ -37,7 +37,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_SOUND=y
diff --git a/configs/chromebook_samus_defconfig b/configs/chromebook_samus_defconfig
index 0d20891..4019c16 100644
--- a/configs/chromebook_samus_defconfig
+++ b/configs/chromebook_samus_defconfig
@@ -39,7 +39,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_SOUND=y
diff --git a/configs/chromebox_panther_defconfig b/configs/chromebox_panther_defconfig
index 96c739c..f050d06 100644
--- a/configs/chromebox_panther_defconfig
+++ b/configs/chromebox_panther_defconfig
@@ -32,7 +32,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_BOOTSTAGE=y
diff --git a/configs/cm_t43_defconfig b/configs/cm_t43_defconfig
index a307e83..12d010a 100644
--- a/configs/cm_t43_defconfig
+++ b/configs/cm_t43_defconfig
@@ -62,7 +62,6 @@
 CONFIG_CMD_NAND=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NFS is not set
 CONFIG_SYS_DISABLE_AUTOLOAD=y
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_CMD_MTDPARTS=y
diff --git a/configs/colibri_imx6_defconfig b/configs/colibri_imx6_defconfig
index 9d2a201..be1037b 100644
--- a/configs/colibri_imx6_defconfig
+++ b/configs/colibri_imx6_defconfig
@@ -61,7 +61,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_SDP=y
 CONFIG_CMD_USB_MASS_STORAGE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_BOOTCOUNT=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
diff --git a/configs/colibri_t20_defconfig b/configs/colibri_t20_defconfig
index cdf9e8b..eb2e202 100644
--- a/configs/colibri_t20_defconfig
+++ b/configs/colibri_t20_defconfig
@@ -36,7 +36,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
diff --git a/configs/colibri_t30_defconfig b/configs/colibri_t30_defconfig
index fed867a..8098ff7 100644
--- a/configs/colibri_t30_defconfig
+++ b/configs/colibri_t30_defconfig
@@ -36,7 +36,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/colibri_vf_defconfig b/configs/colibri_vf_defconfig
index c47bfc8..4d4d0e4 100644
--- a/configs/colibri_vf_defconfig
+++ b/configs/colibri_vf_defconfig
@@ -51,7 +51,6 @@
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 CONFIG_CMD_EXT4=y
diff --git a/configs/conga-qeval20-qa3-e3845-internal-uart_defconfig b/configs/conga-qeval20-qa3-e3845-internal-uart_defconfig
index 14f00b6..656d575 100644
--- a/configs/conga-qeval20-qa3-e3845-internal-uart_defconfig
+++ b/configs/conga-qeval20-qa3-e3845-internal-uart_defconfig
@@ -44,7 +44,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_BOOTSTAGE=y
diff --git a/configs/conga-qeval20-qa3-e3845_defconfig b/configs/conga-qeval20-qa3-e3845_defconfig
index 613dcd3..54dc59e 100644
--- a/configs/conga-qeval20-qa3-e3845_defconfig
+++ b/configs/conga-qeval20-qa3-e3845_defconfig
@@ -40,7 +40,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_BOOTSTAGE=y
diff --git a/configs/coreboot64_defconfig b/configs/coreboot64_defconfig
index 60a1924..8aadaa6 100644
--- a/configs/coreboot64_defconfig
+++ b/configs/coreboot64_defconfig
@@ -30,7 +30,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_SOUND=y
diff --git a/configs/coreboot_defconfig b/configs/coreboot_defconfig
index 058caf0..fc935610 100644
--- a/configs/coreboot_defconfig
+++ b/configs/coreboot_defconfig
@@ -1,5 +1,6 @@
 CONFIG_X86=y
 CONFIG_TEXT_BASE=0x1110000
+CONFIG_SYS_MALLOC_LEN=0x2000000
 CONFIG_NR_DRAM_BANKS=8
 CONFIG_ENV_SIZE=0x1000
 CONFIG_DEFAULT_DEVICE_TREE="coreboot"
@@ -8,12 +9,11 @@
 CONFIG_TARGET_COREBOOT=y
 CONFIG_FIT=y
 CONFIG_FIT_SIGNATURE=y
+CONFIG_BOOTSTD_FULL=y
 CONFIG_SYS_MONITOR_BASE=0x01110000
 CONFIG_SHOW_BOOT_PROGRESS=y
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
-CONFIG_USE_BOOTCOMMAND=y
-CONFIG_BOOTCOMMAND="ext2load scsi 0:3 01000000 /boot/vmlinuz; zboot 01000000"
 CONFIG_PRE_CONSOLE_BUFFER=y
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_LOG=y
@@ -23,16 +23,12 @@
 CONFIG_LAST_STAGE_INIT=y
 CONFIG_PCI_INIT_R=y
 CONFIG_HUSH_PARSER=y
-CONFIG_SYS_PBSIZE=532
-CONFIG_CMD_MEM_SEARCH=y
-CONFIG_CMD_IDE=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PART=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_SOUND=y
@@ -53,13 +49,6 @@
 CONFIG_REGMAP=y
 CONFIG_SYSCON=y
 # CONFIG_ACPIGEN is not set
-CONFIG_SYS_IDE_MAXDEVICE=4
-CONFIG_SYS_ATA_DATA_OFFSET=0
-CONFIG_SYS_ATA_REG_OFFSET=0
-CONFIG_SYS_ATA_ALT_OFFSET=0
-CONFIG_ATAPI=y
-CONFIG_LBA48=y
-CONFIG_SYS_64BIT_LBA=y
 CONFIG_NVME_PCI=y
 # CONFIG_PCI_PNP is not set
 CONFIG_SOUND=y
diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
index a8a79fd..d3513b9 100644
--- a/configs/corstone1000_defconfig
+++ b/configs/corstone1000_defconfig
@@ -36,7 +36,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_RTC=y
 CONFIG_CMD_TIME=y
diff --git a/configs/cougarcanyon2_defconfig b/configs/cougarcanyon2_defconfig
index 47834bb..da5ff55 100644
--- a/configs/cougarcanyon2_defconfig
+++ b/configs/cougarcanyon2_defconfig
@@ -31,7 +31,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT2=y
diff --git a/configs/crownbay_defconfig b/configs/crownbay_defconfig
index 69ad017..70e1a50 100644
--- a/configs/crownbay_defconfig
+++ b/configs/crownbay_defconfig
@@ -33,7 +33,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_SOUND=y
diff --git a/configs/dalmore_defconfig b/configs/dalmore_defconfig
index 936787b..92f4436 100644
--- a/configs/dalmore_defconfig
+++ b/configs/dalmore_defconfig
@@ -36,7 +36,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/dfi-bt700-q7x-151_defconfig b/configs/dfi-bt700-q7x-151_defconfig
index 14e6e6c..9313e7f 100644
--- a/configs/dfi-bt700-q7x-151_defconfig
+++ b/configs/dfi-bt700-q7x-151_defconfig
@@ -38,7 +38,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_BOOTSTAGE=y
diff --git a/configs/edison_defconfig b/configs/edison_defconfig
index 00342aa..8692a8a 100644
--- a/configs/edison_defconfig
+++ b/configs/edison_defconfig
@@ -28,7 +28,6 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PART=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_TIMER=y
 CONFIG_CMD_HASH=y
 CONFIG_CMD_EXT4=y
diff --git a/configs/efi-x86_payload32_defconfig b/configs/efi-x86_payload32_defconfig
index a5c629b..4149eea 100644
--- a/configs/efi-x86_payload32_defconfig
+++ b/configs/efi-x86_payload32_defconfig
@@ -25,7 +25,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT2=y
diff --git a/configs/efi-x86_payload64_defconfig b/configs/efi-x86_payload64_defconfig
index 5cde04a..d41f73c 100644
--- a/configs/efi-x86_payload64_defconfig
+++ b/configs/efi-x86_payload64_defconfig
@@ -25,7 +25,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT2=y
diff --git a/configs/galileo_defconfig b/configs/galileo_defconfig
index 0d2ebda..c6d989e 100644
--- a/configs/galileo_defconfig
+++ b/configs/galileo_defconfig
@@ -29,7 +29,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_EXT2=y
diff --git a/configs/gazerbeam_defconfig b/configs/gazerbeam_defconfig
index c8c8469..7901a19 100644
--- a/configs/gazerbeam_defconfig
+++ b/configs/gazerbeam_defconfig
@@ -123,7 +123,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_AXI=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 CONFIG_CMD_CACHE=y
diff --git a/configs/ge_bx50v3_defconfig b/configs/ge_bx50v3_defconfig
index f005e91..2ef560c 100644
--- a/configs/ge_bx50v3_defconfig
+++ b/configs/ge_bx50v3_defconfig
@@ -34,7 +34,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PCI=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_BMP=y
 CONFIG_CMD_BOOTCOUNT=y
 CONFIG_CMD_CACHE=y
diff --git a/configs/harmony_defconfig b/configs/harmony_defconfig
index b1d9399..8b49505 100644
--- a/configs/harmony_defconfig
+++ b/configs/harmony_defconfig
@@ -31,7 +31,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
diff --git a/configs/imx28_xea_defconfig b/configs/imx28_xea_defconfig
index 06dd6b1..96d15e8 100644
--- a/configs/imx28_xea_defconfig
+++ b/configs/imx28_xea_defconfig
@@ -14,6 +14,9 @@
 CONFIG_DEFAULT_DEVICE_TREE="imx28-xea"
 CONFIG_SPL_TEXT_BASE=0x1000
 CONFIG_TARGET_XEA=y
+CONFIG_SPL_MXS_PMU_MINIMAL_VDD5V_CURRENT=y
+CONFIG_SPL_MXS_PMU_DISABLE_BATT_CHARGE=y
+# CONFIG_SPL_MXS_PMU_ENABLE_4P2_LINEAR_REGULATOR is not set
 CONFIG_SPL_MMC=y
 CONFIG_SPL_SERIAL=y
 CONFIG_SPL_STACK=0x20000
@@ -26,6 +29,8 @@
 CONFIG_SPL_PAYLOAD="u-boot.img"
 CONFIG_FIT=y
 CONFIG_TIMESTAMP=y
+# CONFIG_BOOTMETH_EXTLINUX is not set
+# CONFIG_BOOTMETH_VBE is not set
 CONFIG_OF_BOARD_SETUP=y
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="console=ttyAMA0,115200n8"
@@ -95,7 +100,7 @@
 CONFIG_MTD=y
 CONFIG_DM_MTD=y
 CONFIG_DM_SPI_FLASH=y
-CONFIG_SF_DEFAULT_BUS=3
+CONFIG_SF_DEFAULT_BUS=2
 CONFIG_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPI_FLASH_ISSI=y
 CONFIG_SPI_FLASH_SPANSION=y
@@ -113,9 +118,9 @@
 CONFIG_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
-CONFIG_CONS_INDEX=0
+CONFIG_SPECIFY_CONSOLE_INDEX=y
+CONFIG_DM_SERIAL=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_MXS_SPI=y
-CONFIG_FS_FAT=y
 # CONFIG_SPL_OF_LIBFDT is not set
diff --git a/configs/imx28_xea_sb_defconfig b/configs/imx28_xea_sb_defconfig
index bb7bf5d..a431834 100644
--- a/configs/imx28_xea_sb_defconfig
+++ b/configs/imx28_xea_sb_defconfig
@@ -94,7 +94,9 @@
 CONFIG_DM_REGULATOR=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
+CONFIG_SPECIFY_CONSOLE_INDEX=y
 CONFIG_CONS_INDEX=0
+CONFIG_DM_SERIAL=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_MXS_SPI=y
diff --git a/configs/imx8mm_beacon_defconfig b/configs/imx8mm_beacon_defconfig
index bb02b9b..52edb2e 100644
--- a/configs/imx8mm_beacon_defconfig
+++ b/configs/imx8mm_beacon_defconfig
@@ -5,6 +5,7 @@
 CONFIG_SPL_GPIO=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_ENV_SOURCE_FILE="imx8mm_beacon"
 CONFIG_SF_DEFAULT_SPEED=10000000
 CONFIG_ENV_SIZE=0x2000
 CONFIG_ENV_OFFSET=0xFFFFDE00
diff --git a/configs/imx8mm_beacon_fspi_defconfig b/configs/imx8mm_beacon_fspi_defconfig
new file mode 100644
index 0000000..805fd3f
--- /dev/null
+++ b/configs/imx8mm_beacon_fspi_defconfig
@@ -0,0 +1,155 @@
+CONFIG_ARM=y
+CONFIG_ARCH_IMX8M=y
+CONFIG_TEXT_BASE=0x40200000
+CONFIG_SYS_MALLOC_LEN=0x2000000
+CONFIG_SPL_GPIO=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_ENV_SIZE=0x2000
+CONFIG_ENV_OFFSET=0xFFFFDE00
+CONFIG_IMX_CONFIG="board/freescale/imx8mm_evk/imximage-8mm-lpddr4-fspi.cfg"
+CONFIG_DM_GPIO=y
+CONFIG_DEFAULT_DEVICE_TREE="imx8mm-beacon-kit"
+CONFIG_SPL_TEXT_BASE=0x7E2000
+CONFIG_TARGET_IMX8MM_BEACON=y
+CONFIG_SYS_PROMPT="u-boot=> "
+CONFIG_SPL_SERIAL=y
+CONFIG_SPL_DRIVERS_MISC=y
+CONFIG_SPL=y
+CONFIG_SYS_LOAD_ADDR=0x40480000
+CONFIG_LTO=y
+CONFIG_SYS_MONITOR_LEN=524288
+CONFIG_FIT=y
+CONFIG_FIT_EXTERNAL_OFFSET=0x3000
+CONFIG_SPL_LOAD_FIT=y
+# CONFIG_USE_SPL_FIT_GENERATOR is not set
+CONFIG_OF_SYSTEM_SETUP=y
+CONFIG_USE_BOOTCOMMAND=y
+CONFIG_BOOTCOMMAND="mmc dev ${mmcdev}; if mmc rescan; then if run loadbootscript; then run bootscript; else if run loadimage; then run mmcboot; else run netboot; fi; fi; fi;"
+CONFIG_DEFAULT_FDT_FILE="imx8mm-beacon-kit.dtb"
+CONFIG_SPL_MAX_SIZE=0x25000
+CONFIG_SPL_PAD_TO=0x0
+CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
+CONFIG_SPL_BSS_START_ADDR=0x910000
+CONFIG_SPL_BSS_MAX_SIZE=0x2000
+CONFIG_SPL_BOARD_INIT=y
+# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
+CONFIG_SPL_STACK=0x920000
+CONFIG_SYS_SPL_MALLOC=y
+CONFIG_HAS_CUSTOM_SPL_MALLOC_START=y
+CONFIG_CUSTOM_SYS_SPL_MALLOC_ADDR=0x42200000
+CONFIG_SYS_SPL_MALLOC_SIZE=0x80000
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x300
+CONFIG_SPL_CRC32=y
+CONFIG_SPL_I2C=y
+CONFIG_SPL_NOR_SUPPORT=y
+CONFIG_SPL_POWER=y
+CONFIG_SPL_USB_HOST=y
+CONFIG_SPL_USB_GADGET=y
+CONFIG_SPL_USB_SDP_SUPPORT=y
+CONFIG_SPL_WATCHDOG=y
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_MAXARGS=64
+CONFIG_SYS_CBSIZE=2048
+CONFIG_SYS_PBSIZE=2074
+CONFIG_SYS_BOOTM_LEN=0x800000
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_CRC32 is not set
+CONFIG_CMD_CLK=y
+CONFIG_CMD_FUSE=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_USB_SDP=y
+CONFIG_CMD_USB_MASS_STORAGE=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_CMD_FAT=y
+CONFIG_OF_CONTROL=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_SYS_MMC_ENV_DEV=2
+CONFIG_SYS_MMC_ENV_PART=2
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_USE_ETHPRIME=y
+CONFIG_ETHPRIME="FEC"
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_SPL_DM=y
+CONFIG_SPL_CLK_COMPOSITE_CCF=y
+CONFIG_CLK_COMPOSITE_CCF=y
+CONFIG_SPL_CLK_IMX8MM=y
+CONFIG_CLK_IMX8MM=y
+CONFIG_MXC_GPIO=y
+CONFIG_DM_PCA953X=y
+CONFIG_DM_I2C=y
+CONFIG_SUPPORT_EMMC_BOOT=y
+CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_MMC_UHS_SUPPORT=y
+CONFIG_MMC_HS400_ES_SUPPORT=y
+CONFIG_MMC_HS400_SUPPORT=y
+CONFIG_FSL_USDHC=y
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SF_DEFAULT_MODE=0
+CONFIG_SF_DEFAULT_SPEED=40000000
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHYLIB=y
+CONFIG_PHY_ATHEROS=y
+CONFIG_PHY_GIGE=y
+CONFIG_FEC_MXC=y
+CONFIG_MII=y
+CONFIG_SPL_PHY=y
+CONFIG_SPL_NOP_PHY=y
+CONFIG_PINCTRL=y
+CONFIG_SPL_PINCTRL=y
+CONFIG_PINCTRL_IMX8M=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_IMX8M_POWER_DOMAIN=y
+CONFIG_DM_PMIC=y
+# CONFIG_SPL_PMIC_CHILDREN is not set
+CONFIG_DM_PMIC_BD71837=y
+CONFIG_SPL_DM_PMIC_BD71837=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_BD71837=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_GPIO=y
+CONFIG_DM_SERIAL=y
+CONFIG_MXC_UART=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_NXP_FSPI=y
+CONFIG_SYSRESET=y
+CONFIG_SPL_SYSRESET=y
+CONFIG_SYSRESET_PSCI=y
+CONFIG_SYSRESET_WATCHDOG=y
+CONFIG_DM_THERMAL=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_MXC_USB_OTG_HACTIVE=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VENDOR_NUM=0x0525
+CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
+CONFIG_CI_UDC=y
+CONFIG_SDP_LOADADDR=0x40400000
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_IMX_WATCHDOG=y
+CONFIG_FSPI_CONF_HEADER=y
+CONFIG_FSPI_CONF_FILE="fspi_header.bin"
diff --git a/configs/imx8mm_venice_defconfig b/configs/imx8mm_venice_defconfig
index 9d0d0ee..a485910 100644
--- a/configs/imx8mm_venice_defconfig
+++ b/configs/imx8mm_venice_defconfig
@@ -6,7 +6,7 @@
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
 CONFIG_ENV_SIZE=0x8000
-CONFIG_ENV_OFFSET=0xff0000
+CONFIG_ENV_OFFSET=0x3f0000
 CONFIG_DM_GPIO=y
 CONFIG_DEFAULT_DEVICE_TREE="imx8mm-venice"
 CONFIG_SPL_TEXT_BASE=0x7E1000
@@ -19,7 +19,7 @@
 CONFIG_SPL_DRIVERS_MISC=y
 CONFIG_SPL_STACK=0x920000
 CONFIG_SPL=y
-CONFIG_ENV_OFFSET_REDUND=0xff8000
+CONFIG_ENV_OFFSET_REDUND=0x3f8000
 CONFIG_SYS_LOAD_ADDR=0x48200000
 CONFIG_SYS_MEMTEST_START=0x40000000
 CONFIG_SYS_MEMTEST_END=0x80000000
@@ -36,6 +36,7 @@
 CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
 CONFIG_SPL_BSS_START_ADDR=0x910000
 CONFIG_SPL_BSS_MAX_SIZE=0x2000
+CONFIG_SPL_BOARD_INIT=y
 # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
 CONFIG_SYS_SPL_MALLOC=y
 CONFIG_HAS_CUSTOM_SPL_MALLOC_START=y
@@ -51,6 +52,7 @@
 CONFIG_SYS_BOOTM_LEN=0x10000000
 # CONFIG_CMD_EXPORTENV is not set
 # CONFIG_CMD_IMPORTENV is not set
+CONFIG_CMD_ERASEENV=y
 CONFIG_CRC32_VERIFY=y
 CONFIG_CMD_MD5SUM=y
 CONFIG_MD5SUM_VERIFY=y
@@ -89,6 +91,7 @@
 CONFIG_SPL_CLK_IMX8MM=y
 CONFIG_CLK_IMX8MM=y
 CONFIG_GPIO_HOG=y
+CONFIG_DM_GPIO_LOOKUP_LABEL=y
 CONFIG_MXC_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_LED=y
diff --git a/configs/imx8mn_beacon_2g_defconfig b/configs/imx8mn_beacon_2g_defconfig
index 494085b..00e7cd0 100644
--- a/configs/imx8mn_beacon_2g_defconfig
+++ b/configs/imx8mn_beacon_2g_defconfig
@@ -5,6 +5,7 @@
 CONFIG_SPL_GPIO=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_ENV_SOURCE_FILE="imx8mn_beacon"
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SF_DEFAULT_SPEED=40000000
 CONFIG_ENV_SIZE=0x2000
diff --git a/configs/imx8mn_beacon_defconfig b/configs/imx8mn_beacon_defconfig
index 629025a..d9a413f 100644
--- a/configs/imx8mn_beacon_defconfig
+++ b/configs/imx8mn_beacon_defconfig
@@ -5,6 +5,7 @@
 CONFIG_SPL_GPIO=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_ENV_SOURCE_FILE="imx8mn_beacon"
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SF_DEFAULT_SPEED=40000000
 CONFIG_ENV_SIZE=0x2000
diff --git a/configs/imx8mn_beacon_fspi_defconfig b/configs/imx8mn_beacon_fspi_defconfig
index dade877..6c626ae 100644
--- a/configs/imx8mn_beacon_fspi_defconfig
+++ b/configs/imx8mn_beacon_fspi_defconfig
@@ -5,6 +5,7 @@
 CONFIG_SPL_GPIO=y
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_ENV_SOURCE_FILE="imx8mn_beacon"
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_SF_DEFAULT_SPEED=40000000
 CONFIG_ENV_SIZE=0x2000
diff --git a/configs/imx8mn_var_som_defconfig b/configs/imx8mn_var_som_defconfig
index 350c022..b346b14 100644
--- a/configs/imx8mn_var_som_defconfig
+++ b/configs/imx8mn_var_som_defconfig
@@ -23,12 +23,15 @@
 CONFIG_SPL=y
 CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
 CONFIG_SYS_LOAD_ADDR=0x40480000
+CONFIG_OF_BOARD_FIXUP=y
 CONFIG_FIT=y
 CONFIG_FIT_EXTERNAL_OFFSET=0x3000
 CONFIG_SPL_LOAD_FIT=y
+CONFIG_OF_BOARD_SETUP=y
 CONFIG_OF_SYSTEM_SETUP=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_DEFAULT_FDT_FILE="freescale/imx8mn-var-som-symphony.dtb"
+CONFIG_BOARD_TYPES=y
 CONFIG_ARCH_MISC_INIT=y
 CONFIG_SPL_MAX_SIZE=0x25000
 CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
@@ -76,6 +79,7 @@
 CONFIG_FASTBOOT_UUU_SUPPORT=y
 CONFIG_FASTBOOT_FLASH_MMC_DEV=2
 CONFIG_MXC_GPIO=y
+CONFIG_DM_PCA953X=y
 CONFIG_DM_I2C=y
 CONFIG_SUPPORT_EMMC_BOOT=y
 CONFIG_MMC_IO_VOLTAGE=y
diff --git a/configs/imx8mn_venice_defconfig b/configs/imx8mn_venice_defconfig
index 3974a38..39f930a 100644
--- a/configs/imx8mn_venice_defconfig
+++ b/configs/imx8mn_venice_defconfig
@@ -6,7 +6,7 @@
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
 CONFIG_ENV_SIZE=0x8000
-CONFIG_ENV_OFFSET=0xff0000
+CONFIG_ENV_OFFSET=0x3f0000
 CONFIG_DM_GPIO=y
 CONFIG_DEFAULT_DEVICE_TREE="imx8mn-venice"
 CONFIG_SPL_TEXT_BASE=0x912000
@@ -19,7 +19,7 @@
 CONFIG_SPL_DRIVERS_MISC=y
 CONFIG_SPL_STACK=0x980000
 CONFIG_SPL=y
-CONFIG_ENV_OFFSET_REDUND=0xff8000
+CONFIG_ENV_OFFSET_REDUND=0x3f8000
 CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
 CONFIG_SYS_LOAD_ADDR=0x48200000
 CONFIG_SYS_MEMTEST_START=0x40000000
@@ -38,6 +38,7 @@
 CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
 CONFIG_SPL_BSS_START_ADDR=0x950000
 CONFIG_SPL_BSS_MAX_SIZE=0x2000
+CONFIG_SPL_BOARD_INIT=y
 CONFIG_SPL_BOOTROM_SUPPORT=y
 # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
 CONFIG_SYS_SPL_MALLOC=y
@@ -54,6 +55,7 @@
 CONFIG_SYS_BOOTM_LEN=0x10000000
 # CONFIG_CMD_EXPORTENV is not set
 # CONFIG_CMD_IMPORTENV is not set
+CONFIG_CMD_ERASEENV=y
 CONFIG_CRC32_VERIFY=y
 CONFIG_CMD_MD5SUM=y
 CONFIG_MD5SUM_VERIFY=y
@@ -90,6 +92,7 @@
 CONFIG_SPL_CLK_IMX8MN=y
 CONFIG_CLK_IMX8MN=y
 CONFIG_GPIO_HOG=y
+CONFIG_DM_GPIO_LOOKUP_LABEL=y
 CONFIG_MXC_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_LED=y
diff --git a/configs/imx8mp_beacon_defconfig b/configs/imx8mp_beacon_defconfig
index 99c4043..77a10b9 100644
--- a/configs/imx8mp_beacon_defconfig
+++ b/configs/imx8mp_beacon_defconfig
@@ -18,6 +18,7 @@
 CONFIG_TARGET_IMX8MP_BEACON=y
 CONFIG_SYS_PROMPT="u-boot=> "
 CONFIG_SYS_MONITOR_LEN=524288
+CONFIG_LTO=y
 CONFIG_SPL_MMC=y
 CONFIG_SPL_SERIAL=y
 CONFIG_SPL_DRIVERS_MISC=y
diff --git a/configs/imx8mp_venice_defconfig b/configs/imx8mp_venice_defconfig
index a6f6ec6..294206b 100644
--- a/configs/imx8mp_venice_defconfig
+++ b/configs/imx8mp_venice_defconfig
@@ -6,7 +6,7 @@
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
 CONFIG_ENV_SIZE=0x8000
-CONFIG_ENV_OFFSET=0xff0000
+CONFIG_ENV_OFFSET=0x3f0000
 CONFIG_DM_GPIO=y
 CONFIG_DEFAULT_DEVICE_TREE="imx8mp-venice"
 CONFIG_SPL_TEXT_BASE=0x920000
@@ -19,7 +19,7 @@
 CONFIG_SPL_DRIVERS_MISC=y
 CONFIG_SPL_STACK=0x960000
 CONFIG_SPL=y
-CONFIG_ENV_OFFSET_REDUND=0xff8000
+CONFIG_ENV_OFFSET_REDUND=0x3f8000
 CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
 CONFIG_SYS_LOAD_ADDR=0x40480000
 CONFIG_SYS_MEMTEST_START=0x40000000
@@ -38,6 +38,7 @@
 CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
 CONFIG_SPL_BSS_START_ADDR=0x98fc00
 CONFIG_SPL_BSS_MAX_SIZE=0x400
+CONFIG_SPL_BOARD_INIT=y
 CONFIG_SPL_BOOTROM_SUPPORT=y
 # CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
 CONFIG_SYS_SPL_MALLOC=y
@@ -54,6 +55,7 @@
 CONFIG_SYS_BOOTM_LEN=0x10000000
 # CONFIG_CMD_EXPORTENV is not set
 # CONFIG_CMD_IMPORTENV is not set
+CONFIG_CMD_ERASEENV=y
 CONFIG_CRC32_VERIFY=y
 CONFIG_CMD_MD5SUM=y
 CONFIG_MD5SUM_VERIFY=y
@@ -75,7 +77,7 @@
 # CONFIG_SPL_EFI_PARTITION is not set
 CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
-CONFIG_OF_LIST="imx8mp-venice imx8mp-venice-gw74xx"
+CONFIG_OF_LIST="imx8mp-venice imx8mp-venice-gw74xx imx8mp-venice-gw7905-2x"
 CONFIG_ENV_IS_IN_MMC=y
 CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
 CONFIG_SYS_MMC_ENV_DEV=2
@@ -87,6 +89,7 @@
 CONFIG_CLK_COMPOSITE_CCF=y
 CONFIG_CLK_IMX8MP=y
 CONFIG_GPIO_HOG=y
+CONFIG_DM_GPIO_LOOKUP_LABEL=y
 CONFIG_MXC_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_LED=y
diff --git a/configs/imx93_11x11_evk_defconfig b/configs/imx93_11x11_evk_defconfig
index 0de563f..65f4738 100644
--- a/configs/imx93_11x11_evk_defconfig
+++ b/configs/imx93_11x11_evk_defconfig
@@ -81,6 +81,7 @@
 CONFIG_SPL_DM=y
 CONFIG_REGMAP=y
 CONFIG_SYSCON=y
+CONFIG_ADC_IMX93=y
 CONFIG_CPU=y
 CONFIG_CPU_IMX=y
 CONFIG_IMX_RGPIO2P=y
diff --git a/configs/jetson-tk1_defconfig b/configs/jetson-tk1_defconfig
index b2a39e0..d808628 100644
--- a/configs/jetson-tk1_defconfig
+++ b/configs/jetson-tk1_defconfig
@@ -40,7 +40,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/malta64_defconfig b/configs/malta64_defconfig
index 03de161..a69e193 100644
--- a/configs/malta64_defconfig
+++ b/configs/malta64_defconfig
@@ -26,7 +26,6 @@
 CONFIG_CMD_PCI=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_DATE=y
 # CONFIG_ISO_PARTITION is not set
diff --git a/configs/malta64el_defconfig b/configs/malta64el_defconfig
index 3ea9fa9..21a291d 100644
--- a/configs/malta64el_defconfig
+++ b/configs/malta64el_defconfig
@@ -28,7 +28,6 @@
 CONFIG_CMD_PCI=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_DATE=y
 # CONFIG_ISO_PARTITION is not set
diff --git a/configs/malta_defconfig b/configs/malta_defconfig
index 317b422..8c76ebb 100644
--- a/configs/malta_defconfig
+++ b/configs/malta_defconfig
@@ -25,7 +25,6 @@
 CONFIG_CMD_PCI=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_DATE=y
 # CONFIG_ISO_PARTITION is not set
diff --git a/configs/maltael_defconfig b/configs/maltael_defconfig
index 3e4d2be..4abd3b1 100644
--- a/configs/maltael_defconfig
+++ b/configs/maltael_defconfig
@@ -27,7 +27,6 @@
 CONFIG_CMD_PCI=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_DATE=y
 # CONFIG_ISO_PARTITION is not set
diff --git a/configs/medcom-wide_defconfig b/configs/medcom-wide_defconfig
index 47fcf15..e99bb8f 100644
--- a/configs/medcom-wide_defconfig
+++ b/configs/medcom-wide_defconfig
@@ -31,7 +31,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig
index 6082b8d..8347a9d 100644
--- a/configs/minnowmax_defconfig
+++ b/configs/minnowmax_defconfig
@@ -43,7 +43,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_BOOTSTAGE=y
diff --git a/configs/mscc_jr2_defconfig b/configs/mscc_jr2_defconfig
index b30b804..e3ff906 100644
--- a/configs/mscc_jr2_defconfig
+++ b/configs/mscc_jr2_defconfig
@@ -44,7 +44,6 @@
 CONFIG_CMD_SPI=y
 CONFIG_CMD_DHCP=y
 # CONFIG_NET_TFTP_VARS is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_MTDPARTS=y
 CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
diff --git a/configs/mscc_luton_defconfig b/configs/mscc_luton_defconfig
index 9a1e0c3..e811bc9 100644
--- a/configs/mscc_luton_defconfig
+++ b/configs/mscc_luton_defconfig
@@ -46,7 +46,6 @@
 CONFIG_CMD_SPI=y
 CONFIG_CMD_DHCP=y
 # CONFIG_NET_TFTP_VARS is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_MTDPARTS=y
diff --git a/configs/mscc_ocelot_defconfig b/configs/mscc_ocelot_defconfig
index a372b21..f3246f2 100644
--- a/configs/mscc_ocelot_defconfig
+++ b/configs/mscc_ocelot_defconfig
@@ -44,7 +44,6 @@
 CONFIG_CMD_SPI=y
 CONFIG_CMD_DHCP=y
 # CONFIG_NET_TFTP_VARS is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_MTDPARTS=y
 CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
diff --git a/configs/mscc_serval_defconfig b/configs/mscc_serval_defconfig
index 055ed68..4ff7933 100644
--- a/configs/mscc_serval_defconfig
+++ b/configs/mscc_serval_defconfig
@@ -41,7 +41,6 @@
 CONFIG_CMD_SPI=y
 CONFIG_CMD_DHCP=y
 # CONFIG_NET_TFTP_VARS is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_MTDPARTS=y
 CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
diff --git a/configs/mscc_servalt_defconfig b/configs/mscc_servalt_defconfig
index 6e225a6..5f6ed73 100644
--- a/configs/mscc_servalt_defconfig
+++ b/configs/mscc_servalt_defconfig
@@ -40,7 +40,6 @@
 CONFIG_CMD_SPI=y
 CONFIG_CMD_DHCP=y
 # CONFIG_NET_TFTP_VARS is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_MTDPARTS=y
 CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
diff --git a/configs/mt7620_mt7530_rfb_defconfig b/configs/mt7620_mt7530_rfb_defconfig
index 96f1092..af9df54 100644
--- a/configs/mt7620_mt7530_rfb_defconfig
+++ b/configs/mt7620_mt7530_rfb_defconfig
@@ -38,7 +38,6 @@
 CONFIG_CMD_GPIO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 # CONFIG_CMD_MDIO is not set
 CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clocks clock-names interrupt-parent interrupts resets reset-names"
diff --git a/configs/mt7620_rfb_defconfig b/configs/mt7620_rfb_defconfig
index d96da91d..fe57fd1 100644
--- a/configs/mt7620_rfb_defconfig
+++ b/configs/mt7620_rfb_defconfig
@@ -39,7 +39,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 # CONFIG_CMD_MDIO is not set
 CONFIG_CMD_FAT=y
diff --git a/configs/mt7621_nand_rfb_defconfig b/configs/mt7621_nand_rfb_defconfig
index 5291bb3..368bf80 100644
--- a/configs/mt7621_nand_rfb_defconfig
+++ b/configs/mt7621_nand_rfb_defconfig
@@ -49,7 +49,6 @@
 CONFIG_CMD_PART=y
 # CONFIG_CMD_PINMUX is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 # CONFIG_SPL_DOS_PARTITION is not set
diff --git a/configs/mt7621_rfb_defconfig b/configs/mt7621_rfb_defconfig
index b50fbec..49c9e74 100644
--- a/configs/mt7621_rfb_defconfig
+++ b/configs/mt7621_rfb_defconfig
@@ -47,7 +47,6 @@
 CONFIG_CMD_PART=y
 # CONFIG_CMD_PINMUX is not set
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NFS is not set
 CONFIG_DOS_PARTITION=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_ISO_PARTITION is not set
diff --git a/configs/mt7623a_unielec_u7623_02_defconfig b/configs/mt7623a_unielec_u7623_02_defconfig
index a7687b5..20c84d6 100644
--- a/configs/mt7623a_unielec_u7623_02_defconfig
+++ b/configs/mt7623a_unielec_u7623_02_defconfig
@@ -31,7 +31,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_READ=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_ENV_IS_IN_MMC=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig
index 62a17f2..5e7c1fe 100644
--- a/configs/mt7623n_bpir2_defconfig
+++ b/configs/mt7623n_bpir2_defconfig
@@ -31,7 +31,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_READ=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_ENV_OVERWRITE=y
 CONFIG_ENV_IS_IN_MMC=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
diff --git a/configs/mt7628_rfb_defconfig b/configs/mt7628_rfb_defconfig
index 0e100fc..7e5b76c 100644
--- a/configs/mt7628_rfb_defconfig
+++ b/configs/mt7628_rfb_defconfig
@@ -37,7 +37,6 @@
 CONFIG_CMD_GPIO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NFS is not set
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig
index ea8d77c..0e3bd4f 100644
--- a/configs/mt7629_rfb_defconfig
+++ b/configs/mt7629_rfb_defconfig
@@ -48,7 +48,6 @@
 CONFIG_CMD_SF_TEST=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
diff --git a/configs/mx23_olinuxino_defconfig b/configs/mx23_olinuxino_defconfig
index 89b69fb..24968e1 100644
--- a/configs/mx23_olinuxino_defconfig
+++ b/configs/mx23_olinuxino_defconfig
@@ -50,6 +50,7 @@
 CONFIG_LED_STATUS_CMD=y
 CONFIG_MMC_MXS=y
 CONFIG_CONS_INDEX=0
+CONFIG_DM_SERIAL=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_HOST_ETHER=y
diff --git a/configs/mx23evk_defconfig b/configs/mx23evk_defconfig
index 3602ead..7d0e7cc 100644
--- a/configs/mx23evk_defconfig
+++ b/configs/mx23evk_defconfig
@@ -49,6 +49,7 @@
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_CONS_INDEX=0
+CONFIG_DM_SERIAL=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/mx28evk_defconfig b/configs/mx28evk_defconfig
index dad8839..df0ccea 100644
--- a/configs/mx28evk_defconfig
+++ b/configs/mx28evk_defconfig
@@ -62,6 +62,6 @@
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_RTC_MXS=y
-CONFIG_CONS_INDEX=0
+CONFIG_DM_SERIAL=y
 CONFIG_SPI=y
 CONFIG_USB=y
diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig
index a9c10cd..cc64fac 100644
--- a/configs/nyan-big_defconfig
+++ b/configs/nyan-big_defconfig
@@ -45,7 +45,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_BMP=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
diff --git a/configs/odroid_defconfig b/configs/odroid_defconfig
index ce0c47e..b1943cf 100644
--- a/configs/odroid_defconfig
+++ b/configs/odroid_defconfig
@@ -41,7 +41,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_CACHE=y
 # CONFIG_CMD_SLEEP is not set
 CONFIG_CMD_PMIC=y
diff --git a/configs/omap4_panda_defconfig b/configs/omap4_panda_defconfig
index e27e27d..5571722 100644
--- a/configs/omap4_panda_defconfig
+++ b/configs/omap4_panda_defconfig
@@ -33,7 +33,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_OF_CONTROL=y
 CONFIG_ENV_OVERWRITE=y
diff --git a/configs/omap4_sdp4430_defconfig b/configs/omap4_sdp4430_defconfig
index 909f10e..0a8a1c7 100644
--- a/configs/omap4_sdp4430_defconfig
+++ b/configs/omap4_sdp4430_defconfig
@@ -29,7 +29,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_EFI_PARTITION is not set
 CONFIG_SPL_PARTITION_UUIDS=y
diff --git a/configs/p2371-0000_defconfig b/configs/p2371-0000_defconfig
index 7e75f44..dcfd3eb 100644
--- a/configs/p2371-0000_defconfig
+++ b/configs/p2371-0000_defconfig
@@ -28,7 +28,6 @@
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_PREFER_SERVERIP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_ENV_OVERWRITE=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
diff --git a/configs/p2371-2180_defconfig b/configs/p2371-2180_defconfig
index 2543a2d..5b91631 100644
--- a/configs/p2371-2180_defconfig
+++ b/configs/p2371-2180_defconfig
@@ -34,7 +34,6 @@
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_PREFER_SERVERIP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_OF_LIVE=y
 CONFIG_ENV_OVERWRITE=y
diff --git a/configs/p2571_defconfig b/configs/p2571_defconfig
index 47a0a62..7e2829e 100644
--- a/configs/p2571_defconfig
+++ b/configs/p2571_defconfig
@@ -29,7 +29,6 @@
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_PREFER_SERVERIP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_ENV_OVERWRITE=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
diff --git a/configs/p2771-0000-000_defconfig b/configs/p2771-0000-000_defconfig
index e3b978e..ae23505 100644
--- a/configs/p2771-0000-000_defconfig
+++ b/configs/p2771-0000-000_defconfig
@@ -27,7 +27,6 @@
 CONFIG_CMD_SPI=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_PREFER_SERVERIP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_ENV_OVERWRITE=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
diff --git a/configs/p2771-0000-500_defconfig b/configs/p2771-0000-500_defconfig
index c99a24e..0ea4719 100644
--- a/configs/p2771-0000-500_defconfig
+++ b/configs/p2771-0000-500_defconfig
@@ -27,7 +27,6 @@
 CONFIG_CMD_SPI=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_PREFER_SERVERIP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_ENV_OVERWRITE=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
diff --git a/configs/p3450-0000_defconfig b/configs/p3450-0000_defconfig
index e280be8..b0d538f 100644
--- a/configs/p3450-0000_defconfig
+++ b/configs/p3450-0000_defconfig
@@ -35,7 +35,6 @@
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_PREFER_SERVERIP=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_OF_LIVE=y
 CONFIG_ENV_OVERWRITE=y
diff --git a/configs/paz00_defconfig b/configs/paz00_defconfig
index fadf7fd..8c125c3 100644
--- a/configs/paz00_defconfig
+++ b/configs/paz00_defconfig
@@ -28,7 +28,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
diff --git a/configs/phycore-imx8mm_defconfig b/configs/phycore-imx8mm_defconfig
index ffdb5cc..4a27d15 100644
--- a/configs/phycore-imx8mm_defconfig
+++ b/configs/phycore-imx8mm_defconfig
@@ -21,6 +21,7 @@
 CONFIG_SPL=y
 CONFIG_ENV_OFFSET_REDUND=0x3E0000
 CONFIG_SYS_LOAD_ADDR=0x40480000
+CONFIG_LTO=y
 CONFIG_FIT=y
 CONFIG_FIT_EXTERNAL_OFFSET=0x3000
 CONFIG_SPL_LOAD_FIT=y
diff --git a/configs/phycore-imx8mp_defconfig b/configs/phycore-imx8mp_defconfig
index 3d07620..7bf404b 100644
--- a/configs/phycore-imx8mp_defconfig
+++ b/configs/phycore-imx8mp_defconfig
@@ -21,6 +21,7 @@
 CONFIG_SPL=y
 CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
 CONFIG_SYS_LOAD_ADDR=0x40480000
+CONFIG_LTO=y
 CONFIG_FIT=y
 CONFIG_FIT_EXTERNAL_OFFSET=0x3000
 CONFIG_SPL_LOAD_FIT=y
diff --git a/configs/plutux_defconfig b/configs/plutux_defconfig
index 4fee9df..ab9aef5 100644
--- a/configs/plutux_defconfig
+++ b/configs/plutux_defconfig
@@ -32,7 +32,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/poleg_evb_defconfig b/configs/poleg_evb_defconfig
index b00fb48..cab589d 100644
--- a/configs/poleg_evb_defconfig
+++ b/configs/poleg_evb_defconfig
@@ -102,3 +102,6 @@
 CONFIG_WDT_NPCM=y
 CONFIG_LIB_HW_RAND=y
 CONFIG_SHA_HW_ACCEL=y
+CONFIG_FIT=y
+CONFIG_SHA256=y
+CONFIG_SHA512=y
diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig
index f29a5aa..4a15c51 100644
--- a/configs/qemu-x86_64_defconfig
+++ b/configs/qemu-x86_64_defconfig
@@ -6,30 +6,39 @@
 CONFIG_MAX_CPUS=2
 CONFIG_SPL_DM_SPI=y
 CONFIG_DEFAULT_DEVICE_TREE="qemu-x86_i440fx"
-CONFIG_SPL_TEXT_BASE=0xfffd0000
+CONFIG_SPL_TEXT_BASE=0xfffd8000
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000
 CONFIG_DEBUG_UART_BASE=0x3f8
 CONFIG_DEBUG_UART_CLOCK=1843200
 CONFIG_X86_RUN_64BIT=y
 CONFIG_TARGET_QEMU_X86_64=y
 CONFIG_DEBUG_UART=y
+# CONFIG_HAVE_MICROCODE is not set
 CONFIG_SMP=y
 CONFIG_GENERATE_PIRQ_TABLE=y
 CONFIG_GENERATE_MP_TABLE=y
 CONFIG_X86_OFFSET_U_BOOT=0xfff00000
 CONFIG_FIT=y
 CONFIG_SPL_LOAD_FIT=y
+CONFIG_BOOTSTD_FULL=y
 CONFIG_SYS_MONITOR_BASE=0x01110000
-CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTSTD_DEFAULTS=y
 CONFIG_BOOTSTAGE=y
 CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_SHOW_BOOT_PROGRESS=y
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_LOG=y
+CONFIG_LOGF_FUNC=y
+CONFIG_SPL_LOG=y
 CONFIG_DISPLAY_BOARDINFO_LATE=y
 CONFIG_LAST_STAGE_INIT=y
 CONFIG_PCI_INIT_R=y
+CONFIG_BLOBLIST=y
+CONFIG_BLOBLIST_ADDR=0x10000
 CONFIG_SPL_NO_BSS_LIMIT=y
+CONFIG_SPL_BOARD_INIT=y
 CONFIG_SPL_SYS_MALLOC_SIMPLE=y
 CONFIG_SPL_CPU=y
 CONFIG_SPL_ENV_SUPPORT=y
@@ -42,12 +51,13 @@
 CONFIG_CMD_CPU=y
 CONFIG_CMD_BOOTEFI_SELFTEST=y
 CONFIG_CMD_NVEDIT_EFI=y
+CONFIG_CMD_MEM_SEARCH=y
 CONFIG_CMD_IDE=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
+CONFIG_CMD_EFIDEBUG=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_QFW=y
 CONFIG_CMD_BOOTSTAGE=y
@@ -69,13 +79,13 @@
 CONFIG_SYS_64BIT_LBA=y
 CONFIG_CPU=y
 CONFIG_NVME_PCI=y
+CONFIG_SPL_PCI_PNP=y
 CONFIG_SPL_DM_RTC=y
 CONFIG_SYS_NS16550_PORT_MAPPED=y
 CONFIG_SPI=y
 CONFIG_USB_KEYBOARD=y
-CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
-CONFIG_FRAMEBUFFER_VESA_MODE_USER=y
-CONFIG_FRAMEBUFFER_VESA_MODE=0x144
 CONFIG_CONSOLE_SCROLL_LINES=5
+CONFIG_FAT_BLK_XLATE=y
+# CONFIG_SPL_USE_TINY_PRINTF is not set
 CONFIG_GENERATE_ACPI_TABLE=y
 # CONFIG_GZIP is not set
diff --git a/configs/qemu-x86_defconfig b/configs/qemu-x86_defconfig
index 9bf2964..95a6ff9 100644
--- a/configs/qemu-x86_defconfig
+++ b/configs/qemu-x86_defconfig
@@ -9,7 +9,7 @@
 CONFIG_GENERATE_PIRQ_TABLE=y
 CONFIG_GENERATE_MP_TABLE=y
 CONFIG_FIT=y
-CONFIG_DISTRO_DEFAULTS=y
+CONFIG_BOOTSTD_DEFAULTS=y
 CONFIG_BOOTSTAGE=y
 CONFIG_BOOTSTAGE_REPORT=y
 CONFIG_SHOW_BOOT_PROGRESS=y
@@ -28,7 +28,6 @@
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_TIME=y
 CONFIG_CMD_QFW=y
 CONFIG_CMD_BOOTSTAGE=y
@@ -54,9 +53,6 @@
 CONFIG_SYS_NS16550_PORT_MAPPED=y
 CONFIG_SPI=y
 CONFIG_USB_KEYBOARD=y
-CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
-CONFIG_FRAMEBUFFER_VESA_MODE_USER=y
-CONFIG_FRAMEBUFFER_VESA_MODE=0x144
 CONFIG_CONSOLE_SCROLL_LINES=5
 CONFIG_GENERATE_ACPI_TABLE=y
 # CONFIG_GZIP is not set
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 98b3e0c..9bd81c1 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -51,6 +51,7 @@
 CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_LOADM=y
+CONFIG_CMD_MBR=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_READ=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 1ec44d5..19cc670 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -30,6 +30,7 @@
 CONFIG_AUTOBOOT_STOP_STR_CRYPT="$5$rounds=640000$HrpE65IkB8CM5nCL$BKT3QdF98Bo8fJpTr9tjZLZQyzqPASBY20xuK5Rent9"
 CONFIG_IMAGE_PRE_LOAD=y
 CONFIG_IMAGE_PRE_LOAD_SIG=y
+CONFIG_CEDIT=y
 CONFIG_CONSOLE_RECORD=y
 CONFIG_CONSOLE_RECORD_OUT_SIZE=0x6000
 CONFIG_PRE_CONSOLE_BUFFER=y
@@ -75,6 +76,7 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_LOADM=y
 CONFIG_CMD_LSBLK=y
+CONFIG_CMD_MBR=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_MUX=y
 CONFIG_CMD_OSD=y
@@ -131,6 +133,7 @@
 CONFIG_CMD_STACKPROTECTOR_TEST=y
 CONFIG_MAC_PARTITION=y
 CONFIG_AMIGA_PARTITION=y
+CONFIG_DOS_PARTITION=y
 CONFIG_OF_CONTROL=y
 CONFIG_OF_LIVE=y
 CONFIG_ENV_IS_NOWHERE=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index e7657d4..8aa2956 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -44,6 +44,7 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
+CONFIG_CMD_MBR=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig
index fc20317..2c6aab6 100644
--- a/configs/sandbox_noinst_defconfig
+++ b/configs/sandbox_noinst_defconfig
@@ -59,6 +59,7 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
+CONFIG_CMD_MBR=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_REMOTEPROC=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index dd848c5..8d50162 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -60,6 +60,7 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
+CONFIG_CMD_MBR=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_REMOTEPROC=y
diff --git a/configs/sandbox_vpl_defconfig b/configs/sandbox_vpl_defconfig
index 27971c0..f3a0fd1 100644
--- a/configs/sandbox_vpl_defconfig
+++ b/configs/sandbox_vpl_defconfig
@@ -75,6 +75,7 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
+CONFIG_CMD_MBR=y
 CONFIG_CMD_OSD=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_REMOTEPROC=y
diff --git a/configs/seaboard_defconfig b/configs/seaboard_defconfig
index 00cca91..f8759f2 100644
--- a/configs/seaboard_defconfig
+++ b/configs/seaboard_defconfig
@@ -31,7 +31,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
diff --git a/configs/smdkv310_defconfig b/configs/smdkv310_defconfig
index cc0ecad..2f466d2 100644
--- a/configs/smdkv310_defconfig
+++ b/configs/smdkv310_defconfig
@@ -27,7 +27,6 @@
 # CONFIG_CMD_XIMG is not set
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_CACHE=y
 # CONFIG_CMD_SLEEP is not set
 CONFIG_CMD_EXT4_WRITE=y
diff --git a/configs/sniper_defconfig b/configs/sniper_defconfig
index f6b59a6..c762d75 100644
--- a/configs/sniper_defconfig
+++ b/configs/sniper_defconfig
@@ -32,7 +32,6 @@
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_ENV_OVERWRITE=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_SYS_I2C_LEGACY=y
diff --git a/configs/socrates_defconfig b/configs/socrates_defconfig
index ba5990b..33092c7 100644
--- a/configs/socrates_defconfig
+++ b/configs/socrates_defconfig
@@ -57,7 +57,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 CONFIG_CMD_SNTP=y
diff --git a/configs/som-db5800-som-6867_defconfig b/configs/som-db5800-som-6867_defconfig
index ad95274..4a14913 100644
--- a/configs/som-db5800-som-6867_defconfig
+++ b/configs/som-db5800-som-6867_defconfig
@@ -38,7 +38,6 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_BOOTSTAGE=y
diff --git a/configs/tec-ng_defconfig b/configs/tec-ng_defconfig
index 442cee3..4776e92 100644
--- a/configs/tec-ng_defconfig
+++ b/configs/tec-ng_defconfig
@@ -34,7 +34,6 @@
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/tec_defconfig b/configs/tec_defconfig
index 461c46c..8a5d959 100644
--- a/configs/tec_defconfig
+++ b/configs/tec_defconfig
@@ -31,7 +31,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
diff --git a/configs/theadorable-x86-conga-qa3-e3845-pcie-x4_defconfig b/configs/theadorable-x86-conga-qa3-e3845-pcie-x4_defconfig
index 43dab09..69499e1 100644
--- a/configs/theadorable-x86-conga-qa3-e3845-pcie-x4_defconfig
+++ b/configs/theadorable-x86-conga-qa3-e3845-pcie-x4_defconfig
@@ -38,7 +38,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_BMP=y
 CONFIG_CMD_TIME=y
diff --git a/configs/theadorable-x86-conga-qa3-e3845_defconfig b/configs/theadorable-x86-conga-qa3-e3845_defconfig
index 5aec527..e2e64b7 100644
--- a/configs/theadorable-x86-conga-qa3-e3845_defconfig
+++ b/configs/theadorable-x86-conga-qa3-e3845_defconfig
@@ -37,7 +37,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_BMP=y
 CONFIG_CMD_TIME=y
diff --git a/configs/theadorable-x86-dfi-bt700_defconfig b/configs/theadorable-x86-dfi-bt700_defconfig
index d5a28a2..751ae34 100644
--- a/configs/theadorable-x86-dfi-bt700_defconfig
+++ b/configs/theadorable-x86-dfi-bt700_defconfig
@@ -35,7 +35,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_DHCP=y
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
 CONFIG_CMD_BMP=y
 CONFIG_CMD_TIME=y
diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig
index 2bc3bd9..3f588ea 100644
--- a/configs/tools-only_defconfig
+++ b/configs/tools-only_defconfig
@@ -10,6 +10,7 @@
 CONFIG_TIMESTAMP=y
 CONFIG_FIT_SIGNATURE=y
 # CONFIG_BOOTSTD_FULL is not set
+# CONFIG_BOOTMETH_CROS is not set
 # CONFIG_BOOTMETH_VBE is not set
 CONFIG_USE_BOOTCOMMAND=y
 CONFIG_BOOTCOMMAND="run distro_bootcmd"
diff --git a/configs/trimslice_defconfig b/configs/trimslice_defconfig
index d94a0b4..9ec08bd 100644
--- a/configs/trimslice_defconfig
+++ b/configs/trimslice_defconfig
@@ -35,7 +35,6 @@
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/venice2_defconfig b/configs/venice2_defconfig
index fd538da..ebd1754 100644
--- a/configs/venice2_defconfig
+++ b/configs/venice2_defconfig
@@ -36,7 +36,6 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_USB_MASS_STORAGE=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_EXT4_WRITE=y
 # CONFIG_SPL_DOS_PARTITION is not set
 # CONFIG_SPL_EFI_PARTITION is not set
diff --git a/configs/ventana_defconfig b/configs/ventana_defconfig
index 5e2ff87..2da8ba9 100644
--- a/configs/ventana_defconfig
+++ b/configs/ventana_defconfig
@@ -29,7 +29,6 @@
 CONFIG_CMD_MMC=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
diff --git a/configs/verdin-imx8mm_defconfig b/configs/verdin-imx8mm_defconfig
index 0eb1891..09e14c6 100644
--- a/configs/verdin-imx8mm_defconfig
+++ b/configs/verdin-imx8mm_defconfig
@@ -98,6 +98,7 @@
 CONFIG_SPL_CLK_IMX8MM=y
 CONFIG_CLK_IMX8MM=y
 CONFIG_GPIO_HOG=y
+CONFIG_SPL_GPIO_HOG=y
 CONFIG_MXC_GPIO=y
 CONFIG_DM_I2C=y
 CONFIG_MISC=y
diff --git a/configs/verdin-imx8mp_defconfig b/configs/verdin-imx8mp_defconfig
index f1fa2b8..2df0f4f 100644
--- a/configs/verdin-imx8mp_defconfig
+++ b/configs/verdin-imx8mp_defconfig
@@ -42,6 +42,7 @@
 CONFIG_LOG=y
 # CONFIG_DISPLAY_BOARDINFO is not set
 CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_ARCH_MISC_INIT=y
 CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_BOARD_LATE_INIT=y
 CONFIG_SPL_MAX_SIZE=0x26000
@@ -108,6 +109,7 @@
 CONFIG_CLK_IMX8MP=y
 CONFIG_FSL_CAAM=y
 CONFIG_GPIO_HOG=y
+CONFIG_SPL_GPIO_HOG=y
 CONFIG_MXC_GPIO=y
 CONFIG_DM_PCA953X=y
 CONFIG_DM_I2C=y
diff --git a/configs/vexpress_ca9x4_defconfig b/configs/vexpress_ca9x4_defconfig
index 4ee64c3..5cacecc 100644
--- a/configs/vexpress_ca9x4_defconfig
+++ b/configs/vexpress_ca9x4_defconfig
@@ -30,7 +30,6 @@
 # CONFIG_CMD_ITEST is not set
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_BOOTP_BOOTFILESIZE=y
-# CONFIG_CMD_NFS is not set
 # CONFIG_CMD_SLEEP is not set
 CONFIG_CMD_UBI=y
 CONFIG_OF_CONTROL=y
diff --git a/configs/x240_defconfig b/configs/x240_defconfig
new file mode 100644
index 0000000..6d25c5a
--- /dev/null
+++ b/configs/x240_defconfig
@@ -0,0 +1,86 @@
+CONFIG_ARM=y
+CONFIG_ARCH_CPU_INIT=y
+CONFIG_ARCH_MVEBU=y
+CONFIG_TEXT_BASE=0x200000000
+CONFIG_SYS_MALLOC_LEN=0x900000
+CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x200FF0000
+CONFIG_TARGET_X240=y
+CONFIG_ENV_SIZE=0x10000
+CONFIG_ENV_OFFSET=0x00f80000
+CONFIG_ENV_SECT_SIZE=0x40000
+CONFIG_DM_GPIO=y
+CONFIG_DEFAULT_DEVICE_TREE="ac5-98dx35xx-atl-x240"
+CONFIG_SYS_LOAD_ADDR=0x220000000
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_SYS_CONSOLE_ENV_OVERWRITE=y
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_MEMTEST=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_PCI=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_USB=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_CMD_UBI=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_CLK=y
+CONFIG_CLK_MVEBU=y
+CONFIG_GPIO_HOG=y
+CONFIG_DM_PCA953X=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_MVTWSI=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_PCA954x=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_MISC=y
+# CONFIG_MMC is not set
+CONFIG_MTD=y
+CONFIG_MTD_RAW_NAND=y
+CONFIG_NAND_PXA3XX=y
+CONFIG_SYS_NAND_ONFI_DETECTION=y
+CONFIG_SPI_FLASH_SFDP_SUPPORT=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_PHY=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_ARMADA_8K=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_GPIO=y
+CONFIG_DM_RTC=y
+CONFIG_RTC_MAX313XX=y
+CONFIG_DM_SCSI=y
+CONFIG_SYS_NS16550=y
+CONFIG_MVEBU_A3700_SPI=y
+CONFIG_DM_THERMAL=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_HOST_ETHER=y
+CONFIG_USB_ETHER_ASIX=y
+CONFIG_USB_ETHER_ASIX88179=y
+CONFIG_USB_ETHER_MCS7830=y
+CONFIG_USB_ETHER_RTL8152=y
+CONFIG_USB_ETHER_SMSC95XX=y
+# CONFIG_FAT_WRITE is not set
diff --git a/disk/Kconfig b/disk/Kconfig
index 817b7c8..8549695 100644
--- a/disk/Kconfig
+++ b/disk/Kconfig
@@ -51,7 +51,7 @@
 
 config DOS_PARTITION
 	bool "Enable MS Dos partition table"
-	default y if DISTRO_DEFAULTS
+	default y if BOOT_DEFAULTS
 	default y if x86 || CMD_FAT || USB_STORAGE
 	select PARTITIONS
 	help
@@ -67,7 +67,7 @@
 
 config ISO_PARTITION
 	bool "Enable ISO partition table"
-	default y if DISTRO_DEFAULTS
+	default y if BOOT_DEFAULTS
 	default y if MIPS || ARCH_TEGRA
 	select PARTITIONS
 
@@ -91,7 +91,7 @@
 
 config EFI_PARTITION
 	bool "Enable EFI GPT partition table"
-	default y if DISTRO_DEFAULTS
+	default y if BOOT_DEFAULTS
 	default y if ARCH_TEGRA
 	select PARTITIONS
 	select LIB_UUID
@@ -139,7 +139,7 @@
 config PARTITION_UUIDS
 	bool "Enable support of UUID for partition"
 	depends on PARTITIONS
-	default y if DISTRO_DEFAULTS
+	default y if BOOT_DEFAULTS
 	default y if EFI_PARTITION
 	select LIB_UUID
 	help
diff --git a/disk/part.c b/disk/part.c
index 35300df5..0a03b82 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -26,6 +26,22 @@
 /* Check all partition types */
 #define PART_TYPE_ALL		-1
 
+static struct part_driver *part_driver_get_type(int part_type)
+{
+	struct part_driver *drv =
+		ll_entry_start(struct part_driver, part_driver);
+	const int n_ents = ll_entry_count(struct part_driver, part_driver);
+	struct part_driver *entry;
+
+	for (entry = drv; entry != drv + n_ents; entry++) {
+		if (part_type == entry->part_type)
+			return entry;
+	}
+
+	/* Not found */
+	return NULL;
+}
+
 static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
 {
 	struct part_driver *drv =
@@ -44,16 +60,29 @@
 			}
 		}
 	} else {
-		for (entry = drv; entry != drv + n_ents; entry++) {
-			if (dev_desc->part_type == entry->part_type)
-				return entry;
-		}
+		return part_driver_get_type(dev_desc->part_type);
 	}
 
 	/* Not found */
 	return NULL;
 }
 
+int part_get_type_by_name(const char *name)
+{
+	struct part_driver *drv =
+		ll_entry_start(struct part_driver, part_driver);
+	const int n_ents = ll_entry_count(struct part_driver, part_driver);
+	struct part_driver *entry;
+
+	for (entry = drv; entry != drv + n_ents; entry++) {
+		if (!strcasecmp(name, entry->name))
+			return entry->part_type;
+	}
+
+	/* Not found */
+	return PART_TYPE_UNKNOWN;
+}
+
 static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
 {
 	struct blk_desc *dev_desc;
@@ -306,8 +335,8 @@
 		drv->print(dev_desc);
 }
 
-int part_get_info(struct blk_desc *dev_desc, int part,
-		       struct disk_partition *info)
+int part_get_info_by_type(struct blk_desc *dev_desc, int part, int part_type,
+			  struct disk_partition *info)
 {
 	struct part_driver *drv;
 
@@ -320,7 +349,12 @@
 		info->type_guid[0] = 0;
 #endif
 
+		if (part_type == PART_TYPE_UNKNOWN) {
+			drv = part_driver_lookup_type(dev_desc);
+		} else {
+			drv = part_driver_get_type(part_type);
+		}
+
-		drv = part_driver_lookup_type(dev_desc);
 		if (!drv) {
 			debug("## Unknown partition table type %x\n",
 			      dev_desc->part_type);
@@ -340,6 +374,12 @@
 	return -ENOENT;
 }
 
+int part_get_info(struct blk_desc *dev_desc, int part,
+		  struct disk_partition *info)
+{
+	return part_get_info_by_type(dev_desc, part, PART_TYPE_UNKNOWN, info);
+}
+
 int part_get_info_whole_disk(struct blk_desc *dev_desc,
 			     struct disk_partition *info)
 {
diff --git a/doc/android/ab.rst b/doc/android/ab.rst
index 961895c..2adf887 100644
--- a/doc/android/ab.rst
+++ b/doc/android/ab.rst
@@ -31,6 +31,12 @@
 special partition (e.g. ``misc``) and determines which slot should be used for
 booting up.
 
+If the A/B metadata partition has a backup bootloader_message block that is used
+to ensure one is always valid even in the event of interruption when writing, it
+can be enabled in your board configuration file::
+
+    CONFIG_ANDROID_AB_BACKUP_OFFSET=0x1000
+
 Command usage
 -------------
 
diff --git a/doc/board/beacon/beacon-imx8mm.rst b/doc/board/beacon/beacon-imx8mm.rst
new file mode 100644
index 0000000..8bf983b
--- /dev/null
+++ b/doc/board/beacon/beacon-imx8mm.rst
@@ -0,0 +1,55 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+U-Boot for the Beacon EmbeddedWorks i.MX8M Mini Devkit
+======================================================
+
+Quick Start
+-----------
+
+- Build the ARM Trusted firmware binary
+- Get DDR firmware
+- Build U-Boot
+- Burn U-Boot to microSD Card
+- Boot
+
+Get and Build the ARM Trusted firmware
+--------------------------------------
+
+.. code-block:: bash
+
+    $ git clone https://github.com/nxp-imx/imx-atf.git -b v2.6
+    $ make PLAT=imx8mm bl31 CROSS_COMPILE=aarch64-linux-gnu-
+    $ cp build/imx8mm/release/bl31.bin ../
+
+Get the DDR firmware
+--------------------
+
+.. code-block:: bash
+
+    $ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.15.bin
+    $ chmod +x firmware-imx-8.15.bin
+    $ ./firmware-imx-8.15
+    $ cp firmware-imx-8.15/firmware/ddr/synopsys/lpddr4*.bin .
+
+Build U-Boot
+------------
+
+.. code-block:: bash
+
+    $ make imx8mm_beacon_defconfig
+    $ make CROSS_COMPILE=aarch64-linux-gnu-
+
+Burn U-Boot to microSD Card
+---------------------------
+
+.. code-block:: bash
+
+    $ sudo dd if=flash.bin of=/dev/sd[x] bs=1024 seek=33
+
+Boot
+----
+
+Set baseboard DIP switches for micoSD Card:
+- S11 (1:8) 01101000
+- S10 (1:8) 11001000
+- S17 (1:8) 0110xxxx
diff --git a/doc/board/beacon/beacon-imx8mn.rst b/doc/board/beacon/beacon-imx8mn.rst
new file mode 100644
index 0000000..bb4a863
--- /dev/null
+++ b/doc/board/beacon/beacon-imx8mn.rst
@@ -0,0 +1,53 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+U-Boot for the Beacon EmbeddedWorks i.MX8M Nano Devkit
+======================================================
+
+Quick Start
+-----------
+
+- Build the ARM Trusted firmware binary
+- Get DDR firmware
+- Build U-Boot
+- Burn U-Boot to microSD Card
+- Boot
+
+Get and Build the ARM Trusted firmware
+--------------------------------------
+
+.. code-block:: bash
+
+    $ git clone https://github.com/nxp-imx/imx-atf.git -b v2.6
+    $ make PLAT=imx8mn bl31 CROSS_COMPILE=aarch64-linux-gnu-
+    $ cp build/imx8mn/release/bl31.bin ../
+
+Get the DDR firmware
+--------------------
+
+.. code-block:: bash
+
+    $ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.15.bin
+    $ chmod +x firmware-imx-8.15.bin
+    $ ./firmware-imx-8.15
+    $ cp firmware-imx-8.15/firmware/ddr/synopsys/lpddr4*.bin .
+
+Build U-Boot
+------------
+
+.. code-block:: bash
+
+    $ make imx8mn_beacon_defconfig
+    $ make CROSS_COMPILE=aarch64-linux-gnu-
+
+Burn U-Boot to microSD Card
+---------------------------
+
+.. code-block:: bash
+
+    $ sudo dd if=flash.bin of=/dev/sd[x] bs=1024 seek=32
+
+Boot
+----
+
+Set baseboard DIP switches for micoSD Card:
+S17 (1:8): 1100xxxx
diff --git a/doc/board/beacon/index.rst b/doc/board/beacon/index.rst
index 1fe1046..bf62b09 100644
--- a/doc/board/beacon/index.rst
+++ b/doc/board/beacon/index.rst
@@ -7,3 +7,5 @@
    :maxdepth: 2
 
    beacon-imx8mp
+   beacon-imx8mm
+   beacon-imx8mn
diff --git a/doc/board/gateworks/imx8mm_venice.rst b/doc/board/gateworks/imx8mm_venice.rst
index f1e7e49..ea78dfd 100644
--- a/doc/board/gateworks/imx8mm_venice.rst
+++ b/doc/board/gateworks/imx8mm_venice.rst
@@ -47,4 +47,6 @@
 
    => tftpboot $loadaddr flash.bin
    => setexpr blkcnt $filesize + 0x1ff && setexpr blkcnt $blkcnt / 0x200
-   => mmc dev 2 && mmc write $loadaddr 0x42 $blkcnt
+   => mmc dev 2 0 && mmc write $loadaddr 0x42 $blkcnt # emmc user hw part
+   => mmc dev 2 1 && mmc write $loadaddr 0x42 $blkcnt # or emmc boot0 hw part
+   => mmc dev 2 2 && mmc write $loadaddr 0x42 $blkcnt # or emmc boot1 hw part
diff --git a/doc/board/gateworks/imx8mn_venice.rst b/doc/board/gateworks/imx8mn_venice.rst
index 7ba953a..7015f4e 100644
--- a/doc/board/gateworks/imx8mn_venice.rst
+++ b/doc/board/gateworks/imx8mn_venice.rst
@@ -47,4 +47,6 @@
 
    => tftpboot $loadaddr flash.bin
    => setexpr blkcnt $filesize + 0x1ff && setexpr blkcnt $blkcnt / 0x200
-   => mmc dev 2 && mmc write $loadaddr 0x40 $blkcnt
+   => mmc dev 2 0 && mmc write $loadaddr 0x40 $blkcnt # emmc user hw part
+   => mmc dev 2 1 && mmc write $loadaddr 0 $blkcnt # or emmc boot0 hw part
+   => mmc dev 2 2 && mmc write $loadaddr 0 $blkcnt # or emmc boot1 hw part
diff --git a/doc/board/gateworks/imx8mp_venice.rst b/doc/board/gateworks/imx8mp_venice.rst
index 632cd74..a219caa 100644
--- a/doc/board/gateworks/imx8mp_venice.rst
+++ b/doc/board/gateworks/imx8mp_venice.rst
@@ -47,4 +47,6 @@
 
    => tftpboot $loadaddr flash.bin
    => setexpr blkcnt $filesize + 0x1ff && setexpr blkcnt $blkcnt / 0x200
-   => mmc dev 2 && mmc write $loadaddr 0x40 $blkcnt
+   => mmc dev 2 0 && mmc write $loadaddr 0x40 $blkcnt # emmc user hw part
+   => mmc dev 2 1 && mmc write $loadaddr 0 $blkcnt # or emmc boot0 hw part
+   => mmc dev 2 2 && mmc write $loadaddr 0 $blkcnt # or emmc boot1 hw part
diff --git a/doc/board/index.rst b/doc/board/index.rst
index aadc90a..84aa8c1 100644
--- a/doc/board/index.rst
+++ b/doc/board/index.rst
@@ -32,6 +32,7 @@
    nokia/index
    nxp/index
    openpiton/index
+   phytec/index
    purism/index
    qualcomm/index
    renesas/index
diff --git a/doc/board/phytec/index.rst b/doc/board/phytec/index.rst
new file mode 100644
index 0000000..a5b4420
--- /dev/null
+++ b/doc/board/phytec/index.rst
@@ -0,0 +1,10 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+PHYTEC
+======
+
+.. toctree::
+   :maxdepth: 2
+
+   phycore-imx8mm
+   phycore-imx8mp
diff --git a/doc/board/phytec/phycore-imx8mm.rst b/doc/board/phytec/phycore-imx8mm.rst
new file mode 100644
index 0000000..e9dc225
--- /dev/null
+++ b/doc/board/phytec/phycore-imx8mm.rst
@@ -0,0 +1,60 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+phyCORE-i.MX 8M Mini
+====================
+
+The phyCORE-i.MX 8M Mini with 2GB of main memory is supported.
+
+Quick Start
+-----------
+
+- Build the ARM Trusted firmware binary
+- Get ddr firmware
+- Build U-Boot
+- Boot
+
+Build the ARM Trusted firmware binary
+-------------------------------------
+
+.. code-block:: bash
+
+   $ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+   $ cd trusted-firmware-a
+   $ export CROSS_COMPILE=aarch64-linux-gnu
+   $ export IMX_BOOT_UART_BASE=0x30880000
+   $ make PLAT=imx8mm bl31
+
+Get the ddr firmware
+--------------------
+
+.. code-block:: bash
+
+   $ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.19.bin
+   $ chmod +x firmware-imx-8.19.bin
+   $ ./firmware-imx-8.19.bin
+
+Build U-Boot for SD card
+------------------------
+
+Copy binaries
+^^^^^^^^^^^^^
+
+.. code-block:: bash
+
+   $ cp <TF-A dir>/build/imx8mm/release/bl31.bin .
+   $ cp firmware-imx-8.19/firmware/ddr/synopsys/lpddr4*.bin .
+
+Build U-Boot
+^^^^^^^^^^^^
+
+.. code-block:: bash
+
+   $ make phycore-imx8mm_defconfig
+   $ make flash.bin
+
+Flash SD card
+^^^^^^^^^^^^^
+
+.. code-block:: bash
+
+   $ sudo dd if=flash.bin of=/dev/sd[x] bs=1024 seek=33 conv=sync
diff --git a/doc/board/phytec/phycore-imx8mp.rst b/doc/board/phytec/phycore-imx8mp.rst
new file mode 100644
index 0000000..fda751a
--- /dev/null
+++ b/doc/board/phytec/phycore-imx8mp.rst
@@ -0,0 +1,60 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+phyCORE-i.MX 8M Plus
+====================
+
+The phyCORE-i.MX 8M Plus with 2GB of main memory is supported.
+
+Quick Start
+-----------
+
+- Build the ARM Trusted firmware binary
+- Get ddr firmware
+- Build U-Boot
+- Boot
+
+Build the ARM Trusted firmware binary
+-------------------------------------
+
+.. code-block:: bash
+
+   $ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+   $ cd trusted-firmware-a
+   $ export CROSS_COMPILE=aarch64-linux-gnu
+   $ export IMX_BOOT_UART_BASE=0x30860000
+   $ make PLAT=imx8mp bl31
+
+Get the ddr firmware
+--------------------
+
+.. code-block:: bash
+
+   $ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.19.bin
+   $ chmod +x firmware-imx-8.19.bin
+   $ ./firmware-imx-8.19.bin
+
+Build U-Boot for SD card
+------------------------
+
+Copy binaries
+^^^^^^^^^^^^^
+
+.. code-block:: bash
+
+   $ cp <TF-A dir>/build/imx8mp/release/bl31.bin .
+   $ cp firmware-imx-8.19/firmware/ddr/synopsys/lpddr4*.bin .
+
+Build U-Boot
+^^^^^^^^^^^^
+
+.. code-block:: bash
+
+   $ make phycore-imx8mp_defconfig
+   $ make flash.bin
+
+Flash SD card
+^^^^^^^^^^^^^
+
+.. code-block:: bash
+
+   $ sudo dd if=flash.bin of=/dev/sd[x] bs=1024 seek=32 conv=sync
diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst
index 32dd7f0..2ac4af2 100644
--- a/doc/develop/expo.rst
+++ b/doc/develop/expo.rst
@@ -85,6 +85,9 @@
 handled by allocating space in the enum for a maximum number of items, then
 adding the loop count to the enum values to obtain unique IDs.
 
+Where dynamic IDs are need, use expo_set_dynamic_start() to set the start value,
+so that they are allocated above the starting (enum) IDs.
+
 All text strings are stored in a structure attached to the expo, referenced by
 a text ID. This makes it easier at some point to implement multiple languages or
 to support Unicode strings.
@@ -97,10 +100,13 @@
 Creating an expo
 ----------------
 
-To create an expo, use `expo_new()` followed by `scene_new()` to create a scene.
-Then add objects to the scene, using functions like `scene_txt_str()` and
-`scene_menu()`. For every menu item, add text and image objects, then create
-the menu item with `scene_menuitem()`, referring to those objects.
+To create an expo programmatically, use `expo_new()` followed by `scene_new()`
+to create a scene. Then add objects to the scene, using functions like
+`scene_txt_str()` and `scene_menu()`. For every menu item, add text and image
+objects, then create the menu item with `scene_menuitem()`, referring to those
+objects.
+
+To create an expo using a description file, see :ref:`expo_format` below.
 
 Layout
 ------
@@ -152,8 +158,287 @@
 Themes
 ------
 
+Expo supports simple themes, for setting the font size, for example. Use the
+expo_apply_theme() function to load a theme, passing a node with the required
+properties:
+
+font-size
+    Font size to use for all text (type: u32)
+
+menu-inset
+    Number of pixels to inset the menu on the sides and top (type: u32)
+
+menuitem-gap-y
+    Number of pixels between menu items
+
+Pop-up mode
+-----------
+
+Expos support two modes. The simple mode is used for selecting from a single
+menu, e.g. when choosing with OS to boot. In this mode the menu items are shown
+in a list (label, > pointer, key and description) and can be chosen using arrow
+keys and enter::
+
+   U-Boot Boot Menu
+
+   UP and DOWN to choose, ENTER to select
+
+   mmc1           > 0  Fedora-Workstation-armhfp-31-1.9
+   mmc3             1  Armbian
+
+The popup mode allows multiple menus to be present in a scene. Each is shown
+just as its title and label, as with the `CPU Speed` and `AC Power` menus here::
+
+              Test Configuration
+
+
+   CPU Speed        <2 GHz>  (highlighted)
+
+   AC Power         Always Off
+
+
+     UP and DOWN to choose, ENTER to select
+
+
+.. _expo_format:
+
+Expo Format
+-----------
+
+It can be tedious to create a complex expo using code. Expo supports a
+data-driven approach, where the expo description is in a devicetree file. This
+makes it easier and faster to create and edit the description. An expo builder
+is provided to convert this format into an expo structure.
+
+Layout of the expo scenes is handled automatically, based on a set of simple
+rules. The :doc:`../usage/cmd/cedit` can be used to load a configuration
+and create an expo from it.
+
+Top-level node
+~~~~~~~~~~~~~~
+
+The top-level node has the following properties:
+
+dynamic-start
+    type: u32, optional
+
+    Specifies the start of the dynamically allocated objects. This results in
+    a call to expo_set_dynamic_start().
+
+The top-level node has the following subnodes:
+
+scenes
+    Specifies the scenes in the expo, each one being a subnode
+
+strings
+    Specifies the strings in the expo, each one being a subnode
+
+`scenes` node
+~~~~~~~~~~~~~
+
+Contains a list of scene subnodes. The name of each subnode is passed as the
+name to `scene_new()`.
+
+`strings` node
+~~~~~~~~~~~~~~
+
+Contains a list of string subnodes. The name of each subnode is ignored.
+
+`strings` subnodes
+~~~~~~~~~~~~~~~~~~
+
+Each subnode defines a string which can be used by scenes and objects. Each
+string has an ID number which is used to refer to it.
+
+The `strings` subnodes have the following properties:
+
+id
+    type: u32, required
+
+    Specifies the ID number for the string.
+
+value:
+    type: string, required
+
+    Specifies the string text. For now only a single value is supported. Future
+    work may add support for multiple languages by using a value for each
+    language.
+
+Scene nodes (`scenes` subnodes)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Each subnode of the `scenes` node contains a scene description.
+
+Most properties can use either a string or a string ID. For example, a `title`
+property can be used to provide the title for a menu; alternatively a `title-id`
+property can provide the string ID of the title. If both are present, the
+ID takes preference, except that if a string with that ID does not exist, it
+falls back to using the string from the property (`title` in this example). The
+description below shows these are alternative properties with the same
+description.
+
+The scene nodes have the following properties:
+
+id
+    type: u32, required
+
+    Specifies the ID number for the string.
+
-Expo does not itself support themes. The bootflow_menu implement supposed a
-basic theme, applying font sizes to the various text objects in the expo.
+title / title-id
+    type: string / u32, required
+
+    Specifies the title of the scene. This is shown at the top of the scene.
+
+prompt / prompt-id
+    type: string / u32, required
+
+    Specifies a prompt for the scene. This is shown at the bottom of the scene.
+
+The scene nodes have a subnode for each object in the scene.
+
+Object nodes
+~~~~~~~~~~~~
+
+The object-node name is used as the name of the object, e.g. when calling
+`scene_menu()` to create a menu.
+
+Object nodes have the following common properties:
+
+type
+    type: string, required
+
+    Specifies the type of the object. Valid types are:
+
+    "menu"
+        Menu containing items which can be selected by the user
+
+id
+    type: u32, required
+
+    Specifies the ID of the object. This is used when referring to the object.
+
+
+Menu nodes have the following additional properties:
+
+title / title-id
+    type: string / u32, required
+
+    Specifies the title of the menu. This is shown to the left of the area for
+    this menu.
+
+item-id
+    type: u32 list, required
+
+    Specifies the ID for each menu item. These are used for checking which item
+    has been selected.
+
+item-label / item-label-id
+    type: string list / u32 list, required
+
+    Specifies the label for each item in the menu. These are shown to the user.
+    In 'popup' mode these form the items in the menu.
+
+key-label / key-label-id
+    type: string list / u32 list, optional
+
+    Specifies the key for each item in the menu. These are currently only
+    intended for use in simple mode.
+
+desc-label / desc-label-id
+    type: string list / u32 list, optional
+
+    Specifies the description for each item in the menu. These are currently
+    only intended for use in simple mode.
+
+
+Expo layout
+~~~~~~~~~~~
+
+The `expo_arrange()` function can be called to arrange the expo objects in a
+suitable manner. For each scene it puts the title at the top, the prompt at the
+bottom and the objects in order from top to bottom.
+
+Expo format example
+~~~~~~~~~~~~~~~~~~~
+
+This example shows an expo with a single scene consisting of two menus. The
+scene title is specified using a string from the strings table, but all other
+strings are provided inline in the nodes where they are used.
+
+::
+
+    #define ID_PROMPT           1
+    #define ID_SCENE1           2
+    #define ID_SCENE1_TITLE     3
+
+    #define ID_CPU_SPEED        4
+    #define ID_CPU_SPEED_TITLE  5
+    #define ID_CPU_SPEED_1      6
+    #define ID_CPU_SPEED_2      7
+    #define ID_CPU_SPEED_3      8
+
+    #define ID_POWER_LOSS       9
+    #define ID_AC_OFF           10
+    #define ID_AC_ON            11
+    #define ID_AC_MEMORY        12
+
+    #define ID_DYNAMIC_START    13
+
+    &cedit {
+        dynamic-start = <ID_DYNAMIC_START>;
+
+        scenes {
+            main {
+                id = <ID_SCENE1>;
+
+                /* value refers to the matching id in /strings */
+                title-id = <ID_SCENE1_TITLE>;
+
+                /* simple string is used as it is */
+                prompt = "UP and DOWN to choose, ENTER to select";
+
+                /* defines a menu within the scene */
+                cpu-speed {
+                    type = "menu";
+                    id = <ID_CPU_SPEED>;
+
+                    /*
+                     * has both string and ID. The string is ignored
+                     * if the ID is present and points to a string
+                     */
+                    title = "CPU speed";
+                    title-id = <ID_CPU_SPEED_TITLE>;
+
+                    /* menu items as simple strings */
+                    item-label = "2 GHz", "2.5 GHz", "3 GHz";
+
+                    /* IDs for the menu items */
+                    item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
+                        ID_CPU_SPEED_3>;
+                };
+
+                power-loss {
+                    type = "menu";
+                    id = <ID_POWER_LOSS>;
+
+                    title = "AC Power";
+                    item-label = "Always Off", "Always On",
+                        "Memory";
+
+                    item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
+                };
+            };
+        };
+
+        strings {
+            title {
+                id = <ID_SCENE1_TITLE>;
+                value = "Test Configuration";
+                value-es = "configuración de prueba";
+            };
+        };
+    };
+
 
 API documentation
 -----------------
@@ -166,12 +451,10 @@
 Some ideas for future work:
 
 - Default menu item and a timeout
-- Higher-level / automatic / more flexible layout of objects
 - Image formats other than BMP
 - Use of ANSI sequences to control a serial terminal
 - Colour selection
-- Better support for handling lots of settings, e.g. with multiple menus and
-  radio/option widgets
+- Support for more widgets, e.g. text, numeric, radio/option
 - Mouse support
 - Integrate Nuklear, NxWidgets or some other library for a richer UI
 - Optimise rendering by only updating the display with changes since last render
@@ -179,10 +462,10 @@
 - Add a Kconfig option to drop the names to save code / data space
 - Add a Kconfig option to disable vidconsole support to save code / data space
 - Support both graphical and text menus at the same time on different devices
-- Implement proper measurement of object bounding boxes, to permit more exact
-  layout. This would tidy up the layout when Truetype is not used
 - Support unicode
 - Support curses for proper serial-terminal menus
+- Add support for large menus which need to scroll
+- Add support for reading and writing configuration settings with cedit
 
 .. Simon Glass <sjg@chromium.org>
 .. 7-Oct-22
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst
index 6626cee..a7a41f2 100644
--- a/doc/develop/uefi/uefi.rst
+++ b/doc/develop/uefi/uefi.rst
@@ -552,6 +552,13 @@
 When the --fw-version in the capsule file is updated, lowest-supported-version
 in the dtb might be updated accordingly.
 
+If user needs to enforce anti-rollback to any older version,
+the lowest-supported-version property in dtb must be always updated manually.
+
+Note that the lowest-supported-version property specified in U-Boot's control
+device tree can be changed by U-Boot fdt command.
+Secure systems should not enable this command.
+
 To insert the lowest supported version into a dtb
 
 .. code-block:: console
diff --git a/doc/device-tree-bindings/config.txt b/doc/device-tree-bindings/config.txt
index 3151778..f50c68b 100644
--- a/doc/device-tree-bindings/config.txt
+++ b/doc/device-tree-bindings/config.txt
@@ -76,6 +76,8 @@
 	precedence. In that case, only if the partition is not found,
 	mmc-env-offset* will be tried.
 
+	Note that CONFIG_ENV_MMC_PARTITION overrides this device-tree setting.
+
 u-boot,no-apm-finalize (bool)
 	For x86 devices running on coreboot, this tells U-Boot not to lock
 	down the Intel Management Engine (ME) registers. This allows U-Boot to
diff --git a/doc/device-tree-bindings/spi/brcm,bcm63xx-hsspi.yaml b/doc/device-tree-bindings/spi/brcm,bcm63xx-hsspi.yaml
new file mode 100644
index 0000000..6554978
--- /dev/null
+++ b/doc/device-tree-bindings/spi/brcm,bcm63xx-hsspi.yaml
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/brcm,bcm63xx-hsspi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom Broadband SoC High Speed SPI controller
+
+maintainers:
+  - William Zhang <william.zhang@broadcom.com>
+  - Kursad Oney <kursad.oney@broadcom.com>
+  - Jonas Gorski <jonas.gorski@gmail.com>
+
+description: |
+  Broadcom Broadband SoC supports High Speed SPI master controller since the
+  early MIPS based chips such as BCM6328 and BCM63268.  This initial rev 1.0
+  controller was carried over to recent ARM based chips, such as BCM63138,
+  BCM4908 and BCM6858. The old MIPS based chip should continue to use the
+  brcm,bcm6328-hsspi compatible string. The recent ARM based chip is required to
+  use the brcm,bcmbca-hsspi-v1.0 as part of its compatible string list as
+  defined below to match the specific chip along with ip revision info.
+
+  This rev 1.0 controller has a limitation that can not keep the chip select line
+  active between the SPI transfers within the same SPI message. This can
+  terminate the transaction to some SPI devices prematurely. The issue can be
+  worked around by either the controller's prepend mode or using the dummy chip
+  select workaround. Driver automatically picks the suitable mode based on
+  transfer type so it is transparent to the user.
+
+  The newer SoCs such as BCM6756, BCM4912 and BCM6855 include an updated SPI
+  controller rev 1.1 that add the capability to allow the driver to control chip
+  select explicitly. This solves the issue in the old controller.
+
+properties:
+  compatible:
+    oneOf:
+      - const: brcm,bcm6328-hsspi
+      - items:
+          - enum:
+              - brcm,bcm47622-hsspi
+              - brcm,bcm4908-hsspi
+              - brcm,bcm63138-hsspi
+              - brcm,bcm63146-hsspi
+              - brcm,bcm63148-hsspi
+              - brcm,bcm63158-hsspi
+              - brcm,bcm63178-hsspi
+              - brcm,bcm6846-hsspi
+              - brcm,bcm6856-hsspi
+              - brcm,bcm6858-hsspi
+              - brcm,bcm6878-hsspi
+          - const: brcm,bcmbca-hsspi-v1.0
+      - items:
+          - enum:
+              - brcm,bcm4912-hsspi
+              - brcm,bcm6756-hsspi
+              - brcm,bcm6813-hsspi
+              - brcm,bcm6855-hsspi
+          - const: brcm,bcmbca-hsspi-v1.1
+
+  reg:
+    items:
+      - description: main registers
+      - description: miscellaneous control registers
+    minItems: 1
+
+  reg-names:
+    items:
+      - const: hsspi
+      - const: spim-ctrl
+    minItems: 1
+
+  clocks:
+    items:
+      - description: SPI master reference clock
+      - description: SPI master pll clock
+
+  clock-names:
+    items:
+      - const: hsspi
+      - const: pll
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - interrupts
+
+allOf:
+  - $ref: spi-controller.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - brcm,bcm6328-hsspi
+              - brcm,bcmbca-hsspi-v1.0
+    then:
+      properties:
+        reg:
+          maxItems: 1
+        reg-names:
+          maxItems: 1
+    else:
+      properties:
+        reg:
+          minItems: 2
+          maxItems: 2
+        reg-names:
+          minItems: 2
+          maxItems: 2
+      required:
+        - reg-names
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    spi@ff801000 {
+        compatible = "brcm,bcm6756-hsspi", "brcm,bcmbca-hsspi-v1.1";
+        reg = <0xff801000 0x1000>,
+              <0xff802610 0x4>;
+        reg-names = "hsspi", "spim-ctrl";
+        interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&hsspi>, <&hsspi_pll>;
+        clock-names = "hsspi", "pll";
+        num-cs = <8>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+    };
diff --git a/doc/device-tree-bindings/spi/soft-spi.txt b/doc/device-tree-bindings/spi/soft-spi.txt
index dfb5066..bdf7e86 100644
--- a/doc/device-tree-bindings/spi/soft-spi.txt
+++ b/doc/device-tree-bindings/spi/soft-spi.txt
@@ -9,10 +9,10 @@
 Mandatory properties:
 compatible: "spi-gpio"
 cs-gpios: GPIOs to use for SPI chip select (output)
-gpio-sck: GPIO to use for SPI clock (output)
+sck-gpios: GPIO to use for SPI clock (output)
 And at least one of:
-gpio-mosi: GPIO to use for SPI MOSI line (output)
-gpio-miso: GPIO to use for SPI MISO line (input)
+mosi-gpios: GPIO to use for SPI MOSI line (output)
+miso-gpios: GPIO to use for SPI MISO line (input)
 
 Optional propertie:
 spi-delay-us: Number of microseconds of delay between each CS transition
@@ -27,9 +27,9 @@
 	soft-spi {
 		compatible = "spi-gpio";
 		cs-gpios = <&gpio 235 0>;	/* Y43 */
-		gpio-sck = <&gpio 225 0>;	/* Y31 */
-		gpio-mosi = <&gpio 227 0>;	/* Y33 */
-		gpio-miso = <&gpio 224 0>;	/* Y30 */
+		sck-gpios = <&gpio 225 0>;	/* Y31 */
+		mosi-gpios = <&gpio 227 0>;	/* Y33 */
+		miso-gpios = <&gpio 224 0>;	/* Y30 */
 		spi-delay-us = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/doc/imx/habv4/csf_examples/mx8m/csf.sh b/doc/imx/habv4/csf_examples/mx8m/csf.sh
index 5b383fa..d87015f 100644
--- a/doc/imx/habv4/csf_examples/mx8m/csf.sh
+++ b/doc/imx/habv4/csf_examples/mx8m/csf.sh
@@ -22,6 +22,27 @@
 cp doc/imx/habv4/csf_examples/mx8m/csf_spl.txt csf_spl.tmp
 cp doc/imx/habv4/csf_examples/mx8m/csf_fit.txt csf_fit.tmp
 
+# update File Paths from env vars
+if ! [ -r $CSF_KEY ]; then
+	echo "Error: \$CSF_KEY not found"
+	exit 1
+fi
+if ! [ -r $IMG_KEY ]; then
+	echo "Error: \$IMG_KEY not found"
+	exit 1
+fi
+if ! [ -r $SRK_TABLE ]; then
+	echo "Error: \$SRK_TABLE not found"
+	exit 1
+fi
+sed -i "s:\$CSF_KEY:$CSF_KEY:" csf_spl.tmp
+sed -i "s:\$IMG_KEY:$IMG_KEY:" csf_spl.tmp
+sed -i "s:\$SRK_TABLE:$SRK_TABLE:" csf_spl.tmp
+sed -i "s:\$CSF_KEY:$CSF_KEY:" csf_fit.tmp
+sed -i "s:\$IMG_KEY:$IMG_KEY:" csf_fit.tmp
+sed -i "s:\$SRK_TABLE:$SRK_TABLE:" csf_fit.tmp
+
+# update SPL Blocks
 spl_block_base=$(printf "0x%x" $(( $(sed -n "/CONFIG_SPL_TEXT_BASE=/ s@.*=@@p" .config) - 0x40)) )
 spl_block_size=$(printf "0x%x" $(stat -tc %s u-boot-spl-ddr.bin))
 sed -i "/Blocks = / s@.*@  Blocks = $spl_block_base 0x0 $spl_block_size \"flash.bin\"@" csf_spl.tmp
diff --git a/doc/imx/habv4/csf_examples/mx8m/csf_fit.txt b/doc/imx/habv4/csf_examples/mx8m/csf_fit.txt
index bbb82f6..3d79edf 100644
--- a/doc/imx/habv4/csf_examples/mx8m/csf_fit.txt
+++ b/doc/imx/habv4/csf_examples/mx8m/csf_fit.txt
@@ -7,21 +7,21 @@
   Signature Format = CMS
 
 [Install SRK]
-  # FIXME: Adjust path here
-  File = "/path/to/cst-3.3.1/crts/SRK_1_2_3_4_table.bin"
+  # SRK_TABLE is full path to SRK_1_2_3_4_table.bin
+  File = "$SRK_TABLE"
   Source index = 0
 
 [Install CSFK]
-  # FIXME: Adjust path here
-  File = "/path/to/cst-3.3.1/crts/CSF1_1_sha256_4096_65537_v3_usr_crt.pem"
+  # CSF_KEY is full path to CSF1_1_sha256_4096_65537_v3_usr_crt.pem
+  File = "$CSF_KEY"
 
 [Authenticate CSF]
 
 [Install Key]
   Verification index = 0
   Target Index = 2
-  # FIXME: Adjust path here
-  File = "/path/to/cst-3.3.1/crts/IMG1_1_sha256_4096_65537_v3_usr_crt.pem"
+  # IMG_KEY is full path to IMG1_1_sha256_4096_65537_v3_usr_crt.pem
+  File = "$IMG_KEY"
 
 [Authenticate Data]
   Verification index = 2
diff --git a/doc/imx/habv4/csf_examples/mx8m/csf_spl.txt b/doc/imx/habv4/csf_examples/mx8m/csf_spl.txt
index 00e34f6..88fa420 100644
--- a/doc/imx/habv4/csf_examples/mx8m/csf_spl.txt
+++ b/doc/imx/habv4/csf_examples/mx8m/csf_spl.txt
@@ -7,13 +7,13 @@
   Signature Format = CMS
 
 [Install SRK]
-  # FIXME: Adjust path here
-  File = "/path/to/cst-3.3.1/crts/SRK_1_2_3_4_table.bin"
+  # SRK_TABLE is full path to SRK_1_2_3_4_table.bin
+  File = "$SRK_TABLE"
   Source index = 0
 
 [Install CSFK]
-  # FIXME: Adjust path here
-  File = "/path/to/cst-3.3.1/crts/CSF1_1_sha256_4096_65537_v3_usr_crt.pem"
+  # CSF_KEY is full path to CSF1_1_sha256_4096_65537_v3_usr_crt.pem
+  File = "$CSF_KEY"
 
 [Authenticate CSF]
 
@@ -24,8 +24,8 @@
 [Install Key]
   Verification index = 0
   Target Index = 2
-  # FIXME: Adjust path here
-  File = "/path/to/cst-3.3.1/crts/IMG1_1_sha256_4096_65537_v3_usr_crt.pem"
+  # IMG_KEY is full path to IMG1_1_sha256_4096_65537_v3_usr_crt.pem
+  File = "$IMG_KEY"
 
 [Authenticate Data]
   Verification index = 2
diff --git a/doc/imx/habv4/guides/mx8m_spl_secure_boot.txt b/doc/imx/habv4/guides/mx8m_spl_secure_boot.txt
index e79726b..e16e541 100644
--- a/doc/imx/habv4/guides/mx8m_spl_secure_boot.txt
+++ b/doc/imx/habv4/guides/mx8m_spl_secure_boot.txt
@@ -207,6 +207,16 @@
 ```
 
 The entire script is available in doc/imx/habv4/csf_examples/mx8m/csf.sh
+and can be used as follows to modify flash.bin to be signed
+(adjust paths as needed):
+```
+export CST_DIR=/usr/src/cst-3.3.1/
+export CSF_KEY=$CST_DIR/crts/CSF1_1_sha256_4096_65537_v3_usr_crt.pem
+export IMG_KEY=$CST_DIR/crts/IMG1_1_sha256_4096_65537_v3_usr_crt.pem
+export SRK_TABLE=$CST_DIR/crts/SRK_1_2_3_4_table.bin
+export PATH=$CST_DIR/linux64/bin:$PATH
+/bin/sh doc/imx/habv4/csf_examples/mx8m/csf.sh
+```
 
 1.4 Closing the device
 -----------------------
diff --git a/doc/usage/cmd/acpi.rst b/doc/usage/cmd/acpi.rst
index 14bafc8..6b9b894 100644
--- a/doc/usage/cmd/acpi.rst
+++ b/doc/usage/cmd/acpi.rst
@@ -11,12 +11,14 @@
     acpi list
     acpi items [-d]
     acpi dump <name>
+    acpi set <address>
 
 Description
 -----------
 
-The *acpi* command is used to dump the ACPI tables generated by U-Boot for passing
-to the operating systems.
+The *acpi* command is used to dump the ACPI tables generated by U-Boot for
+passing to the operating systems. It allows manually setting the address to take
+a look at existing ACPI tables.
 
 ACPI tables can be generated by various output functions and even devices can
 output material to include in the Differentiated System Description Table (DSDT)
@@ -231,5 +233,28 @@
     00000000: 44 53 44 54 ea 32 00 00 02 eb 55 2d 42 4f 4f 54  DSDT.2....U-BOOT
     00000010: 55 2d 42 4f 4f 54 42 4c 25 07 11 20 49 4e 54 4c  U-BOOTBL%.. INTL
 
+This shows searching for tables in a known area of memory, then setting the
+pointer::
+
+    => acpi list
+    No ACPI tables present
+    => ms.s bff00000 80000 "RSD PTR"
+    bff75000: 52 53 44 20 50 54 52 20 cf 42 4f 43 48 53 20 00  RSD PTR .BOCHS .
+    1 match
+    => acpi set bff75000
+    Setting ACPI pointer to bff75000
+    => acpi list
+    Name      Base   Size  Detail
+    ----  --------  -----  ------
+    RSDP  bff75000      0  v00 BOCHS
+    RSDT  bff76a63     38  v01 BOCHS  BXPC     1 BXPC 1
+    FACP  bff768ff     74  v01 BOCHS  BXPC     1 BXPC 1
+    DSDT  bff75080   187f  v01 BOCHS  BXPC     1 BXPC 1
+    FACS  bff75040     40
+    APIC  bff76973     90  v01 BOCHS  BXPC     1 BXPC 1
+    HPET  bff76a03     38  v01 BOCHS  BXPC     1 BXPC 1
+    WAET  bff76a3b     28  v01 BOCHS  BXPC     1 BXPC 1
+    SSDT  bff95040     c5  v02 COREv4 COREBOOT 2a CORE 20221020
+
 
 .. _`ACPI specification`: https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
diff --git a/doc/usage/cmd/bootflow.rst b/doc/usage/cmd/bootflow.rst
index 8590efc..a8af1f8 100644
--- a/doc/usage/cmd/bootflow.rst
+++ b/doc/usage/cmd/bootflow.rst
@@ -13,7 +13,7 @@
     bootflow select [<num|name>]
     bootflow info [-d]
     bootflow boot
-
+    bootflow cmdline [set|get|clear|delete|auto] <param> [<value>]
 
 Description
 -----------
@@ -197,6 +197,36 @@
 
 This boots the current bootflow.
 
+
+bootflow cmdline
+~~~~~~~~~~~~~~~~
+
+Some bootmeths can obtain the OS command line since it is stored with the OS.
+In that case, you can use `bootflow cmdline` to adjust this. The command line
+is assumed to be in the format used by Linux, i.e. a space-separated set of
+parameters with optional values, e.g. "noinitrd console=/dev/tty0".
+
+To change or add a parameter, use::
+
+    bootflow cmdline set <param> <value>
+
+To clear a parameter value to empty you can use "" for the value, or use::
+
+    bootflow cmdline clear <param>
+
+To delete a parameter entirely, use::
+
+    bootflow cmdline delete <param>
+
+Automatic parameters are available in a very few cases. You can use these to
+add parmeters where the value is known by U-Boot. For example::
+
+    bootflow cmdline auto earlycon
+    bootflow cmdline auto console
+
+can be used to set the early console (or console) to a suitable value so that
+output appears on the serial port. This is only supported by the 16550 serial
+driver so far.
 
 Example
 -------
@@ -258,7 +288,6 @@
     Name:      mmc@7e202000.bootdev.part_2
     Device:    mmc@7e202000.bootdev
     Block dev: mmc@7e202000.blk
-    Sequence:  1
     Method:    distro
     State:     ready
     Partition: 2
@@ -266,6 +295,10 @@
     Filename:  extlinux/extlinux.conf
     Buffer:    3db7ae88
     Size:      232 (562 bytes)
+    OS:        Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
+    Cmdline:   (none)
+    Logo:      (none)
+    FDT:       <NULL>
     Error:     0
     U-Boot> bootflow boot
     ** Booting bootflow 'smsc95xx_eth.bootdev.0'
@@ -427,6 +460,69 @@
     (21 bootflows, 2 valid)
     U-Boot>
 
+Here is an example of booting ChromeOS, adjusting the console beforehand. Note that
+the cmdline is word-wrapped here and some parts of the command line are elided::
+
+    => bootfl list
+    Showing all bootflows
+    Seq  Method       State   Uclass    Part  Name                      Filename
+    ---  -----------  ------  --------  ----  ------------------------  ----------------
+    0  cros         ready   nvme         0  5.10.153-20434-g98da1eb2c <NULL>
+    1  efi          ready   nvme         c  nvme#0.blk#1.bootdev.part efi/boot/bootia32.efi
+    2  efi          ready   usb_mass_    2  usb_mass_storage.lun0.boo efi/boot/bootia32.efi
+    ---  -----------  ------  --------  ----  ------------------------  ----------------
+    (3 bootflows, 3 valid)
+    => bootfl sel 0
+    => bootfl inf
+    Name:      5.10.153-20434-g98da1eb2cf9d (chrome-bot@chromeos-release-builder-us-central1-b-x32-12-xijx) #1 SMP PREEMPT Tue Jan 24 19:38:23 PST 2023
+    Device:    nvme#0.blk#1.bootdev
+    Block dev: nvme#0.blk#1
+    Method:    cros
+    State:     ready
+    Partition: 0
+    Subdir:    (none)
+    Filename:  <NULL>
+    Buffer:    737a1400
+    Size:      c47000 (12873728 bytes)
+    OS:        ChromeOS
+    Cmdline:   console= loglevel=7 init=/sbin/init cros_secure drm.trace=0x106
+        root=/dev/dm-0 rootwait ro dm_verity.error_behavior=3
+        dm_verity.max_bios=-1 dm_verity.dev_wait=1
+        dm="1 vroot none ro 1,0 6348800
+          verity payload=PARTUUID=799c935b-ae62-d143-8493-816fa936eef7/PARTNROFF=1
+          hashtree=PARTUUID=799c935b-ae62-d143-8493-816fa936eef7/PARTNROFF=1
+          hashstart=6348800 alg=sha256
+          root_hexdigest=78cc462cd45aecbcd49ca476587b4dee59aa1b00ba5ece58e2c29ec9acd914ab
+          salt=8dec4dc80a75dd834a9b3175c674405e15b16a253fdfe05c79394ae5fd76f66a"
+        noinitrd vt.global_cursor_default=0
+        kern_guid=799c935b-ae62-d143-8493-816fa936eef7 add_efi_memmap boot=local
+        noresume noswap i915.modeset=1 ramoops.ecc=1 tpm_tis.force=0
+        intel_pmc_core.warn_on_s0ix_failures=1 i915.enable_guc=3 i915.enable_dc=4
+        xdomain=0 swiotlb=65536 intel_iommu=on i915.enable_psr=1
+        usb-storage.quirks=13fe:6500:u
+    X86 setup: 742e3400
+    Logo:      (none)
+    FDT:       <NULL>
+    Error:     0
+    => bootflow cmdline auto earlycon
+    => bootflow cmd auto console
+    => print bootargs
+    bootargs=console=ttyS0,115200n8 loglevel=7 ...
+        usb-storage.quirks=13fe:6500:u earlycon=uart8250,mmio32,0xfe03e000,115200n8
+    => bootflow cmd del console
+    => print bootargs
+    bootargs=loglevel=7 ... earlycon=uart8250,mmio32,0xfe03e000,115200n8
+    => bootfl boot
+    ** Booting bootflow '5.10.153-20434-g98da1eb2cf9d (chrome-bot@chromeos-release-builder-us-central1-b-x32-12-xijx) #1 SMP PREEMPT Tue Jan 24 19:38:23 PST 2023' with cros
+    Kernel command line: "loglevel=7 ... earlycon=uart8250,mmio32,0xfe03e000,115200n8"
+
+    Starting kernel ...
+
+    [    0.000000] Linux version 5.10.153-20434-g98da1eb2cf9d (chrome-bot@chromeos-release-builder-us-central1-b-x32-12-xijx) (Chromium OS 15.0_pre465103_p20220825-r4 clang version 15.0.0 (/var/tmp/portage/sys-devel/llvm-15.0_pre465103_p20220825-r4/work/llvm-15.0_pre465103_p20220825/clang db1978b67431ca3462ad8935bf662c15750b8252), LLD 15.0.0) #1 SMP PREEMPT Tue Jan 24 19:38:23 PST 2023
+    [    0.000000] Command line: loglevel=7 ... usb-storage.quirks=13fe:6500:u earlycon=uart8250,mmio32,0xfe03e000,115200n8
+    [    0.000000] x86/split lock detection: warning about user-space split_locks
+
+
 
 Return value
 ------------
diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst
new file mode 100644
index 0000000..8e1110c
--- /dev/null
+++ b/doc/usage/cmd/cedit.rst
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+cedit command
+=============
+
+Synopis
+-------
+
+::
+
+    cedit load <interface> <dev[:part]> <filename>
+    cedit run
+
+Description
+-----------
+
+The *cedit* command is used to load a configuration-editor description and allow
+the user to interact with it.
+
+It makes use of the expo subsystem.
+
+The description is in the form of a devicetree file, as documented at
+:ref:`expo_format`.
+
+Example
+-------
+
+::
+
+    => cedit load hostfs - fred.dtb
+    => cedit run
diff --git a/doc/usage/cmd/mtrr.rst b/doc/usage/cmd/mtrr.rst
new file mode 100644
index 0000000..531153b
--- /dev/null
+++ b/doc/usage/cmd/mtrr.rst
@@ -0,0 +1,151 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+mtrr command
+============
+
+Synopis
+-------
+
+    mtrr [list]
+    mtrr set <reg> <type> <start> <size>
+    mtrr disable <reg>
+    mtrr enable
+
+
+Description
+-----------
+
+The *mtrr* command is used to dump the Memory Type Range Registers (MTRRs) on
+an x86 machine. These register control cache behaviour in selected memory
+ranges.
+
+Note that the number of registers can vary between CPUs.
+
+
+mtrr [list]
+~~~~~~~~~~~
+
+List the MTRRs. The table shows the following information:
+
+Reg
+    Register number (the first is register 0)
+
+Valid
+    Shows Y if the register is valid (has bit 11 set), N if not
+
+Write-type
+    Shows the behaviour when writing to the memory region. The types are
+    abbreviated to fit a reasonable line length. Valid types shown below.
+
+    ======  ==============  ====================================================
+    Value   Type            Meaning
+    ======  ==============  ====================================================
+    0       Uncacheable     Skip cache and write directly to memory
+    1       Combine         Multiple writes can be combined into one transaction
+    4       Through         Update cache and also write to memory
+    5       Protect         Writes are prohibited
+    6       Back            Update cache but don't write to memory
+    ======  ==============  ====================================================
+
+Base
+    Base memory address from which the register controls behaviour
+
+Mask
+    Mask value, which also indicates the size
+
+Size
+    Length of memory region within which the register controls behaviour
+
+
+mtrr set
+~~~~~~~~
+
+This sets the value of a particular MTRR. Parameters are:
+
+reg
+    Register number to set, with 0 being the first
+
+type
+    Access type to set. See Write-type above for valid types. This uses the name
+    rather than its numeric value.
+
+start
+    Base memory address from which the register should control behaviour
+
+size
+    Length of memory region within which the register controls behaviour
+
+
+mtrr disable
+~~~~~~~~~~~~
+
+This disables a particular register, by clearing its `valid` bit (11).
+
+
+mtrr enable
+~~~~~~~~~~~
+
+This enables a particular register, by setting its `valid` bit (11).
+
+
+Example
+-------
+
+This shows disabling and enabling an MTRR, as well as setting its type::
+
+    => mtrr
+    CPU 0:
+    Reg Valid Write-type   Base   ||        Mask   ||        Size   ||
+    0   Y     Back         0000000000000000 0000000f80000000 0000000080000000
+    1   Y     Back         0000000080000000 0000000fe0000000 0000000020000000
+    2   Y     Back         00000000a0000000 0000000ff0000000 0000000010000000
+    3   Y     Uncacheable  00000000ad000000 0000000fff000000 0000000001000000
+    4   Y     Uncacheable  00000000ae000000 0000000ffe000000 0000000002000000
+    5   Y     Combine      00000000d0000000 0000000ff0000000 0000000010000000
+    6   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    7   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    8   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    9   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    => mtrr d 5
+    => mtrr
+    CPU 0:
+    Reg Valid Write-type   Base   ||        Mask   ||        Size   ||
+    0   Y     Back         0000000000000000 0000000f80000000 0000000080000000
+    1   Y     Back         0000000080000000 0000000fe0000000 0000000020000000
+    2   Y     Back         00000000a0000000 0000000ff0000000 0000000010000000
+    3   Y     Uncacheable  00000000ad000000 0000000fff000000 0000000001000000
+    4   Y     Uncacheable  00000000ae000000 0000000ffe000000 0000000002000000
+    5   N     Combine      00000000d0000000 0000000ff0000000 0000000010000000
+    6   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    7   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    8   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    9   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    => mtrr e 5
+    => mtrr
+    CPU 0:
+    Reg Valid Write-type   Base   ||        Mask   ||        Size   ||
+    0   Y     Back         0000000000000000 0000000f80000000 0000000080000000
+    1   Y     Back         0000000080000000 0000000fe0000000 0000000020000000
+    2   Y     Back         00000000a0000000 0000000ff0000000 0000000010000000
+    3   Y     Uncacheable  00000000ad000000 0000000fff000000 0000000001000000
+    4   Y     Uncacheable  00000000ae000000 0000000ffe000000 0000000002000000
+    5   Y     Combine      00000000d0000000 0000000ff0000000 0000000010000000
+    6   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    7   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    8   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    9   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    => mtrr set 5 Uncacheable d0000000 10000000
+    => mtrr
+    CPU 0:
+    Reg Valid Write-type   Base   ||        Mask   ||        Size   ||
+    0   Y     Back         0000000000000000 0000000f80000000 0000000080000000
+    1   Y     Back         0000000080000000 0000000fe0000000 0000000020000000
+    2   Y     Back         00000000a0000000 0000000ff0000000 0000000010000000
+    3   Y     Uncacheable  00000000ad000000 0000000fff000000 0000000001000000
+    4   Y     Uncacheable  00000000ae000000 0000000ffe000000 0000000002000000
+    5   Y     Uncacheable  00000000d0000000 0000000ff0000000 0000000010000000
+    6   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    7   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    8   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    9   N     Uncacheable  0000000000000000 0000000000000000 0000001000000000
+    =>
diff --git a/doc/usage/cmd/part.rst b/doc/usage/cmd/part.rst
index 8d2a280..8a594aa 100644
--- a/doc/usage/cmd/part.rst
+++ b/doc/usage/cmd/part.rst
@@ -13,6 +13,7 @@
     part start <interface> <dev> <part> <varname>
     part size <interface> <dev> <part> <varname>
     part number <interface> <dev> <part> <varname>
+    part set <interface> <dev> <part> <type>
     part type <interface> <dev>:<part> [varname]
     part types
 
@@ -82,6 +83,18 @@
     varname
         a variable to store the current partition number value into
 
+The 'part set' command sets the type of a partition. This is useful when
+autodetection fails or does not do the correct thing:
+
+    interface
+        interface for accessing the block device (mmc, sata, scsi, usb, ....)
+    dev
+        device number
+    part
+        partition number
+    type
+        partition type to use (see 'part types') to check available types
+
 The 'part type' command prints or sets an environment variable to the partition type UUID.
 
     interface
@@ -147,6 +160,67 @@
     => part types
     Supported partition tables: EFI, AMIGA, DOS, ISO, MAC
 
+This shows looking at a device with multiple partition tables::
+
+    => virtio scan
+    => part list virtio 0
+
+    Partition Map for VirtIO device 0  --   Partition Type: EFI
+
+    Part	Start LBA	End LBA		Name
+            Attributes
+            Type GUID
+            Partition GUID
+    1	0x00000040	0x0092b093	"ISO9660"
+            attrs:	0x1000000000000001
+            type:	ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
+            guid:	a0891d7e-b930-4513-94d8-f629dbd637b2
+    2	0x0092b094	0x0092d7e7	"Appended2"
+            attrs:	0x0000000000000000
+            type:	c12a7328-f81f-11d2-ba4b-00a0c93ec93b
+            guid:	a0891d7e-b930-4513-94db-f629dbd637b2
+    3	0x0092d7e8	0x0092da3f	"Gap1"
+            attrs:	0x1000000000000001
+            type:	ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
+            guid:	a0891d7e-b930-4513-94da-f629dbd637b2
+    => ls virtio 0:3
+    => part types
+    Supported partition tables: EFI, DOS, ISO
+    => part set virtio 0 dos
+
+    Partition Map for VirtIO device 0  --   Partition Type: DOS
+
+    Part	Start Sector	Num Sectors	UUID		Type
+    1	1         	9624191   	00000000-01	ee
+    => part set virtio 0 iso
+
+    Partition Map for VirtIO device 0  --   Partition Type: ISO
+
+    Part   Start     Sect x Size Type
+    1     3020        4    512 U-Boot
+    2  9613460    10068    512 U-Boot
+    => part set virtio 0 efi
+
+    Partition Map for VirtIO device 0  --   Partition Type: EFI
+
+    Part	Start LBA	End LBA		Name
+            Attributes
+            Type GUID
+            Partition GUID
+    1	0x00000040	0x0092b093	"ISO9660"
+            attrs:	0x1000000000000001
+            type:	ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
+            guid:	a0891d7e-b930-4513-94d8-f629dbd637b2
+    2	0x0092b094	0x0092d7e7	"Appended2"
+            attrs:	0x0000000000000000
+            type:	c12a7328-f81f-11d2-ba4b-00a0c93ec93b
+            guid:	a0891d7e-b930-4513-94db-f629dbd637b2
+    3	0x0092d7e8	0x0092da3f	"Gap1"
+            attrs:	0x1000000000000001
+            type:	ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
+            guid:	a0891d7e-b930-4513-94da-f629dbd637b2
+    =>
+
 Return value
 ------------
 
diff --git a/doc/usage/cmd/qfw.rst b/doc/usage/cmd/qfw.rst
index cc0e27c..ec13e09 100644
--- a/doc/usage/cmd/qfw.rst
+++ b/doc/usage/cmd/qfw.rst
@@ -41,18 +41,21 @@
 ::
 
     => qfw list
-    etc/boot-fail-wait
-    etc/smbios/smbios-tables
-    etc/smbios/smbios-anchor
-    etc/e820
-    genroms/kvmvapic.bin
-    genroms/linuxboot.bin
-    etc/system-states
-    etc/acpi/tables
-    etc/table-loader
-    etc/tpm/log
-    etc/acpi/rsdp
-    bootorder
+    00000000 bios-geometry
+    00000000 bootorder
+    000f0060 etc/acpi/rsdp
+    bed14040 etc/acpi/tables
+    00000000 etc/boot-fail-wait
+    00000000 etc/e820
+    00000000 etc/smbios/smbios-anchor
+    00000000 etc/smbios/smbios-tables
+    00000000 etc/system-states
+    00000000 etc/table-loader
+    00000000 etc/tpm/log
+    00000000 genroms/kvmvapic.bin
+
+Where an address is shown, it indicates where the data is available for
+inspection, e.g. using the :doc:`md`.
 
 The available CPUs can be shown via the *qfw cpus* command:
 
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 388e59f..072db53 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -39,6 +39,7 @@
    cmd/bootz
    cmd/cat
    cmd/cbsysinfo
+   cmd/cedit
    cmd/cls
    cmd/cmp
    cmd/coninfo
@@ -75,6 +76,7 @@
    cmd/md
    cmd/mmc
    cmd/mtest
+   cmd/mtrr
    cmd/panic
    cmd/part
    cmd/pause
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 75937fb..a25f6ae 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -10,6 +10,8 @@
 
 source "drivers/axi/Kconfig"
 
+source "drivers/bios_emulator/Kconfig"
+
 source "drivers/bus/Kconfig"
 
 source "drivers/block/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 78dcf62..3bc6d27 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0+
 
+obj-$(CONFIG_$(SPL_TPL_)BIOSEMU) += bios_emulator/
 obj-$(CONFIG_$(SPL_TPL_)BLK) += block/
 obj-$(CONFIG_$(SPL_TPL_)BOOTCOUNT_LIMIT) += bootcount/
 obj-$(CONFIG_$(SPL_TPL_)BUTTON) += button/
@@ -80,7 +81,6 @@
 obj-y += adc/
 obj-y += ata/
 obj-$(CONFIG_DM_DEMO) += demo/
-obj-$(CONFIG_BIOSEMU) += bios_emulator/
 obj-y += block/
 obj-y += cache/
 obj-$(CONFIG_CPU) += cpu/
diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig
index e719c38..4336732 100644
--- a/drivers/adc/Kconfig
+++ b/drivers/adc/Kconfig
@@ -63,3 +63,11 @@
 	  - core driver to deal with common resources
 	  - child driver to deal with individual ADC resources (declare ADC
 	  device and associated channels, start/stop conversions)
+
+config ADC_IMX93
+	bool "Enable NXP IMX93 ADC driver"
+	help
+	  This enables basic driver for NXP IMX93 ADC.
+	  It provides:
+	  - 4 analog input channels
+	  - 12-bit resolution
diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile
index c1387f3..5336c82 100644
--- a/drivers/adc/Makefile
+++ b/drivers/adc/Makefile
@@ -10,3 +10,4 @@
 obj-$(CONFIG_SARADC_ROCKCHIP) += rockchip-saradc.o
 obj-$(CONFIG_SARADC_MESON) += meson-saradc.o
 obj-$(CONFIG_STM32_ADC) += stm32-adc.o stm32-adc-core.o
+obj-$(CONFIG_ADC_IMX93) += imx93-adc.o
diff --git a/drivers/adc/imx93-adc.c b/drivers/adc/imx93-adc.c
new file mode 100644
index 0000000..41d04e0
--- /dev/null
+++ b/drivers/adc/imx93-adc.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2023 ASEM Srl
+ * Author: Luca Ellero <l.ellero@asem.it>
+ *
+ * Originally based on NXP linux-imx kernel v5.15 drivers/iio/adc/imx93_adc.c
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <clk.h>
+#include <adc.h>
+
+#define IMX93_ADC_MCR			0x00
+#define IMX93_ADC_MSR			0x04
+#define IMX93_ADC_ISR			0x10
+#define IMX93_ADC_IMR			0x20
+#define IMX93_ADC_CIMR0			0x24
+#define IMX93_ADC_CTR0			0x94
+#define IMX93_ADC_NCMR0			0xA4
+#define IMX93_ADC_PCDR0			0x100
+#define IMX93_ADC_PCDR1			0x104
+#define IMX93_ADC_PCDR2			0x108
+#define IMX93_ADC_PCDR3			0x10c
+#define IMX93_ADC_PCDR4			0x110
+#define IMX93_ADC_PCDR5			0x114
+#define IMX93_ADC_PCDR6			0x118
+#define IMX93_ADC_PCDR7			0x11c
+#define IMX93_ADC_CALSTAT		0x39C
+
+#define IMX93_ADC_MCR_MODE_MASK		BIT(29)
+#define IMX93_ADC_MCR_NSTART_MASK	BIT(24)
+#define IMX93_ADC_MCR_CALSTART_MASK	BIT(14)
+#define IMX93_ADC_MCR_ADCLKSE_MASK	BIT(8)
+#define IMX93_ADC_MCR_PWDN_MASK		BIT(0)
+
+#define IMX93_ADC_MSR_CALFAIL_MASK	BIT(30)
+#define IMX93_ADC_MSR_CALBUSY_MASK	BIT(29)
+#define IMX93_ADC_MSR_ADCSTATUS_MASK	GENMASK(2, 0)
+
+#define IMX93_ADC_ISR_EOC_MASK		BIT(1)
+
+#define IMX93_ADC_IMR_EOC_MASK		BIT(1)
+#define IMX93_ADC_IMR_ECH_MASK		BIT(0)
+
+#define IMX93_ADC_PCDR_CDATA_MASK	GENMASK(11, 0)
+
+#define IDLE				0
+#define POWER_DOWN			1
+#define WAIT_STATE			2
+#define BUSY_IN_CALIBRATION		3
+#define SAMPLE				4
+#define CONVERSION			6
+
+#define IMX93_ADC_MAX_CHANNEL		3
+#define IMX93_ADC_DAT_MASK		0xfff
+#define IMX93_ADC_TIMEOUT		100000
+
+struct imx93_adc_priv {
+	int active_channel;
+	void __iomem *regs;
+	struct clk ipg_clk;
+};
+
+static void imx93_adc_power_down(struct imx93_adc_priv *adc)
+{
+	u32 mcr, msr;
+	int ret;
+
+	mcr = readl(adc->regs + IMX93_ADC_MCR);
+	mcr |= FIELD_PREP(IMX93_ADC_MCR_PWDN_MASK, 1);
+	writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+	ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr,
+		((msr & IMX93_ADC_MSR_ADCSTATUS_MASK) == POWER_DOWN), 50);
+	if (ret == -ETIMEDOUT)
+		pr_warn("ADC not in power down mode, current MSR: %x\n", msr);
+}
+
+static void imx93_adc_power_up(struct imx93_adc_priv *adc)
+{
+	u32 mcr;
+
+	/* bring ADC out of power down state, in idle state */
+	mcr = readl(adc->regs + IMX93_ADC_MCR);
+	mcr &= ~FIELD_PREP(IMX93_ADC_MCR_PWDN_MASK, 1);
+	writel(mcr, adc->regs + IMX93_ADC_MCR);
+}
+
+static void imx93_adc_config_ad_clk(struct imx93_adc_priv *adc)
+{
+	u32 mcr;
+
+	/* put adc in power down mode */
+	imx93_adc_power_down(adc);
+
+	/* config the AD_CLK equal to bus clock */
+	mcr = readl(adc->regs + IMX93_ADC_MCR);
+	mcr |= FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1);
+	writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+	/* bring ADC out of power down state, in idle state */
+	imx93_adc_power_up(adc);
+}
+
+static int imx93_adc_calibration(struct imx93_adc_priv *adc)
+{
+	u32 mcr, msr;
+	int ret;
+
+	/* make sure ADC is in power down mode */
+	imx93_adc_power_down(adc);
+
+	/* config SAR controller operating clock */
+	mcr = readl(adc->regs + IMX93_ADC_MCR);
+	mcr &= ~FIELD_PREP(IMX93_ADC_MCR_ADCLKSE_MASK, 1);
+	writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+	/* bring ADC out of power down state */
+	imx93_adc_power_up(adc);
+
+	/*
+	 * we use the default TSAMP/NRSMPL/AVGEN in MCR,
+	 * can add the setting of these bit if need
+	 */
+
+	/* run calibration */
+	mcr = readl(adc->regs + IMX93_ADC_MCR);
+	mcr |= FIELD_PREP(IMX93_ADC_MCR_CALSTART_MASK, 1);
+	writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+	/* wait calibration to be finished */
+	ret = readl_poll_timeout(adc->regs + IMX93_ADC_MSR, msr,
+		!(msr & IMX93_ADC_MSR_CALBUSY_MASK), 2000000);
+	if (ret == -ETIMEDOUT) {
+		pr_warn("ADC calibration timeout\n");
+		return ret;
+	}
+
+	/* check whether calbration is successful or not */
+	msr = readl(adc->regs + IMX93_ADC_MSR);
+	if (msr & IMX93_ADC_MSR_CALFAIL_MASK) {
+		pr_warn("ADC calibration failed!\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static int imx93_adc_channel_data(struct udevice *dev, int channel,
+			    unsigned int *data)
+{
+	struct imx93_adc_priv *adc = dev_get_priv(dev);
+	u32 isr, pcda;
+	int ret;
+
+	if (channel != adc->active_channel) {
+		pr_err("Requested channel is not active!\n");
+		return -EINVAL;
+	}
+
+	ret = readl_poll_timeout(adc->regs + IMX93_ADC_ISR, isr,
+		(isr & IMX93_ADC_ISR_EOC_MASK), IMX93_ADC_TIMEOUT);
+
+	/* clear interrupts */
+	writel(isr, adc->regs + IMX93_ADC_ISR);
+
+	if (ret == -ETIMEDOUT) {
+		pr_warn("ADC conversion timeout!\n");
+		return ret;
+	}
+
+	pcda = readl(adc->regs + IMX93_ADC_PCDR0 + channel * 4);
+
+	*data = FIELD_GET(IMX93_ADC_PCDR_CDATA_MASK, pcda);
+
+	return 0;
+}
+
+static int imx93_adc_start_channel(struct udevice *dev, int channel)
+{
+	struct imx93_adc_priv *adc = dev_get_priv(dev);
+	u32 imr, mcr;
+
+	/* config channel mask register */
+	writel(1 << channel, adc->regs + IMX93_ADC_NCMR0);
+
+	/* config interrupt mask */
+	imr = FIELD_PREP(IMX93_ADC_IMR_EOC_MASK, 1);
+	writel(imr, adc->regs + IMX93_ADC_IMR);
+	writel(1 << channel, adc->regs + IMX93_ADC_CIMR0);
+
+	/* config one-shot mode */
+	mcr = readl(adc->regs + IMX93_ADC_MCR);
+	mcr &= ~FIELD_PREP(IMX93_ADC_MCR_MODE_MASK, 1);
+	writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+	/* start normal conversion */
+	mcr = readl(adc->regs + IMX93_ADC_MCR);
+	mcr |= FIELD_PREP(IMX93_ADC_MCR_NSTART_MASK, 1);
+	writel(mcr, adc->regs + IMX93_ADC_MCR);
+
+	adc->active_channel = channel;
+
+	return 0;
+}
+
+static int imx93_adc_stop(struct udevice *dev)
+{
+	struct imx93_adc_priv *adc = dev_get_priv(dev);
+
+	imx93_adc_power_down(adc);
+
+	adc->active_channel = -1;
+
+	return 0;
+}
+
+static int imx93_adc_probe(struct udevice *dev)
+{
+	struct imx93_adc_priv *adc = dev_get_priv(dev);
+	unsigned int ret;
+
+	ret = imx93_adc_calibration(adc);
+	if (ret < 0)
+		return ret;
+
+	imx93_adc_config_ad_clk(adc);
+
+	adc->active_channel = -1;
+
+	return 0;
+}
+
+static int imx93_adc_of_to_plat(struct udevice *dev)
+{
+	struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
+	struct imx93_adc_priv *adc = dev_get_priv(dev);
+	unsigned int ret;
+
+	adc->regs = dev_read_addr_ptr(dev);
+	if (adc->regs == (struct imx93_adc *)FDT_ADDR_T_NONE) {
+		pr_err("Dev: %s - can't get address!", dev->name);
+		return -ENODATA;
+	}
+
+	ret = clk_get_by_name(dev, "ipg", &adc->ipg_clk);
+	if (ret < 0) {
+		pr_err("Can't get ADC ipg clk: %d\n", ret);
+		return ret;
+	}
+	ret = clk_enable(&adc->ipg_clk);
+	if(ret) {
+		pr_err("Can't enable ADC ipg clk: %d\n", ret);
+		return ret;
+	}
+
+	uc_pdata->data_mask = IMX93_ADC_DAT_MASK;
+	uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
+	uc_pdata->data_timeout_us = IMX93_ADC_TIMEOUT;
+
+	/* Mask available channel bits: [0:3] */
+	uc_pdata->channel_mask = (2 << IMX93_ADC_MAX_CHANNEL) - 1;
+
+	return 0;
+}
+
+static const struct adc_ops imx93_adc_ops = {
+	.start_channel = imx93_adc_start_channel,
+	.channel_data = imx93_adc_channel_data,
+	.stop = imx93_adc_stop,
+};
+
+static const struct udevice_id imx93_adc_ids[] = {
+	{ .compatible = "nxp,imx93-adc" },
+	{ }
+};
+
+U_BOOT_DRIVER(imx93_adc) = {
+	.name		= "imx93-adc",
+	.id		= UCLASS_ADC,
+	.of_match	= imx93_adc_ids,
+	.ops		= &imx93_adc_ops,
+	.probe		= imx93_adc_probe,
+	.of_to_plat	= imx93_adc_of_to_plat,
+	.priv_auto	= sizeof(struct imx93_adc_priv),
+};
diff --git a/drivers/bios_emulator/Kconfig b/drivers/bios_emulator/Kconfig
new file mode 100644
index 0000000..3660576
--- /dev/null
+++ b/drivers/bios_emulator/Kconfig
@@ -0,0 +1,10 @@
+config BIOSEMU
+	bool
+	select X86EMU_RAW_IO
+
+config SPL_BIOSEMU
+	bool
+	select X86EMU_RAW_IO
+
+config X86EMU_RAW_IO
+	bool
diff --git a/drivers/bios_emulator/biosemui.h b/drivers/bios_emulator/biosemui.h
index 7853015..954cd88 100644
--- a/drivers/bios_emulator/biosemui.h
+++ b/drivers/bios_emulator/biosemui.h
@@ -128,19 +128,19 @@
 	u32 finalVal;
 } BE_portInfo;
 
-#define PM_inpb(port)	inb(port+VIDEO_IO_OFFSET)
-#define PM_inpw(port)	inw(port+VIDEO_IO_OFFSET)
-#define PM_inpd(port)	inl(port+VIDEO_IO_OFFSET)
-#define PM_outpb(port,val)	outb(val,port+VIDEO_IO_OFFSET)
-#define PM_outpw(port,val)	outw(val,port+VIDEO_IO_OFFSET)
-#define PM_outpd(port,val)	outl(val,port+VIDEO_IO_OFFSET)
+#define PM_inpb(port)	inb(port)
+#define PM_inpw(port)	inw(port)
+#define PM_inpd(port)	inl(port)
+#define PM_outpb(port, val)	outb(val, port)
+#define PM_outpw(port, val)	outw(val, port)
+#define PM_outpd(port, val)	outl(val, port)
 
 #define LOG_inpb(port)	PM_inpb(port)
 #define LOG_inpw(port)	PM_inpw(port)
 #define LOG_inpd(port)	PM_inpd(port)
-#define LOG_outpb(port,val)	PM_outpb(port,val)
-#define LOG_outpw(port,val)	PM_outpw(port,val)
-#define LOG_outpd(port,val)	PM_outpd(port,val)
+#define LOG_outpb(port, val)	PM_outpb(port, val)
+#define LOG_outpw(port, val)	PM_outpw(port, val)
+#define LOG_outpd(port, val)	PM_outpd(port, val)
 
 /*-------------------------- Function Prototypes --------------------------*/
 
diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c
index c2db121..882a8a3 100644
--- a/drivers/bios_emulator/x86emu/sys.c
+++ b/drivers/bios_emulator/x86emu/sys.c
@@ -44,6 +44,7 @@
 
 /*------------------------- Global Variables ------------------------------*/
 
+/* Note: bios.c defines this if the emulator is not enabled */
 X86EMU_sysEnv _X86EMU_env;	/* Global emulator machine state */
 X86EMU_intrFuncs _X86EMU_intrTab[256];
 
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3ad5af9..29859cd 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -160,6 +160,7 @@
 
 config CLK_SCMI
 	bool "Enable SCMI clock driver"
+	depends on CLK
 	depends on SCMI_FIRMWARE
 	help
 	  Enable this option if you want to support clock devices exposed
diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
index 09bef59..a21a3ce 100644
--- a/drivers/clk/imx/clk-imx8mp.c
+++ b/drivers/clk/imx/clk-imx8mp.c
@@ -337,7 +337,8 @@
 	clk_dm(IMX8MP_CLK_UART2_ROOT, imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0));
 	clk_dm(IMX8MP_CLK_UART3_ROOT, imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0));
 	clk_dm(IMX8MP_CLK_UART4_ROOT, imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0));
-	clk_dm(IMX8MP_CLK_USB_ROOT, imx_clk_gate4("usb_root_clk", "usb_core_ref", base + 0x44d0, 0));
+	clk_dm(IMX8MP_CLK_USB_ROOT, imx_clk_gate2("usb_root_clk", "hsio_axi", base + 0x44d0, 0));
+	clk_dm(IMX8MP_CLK_USB_SUSP, imx_clk_gate2("usb_suspend_clk", "clock-osc-24m", base + 0x44d0, 0));
 	clk_dm(IMX8MP_CLK_USB_PHY_ROOT, imx_clk_gate4("usb_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0));
 	clk_dm(IMX8MP_CLK_USDHC1_ROOT, imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0));
 	clk_dm(IMX8MP_CLK_USDHC2_ROOT, imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0));
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index ec574c4..8df16e5 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -12,6 +12,7 @@
 #include <fdt_support.h>
 #include <log.h>
 #include <malloc.h>
+#include <of_live.h>
 #include <linux/libfdt.h>
 #include <dm/of_access.h>
 #include <dm/of_addr.h>
@@ -51,6 +52,20 @@
 	oftree tree;
 	int i;
 
+	if (of_live_active()) {
+		struct device_node *root;
+		int ret;
+
+		ret = unflatten_device_tree(fdt, &root);
+		if (ret) {
+			log_err("Failed to create live tree: err=%d\n", ret);
+			return oftree_null();
+		}
+		tree = oftree_from_np(root);
+
+		return tree;
+	}
+
 	if (gd->flags & GD_FLG_RELOC) {
 		i = oftree_find(fdt);
 		if (i == -1) {
@@ -67,7 +82,7 @@
 		}
 	} else {
 		if (fdt != gd->fdt_blob) {
-			log_debug("Cannot only access control FDT before relocation\n");
+			log_debug("Only the control FDT can be accessed before relocation\n");
 			return oftree_null();
 		}
 	}
@@ -77,6 +92,12 @@
 	return tree;
 }
 
+void oftree_dispose(oftree tree)
+{
+	if (of_live_active())
+		of_live_free(tree.np);
+}
+
 void *ofnode_lookup_fdt(ofnode node)
 {
 	if (gd->flags & GD_FLG_RELOC) {
@@ -133,6 +154,10 @@
 	if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
 		return oftree_ensure(fdt);
 
+#ifdef OF_CHECKS
+	if (of_live_active())
+		return oftree_null();
+#endif
 	tree.fdt = fdt;
 
 	return tree;
diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig
index c3a0b93..4e80e85 100644
--- a/drivers/dfu/Kconfig
+++ b/drivers/dfu/Kconfig
@@ -35,6 +35,7 @@
 
 config DFU_MMC
 	bool "MMC back end for DFU"
+	depends on MMC
 	help
 	  This option enables using DFU to read and write to MMC based storage.
 
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 54d563d..02de692 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -46,7 +46,7 @@
 
 	for (n = 0; n < ARRAY_SIZE(scmi_linux_errmap); n++)
 		if (scmi_code == scmi_linux_errmap[n].scmi)
-			return scmi_linux_errmap[1].errno;
+			return scmi_linux_errmap[n].errno;
 
 	return -EPROTO;
 }
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 712119c..31027f3 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -1474,7 +1474,7 @@
 	}
 #endif
 
-	if (CONFIG_IS_ENABLED(GPIO_HOG)) {
+	if (CONFIG_IS_ENABLED(GPIO_HOG) && dev_has_ofnode(dev)) {
 		struct udevice *child;
 		ofnode node;
 
diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c
index 63a07b9..2ed0d0b 100644
--- a/drivers/gpio/intel_ich6_gpio.c
+++ b/drivers/gpio/intel_ich6_gpio.c
@@ -26,6 +26,8 @@
  * reserved or subject to arcane restrictions.
  */
 
+#define LOG_CATEGORY	UCLASS_GPIO
+
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
@@ -155,8 +157,7 @@
 	 */
 	tmplong = inl(bank->use_sel);
 	if (!(tmplong & (1UL << offset))) {
-		debug("%s: gpio %d is reserved for internal use\n", __func__,
-		      offset);
+		log_debug("gpio %d is reserved for internal use\n", offset);
 		return -EPERM;
 	}
 
diff --git a/drivers/led/led_bcm6753.c b/drivers/led/led_bcm6753.c
index 88b650c..2466d93 100644
--- a/drivers/led/led_bcm6753.c
+++ b/drivers/led/led_bcm6753.c
@@ -174,57 +174,65 @@
 
 static int bcm6753_led_probe(struct udevice *dev)
 {
-	struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+	struct bcm6753_led_priv *priv = dev_get_priv(dev);
+	void __iomem *regs;
+	unsigned int pin;
 
-	/* Top-level LED node */
-	if (!uc_plat->label) {
-		void __iomem *regs;
-		u32 set_bits = 0;
+	regs = dev_remap_addr(dev_get_parent(dev));
+	if (!regs)
+		return -EINVAL;
 
-		regs = dev_remap_addr(dev);
-		if (!regs)
-			return -EINVAL;
+	pin = dev_read_u32_default(dev, "reg", LEDS_MAX);
+	if (pin >= LEDS_MAX)
+		return -EINVAL;
 
-		if (dev_read_bool(dev, "brcm,serial-led-msb-first"))
-			set_bits |= CLED_CTRL_SERIAL_LED_MSB_FIRST;
-		if (dev_read_bool(dev, "brcm,serial-led-en-pol"))
-			set_bits |= CLED_CTRL_SERIAL_LED_EN_POL;
-		if (dev_read_bool(dev, "brcm,serial-led-clk-pol"))
-			set_bits |= CLED_CTRL_SERIAL_LED_CLK_POL;
-		if (dev_read_bool(dev, "brcm,serial-led-data-ppol"))
-			set_bits |= CLED_CTRL_SERIAL_LED_DATA_PPOL;
+	priv->regs = regs;
+	priv->pin = pin;
 
-		clrsetbits_32(regs + CLED_CTRL_REG, CLED_CTRL_MASK, set_bits);
-	} else {
-		struct bcm6753_led_priv *priv = dev_get_priv(dev);
-		void __iomem *regs;
-		unsigned int pin;
+	/* this led is managed by software */
+	clrbits_32(regs + CLED_HW_LED_EN_REG, 1 << pin);
 
-		regs = dev_remap_addr(dev_get_parent(dev));
-		if (!regs)
-			return -EINVAL;
+	/* configure the polarity */
+	if (dev_read_bool(dev, "active-low"))
+		clrbits_32(regs + CLED_PLED_OP_PPOL_REG, 1 << pin);
+	else
+		setbits_32(regs + CLED_PLED_OP_PPOL_REG, 1 << pin);
 
-		pin = dev_read_u32_default(dev, "reg", LEDS_MAX);
-		if (pin >= LEDS_MAX)
-			return -EINVAL;
+	return 0;
+}
 
-		priv->regs = regs;
-		priv->pin = pin;
+U_BOOT_DRIVER(bcm6753_led) = {
+	.name = "bcm6753-led",
+	.id = UCLASS_LED,
+	.probe = bcm6753_led_probe,
+	.priv_auto = sizeof(struct bcm6753_led_priv),
+	.ops = &bcm6753_led_ops,
+};
 
-		/* this led is managed by software */
-		clrbits_32(regs + CLED_HW_LED_EN_REG, 1 << pin);
+static int bcm6753_led_wrap_probe(struct udevice *dev)
+{
+	void __iomem *regs;
+	u32 set_bits = 0;
 
-		/* configure the polarity */
-		if (dev_read_bool(dev, "active-low"))
-			clrbits_32(regs + CLED_PLED_OP_PPOL_REG, 1 << pin);
-		else
-			setbits_32(regs + CLED_PLED_OP_PPOL_REG, 1 << pin);
-	}
+	regs = dev_remap_addr(dev);
+	if (!regs)
+		return -EINVAL;
+
+	if (dev_read_bool(dev, "brcm,serial-led-msb-first"))
+		set_bits |= CLED_CTRL_SERIAL_LED_MSB_FIRST;
+	if (dev_read_bool(dev, "brcm,serial-led-en-pol"))
+		set_bits |= CLED_CTRL_SERIAL_LED_EN_POL;
+	if (dev_read_bool(dev, "brcm,serial-led-clk-pol"))
+		set_bits |= CLED_CTRL_SERIAL_LED_CLK_POL;
+	if (dev_read_bool(dev, "brcm,serial-led-data-ppol"))
+		set_bits |= CLED_CTRL_SERIAL_LED_DATA_PPOL;
+
+	clrsetbits_32(regs + CLED_CTRL_REG, CLED_CTRL_MASK, set_bits);
 
 	return 0;
 }
 
-static int bcm6753_led_bind(struct udevice *parent)
+static int bcm6753_led_wrap_bind(struct udevice *parent)
 {
 	ofnode node;
 
@@ -247,12 +255,10 @@
 	{ /* sentinel */ }
 };
 
-U_BOOT_DRIVER(bcm6753_led) = {
-	.name = "bcm6753-led",
-	.id = UCLASS_LED,
+U_BOOT_DRIVER(bcm6753_led_wrap) = {
+	.name	= "bcm6753_led_wrap",
+	.id	= UCLASS_NOP,
 	.of_match = bcm6753_led_ids,
-	.bind = bcm6753_led_bind,
-	.probe = bcm6753_led_probe,
-	.priv_auto = sizeof(struct bcm6753_led_priv),
-	.ops = &bcm6753_led_ops,
+	.probe = bcm6753_led_wrap_probe,
+	.bind = bcm6753_led_wrap_bind,
 };
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 04460f1..b9f5c7a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -364,8 +364,8 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called npcm_otp.
 
-config IMX_SENTINEL
-	bool "Enable i.MX Sentinel MU driver and API"
+config IMX_ELE
+	bool "Enable i.MX EdgeLock Enclave MU driver and API"
 	depends on MISC && (ARCH_IMX9 || ARCH_IMX8ULP)
 	help
 	  If you say Y here to enable Message Unit driver to work with
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 52aed09..fd8805f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -47,7 +47,7 @@
 obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
 obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
 obj-$(CONFIG_IMX8) += imx8/
-obj-$(CONFIG_IMX_SENTINEL) += sentinel/
+obj-$(CONFIG_IMX_ELE) += imx_ele/
 obj-$(CONFIG_LED_STATUS) += status_led.o
 obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
 obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
diff --git a/drivers/misc/imx8/scu_api.c b/drivers/misc/imx8/scu_api.c
index dfede7f..3e3002b 100644
--- a/drivers/misc/imx8/scu_api.c
+++ b/drivers/misc/imx8/scu_api.c
@@ -481,6 +481,22 @@
 	return 0;
 }
 
+void sc_misc_get_button_status(sc_ipc_t ipc, sc_bool_t *status)
+{
+	struct sc_rpc_msg_s msg;
+	struct udevice *dev = gd->arch.scu_dev;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SIZE(&msg) = 1U;
+	RPC_SVC(&msg) = (u8)(SC_RPC_SVC_MISC);
+	RPC_FUNC(&msg) = (u8)(MISC_FUNC_GET_BUTTON_STATUS);
+
+	misc_call(dev, SC_FALSE, &msg, 1U, &msg, 1U);
+
+	if (status)
+		*status = (sc_bool_t)(!!(RPC_U8(&msg, 0U)));
+}
+
 /* RM */
 sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr)
 {
@@ -851,6 +867,21 @@
 	return ret;
 }
 
+void sc_pm_reboot(sc_ipc_t ipc, sc_pm_reset_type_t type)
+{
+	struct udevice *dev = gd->arch.scu_dev;
+	struct sc_rpc_msg_s msg;
+	int size = sizeof(struct sc_rpc_msg_s);
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SVC(&msg) = (u8)(SC_RPC_SVC_PM);
+	RPC_FUNC(&msg) = (u8)(PM_FUNC_REBOOT);
+	RPC_U8(&msg, 0U) = (u8)(type);
+	RPC_SIZE(&msg) = 2U;
+
+	misc_call(dev, SC_TRUE, &msg, size, &msg, size);
+}
+
 int sc_pm_get_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
 				  sc_pm_power_mode_t *mode)
 {
@@ -877,6 +908,28 @@
 	return ret;
 }
 
+int sc_timer_set_wdog_window(sc_ipc_t ipc, sc_timer_wdog_time_t window)
+{
+	struct udevice *dev = gd->arch.scu_dev;
+	struct sc_rpc_msg_s msg;
+	int size = sizeof(struct sc_rpc_msg_s);
+	int ret;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SIZE(&msg) = 2U;
+	RPC_SVC(&msg) = (u8)(SC_RPC_SVC_TIMER);
+	RPC_FUNC(&msg) = (u8)(TIMER_FUNC_SET_WDOG_WINDOW);
+
+	RPC_U32(&msg, 0U) = (u32)(window);
+
+	ret = misc_call(dev, SC_FALSE, &msg, size, &msg, size);
+	if (ret)
+		printf("%s: window:%u: res:%d\n",
+		       __func__, window, RPC_R8(&msg));
+
+	return ret;
+}
+
 int sc_seco_authenticate(sc_ipc_t ipc, sc_seco_auth_cmd_t cmd,
 			 sc_faddr_t addr)
 {
@@ -974,6 +1027,31 @@
 		*commit = RPC_U32(&msg, 4U);
 }
 
+int sc_seco_v2x_build_info(sc_ipc_t ipc, u32 *version, u32 *commit)
+{
+	struct udevice *dev = gd->arch.scu_dev;
+	struct sc_rpc_msg_s msg;
+	int size = sizeof(struct sc_rpc_msg_s);
+	int ret;
+
+	RPC_VER(&msg) = SC_RPC_VERSION;
+	RPC_SIZE(&msg) = 1U;
+	RPC_SVC(&msg) = (u8)(SC_RPC_SVC_SECO);
+	RPC_FUNC(&msg) = (u8)(SECO_FUNC_V2X_BUILD_INFO);
+
+	ret = misc_call(dev, SC_FALSE, &msg, size, &msg, size);
+	if (ret)
+		printf("%s: res:%d\n", __func__, RPC_R8(&msg));
+
+	if (version)
+		*version = RPC_U32(&msg, 0U);
+
+	if (commit)
+		*commit = RPC_U32(&msg, 4U);
+
+	return ret;
+}
+
 int sc_seco_get_event(sc_ipc_t ipc, u8 idx, u32 *event)
 {
 	struct udevice *dev = gd->arch.scu_dev;
diff --git a/drivers/misc/sentinel/Makefile b/drivers/misc/imx_ele/Makefile
similarity index 71%
rename from drivers/misc/sentinel/Makefile
rename to drivers/misc/imx_ele/Makefile
index 446154c..f8d8c55 100644
--- a/drivers/misc/sentinel/Makefile
+++ b/drivers/misc/imx_ele/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0+
 
-obj-y += s400_api.o s4mu.o
+obj-y += ele_api.o ele_mu.o
 obj-$(CONFIG_CMD_FUSE) += fuse.o
diff --git a/drivers/misc/imx_ele/ele_api.c b/drivers/misc/imx_ele/ele_api.c
new file mode 100644
index 0000000..0c01773
--- /dev/null
+++ b/drivers/misc/imx_ele/ele_api.c
@@ -0,0 +1,623 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2020, 2023 NXP
+ *
+ */
+
+#include <common.h>
+#include <hang.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <asm/mach-imx/ele_api.h>
+#include <misc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u32 compute_crc(const struct ele_msg *msg)
+{
+	u32 crc = 0;
+	size_t i = 0;
+	u32 *data = (u32 *)msg;
+
+	for (i = 0; i < (msg->size - 1); i++)
+		crc ^= data[i];
+
+	return crc;
+}
+
+int ele_release_rdc(u8 core_id, u8 xrdc, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 2;
+	msg.command = ELE_RELEASE_RDC_REQ;
+	switch (xrdc) {
+	case 0:
+		msg.data[0] = (0x74 << 8) | core_id;
+		break;
+	case 1:
+		msg.data[0] = (0x78 << 8) | core_id;
+		break;
+	case 2:
+		msg.data[0] = (0x82 << 8) | core_id;
+		break;
+	case 3:
+		msg.data[0] = (0x86 << 8) | core_id;
+		break;
+	default:
+		printf("Error: wrong xrdc index %u\n", xrdc);
+		return -EINVAL;
+	}
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, core id %u, response 0x%x\n",
+		       __func__, ret, core_id, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_auth_oem_ctnr(ulong ctnr_addr, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 3;
+	msg.command = ELE_OEM_CNTN_AUTH_REQ;
+	msg.data[0] = upper_32_bits(ctnr_addr);
+	msg.data[1] = lower_32_bits(ctnr_addr);
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, cntr_addr 0x%lx, response 0x%x\n",
+		       __func__, ret, ctnr_addr, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_release_container(u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 1;
+	msg.command = ELE_RELEASE_CONTAINER_REQ;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_verify_image(u32 img_id, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 2;
+	msg.command = ELE_VERIFY_IMAGE_REQ;
+	msg.data[0] = 1 << img_id;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, img_id %u, response 0x%x\n",
+		       __func__, ret, img_id, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_forward_lifecycle(u16 life_cycle, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 2;
+	msg.command = ELE_FWD_LIFECYCLE_UP_REQ;
+	msg.data[0] = life_cycle;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, life_cycle 0x%x, response 0x%x\n",
+		       __func__, ret, life_cycle, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	if (!fuse_words) {
+		printf("Invalid parameters for fuse read\n");
+		return -EINVAL;
+	}
+
+	if ((fuse_id != 1 && fuse_num != 1) ||
+	    (fuse_id == 1 && fuse_num != 4)) {
+		printf("Invalid fuse number parameter\n");
+		return -EINVAL;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 2;
+	msg.command = ELE_READ_FUSE_REQ;
+	msg.data[0] = fuse_id;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n",
+		       __func__, ret, fuse_id, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	fuse_words[0] = msg.data[1];
+	if (fuse_id == 1) {
+		/* OTP_UNIQ_ID */
+		fuse_words[1] = msg.data[2];
+		fuse_words[2] = msg.data[3];
+		fuse_words[3] = msg.data[4];
+	}
+
+	return ret;
+}
+
+int ele_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 3;
+	msg.command = ELE_WRITE_FUSE_REQ;
+	msg.data[0] = (32 << 16) | (fuse_id << 5);
+	if (lock)
+		msg.data[0] |= (1 << 31);
+
+	msg.data[1] = fuse_val;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n",
+		       __func__, ret, fuse_id, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_release_caam(u32 core_did, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 2;
+	msg.command = ELE_RELEASE_CAAM_REQ;
+	msg.data[0] = core_did;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_get_fw_version(u32 *fw_version, u32 *sha1, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	if (!fw_version) {
+		printf("Invalid parameters for f/w version read\n");
+		return -EINVAL;
+	}
+
+	if (!sha1) {
+		printf("Invalid parameters for commit sha1\n");
+		return -EINVAL;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 1;
+	msg.command = ELE_GET_FW_VERSION_REQ;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	*fw_version = msg.data[1];
+	*sha1 = msg.data[2];
+
+	return ret;
+}
+
+int ele_dump_buffer(u32 *buffer, u32 buffer_length)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret, i = 0;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 1;
+	msg.command = ELE_DUMP_DEBUG_BUFFER_REQ;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret) {
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+		return ret;
+	}
+
+	if (buffer) {
+		buffer[i++] = *(u32 *)&msg; /* Need dump the response header */
+		for (; i < buffer_length && i < msg.size; i++)
+			buffer[i] = msg.data[i - 1];
+	}
+
+	return i;
+}
+
+int ele_get_info(struct ele_get_info_data *info, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 4;
+	msg.command = ELE_GET_INFO_REQ;
+	msg.data[0] = upper_32_bits((ulong)info);
+	msg.data[1] = lower_32_bits((ulong)info);
+	msg.data[2] = sizeof(struct ele_get_info_data);
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_get_fw_status(u32 *status, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 1;
+	msg.command = ELE_GET_FW_STATUS_REQ;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	*status = msg.data[1] & 0xF;
+
+	return ret;
+}
+
+int ele_release_m33_trout(void)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 1;
+	msg.command = ELE_ENABLE_RTC_REQ;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	return ret;
+}
+
+int ele_get_events(u32 *events, u32 *events_cnt, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret, i = 0;
+	u32 actual_events;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	if (!events || !events_cnt || *events_cnt == 0) {
+		printf("Invalid parameters for %s\n", __func__);
+		return -EINVAL;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 1;
+	msg.command = ELE_GET_EVENTS_REQ;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	if (response)
+		*response = msg.data[0];
+
+	if (!ret) {
+		actual_events = msg.data[1] & 0xffff;
+		if (*events_cnt < actual_events)
+			actual_events = *events_cnt;
+
+		for (; i < actual_events; i++)
+			events[i] = msg.data[i + 2];
+
+		*events_cnt = actual_events;
+	}
+
+	return ret;
+}
+
+int ele_start_rng(void)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 1;
+	msg.command = ELE_START_RNG;
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	return ret;
+}
+
+int ele_write_secure_fuse(ulong signed_msg_blk, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 3;
+	msg.command = ELE_WRITE_SECURE_FUSE_REQ;
+
+	msg.data[0] = upper_32_bits(signed_msg_blk);
+	msg.data[1] = lower_32_bits(signed_msg_blk);
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x, failed fuse row index %u\n",
+		       __func__, ret, msg.data[0], msg.data[1]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_return_lifecycle_update(ulong signed_msg_blk, u32 *response)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 3;
+	msg.command = ELE_RET_LIFECYCLE_UP_REQ;
+
+	msg.data[0] = upper_32_bits(signed_msg_blk);
+	msg.data[1] = lower_32_bits(signed_msg_blk);
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret %d, response 0x%x, failed fuse row index %u\n",
+		       __func__, ret, msg.data[0], msg.data[1]);
+
+	if (response)
+		*response = msg.data[0];
+
+	return ret;
+}
+
+int ele_generate_dek_blob(u32 key_id, u32 src_paddr, u32 dst_paddr, u32 max_output_size)
+{
+	struct udevice *dev = gd->arch.ele_dev;
+	int size = sizeof(struct ele_msg);
+	struct ele_msg msg;
+	int ret;
+
+	if (!dev) {
+		printf("ele dev is not initialized\n");
+		return -ENODEV;
+	}
+
+	msg.version = ELE_VERSION;
+	msg.tag = ELE_CMD_TAG;
+	msg.size = 8;
+	msg.command = ELE_GENERATE_DEK_BLOB;
+	msg.data[0] = key_id;
+	msg.data[1] = 0x0;
+	msg.data[2] = src_paddr;
+	msg.data[3] = 0x0;
+	msg.data[4] = dst_paddr;
+	msg.data[5] = max_output_size;
+	msg.data[6] = compute_crc(&msg);
+
+	ret = misc_call(dev, false, &msg, size, &msg, size);
+	if (ret)
+		printf("Error: %s: ret 0x%x, response 0x%x\n",
+		       __func__, ret, msg.data[0]);
+
+	return ret;
+}
diff --git a/drivers/misc/sentinel/s4mu.c b/drivers/misc/imx_ele/ele_mu.c
similarity index 84%
rename from drivers/misc/sentinel/s4mu.c
rename to drivers/misc/imx_ele/ele_mu.c
index 794fc40..053cdcf 100644
--- a/drivers/misc/sentinel/s4mu.c
+++ b/drivers/misc/imx_ele/ele_mu.c
@@ -9,7 +9,7 @@
 #include <dm/lists.h>
 #include <dm/root.h>
 #include <dm/device-internal.h>
-#include <asm/mach-imx/s400_api.h>
+#include <asm/mach-imx/ele_api.h>
 #include <asm/arch/imx-regs.h>
 #include <linux/iopoll.h>
 #include <misc.h>
@@ -22,7 +22,7 @@
 
 #define MU_SR_TE0_MASK		BIT(0)
 #define MU_SR_RF0_MASK		BIT(0)
-#define MU_TR_COUNT		4
+#define MU_TR_COUNT		8
 #define MU_RR_COUNT		4
 
 void mu_hal_init(ulong base)
@@ -42,7 +42,7 @@
 
 	assert(reg_index < MU_TR_COUNT);
 
-	debug("sendmsg sr 0x%x\n", readl(&mu_base->sr));
+	debug("sendmsg tsr 0x%x\n", readl(&mu_base->tsr));
 
 	/* Wait TX register to be empty. */
 	ret = readl_poll_timeout(&mu_base->tsr, val, val & mask, 10000);
@@ -64,14 +64,24 @@
 	u32 mask = MU_SR_RF0_MASK << reg_index;
 	u32 val;
 	int ret;
+	u32 count = 10;
 
-	assert(reg_index < MU_TR_COUNT);
+	assert(reg_index < MU_RR_COUNT);
 
-	debug("receivemsg sr 0x%x\n", readl(&mu_base->sr));
+	debug("receivemsg rsr 0x%x\n", readl(&mu_base->rsr));
 
-	/* Wait RX register to be full. */
-	ret = readl_poll_timeout(&mu_base->rsr, val, val & mask, 10000);
-	if (ret < 0) {
+	do {
+		/* Wait RX register to be full. */
+		ret = readl_poll_timeout(&mu_base->rsr, val, val & mask, 1000000);
+		if (ret < 0) {
+			count--;
+			printf("mu receive msg wait %us\n", 10 - count);
+		} else {
+			break;
+		}
+	} while (count > 0);
+
+	if (count == 0) {
 		debug("%s timeout\n", __func__);
 		return -ETIMEDOUT;
 	}
@@ -85,7 +95,7 @@
 
 static int imx8ulp_mu_read(struct mu_type *base, void *data)
 {
-	struct sentinel_msg *msg = (struct sentinel_msg *)data;
+	struct ele_msg *msg = (struct ele_msg *)data;
 	int ret;
 	u8 count = 0;
 
@@ -99,7 +109,7 @@
 	count++;
 
 	/* Check size */
-	if (msg->size > S400_MAX_MSG) {
+	if (msg->size > ELE_MAX_MSG) {
 		*((u32 *)msg) = 0;
 		return -EINVAL;
 	}
@@ -118,7 +128,7 @@
 
 static int imx8ulp_mu_write(struct mu_type *base, void *data)
 {
-	struct sentinel_msg *msg = (struct sentinel_msg *)data;
+	struct ele_msg *msg = (struct ele_msg *)data;
 	int ret;
 	u8 count = 0;
 
@@ -126,7 +136,7 @@
 		return -EINVAL;
 
 	/* Check size */
-	if (msg->size > S400_MAX_MSG)
+	if (msg->size > ELE_MAX_MSG)
 		return -EINVAL;
 
 	/* Write first word */
@@ -171,7 +181,7 @@
 			return ret;
 	}
 
-	result = ((struct sentinel_msg *)rx_msg)->data[0];
+	result = ((struct ele_msg *)rx_msg)->data[0];
 	if ((result & 0xff) == 0xd6)
 		return 0;
 
@@ -196,7 +206,7 @@
 	/* U-Boot not enable interrupts, so need to enable RX interrupts */
 	mu_hal_init((ulong)priv->base);
 
-	gd->arch.s400_dev = dev;
+	gd->arch.ele_dev = dev;
 
 	return 0;
 }
diff --git a/drivers/misc/sentinel/fuse.c b/drivers/misc/imx_ele/fuse.c
similarity index 84%
rename from drivers/misc/sentinel/fuse.c
rename to drivers/misc/imx_ele/fuse.c
index 99342d3..4e4dcb4 100644
--- a/drivers/misc/sentinel/fuse.c
+++ b/drivers/misc/imx_ele/fuse.c
@@ -10,7 +10,7 @@
 #include <asm/arch/sys_proto.h>
 #include <asm/arch/imx-regs.h>
 #include <env.h>
-#include <asm/mach-imx/s400_api.h>
+#include <asm/mach-imx/ele_api.h>
 #include <asm/global_data.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -24,11 +24,11 @@
 	bool redundancy;
 };
 
-struct s400_map_entry {
+struct ele_map_entry {
 	s32 fuse_bank;
 	u32 fuse_words;
 	u32 fuse_offset;
-	u32 s400_index;
+	u32 ele_index;
 };
 
 #if defined(CONFIG_IMX8ULP)
@@ -65,7 +65,7 @@
 	0, 1, 8, 12, 16, 22, 24, 25, 26, 27, 36, 41, 51, 56
 };
 
-struct s400_map_entry s400_api_mapping_table[] = {
+struct ele_map_entry ele_api_mapping_table[] = {
 	{ 1, 8 },	/* LOCK */
 	{ 2, 8 },	/* ECID */
 	{ 7, 4, 0, 1 },	/* OTP_UNIQ_ID */
@@ -122,7 +122,7 @@
 	{ 63, 8 },
 };
 
-struct s400_map_entry s400_api_mapping_table[] = {
+struct ele_map_entry ele_api_mapping_table[] = {
 	{ 7, 1, 7, 63 },
 	{ 16, 8, },
 	{ 17, 8, },
@@ -159,18 +159,18 @@
 	return word + word_pos;
 }
 
-static s32 map_s400_fuse_index(u32 bank, u32 word)
+static s32 map_ele_fuse_index(u32 bank, u32 word)
 {
-	s32 size = ARRAY_SIZE(s400_api_mapping_table);
+	s32 size = ARRAY_SIZE(ele_api_mapping_table);
 	s32 i;
 
 	/* map the fuse from ocotp fuse map to FSB*/
 	for (i = 0; i < size; i++) {
-		if (s400_api_mapping_table[i].fuse_bank != -1 &&
-		    s400_api_mapping_table[i].fuse_bank == bank) {
-			if (word >= s400_api_mapping_table[i].fuse_offset &&
-			    word < (s400_api_mapping_table[i].fuse_offset +
-			    s400_api_mapping_table[i].fuse_words))
+		if (ele_api_mapping_table[i].fuse_bank != -1 &&
+		    ele_api_mapping_table[i].fuse_bank == bank) {
+			if (word >= ele_api_mapping_table[i].fuse_offset &&
+			    word < (ele_api_mapping_table[i].fuse_offset +
+			    ele_api_mapping_table[i].fuse_words))
 				break;
 		}
 	}
@@ -178,10 +178,10 @@
 	if (i == size)
 		return -1; /* Failed to find */
 
-	if (s400_api_mapping_table[i].s400_index != 0)
-		return s400_api_mapping_table[i].s400_index;
+	if (ele_api_mapping_table[i].ele_index != 0)
+		return ele_api_mapping_table[i].ele_index;
 
-	return s400_api_mapping_table[i].fuse_bank * 8 + word;
+	return ele_api_mapping_table[i].fuse_bank * 8 + word;
 }
 
 #if defined(CONFIG_IMX8ULP)
@@ -202,7 +202,7 @@
 		return 0;
 	}
 
-	word_index = map_s400_fuse_index(bank, word);
+	word_index = map_ele_fuse_index(bank, word);
 	if (word_index >= 0) {
 		u32 data[4];
 		u32 res, size = 4;
@@ -212,7 +212,7 @@
 		if (word_index != 1)
 			size = 1;
 
-		ret = ahab_read_common_fuse(word_index, data, size, &res);
+		ret = ele_read_common_fuse(word_index, data, size, &res);
 		if (ret) {
 			printf("ahab read fuse failed %d, 0x%x\n", ret, res);
 			return ret;
@@ -255,13 +255,13 @@
 		return 0;
 	}
 
-	word_index = map_s400_fuse_index(bank, word);
+	word_index = map_ele_fuse_index(bank, word);
 	if (word_index >= 0) {
 		u32 data;
 		u32 res, size = 1;
 		int ret;
 
-		ret = ahab_read_common_fuse(word_index, &data, size, &res);
+		ret = ele_read_common_fuse(word_index, &data, size, &res);
 		if (ret) {
 			printf("ahab read fuse failed %d, 0x%x\n", ret, res);
 			return ret;
@@ -304,7 +304,7 @@
 		lock = true;
 #endif
 
-	ret = ahab_write_fuse((bank * 8 + word), val, lock, &res);
+	ret = ele_write_fuse((bank * 8 + word), val, lock, &res);
 	if (ret) {
 		printf("ahab write fuse failed %d, 0x%x\n", ret, res);
 		return ret;
diff --git a/drivers/misc/npcm_host_intf.c b/drivers/misc/npcm_host_intf.c
index 0244e40..79f57f5 100644
--- a/drivers/misc/npcm_host_intf.c
+++ b/drivers/misc/npcm_host_intf.c
@@ -50,9 +50,6 @@
 	const char *type;
 	int ret;
 
-	/* Release host wait */
-	setbits_8(SMC_CTL_REG_ADDR, SMC_CTL_HOSTWAIT);
-
 	syscon = syscon_regmap_lookup_by_phandle(dev, "syscon");
 	if (IS_ERR(syscon)) {
 		dev_err(dev, "%s: unable to get syscon, dev %s\n", __func__, dev->name);
@@ -93,6 +90,9 @@
 		regmap_update_bits(syscon, MFSEL1, MFSEL1_LPCSEL, MFSEL1_LPCSEL);
 	}
 
+	/* Release host wait */
+	setbits_8(SMC_CTL_REG_ADDR, SMC_CTL_HOSTWAIT);
+
 	return 0;
 }
 
diff --git a/drivers/misc/npcm_otp.c b/drivers/misc/npcm_otp.c
index 3049108..0802972 100644
--- a/drivers/misc/npcm_otp.c
+++ b/drivers/misc/npcm_otp.c
@@ -33,7 +33,7 @@
 	if (arr >= NPCM_NUM_OF_SA) {
 		if (IS_ENABLED(CONFIG_ARCH_NPCM8XX))
 			printf("\nError: npcm8XX otp includs only one bank: 0\n");
-		if (IS_ENABLED(CONFIG_ARCH_NPCM7XX))
+		if (IS_ENABLED(CONFIG_ARCH_NPCM7xx))
 			printf("\nError: npcm7XX otp includs only two banks: 0 and 1\n");
 		return -1;
 	}
diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c
index 9ef95ca..7c01bf2 100644
--- a/drivers/misc/qfw.c
+++ b/drivers/misc/qfw.c
@@ -18,6 +18,7 @@
 #include <dm.h>
 #include <misc.h>
 #include <tables_csum.h>
+#include <asm/acpi_table.h>
 
 #if defined(CONFIG_GENERATE_ACPI_TABLE) && !defined(CONFIG_SANDBOX)
 /*
@@ -64,6 +65,11 @@
 			printf("error: allocating resource\n");
 			return -ENOMEM;
 		}
+		if (aligned_addr < gd->arch.table_start_high)
+			gd->arch.table_start_high = aligned_addr;
+		if (aligned_addr + size > gd->arch.table_end_high)
+			gd->arch.table_end_high = aligned_addr + size;
+
 	} else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) {
 		aligned_addr = ALIGN(*addr, align);
 	} else {
@@ -188,6 +194,10 @@
 		return addr;
 	}
 
+	/* QFW always puts tables at high addresses */
+	gd->arch.table_start_high = (ulong)table_loader;
+	gd->arch.table_end_high = (ulong)table_loader;
+
 	qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader);
 
 	for (i = 0; i < (size / sizeof(*entry)); i++) {
@@ -227,6 +237,9 @@
 	}
 
 	free(table_loader);
+
+	gd_set_acpi_start(acpi_get_rsdp_addr());
+
 	return addr;
 }
 
diff --git a/drivers/misc/sentinel/s400_api.c b/drivers/misc/sentinel/s400_api.c
deleted file mode 100644
index 6c0d0b3..0000000
--- a/drivers/misc/sentinel/s400_api.c
+++ /dev/null
@@ -1,492 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright 2020 NXP
- *
- */
-
-#include <common.h>
-#include <hang.h>
-#include <malloc.h>
-#include <asm/io.h>
-#include <dm.h>
-#include <asm/mach-imx/s400_api.h>
-#include <misc.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-int ahab_release_rdc(u8 core_id, u8 xrdc, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 2;
-	msg.command = ELE_RELEASE_RDC_REQ;
-	switch (xrdc) {
-	case 0:
-		msg.data[0] = (0x74 << 8) | core_id;
-		break;
-	case 1:
-		msg.data[0] = (0x78 << 8) | core_id;
-		break;
-	case 2:
-		msg.data[0] = (0x82 << 8) | core_id;
-		break;
-	case 3:
-		msg.data[0] = (0x86 << 8) | core_id;
-		break;
-	default:
-		printf("Error: wrong xrdc index %u\n", xrdc);
-		return -EINVAL;
-	}
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, core id %u, response 0x%x\n",
-		       __func__, ret, core_id, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	return ret;
-}
-
-int ahab_auth_oem_ctnr(ulong ctnr_addr, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 3;
-	msg.command = ELE_OEM_CNTN_AUTH_REQ;
-	msg.data[0] = upper_32_bits(ctnr_addr);
-	msg.data[1] = lower_32_bits(ctnr_addr);
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, cntr_addr 0x%lx, response 0x%x\n",
-		       __func__, ret, ctnr_addr, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	return ret;
-}
-
-int ahab_release_container(u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 1;
-	msg.command = ELE_RELEASE_CONTAINER_REQ;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, response 0x%x\n",
-		       __func__, ret, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	return ret;
-}
-
-int ahab_verify_image(u32 img_id, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 2;
-	msg.command = ELE_VERIFY_IMAGE_REQ;
-	msg.data[0] = 1 << img_id;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, img_id %u, response 0x%x\n",
-		       __func__, ret, img_id, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	return ret;
-}
-
-int ahab_forward_lifecycle(u16 life_cycle, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 2;
-	msg.command = ELE_FWD_LIFECYCLE_UP_REQ;
-	msg.data[0] = life_cycle;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, life_cycle 0x%x, response 0x%x\n",
-		       __func__, ret, life_cycle, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	return ret;
-}
-
-int ahab_read_common_fuse(u16 fuse_id, u32 *fuse_words, u32 fuse_num, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	if (!fuse_words) {
-		printf("Invalid parameters for fuse read\n");
-		return -EINVAL;
-	}
-
-	if ((fuse_id != 1 && fuse_num != 1) ||
-	    (fuse_id == 1 && fuse_num != 4)) {
-		printf("Invalid fuse number parameter\n");
-		return -EINVAL;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 2;
-	msg.command = ELE_READ_FUSE_REQ;
-	msg.data[0] = fuse_id;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n",
-		       __func__, ret, fuse_id, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	fuse_words[0] = msg.data[1];
-	if (fuse_id == 1) {
-		/* OTP_UNIQ_ID */
-		fuse_words[1] = msg.data[2];
-		fuse_words[2] = msg.data[3];
-		fuse_words[3] = msg.data[4];
-	}
-
-	return ret;
-}
-
-int ahab_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 3;
-	msg.command = ELE_WRITE_FUSE_REQ;
-	msg.data[0] = (32 << 16) | (fuse_id << 5);
-	if (lock)
-		msg.data[0] |= (1 << 31);
-
-	msg.data[1] = fuse_val;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, fuse_id 0x%x, response 0x%x\n",
-		       __func__, ret, fuse_id, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	return ret;
-}
-
-int ahab_release_caam(u32 core_did, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 2;
-	msg.command = ELE_RELEASE_CAAM_REQ;
-	msg.data[0] = core_did;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, response 0x%x\n",
-		       __func__, ret, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	return ret;
-}
-
-int ahab_get_fw_version(u32 *fw_version, u32 *sha1, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	if (!fw_version) {
-		printf("Invalid parameters for f/w version read\n");
-		return -EINVAL;
-	}
-
-	if (!sha1) {
-		printf("Invalid parameters for commit sha1\n");
-		return -EINVAL;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 1;
-	msg.command = ELE_GET_FW_VERSION_REQ;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, response 0x%x\n",
-		       __func__, ret, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	*fw_version = msg.data[1];
-	*sha1 = msg.data[2];
-
-	return ret;
-}
-
-int ahab_dump_buffer(u32 *buffer, u32 buffer_length)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret, i = 0;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 1;
-	msg.command = ELE_DUMP_DEBUG_BUFFER_REQ;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret) {
-		printf("Error: %s: ret %d, response 0x%x\n",
-		       __func__, ret, msg.data[0]);
-
-		return ret;
-	}
-
-	if (buffer) {
-		buffer[i++] = *(u32 *)&msg; /* Need dump the response header */
-		for (; i < buffer_length && i < msg.size; i++)
-			buffer[i] = msg.data[i - 1];
-	}
-
-	return i;
-}
-
-int ahab_get_info(struct sentinel_get_info_data *info, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 4;
-	msg.command = ELE_GET_INFO_REQ;
-	msg.data[0] = upper_32_bits((ulong)info);
-	msg.data[1] = lower_32_bits((ulong)info);
-	msg.data[2] = sizeof(struct sentinel_get_info_data);
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, response 0x%x\n",
-		       __func__, ret, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	return ret;
-}
-
-int ahab_get_fw_status(u32 *status, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 1;
-	msg.command = ELE_GET_FW_STATUS_REQ;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, response 0x%x\n",
-		       __func__, ret, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	*status = msg.data[1] & 0xF;
-
-	return ret;
-}
-
-int ahab_release_m33_trout(void)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 1;
-	msg.command = ELE_ENABLE_RTC_REQ;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, response 0x%x\n",
-		       __func__, ret, msg.data[0]);
-
-	return ret;
-}
-
-int ahab_get_events(u32 *events, u32 *events_cnt, u32 *response)
-{
-	struct udevice *dev = gd->arch.s400_dev;
-	int size = sizeof(struct sentinel_msg);
-	struct sentinel_msg msg;
-	int ret, i = 0;
-	u32 actual_events;
-
-	if (!dev) {
-		printf("s400 dev is not initialized\n");
-		return -ENODEV;
-	}
-
-	if (!events || !events_cnt || *events_cnt == 0) {
-		printf("Invalid parameters for %s\n", __func__);
-		return -EINVAL;
-	}
-
-	msg.version = AHAB_VERSION;
-	msg.tag = AHAB_CMD_TAG;
-	msg.size = 1;
-	msg.command = ELE_GET_EVENTS_REQ;
-
-	ret = misc_call(dev, false, &msg, size, &msg, size);
-	if (ret)
-		printf("Error: %s: ret %d, response 0x%x\n",
-		       __func__, ret, msg.data[0]);
-
-	if (response)
-		*response = msg.data[0];
-
-	if (!ret) {
-		actual_events = msg.data[1] & 0xffff;
-		if (*events_cnt < actual_events)
-			actual_events = *events_cnt;
-
-		for (; i < actual_events; i++)
-			events[i] = msg.data[i + 2];
-
-		*events_cnt = actual_events;
-	}
-
-	return ret;
-}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 72c1076..31cfda2 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -398,6 +398,26 @@
 }
 #endif
 
+int mmc_send_stop_transmission(struct mmc *mmc, bool write)
+{
+	struct mmc_cmd cmd;
+
+	cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+	cmd.cmdarg = 0;
+	/*
+	 * JEDEC Standard No. 84-B51 Page 126
+	 * CMD12 STOP_TRANSMISSION R1/R1b[3]
+	 * NOTE 3 R1 for read cases and R1b for write cases.
+	 *
+	 * Physical Layer Simplified Specification Version 9.00
+	 * 7.3.1.3 Detailed Command Description
+	 * CMD12 R1b
+	 */
+	cmd.resp_type = (IS_SD(mmc) || write) ? MMC_RSP_R1b : MMC_RSP_R1;
+
+	return mmc_send_cmd(mmc, &cmd, NULL);
+}
+
 static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
 			   lbaint_t blkcnt)
 {
@@ -425,10 +445,7 @@
 		return 0;
 
 	if (blkcnt > 1) {
-		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
-		cmd.cmdarg = 0;
-		cmd.resp_type = MMC_RSP_R1b;
-		if (mmc_send_cmd(mmc, &cmd, NULL)) {
+		if (mmc_send_stop_transmission(mmc, false)) {
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
 			pr_err("mmc fail to send stop cmd\n");
 #endif
@@ -2223,6 +2240,7 @@
 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
 			mmc_select_mode(mmc, MMC_LEGACY);
+			mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE);
 			mmc_set_bus_width(mmc, 1);
 		}
 	}
diff --git a/drivers/mmc/mmc_bootdev.c b/drivers/mmc/mmc_bootdev.c
index b57b8a6..55ecead 100644
--- a/drivers/mmc/mmc_bootdev.c
+++ b/drivers/mmc/mmc_bootdev.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Bootdevice for MMC
+ * Bootdev for MMC
  *
  * Copyright 2021 Google LLC
  * Written by Simon Glass <sjg@chromium.org>
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 280d96d..8e716f7 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -611,6 +611,17 @@
 			priv->smpcmp |= BIT(i);
 
 		mdelay(1);
+
+		/*
+		 * eMMC specification specifies that CMD12 can be used to stop a tuning
+		 * command, but SD specification does not, so do nothing unless it is
+		 * eMMC.
+		 */
+		if (ret && (opcode == MMC_CMD_SEND_TUNING_BLOCK_HS200)) {
+			ret = mmc_send_stop_transmission(mmc, false);
+			if (ret < 0)
+				dev_dbg(dev, "Tuning abort fail (%d)\n", ret);
+		}
 	}
 
 	ret = renesas_sdhi_select_tuning(priv, taps);
diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c
index fcd1b9c..d502e96 100644
--- a/drivers/mtd/nand/raw/pxa3xx_nand.c
+++ b/drivers/mtd/nand/raw/pxa3xx_nand.c
@@ -125,6 +125,7 @@
 /* System control register and bit to enable NAND on some SoCs */
 #define GENCONF_SOC_DEVICE_MUX	0x208
 #define GENCONF_SOC_DEVICE_MUX_NFC_EN BIT(0)
+#define GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN BIT(27)
 
 /*
  * This should be large enough to read 'ONFI' and 'JEDEC'.
@@ -167,6 +168,7 @@
 	PXA3XX_NAND_VARIANT_PXA,
 	PXA3XX_NAND_VARIANT_ARMADA370,
 	PXA3XX_NAND_VARIANT_ARMADA_8K,
+	PXA3XX_NAND_VARIANT_AC5,
 };
 
 struct pxa3xx_nand_host {
@@ -391,6 +393,10 @@
 		.compatible = "marvell,armada-8k-nand-controller",
 		.data = PXA3XX_NAND_VARIANT_ARMADA_8K,
 	},
+	{
+		.compatible = "marvell,mvebu-ac5-pxa3xx-nand",
+		.data = PXA3XX_NAND_VARIANT_AC5,
+	},
 	{}
 };
 
@@ -505,6 +511,9 @@
 		if (mode < 0)
 			mode = 0;
 
+		if (info->variant == PXA3XX_NAND_VARIANT_AC5)
+			mode = min(mode, 3);
+
 		timings = onfi_async_timing_mode_to_sdr_timings(mode);
 		if (IS_ERR(timings))
 			return PTR_ERR(timings);
@@ -730,7 +739,8 @@
 
 		/* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
 		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-			info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
+			info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K ||
+			info->variant == PXA3XX_NAND_VARIANT_AC5)
 			nand_writel(info, NDCB0, info->ndcb3);
 	}
 
@@ -1579,7 +1589,8 @@
 
 	/* Device detection must be done with ECC disabled */
 	if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-		info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K)
+		info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K ||
+		info->variant == PXA3XX_NAND_VARIANT_AC5)
 		nand_writel(info, NDECCCTRL, 0x0);
 
 	if (nand_scan_ident(mtd, 1, NULL))
@@ -1630,7 +1641,8 @@
 	 */
 	if (mtd->writesize > info->chunk_size) {
 		if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 ||
-			info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K) {
+			info->variant == PXA3XX_NAND_VARIANT_ARMADA_8K ||
+			info->variant == PXA3XX_NAND_VARIANT_AC5) {
 			chip->cmdfunc = nand_cmdfunc_extended;
 		} else {
 			dev_err(mtd->dev,
@@ -1728,7 +1740,7 @@
 			return PTR_ERR(sysctrl_base);
 
 		regmap_read(sysctrl_base, GENCONF_SOC_DEVICE_MUX, &reg);
-		reg |= GENCONF_SOC_DEVICE_MUX_NFC_EN;
+		reg |= GENCONF_SOC_DEVICE_MUX_NFC_EN | GENCONF_SOC_DEVICE_MUX_NFC_DEVBUS_ARB_EN;
 		regmap_write(sysctrl_base, GENCONF_SOC_DEVICE_MUX, reg);
 	}
 
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 3f8b796..4587215 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -446,6 +446,11 @@
 			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 	},
+	{
+		INFO("w25q256jwm", 0xef8019, 0, 64 * 1024, 512,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+	},
 	{ INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K) },
 	{
 		INFO("w25q64dw", 0xef6017, 0, 64 * 1024, 128,
@@ -528,8 +533,42 @@
 	{ INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 #endif
 #ifdef CONFIG_SPI_FLASH_XTX
-	/* XTX Technology (Shenzhen) Limited */
-	{ INFO("xt25f128b", 0x0b4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	/* XTX Technology Limited */
+	/* adding these 3V QSPI flash parts */
+	{ INFO("xt25f08", 0x0b4014, 0, 64 * 1024, 16,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25f16", 0x0b4015, 0, 64 * 1024, 32,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25f32", 0x0b4016, 0, 64 * 1024, 64,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25f64", 0x0b4017, 0, 64 * 1024, 128,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25f128", 0x0b4018, 0, 64 * 1024, 256,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25f256", 0x0b4019, 0, 64 * 1024, 512,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	/* adding these 1.8V QSPI flash parts */
+	{ INFO("xt25q08", 0x0b6014, 0, 64 * 1024, 16,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25q16", 0x0b6015, 0, 64 * 1024, 32,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25q32", 0x0b6016, 0, 64 * 1024, 64,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25q64", 0x0b6017, 0, 64 * 1024, 128,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25q128", 0x0b6018, 0, 64 * 1024, 256,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ INFO("xt25q256", 0x0b6019, 0, 64 * 1024, 512,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("xt25q512", 0x0b601A, 0, 64 * 1024, 1024,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("xt25q01g", 0x0b601B, 0, 64 * 1024, 2048,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	/* adding these wide voltage QSPI flash parts */
+	{ INFO("xt25w512", 0x0b651A, 0, 64 * 1024, 1024,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("xt25w01g", 0x0b651B, 0, 64 * 1024, 2048,
+	       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 #endif
 	{ },
 };
diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c
index f674b0b..523a4c9 100644
--- a/drivers/net/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ti/am65-cpsw-nuss.c
@@ -223,6 +223,8 @@
 	return phy->link;
 }
 
+#define AM65_GMII_SEL_PORT_OFFS(x)	(0x4 * ((x) - 1))
+
 #define AM65_GMII_SEL_MODE_MII		0
 #define AM65_GMII_SEL_MODE_RMII		1
 #define AM65_GMII_SEL_MODE_RGMII	2
@@ -233,11 +235,12 @@
 				  phy_interface_t phy_mode, int slave)
 {
 	struct am65_cpsw_common	*common = priv->cpsw_common;
+	fdt_addr_t gmii_sel = common->gmii_sel + AM65_GMII_SEL_PORT_OFFS(slave);
 	u32 reg;
 	u32 mode = 0;
 	bool rgmii_id = false;
 
-	reg = readl(common->gmii_sel);
+	reg = readl(gmii_sel);
 
 	dev_dbg(common->dev, "old gmii_sel: %08x\n", reg);
 
@@ -273,9 +276,9 @@
 	reg = mode;
 	dev_dbg(common->dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n",
 		phy_mode, reg);
-	writel(reg, common->gmii_sel);
+	writel(reg, gmii_sel);
 
-	reg = readl(common->gmii_sel);
+	reg = readl(gmii_sel);
 	if (reg != mode)
 		dev_err(common->dev,
 			"gmii_sel PHY mode NOT SET!: requested: %08x, gmii_sel: %08x\n",
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index 74e7a5b..a7add66 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -578,17 +578,22 @@
 	return min(result & 0xffff, result >> 16) + 1;
 }
 
-static void nvme_create_io_queues(struct nvme_dev *dev)
+static int nvme_create_io_queues(struct nvme_dev *dev)
 {
 	unsigned int i;
+	int ret;
 
 	for (i = dev->queue_count; i <= dev->max_qid; i++)
 		if (!nvme_alloc_queue(dev, i, dev->q_depth))
-			break;
+			return log_msg_ret("all", -ENOMEM);
 
-	for (i = dev->online_queues; i <= dev->queue_count - 1; i++)
-		if (nvme_create_queue(dev->queues[i], i))
-			break;
+	for (i = dev->online_queues; i <= dev->queue_count - 1; i++) {
+		ret = nvme_create_queue(dev->queues[i], i);
+		if (ret)
+			return log_msg_ret("cre", ret);
+	}
+
+	return 0;
 }
 
 static int nvme_setup_io_queues(struct nvme_dev *dev)
@@ -598,14 +603,18 @@
 
 	nr_io_queues = 1;
 	result = nvme_set_queue_count(dev, nr_io_queues);
-	if (result <= 0)
+	if (result <= 0) {
+		log_debug("Cannot set queue count (err=%dE)\n", result);
 		return result;
+	}
 
 	dev->max_qid = nr_io_queues;
 
 	/* Free previously allocated queues */
 	nvme_free_queues(dev, nr_io_queues + 1);
-	nvme_create_io_queues(dev);
+	result = nvme_create_io_queues(dev);
+	if (result)
+		return result;
 
 	return 0;
 }
@@ -683,8 +692,11 @@
 
 	uclass_foreach_dev(dev, uc) {
 		ret = device_probe(dev);
-		if (ret)
+		if (ret) {
+			log_err("Failed to probe '%s': err=%dE\n", dev->name,
+				ret);
 			return ret;
+		}
 	}
 
 	return 0;
@@ -842,8 +854,10 @@
 	ndev->dbs = ((void __iomem *)ndev->bar) + 4096;
 
 	ret = nvme_configure_admin_queue(ndev);
-	if (ret)
+	if (ret) {
+		log_debug("Unable to configure admin queue (err=%dE)\n", ret);
 		goto free_queue;
+	}
 
 	/* Allocate after the page size is known */
 	ndev->prp_pool = memalign(ndev->page_size, MAX_PRP_POOL);
@@ -855,8 +869,10 @@
 	ndev->prp_entry_num = MAX_PRP_POOL >> 3;
 
 	ret = nvme_setup_io_queues(ndev);
-	if (ret)
+	if (ret) {
+		log_debug("Unable to setup I/O queues(err=%dE)\n", ret);
 		goto free_queue;
+	}
 
 	nvme_get_info_from_identify(ndev);
 
diff --git a/drivers/pch/pch9.c b/drivers/pch/pch9.c
index 3bd0115..3137eb2 100644
--- a/drivers/pch/pch9.c
+++ b/drivers/pch/pch9.c
@@ -3,6 +3,8 @@
  * Copyright (C) 2014 Google, Inc
  */
 
+#define LOG_CATEGORY	UCLASS_PCH
+
 #include <common.h>
 #include <dm.h>
 #include <log.h>
@@ -38,7 +40,7 @@
 	 */
 	dm_pci_read_config32(dev, GPIO_BASE, &base);
 	if (base == 0x00000000 || base == 0xffffffff) {
-		debug("%s: unexpected BASE value\n", __func__);
+		log_debug("unexpected BASE value\n");
 		return -ENODEV;
 	}
 
@@ -59,7 +61,7 @@
 
 	dm_pci_read_config32(dev, IO_BASE, &base);
 	if (base == 0x00000000 || base == 0xffffffff) {
-		debug("%s: unexpected BASE value\n", __func__);
+		log_debug("unexpected BASE value\n");
 		return -ENODEV;
 	}
 
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 84a2ae9..aca439d 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -44,8 +44,13 @@
 	bool "Enable Plug & Play support for PCI"
 	help
 	  Enable PCI memory and I/O space resource allocation and assignment.
+
 	  This is required to auto configure the enumerated devices.
 
+	  This is normally not done in SPL, but can be enabled if devices must
+	  be set up in the SPL phase. Often it is enough to manually configure
+	  one device, so this option can be disabled.
+
 config PCI_REGION_MULTI_ENTRY
 	bool "Enable Multiple entries of region type MEMORY in ranges for PCI"
 	help
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 8d27e40..632c1a6 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -13,6 +13,7 @@
 #include <log.h>
 #include <malloc.h>
 #include <pci.h>
+#include <spl.h>
 #include <asm/global_data.h>
 #include <asm/io.h>
 #include <dm/device-internal.h>
@@ -722,6 +723,9 @@
 	u32 vendev;
 	int index;
 
+	if (spl_phase() == PHASE_SPL && CONFIG_IS_ENABLED(PCI_PNP))
+		return true;
+
 	for (index = 0;
 	     !dev_read_u32_index(bus, "u-boot,pci-pre-reloc", index,
 				 &vendev);
@@ -793,7 +797,9 @@
 			 * space is pretty limited (ie: using Cache As RAM).
 			 */
 			if (!(gd->flags & GD_FLG_RELOC) &&
-			    !(drv->flags & DM_FLAG_PRE_RELOC))
+			    !(drv->flags & DM_FLAG_PRE_RELOC) &&
+			    (!CONFIG_IS_ENABLED(PCI_PNP) ||
+			     spl_phase() != PHASE_SPL))
 				return log_msg_ret("pre", -EPERM);
 
 			/*
@@ -918,6 +924,8 @@
 			}
 			ret = pci_find_and_bind_driver(bus, &find_id, bdf,
 						       &dev);
+		} else {
+			debug("device: %s\n", dev->name);
 		}
 		if (ret == -EPERM)
 			continue;
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index f0dfe63..438583a 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -26,6 +26,7 @@
 
 #include <common.h>
 #include <bios_emul.h>
+#include <bloblist.h>
 #include <bootstage.h>
 #include <dm.h>
 #include <errno.h>
@@ -34,6 +35,7 @@
 #include <malloc.h>
 #include <pci.h>
 #include <pci_rom.h>
+#include <spl.h>
 #include <vesa.h>
 #include <video.h>
 #include <acpi/acpi_s3.h>
@@ -91,6 +93,7 @@
 		debug("%s: rom_address=%x\n", __func__, rom_address);
 		return -ENOENT;
 	}
+	rom_address &= PCI_ROM_ADDRESS_MASK;
 
 	/* Enable expansion ROM address decoding. */
 	dm_pci_write_config32(dev, PCI_ROM_ADDRESS,
@@ -254,14 +257,16 @@
 
 	ret = pci_rom_probe(dev, &rom);
 	if (ret)
-		return ret;
+		return log_msg_ret("pro", ret);
 
 	ret = pci_rom_load(rom, &ram, &alloced);
-	if (ret)
+	if (ret) {
+		ret = log_msg_ret("ld", ret);
 		goto err;
+	}
 
 	if (!board_should_run_oprom(dev)) {
-		ret = -ENXIO;
+		ret = log_msg_ret("run", -ENXIO);
 		goto err;
 	}
 
@@ -269,7 +274,7 @@
 		defined(CONFIG_FRAMEBUFFER_VESA_MODE)
 	vesa_mode = CONFIG_FRAMEBUFFER_VESA_MODE;
 #endif
-	debug("Selected vesa mode %#x\n", vesa_mode);
+	debug("Selected vesa mode 0x%x\n", vesa_mode);
 
 	if (exec_method & PCI_ROM_USE_NATIVE) {
 #ifdef CONFIG_X86
@@ -296,27 +301,31 @@
 	}
 
 	if (emulate) {
-#ifdef CONFIG_BIOSEMU
-		BE_VGAInfo *info;
+		if (CONFIG_IS_ENABLED(BIOSEMU)) {
+			BE_VGAInfo *info;
 
-		ret = biosemu_setup(dev, &info);
-		if (ret)
-			goto err;
-		biosemu_set_interrupt_handler(0x15, int15_handler);
-		ret = biosemu_run(dev, (uchar *)ram, 1 << 16, info,
-				  true, vesa_mode, &mode_info);
-		if (ret)
-			goto err;
-#endif
+			log_debug("Running video BIOS with emulator...");
+			ret = biosemu_setup(dev, &info);
+			if (ret)
+				goto err;
+			biosemu_set_interrupt_handler(0x15, int15_handler);
+			ret = biosemu_run(dev, (uchar *)ram, 1 << 16, info,
+					  true, vesa_mode, &mode_info);
+			log_debug("done\n");
+			if (ret)
+				goto err;
+		}
 	} else {
 #if defined(CONFIG_X86) && (CONFIG_IS_ENABLED(X86_32BIT_INIT) || CONFIG_TPL)
+		log_debug("Running video BIOS...");
 		bios_set_interrupt_handler(0x15, int15_handler);
 
 		bios_run_on_x86(dev, (unsigned long)ram, vesa_mode,
 				&mode_info);
+		log_debug("done\n");
 #endif
 	}
-	debug("Final vesa mode %#x\n", mode_info.video_mode);
+	debug("Final vesa mode %x\n", mode_info.video_mode);
 	ret = 0;
 
 err:
@@ -368,34 +377,68 @@
 		printf("Not available (previous bootloader prevents it)\n");
 		return -EPERM;
 	}
-	bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "vesa display");
-	ret = dm_pci_run_vga_bios(dev, int15_handler, PCI_ROM_USE_NATIVE |
-					PCI_ROM_ALLOW_FALLBACK);
-	bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD);
-	if (ret) {
-		debug("failed to run video BIOS: %d\n", ret);
-		return ret;
-	}
 
-	ret = vesa_setup_video_priv(&mode_info.vesa,
-				    mode_info.vesa.phys_base_ptr, uc_priv,
-				    plat);
-	if (ret) {
-		if (ret == -ENFILE) {
-			/*
-			 * See video-uclass.c for how to set up reserved memory
-			 * in your video driver
-			 */
-			log_err("CONFIG_VIDEO_COPY enabled but driver '%s' set up no reserved memory\n",
-				dev->driver->name);
+	/* In U-Boot proper, collect the information added by SPL (see below) */
+	if (IS_ENABLED(CONFIG_SPL_VIDEO) && spl_phase() > PHASE_SPL &&
+	    CONFIG_IS_ENABLED(BLOBLIST)) {
+		struct video_handoff *ho;
+
+		ho = bloblist_find(BLOBLISTT_U_BOOT_VIDEO, sizeof(*ho));
+		if (!ho)
+			return log_msg_ret("blf", -ENOENT);
+		plat->base = ho->fb;
+		plat->size = ho->size;
+		uc_priv->xsize = ho->xsize;
+		uc_priv->ysize = ho->ysize;
+		uc_priv->line_length = ho->line_length;
+		uc_priv->bpix = ho->bpix;
+	} else {
+		bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "vesa display");
+		ret = dm_pci_run_vga_bios(dev, int15_handler,
+					  PCI_ROM_USE_NATIVE |
+					  PCI_ROM_ALLOW_FALLBACK);
+		bootstage_accum(BOOTSTAGE_ID_ACCUM_LCD);
+		if (ret) {
+			debug("failed to run video BIOS: %d\n", ret);
+			return ret;
 		}
 
-		debug("No video mode configured\n");
-		return ret;
+		ret = vesa_setup_video_priv(&mode_info.vesa,
+					    mode_info.vesa.phys_base_ptr,
+					    uc_priv, plat);
+		if (ret) {
+			if (ret == -ENFILE) {
+				/*
+				 * See video-uclass.c for how to set up reserved
+				 * memory in your video driver
+				 */
+				log_err("CONFIG_VIDEO_COPY enabled but driver '%s' set up no reserved memory\n",
+					dev->driver->name);
+			}
+
+			debug("No video mode configured\n");
+			return ret;
+		}
 	}
 
 	printf("Video: %dx%dx%d\n", uc_priv->xsize, uc_priv->ysize,
 	       mode_info.vesa.bits_per_pixel);
 
+	/* In SPL, store the information for use by U-Boot proper */
+	if (spl_phase() == PHASE_SPL && CONFIG_IS_ENABLED(BLOBLIST)) {
+		struct video_handoff *ho;
+
+		ho = bloblist_add(BLOBLISTT_U_BOOT_VIDEO, sizeof(*ho), 0);
+		if (!ho)
+			return log_msg_ret("blc", -ENOMEM);
+
+		ho->fb = plat->base;
+		ho->size = plat->size;
+		ho->xsize = uc_priv->xsize;
+		ho->ysize = uc_priv->ysize;
+		ho->line_length = uc_priv->line_length;
+		ho->bpix = uc_priv->bpix;
+	}
+
 	return 0;
 }
diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
index f18be08..7976e3b 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
@@ -808,6 +808,9 @@
 	status = npcm_get_reset_status();
 	dev_dbg(dev, "reset status: 0x%x\n", status);
 
+	if (status & PORST)
+		return false;
+
 	if (status & CORST)
 		regmap_read(priv->rst_regmap, CORSTC, &val);
 	else if (status & WD0RST)
diff --git a/drivers/power/domain/imx8-power-domain-legacy.c b/drivers/power/domain/imx8-power-domain-legacy.c
index 37b0f95..c8ca266 100644
--- a/drivers/power/domain/imx8-power-domain-legacy.c
+++ b/drivers/power/domain/imx8-power-domain-legacy.c
@@ -89,7 +89,6 @@
 	struct udevice *dev = power_domain->dev;
 	struct imx8_power_domain_plat *pdata;
 	struct imx8_power_domain_priv *ppriv;
-	sc_err_t ret;
 	int err;
 
 	struct power_domain parent_domain;
@@ -117,11 +116,11 @@
 		if (!sc_rm_is_resource_owned(-1, pdata->resource_id))
 			printf("%s [%d] not owned by curr partition\n", dev->name, pdata->resource_id);
 
-		ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id,
+		err = sc_pm_set_resource_power_mode(-1, pdata->resource_id,
 						    SC_PM_PW_MODE_ON);
-		if (ret) {
+		if (err) {
 			printf("Error: %s Power up failed! (error = %d)\n",
-			       dev->name, ret);
+			       dev->name, err);
 			return -EIO;
 		}
 	}
@@ -139,7 +138,7 @@
 	struct imx8_power_domain_priv *ppriv;
 	struct imx8_power_domain_priv *child_ppriv;
 	struct imx8_power_domain_plat *pdata;
-	sc_err_t ret;
+	int ret;
 
 	ppriv = dev_get_priv(dev);
 	pdata = dev_get_plat(dev);
diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c
index 145f6ec..df5d7d6 100644
--- a/drivers/power/domain/imx8m-power-domain.c
+++ b/drivers/power/domain/imx8m-power-domain.c
@@ -338,6 +338,9 @@
 		}
 	}
 
+	/* delay for reset to propagate */
+	udelay(5);
+
 	if (domain->bits.pxx) {
 		/* request the domain to power up */
 		setbits_le32(base + regs->pup, domain->bits.pxx);
diff --git a/drivers/scsi/scsi_bootdev.c b/drivers/scsi/scsi_bootdev.c
index 991013f..218221f 100644
--- a/drivers/scsi/scsi_bootdev.c
+++ b/drivers/scsi/scsi_bootdev.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Bootdevice for USB
+ * Bootdev for SCSI
  *
  * Copyright 2021 Google LLC
  * Written by Simon Glass <sjg@chromium.org>
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index f546835..428a4d2 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -291,8 +291,16 @@
 	struct pl01x_serial_plat *plat = dev_get_plat(dev);
 	struct pl01x_priv *priv = dev_get_priv(dev);
 
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_serial_pl01x *dtplat = &plat->dtplat;
+
+	priv->regs = (struct pl01x_regs *)dtplat->reg[0];
+	plat->type = dtplat->type;
+#else
 	priv->regs = (struct pl01x_regs *)plat->base;
+#endif
 	priv->type = plat->type;
+
 	if (!plat->skip_init)
 		return pl01x_generic_serial_init(priv->regs, priv->type);
 	else
@@ -321,7 +329,7 @@
 	if (input)
 		return pl01x_tstc(priv->regs);
 	else
-		return fr & UART_PL01x_FR_TXFF ? 0 : 1;
+		return fr & UART_PL01x_FR_TXFE ? 0 : 1;
 }
 
 static const struct dm_serial_ops pl01x_serial_ops = {
@@ -331,7 +339,7 @@
 	.setbrg = pl01x_serial_setbrg,
 };
 
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_REAL)
 static const struct udevice_id pl01x_serial_id[] ={
 	{.compatible = "arm,pl011", .data = TYPE_PL011},
 	{.compatible = "arm,pl010", .data = TYPE_PL010},
@@ -380,8 +388,10 @@
 U_BOOT_DRIVER(serial_pl01x) = {
 	.name	= "serial_pl01x",
 	.id	= UCLASS_SERIAL,
+#if CONFIG_IS_ENABLED(OF_REAL)
 	.of_match = of_match_ptr(pl01x_serial_id),
 	.of_to_plat = of_match_ptr(pl01x_serial_of_to_plat),
+#endif
 	.plat_auto	= sizeof(struct pl01x_serial_plat),
 	.probe = pl01x_serial_probe,
 	.ops	= &pl01x_serial_ops,
@@ -389,6 +399,8 @@
 	.priv_auto	= sizeof(struct pl01x_priv),
 };
 
+DM_DRIVER_ALIAS(serial_pl01x, arm_pl011)
+DM_DRIVER_ALIAS(serial_pl01x, arm_pl010)
 #endif
 
 #if defined(CONFIG_DEBUG_UART_PL010) || defined(CONFIG_DEBUG_UART_PL011)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 453a598..854b8b8 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -101,12 +101,21 @@
 
 config BCM63XX_HSSPI
 	bool "BCM63XX HSSPI driver"
-	depends on (ARCH_BMIPS || BCM6856 || BCM6858 || BCM63158)
+	depends on (ARCH_BMIPS || ARCH_BCMBCA)
 	help
-	  Enable the BCM6328 HSSPI driver. This driver can be used to
+	  Enable the BCM63XX HSSPI driver. This driver can be used to
 	  access the SPI NOR flash on platforms embedding this Broadcom
 	  SPI core.
 
+config BCMBCA_HSSPI
+	bool "BCMBCA HSSPI driver"
+	depends on ARCH_BCMBCA && HAVE_SPI_CS_CTRL
+	help
+	  This enables support for the High Speed SPI controller present on
+	  newer Broadcom BCMBCA SoCs. These SoCs include an updated SPI controller
+	  that adds the capability to allow the driver to control chip select
+	  explicitly.
+
 config BCM63XX_SPI
 	bool "BCM6348 SPI driver"
 	depends on ARCH_BMIPS
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 95dba9a..c27b332 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -25,6 +25,7 @@
 obj-$(CONFIG_ATMEL_QSPI) += atmel-quadspi.o
 obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
 obj-$(CONFIG_BCM63XX_HSSPI) += bcm63xx_hsspi.o
+obj-$(CONFIG_BCMBCA_HSSPI) += bcmbca_hsspi.o
 obj-$(CONFIG_BCM63XX_SPI) += bcm63xx_spi.o
 obj-$(CONFIG_BCMSTB_SPI) += bcmstb_spi.o
 obj-$(CONFIG_CF_SPI) += cf_spi.o
diff --git a/drivers/spi/bcm63xx_hsspi.c b/drivers/spi/bcm63xx_hsspi.c
index 4d714ad..a24bb43 100644
--- a/drivers/spi/bcm63xx_hsspi.c
+++ b/drivers/spi/bcm63xx_hsspi.c
@@ -20,7 +20,13 @@
 
 #define HSSPI_PP			0
 
-#define SPI_MAX_SYNC_CLOCK		30000000
+/*
+ * The maximum frequency for SPI synchronous mode is 30MHz for some chips and
+ * 25MHz for some others. This depends on the chip layout and SPI signals
+ * distance to the pad. We use the lower of these values to cover all relevant
+ * chips.
+ */
+#define SPI_MAX_SYNC_CLOCK		25000000
 
 /* SPI Control register */
 #define SPI_CTL_REG			0x000
@@ -72,12 +78,16 @@
 #define SPI_PFL_MODE_REG(x)		(0x100 + (0x20 * (x)) + 0x08)
 #define SPI_PFL_MODE_FILL_SHIFT		0
 #define SPI_PFL_MODE_FILL_MASK		(0xff << SPI_PFL_MODE_FILL_SHIFT)
+#define SPI_PFL_MODE_MDRDST_SHIFT	8
+#define SPI_PFL_MODE_MDWRST_SHIFT	12
 #define SPI_PFL_MODE_MDRDSZ_SHIFT	16
 #define SPI_PFL_MODE_MDRDSZ_MASK	(1 << SPI_PFL_MODE_MDRDSZ_SHIFT)
 #define SPI_PFL_MODE_MDWRSZ_SHIFT	18
 #define SPI_PFL_MODE_MDWRSZ_MASK	(1 << SPI_PFL_MODE_MDWRSZ_SHIFT)
 #define SPI_PFL_MODE_3WIRE_SHIFT	20
 #define SPI_PFL_MODE_3WIRE_MASK		(1 << SPI_PFL_MODE_3WIRE_SHIFT)
+#define SPI_PFL_MODE_PREPCNT_SHIFT	24
+#define SPI_PFL_MODE_PREPCNT_MASK	(4 << SPI_PFL_MODE_PREPCNT_SHIFT)
 
 /* SPI Ping-Pong FIFO registers */
 #define HSSPI_FIFO_SIZE			0x200
@@ -96,12 +106,21 @@
 #define HSSPI_FIFO_OP_CODE_W		(2 << HSSPI_FIFO_OP_CODE_SHIFT)
 #define HSSPI_FIFO_OP_CODE_R		(3 << HSSPI_FIFO_OP_CODE_SHIFT)
 
+#define HSSPI_MAX_DATA_SIZE			(HSSPI_FIFO_SIZE - HSSPI_FIFO_OP_SIZE)
+#define HSSPI_MAX_PREPEND_SIZE		15
+
+#define HSSPI_XFER_MODE_PREPEND		0
+#define HSSPI_XFER_MODE_DUMMYCS		1
+
 struct bcm63xx_hsspi_priv {
 	void __iomem *regs;
 	ulong clk_rate;
 	uint8_t num_cs;
 	uint8_t cs_pols;
 	uint speed;
+	uint xfer_mode;
+	uint32_t prepend_cnt;
+	uint8_t prepend_buf[HSSPI_MAX_PREPEND_SIZE];
 };
 
 static int bcm63xx_hsspi_cs_info(struct udevice *bus, uint cs,
@@ -143,9 +162,16 @@
 				   struct dm_spi_slave_plat *plat)
 {
 	uint32_t clr, set;
+	uint speed = priv->speed;
+
+	if (priv->xfer_mode == HSSPI_XFER_MODE_DUMMYCS &&
+	    speed > SPI_MAX_SYNC_CLOCK) {
+		speed = SPI_MAX_SYNC_CLOCK;
+		debug("Force to dummy cs mode. Reduce the speed to %dHz\n", speed);
+	}
 
 	/* profile clock */
-	set = DIV_ROUND_UP(priv->clk_rate, priv->speed);
+	set = DIV_ROUND_UP(priv->clk_rate, speed);
 	set = DIV_ROUND_UP(2048, set);
 	set &= SPI_PFL_CLK_FREQ_MASK;
 	set |= SPI_PFL_CLK_RSTLOOP_MASK;
@@ -164,7 +190,7 @@
 		set |= SPI_PFL_SIG_LATCHRIS_MASK;
 
 	/* async clk */
-	if (priv->speed > SPI_MAX_SYNC_CLOCK)
+	if (speed > SPI_MAX_SYNC_CLOCK)
 		set |= SPI_PFL_SIG_ASYNCIN_MASK;
 
 	clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs), clr, set);
@@ -173,17 +199,24 @@
 	set = 0;
 	clr = 0;
 
-	/* invert cs polarity */
-	if (priv->cs_pols & BIT(plat->cs))
-		clr |= BIT(plat->cs);
-	else
-		set |= BIT(plat->cs);
+	if (priv->xfer_mode == HSSPI_XFER_MODE_PREPEND) {
+		if (priv->cs_pols & BIT(plat->cs))
+			set |= BIT(plat->cs);
+		else
+			clr |= BIT(plat->cs);
+	} else {
+		/* invert cs polarity */
+		if (priv->cs_pols & BIT(plat->cs))
+			clr |= BIT(plat->cs);
+		else
+			set |= BIT(plat->cs);
 
-	/* invert dummy cs polarity */
-	if (priv->cs_pols & BIT(!plat->cs))
-		clr |= BIT(!plat->cs);
-	else
-		set |= BIT(!plat->cs);
+		/* invert dummy cs polarity */
+		if (priv->cs_pols & BIT(!plat->cs))
+			clr |= BIT(!plat->cs);
+		else
+			set |= BIT(!plat->cs);
+	}
 
 	clrsetbits_32(priv->regs + SPI_CTL_REG, clr, set);
 }
@@ -212,16 +245,21 @@
  * all the time. This hack is also used in the upstream linux driver and
  * allows keeping CS active between transfers even if the HW doesn't give
  * this possibility.
+ *
+ * This workaround only works when the dummy CS (usually CS1 when the actual
+ * CS is 0) pinmuxed to SPI chip select function if SPI clock is faster than
+ * SPI_MAX_SYNC_CLOCK. In old broadcom chip, CS1 pin is default to chip select
+ * function. But this is not the case for new chips. To make this function
+ * always work, it should be called with maximum clock of SPI_MAX_SYNC_CLOCK.
  */
-static int bcm63xx_hsspi_xfer(struct udevice *dev, unsigned int bitlen,
-		const void *dout, void *din, unsigned long flags)
+static int bcm63xx_hsspi_xfer_dummy_cs(struct udevice *dev, unsigned int data_bytes,
+				       const void *dout, void *din, unsigned long flags)
 {
 	struct bcm63xx_hsspi_priv *priv = dev_get_priv(dev->parent);
 	struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
-	size_t data_bytes = bitlen / 8;
 	size_t step_size = HSSPI_FIFO_SIZE;
 	uint16_t opcode = 0;
-	uint32_t val;
+	uint32_t val = SPI_PFL_MODE_FILL_MASK;
 	const uint8_t *tx = dout;
 	uint8_t *rx = din;
 
@@ -240,14 +278,17 @@
 		step_size -= HSSPI_FIFO_OP_SIZE;
 
 	/* dual mode */
-	if ((opcode == HSSPI_FIFO_OP_CODE_R && plat->mode == SPI_RX_DUAL) ||
-	    (opcode == HSSPI_FIFO_OP_CODE_W && plat->mode == SPI_TX_DUAL))
+	if ((opcode == HSSPI_FIFO_OP_CODE_R && (plat->mode & SPI_RX_DUAL)) ||
+	    (opcode == HSSPI_FIFO_OP_CODE_W && (plat->mode & SPI_TX_DUAL))) {
 		opcode |= HSSPI_FIFO_OP_MBIT_MASK;
 
-	/* profile mode */
-	val = SPI_PFL_MODE_FILL_MASK |
-	      SPI_PFL_MODE_MDRDSZ_MASK |
-	      SPI_PFL_MODE_MDWRSZ_MASK;
+		/* profile mode */
+		if (plat->mode & SPI_RX_DUAL)
+			val |= SPI_PFL_MODE_MDRDSZ_MASK;
+		if (plat->mode & SPI_TX_DUAL)
+			val |= SPI_PFL_MODE_MDWRSZ_MASK;
+	}
+
 	if (plat->mode & SPI_3WIRE)
 		val |= SPI_PFL_MODE_3WIRE_MASK;
 	writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs));
@@ -297,10 +338,186 @@
 
 	if (flags & SPI_XFER_END)
 		bcm63xx_hsspi_deactivate_cs(priv);
+
+	return 0;
+}
+
+static int bcm63xx_prepare_prepend_transfer(struct bcm63xx_hsspi_priv *priv,
+					    unsigned int data_bytes, const void *dout, void *din,
+					    unsigned long flags)
+{
+	/*
+	 * only support multiple half duplex write transfer + optional
+	 * full duplex read/write at the end.
+	 */
+	if (flags & SPI_XFER_BEGIN) {
+		/* clear prepends */
+		priv->prepend_cnt = 0;
+	}
+
+	if (din) {
+		/* buffering reads not possible for prepend mode */
+		if (!(flags & SPI_XFER_END)) {
+			debug("unable to buffer reads\n");
+			return HSSPI_XFER_MODE_DUMMYCS;
+		}
+
+		/* check rx size */
+		if (data_bytes > HSSPI_MAX_DATA_SIZE) {
+			debug("max rx bytes exceeded\n");
+			return HSSPI_XFER_MODE_DUMMYCS;
+		}
+	}
+
+	if (dout) {
+		/* check tx size */
+		if (flags & SPI_XFER_END) {
+			if (priv->prepend_cnt + data_bytes > HSSPI_MAX_DATA_SIZE) {
+				debug("max tx bytes exceeded\n");
+				return HSSPI_XFER_MODE_DUMMYCS;
+			}
+		} else {
+			if (priv->prepend_cnt + data_bytes > HSSPI_MAX_PREPEND_SIZE) {
+				debug("max prepend bytes exceeded\n");
+				return HSSPI_XFER_MODE_DUMMYCS;
+			}
+
+			/*
+			 * buffer transfer data in the prepend buf in case we have to fall
+			 * back to dummy cs mode.
+			 */
+			memcpy(&priv->prepend_buf[priv->prepend_cnt], dout, data_bytes);
+			priv->prepend_cnt += data_bytes;
+		}
+	}
+
+	return	HSSPI_XFER_MODE_PREPEND;
+}
+
+static int bcm63xx_hsspi_xfer_prepend(struct udevice *dev, unsigned int data_bytes,
+				      const void *dout, void *din, unsigned long flags)
+{
+	struct bcm63xx_hsspi_priv *priv = dev_get_priv(dev->parent);
+	struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
+	uint16_t opcode = 0;
+	uint32_t val, offset;
+	int ret;
+
+	if (flags & SPI_XFER_END) {
+		offset = HSSPI_FIFO_BASE + HSSPI_FIFO_OP_SIZE;
+		if (priv->prepend_cnt) {
+			/* copy prepend data */
+			memcpy_toio(priv->regs + offset,
+				    priv->prepend_buf, priv->prepend_cnt);
+		}
+
+		if (dout && data_bytes) {
+			/* copy tx data */
+			offset += priv->prepend_cnt;
+			memcpy_toio(priv->regs + offset, dout, data_bytes);
+		}
+
+		bcm63xx_hsspi_activate_cs(priv, plat);
+		if (dout && !din) {
+			/* all half-duplex write. merge to single write */
+			data_bytes += priv->prepend_cnt;
+			opcode = HSSPI_FIFO_OP_CODE_W;
+			priv->prepend_cnt = 0;
+		} else if (!dout && din) {
+			/* half-duplex read with prepend write */
+			opcode = HSSPI_FIFO_OP_CODE_R;
+		} else {
+			/* full duplex read/write */
+			opcode = HSSPI_FIFO_OP_READ_WRITE;
+		}
+
+		/* profile mode */
+		val = SPI_PFL_MODE_FILL_MASK;
+		if (plat->mode & SPI_3WIRE)
+			val |= SPI_PFL_MODE_3WIRE_MASK;
+
+		/* dual mode */
+		if ((opcode == HSSPI_FIFO_OP_CODE_R && (plat->mode & SPI_RX_DUAL)) ||
+		    (opcode == HSSPI_FIFO_OP_CODE_W && (plat->mode & SPI_TX_DUAL))) {
+			opcode |= HSSPI_FIFO_OP_MBIT_MASK;
+
+			if (plat->mode & SPI_RX_DUAL) {
+				val |= SPI_PFL_MODE_MDRDSZ_MASK;
+				val |= priv->prepend_cnt << SPI_PFL_MODE_MDRDST_SHIFT;
+			}
+			if (plat->mode & SPI_TX_DUAL) {
+				val |= SPI_PFL_MODE_MDWRSZ_MASK;
+				val |= priv->prepend_cnt << SPI_PFL_MODE_MDWRST_SHIFT;
+			}
+		}
+		val |= (priv->prepend_cnt << SPI_PFL_MODE_PREPCNT_SHIFT);
+		writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs));
+
+		/* set fifo operation */
+		val = opcode | (data_bytes & HSSPI_FIFO_OP_BYTES_MASK);
+		writew(cpu_to_be16(val),
+		       priv->regs + HSSPI_FIFO_OP_REG);
+
+		/* issue the transfer */
+		val = SPI_CMD_OP_START;
+		val |= (plat->cs << SPI_CMD_PFL_SHIFT) &
+		       SPI_CMD_PFL_MASK;
+		val |= (plat->cs << SPI_CMD_SLAVE_SHIFT) &
+		       SPI_CMD_SLAVE_MASK;
+		writel(val, priv->regs + SPI_CMD_REG);
+
+		/* wait for completion */
+		ret = wait_for_bit_32(priv->regs + SPI_STAT_REG,
+				      SPI_STAT_SRCBUSY_MASK, false,
+				      1000, false);
+		if (ret) {
+			bcm63xx_hsspi_deactivate_cs(priv);
+			printf("spi polling timeout\n");
+			return ret;
+		}
+
+		/* copy rx data */
+		if (din)
+			memcpy_fromio(din, priv->regs + HSSPI_FIFO_BASE,
+				      data_bytes);
+		bcm63xx_hsspi_deactivate_cs(priv);
+	}
 
 	return 0;
 }
 
+static int bcm63xx_hsspi_xfer(struct udevice *dev, unsigned int bitlen,
+			      const void *dout, void *din, unsigned long flags)
+{
+	struct bcm63xx_hsspi_priv *priv = dev_get_priv(dev->parent);
+	int ret;
+	u32 data_bytes = bitlen >> 3;
+
+	if (priv->xfer_mode == HSSPI_XFER_MODE_PREPEND) {
+		priv->xfer_mode =
+			bcm63xx_prepare_prepend_transfer(priv, data_bytes, dout, din, flags);
+	}
+
+	/* if not prependable, fall back to dummy cs mode with safe clock */
+	if (priv->xfer_mode == HSSPI_XFER_MODE_DUMMYCS) {
+		/* For pending prepend data from previous transfers, send it first */
+		if (priv->prepend_cnt) {
+			bcm63xx_hsspi_xfer_dummy_cs(dev, priv->prepend_cnt,
+						    priv->prepend_buf, NULL,
+						    (flags & ~SPI_XFER_END) | SPI_XFER_BEGIN);
+			priv->prepend_cnt = 0;
+		}
+		ret = bcm63xx_hsspi_xfer_dummy_cs(dev, data_bytes, dout, din, flags);
+	} else {
+		ret = bcm63xx_hsspi_xfer_prepend(dev, data_bytes, dout, din, flags);
+	}
+
+	if (flags & SPI_XFER_END)
+		priv->xfer_mode = HSSPI_XFER_MODE_PREPEND;
+
+	return ret;
+}
+
 static const struct dm_spi_ops bcm63xx_hsspi_ops = {
 	.cs_info = bcm63xx_hsspi_cs_info,
 	.set_mode = bcm63xx_hsspi_set_mode,
@@ -310,6 +527,7 @@
 
 static const struct udevice_id bcm63xx_hsspi_ids[] = {
 	{ .compatible = "brcm,bcm6328-hsspi", },
+	{ .compatible = "brcm,bcmbca-hsspi-v1.0", },
 	{ /* sentinel */ }
 };
 
@@ -317,6 +535,7 @@
 {
 	struct bcm63xx_hsspi_priv *priv = dev_get_priv(dev->parent);
 	struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
+	struct spi_slave *slave = dev_get_parent_priv(dev);
 
 	/* check cs */
 	if (plat->cs >= priv->num_cs) {
@@ -330,6 +549,13 @@
 	else
 		priv->cs_pols &= ~BIT(plat->cs);
 
+	/*
+	 * set the max read/write size to make sure each xfer are within the
+	 * prepend limit
+	 */
+	slave->max_read_size = HSSPI_MAX_DATA_SIZE;
+	slave->max_write_size = HSSPI_MAX_DATA_SIZE;
+
 	return 0;
 }
 
@@ -391,6 +617,9 @@
 	priv->cs_pols = readl(priv->regs + SPI_CTL_REG) &
 			SPI_CTL_CS_POL_MASK;
 
+	/* default in prepend mode */
+	priv->xfer_mode = HSSPI_XFER_MODE_PREPEND;
+
 	return 0;
 }
 
diff --git a/drivers/spi/bcmbca_hsspi.c b/drivers/spi/bcmbca_hsspi.c
new file mode 100644
index 0000000..fbe315a
--- /dev/null
+++ b/drivers/spi/bcmbca_hsspi.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/spi/spi-bcm63xx-hsspi.c:
+ *	Copyright (C) 2000-2010 Broadcom Corporation
+ *	Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
+ *	Copyright (C) 2021 Broadcom Ltd
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <clk.h>
+#include <spi.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+
+#define HSSPI_PP			0
+
+#define SPI_MAX_SYNC_CLOCK		30000000
+
+/* SPI Control register */
+#define SPI_CTL_REG			0x000
+#define SPI_CTL_CS_POL_SHIFT		0
+#define SPI_CTL_CS_POL_MASK		(0xff << SPI_CTL_CS_POL_SHIFT)
+#define SPI_CTL_CLK_GATE_SHIFT		16
+#define SPI_CTL_CLK_GATE_MASK		BIT(SPI_CTL_CLK_GATE_SHIFT)
+#define SPI_CTL_CLK_POL_SHIFT		17
+#define SPI_CTL_CLK_POL_MASK		BIT(SPI_CTL_CLK_POL_SHIFT)
+
+/* SPI Interrupts registers */
+#define SPI_IR_STAT_REG			0x008
+#define SPI_IR_ST_MASK_REG		0x00c
+#define SPI_IR_MASK_REG			0x010
+
+#define SPI_IR_CLEAR_ALL		0xff001f1f
+
+/* SPI Ping-Pong Command registers */
+#define SPI_CMD_REG			(0x080 + (0x40 * (HSSPI_PP)) + 0x00)
+#define SPI_CMD_OP_SHIFT		0
+#define SPI_CMD_OP_START		BIT(SPI_CMD_OP_SHIFT)
+#define SPI_CMD_PFL_SHIFT		8
+#define SPI_CMD_PFL_MASK		(0x7 << SPI_CMD_PFL_SHIFT)
+#define SPI_CMD_SLAVE_SHIFT		12
+#define SPI_CMD_SLAVE_MASK		(0x7 << SPI_CMD_SLAVE_SHIFT)
+
+/* SPI Ping-Pong Status registers */
+#define SPI_STAT_REG			(0x080 + (0x40 * (HSSPI_PP)) + 0x04)
+#define SPI_STAT_SRCBUSY_SHIFT		1
+#define SPI_STAT_SRCBUSY_MASK		BIT(SPI_STAT_SRCBUSY_SHIFT)
+
+/* SPI Profile Clock registers */
+#define SPI_PFL_CLK_REG(x)		(0x100 + (0x20 * (x)) + 0x00)
+#define SPI_PFL_CLK_FREQ_SHIFT		0
+#define SPI_PFL_CLK_FREQ_MASK		(0x3fff << SPI_PFL_CLK_FREQ_SHIFT)
+#define SPI_PFL_CLK_RSTLOOP_SHIFT	15
+#define SPI_PFL_CLK_RSTLOOP_MASK	BIT(SPI_PFL_CLK_RSTLOOP_SHIFT)
+
+/* SPI Profile Signal registers */
+#define SPI_PFL_SIG_REG(x)		(0x100 + (0x20 * (x)) + 0x04)
+#define SPI_PFL_SIG_LATCHRIS_SHIFT	12
+#define SPI_PFL_SIG_LATCHRIS_MASK	BIT(SPI_PFL_SIG_LATCHRIS_SHIFT)
+#define SPI_PFL_SIG_LAUNCHRIS_SHIFT	13
+#define SPI_PFL_SIG_LAUNCHRIS_MASK	BIT(SPI_PFL_SIG_LAUNCHRIS_SHIFT)
+#define SPI_PFL_SIG_ASYNCIN_SHIFT	16
+#define SPI_PFL_SIG_ASYNCIN_MASK	BIT(SPI_PFL_SIG_ASYNCIN_SHIFT)
+
+/* SPI Profile Mode registers */
+#define SPI_PFL_MODE_REG(x)		(0x100 + (0x20 * (x)) + 0x08)
+#define SPI_PFL_MODE_FILL_SHIFT		0
+#define SPI_PFL_MODE_FILL_MASK		(0xff << SPI_PFL_MODE_FILL_SHIFT)
+#define SPI_PFL_MODE_MDRDSZ_SHIFT	16
+#define SPI_PFL_MODE_MDRDSZ_MASK	BIT(SPI_PFL_MODE_MDRDSZ_SHIFT)
+#define SPI_PFL_MODE_MDWRSZ_SHIFT	18
+#define SPI_PFL_MODE_MDWRSZ_MASK	BIT(SPI_PFL_MODE_MDWRSZ_SHIFT)
+#define SPI_PFL_MODE_3WIRE_SHIFT	20
+#define SPI_PFL_MODE_3WIRE_MASK		BIT(SPI_PFL_MODE_3WIRE_SHIFT)
+
+/* SPI Ping-Pong FIFO registers */
+#define HSSPI_FIFO_SIZE			0x200
+#define HSSPI_FIFO_BASE			(0x200 + \
+					 (HSSPI_FIFO_SIZE * HSSPI_PP))
+
+/* SPI Ping-Pong FIFO OP register */
+#define HSSPI_FIFO_OP_SIZE		0x2
+#define HSSPI_FIFO_OP_REG		(HSSPI_FIFO_BASE + 0x00)
+#define HSSPI_FIFO_OP_BYTES_SHIFT	0
+#define HSSPI_FIFO_OP_BYTES_MASK	(0x3ff << HSSPI_FIFO_OP_BYTES_SHIFT)
+#define HSSPI_FIFO_OP_MBIT_SHIFT	11
+#define HSSPI_FIFO_OP_MBIT_MASK		BIT(HSSPI_FIFO_OP_MBIT_SHIFT)
+#define HSSPI_FIFO_OP_CODE_SHIFT	13
+#define HSSPI_FIFO_OP_READ_WRITE	(1 << HSSPI_FIFO_OP_CODE_SHIFT)
+#define HSSPI_FIFO_OP_CODE_W		(2 << HSSPI_FIFO_OP_CODE_SHIFT)
+#define HSSPI_FIFO_OP_CODE_R		(3 << HSSPI_FIFO_OP_CODE_SHIFT)
+
+#define HSSPI_MAX_DATA_SIZE		(HSSPI_FIFO_SIZE - HSSPI_FIFO_OP_SIZE)
+
+#define SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT		0
+#define SPIM_CTRL_CS_OVERRIDE_SEL_MASK		0xff
+#define SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT		8
+#define SPIM_CTRL_CS_OVERRIDE_VAL_MASK		0xff
+
+struct bcmbca_hsspi_priv {
+	void __iomem *regs;
+	void __iomem *spim_ctrl;
+	u32 clk_rate;
+	u8 num_cs;
+	u8 cs_pols;
+	u32 speed;
+};
+
+static int bcmbca_hsspi_cs_info(struct udevice *bus, uint cs,
+				struct spi_cs_info *info)
+{
+	struct bcmbca_hsspi_priv *priv = dev_get_priv(bus);
+
+	if (cs >= priv->num_cs) {
+		dev_err(bus, "no cs %u\n", cs);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bcmbca_hsspi_set_mode(struct udevice *bus, uint mode)
+{
+	struct bcmbca_hsspi_priv *priv = dev_get_priv(bus);
+
+	/* clock polarity */
+	if (mode & SPI_CPOL)
+		setbits_32(priv->regs + SPI_CTL_REG, SPI_CTL_CLK_POL_MASK);
+	else
+		clrbits_32(priv->regs + SPI_CTL_REG, SPI_CTL_CLK_POL_MASK);
+
+	return 0;
+}
+
+static int bcmbca_hsspi_set_speed(struct udevice *bus, uint speed)
+{
+	struct bcmbca_hsspi_priv *priv = dev_get_priv(bus);
+
+	priv->speed = speed;
+
+	return 0;
+}
+
+static void bcmbca_hsspi_setup_clock(struct bcmbca_hsspi_priv *priv,
+				     struct dm_spi_slave_plat *plat)
+{
+	u32 clr, set;
+
+	/* profile clock */
+	set = DIV_ROUND_UP(priv->clk_rate, priv->speed);
+	set = DIV_ROUND_UP(2048, set);
+	set &= SPI_PFL_CLK_FREQ_MASK;
+	set |= SPI_PFL_CLK_RSTLOOP_MASK;
+	writel(set, priv->regs + SPI_PFL_CLK_REG(plat->cs));
+
+	/* profile signal */
+	set = 0;
+	clr = SPI_PFL_SIG_LAUNCHRIS_MASK |
+	      SPI_PFL_SIG_LATCHRIS_MASK |
+	      SPI_PFL_SIG_ASYNCIN_MASK;
+
+	/* latch/launch config */
+	if (plat->mode & SPI_CPHA)
+		set |= SPI_PFL_SIG_LAUNCHRIS_MASK;
+	else
+		set |= SPI_PFL_SIG_LATCHRIS_MASK;
+
+	/* async clk */
+	if (priv->speed > SPI_MAX_SYNC_CLOCK)
+		set |= SPI_PFL_SIG_ASYNCIN_MASK;
+
+	clrsetbits_32(priv->regs + SPI_PFL_SIG_REG(plat->cs), clr, set);
+
+	/* global control */
+	set = 0;
+	clr = 0;
+
+	if (priv->cs_pols & BIT(plat->cs))
+		set |= BIT(plat->cs);
+	else
+		clr |= BIT(plat->cs);
+
+	clrsetbits_32(priv->regs + SPI_CTL_REG, clr, set);
+}
+
+static void bcmbca_hsspi_activate_cs(struct bcmbca_hsspi_priv *priv,
+				     struct dm_spi_slave_plat *plat)
+{
+	u32 val;
+
+	/* set the override bit */
+	val = readl(priv->spim_ctrl);
+	val |= BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
+	writel(val, priv->spim_ctrl);
+}
+
+static void bcmbca_hsspi_deactivate_cs(struct bcmbca_hsspi_priv *priv,
+				       struct dm_spi_slave_plat *plat)
+{
+	u32 val;
+
+	/* clear the cs override bit */
+	val = readl(priv->spim_ctrl);
+	val &= ~BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
+	writel(val, priv->spim_ctrl);
+}
+
+static int bcmbca_hsspi_xfer(struct udevice *dev, unsigned int bitlen,
+			     const void *dout, void *din, unsigned long flags)
+{
+	struct bcmbca_hsspi_priv *priv = dev_get_priv(dev->parent);
+	struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
+	size_t data_bytes = bitlen / 8;
+	size_t step_size = HSSPI_FIFO_SIZE;
+	u16 opcode = 0;
+	u32 val = SPI_PFL_MODE_FILL_MASK;
+	const u8 *tx = dout;
+	u8 *rx = din;
+	u32 cs_act = 0;
+
+	if (flags & SPI_XFER_BEGIN)
+		bcmbca_hsspi_setup_clock(priv, plat);
+
+	/* fifo operation */
+	if (tx && rx)
+		opcode = HSSPI_FIFO_OP_READ_WRITE;
+	else if (rx)
+		opcode = HSSPI_FIFO_OP_CODE_R;
+	else if (tx)
+		opcode = HSSPI_FIFO_OP_CODE_W;
+
+	if (opcode != HSSPI_FIFO_OP_CODE_R)
+		step_size -= HSSPI_FIFO_OP_SIZE;
+
+	/* dual mode */
+	if ((opcode == HSSPI_FIFO_OP_CODE_R && (plat->mode & SPI_RX_DUAL)) ||
+	    (opcode == HSSPI_FIFO_OP_CODE_W && (plat->mode & SPI_TX_DUAL))) {
+		opcode |= HSSPI_FIFO_OP_MBIT_MASK;
+
+		/* profile mode */
+		if (plat->mode & SPI_RX_DUAL)
+			val |= SPI_PFL_MODE_MDRDSZ_MASK;
+		if (plat->mode & SPI_TX_DUAL)
+			val |= SPI_PFL_MODE_MDWRSZ_MASK;
+	}
+
+	if (plat->mode & SPI_3WIRE)
+		val |= SPI_PFL_MODE_3WIRE_MASK;
+	writel(val, priv->regs + SPI_PFL_MODE_REG(plat->cs));
+
+	/* transfer loop */
+	while (data_bytes > 0) {
+		size_t curr_step = min(step_size, data_bytes);
+		int ret;
+
+		/* copy tx data */
+		if (tx) {
+			memcpy_toio(priv->regs + HSSPI_FIFO_BASE +
+				    HSSPI_FIFO_OP_SIZE, tx, curr_step);
+			tx += curr_step;
+		}
+
+		/* set fifo operation */
+		writew(cpu_to_be16(opcode | (curr_step & HSSPI_FIFO_OP_BYTES_MASK)),
+		       priv->regs + HSSPI_FIFO_OP_REG);
+
+		/* make sure we keep cs active until spi transfer is done */
+		if (!cs_act) {
+			bcmbca_hsspi_activate_cs(priv, plat);
+			cs_act = 1;
+		}
+
+		/* issue the transfer */
+		val = SPI_CMD_OP_START;
+		val |= (plat->cs << SPI_CMD_PFL_SHIFT) &
+			  SPI_CMD_PFL_MASK;
+		val |= (plat->cs << SPI_CMD_SLAVE_SHIFT) &
+			  SPI_CMD_SLAVE_MASK;
+		writel(val, priv->regs + SPI_CMD_REG);
+
+		/* wait for completion */
+		ret = wait_for_bit_32(priv->regs + SPI_STAT_REG,
+				      SPI_STAT_SRCBUSY_MASK, false,
+				      1000, false);
+		if (ret) {
+			bcmbca_hsspi_deactivate_cs(priv, plat);
+			dev_err(dev, "interrupt timeout\n");
+			return ret;
+		}
+
+		data_bytes -= curr_step;
+		if ((flags & SPI_XFER_END) && !data_bytes)
+			bcmbca_hsspi_deactivate_cs(priv, plat);
+
+		/* copy rx data */
+		if (rx) {
+			memcpy_fromio(rx, priv->regs + HSSPI_FIFO_BASE,
+				      curr_step);
+			rx += curr_step;
+		}
+	}
+
+	return 0;
+}
+
+static const struct dm_spi_ops bcmbca_hsspi_ops = {
+	.cs_info = bcmbca_hsspi_cs_info,
+	.set_mode = bcmbca_hsspi_set_mode,
+	.set_speed = bcmbca_hsspi_set_speed,
+	.xfer = bcmbca_hsspi_xfer,
+};
+
+static const struct udevice_id bcmbca_hsspi_ids[] = {
+	{ .compatible = "brcm,bcmbca-hsspi-v1.1", },
+	{ /* sentinel */ }
+};
+
+static int bcmbca_hsspi_child_pre_probe(struct udevice *dev)
+{
+	struct bcmbca_hsspi_priv *priv = dev_get_priv(dev->parent);
+	struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev);
+	u32 val;
+
+	/* check cs */
+	if (plat->cs >= priv->num_cs) {
+		dev_err(dev, "no cs %u\n", plat->cs);
+		return -EINVAL;
+	}
+
+	/* cs polarity */
+	if (plat->mode & SPI_CS_HIGH)
+		priv->cs_pols |= BIT(plat->cs);
+	else
+		priv->cs_pols &= ~BIT(plat->cs);
+
+	/* set the polarity to spim cs register */
+	val = readl(priv->spim_ctrl);
+	val &= ~BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
+	if (priv->cs_pols & BIT(plat->cs))
+		val |= BIT(plat->cs + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
+	writel(val, priv->spim_ctrl);
+
+	return 0;
+}
+
+static int bcmbca_hsspi_probe(struct udevice *dev)
+{
+	struct bcmbca_hsspi_priv *priv = dev_get_priv(dev);
+	struct clk clk;
+	int ret;
+
+	priv->regs = dev_remap_addr_name(dev, "hsspi");
+	if (!priv->regs)
+		return -EINVAL;
+
+	priv->spim_ctrl = dev_remap_addr_name(dev, "spim-ctrl");
+	if (!priv->spim_ctrl) {
+		dev_err(dev, "misc spim ctrl register not defined in dts!\n");
+		return -EINVAL;
+	}
+
+	priv->num_cs = dev_read_u32_default(dev, "num-cs", 8);
+
+	/* enable clock */
+	ret = clk_get_by_name(dev, "hsspi", &clk);
+	if (ret < 0)
+		return ret;
+
+	ret = clk_enable(&clk);
+	if (ret < 0 && ret != -ENOSYS)
+		return ret;
+
+	clk_free(&clk);
+
+	/* get clock rate */
+	ret = clk_get_by_name(dev, "pll", &clk);
+	if (ret < 0 && ret != -ENOSYS)
+		return ret;
+
+	priv->clk_rate = clk_get_rate(&clk);
+
+	clk_free(&clk);
+
+	/* initialize hardware */
+	writel(0, priv->regs + SPI_IR_MASK_REG);
+
+	/* clear pending interrupts */
+	writel(SPI_IR_CLEAR_ALL, priv->regs + SPI_IR_STAT_REG);
+
+	/* enable clk gate */
+	setbits_32(priv->regs + SPI_CTL_REG, SPI_CTL_CLK_GATE_MASK);
+
+	/* read default cs polarities */
+	priv->cs_pols = readl(priv->regs + SPI_CTL_REG) &
+			SPI_CTL_CS_POL_MASK;
+
+	dev_info(dev, "Broadcom BCMBCA HS SPI bus driver\n");
+	return 0;
+}
+
+U_BOOT_DRIVER(bcmbca_hsspi) = {
+	.name = "bcmbca_hsspi",
+	.id = UCLASS_SPI,
+	.of_match = bcmbca_hsspi_ids,
+	.ops = &bcmbca_hsspi_ops,
+	.priv_auto = sizeof(struct bcmbca_hsspi_priv),
+	.child_pre_probe = bcmbca_hsspi_child_pre_probe,
+	.probe = bcmbca_hsspi_probe,
+};
diff --git a/drivers/spi/npcm_pspi.c b/drivers/spi/npcm_pspi.c
index bd9ac65..37bab70 100644
--- a/drivers/spi/npcm_pspi.c
+++ b/drivers/spi/npcm_pspi.c
@@ -40,7 +40,7 @@
 	struct udevice *bus = dev->parent;
 	struct npcm_pspi_priv *priv = dev_get_priv(bus);
 
-	dm_gpio_set_value(&priv->cs_gpio, 0);
+	dm_gpio_set_value(&priv->cs_gpio, 1);
 }
 
 static inline void spi_cs_deactivate(struct udevice *dev)
@@ -48,7 +48,7 @@
 	struct udevice *bus = dev->parent;
 	struct npcm_pspi_priv *priv = dev_get_priv(bus);
 
-	dm_gpio_set_value(&priv->cs_gpio, 1);
+	dm_gpio_set_value(&priv->cs_gpio, 0);
 }
 
 static inline void npcm_pspi_enable(struct npcm_pspi_priv *priv)
@@ -122,6 +122,9 @@
 	if (flags & SPI_XFER_END)
 		spi_cs_deactivate(dev);
 
+	debug("npcm_pspi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n",
+	      dev->parent->name, dev->name, *(uint *)tx, *(uint *)rx, bitlen);
+
 	npcm_pspi_disable(priv);
 
 	return ret;
@@ -183,6 +186,7 @@
 	val |= pspi_mode;
 	writew(val, priv->base + PSPI_CTL1);
 
+	debug("%s: mode=%u\n", __func__, mode);
 	return 0;
 }
 
@@ -197,9 +201,9 @@
 		return ret;
 
 	priv->base = dev_read_addr_ptr(bus);
-	priv->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 0);
+	priv->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 1000000);
 	gpio_request_by_name_nodev(offset_to_ofnode(node), "cs-gpios", 0,
-				   &priv->cs_gpio, GPIOD_IS_OUT);
+				   &priv->cs_gpio, GPIOD_IS_OUT| GPIOD_ACTIVE_LOW);
 
 	return 0;
 }
diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c
index 828eab3..fc7388b 100644
--- a/drivers/spi/pl022_spi.c
+++ b/drivers/spi/pl022_spi.c
@@ -12,9 +12,11 @@
 #include <clk.h>
 #include <common.h>
 #include <dm.h>
-#include <dm/platform_data/spi_pl022.h>
+#include <dm/device_compat.h>
+#include <fdtdec.h>
 #include <linux/io.h>
 #include <asm/global_data.h>
+#include <asm/gpio.h>
 #include <spi.h>
 
 #define SSP_CR0		0x000
@@ -66,6 +68,15 @@
 #define SSP_SR_MASK_RFF		(0x1 << 3) /* Receive FIFO full */
 #define SSP_SR_MASK_BSY		(0x1 << 4) /* Busy Flag */
 
+struct pl022_spi_pdata {
+	fdt_addr_t addr;
+	fdt_size_t size;
+	unsigned int freq;
+#if CONFIG_IS_ENABLED(DM_GPIO)
+	struct gpio_desc cs_gpio;
+#endif
+};
+
 struct pl022_spi_slave {
 	void *base;
 	unsigned int freq;
@@ -107,7 +118,7 @@
 	return 0;
 }
 
-static void flush(struct pl022_spi_slave *ps)
+static void pl022_spi_flush(struct pl022_spi_slave *ps)
 {
 	do {
 		while (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE)
@@ -126,7 +137,7 @@
 	reg |= SSP_CR1_MASK_SSE;
 	writew(reg, ps->base + SSP_CR1);
 
-	flush(ps);
+	pl022_spi_flush(ps);
 
 	return 0;
 }
@@ -137,7 +148,7 @@
 	struct pl022_spi_slave *ps = dev_get_priv(bus);
 	u16 reg;
 
-	flush(ps);
+	pl022_spi_flush(ps);
 
 	/* Disable the SPI hardware */
 	reg = readw(ps->base + SSP_CR1);
@@ -147,6 +158,17 @@
 	return 0;
 }
 
+static void pl022_spi_set_cs(struct udevice *dev, bool on)
+{
+#if CONFIG_IS_ENABLED(DM_GPIO)
+	struct udevice *bus = dev->parent;
+	struct pl022_spi_pdata *plat = dev_get_plat(bus);
+
+	if (dm_gpio_is_valid(&plat->cs_gpio))
+		dm_gpio_set_value(&plat->cs_gpio, on ? 1 : 0);
+#endif
+}
+
 static int pl022_spi_xfer(struct udevice *dev, unsigned int bitlen,
 			  const void *dout, void *din, unsigned long flags)
 {
@@ -159,7 +181,7 @@
 
 	if (bitlen == 0)
 		/* Finish any previously submitted transfers */
-		return 0;
+		goto done;
 
 	/*
 	 * TODO: The controller can do non-multiple-of-8 bit
@@ -172,9 +194,13 @@
 	if (bitlen % 8) {
 		/* Errors always terminate an ongoing transfer */
 		flags |= SPI_XFER_END;
-		return -1;
+		ret = -1;
+		goto done;
 	}
 
+	if (flags & SPI_XFER_BEGIN)
+		pl022_spi_set_cs(dev, true);
+
 	len = bitlen / 8;
 
 	while (len_tx < len) {
@@ -201,6 +227,10 @@
 		}
 	}
 
+done:
+	if (flags & SPI_XFER_END)
+		pl022_spi_set_cs(dev, false);
+
 	return ret;
 }
 
@@ -303,11 +333,18 @@
 
 	plat->freq = clk_get_rate(&clkdev);
 
+#if CONFIG_IS_ENABLED(DM_GPIO)
+	ret = gpio_request_by_name(bus, "cs-gpios", 0, &plat->cs_gpio,
+				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	if (ret < 0 && ret != -ENOENT)
+		return ret;
+#endif
+
 	return 0;
 }
 
 static const struct udevice_id pl022_spi_ids[] = {
-	{ .compatible = "arm,pl022-spi" },
+	{ .compatible = "arm,pl022" },
 	{ }
 };
 #endif
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index f3602a2..0fa1433 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -248,20 +248,33 @@
 	cs_flags = (slave && slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW;
 	clk_flags = (slave && slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0;
 
-	if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs,
-				 GPIOD_IS_OUT | cs_flags) ||
-	    gpio_request_by_name(dev, "gpio-sck", 0, &plat->sclk,
-				 GPIOD_IS_OUT | clk_flags))
+	ret = gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs,
+				   GPIOD_IS_OUT | cs_flags);
+	if (ret)
 		return -EINVAL;
 
+	ret = gpio_request_by_name(dev, "gpio-sck", 0, &plat->sclk,
+				   GPIOD_IS_OUT | clk_flags);
+	if (ret)
+		ret = gpio_request_by_name(dev, "sck-gpios", 0, &plat->sclk,
+					   GPIOD_IS_OUT | clk_flags);
+	if (ret)
+		return -EINVAL;
+
 	ret = gpio_request_by_name(dev, "gpio-mosi", 0, &plat->mosi,
 				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
 	if (ret)
+		ret = gpio_request_by_name(dev, "mosi-gpios", 0, &plat->mosi,
+					   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	if (ret)
 		plat->flags |= SPI_MASTER_NO_TX;
 
 	ret = gpio_request_by_name(dev, "gpio-miso", 0, &plat->miso,
 				   GPIOD_IS_IN);
 	if (ret)
+		ret = gpio_request_by_name(dev, "gpio-miso", 0, &plat->miso,
+					   GPIOD_IS_IN);
+	if (ret)
 		plat->flags |= SPI_MASTER_NO_RX;
 
 	if ((plat->flags & (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX)) ==
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
index 0f5d0a3..553f968 100644
--- a/drivers/spi/spi-synquacer.c
+++ b/drivers/spi/spi-synquacer.c
@@ -186,7 +186,7 @@
 	struct udevice *bus = dev->parent;
 	struct synquacer_spi_priv *priv = dev_get_priv(bus);
 	struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
-	u32 val, div, bus_width = 1;
+	u32 val, div, bus_width;
 	int rwflag;
 
 	rwflag = (rx ? 1 : 0) | (tx ? 2 : 0);
@@ -203,16 +203,14 @@
 	priv->mode = slave_plat->mode;
 	priv->speed = slave_plat->max_hz;
 
-	if (priv->mode & SPI_TX_BYTE)
-		bus_width = 1;
-	else if (priv->mode & SPI_TX_DUAL)
+	if (priv->mode & SPI_TX_DUAL)
 		bus_width = 2;
 	else if (priv->mode & SPI_TX_QUAD)
 		bus_width = 4;
 	else if (priv->mode & SPI_TX_OCTAL)
 		bus_width = 8;
 	else
-		log_warning("SPI mode not configured, setting to byte mode\n");
+		bus_width = 1; /* default is single bit mode */
 
 	div = DIV_ROUND_UP(125000000, priv->speed);
 
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index 8dd29ed..3bf1a95 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -775,7 +775,7 @@
 
 	/* command descriptor fields */
 	ucd_req_ptr->header.dword_0 =
-			UPIU_HEADER_DWORD(UPIU_TRANSACTION_NOP_OUT, 0, 0, 0x1f);
+			UPIU_HEADER_DWORD(UPIU_TRANSACTION_NOP_OUT, 0, 0, TASK_TAG);
 	/* clear rest of the fields of basic header */
 	ucd_req_ptr->header.dword_1 = 0;
 	ucd_req_ptr->header.dword_2 = 0;
diff --git a/drivers/usb/host/usb_bootdev.c b/drivers/usb/host/usb_bootdev.c
index 06e8f61..7fa1c60 100644
--- a/drivers/usb/host/usb_bootdev.c
+++ b/drivers/usb/host/usb_bootdev.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Bootdevice for USB
+ * Bootdev for USB
  *
  * Copyright 2021 Google LLC
  * Written by Simon Glass <sjg@chromium.org>
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4976295..b8147f2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -278,6 +278,36 @@
 	  possible to update the environment, the breakage may be confusing for
 	  users. This option will be removed around the end of 2020.
 
+config VIDEO_BOCHS
+	bool "Enable Bochs video emulation for QEMU"
+	depends on X86
+	help
+	  Enable this to use the Bochs video support provided in the QEMU
+	  emulator. This appears as a PCI device which U-Boot can set up to
+	  provide a frame buffer.
+
+if VIDEO_BOCHS
+
+config VIDEO_BOCHS_SIZE_X
+	int "Width of display (X resolution)"
+	default 1280
+	help
+	  Sets the width of the display.
+
+	  These two options control the size of the display set up by QEMU.
+	  Typical sizes are 1024 x 768 or 1280 x 1024.
+
+config VIDEO_BOCHS_SIZE_Y
+	int "High of display (Y resolution)"
+	default 1024
+	help
+	  Sets the height of the display.
+
+	  These two options control the size of the display set up by QEMU.
+	  Typical sizes are 1024 x 768 or 1280 x 1024.
+
+endif
+
 config VIDEO_COREBOOT
 	bool "Enable coreboot framebuffer driver support"
 	depends on X86
@@ -477,6 +507,14 @@
 	  using the same DSI command sequence. The panel has a 720x1280
 	  resolution and uses 24 bit RGB per pixel.
 
+config VIDEO_LCD_HIMAX_HX8394
+	bool "Himax HX8394 DSI LCD panel support"
+	depends on PANEL && BACKLIGHT
+	select VIDEO_MIPI_DSI
+	help
+	Say Y here if you want to enable support for Himax HX8394
+	dsi 4dl panel.
+
 config VIDEO_LCD_ORISETECH_OTM8009A
 	bool "OTM8009A DSI LCD panel support"
 	select VIDEO_MIPI_DSI
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index f99d7e3..d13af9f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -45,6 +45,7 @@
 obj-$(CONFIG_SANDBOX_OSD) += sandbox_osd.o
 obj-$(CONFIG_VIDEO_ARM_MALIDP) += mali_dp.o
 obj-$(CONFIG_VIDEO_BCM2835) += bcm2835.o
+obj-$(CONFIG_VIDEO_BOCHS) += bochs.o
 obj-$(CONFIG_VIDEO_BROADWELL_IGD) += broadwell_igd.o
 obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o
 obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
@@ -54,6 +55,7 @@
 obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o
 obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o
 obj-$(CONFIG_VIDEO_LCD_ENDEAVORU) += endeavoru-panel.o
+obj-$(CONFIG_VIDEO_LCD_HIMAX_HX8394) += himax-hx8394.o
 obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
 obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o
 obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o
diff --git a/drivers/video/bochs.c b/drivers/video/bochs.c
new file mode 100644
index 0000000..2136b51
--- /dev/null
+++ b/drivers/video/bochs.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Modified from coreboot bochs.c
+ */
+
+#define LOG_CATEGORY	UCLASS_VIDEO
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <pci.h>
+#include <video.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <linux/sizes.h>
+#include "bochs.h"
+
+static int xsize = CONFIG_VIDEO_BOCHS_SIZE_X;
+static int ysize = CONFIG_VIDEO_BOCHS_SIZE_Y;
+
+static void bochs_write(void *mmio, int index, int val)
+{
+	writew(val, mmio + MMIO_BASE + index * 2);
+}
+
+static int bochs_read(void *mmio, int index)
+{
+	return readw(mmio + MMIO_BASE + index * 2);
+}
+
+static void bochs_vga_write(int index, uint8_t val)
+{
+	outb(val, VGA_INDEX);
+}
+
+static int bochs_init_fb(struct udevice *dev)
+{
+	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+	ulong fb;
+	void *mmio;
+	int id, mem;
+
+	log_debug("probing %s at PCI %x\n", dev->name, dm_pci_get_bdf(dev));
+	fb = dm_pci_read_bar32(dev, 0);
+	if (!fb)
+		return log_msg_ret("fb", -EIO);
+
+	/* MMIO bar supported since qemu 3.0+ */
+	mmio = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_2, 0, 0, PCI_REGION_TYPE,
+			      PCI_REGION_MEM);
+
+	if (!mmio)
+		return log_msg_ret("map", -EIO);
+
+	/* bochs dispi detection */
+	id = bochs_read(mmio, INDEX_ID);
+	if ((id & 0xfff0) != ID0) {
+		log_debug("ID mismatch\n");
+		return -EPROTONOSUPPORT;
+	}
+	mem = bochs_read(mmio, INDEX_VIDEO_MEMORY_64K) * SZ_64K;
+	log_debug("QEMU VGA: bochs @ %p: %d MiB FB at %lx\n", mmio, mem / SZ_1M,
+		  fb);
+
+	uc_priv->xsize = xsize;
+	uc_priv->ysize = ysize;
+	uc_priv->bpix = VIDEO_BPP32;
+
+	/* setup video mode */
+	bochs_write(mmio, INDEX_ENABLE,  0);
+	bochs_write(mmio, INDEX_BANK,  0);
+	bochs_write(mmio, INDEX_BPP, VNBITS(uc_priv->bpix));
+	bochs_write(mmio, INDEX_XRES, xsize);
+	bochs_write(mmio, INDEX_YRES, ysize);
+	bochs_write(mmio, INDEX_VIRT_WIDTH, xsize);
+	bochs_write(mmio, INDEX_VIRT_HEIGHT, ysize);
+	bochs_write(mmio, INDEX_X_OFFSET, 0);
+	bochs_write(mmio, INDEX_Y_OFFSET, 0);
+	bochs_write(mmio, INDEX_ENABLE, ENABLED | LFB_ENABLED);
+
+	bochs_vga_write(0, 0x20);	/* disable blanking */
+
+	plat->base = fb;
+
+	return 0;
+}
+
+static int bochs_video_probe(struct udevice *dev)
+{
+	int ret;
+
+	ret = bochs_init_fb(dev);
+	if (ret)
+		return log_ret(ret);
+
+	return 0;
+}
+
+static int bochs_video_bind(struct udevice *dev)
+{
+	struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
+
+	/* Set the maximum supported resolution */
+	uc_plat->size = 2560 * 1600 * 4;
+	log_debug("%s: Frame buffer size %x\n", __func__, uc_plat->size);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bochs_video) = {
+	.name	= "bochs_video",
+	.id	= UCLASS_VIDEO,
+	.bind	= bochs_video_bind,
+	.probe	= bochs_video_probe,
+};
+
+static struct pci_device_id bochs_video_supported[] = {
+	{ PCI_DEVICE(0x1234, 0x1111) },
+	{ },
+};
+
+U_BOOT_PCI_DEVICE(bochs_video, bochs_video_supported);
diff --git a/drivers/video/bochs.h b/drivers/video/bochs.h
new file mode 100644
index 0000000..4c8ec83
--- /dev/null
+++ b/drivers/video/bochs.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Modified from coreboot bochs.c
+ */
+
+#ifndef __BOCHS_H
+#define __BOCHS_H
+
+#define VGA_INDEX	0x3c0
+
+#define IOPORT_INDEX	0x01ce
+#define IOPORT_DATA	0x01cf
+
+enum {
+	INDEX_ID,
+	INDEX_XRES,
+	INDEX_YRES,
+	INDEX_BPP,
+	INDEX_ENABLE,
+	INDEX_BANK,
+	INDEX_VIRT_WIDTH,
+	INDEX_VIRT_HEIGHT,
+	INDEX_X_OFFSET,
+	INDEX_Y_OFFSET,
+	INDEX_VIDEO_MEMORY_64K
+};
+
+#define ID0		0xb0c0
+
+#define ENABLED		BIT(0)
+#define LFB_ENABLED	BIT(6)
+#define NOCLEARMEM	BIT(7)
+
+#define MMIO_BASE	0x500
+
+#endif
diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c
index 1f93b1b..b5d0e3d 100644
--- a/drivers/video/console_core.c
+++ b/drivers/video/console_core.c
@@ -201,6 +201,12 @@
 {
 	struct video_fontdata *font;
 
+	if (!name) {
+		if (fonts->name)
+			console_set_font(dev, fonts);
+		return 0;
+	}
+
 	for (font = fonts; font->name; font++) {
 		if (!strcmp(name, font->name)) {
 			console_set_font(dev, font);
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index 6b53901..0f9bb49 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -62,10 +62,43 @@
 	return lo;
 }
 
+static double tt_fmod(double x, double y)
+{
+	double rem;
+
+	if (y == 0.0)
+		return 0.0;
+	rem = x - (x / y) * y;
+
+	return rem;
+}
+
+/* dummy implementation */
+static double tt_pow(double x, double y)
+{
+	return 0;
+}
+
+/* dummy implementation */
+static double tt_cos(double val)
+{
+	return 0;
+}
+
+/* dummy implementation */
+static double tt_acos(double val)
+{
+	return 0;
+}
+
 #define STBTT_ifloor		tt_floor
 #define STBTT_iceil		tt_ceil
 #define STBTT_fabs		tt_fabs
 #define STBTT_sqrt		tt_sqrt
+#define STBTT_pow		tt_pow
+#define STBTT_fmod		tt_fmod
+#define STBTT_cos		tt_cos
+#define STBTT_acos		tt_acos
 #define STBTT_malloc(size, u)	((void)(u), malloc(size))
 #define STBTT_free(size, u)	((void)(u), free(size))
 #define STBTT_assert(x)
@@ -154,33 +187,33 @@
 	end = line + met->font_size * vid_priv->line_length;
 
 	switch (vid_priv->bpix) {
-#ifdef CONFIG_VIDEO_BPP8
 	case VIDEO_BPP8: {
 		u8 *dst;
 
-		for (dst = line; dst < (u8 *)end; ++dst)
-			*dst = clr;
+		if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
+			for (dst = line; dst < (u8 *)end; ++dst)
+				*dst = clr;
+		}
 		break;
 	}
-#endif
-#ifdef CONFIG_VIDEO_BPP16
 	case VIDEO_BPP16: {
 		u16 *dst = line;
 
-		for (dst = line; dst < (u16 *)end; ++dst)
-			*dst = clr;
+		if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
+			for (dst = line; dst < (u16 *)end; ++dst)
+				*dst = clr;
+		}
 		break;
 	}
-#endif
-#ifdef CONFIG_VIDEO_BPP32
 	case VIDEO_BPP32: {
 		u32 *dst = line;
 
-		for (dst = line; dst < (u32 *)end; ++dst)
-			*dst = clr;
+		if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
+			for (dst = line; dst < (u32 *)end; ++dst)
+				*dst = clr;
+		}
 		break;
 	}
-#endif
 	default:
 		return -ENOSYS;
 	}
@@ -256,7 +289,7 @@
 	 */
 	x_shift = xpos - (double)tt_floor(xpos);
 	xpos += advance * met->scale;
-	width_frac = (int)VID_TO_POS(xpos);
+	width_frac = (int)VID_TO_POS(advance * met->scale);
 	if (x + width_frac >= vc_priv->xsize_frac)
 		return -EAGAIN;
 
@@ -317,52 +350,52 @@
 				end = dst;
 			}
 			break;
-#ifdef CONFIG_VIDEO_BPP16
 		case VIDEO_BPP16: {
 			uint16_t *dst = (uint16_t *)line + xoff;
 			int i;
 
-			for (i = 0; i < width; i++) {
-				int val = *bits;
-				int out;
+			if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
+				for (i = 0; i < width; i++) {
+					int val = *bits;
+					int out;
 
-				if (vid_priv->colour_bg)
-					val = 255 - val;
-				out = val >> 3 |
-					(val >> 2) << 5 |
-					(val >> 3) << 11;
-				if (vid_priv->colour_fg)
-					*dst++ |= out;
-				else
-					*dst++ &= out;
-				bits++;
+					if (vid_priv->colour_bg)
+						val = 255 - val;
+					out = val >> 3 |
+						(val >> 2) << 5 |
+						(val >> 3) << 11;
+					if (vid_priv->colour_fg)
+						*dst++ |= out;
+					else
+						*dst++ &= out;
+					bits++;
+				}
+				end = dst;
 			}
-			end = dst;
 			break;
 		}
-#endif
-#ifdef CONFIG_VIDEO_BPP32
 		case VIDEO_BPP32: {
 			u32 *dst = (u32 *)line + xoff;
 			int i;
 
-			for (i = 0; i < width; i++) {
-				int val = *bits;
-				int out;
+			if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
+				for (i = 0; i < width; i++) {
+					int val = *bits;
+					int out;
 
-				if (vid_priv->colour_bg)
-					val = 255 - val;
-				out = val | val << 8 | val << 16;
-				if (vid_priv->colour_fg)
-					*dst++ |= out;
-				else
-					*dst++ &= out;
-				bits++;
+					if (vid_priv->colour_bg)
+						val = 255 - val;
+					out = val | val << 8 | val << 16;
+					if (vid_priv->colour_fg)
+						*dst++ |= out;
+					else
+						*dst++ &= out;
+					bits++;
+				}
+				end = dst;
 			}
-			end = dst;
 			break;
 		}
-#endif
 		default:
 			free(data);
 			return -ENOSYS;
@@ -379,72 +412,6 @@
 }
 
 /**
- * console_truetype_erase() - Erase a character
- *
- * This is used for backspace. We erase a square of the display within the
- * given bounds.
- *
- * @dev:	Device to update
- * @xstart:	X start position in pixels from the left
- * @ystart:	Y start position in pixels from the top
- * @xend:	X end position in pixels from the left
- * @yend:	Y end position  in pixels from the top
- * @clr:	Value to write
- * Return: 0 if OK, -ENOSYS if the display depth is not supported
- */
-static int console_truetype_erase(struct udevice *dev, int xstart, int ystart,
-				  int xend, int yend, int clr)
-{
-	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
-	void *start, *line;
-	int pixels = xend - xstart;
-	int row, i, ret;
-
-	start = vid_priv->fb + ystart * vid_priv->line_length;
-	start += xstart * VNBYTES(vid_priv->bpix);
-	line = start;
-	for (row = ystart; row < yend; row++) {
-		switch (vid_priv->bpix) {
-#ifdef CONFIG_VIDEO_BPP8
-		case VIDEO_BPP8: {
-			uint8_t *dst = line;
-
-			for (i = 0; i < pixels; i++)
-				*dst++ = clr;
-			break;
-		}
-#endif
-#ifdef CONFIG_VIDEO_BPP16
-		case VIDEO_BPP16: {
-			uint16_t *dst = line;
-
-			for (i = 0; i < pixels; i++)
-				*dst++ = clr;
-			break;
-		}
-#endif
-#ifdef CONFIG_VIDEO_BPP32
-		case VIDEO_BPP32: {
-			uint32_t *dst = line;
-
-			for (i = 0; i < pixels; i++)
-				*dst++ = clr;
-			break;
-		}
-#endif
-		default:
-			return -ENOSYS;
-		}
-		line += vid_priv->line_length;
-	}
-	ret = vidconsole_sync_copy(dev, start, line);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-/**
  * console_truetype_backspace() - Handle a backspace operation
  *
  * This clears the previous character so that the console looks as if it had
@@ -482,9 +449,9 @@
 	else
 		xend = vid_priv->xsize;
 
-	console_truetype_erase(dev, VID_TO_PIXEL(pos->xpos_frac), pos->ypos,
-			       xend, pos->ypos + vc_priv->y_charsize,
-			       vid_priv->colour_bg);
+	video_fill_part(vid_dev, VID_TO_PIXEL(pos->xpos_frac), pos->ypos,
+			xend, pos->ypos + vc_priv->y_charsize,
+			vid_priv->colour_bg);
 
 	/* Move the cursor back to where it was when we pushed this record */
 	vc_priv->xcur_frac = pos->xpos_frac;
@@ -680,8 +647,8 @@
 	vc_priv->tab_width_frac = VID_TO_POS(met->font_size) * 8 / 2;
 }
 
-static int truetype_select_font(struct udevice *dev, const char *name,
-				uint size)
+static int get_metrics(struct udevice *dev, const char *name, uint size,
+		       struct console_tt_metrics **metp)
 {
 	struct console_tt_priv *priv = dev_get_priv(dev);
 	struct console_tt_metrics *met;
@@ -719,11 +686,70 @@
 		met = priv->metrics;
 	}
 
+	*metp = met;
+
+	return 0;
+}
+
+static int truetype_select_font(struct udevice *dev, const char *name,
+				uint size)
+{
+	struct console_tt_metrics *met;
+	int ret;
+
+	ret = get_metrics(dev, name, size, &met);
+	if (ret)
+		return log_msg_ret("sel", ret);
+
 	select_metrics(dev, met);
 
 	return 0;
 }
 
+int truetype_measure(struct udevice *dev, const char *name, uint size,
+		     const char *text, struct vidconsole_bbox *bbox)
+{
+	struct console_tt_metrics *met;
+	stbtt_fontinfo *font;
+	int lsb, advance;
+	const char *s;
+	int width;
+	int last;
+	int ret;
+
+	ret = get_metrics(dev, name, size, &met);
+	if (ret)
+		return log_msg_ret("sel", ret);
+
+	bbox->valid = false;
+	if (!*text)
+		return 0;
+
+	font = &met->font;
+	width = 0;
+	for (last = 0, s = text; *s; s++) {
+		int ch = *s;
+
+		/* Used kerning to fine-tune the position of this character */
+		if (last)
+			width += stbtt_GetCodepointKernAdvance(font, last, ch);
+
+		/* First get some basic metrics about this character */
+		stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
+
+		width += advance;
+		last = ch;
+	}
+
+	bbox->valid = true;
+	bbox->x0 = 0;
+	bbox->y0 = 0;
+	bbox->x1 = tt_ceil((double)width * met->scale);
+	bbox->y1 = met->font_size;
+
+	return 0;
+}
+
 const char *console_truetype_get_font_size(struct udevice *dev, uint *sizep)
 {
 	struct console_tt_priv *priv = dev_get_priv(dev);
@@ -775,6 +801,7 @@
 	.get_font	= console_truetype_get_font,
 	.get_font_size	= console_truetype_get_font_size,
 	.select_font	= truetype_select_font,
+	.measure	= truetype_measure,
 };
 
 U_BOOT_DRIVER(vidconsole_truetype) = {
diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c
index 92e388a..22fef7e 100644
--- a/drivers/video/dw_mipi_dsi.c
+++ b/drivers/video/dw_mipi_dsi.c
@@ -538,9 +538,9 @@
 		break;
 	}
 
-	if (device->mode_flags & DISPLAY_FLAGS_VSYNC_HIGH)
+	if (timings->flags & DISPLAY_FLAGS_VSYNC_LOW)
 		val |= VSYNC_ACTIVE_LOW;
-	if (device->mode_flags & DISPLAY_FLAGS_HSYNC_HIGH)
+	if (timings->flags & DISPLAY_FLAGS_HSYNC_LOW)
 		val |= HSYNC_ACTIVE_LOW;
 
 	dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel));
diff --git a/drivers/video/himax-hx8394.c b/drivers/video/himax-hx8394.c
new file mode 100644
index 0000000..63637b4
--- /dev/null
+++ b/drivers/video/himax-hx8394.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Ondrej Jirman <megi@xff.cz>
+ */
+#include <common.h>
+#include <backlight.h>
+#include <dm.h>
+#include <mipi_dsi.h>
+#include <panel.h>
+#include <asm/gpio.h>
+#include <dm/device_compat.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+
+struct hx8394_panel_priv {
+	struct udevice *reg_vcc;
+	struct udevice *reg_iovcc;
+	struct gpio_desc reset;
+	struct udevice *backlight;
+};
+
+static const struct display_timing default_timing = {
+	.pixelclock.typ		= 74250000,
+	.hactive.typ		= 720,
+	.hfront_porch.typ	= 40,
+	.hback_porch.typ	= 40,
+	.hsync_len.typ		= 46,
+	.vactive.typ		= 1440,
+	.vfront_porch.typ	= 7,
+	.vback_porch.typ	= 9,
+	.vsync_len.typ		= 7,
+	.flags			= DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
+};
+
+#define dsi_dcs_write_seq(device, seq...) do {					\
+		static const u8 d[] = { seq };					\
+		int ret;							\
+		ret = mipi_dsi_dcs_write_buffer(device, d, ARRAY_SIZE(d));	\
+		if (ret < 0)							\
+			return ret;						\
+	} while (0)
+
+static int hx8394_init_sequence(struct udevice *dev)
+{
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+	struct mipi_dsi_device *device = plat->device;
+	int ret;
+
+	dsi_dcs_write_seq(device, 0xb9, 0xff, 0x83, 0x94);
+	dsi_dcs_write_seq(device, 0xb1, 0x48, 0x11, 0x71, 0x09, 0x32, 0x24,
+			  0x71, 0x31, 0x55, 0x30);
+	dsi_dcs_write_seq(device, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
+	dsi_dcs_write_seq(device, 0xb2, 0x00, 0x80, 0x78, 0x0c, 0x07);
+	dsi_dcs_write_seq(device, 0xb4, 0x12, 0x63, 0x12, 0x63, 0x12, 0x63,
+			  0x01, 0x0c, 0x7c, 0x55, 0x00, 0x3f, 0x12, 0x6b, 0x12,
+			  0x6b, 0x12, 0x6b, 0x01, 0x0c, 0x7c);
+	dsi_dcs_write_seq(device, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c,
+			  0x00, 0x00, 0x32, 0x10, 0x09, 0x00, 0x09, 0x32, 0x15,
+			  0xad, 0x05, 0xad, 0x32, 0x00, 0x00, 0x00, 0x00, 0x37,
+			  0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00, 0x00, 0x0c, 0x40);
+	dsi_dcs_write_seq(device, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b,
+			  0x1a, 0x1a, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+			  0x07, 0x20, 0x21, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+			  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x24, 0x25, 0x18,
+			  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+			  0x18, 0x18);
+	dsi_dcs_write_seq(device, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b,
+			  0x1a, 0x1a, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
+			  0x00, 0x25, 0x24, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+			  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x21, 0x20, 0x18,
+			  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+			  0x18, 0x18);
+	dsi_dcs_write_seq(device, 0xe0, 0x00, 0x04, 0x0c, 0x12, 0x14, 0x18,
+			  0x1a, 0x18, 0x31, 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b,
+			  0x70, 0x7f, 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49,
+			  0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00, 0x04, 0x0c, 0x11,
+			  0x13, 0x17, 0x1a, 0x18, 0x31, 0x3f, 0x4d, 0x4c, 0x54,
+			  0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, 0x99, 0x4a,
+			  0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f);
+	dsi_dcs_write_seq(device, 0xcc, 0x0b);
+	dsi_dcs_write_seq(device, 0xc0, 0x1f, 0x31);
+	dsi_dcs_write_seq(device, 0xb6, 0x7d, 0x7d);
+	dsi_dcs_write_seq(device, 0xd4, 0x02);
+	dsi_dcs_write_seq(device, 0xbd, 0x01);
+	dsi_dcs_write_seq(device, 0xb1, 0x00);
+	dsi_dcs_write_seq(device, 0xbd, 0x00);
+	dsi_dcs_write_seq(device, 0xc6, 0xed);
+
+	ret = mipi_dsi_dcs_exit_sleep_mode(device);
+	if (ret)
+		return ret;
+
+	/* Panel is operational 120 msec after reset */
+	mdelay(120);
+
+	ret = mipi_dsi_dcs_set_display_on(device);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int hx8394_panel_enable_backlight(struct udevice *dev)
+{
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+	struct mipi_dsi_device *device = plat->device;
+	struct hx8394_panel_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = mipi_dsi_attach(device);
+	if (ret < 0) {
+		printf("mipi_dsi_attach failed %d\n", ret);
+		return ret;
+	}
+
+	ret = hx8394_init_sequence(dev);
+	if (ret) {
+		printf("hx8394_init_sequence failed %d\n", ret);
+		return ret;
+	}
+
+	if (priv->backlight) {
+		ret = backlight_enable(priv->backlight);
+		if (ret) {
+			printf("backlight enabled failed %d\n", ret);
+			return ret;
+		}
+
+		backlight_set_brightness(priv->backlight, 60);
+	}
+
+	mdelay(10);
+
+	return 0;
+}
+
+static int hx8394_panel_get_display_timing(struct udevice *dev,
+					   struct display_timing *timings)
+{
+	memcpy(timings, &default_timing, sizeof(*timings));
+
+	return 0;
+}
+
+static int hx8394_panel_of_to_plat(struct udevice *dev)
+{
+	struct hx8394_panel_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
+		ret =  device_get_supply_regulator(dev, "vcc-supply",
+						   &priv->reg_vcc);
+		if (ret && ret != -ENOENT) {
+			dev_err(dev, "Warning: cannot get vcc supply\n");
+			return ret;
+		}
+
+		ret =  device_get_supply_regulator(dev, "iovcc-supply",
+						   &priv->reg_iovcc);
+		if (ret && ret != -ENOENT) {
+			dev_err(dev, "Warning: cannot get iovcc supply\n");
+			return ret;
+		}
+	}
+
+	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight", &priv->backlight);
+	if (ret)
+		dev_warn(dev, "failed to get backlight\n");
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset,
+				   GPIOD_IS_OUT);
+	if (ret) {
+		dev_err(dev, "warning: cannot get reset GPIO (%d)\n", ret);
+		if (ret != -ENOENT)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int hx8394_panel_probe(struct udevice *dev)
+{
+	struct hx8394_panel_priv *priv = dev_get_priv(dev);
+	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
+	int ret;
+
+	dm_gpio_set_value(&priv->reset, true);
+
+	if (CONFIG_IS_ENABLED(DM_REGULATOR)) {
+		dev_dbg(dev, "enable vcc '%s'\n", priv->reg_vcc->name);
+		ret = regulator_set_enable(priv->reg_vcc, true);
+		if (ret)
+			return ret;
+
+		dev_dbg(dev, "enable iovcc '%s'\n", priv->reg_iovcc->name);
+		ret = regulator_set_enable(priv->reg_iovcc, true);
+		if (ret) {
+			regulator_set_enable(priv->reg_vcc, false);
+			return ret;
+		}
+	}
+
+	mdelay(5);
+	dm_gpio_set_value(&priv->reset, false);
+
+	mdelay(180);
+
+	/* fill characteristics of DSI data link */
+	plat->lanes = 4;
+	plat->format = MIPI_DSI_FMT_RGB888;
+	plat->mode_flags = MIPI_DSI_MODE_VIDEO |
+			   MIPI_DSI_MODE_VIDEO_BURST;
+
+	return 0;
+}
+
+static const struct panel_ops hx8394_panel_ops = {
+	.enable_backlight = hx8394_panel_enable_backlight,
+	.get_display_timing = hx8394_panel_get_display_timing,
+};
+
+static const struct udevice_id hx8394_panel_ids[] = {
+	{ .compatible = "hannstar,hsd060bhw4" },
+	{ }
+};
+
+U_BOOT_DRIVER(hx8394_panel) = {
+	.name		= "hx8394_panel",
+	.id		= UCLASS_PANEL,
+	.of_match	= hx8394_panel_ids,
+	.ops		= &hx8394_panel_ops,
+	.of_to_plat	= hx8394_panel_of_to_plat,
+	.probe		= hx8394_panel_probe,
+	.plat_auto	= sizeof(struct mipi_dsi_panel_plat),
+	.priv_auto	= sizeof(struct hx8394_panel_priv),
+};
diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index d7c0969..46c16a8 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -63,7 +63,7 @@
 	int ret;
 
 	if (priv->period_ns) {
-		duty_cycle = priv->period_ns * (priv->cur_level - priv->min_level) /
+		duty_cycle = (u64)priv->period_ns * (priv->cur_level - priv->min_level) /
 			(priv->max_level - priv->min_level);
 		ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
 				     duty_cycle);
diff --git a/drivers/video/rockchip/dw_mipi_dsi_rockchip.c b/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
index ca548a6..117c3db 100644
--- a/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
+++ b/drivers/video/rockchip/dw_mipi_dsi_rockchip.c
@@ -18,6 +18,7 @@
 #include <panel.h>
 #include <phy-mipi-dphy.h>
 #include <reset.h>
+#include <syscon.h>
 #include <video_bridge.h>
 #include <dm/device_compat.h>
 #include <dm/lists.h>
@@ -30,6 +31,9 @@
 #include <dm/device-internal.h>
 #include <linux/bitops.h>
 
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/hardware.h>
+
 #define USEC_PER_SEC	1000000L
 
 /*
@@ -197,6 +201,7 @@
 	struct mipi_dsi_device device;
 	void __iomem *base;
 	struct udevice *panel;
+	void __iomem *grf;
 
 	/* Optional external dphy */
 	struct phy phy;
@@ -344,7 +349,7 @@
 	struct dw_rockchip_dsi_priv *dsi = dev_get_priv(dev);
 	int ret, i, vco;
 
-	if (&dsi->phy) {
+	if (dsi->phy.dev) {
 		ret = generic_phy_configure(&dsi->phy, &dsi->phy_opts);
 		if (ret) {
 			dev_err(dsi->dsi_host,
@@ -460,7 +465,7 @@
 	dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
 			      BIT(5) | ns2bc(dsi, 100));
 
-	return ret;
+	return 0;
 }
 
 static void dsi_phy_post_set_mode(void *priv_data, unsigned long mode_flags)
@@ -505,7 +510,6 @@
 	unsigned int _prediv, best_prediv;
 	unsigned long _fbdiv, best_fbdiv;
 	unsigned long min_delta = ULONG_MAX;
-	unsigned int pllref_clk;
 
 	bpp = mipi_dsi_pixel_format_to_bpp(format);
 	if (bpp < 0) {
@@ -527,7 +531,7 @@
 	}
 
 	/* for external phy only the mipi_dphy_config is necessary */
-	if (&dsi->phy) {
+	if (dsi->phy.dev) {
 		phy_mipi_dphy_get_default_config(timings->pixelclock.typ  * 10 / 8,
 						 bpp, lanes,
 						 &dsi->phy_opts);
@@ -537,7 +541,7 @@
 		return 0;
 	}
 
-	pllref_clk = clk_get_rate(dsi->ref);
+	fin = clk_get_rate(dsi->ref);
 	fout = target_mbps * USEC_PER_SEC;
 
 	/* constraint: 5Mhz <= Fref / N <= 40MHz */
@@ -753,16 +757,13 @@
 static void dw_mipi_dsi_rockchip_config(struct dw_rockchip_dsi_priv *dsi)
 {
 	if (dsi->cdata->lanecfg1_grf_reg)
-		dsi_write(dsi, dsi->cdata->lanecfg1_grf_reg,
-			  dsi->cdata->lanecfg1);
+		rk_setreg(dsi->grf + dsi->cdata->lanecfg1_grf_reg, dsi->cdata->lanecfg1);
 
 	if (dsi->cdata->lanecfg2_grf_reg)
-		dsi_write(dsi, dsi->cdata->lanecfg2_grf_reg,
-			  dsi->cdata->lanecfg2);
+		rk_setreg(dsi->grf + dsi->cdata->lanecfg2_grf_reg, dsi->cdata->lanecfg2);
 
 	if (dsi->cdata->enable_grf_reg)
-		dsi_write(dsi, dsi->cdata->enable_grf_reg,
-			  dsi->cdata->enable);
+		rk_setreg(dsi->grf + dsi->cdata->enable_grf_reg, dsi->cdata->enable);
 }
 
 static int dw_mipi_dsi_rockchip_bind(struct udevice *dev)
@@ -795,6 +796,8 @@
 		return -EINVAL;
 	}
 
+	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+
 	i = 0;
 	while (cdata[i].reg) {
 		if (cdata[i].reg == (fdt_addr_t)priv->base) {
@@ -815,25 +818,27 @@
 	 * NULL if it's not initialized.
 	 */
 	ret = generic_phy_get_by_name(dev, "dphy", &priv->phy);
-	if ((ret) && (ret != -ENODEV)) {
+	if (ret && ret != -ENODATA) {
 		dev_err(dev, "failed to get mipi dphy: %d\n", ret);
-		return -EINVAL;
+		return ret;
 	}
 
 	priv->pclk = devm_clk_get(dev, "pclk");
 	if (IS_ERR(priv->pclk)) {
+		ret = PTR_ERR(priv->pclk);
 		dev_err(dev, "peripheral clock get error %d\n", ret);
 		return ret;
 	}
 
 	/* Get a ref clock only if not using an external phy. */
-	if (&priv->phy) {
+	if (priv->phy.dev) {
 		dev_dbg(dev, "setting priv->ref to NULL\n");
 		priv->ref = NULL;
 
 	} else {
 		priv->ref = devm_clk_get(dev, "ref");
-		if (ret) {
+		if (IS_ERR(priv->ref)) {
+			ret = PTR_ERR(priv->ref);
 			dev_err(dev, "pll reference clock get error %d\n", ret);
 			return ret;
 		}
@@ -841,7 +846,8 @@
 
 	priv->rst = devm_reset_control_get_by_index(device->dev, 0);
 	if (IS_ERR(priv->rst)) {
-		dev_err(dev, "missing dsi hardware reset\n");
+		ret = PTR_ERR(priv->rst);
+		dev_err(dev, "missing dsi hardware reset %d\n", ret);
 		return ret;
 	}
 
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
index dab9902..c514e2a 100644
--- a/drivers/video/rockchip/rk_vop.c
+++ b/drivers/video/rockchip/rk_vop.c
@@ -432,7 +432,7 @@
 	ret = reset_assert(&ahb_rst);
 	if (ret) {
 		dev_err(dev, "failed to assert ahb reset (ret=%d)\n", ret);
-	return ret;
+		return ret;
 	}
 	udelay(20);
 
diff --git a/drivers/video/stb_truetype.h b/drivers/video/stb_truetype.h
index 438bfce..c6973bb 100644
--- a/drivers/video/stb_truetype.h
+++ b/drivers/video/stb_truetype.h
@@ -1,11 +1,21 @@
-// stb_truetype.h - v1.08 - public domain
-// authored from 2009-2015 by Sean Barrett / RAD Game Tools
+// stb_truetype.h - v1.26 - public domain
+// authored from 2009-2021 by Sean Barrett / RAD Game Tools
+//
+// =======================================================================
+//
+//    NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES
+//
+// This library does no range checking of the offsets found in the file,
+// meaning an attacker can use it to read arbitrary memory.
+//
+// =======================================================================
 //
 //   This library processes TrueType files:
 //        parse files
 //        extract glyph metrics
 //        extract glyph shapes
 //        render glyphs to one-channel bitmaps with antialiasing (box filter)
+//        render glyphs to one-channel SDF bitmaps (signed-distance field/function)
 //
 //   Todo:
 //        non-MS cmaps
@@ -20,58 +30,68 @@
 //
 //   Mikko Mononen: compound shape support, more cmap formats
 //   Tor Andersson: kerning, subpixel rendering
-//
-//   Bug/warning reports/fixes:
-//       "Zer" on mollyrocket (with fix)
-//       Cass Everitt
-//       stoiko (Haemimont Games)
-//       Brian Hook 
-//       Walter van Niftrik
-//       David Gow
-//       David Given
-//       Ivan-Assen Ivanov
-//       Anthony Pesch
-//       Johan Duparc
-//       Hou Qiming
-//       Fabian "ryg" Giesen
-//       Martins Mozeiko
-//       Cap Petschulat
-//       Omar Cornut
-//       github:aloucks
-//       Peter LaValle
-//       Sergey Popov
-//       Giumo X. Clanjor
-//       Higor Euripedes
+//   Dougall Johnson: OpenType / Type 2 font handling
+//   Daniel Ribeiro Maciel: basic GPOS-based kerning
 //
 //   Misc other:
 //       Ryan Gordon
+//       Simon Glass
+//       github:IntellectualKitty
+//       Imanol Celaya
+//       Daniel Ribeiro Maciel
+//
+//   Bug/warning reports/fixes:
+//       "Zer" on mollyrocket       Fabian "ryg" Giesen   github:NiLuJe
+//       Cass Everitt               Martins Mozeiko       github:aloucks
+//       stoiko (Haemimont Games)   Cap Petschulat        github:oyvindjam
+//       Brian Hook                 Omar Cornut           github:vassvik
+//       Walter van Niftrik         Ryan Griege
+//       David Gow                  Peter LaValle
+//       David Given                Sergey Popov
+//       Ivan-Assen Ivanov          Giumo X. Clanjor
+//       Anthony Pesch              Higor Euripedes
+//       Johan Duparc               Thomas Fields
+//       Hou Qiming                 Derek Vinyard
+//       Rob Loach                  Cort Stratton
+//       Kenney Phillis Jr.         Brian Costabile
+//       Ken Voskuil (kaesve)
 //
 // VERSION HISTORY
 //
+//   1.26 (2021-08-28) fix broken rasterizer
+//   1.25 (2021-07-11) many fixes
+//   1.24 (2020-02-05) fix warning
+//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
+//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
+//   1.21 (2019-02-25) fix warning
+//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
+//   1.19 (2018-02-11) GPOS kerning, STBTT_fmod
+//   1.18 (2018-01-29) add missing function
+//   1.17 (2017-07-23) make more arguments const; doc fix
+//   1.16 (2017-07-12) SDF support
+//   1.15 (2017-03-03) make more arguments const
+//   1.14 (2017-01-16) num-fonts-in-TTC function
+//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
+//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
+//   1.11 (2016-04-02) fix unused-variable warning
+//   1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef
+//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
 //   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
 //   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
 //                     variant PackFontRanges to pack and render in separate phases;
 //                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
 //                     fixed an assert() bug in the new rasterizer
 //                     replace assert() with STBTT_assert() in new rasterizer
-//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)
-//                     also more precise AA rasterizer, except if shapes overlap
-//                     remove need for STBTT_sort
-//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC
-//   1.04 (2015-04-15) typo in example
-//   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes
 //
 //   Full history can be found at the end of this file.
 //
 // LICENSE
 //
-//   This software is in the public domain. Where that dedication is not
-//   recognized, you are granted a perpetual, irrevocable license to copy,
-//   distribute, and modify this file as you see fit.
+//   See end of file for license information.
 //
 // USAGE
 //
-//   Include this file in whatever places neeed to refer to it. In ONE C/C++
+//   Include this file in whatever places need to refer to it. In ONE C/C++
 //   file, write:
 //      #define STB_TRUETYPE_IMPLEMENTATION
 //   before the #include of this file. This expands out the actual
@@ -87,14 +107,15 @@
 //   Improved 3D API (more shippable):
 //           #include "stb_rect_pack.h"           -- optional, but you really want it
 //           stbtt_PackBegin()
-//           stbtt_PackSetOversample()            -- for improved quality on small fonts
+//           stbtt_PackSetOversampling()          -- for improved quality on small fonts
 //           stbtt_PackFontRanges()               -- pack and renders
 //           stbtt_PackEnd()
 //           stbtt_GetPackedQuad()
 //
 //   "Load" a font file from a memory buffer (you have to keep the buffer loaded)
 //           stbtt_InitFont()
-//           stbtt_GetFontOffsetForIndex()        -- use for TTC font collections
+//           stbtt_GetFontOffsetForIndex()        -- indexing for TTC font collections
+//           stbtt_GetNumberOfFonts()             -- number of fonts for TTC font collections
 //
 //   Render a unicode codepoint to a bitmap
 //           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap
@@ -104,6 +125,7 @@
 //   Character advance/positioning
 //           stbtt_GetCodepointHMetrics()
 //           stbtt_GetFontVMetrics()
+//           stbtt_GetFontVMetricsOS2()
 //           stbtt_GetCodepointKernAdvance()
 //
 //   Starting with version 1.06, the rasterizer was replaced with a new,
@@ -159,7 +181,7 @@
 //         measurement for describing font size, defined as 72 points per inch.
 //         stb_truetype provides a point API for compatibility. However, true
 //         "per inch" conventions don't make much sense on computer displays
-//         since they different monitors have different number of pixels per
+//         since different monitors have different number of pixels per
 //         inch. For example, Windows traditionally uses a convention that
 //         there are 96 pixels per inch, thus making 'inch' measurements have
 //         nothing to do with inches, and thus effectively defining a point to
@@ -169,6 +191,39 @@
 //         for non-commercial fonts, thus making fonts scaled in points
 //         according to the TrueType spec incoherently sized in practice.
 //
+// DETAILED USAGE:
+//
+//  Scale:
+//    Select how high you want the font to be, in points or pixels.
+//    Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute
+//    a scale factor SF that will be used by all other functions.
+//
+//  Baseline:
+//    You need to select a y-coordinate that is the baseline of where
+//    your text will appear. Call GetFontBoundingBox to get the baseline-relative
+//    bounding box for all characters. SF*-y0 will be the distance in pixels
+//    that the worst-case character could extend above the baseline, so if
+//    you want the top edge of characters to appear at the top of the
+//    screen where y=0, then you would set the baseline to SF*-y0.
+//
+//  Current point:
+//    Set the current point where the first character will appear. The
+//    first character could extend left of the current point; this is font
+//    dependent. You can either choose a current point that is the leftmost
+//    point and hope, or add some padding, or check the bounding box or
+//    left-side-bearing of the first character to be displayed and set
+//    the current point based on that.
+//
+//  Displaying a character:
+//    Compute the bounding box of the character. It will contain signed values
+//    relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,
+//    then the character should be displayed in the rectangle from
+//    <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).
+//
+//  Advancing for the next character:
+//    Call GlyphHMetrics, and compute 'current_point += SF * advance'.
+//
+//
 // ADVANCED USAGE
 //
 //   Quality:
@@ -202,19 +257,6 @@
 //   given file is in a general way. I provide an API for this, but I don't
 //   recommend it.
 //
-//
-// SOURCE STATISTICS (based on v0.6c, 2050 LOC)
-//
-//   Documentation & header file        520 LOC  \___ 660 LOC documentation
-//   Sample code                        140 LOC  /
-//   Truetype parsing                   620 LOC  ---- 620 LOC TrueType
-//   Software rasterization             240 LOC  \                           .
-//   Curve tesselation                  120 LOC   \__ 550 LOC Bitmap creation
-//   Bitmap management                  100 LOC   /
-//   Baked bitmap interface              70 LOC  /
-//   Font name matching & access        150 LOC  ---- 150 
-//   C runtime library abstraction       60 LOC  ----  60
-//
 //
 // PERFORMANCE MEASUREMENTS FOR 1.06:
 //
@@ -230,8 +272,8 @@
 ////  SAMPLE PROGRAMS
 ////
 //
-//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
-//
+//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.
+//  See "tests/truetype_demo_win32.c" for a complete version.
 #if 0
 #define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation
 #include "stb_truetype.h"
@@ -257,6 +299,8 @@
 void my_stbtt_print(float x, float y, char *text)
 {
    // assume orthographic projection with units = screen pixels, origin at top left
+   glEnable(GL_BLEND);
+   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, ftex);
    glBegin(GL_QUADS);
@@ -264,10 +308,10 @@
       if (*text >= 32 && *text < 128) {
          stbtt_aligned_quad q;
          stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
-         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
-         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
-         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
-         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
+         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
+         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
+         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
+         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
       }
       ++text;
    }
@@ -305,7 +349,7 @@
    }
    return 0;
 }
-#endif 
+#endif
 //
 // Output:
 //
@@ -319,9 +363,9 @@
 //  :@@.  M@M
 //   @@@o@@@@
 //   :M@@V:@@.
-//  
+//
 //////////////////////////////////////////////////////////////////////////////
-// 
+//
 // Complete program: print "Hello World!" banner, with bugs
 //
 #if 0
@@ -375,7 +419,8 @@
 ////   INTEGRATION WITH YOUR CODEBASE
 ////
 ////   The following sections allow you to supply alternate definitions
-////   of C library functions used by stb_truetype.
+////   of C library functions used by stb_truetype, e.g. if you don't
+////   link with the C runtime library.
 
 #ifdef STB_TRUETYPE_IMPLEMENTATION
    // #define your own (u)stbtt_int8/16/32 before including to override this
@@ -391,7 +436,7 @@
    typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
    typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
 
-   // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
+   // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
    #ifndef STBTT_ifloor
    #include <math.h>
    #define STBTT_ifloor(x)   ((int) floor(x))
@@ -401,8 +446,20 @@
    #ifndef STBTT_sqrt
    #include <math.h>
    #define STBTT_sqrt(x)      sqrt(x)
+   #define STBTT_pow(x,y)     pow(x,y)
    #endif
 
+   #ifndef STBTT_fmod
+   #include <math.h>
+   #define STBTT_fmod(x,y)    fmod(x,y)
+   #endif
+
+   #ifndef STBTT_cos
+   #include <math.h>
+   #define STBTT_cos(x)       cos(x)
+   #define STBTT_acos(x)      acos(x)
+   #endif
+
    #ifndef STBTT_fabs
    #include <math.h>
    #define STBTT_fabs(x)      fabs(x)
@@ -452,6 +509,14 @@
 extern "C" {
 #endif
 
+// private structure
+typedef struct
+{
+   unsigned char *data;
+   int cursor;
+   int size;
+} stbtt__buf;
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // TEXTURE BAKING API
@@ -481,7 +546,7 @@
    float x1,y1,s1,t1; // bottom-right
 } stbtt_aligned_quad;
 
-STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph,  // same data as above
+STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  // same data as above
                                int char_index,             // character to display
                                float *xpos, float *ypos,   // pointers to current position in screen pixel space
                                stbtt_aligned_quad *q,      // output: quad to draw
@@ -496,6 +561,9 @@
 //
 // It's inefficient; you might want to c&p it and optimize it.
 
+STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
+// Query the font vertical metrics without having to create a font first.
+
 
 //////////////////////////////////////////////////////////////////////////////
 //
@@ -520,7 +588,7 @@
 STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
 // Initializes a packing context stored in the passed-in stbtt_pack_context.
 // Future calls using this context will pack characters into the bitmap passed
-// in here: a 1-channel bitmap that is weight x height. stride_in_bytes is
+// in here: a 1-channel bitmap that is width * height. stride_in_bytes is
 // the distance from one row to the next (or 0 to mean they are packed tightly
 // together). "padding" is the amount of padding to leave between each
 // character (normally you want '1' for bitmaps you'll use as textures with
@@ -533,7 +601,7 @@
 
 #define STBTT_POINT_SIZE(x)   (-(x))
 
-STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
+STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
                                 int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
 // Creates character bitmaps from the font_index'th font found in fontdata (use
 // font_index=0 if you don't know what that is). It creates num_chars_in_range
@@ -558,7 +626,7 @@
    unsigned char h_oversample, v_oversample; // don't set these, they're used internally
 } stbtt_pack_range;
 
-STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
+STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
 // Creates character bitmaps from multiple ranges of characters stored in
 // ranges. This will usually create a better-packed bitmap than multiple
 // calls to stbtt_PackFontRange. Note that you can call this multiple
@@ -580,19 +648,25 @@
 // To use with PackFontRangesGather etc., you must set it before calls
 // call to PackFontRangesGatherRects.
 
-STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph,  // same data as above
+STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
+// If skip != 0, this tells stb_truetype to skip any codepoints for which
+// there is no corresponding glyph. If skip=0, which is the default, then
+// codepoints without a glyph recived the font's "missing character" glyph,
+// typically an empty box by convention.
+
+STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  // same data as above
                                int char_index,             // character to display
                                float *xpos, float *ypos,   // pointers to current position in screen pixel space
                                stbtt_aligned_quad *q,      // output: quad to draw
                                int align_to_integer);
 
-STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
+STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
 STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
-STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
+STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
 // Calling these functions in sequence is roughly equivalent to calling
 // stbtt_PackFontRanges(). If you more control over the packing of multiple
 // fonts, or if you want to pack custom data into a font texture, take a look
-// at the source to of stbtt_PackFontRanges() and create a custom version 
+// at the source to of stbtt_PackFontRanges() and create a custom version
 // using these functions, e.g. call GatherRects multiple times,
 // building up a single array of rects, then call PackRects once,
 // then call RenderIntoRects repeatedly. This may result in a
@@ -608,6 +682,7 @@
    int   height;
    int   stride_in_bytes;
    int   padding;
+   int   skip_missing;
    unsigned int   h_oversample, v_oversample;
    unsigned char *pixels;
    void  *nodes;
@@ -619,18 +694,23 @@
 //
 //
 
+STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
+// This function will determine the number of fonts in a font file.  TrueType
+// collection (.ttc) files may contain multiple fonts, while TrueType font
+// (.ttf) files only contain one font. The number of fonts can be used for
+// indexing with the previous function where the index is between zero and one
+// less than the total fonts. If an error occurs, -1 is returned.
+
 STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
 // Each .ttf/.ttc file may have more than one font. Each font has a sequential
 // index number starting from 0. Call this function to get the font offset for
 // a given index; it returns -1 if the index is out of range. A regular .ttf
 // file will only define one font and it always be at offset 0, so it will
-// return '0' for index 0, and -1 for all other indices. You can just skip
-// this step if you know it's that kind of font.
+// return '0' for index 0, and -1 for all other indices.
 
-
-// The following structure is defined publically so you can declare one on
+// The following structure is defined publicly so you can declare one on
 // the stack or as a global or etc, but you should treat it as opaque.
-typedef struct stbtt_fontinfo
+struct stbtt_fontinfo
 {
    void           * userdata;
    unsigned char  * data;              // pointer to .ttf file
@@ -638,10 +718,17 @@
 
    int numGlyphs;                     // number of glyphs, needed for range checking
 
-   int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
+   int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf
    int index_map;                     // a cmap mapping for our chosen character encoding
    int indexToLocFormat;              // format needed to map from glyph index to glyph
-} stbtt_fontinfo;
+
+   stbtt__buf cff;                    // cff font data
+   stbtt__buf charstrings;            // the charstring index
+   stbtt__buf gsubrs;                 // global charstring subroutines index
+   stbtt__buf subrs;                  // private charstring subroutines index
+   stbtt__buf fontdicts;              // array of font dicts
+   stbtt__buf fdselect;               // map from glyph to fontdict
+};
 
 STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
 // Given an offset into the file that defines a font, this function builds
@@ -660,6 +747,7 @@
 // and you want a speed-up, call this function with the character you're
 // going to process, then use glyph-based functions instead of the
 // codepoint-based functions.
+// Returns 0 if the character codepoint is not defined in the font.
 
 
 //////////////////////////////////////////////////////////////////////////////
@@ -688,6 +776,12 @@
 //   these are expressed in unscaled coordinates, so you must multiply by
 //   the scale factor for a given size
 
+STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
+// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
+// table (specific to MS/Windows TTF files).
+//
+// Returns 1 on success (table present), 0 on failure.
+
 STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
 // the bounding box around all possible characters
 
@@ -707,6 +801,18 @@
 STBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
 // as above, but takes one or more glyph indices for greater efficiency
 
+typedef struct stbtt_kerningentry
+{
+   int glyph1; // use stbtt_FindGlyphIndex
+   int glyph2;
+   int advance;
+} stbtt_kerningentry;
+
+STBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info);
+STBTT_DEF int  stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);
+// Retrieves a complete list of all of the kerning pairs provided by the font
+// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.
+// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)
 
 //////////////////////////////////////////////////////////////////////////////
 //
@@ -718,7 +824,8 @@
    enum {
       STBTT_vmove=1,
       STBTT_vline,
-      STBTT_vcurve
+      STBTT_vcurve,
+      STBTT_vcubic
    };
 #endif
 
@@ -727,7 +834,7 @@
    #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
    typedef struct
    {
-      stbtt_vertex_type x,y,cx,cy;
+      stbtt_vertex_type x,y,cx,cy,cx1,cy1;
       unsigned char type,padding;
    } stbtt_vertex;
 #endif
@@ -740,7 +847,7 @@
 // returns # of vertices and fills *vertices with the pointer to them
 //   these are expressed in "unscaled" coordinates
 //
-// The shape is a series of countours. Each one starts with
+// The shape is a series of contours. Each one starts with
 // a STBTT_moveto, then consists of a series of mixed
 // STBTT_lineto and STBTT_curveto segments. A lineto
 // draws a line from previous endpoint to its x,y; a curveto
@@ -750,6 +857,12 @@
 STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
 // frees the data allocated above
 
+STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
+STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
+STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
+// fills svg with the character's SVG data.
+// returns data size or 0 if SVG not found.
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // BITMAP RENDERING
@@ -781,6 +894,10 @@
 // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
 // shift for the character
 
+STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
+// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
+// is performed (see stbtt_PackSetOversampling)
+
 STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
 // get the bbox of the bitmap centered around the glyph origin; so the
 // bitmap width is ix1-ix0, height is iy1-iy0, and location to place
@@ -798,6 +915,7 @@
 STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
 STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
 STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
 STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
 STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
 
@@ -822,6 +940,64 @@
 
 //////////////////////////////////////////////////////////////////////////////
 //
+// Signed Distance Function (or Field) rendering
+
+STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
+// frees the SDF bitmap allocated below
+
+STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
+STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
+// These functions compute a discretized SDF field for a single character, suitable for storing
+// in a single-channel texture, sampling with bilinear filtering, and testing against
+// larger than some threshold to produce scalable fonts.
+//        info              --  the font
+//        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
+//        glyph/codepoint   --  the character to generate the SDF for
+//        padding           --  extra "pixels" around the character which are filled with the distance to the character (not 0),
+//                                 which allows effects like bit outlines
+//        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
+//        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
+//                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside
+//        width,height      --  output height & width of the SDF bitmap (including padding)
+//        xoff,yoff         --  output origin of the character
+//        return value      --  a 2D array of bytes 0..255, width*height in size
+//
+// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
+// optimal use of the limited 0..255 for your application, trading off precision
+// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
+//
+// Example:
+//      scale = stbtt_ScaleForPixelHeight(22)
+//      padding = 5
+//      onedge_value = 180
+//      pixel_dist_scale = 180/5.0 = 36.0
+//
+//      This will create an SDF bitmap in which the character is about 22 pixels
+//      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
+//      shape, sample the SDF at each pixel and fill the pixel if the SDF value
+//      is greater than or equal to 180/255. (You'll actually want to antialias,
+//      which is beyond the scope of this example.) Additionally, you can compute
+//      offset outlines (e.g. to stroke the character border inside & outside,
+//      or only outside). For example, to fill outside the character up to 3 SDF
+//      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
+//      choice of variables maps a range from 5 pixels outside the shape to
+//      2 pixels inside the shape to 0..255; this is intended primarily for apply
+//      outside effects only (the interior range is needed to allow proper
+//      antialiasing of the font at *smaller* sizes)
+//
+// The function computes the SDF analytically at each SDF pixel, not by e.g.
+// building a higher-res bitmap and approximating it. In theory the quality
+// should be as high as possible for an SDF of this size & representation, but
+// unclear if this is true in practice (perhaps building a higher-res bitmap
+// and computing from that can allow drop-out prevention).
+//
+// The algorithm has not been optimized at all, so expect it to be slow
+// if computing lots of characters or very large sizes.
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
 // Finding the right font...
 //
 // You should really just solve this offline, keep your own tables
@@ -943,6 +1119,158 @@
 #define STBTT_RASTERIZER_VERSION 2
 #endif
 
+#ifdef _MSC_VER
+#define STBTT__NOTUSED(v)  (void)(v)
+#else
+#define STBTT__NOTUSED(v)  (void)sizeof(v)
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+//
+// stbtt__buf helpers to parse data from file
+//
+
+static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
+{
+   if (b->cursor >= b->size)
+      return 0;
+   return b->data[b->cursor++];
+}
+
+static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
+{
+   if (b->cursor >= b->size)
+      return 0;
+   return b->data[b->cursor];
+}
+
+static void stbtt__buf_seek(stbtt__buf *b, int o)
+{
+   STBTT_assert(!(o > b->size || o < 0));
+   b->cursor = (o > b->size || o < 0) ? b->size : o;
+}
+
+static void stbtt__buf_skip(stbtt__buf *b, int o)
+{
+   stbtt__buf_seek(b, b->cursor + o);
+}
+
+static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
+{
+   stbtt_uint32 v = 0;
+   int i;
+   STBTT_assert(n >= 1 && n <= 4);
+   for (i = 0; i < n; i++)
+      v = (v << 8) | stbtt__buf_get8(b);
+   return v;
+}
+
+static stbtt__buf stbtt__new_buf(const void *p, size_t size)
+{
+   stbtt__buf r;
+   STBTT_assert(size < 0x40000000);
+   r.data = (stbtt_uint8*) p;
+   r.size = (int) size;
+   r.cursor = 0;
+   return r;
+}
+
+#define stbtt__buf_get16(b)  stbtt__buf_get((b), 2)
+#define stbtt__buf_get32(b)  stbtt__buf_get((b), 4)
+
+static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)
+{
+   stbtt__buf r = stbtt__new_buf(NULL, 0);
+   if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;
+   r.data = b->data + o;
+   r.size = s;
+   return r;
+}
+
+static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
+{
+   int count, start, offsize;
+   start = b->cursor;
+   count = stbtt__buf_get16(b);
+   if (count) {
+      offsize = stbtt__buf_get8(b);
+      STBTT_assert(offsize >= 1 && offsize <= 4);
+      stbtt__buf_skip(b, offsize * count);
+      stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
+   }
+   return stbtt__buf_range(b, start, b->cursor - start);
+}
+
+static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
+{
+   int b0 = stbtt__buf_get8(b);
+   if (b0 >= 32 && b0 <= 246)       return b0 - 139;
+   else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
+   else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
+   else if (b0 == 28)               return stbtt__buf_get16(b);
+   else if (b0 == 29)               return stbtt__buf_get32(b);
+   STBTT_assert(0);
+   return 0;
+}
+
+static void stbtt__cff_skip_operand(stbtt__buf *b) {
+   int v, b0 = stbtt__buf_peek8(b);
+   STBTT_assert(b0 >= 28);
+   if (b0 == 30) {
+      stbtt__buf_skip(b, 1);
+      while (b->cursor < b->size) {
+         v = stbtt__buf_get8(b);
+         if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
+            break;
+      }
+   } else {
+      stbtt__cff_int(b);
+   }
+}
+
+static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
+{
+   stbtt__buf_seek(b, 0);
+   while (b->cursor < b->size) {
+      int start = b->cursor, end, op;
+      while (stbtt__buf_peek8(b) >= 28)
+         stbtt__cff_skip_operand(b);
+      end = b->cursor;
+      op = stbtt__buf_get8(b);
+      if (op == 12)  op = stbtt__buf_get8(b) | 0x100;
+      if (op == key) return stbtt__buf_range(b, start, end-start);
+   }
+   return stbtt__buf_range(b, 0, 0);
+}
+
+static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)
+{
+   int i;
+   stbtt__buf operands = stbtt__dict_get(b, key);
+   for (i = 0; i < outcount && operands.cursor < operands.size; i++)
+      out[i] = stbtt__cff_int(&operands);
+}
+
+static int stbtt__cff_index_count(stbtt__buf *b)
+{
+   stbtt__buf_seek(b, 0);
+   return stbtt__buf_get16(b);
+}
+
+static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
+{
+   int count, offsize, start, end;
+   stbtt__buf_seek(&b, 0);
+   count = stbtt__buf_get16(&b);
+   offsize = stbtt__buf_get8(&b);
+   STBTT_assert(i >= 0 && i < count);
+   STBTT_assert(offsize >= 1 && offsize <= 4);
+   stbtt__buf_skip(&b, i*offsize);
+   start = stbtt__buf_get(&b, offsize);
+   end = stbtt__buf_get(&b, offsize);
+   return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
+}
+
 //////////////////////////////////////////////////////////////////////////
 //
 // accessors to parse data from file
@@ -955,32 +1283,22 @@
 #define ttCHAR(p)     (* (stbtt_int8 *) (p))
 #define ttFixed(p)    ttLONG(p)
 
-#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE)
-
-   #define ttUSHORT(p)   (* (stbtt_uint16 *) (p))
-   #define ttSHORT(p)    (* (stbtt_int16 *) (p))
-   #define ttULONG(p)    (* (stbtt_uint32 *) (p))
-   #define ttLONG(p)     (* (stbtt_int32 *) (p))
-
-#else
-
-   static stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; }
-   static stbtt_int16 ttSHORT(const stbtt_uint8 *p)   { return p[0]*256 + p[1]; }
-   static stbtt_uint32 ttULONG(const stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
-   static stbtt_int32 ttLONG(const stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
-
-#endif
+static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
+static stbtt_int16 ttSHORT(stbtt_uint8 *p)   { return p[0]*256 + p[1]; }
+static stbtt_uint32 ttULONG(stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
+static stbtt_int32 ttLONG(stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
 
 #define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
 #define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])
 
-static int stbtt__isfont(const stbtt_uint8 *font)
+static int stbtt__isfont(stbtt_uint8 *font)
 {
    // check the version number
    if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1
    if (stbtt_tag(font, "typ1"))   return 1; // TrueType with type 1 font -- we don't support this!
    if (stbtt_tag(font, "OTTO"))   return 1; // OpenType with CFF
    if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
+   if (stbtt_tag(font, "true"))   return 1; // Apple specification for TrueType fonts
    return 0;
 }
 
@@ -998,7 +1316,7 @@
    return 0;
 }
 
-STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index)
+static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)
 {
    // if it's just a font, there's only one valid index
    if (stbtt__isfont(font_collection))
@@ -1017,14 +1335,59 @@
    return -1;
 }
 
-STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart)
+static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)
 {
-   stbtt_uint8 *data = (stbtt_uint8 *) data2;
+   // if it's just a font, there's only one valid font
+   if (stbtt__isfont(font_collection))
+      return 1;
+
+   // check if it's a TTC
+   if (stbtt_tag(font_collection, "ttcf")) {
+      // version 1?
+      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
+         return ttLONG(font_collection+8);
+      }
+   }
+   return 0;
+}
+
+static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
+{
+   stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };
+   stbtt__buf pdict;
+   stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);
+   if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);
+   pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
+   stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
+   if (!subrsoff) return stbtt__new_buf(NULL, 0);
+   stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
+   return stbtt__cff_get_index(&cff);
+}
+
+// since most people won't use this, find this table the first time it's needed
+static int stbtt__get_svg(stbtt_fontinfo *info)
+{
+   stbtt_uint32 t;
+   if (info->svg < 0) {
+      t = stbtt__find_table(info->data, info->fontstart, "SVG ");
+      if (t) {
+         stbtt_uint32 offset = ttULONG(info->data + t + 2);
+         info->svg = t + offset;
+      } else {
+         info->svg = 0;
+      }
+   }
+   return info->svg;
+}
+
+static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
+{
    stbtt_uint32 cmap, t;
    stbtt_int32 i,numTables;
 
    info->data = data;
    info->fontstart = fontstart;
+   info->cff = stbtt__new_buf(NULL, 0);
 
    cmap = stbtt__find_table(data, fontstart, "cmap");       // required
    info->loca = stbtt__find_table(data, fontstart, "loca"); // required
@@ -1033,8 +1396,62 @@
    info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
    info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
    info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
-   if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)
+   info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required
+
+   if (!cmap || !info->head || !info->hhea || !info->hmtx)
       return 0;
+   if (info->glyf) {
+      // required for truetype
+      if (!info->loca) return 0;
+   } else {
+      // initialization for CFF / Type2 fonts (OTF)
+      stbtt__buf b, topdict, topdictidx;
+      stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
+      stbtt_uint32 cff;
+
+      cff = stbtt__find_table(data, fontstart, "CFF ");
+      if (!cff) return 0;
+
+      info->fontdicts = stbtt__new_buf(NULL, 0);
+      info->fdselect = stbtt__new_buf(NULL, 0);
+
+      // @TODO this should use size from table (not 512MB)
+      info->cff = stbtt__new_buf(data+cff, 512*1024*1024);
+      b = info->cff;
+
+      // read the header
+      stbtt__buf_skip(&b, 2);
+      stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
+
+      // @TODO the name INDEX could list multiple fonts,
+      // but we just use the first one.
+      stbtt__cff_get_index(&b);  // name INDEX
+      topdictidx = stbtt__cff_get_index(&b);
+      topdict = stbtt__cff_index_get(topdictidx, 0);
+      stbtt__cff_get_index(&b);  // string INDEX
+      info->gsubrs = stbtt__cff_get_index(&b);
+
+      stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
+      stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
+      stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
+      stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
+      info->subrs = stbtt__get_subrs(b, topdict);
+
+      // we only support Type 2 charstrings
+      if (cstype != 2) return 0;
+      if (charstrings == 0) return 0;
+
+      if (fdarrayoff) {
+         // looks like a CID font
+         if (!fdselectoff) return 0;
+         stbtt__buf_seek(&b, fdarrayoff);
+         info->fontdicts = stbtt__cff_get_index(&b);
+         info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
+      }
+
+      stbtt__buf_seek(&b, charstrings);
+      info->charstrings = stbtt__cff_get_index(&b);
+   }
 
    t = stbtt__find_table(data, fontstart, "maxp");
    if (t)
@@ -1042,6 +1459,8 @@
    else
       info->numGlyphs = 0xffff;
 
+   info->svg = -1;
+
    // find a cmap encoding table we understand *now* to avoid searching
    // later. (todo: could make this installable)
    // the same regardless of glyph.
@@ -1125,12 +1544,12 @@
       search += 2;
 
       {
-         stbtt_uint16 offset, start;
+         stbtt_uint16 offset, start, last;
          stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
 
-         STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
          start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
-         if (unicode_codepoint < start)
+         last = ttUSHORT(data + endCount + 2*item);
+         if (unicode_codepoint < start || unicode_codepoint > last)
             return 0;
 
          offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
@@ -1185,6 +1604,8 @@
 {
    int g1,g2;
 
+   STBTT_assert(!info->cff.size);
+
    if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
    if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format
 
@@ -1199,15 +1620,21 @@
    return g1==g2 ? -1 : g1; // if length is 0, return -1
 }
 
+static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
+
 STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
 {
-   int g = stbtt__GetGlyfOffset(info, glyph_index);
-   if (g < 0) return 0;
+   if (info->cff.size) {
+      stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
+   } else {
+      int g = stbtt__GetGlyfOffset(info, glyph_index);
+      if (g < 0) return 0;
 
-   if (x0) *x0 = ttSHORT(info->data + g + 2);
-   if (y0) *y0 = ttSHORT(info->data + g + 4);
-   if (x1) *x1 = ttSHORT(info->data + g + 6);
-   if (y1) *y1 = ttSHORT(info->data + g + 8);
+      if (x0) *x0 = ttSHORT(info->data + g + 2);
+      if (y0) *y0 = ttSHORT(info->data + g + 4);
+      if (x1) *x1 = ttSHORT(info->data + g + 6);
+      if (y1) *y1 = ttSHORT(info->data + g + 8);
+   }
    return 1;
 }
 
@@ -1219,7 +1646,10 @@
 STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
 {
    stbtt_int16 numberOfContours;
-   int g = stbtt__GetGlyfOffset(info, glyph_index);
+   int g;
+   if (info->cff.size)
+      return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;
+   g = stbtt__GetGlyfOffset(info, glyph_index);
    if (g < 0) return 1;
    numberOfContours = ttSHORT(info->data + g);
    return numberOfContours == 0;
@@ -1241,7 +1671,7 @@
    return num_vertices;
 }
 
-STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
 {
    stbtt_int16 numberOfContours;
    stbtt_uint8 *endPtsOfContours;
@@ -1337,7 +1767,7 @@
             if (i != 0)
                num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
 
-            // now start the new one               
+            // now start the new one
             start_off = !(flags & 1);
             if (start_off) {
                // if we start off with an off-curve point, then when we need to find a point on the curve
@@ -1379,7 +1809,7 @@
          }
       }
       num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
-   } else if (numberOfContours == -1) {
+   } else if (numberOfContours < 0) {
       // Compound shapes.
       int more = 1;
       stbtt_uint8 *comp = data + g + 10;
@@ -1390,7 +1820,7 @@
          int comp_num_verts = 0, i;
          stbtt_vertex *comp_verts = 0, *tmp = 0;
          float mtx[6] = {1,0,0,1,0,0}, m, n;
-         
+
          flags = ttSHORT(comp); comp+=2;
          gidx = ttSHORT(comp); comp+=2;
 
@@ -1420,7 +1850,7 @@
             mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
             mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
          }
-         
+
          // Find transformation scales.
          m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
          n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
@@ -1446,7 +1876,7 @@
                if (comp_verts) STBTT_free(comp_verts, info->userdata);
                return 0;
             }
-            if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
+            if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
             STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
             if (vertices) STBTT_free(vertices, info->userdata);
             vertices = tmp;
@@ -1456,9 +1886,6 @@
          // More components ?
          more = flags & (1<<5);
       }
-   } else if (numberOfContours < 0) {
-      // @TODO other compound variations?
-      STBTT_assert(0);
    } else {
       // numberOfCounters == 0, do nothing
    }
@@ -1467,6 +1894,414 @@
    return num_vertices;
 }
 
+typedef struct
+{
+   int bounds;
+   int started;
+   float first_x, first_y;
+   float x, y;
+   stbtt_int32 min_x, max_x, min_y, max_y;
+
+   stbtt_vertex *pvertices;
+   int num_vertices;
+} stbtt__csctx;
+
+#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}
+
+static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
+{
+   if (x > c->max_x || !c->started) c->max_x = x;
+   if (y > c->max_y || !c->started) c->max_y = y;
+   if (x < c->min_x || !c->started) c->min_x = x;
+   if (y < c->min_y || !c->started) c->min_y = y;
+   c->started = 1;
+}
+
+static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)
+{
+   if (c->bounds) {
+      stbtt__track_vertex(c, x, y);
+      if (type == STBTT_vcubic) {
+         stbtt__track_vertex(c, cx, cy);
+         stbtt__track_vertex(c, cx1, cy1);
+      }
+   } else {
+      stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
+      c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;
+      c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;
+   }
+   c->num_vertices++;
+}
+
+static void stbtt__csctx_close_shape(stbtt__csctx *ctx)
+{
+   if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)
+      stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
+{
+   stbtt__csctx_close_shape(ctx);
+   ctx->first_x = ctx->x = ctx->x + dx;
+   ctx->first_y = ctx->y = ctx->y + dy;
+   stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
+{
+   ctx->x += dx;
+   ctx->y += dy;
+   stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
+{
+   float cx1 = ctx->x + dx1;
+   float cy1 = ctx->y + dy1;
+   float cx2 = cx1 + dx2;
+   float cy2 = cy1 + dy2;
+   ctx->x = cx2 + dx3;
+   ctx->y = cy2 + dy3;
+   stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
+}
+
+static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
+{
+   int count = stbtt__cff_index_count(&idx);
+   int bias = 107;
+   if (count >= 33900)
+      bias = 32768;
+   else if (count >= 1240)
+      bias = 1131;
+   n += bias;
+   if (n < 0 || n >= count)
+      return stbtt__new_buf(NULL, 0);
+   return stbtt__cff_index_get(idx, n);
+}
+
+static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)
+{
+   stbtt__buf fdselect = info->fdselect;
+   int nranges, start, end, v, fmt, fdselector = -1, i;
+
+   stbtt__buf_seek(&fdselect, 0);
+   fmt = stbtt__buf_get8(&fdselect);
+   if (fmt == 0) {
+      // untested
+      stbtt__buf_skip(&fdselect, glyph_index);
+      fdselector = stbtt__buf_get8(&fdselect);
+   } else if (fmt == 3) {
+      nranges = stbtt__buf_get16(&fdselect);
+      start = stbtt__buf_get16(&fdselect);
+      for (i = 0; i < nranges; i++) {
+         v = stbtt__buf_get8(&fdselect);
+         end = stbtt__buf_get16(&fdselect);
+         if (glyph_index >= start && glyph_index < end) {
+            fdselector = v;
+            break;
+         }
+         start = end;
+      }
+   }
+   if (fdselector == -1) stbtt__new_buf(NULL, 0);
+   return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));
+}
+
+static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)
+{
+   int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
+   int has_subrs = 0, clear_stack;
+   float s[48];
+   stbtt__buf subr_stack[10], subrs = info->subrs, b;
+   float f;
+
+#define STBTT__CSERR(s) (0)
+
+   // this currently ignores the initial width value, which isn't needed if we have hmtx
+   b = stbtt__cff_index_get(info->charstrings, glyph_index);
+   while (b.cursor < b.size) {
+      i = 0;
+      clear_stack = 1;
+      b0 = stbtt__buf_get8(&b);
+      switch (b0) {
+      // @TODO implement hinting
+      case 0x13: // hintmask
+      case 0x14: // cntrmask
+         if (in_header)
+            maskbits += (sp / 2); // implicit "vstem"
+         in_header = 0;
+         stbtt__buf_skip(&b, (maskbits + 7) / 8);
+         break;
+
+      case 0x01: // hstem
+      case 0x03: // vstem
+      case 0x12: // hstemhm
+      case 0x17: // vstemhm
+         maskbits += (sp / 2);
+         break;
+
+      case 0x15: // rmoveto
+         in_header = 0;
+         if (sp < 2) return STBTT__CSERR("rmoveto stack");
+         stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
+         break;
+      case 0x04: // vmoveto
+         in_header = 0;
+         if (sp < 1) return STBTT__CSERR("vmoveto stack");
+         stbtt__csctx_rmove_to(c, 0, s[sp-1]);
+         break;
+      case 0x16: // hmoveto
+         in_header = 0;
+         if (sp < 1) return STBTT__CSERR("hmoveto stack");
+         stbtt__csctx_rmove_to(c, s[sp-1], 0);
+         break;
+
+      case 0x05: // rlineto
+         if (sp < 2) return STBTT__CSERR("rlineto stack");
+         for (; i + 1 < sp; i += 2)
+            stbtt__csctx_rline_to(c, s[i], s[i+1]);
+         break;
+
+      // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
+      // starting from a different place.
+
+      case 0x07: // vlineto
+         if (sp < 1) return STBTT__CSERR("vlineto stack");
+         goto vlineto;
+      case 0x06: // hlineto
+         if (sp < 1) return STBTT__CSERR("hlineto stack");
+         for (;;) {
+            if (i >= sp) break;
+            stbtt__csctx_rline_to(c, s[i], 0);
+            i++;
+      vlineto:
+            if (i >= sp) break;
+            stbtt__csctx_rline_to(c, 0, s[i]);
+            i++;
+         }
+         break;
+
+      case 0x1F: // hvcurveto
+         if (sp < 4) return STBTT__CSERR("hvcurveto stack");
+         goto hvcurveto;
+      case 0x1E: // vhcurveto
+         if (sp < 4) return STBTT__CSERR("vhcurveto stack");
+         for (;;) {
+            if (i + 3 >= sp) break;
+            stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);
+            i += 4;
+      hvcurveto:
+            if (i + 3 >= sp) break;
+            stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);
+            i += 4;
+         }
+         break;
+
+      case 0x08: // rrcurveto
+         if (sp < 6) return STBTT__CSERR("rcurveline stack");
+         for (; i + 5 < sp; i += 6)
+            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+         break;
+
+      case 0x18: // rcurveline
+         if (sp < 8) return STBTT__CSERR("rcurveline stack");
+         for (; i + 5 < sp - 2; i += 6)
+            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+         if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
+         stbtt__csctx_rline_to(c, s[i], s[i+1]);
+         break;
+
+      case 0x19: // rlinecurve
+         if (sp < 8) return STBTT__CSERR("rlinecurve stack");
+         for (; i + 1 < sp - 6; i += 2)
+            stbtt__csctx_rline_to(c, s[i], s[i+1]);
+         if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
+         stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+         break;
+
+      case 0x1A: // vvcurveto
+      case 0x1B: // hhcurveto
+         if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
+         f = 0.0;
+         if (sp & 1) { f = s[i]; i++; }
+         for (; i + 3 < sp; i += 4) {
+            if (b0 == 0x1B)
+               stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
+            else
+               stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
+            f = 0.0;
+         }
+         break;
+
+      case 0x0A: // callsubr
+         if (!has_subrs) {
+            if (info->fdselect.size)
+               subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
+            has_subrs = 1;
+         }
+         // FALLTHROUGH
+      case 0x1D: // callgsubr
+         if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
+         v = (int) s[--sp];
+         if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
+         subr_stack[subr_stack_height++] = b;
+         b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
+         if (b.size == 0) return STBTT__CSERR("subr not found");
+         b.cursor = 0;
+         clear_stack = 0;
+         break;
+
+      case 0x0B: // return
+         if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
+         b = subr_stack[--subr_stack_height];
+         clear_stack = 0;
+         break;
+
+      case 0x0E: // endchar
+         stbtt__csctx_close_shape(c);
+         return 1;
+
+      case 0x0C: { // two-byte escape
+         float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
+         float dx, dy;
+         int b1 = stbtt__buf_get8(&b);
+         switch (b1) {
+         // @TODO These "flex" implementations ignore the flex-depth and resolution,
+         // and always draw beziers.
+         case 0x22: // hflex
+            if (sp < 7) return STBTT__CSERR("hflex stack");
+            dx1 = s[0];
+            dx2 = s[1];
+            dy2 = s[2];
+            dx3 = s[3];
+            dx4 = s[4];
+            dx5 = s[5];
+            dx6 = s[6];
+            stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
+            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
+            break;
+
+         case 0x23: // flex
+            if (sp < 13) return STBTT__CSERR("flex stack");
+            dx1 = s[0];
+            dy1 = s[1];
+            dx2 = s[2];
+            dy2 = s[3];
+            dx3 = s[4];
+            dy3 = s[5];
+            dx4 = s[6];
+            dy4 = s[7];
+            dx5 = s[8];
+            dy5 = s[9];
+            dx6 = s[10];
+            dy6 = s[11];
+            //fd is s[12]
+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
+            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
+            break;
+
+         case 0x24: // hflex1
+            if (sp < 9) return STBTT__CSERR("hflex1 stack");
+            dx1 = s[0];
+            dy1 = s[1];
+            dx2 = s[2];
+            dy2 = s[3];
+            dx3 = s[4];
+            dx4 = s[5];
+            dx5 = s[6];
+            dy5 = s[7];
+            dx6 = s[8];
+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
+            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
+            break;
+
+         case 0x25: // flex1
+            if (sp < 11) return STBTT__CSERR("flex1 stack");
+            dx1 = s[0];
+            dy1 = s[1];
+            dx2 = s[2];
+            dy2 = s[3];
+            dx3 = s[4];
+            dy3 = s[5];
+            dx4 = s[6];
+            dy4 = s[7];
+            dx5 = s[8];
+            dy5 = s[9];
+            dx6 = dy6 = s[10];
+            dx = dx1+dx2+dx3+dx4+dx5;
+            dy = dy1+dy2+dy3+dy4+dy5;
+            if (STBTT_fabs(dx) > STBTT_fabs(dy))
+               dy6 = -dy;
+            else
+               dx6 = -dx;
+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
+            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
+            break;
+
+         default:
+            return STBTT__CSERR("unimplemented");
+         }
+      } break;
+
+      default:
+         if (b0 != 255 && b0 != 28 && b0 < 32)
+            return STBTT__CSERR("reserved operator");
+
+         // push immediate
+         if (b0 == 255) {
+            f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
+         } else {
+            stbtt__buf_skip(&b, -1);
+            f = (float)(stbtt_int16)stbtt__cff_int(&b);
+         }
+         if (sp >= 48) return STBTT__CSERR("push stack overflow");
+         s[sp++] = f;
+         clear_stack = 0;
+         break;
+      }
+      if (clear_stack) sp = 0;
+   }
+   return STBTT__CSERR("no endchar");
+
+#undef STBTT__CSERR
+}
+
+static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+   // runs the charstring twice, once to count and once to output (to avoid realloc)
+   stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);
+   stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);
+   if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
+      *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);
+      output_ctx.pvertices = *pvertices;
+      if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
+         STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);
+         return output_ctx.num_vertices;
+      }
+   }
+   *pvertices = NULL;
+   return 0;
+}
+
+static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
+{
+   stbtt__csctx c = STBTT__CSCTX_INIT(1);
+   int r = stbtt__run_charstring(info, glyph_index, &c);
+   if (x0)  *x0 = r ? c.min_x : 0;
+   if (y0)  *y0 = r ? c.min_y : 0;
+   if (x1)  *x1 = r ? c.max_x : 0;
+   if (y1)  *y1 = r ? c.max_y : 0;
+   return r ? c.num_vertices : 0;
+}
+
+STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+   if (!info->cff.size)
+      return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
+   else
+      return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
+}
+
 STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
 {
    stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
@@ -1477,41 +2312,316 @@
       if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
       if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
    }
+}
+
+STBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info)
+{
+   stbtt_uint8 *data = info->data + info->kern;
+
+   // we only look at the first table. it must be 'horizontal' and format 0.
+   if (!info->kern)
+      return 0;
+   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
+      return 0;
+   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
+      return 0;
+
+   return ttUSHORT(data+10);
+}
+
+STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)
+{
+   stbtt_uint8 *data = info->data + info->kern;
+   int k, length;
+
+   // we only look at the first table. it must be 'horizontal' and format 0.
+   if (!info->kern)
+      return 0;
+   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
+      return 0;
+   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
+      return 0;
+
+   length = ttUSHORT(data+10);
+   if (table_length < length)
+      length = table_length;
+
+   for (k = 0; k < length; k++)
+   {
+      table[k].glyph1 = ttUSHORT(data+18+(k*6));
+      table[k].glyph2 = ttUSHORT(data+20+(k*6));
+      table[k].advance = ttSHORT(data+22+(k*6));
+   }
+
+   return length;
+}
+
+static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
+{
+   stbtt_uint8 *data = info->data + info->kern;
+   stbtt_uint32 needle, straw;
+   int l, r, m;
+
+   // we only look at the first table. it must be 'horizontal' and format 0.
+   if (!info->kern)
+      return 0;
+   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
+      return 0;
+   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
+      return 0;
+
+   l = 0;
+   r = ttUSHORT(data+10) - 1;
+   needle = glyph1 << 16 | glyph2;
+   while (l <= r) {
+      m = (l + r) >> 1;
+      straw = ttULONG(data+18+(m*6)); // note: unaligned read
+      if (needle < straw)
+         r = m - 1;
+      else if (needle > straw)
+         l = m + 1;
+      else
+         return ttSHORT(data+22+(m*6));
+   }
+   return 0;
+}
+
+static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
+{
+   stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
+   switch (coverageFormat) {
+      case 1: {
+         stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
+
+         // Binary search.
+         stbtt_int32 l=0, r=glyphCount-1, m;
+         int straw, needle=glyph;
+         while (l <= r) {
+            stbtt_uint8 *glyphArray = coverageTable + 4;
+            stbtt_uint16 glyphID;
+            m = (l + r) >> 1;
+            glyphID = ttUSHORT(glyphArray + 2 * m);
+            straw = glyphID;
+            if (needle < straw)
+               r = m - 1;
+            else if (needle > straw)
+               l = m + 1;
+            else {
+               return m;
+            }
+         }
+         break;
+      }
+
+      case 2: {
+         stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
+         stbtt_uint8 *rangeArray = coverageTable + 4;
+
+         // Binary search.
+         stbtt_int32 l=0, r=rangeCount-1, m;
+         int strawStart, strawEnd, needle=glyph;
+         while (l <= r) {
+            stbtt_uint8 *rangeRecord;
+            m = (l + r) >> 1;
+            rangeRecord = rangeArray + 6 * m;
+            strawStart = ttUSHORT(rangeRecord);
+            strawEnd = ttUSHORT(rangeRecord + 2);
+            if (needle < strawStart)
+               r = m - 1;
+            else if (needle > strawEnd)
+               l = m + 1;
+            else {
+               stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
+               return startCoverageIndex + glyph - strawStart;
+            }
+         }
+         break;
+      }
+
+      default: return -1; // unsupported
+   }
+
+   return -1;
+}
+
+static stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
+{
+   stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
+   switch (classDefFormat)
+   {
+      case 1: {
+         stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
+         stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
+         stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
+
+         if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
+            return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
+         break;
+      }
+
+      case 2: {
+         stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
+         stbtt_uint8 *classRangeRecords = classDefTable + 4;
+
+         // Binary search.
+         stbtt_int32 l=0, r=classRangeCount-1, m;
+         int strawStart, strawEnd, needle=glyph;
+         while (l <= r) {
+            stbtt_uint8 *classRangeRecord;
+            m = (l + r) >> 1;
+            classRangeRecord = classRangeRecords + 6 * m;
+            strawStart = ttUSHORT(classRangeRecord);
+            strawEnd = ttUSHORT(classRangeRecord + 2);
+            if (needle < strawStart)
+               r = m - 1;
+            else if (needle > strawEnd)
+               l = m + 1;
+            else
+               return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
+         }
+         break;
+      }
+
+      default:
+         return -1; // Unsupported definition type, return an error.
+   }
+
+   // "All glyphs not assigned to a class fall into class 0". (OpenType spec)
+   return 0;
+}
+
+// Define to STBTT_assert(x) if you want to break on unimplemented formats.
+#define STBTT_GPOS_TODO_assert(x)
+
+static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
+{
+   stbtt_uint16 lookupListOffset;
+   stbtt_uint8 *lookupList;
+   stbtt_uint16 lookupCount;
+   stbtt_uint8 *data;
+   stbtt_int32 i, sti;
+
+   if (!info->gpos) return 0;
+
+   data = info->data + info->gpos;
+
+   if (ttUSHORT(data+0) != 1) return 0; // Major version 1
+   if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
+
+   lookupListOffset = ttUSHORT(data+8);
+   lookupList = data + lookupListOffset;
+   lookupCount = ttUSHORT(lookupList);
+
+   for (i=0; i<lookupCount; ++i) {
+      stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
+      stbtt_uint8 *lookupTable = lookupList + lookupOffset;
+
+      stbtt_uint16 lookupType = ttUSHORT(lookupTable);
+      stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
+      stbtt_uint8 *subTableOffsets = lookupTable + 6;
+      if (lookupType != 2) // Pair Adjustment Positioning Subtable
+         continue;
+
+      for (sti=0; sti<subTableCount; sti++) {
+         stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
+         stbtt_uint8 *table = lookupTable + subtableOffset;
+         stbtt_uint16 posFormat = ttUSHORT(table);
+         stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
+         stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
+         if (coverageIndex == -1) continue;
+
+         switch (posFormat) {
+            case 1: {
+               stbtt_int32 l, r, m;
+               int straw, needle;
+               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
+               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
+               if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
+                  stbtt_int32 valueRecordPairSizeInBytes = 2;
+                  stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
+                  stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
+                  stbtt_uint8 *pairValueTable = table + pairPosOffset;
+                  stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
+                  stbtt_uint8 *pairValueArray = pairValueTable + 2;
+
+                  if (coverageIndex >= pairSetCount) return 0;
+
+                  needle=glyph2;
+                  r=pairValueCount-1;
+                  l=0;
+
+                  // Binary search.
+                  while (l <= r) {
+                     stbtt_uint16 secondGlyph;
+                     stbtt_uint8 *pairValue;
+                     m = (l + r) >> 1;
+                     pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
+                     secondGlyph = ttUSHORT(pairValue);
+                     straw = secondGlyph;
+                     if (needle < straw)
+                        r = m - 1;
+                     else if (needle > straw)
+                        l = m + 1;
+                     else {
+                        stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
+                        return xAdvance;
+                     }
+                  }
+               } else
+                  return 0;
+               break;
+            }
+
+            case 2: {
+               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
+               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
+               if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
+                  stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
+                  stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
+                  int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
+                  int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
+
+                  stbtt_uint16 class1Count = ttUSHORT(table + 12);
+                  stbtt_uint16 class2Count = ttUSHORT(table + 14);
+                  stbtt_uint8 *class1Records, *class2Records;
+                  stbtt_int16 xAdvance;
+
+                  if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
+                  if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
+
+                  class1Records = table + 16;
+                  class2Records = class1Records + 2 * (glyph1class * class2Count);
+                  xAdvance = ttSHORT(class2Records + 2 * glyph2class);
+                  return xAdvance;
+               } else
+                  return 0;
+               break;
+            }
+
+            default:
+               return 0; // Unsupported position format
+         }
+      }
+   }
+
+   return 0;
 }
 
-STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
+STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)
 {
-   stbtt_uint8 *data = info->data + info->kern;
-   stbtt_uint32 needle, straw;
-   int l, r, m;
+   int xAdvance = 0;
 
-   // we only look at the first table. it must be 'horizontal' and format 0.
-   if (!info->kern)
-      return 0;
-   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
-      return 0;
-   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
-      return 0;
+   if (info->gpos)
+      xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);
+   else if (info->kern)
+      xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);
 
-   l = 0;
-   r = ttUSHORT(data+10) - 1;
-   needle = glyph1 << 16 | glyph2;
-   while (l <= r) {
-      m = (l + r) >> 1;
-      straw = ttULONG(data+18+(m*6)); // note: unaligned read
-      if (needle < straw)
-         r = m - 1;
-      else if (needle > straw)
-         l = m + 1;
-      else
-         return ttSHORT(data+22+(m*6));
-   }
-   return 0;
+   return xAdvance;
 }
 
 STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)
 {
-   if (!info->kern) // if no kerning table, don't waste time looking up both codepoint->glyphs
+   if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs
       return 0;
    return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
 }
@@ -1528,6 +2638,17 @@
    if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
 }
 
+STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)
+{
+   int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");
+   if (!tab)
+      return 0;
+   if (typoAscent ) *typoAscent  = ttSHORT(info->data+tab + 68);
+   if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);
+   if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);
+   return 1;
+}
+
 STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
 {
    *x0 = ttSHORT(info->data + info->head + 36);
@@ -1553,6 +2674,45 @@
    STBTT_free(v, info->userdata);
 }
 
+STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)
+{
+   int i;
+   stbtt_uint8 *data = info->data;
+   stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);
+
+   int numEntries = ttUSHORT(svg_doc_list);
+   stbtt_uint8 *svg_docs = svg_doc_list + 2;
+
+   for(i=0; i<numEntries; i++) {
+      stbtt_uint8 *svg_doc = svg_docs + (12 * i);
+      if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))
+         return svg_doc;
+   }
+   return 0;
+}
+
+STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)
+{
+   stbtt_uint8 *data = info->data;
+   stbtt_uint8 *svg_doc;
+
+   if (info->svg == 0)
+      return 0;
+
+   svg_doc = stbtt_FindSVGDoc(info, gl);
+   if (svg_doc != NULL) {
+      *svg = (char *) data + info->svg + ttULONG(svg_doc + 4);
+      return ttULONG(svg_doc + 8);
+   } else {
+      return 0;
+   }
+}
+
+STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)
+{
+   return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 //
 // antialiasing software rasterizer
@@ -1560,7 +2720,7 @@
 
 STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
 {
-   int x0,y0,x1,y1;
+   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
    if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
       // e.g. space character
       if (ix0) *ix0 = 0;
@@ -1624,7 +2784,7 @@
          hh->num_remaining_in_head_chunk = count;
       }
       --hh->num_remaining_in_head_chunk;
-      return (char *) (hh->head) + size * hh->num_remaining_in_head_chunk;
+      return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
    }
 }
 
@@ -1676,8 +2836,9 @@
 {
    stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
    float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+   STBTT_assert(z != NULL);
    if (!z) return z;
-   
+
    // round dx down to avoid overshooting
    if (dxdy < 0)
       z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);
@@ -1697,6 +2858,7 @@
 {
    stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
    float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+   STBTT_assert(z != NULL);
    //STBTT_assert(e->y0 <= start_point);
    if (!z) return z;
    z->fdx = dxdy;
@@ -1754,7 +2916,7 @@
             }
          }
       }
-      
+
       e = e->next;
    }
 }
@@ -1768,13 +2930,10 @@
    int s; // vertical subsample index
    unsigned char scanline_data[512], *scanline;
 
-   if (result->w > 512) {
+   if (result->w > 512)
       scanline = (unsigned char *) STBTT_malloc(result->w, userdata);
-      if (!scanline)
-         return;
-   } else {
+   else
       scanline = scanline_data;
-   }
 
    y = off_y * vsubsample;
    e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;
@@ -1824,23 +2983,23 @@
          while (e->y0 <= scan_y) {
             if (e->y1 > scan_y) {
                stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);
-               if (!z)
-                  return;
-               // find insertion point
-               if (active == NULL)
-                  active = z;
-               else if (z->x < active->x) {
-                  // insert at front
-                  z->next = active;
-                  active = z;
-               } else {
-                  // find thing to insert AFTER
-                  stbtt__active_edge *p = active;
-                  while (p->next && p->next->x < z->x)
-                     p = p->next;
-                  // at this point, p->next->x is NOT < z->x
-                  z->next = p->next;
-                  p->next = z;
+               if (z != NULL) {
+                  // find insertion point
+                  if (active == NULL)
+                     active = z;
+                  else if (z->x < active->x) {
+                     // insert at front
+                     z->next = active;
+                     active = z;
+                  } else {
+                     // find thing to insert AFTER
+                     stbtt__active_edge *p = active;
+                     while (p->next && p->next->x < z->x)
+                        p = p->next;
+                     // at this point, p->next->x is NOT < z->x
+                     z->next = p->next;
+                     p->next = z;
+                  }
                }
             }
             ++e;
@@ -1903,6 +3062,23 @@
    }
 }
 
+static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
+{
+   STBTT_assert(top_width >= 0);
+   STBTT_assert(bottom_width >= 0);
+   return (top_width + bottom_width) / 2.0f * height;
+}
+
+static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
+{
+   return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
+}
+
+static float stbtt__sized_triangle_area(float height, float width)
+{
+   return height * width / 2;
+}
+
 static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
 {
    float y_bottom = y_top+1;
@@ -1957,13 +3133,13 @@
                float height;
                // simple case, only spans one pixel
                int x = (int) x_top;
-               height = sy1 - sy0;
+               height = (sy1 - sy0) * e->direction;
                STBTT_assert(x >= 0 && x < len);
-               scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2)  * height;
-               scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
+               scanline[x]      += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
+               scanline_fill[x] += height; // everything right of this pixel is filled
             } else {
                int x,x1,x2;
-               float y_crossing, step, sign, area;
+               float y_crossing, y_final, step, sign, area;
                // covers 2+ pixels
                if (x_top > x_bottom) {
                   // flip scanline vertically; signed area is the same
@@ -1976,29 +3152,79 @@
                   dy = -dy;
                   t = x0, x0 = xb, xb = t;
                }
+               STBTT_assert(dy >= 0);
+               STBTT_assert(dx >= 0);
 
                x1 = (int) x_top;
                x2 = (int) x_bottom;
                // compute intersection with y axis at x1+1
-               y_crossing = (x1+1 - x0) * dy + y_top;
+               y_crossing = y_top + dy * (x1+1 - x0);
+
+               // compute intersection with y axis at x2
+               y_final = y_top + dy * (x2 - x0);
+
+               //           x1    x_top                            x2    x_bottom
+               //     y_top  +------|-----+------------+------------+--------|---+------------+
+               //            |            |            |            |            |            |
+               //            |            |            |            |            |            |
+               //       sy0  |      Txxxxx|............|............|............|............|
+               // y_crossing |            *xxxxx.......|............|............|............|
+               //            |            |     xxxxx..|............|............|............|
+               //            |            |     /-   xx*xxxx........|............|............|
+               //            |            | dy <       |    xxxxxx..|............|............|
+               //   y_final  |            |     \-     |          xx*xxx.........|............|
+               //       sy1  |            |            |            |   xxxxxB...|............|
+               //            |            |            |            |            |            |
+               //            |            |            |            |            |            |
+               //  y_bottom  +------------+------------+------------+------------+------------+
+               //
+               // goal is to measure the area covered by '.' in each pixel
+
+               // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
+               // @TODO: maybe test against sy1 rather than y_bottom?
+               if (y_crossing > y_bottom)
+                  y_crossing = y_bottom;
 
                sign = e->direction;
-               // area of the rectangle covered from y0..y_crossing
+
+               // area of the rectangle covered from sy0..y_crossing
                area = sign * (y_crossing-sy0);
-               // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
-               scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
+
+               // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
+               scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
+
+               // check if final y_crossing is blown up; no test case for this
+               if (y_final > y_bottom) {
+                  y_final = y_bottom;
+                  dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
+               }
 
-               step = sign * dy;
+               // in second pixel, area covered by line segment found in first pixel
+               // is always a rectangle 1 wide * the height of that line segment; this
+               // is exactly what the variable 'area' stores. it also gets a contribution
+               // from the line segment within it. the THIRD pixel will get the first
+               // pixel's rectangle contribution, the second pixel's rectangle contribution,
+               // and its own contribution. the 'own contribution' is the same in every pixel except
+               // the leftmost and rightmost, a trapezoid that slides down in each pixel.
+               // the second pixel's contribution to the third pixel will be the
+               // rectangle 1 wide times the height change in the second pixel, which is dy.
+
+               step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,
+               // which multiplied by 1-pixel-width is how much pixel area changes for each step in x
+               // so the area advances by 'step' every time
+
                for (x = x1+1; x < x2; ++x) {
-                  scanline[x] += area + step/2;
+                  scanline[x] += area + step/2; // area of trapezoid is 1*step/2
                   area += step;
                }
-               y_crossing += dy * (x2 - (x1+1));
+               STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
+               STBTT_assert(sy1 > y_final-0.01f);
 
-               STBTT_assert(fabs(area) <= 1.01f);
+               // area covered in the last pixel is the rectangle from all the pixels to the left,
+               // plus the trapezoid filled by the line segment in this pixel all the way to the right edge
+               scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
 
-               scanline[x2] += area + sign * (1-(x_bottom-x2)/2) * (sy1-y_crossing);
-
+               // the rest of the line is filled based on the total height of the line segment in this pixel
                scanline_fill[x2] += sign * (sy1-sy0);
             }
          } else {
@@ -2006,6 +3232,9 @@
             // clipping logic. since this does not match the intended use
             // of this library, we use a different, very slow brute
             // force implementation
+            // note though that this does happen some of the time because
+            // x_top and x_bottom can be extrapolated at the top & bottom of
+            // the shape and actually lie outside the bounding box
             int x;
             for (x=0; x < len; ++x) {
                // cases:
@@ -2021,19 +3250,18 @@
                // from the other y segment, and it might ignored as an empty segment. to avoid
                // that, we need to explicitly produce segments based on x positions.
 
-               // rename variables to clear pairs
+               // rename variables to clearly-defined pairs
                float y0 = y_top;
                float x1 = (float) (x);
                float x2 = (float) (x+1);
                float x3 = xb;
                float y3 = y_bottom;
-               float y1,y2;
 
                // x = e->x + e->dx * (y-y_top)
                // (y-y_top) = (x - e->x) / e->dx
                // y = (x - e->x) / e->dx + y_top
-               y1 = (x - x0) / dx + y_top;
-               y2 = (x+1 - x0) / dx + y_top;
+               float y1 = (x - x0) / dx + y_top;
+               float y2 = (x+1 - x0) / dx + y_top;
 
                if (x0 < x1 && x3 > x2) {         // three segments descending down-right
                   stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
@@ -2073,13 +3301,12 @@
    int y,j=0, i;
    float scanline_data[129], *scanline, *scanline2;
 
+   STBTT__NOTUSED(vsubsample);
+
-   if (result->w > 64) {
+   if (result->w > 64)
       scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);
-      if (!scanline)
-         return;
-   } else {
+   else
       scanline = scanline_data;
-   }
 
    scanline2 = scanline + result->w;
 
@@ -2113,12 +3340,18 @@
       while (e->y0 <= scan_y_bottom) {
          if (e->y0 != e->y1) {
             stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
-            if (!z)
-               return;
-            STBTT_assert(z->ey >= scan_y_top);
-            // insert at front
-            z->next = active;
-            active = z;
+            if (z != NULL) {
+               if (j == 0 && off_y != 0) {
+                  if (z->ey < scan_y_top) {
+                     // this can happen due to subpixel positioning and some kind of fp rounding error i think
+                     z->ey = scan_y_top;
+                  }
+               }
+               STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds
+               // insert at front
+               z->next = active;
+               active = z;
+            }
          }
          ++e;
       }
@@ -2183,7 +3416,7 @@
 
 static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
 {
-   /* threshhold for transitioning to insertion sort */
+   /* threshold for transitioning to insertion sort */
    while (n > 12) {
       stbtt__edge t;
       int c01,c12,c,m,i,j;
@@ -2318,7 +3551,7 @@
    points[n].y = y;
 }
 
-// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
+// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching
 static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
 {
    // midpoint
@@ -2339,6 +3572,48 @@
    return 1;
 }
 
+static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)
+{
+   // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
+   float dx0 = x1-x0;
+   float dy0 = y1-y0;
+   float dx1 = x2-x1;
+   float dy1 = y2-y1;
+   float dx2 = x3-x2;
+   float dy2 = y3-y2;
+   float dx = x3-x0;
+   float dy = y3-y0;
+   float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
+   float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);
+   float flatness_squared = longlen*longlen-shortlen*shortlen;
+
+   if (n > 16) // 65536 segments on one curve better be enough!
+      return;
+
+   if (flatness_squared > objspace_flatness_squared) {
+      float x01 = (x0+x1)/2;
+      float y01 = (y0+y1)/2;
+      float x12 = (x1+x2)/2;
+      float y12 = (y1+y2)/2;
+      float x23 = (x2+x3)/2;
+      float y23 = (y2+y3)/2;
+
+      float xa = (x01+x12)/2;
+      float ya = (y01+y12)/2;
+      float xb = (x12+x23)/2;
+      float yb = (y12+y23)/2;
+
+      float mx = (xa+xb)/2;
+      float my = (ya+yb)/2;
+
+      stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
+      stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
+   } else {
+      stbtt__add_point(points, *num_points,x3,y3);
+      *num_points = *num_points+1;
+   }
+}
+
 // returns number of contours
 static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
 {
@@ -2391,6 +3666,14 @@
             case STBTT_vcurve:
                stbtt__tesselate_curve(points, &num_points, x,y,
                                         vertices[i].cx, vertices[i].cy,
+                                        vertices[i].x,  vertices[i].y,
+                                        objspace_flatness_squared, 0);
+               x = vertices[i].x, y = vertices[i].y;
+               break;
+            case STBTT_vcubic:
+               stbtt__tesselate_cubic(points, &num_points, x,y,
+                                        vertices[i].cx, vertices[i].cy,
+                                        vertices[i].cx1, vertices[i].cy1,
                                         vertices[i].x,  vertices[i].y,
                                         objspace_flatness_squared, 0);
                x = vertices[i].x, y = vertices[i].y;
@@ -2411,8 +3694,9 @@
 
 STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
 {
-   float scale = scale_x > scale_y ? scale_y : scale_x;
-   int winding_count, *winding_lengths;
+   float scale            = scale_x > scale_y ? scale_y : scale_x;
+   int winding_count      = 0;
+   int *winding_lengths   = NULL;
    stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
    if (windings) {
       stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);
@@ -2430,7 +3714,7 @@
 {
    int ix0,iy0,ix1,iy1;
    stbtt__bitmap gbm;
-   stbtt_vertex *vertices;   
+   stbtt_vertex *vertices;
    int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
 
    if (scale_x == 0) scale_x = scale_y;
@@ -2453,7 +3737,7 @@
    if (height) *height = gbm.h;
    if (xoff  ) *xoff   = ix0;
    if (yoff  ) *yoff   = iy0;
-   
+
    if (gbm.w && gbm.h) {
       gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
       if (gbm.pixels) {
@@ -2464,7 +3748,7 @@
    }
    STBTT_free(vertices, info->userdata);
    return gbm.pixels;
-}   
+}
 
 STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
 {
@@ -2476,7 +3760,7 @@
    int ix0,iy0;
    stbtt_vertex *vertices;
    int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
-   stbtt__bitmap gbm;   
+   stbtt__bitmap gbm;
 
    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
    gbm.pixels = output;
@@ -2498,7 +3782,12 @@
 STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
 {
    return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
-}   
+}
+
+STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
+{
+   stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
+}
 
 STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
 {
@@ -2508,7 +3797,7 @@
 STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
 {
    return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
-}   
+}
 
 STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
 {
@@ -2521,7 +3810,7 @@
 //
 // This is SUPER-CRAPPY packing to keep source code small
 
-STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
+static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
                                 float pixel_height,                     // height of font in pixels
                                 unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
                                 int first_char, int num_chars,          // characters to bake
@@ -2530,6 +3819,7 @@
    float scale;
    int x,y,bottom_y, i;
    stbtt_fontinfo f;
+   f.userdata = NULL;
    if (!stbtt_InitFont(&f, data, offset))
       return -1;
    STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
@@ -2566,11 +3856,11 @@
    return bottom_y;
 }
 
-STBTT_DEF void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
+STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)
 {
    float d3d_bias = opengl_fillrule ? 0 : -0.5f;
    float ipw = 1.0f / pw, iph = 1.0f / ph;
-   stbtt_bakedchar *b = chardata + char_index;
+   const stbtt_bakedchar *b = chardata + char_index;
    int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);
    int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);
 
@@ -2593,11 +3883,6 @@
 //
 
 #ifndef STB_RECT_PACK_VERSION
-#ifdef _MSC_VER
-#define STBTT__NOTUSED(v)  (void)(v)
-#else
-#define STBTT__NOTUSED(v)  (void)sizeof(v)
-#endif
 
 typedef int stbrp_coord;
 
@@ -2637,7 +3922,7 @@
    con->y = 0;
    con->bottom_y = 0;
    STBTT__NOTUSED(nodes);
-   STBTT__NOTUSED(num_nodes);   
+   STBTT__NOTUSED(num_nodes);
 }
 
 static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)
@@ -2691,6 +3976,7 @@
    spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;
    spc->h_oversample = 1;
    spc->v_oversample = 1;
+   spc->skip_missing = 0;
 
    stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
 
@@ -2716,6 +4002,11 @@
       spc->v_oversample = v_oversample;
 }
 
+STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)
+{
+   spc->skip_missing = skip;
+}
+
 #define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)
 
 static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)
@@ -2723,6 +4014,7 @@
    unsigned char buffer[STBTT_MAX_OVERSAMPLE];
    int safe_w = w - kernel_width;
    int j;
+   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
    for (j=0; j < h; ++j) {
       int i;
       unsigned int total;
@@ -2784,6 +4076,7 @@
    unsigned char buffer[STBTT_MAX_OVERSAMPLE];
    int safe_h = h - kernel_width;
    int j;
+   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
    for (j=0; j < w; ++j) {
       int i;
       unsigned int total;
@@ -2853,9 +4146,10 @@
 }
 
 // rects array must be big enough to accommodate all characters in the given ranges
-STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
+STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
 {
    int i,j,k;
+   int missing_glyph_added = 0;
 
    k=0;
    for (i=0; i < num_ranges; ++i) {
@@ -2867,13 +4161,19 @@
          int x0,y0,x1,y1;
          int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
          int glyph = stbtt_FindGlyphIndex(info, codepoint);
-         stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
-                                         scale * spc->h_oversample,
-                                         scale * spc->v_oversample,
-                                         0,0,
-                                         &x0,&y0,&x1,&y1);
-         rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
-         rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
+         if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {
+            rects[k].w = rects[k].h = 0;
+         } else {
+            stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
+                                            scale * spc->h_oversample,
+                                            scale * spc->v_oversample,
+                                            0,0,
+                                            &x0,&y0,&x1,&y1);
+            rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
+            rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
+            if (glyph == 0)
+               missing_glyph_added = 1;
+         }
          ++k;
       }
    }
@@ -2881,10 +4181,33 @@
    return k;
 }
 
+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)
+{
+   stbtt_MakeGlyphBitmapSubpixel(info,
+                                 output,
+                                 out_w - (prefilter_x - 1),
+                                 out_h - (prefilter_y - 1),
+                                 out_stride,
+                                 scale_x,
+                                 scale_y,
+                                 shift_x,
+                                 shift_y,
+                                 glyph);
+
+   if (prefilter_x > 1)
+      stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
+
+   if (prefilter_y > 1)
+      stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
+
+   *sub_x = stbtt__oversample_shift(prefilter_x);
+   *sub_y = stbtt__oversample_shift(prefilter_y);
+}
+
 // rects array must be big enough to accommodate all characters in the given ranges
-STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
+STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
 {
-   int i,j,k, return_value = 1;
+   int i,j,k, missing_glyph = -1, return_value = 1;
 
    // save current values
    int old_h_over = spc->h_oversample;
@@ -2903,7 +4226,7 @@
       sub_y = stbtt__oversample_shift(spc->v_oversample);
       for (j=0; j < ranges[i].num_chars; ++j) {
          stbrp_rect *r = &rects[k];
-         if (r->was_packed) {
+         if (r->was_packed && r->w != 0 && r->h != 0) {
             stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
             int advance, lsb, x0,y0,x1,y1;
             int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
@@ -2949,6 +4272,13 @@
             bc->yoff     =       (float)  y0 * recip_v + sub_y;
             bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;
             bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;
+
+            if (glyph == 0)
+               missing_glyph = j;
+         } else if (spc->skip_missing) {
+            return_value = 0;
+         } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {
+            ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];
          } else {
             return_value = 0; // if any fail, report failure
          }
@@ -2969,7 +4299,7 @@
    stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
 }
 
-STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
+STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
 {
    stbtt_fontinfo info;
    int i,j,n, return_value = 1;
@@ -2987,24 +4317,25 @@
    n = 0;
    for (i=0; i < num_ranges; ++i)
       n += ranges[i].num_chars;
-         
+
    rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
    if (rects == NULL)
       return 0;
 
+   info.userdata = spc->user_allocator_context;
    stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
 
    n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
 
    stbtt_PackFontRangesPackRects(spc, rects, n);
-  
+
    return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
 
    STBTT_free(rects, spc->user_allocator_context);
    return return_value;
 }
 
-STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
+STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
             int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
 {
    stbtt_pack_range range;
@@ -3016,10 +4347,23 @@
    return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
 }
 
-STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
+STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)
+{
+   int i_ascent, i_descent, i_lineGap;
+   float scale;
+   stbtt_fontinfo info;
+   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
+   scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
+   stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
+   *ascent  = (float) i_ascent  * scale;
+   *descent = (float) i_descent * scale;
+   *lineGap = (float) i_lineGap * scale;
+}
+
+STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)
 {
    float ipw = 1.0f / pw, iph = 1.0f / ph;
-   stbtt_packedchar *b = chardata + char_index;
+   const stbtt_packedchar *b = chardata + char_index;
 
    if (align_to_integer) {
       float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);
@@ -3043,6 +4387,385 @@
    *xpos += b->xadvance;
 }
 
+//////////////////////////////////////////////////////////////////////////////
+//
+// sdf computation
+//
+
+#define STBTT_min(a,b)  ((a) < (b) ? (a) : (b))
+#define STBTT_max(a,b)  ((a) < (b) ? (b) : (a))
+
+static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])
+{
+   float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
+   float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
+   float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
+   float roperp = orig[1]*ray[0] - orig[0]*ray[1];
+
+   float a = q0perp - 2*q1perp + q2perp;
+   float b = q1perp - q0perp;
+   float c = q0perp - roperp;
+
+   float s0 = 0., s1 = 0.;
+   int num_s = 0;
+
+   if (a != 0.0) {
+      float discr = b*b - a*c;
+      if (discr > 0.0) {
+         float rcpna = -1 / a;
+         float d = (float) STBTT_sqrt(discr);
+         s0 = (b+d) * rcpna;
+         s1 = (b-d) * rcpna;
+         if (s0 >= 0.0 && s0 <= 1.0)
+            num_s = 1;
+         if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
+            if (num_s == 0) s0 = s1;
+            ++num_s;
+         }
+      }
+   } else {
+      // 2*b*s + c = 0
+      // s = -c / (2*b)
+      s0 = c / (-2 * b);
+      if (s0 >= 0.0 && s0 <= 1.0)
+         num_s = 1;
+   }
+
+   if (num_s == 0)
+      return 0;
+   else {
+      float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
+      float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
+
+      float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;
+      float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;
+      float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;
+      float rod = orig[0]*rayn_x + orig[1]*rayn_y;
+
+      float q10d = q1d - q0d;
+      float q20d = q2d - q0d;
+      float q0rd = q0d - rod;
+
+      hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
+      hits[0][1] = a*s0+b;
+
+      if (num_s > 1) {
+         hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
+         hits[1][1] = a*s1+b;
+         return 2;
+      } else {
+         return 1;
+      }
+   }
+}
+
+static int equal(float *a, float *b)
+{
+   return (a[0] == b[0] && a[1] == b[1]);
+}
+
+static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
+{
+   int i;
+   float orig[2], ray[2] = { 1, 0 };
+   float y_frac;
+   int winding = 0;
+
+   // make sure y never passes through a vertex of the shape
+   y_frac = (float) STBTT_fmod(y, 1.0f);
+   if (y_frac < 0.01f)
+      y += 0.01f;
+   else if (y_frac > 0.99f)
+      y -= 0.01f;
+
+   orig[0] = x;
+   orig[1] = y;
+
+   // test a ray from (-infinity,y) to (x,y)
+   for (i=0; i < nverts; ++i) {
+      if (verts[i].type == STBTT_vline) {
+         int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;
+         int x1 = (int) verts[i  ].x, y1 = (int) verts[i  ].y;
+         if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
+            float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
+            if (x_inter < x)
+               winding += (y0 < y1) ? 1 : -1;
+         }
+      }
+      if (verts[i].type == STBTT_vcurve) {
+         int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;
+         int x1 = (int) verts[i  ].cx, y1 = (int) verts[i  ].cy;
+         int x2 = (int) verts[i  ].x , y2 = (int) verts[i  ].y ;
+         int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
+         int by = STBTT_max(y0,STBTT_max(y1,y2));
+         if (y > ay && y < by && x > ax) {
+            float q0[2],q1[2],q2[2];
+            float hits[2][2];
+            q0[0] = (float)x0;
+            q0[1] = (float)y0;
+            q1[0] = (float)x1;
+            q1[1] = (float)y1;
+            q2[0] = (float)x2;
+            q2[1] = (float)y2;
+            if (equal(q0,q1) || equal(q1,q2)) {
+               x0 = (int)verts[i-1].x;
+               y0 = (int)verts[i-1].y;
+               x1 = (int)verts[i  ].x;
+               y1 = (int)verts[i  ].y;
+               if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
+                  float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
+                  if (x_inter < x)
+                     winding += (y0 < y1) ? 1 : -1;
+               }
+            } else {
+               int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
+               if (num_hits >= 1)
+                  if (hits[0][0] < 0)
+                     winding += (hits[0][1] < 0 ? -1 : 1);
+               if (num_hits >= 2)
+                  if (hits[1][0] < 0)
+                     winding += (hits[1][1] < 0 ? -1 : 1);
+            }
+         }
+      }
+   }
+   return winding;
+}
+
+static float stbtt__cuberoot( float x )
+{
+   if (x<0)
+      return -(float) STBTT_pow(-x,1.0f/3.0f);
+   else
+      return  (float) STBTT_pow( x,1.0f/3.0f);
+}
+
+// x^3 + a*x^2 + b*x + c = 0
+static int stbtt__solve_cubic(float a, float b, float c, float* r)
+{
+   float s = -a / 3;
+   float p = b - a*a / 3;
+   float q = a * (2*a*a - 9*b) / 27 + c;
+   float p3 = p*p*p;
+   float d = q*q + 4*p3 / 27;
+   if (d >= 0) {
+      float z = (float) STBTT_sqrt(d);
+      float u = (-q + z) / 2;
+      float v = (-q - z) / 2;
+      u = stbtt__cuberoot(u);
+      v = stbtt__cuberoot(v);
+      r[0] = s + u + v;
+      return 1;
+   } else {
+      float u = (float) STBTT_sqrt(-p/3);
+      float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
+      float m = (float) STBTT_cos(v);
+      float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
+      r[0] = s + u * 2 * m;
+      r[1] = s - u * (m + n);
+      r[2] = s - u * (m - n);
+
+      //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f);  // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
+      //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
+      //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
+      return 3;
+   }
+}
+
+STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
+{
+   float scale_x = scale, scale_y = scale;
+   int ix0,iy0,ix1,iy1;
+   int w,h;
+   unsigned char *data;
+
+   if (scale == 0) return NULL;
+
+   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
+
+   // if empty, return NULL
+   if (ix0 == ix1 || iy0 == iy1)
+      return NULL;
+
+   ix0 -= padding;
+   iy0 -= padding;
+   ix1 += padding;
+   iy1 += padding;
+
+   w = (ix1 - ix0);
+   h = (iy1 - iy0);
+
+   if (width ) *width  = w;
+   if (height) *height = h;
+   if (xoff  ) *xoff   = ix0;
+   if (yoff  ) *yoff   = iy0;
+
+   // invert for y-downwards bitmaps
+   scale_y = -scale_y;
+
+   {
+      int x,y,i,j;
+      float *precompute;
+      stbtt_vertex *verts;
+      int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
+      data = (unsigned char *) STBTT_malloc(w * h, info->userdata);
+      precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);
+
+      for (i=0,j=num_verts-1; i < num_verts; j=i++) {
+         if (verts[i].type == STBTT_vline) {
+            float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
+            float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
+            float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
+            precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
+         } else if (verts[i].type == STBTT_vcurve) {
+            float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
+            float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
+            float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
+            float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
+            float len2 = bx*bx + by*by;
+            if (len2 != 0.0f)
+               precompute[i] = 1.0f / (bx*bx + by*by);
+            else
+               precompute[i] = 0.0f;
+         } else
+            precompute[i] = 0.0f;
+      }
+
+      for (y=iy0; y < iy1; ++y) {
+         for (x=ix0; x < ix1; ++x) {
+            float val;
+            float min_dist = 999999.0f;
+            float sx = (float) x + 0.5f;
+            float sy = (float) y + 0.5f;
+            float x_gspace = (sx / scale_x);
+            float y_gspace = (sy / scale_y);
+
+            int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path
+
+            for (i=0; i < num_verts; ++i) {
+               float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
+
+               if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
+                  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
+
+                  float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
+                  if (dist2 < min_dist*min_dist)
+                     min_dist = (float) STBTT_sqrt(dist2);
+
+                  // coarse culling against bbox
+                  //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
+                  //    sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
+                  dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
+                  STBTT_assert(i != 0);
+                  if (dist < min_dist) {
+                     // check position along line
+                     // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
+                     // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
+                     float dx = x1-x0, dy = y1-y0;
+                     float px = x0-sx, py = y0-sy;
+                     // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy
+                     // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
+                     float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
+                     if (t >= 0.0f && t <= 1.0f)
+                        min_dist = dist;
+                  }
+               } else if (verts[i].type == STBTT_vcurve) {
+                  float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
+                  float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;
+                  float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
+                  float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
+                  float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
+                  float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
+                  // coarse culling against bbox to avoid computing cubic unnecessarily
+                  if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
+                     int num=0;
+                     float ax = x1-x0, ay = y1-y0;
+                     float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
+                     float mx = x0 - sx, my = y0 - sy;
+                     float res[3] = {0.f,0.f,0.f};
+                     float px,py,t,it,dist2;
+                     float a_inv = precompute[i];
+                     if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
+                        float a = 3*(ax*bx + ay*by);
+                        float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
+                        float c = mx*ax+my*ay;
+                        if (a == 0.0) { // if a is 0, it's linear
+                           if (b != 0.0) {
+                              res[num++] = -c/b;
+                           }
+                        } else {
+                           float discriminant = b*b - 4*a*c;
+                           if (discriminant < 0)
+                              num = 0;
+                           else {
+                              float root = (float) STBTT_sqrt(discriminant);
+                              res[0] = (-b - root)/(2*a);
+                              res[1] = (-b + root)/(2*a);
+                              num = 2; // don't bother distinguishing 1-solution case, as code below will still work
+                           }
+                        }
+                     } else {
+                        float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
+                        float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
+                        float d = (mx*ax+my*ay) * a_inv;
+                        num = stbtt__solve_cubic(b, c, d, res);
+                     }
+                     dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
+                     if (dist2 < min_dist*min_dist)
+                        min_dist = (float) STBTT_sqrt(dist2);
+
+                     if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
+                        t = res[0], it = 1.0f - t;
+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
+                        if (dist2 < min_dist * min_dist)
+                           min_dist = (float) STBTT_sqrt(dist2);
+                     }
+                     if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
+                        t = res[1], it = 1.0f - t;
+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
+                        if (dist2 < min_dist * min_dist)
+                           min_dist = (float) STBTT_sqrt(dist2);
+                     }
+                     if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
+                        t = res[2], it = 1.0f - t;
+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
+                        if (dist2 < min_dist * min_dist)
+                           min_dist = (float) STBTT_sqrt(dist2);
+                     }
+                  }
+               }
+            }
+            if (winding == 0)
+               min_dist = -min_dist;  // if outside the shape, value is negative
+            val = onedge_value + pixel_dist_scale * min_dist;
+            if (val < 0)
+               val = 0;
+            else if (val > 255)
+               val = 255;
+            data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;
+         }
+      }
+      STBTT_free(precompute, info->userdata);
+      STBTT_free(verts, info->userdata);
+   }
+   return data;
+}
+
+STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
+{
+   return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
+}
+
+STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
+{
+   STBTT_free(bitmap, userdata);
+}
 
 //////////////////////////////////////////////////////////////////////////////
 //
@@ -3050,7 +4773,7 @@
 //
 
 // check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
-static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2) 
+static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
 {
    stbtt_int32 i=0;
 
@@ -3089,9 +4812,9 @@
    return i;
 }
 
-STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) 
+static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
 {
-   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((const stbtt_uint8*) s1, len1, (const stbtt_uint8*) s2, len2);
+   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
 }
 
 // returns results in whatever encoding you request... but note that 2-byte encodings
@@ -3147,7 +4870,7 @@
                         return 1;
                   } else if (matchlen < nlen && name[matchlen] == ' ') {
                      ++matchlen;
-                     if (stbtt_CompareUTF8toUTF16_bigendian((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
+                     if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
                         return 1;
                   }
                } else {
@@ -3193,7 +4916,7 @@
    return 0;
 }
 
-STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags)
+static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)
 {
    stbtt_int32 i;
    for (i=0;;++i) {
@@ -3204,11 +4927,71 @@
    }
 }
 
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+
+STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
+                                float pixel_height, unsigned char *pixels, int pw, int ph,
+                                int first_char, int num_chars, stbtt_bakedchar *chardata)
+{
+   return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
+}
+
+STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
+{
+   return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
+}
+
+STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
+{
+   return stbtt_GetNumberOfFonts_internal((unsigned char *) data);
+}
+
+STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)
+{
+   return stbtt_InitFont_internal(info, (unsigned char *) data, offset);
+}
+
+STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)
+{
+   return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);
+}
+
+STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
+{
+   return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
 #endif // STB_TRUETYPE_IMPLEMENTATION
 
 
 // FULL VERSION HISTORY
 //
+//   1.25 (2021-07-11) many fixes
+//   1.24 (2020-02-05) fix warning
+//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
+//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
+//   1.21 (2019-02-25) fix warning
+//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
+//   1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
+//   1.18 (2018-01-29) add missing function
+//   1.17 (2017-07-23) make more arguments const; doc fix
+//   1.16 (2017-07-12) SDF support
+//   1.15 (2017-03-03) make more arguments const
+//   1.14 (2017-01-16) num-fonts-in-TTC function
+//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
+//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
+//   1.11 (2016-04-02) fix unused-variable warning
+//   1.10 (2016-04-02) allow user-defined fabs() replacement
+//                     fix memory leak if fontsize=0.0
+//                     fix warning from duplicate typedef
+//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges
 //   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges
 //   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;
 //                     allow PackFontRanges to pack and render in separate phases;
@@ -3250,3 +5033,45 @@
 //   0.2  (2009-03-11) Fix unsigned/signed char warnings
 //   0.1  (2009-03-09) First public release
 //
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index a21fde0..05f9304 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -596,6 +596,48 @@
 	return ops->select_font(dev, name, size);
 }
 
+int vidconsole_measure(struct udevice *dev, const char *name, uint size,
+		       const char *text, struct vidconsole_bbox *bbox)
+{
+	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+	int ret;
+
+	if (ops->select_font) {
+		ret = ops->measure(dev, name, size, text, bbox);
+		if (ret != -ENOSYS)
+			return ret;
+	}
+
+	bbox->valid = true;
+	bbox->x0 = 0;
+	bbox->y0 = 0;
+	bbox->x1 = priv->x_charsize * strlen(text);
+	bbox->y1 = priv->y_charsize;
+
+	return 0;
+}
+
+void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg,
+			    enum colour_idx bg, struct vidconsole_colour *old)
+{
+	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+
+	old->colour_fg = vid_priv->colour_fg;
+	old->colour_bg = vid_priv->colour_bg;
+
+	vid_priv->colour_fg = video_index_to_colour(vid_priv, fg);
+	vid_priv->colour_bg = video_index_to_colour(vid_priv, bg);
+}
+
+void vidconsole_pop_colour(struct udevice *dev, struct vidconsole_colour *old)
+{
+	struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
+
+	vid_priv->colour_fg = old->colour_fg;
+	vid_priv->colour_bg = old->colour_bg;
+}
+
 /* Set up the number of rows and colours (rotated drivers override this) */
 static int vidconsole_pre_probe(struct udevice *dev)
 {
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index 1b66a80..95e874b 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -142,6 +142,58 @@
 	return 0;
 }
 
+int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
+		    int yend, u32 colour)
+{
+	struct video_priv *priv = dev_get_uclass_priv(dev);
+	void *start, *line;
+	int pixels = xend - xstart;
+	int row, i, ret;
+
+	start = priv->fb + ystart * priv->line_length;
+	start += xstart * VNBYTES(priv->bpix);
+	line = start;
+	for (row = ystart; row < yend; row++) {
+		switch (priv->bpix) {
+		case VIDEO_BPP8: {
+			u8 *dst = line;
+
+			if (IS_ENABLED(CONFIG_VIDEO_BPP8)) {
+				for (i = 0; i < pixels; i++)
+					*dst++ = colour;
+			}
+			break;
+		}
+		case VIDEO_BPP16: {
+			u16 *dst = line;
+
+			if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
+				for (i = 0; i < pixels; i++)
+					*dst++ = colour;
+			}
+			break;
+		}
+		case VIDEO_BPP32: {
+			u32 *dst = line;
+
+			if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
+				for (i = 0; i < pixels; i++)
+					*dst++ = colour;
+			}
+			break;
+		}
+		default:
+			return -ENOSYS;
+		}
+		line += priv->line_length;
+	}
+	ret = video_sync_copy(dev, start, line);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 int video_fill(struct udevice *dev, u32 colour)
 {
 	struct video_priv *priv = dev_get_uclass_priv(dev);
@@ -208,7 +260,7 @@
 	{ 0xff, 0xff, 0xff },  /* white */
 };
 
-u32 video_index_to_colour(struct video_priv *priv, unsigned int idx)
+u32 video_index_to_colour(struct video_priv *priv, enum colour_idx idx)
 {
 	switch (priv->bpix) {
 	case VIDEO_BPP16:
diff --git a/env/Kconfig b/env/Kconfig
index 7342397..13e3210 100644
--- a/env/Kconfig
+++ b/env/Kconfig
@@ -662,6 +662,18 @@
 	  partition 0 or the first boot partition, which is 1 or some other defined
 	  partition.
 
+config USE_ENV_MMC_PARTITION
+	bool "use the mmc environment partition name"
+	depends on ENV_IS_IN_MMC
+
+config ENV_MMC_PARTITION
+	string "mmc environment partition name"
+	depends on USE_ENV_MMC_PARTITION
+	help
+	  MMC partition name used to save environment variables.
+	  If this variable is unset, u-boot will try to get the env partition name
+	  from the device-tree's /config node.
+
 config ENV_MMC_USE_DT
 	bool "Read partition name and offset in DT"
 	depends on ENV_IS_IN_MMC && OF_CONTROL
diff --git a/env/common.c b/env/common.c
index 8beb8e6..0ecdb24 100644
--- a/env/common.c
+++ b/env/common.c
@@ -353,6 +353,7 @@
 				tmp_env2->crc;
 
 	if (!crc1_ok && !crc2_ok) {
+		gd->env_valid = ENV_INVALID;
 		return -ENOMSG; /* needed for env_load() */
 	} else if (crc1_ok && !crc2_ok) {
 		gd->env_valid = ENV_VALID;
diff --git a/env/mmc.c b/env/mmc.c
index 7a5836a..cb14bbb 100644
--- a/env/mmc.c
+++ b/env/mmc.c
@@ -114,8 +114,13 @@
 	if (IS_ENABLED(CONFIG_SYS_MMC_ENV_PART))
 		hwpart = mmc_get_env_part(mmc);
 
+#if defined(CONFIG_ENV_MMC_PARTITION)
+	str = CONFIG_ENV_MMC_PARTITION;
+#else
 	/* look for the partition in mmc CONFIG_SYS_MMC_ENV_DEV */
 	str = ofnode_conf_read_str(dt_prop.partition);
+#endif
+
 	if (str) {
 		/* try to place the environment at end of the partition */
 		err = mmc_offset_try_partition(str, copy, &val);
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 7618960..f4b21d7 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -12,23 +12,23 @@
 	struct erofs_inode *vi = inode;
 	bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE);
 
-	nblocks = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
+	nblocks = BLK_ROUND_UP(inode->i_size);
 	lastblk = nblocks - tailendpacking;
 
 	/* there is no hole in flatmode */
 	map->m_flags = EROFS_MAP_MAPPED;
 
-	if (offset < blknr_to_addr(lastblk)) {
-		map->m_pa = blknr_to_addr(vi->u.i_blkaddr) + map->m_la;
-		map->m_plen = blknr_to_addr(lastblk) - offset;
+	if (offset < erofs_pos(lastblk)) {
+		map->m_pa = erofs_pos(vi->u.i_blkaddr) + map->m_la;
+		map->m_plen = erofs_pos(lastblk) - offset;
 	} else if (tailendpacking) {
 		/* 2 - inode inline B: inode, [xattrs], inline last blk... */
 		map->m_pa = iloc(vi->nid) + vi->inode_isize +
 			vi->xattr_isize + erofs_blkoff(map->m_la);
 		map->m_plen = inode->i_size - offset;
 
-		/* inline data should be located in one meta block */
-		if (erofs_blkoff(map->m_pa) + map->m_plen > PAGE_SIZE) {
+		/* inline data should be located in the same meta block */
+		if (erofs_blkoff(map->m_pa) + map->m_plen > erofs_blksiz()) {
 			erofs_err("inline data cross block boundary @ nid %" PRIu64,
 				  vi->nid);
 			DBG_BUGON(1);
@@ -55,7 +55,7 @@
 {
 	struct erofs_inode *vi = inode;
 	struct erofs_inode_chunk_index *idx;
-	u8 buf[EROFS_BLKSIZ];
+	u8 buf[EROFS_MAX_BLOCK_SIZE];
 	u64 chunknr;
 	unsigned int unit;
 	erofs_off_t pos;
@@ -87,7 +87,7 @@
 
 	map->m_la = chunknr << vi->u.chunkbits;
 	map->m_plen = min_t(erofs_off_t, 1UL << vi->u.chunkbits,
-			    roundup(inode->i_size - map->m_la, EROFS_BLKSIZ));
+			    roundup(inode->i_size - map->m_la, erofs_blksiz()));
 
 	/* handle block map */
 	if (!(vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)) {
@@ -96,7 +96,7 @@
 		if (le32_to_cpu(*blkaddr) == EROFS_NULL_ADDR) {
 			map->m_flags = 0;
 		} else {
-			map->m_pa = blknr_to_addr(le32_to_cpu(*blkaddr));
+			map->m_pa = erofs_pos(le32_to_cpu(*blkaddr));
 			map->m_flags = EROFS_MAP_MAPPED;
 		}
 		goto out;
@@ -110,7 +110,7 @@
 	default:
 		map->m_deviceid = le16_to_cpu(idx->device_id) &
 			sbi.device_id_mask;
-		map->m_pa = blknr_to_addr(le32_to_cpu(idx->blkaddr));
+		map->m_pa = erofs_pos(le32_to_cpu(idx->blkaddr));
 		map->m_flags = EROFS_MAP_MAPPED;
 		break;
 	}
@@ -119,23 +119,23 @@
 	return err;
 }
 
-int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map)
+int erofs_map_dev(struct erofs_map_dev *map)
 {
 	struct erofs_device_info *dif;
 	int id;
 
 	if (map->m_deviceid) {
-		if (sbi->extra_devices < map->m_deviceid)
+		if (sbi.extra_devices < map->m_deviceid)
 			return -ENODEV;
-	} else if (sbi->extra_devices) {
-		for (id = 0; id < sbi->extra_devices; ++id) {
+	} else if (sbi.extra_devices) {
+		for (id = 0; id < sbi.extra_devices; ++id) {
 			erofs_off_t startoff, length;
 
-			dif = sbi->devs + id;
+			dif = sbi.devs + id;
 			if (!dif->mapped_blkaddr)
 				continue;
-			startoff = blknr_to_addr(dif->mapped_blkaddr);
-			length = blknr_to_addr(dif->blocks);
+			startoff = erofs_pos(dif->mapped_blkaddr);
+			length = erofs_pos(dif->blocks);
 
 			if (map->m_pa >= startoff &&
 			    map->m_pa < startoff + length) {
@@ -147,19 +147,38 @@
 	return 0;
 }
 
+int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset,
+			size_t len)
+{
+	struct erofs_map_dev mdev;
+	int ret;
+
+	mdev = (struct erofs_map_dev) {
+		.m_deviceid = map->m_deviceid,
+		.m_pa = map->m_pa,
+	};
+	ret = erofs_map_dev(&mdev);
+	if (ret)
+		return ret;
+
+	ret = erofs_dev_read(mdev.m_deviceid, buffer, mdev.m_pa + offset, len);
+	if (ret < 0)
+		return -EIO;
+	return 0;
+}
+
 static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
 			       erofs_off_t size, erofs_off_t offset)
 {
 	struct erofs_map_blocks map = {
 		.index = UINT_MAX,
 	};
-	struct erofs_map_dev mdev;
 	int ret;
 	erofs_off_t ptr = offset;
 
 	while (ptr < offset + size) {
 		char *const estart = buffer + ptr - offset;
-		erofs_off_t eend;
+		erofs_off_t eend, moff = 0;
 
 		map.m_la = ptr;
 		ret = erofs_map_blocks(inode, &map, 0);
@@ -168,14 +187,6 @@
 
 		DBG_BUGON(map.m_plen != map.m_llen);
 
-		mdev = (struct erofs_map_dev) {
-			.m_deviceid = map.m_deviceid,
-			.m_pa = map.m_pa,
-		};
-		ret = erofs_map_dev(&sbi, &mdev);
-		if (ret)
-			return ret;
-
 		/* trim extent */
 		eend = min(offset + size, map.m_la + map.m_llen);
 		DBG_BUGON(ptr < map.m_la);
@@ -193,19 +204,73 @@
 		}
 
 		if (ptr > map.m_la) {
-			mdev.m_pa += ptr - map.m_la;
+			moff = ptr - map.m_la;
 			map.m_la = ptr;
 		}
 
-		ret = erofs_dev_read(mdev.m_deviceid, estart, mdev.m_pa,
-				     eend - map.m_la);
-		if (ret < 0)
-			return -EIO;
+		ret = erofs_read_one_data(&map, estart, moff, eend - map.m_la);
+		if (ret)
+			return ret;
 		ptr = eend;
 	}
 	return 0;
 }
 
+int z_erofs_read_one_data(struct erofs_inode *inode,
+			  struct erofs_map_blocks *map, char *raw, char *buffer,
+			  erofs_off_t skip, erofs_off_t length, bool trimmed)
+{
+	struct erofs_map_dev mdev;
+	int ret = 0;
+
+	if (map->m_flags & EROFS_MAP_FRAGMENT) {
+		struct erofs_inode packed_inode = {
+			.nid = sbi.packed_nid,
+		};
+
+		ret = erofs_read_inode_from_disk(&packed_inode);
+		if (ret) {
+			erofs_err("failed to read packed inode from disk");
+			return ret;
+		}
+
+		return erofs_pread(&packed_inode, buffer, length - skip,
+				   inode->fragmentoff + skip);
+	}
+
+	/* no device id here, thus it will always succeed */
+	mdev = (struct erofs_map_dev) {
+		.m_pa = map->m_pa,
+	};
+	ret = erofs_map_dev(&mdev);
+	if (ret) {
+		DBG_BUGON(1);
+		return ret;
+	}
+
+	ret = erofs_dev_read(mdev.m_deviceid, raw, mdev.m_pa, map->m_plen);
+	if (ret < 0)
+		return ret;
+
+	ret = z_erofs_decompress(&(struct z_erofs_decompress_req) {
+			.in = raw,
+			.out = buffer,
+			.decodedskip = skip,
+			.interlaced_offset =
+				map->m_algorithmformat == Z_EROFS_COMPRESSION_INTERLACED ?
+					erofs_blkoff(map->m_la) : 0,
+			.inputsize = map->m_plen,
+			.decodedlength = length,
+			.alg = map->m_algorithmformat,
+			.partial_decoding = trimmed ? true :
+				!(map->m_flags & EROFS_MAP_FULL_MAPPED) ||
+					(map->m_flags & EROFS_MAP_PARTIAL_REF),
+			 });
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
 static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 			     erofs_off_t size, erofs_off_t offset)
 {
@@ -213,8 +278,7 @@
 	struct erofs_map_blocks map = {
 		.index = UINT_MAX,
 	};
-	struct erofs_map_dev mdev;
-	bool partial;
+	bool trimmed;
 	unsigned int bufsize = 0;
 	char *raw = NULL;
 	int ret = 0;
@@ -227,27 +291,17 @@
 		if (ret)
 			break;
 
-		/* no device id here, thus it will always succeed */
-		mdev = (struct erofs_map_dev) {
-			.m_pa = map.m_pa,
-		};
-		ret = erofs_map_dev(&sbi, &mdev);
-		if (ret) {
-			DBG_BUGON(1);
-			break;
-		}
-
 		/*
 		 * trim to the needed size if the returned extent is quite
 		 * larger than requested, and set up partial flag as well.
 		 */
 		if (end < map.m_la + map.m_llen) {
 			length = end - map.m_la;
-			partial = true;
+			trimmed = true;
 		} else {
 			DBG_BUGON(end != map.m_la + map.m_llen);
 			length = map.m_llen;
-			partial = !(map.m_flags & EROFS_MAP_FULL_MAPPED);
+			trimmed = false;
 		}
 
 		if (map.m_la < offset) {
@@ -272,19 +326,10 @@
 				break;
 			}
 		}
-		ret = erofs_dev_read(mdev.m_deviceid, raw, mdev.m_pa, map.m_plen);
-		if (ret < 0)
-			break;
 
-		ret = z_erofs_decompress(&(struct z_erofs_decompress_req) {
-					.in = raw,
-					.out = buffer + end - offset,
-					.decodedskip = skip,
-					.inputsize = map.m_plen,
-					.decodedlength = length,
-					.alg = map.m_algorithmformat,
-					.partial_decoding = partial
-					 });
+		ret = z_erofs_read_one_data(inode, &map, raw,
+					    buffer + end - offset, skip, length,
+					    trimmed);
 		if (ret < 0)
 			break;
 	}
@@ -301,8 +346,8 @@
 	case EROFS_INODE_FLAT_INLINE:
 	case EROFS_INODE_CHUNK_BASED:
 		return erofs_read_raw_data(inode, buf, count, offset);
-	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
-	case EROFS_INODE_FLAT_COMPRESSION:
+	case EROFS_INODE_COMPRESSED_FULL:
+	case EROFS_INODE_COMPRESSED_COMPACT:
 		return z_erofs_read_data(inode, buf, count, offset);
 	default:
 		break;
diff --git a/fs/erofs/decompress.c b/fs/erofs/decompress.c
index 2be3b84..e04e5c3 100644
--- a/fs/erofs/decompress.c
+++ b/fs/erofs/decompress.c
@@ -15,8 +15,8 @@
 	if (erofs_sb_has_lz4_0padding()) {
 		support_0padding = true;
 
-		while (!src[inputmargin & ~PAGE_MASK])
-			if (!(++inputmargin & ~PAGE_MASK))
+		while (!src[inputmargin & (erofs_blksiz() - 1)])
+			if (!(++inputmargin & (erofs_blksiz() - 1)))
 				break;
 
 		if (inputmargin >= rq->inputsize)
@@ -40,6 +40,9 @@
 					  rq->decodedlength);
 
 	if (ret != (int)rq->decodedlength) {
+		erofs_err("failed to %s decompress %d in[%u, %u] out[%u]",
+			  rq->partial_decoding ? "partial" : "full",
+			  ret, rq->inputsize, inputmargin, rq->decodedlength);
 		ret = -EIO;
 		goto out;
 	}
@@ -58,13 +61,30 @@
 
 int z_erofs_decompress(struct z_erofs_decompress_req *rq)
 {
-	if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
-		if (rq->inputsize != EROFS_BLKSIZ)
+	if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
+		unsigned int count, rightpart, skip;
+
+		/* XXX: should support inputsize >= erofs_blksiz() later */
+		if (rq->inputsize > erofs_blksiz())
 			return -EFSCORRUPTED;
 
-		DBG_BUGON(rq->decodedlength > EROFS_BLKSIZ);
-		DBG_BUGON(rq->decodedlength < rq->decodedskip);
+		if (rq->decodedlength > erofs_blksiz())
+			return -EFSCORRUPTED;
+
+		if (rq->decodedlength < rq->decodedskip)
+			return -EFSCORRUPTED;
+
+		count = rq->decodedlength - rq->decodedskip;
+		skip = erofs_blkoff(rq->interlaced_offset + rq->decodedskip);
+		rightpart = min(erofs_blksiz() - skip, count);
+		memcpy(rq->out, rq->in + skip, rightpart);
+		memcpy(rq->out + rightpart, rq->in, count - rightpart);
+		return 0;
+	} else if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
+		if (rq->decodedlength > rq->inputsize)
+			return -EFSCORRUPTED;
 
+		DBG_BUGON(rq->decodedlength < rq->decodedskip);
 		memcpy(rq->out, rq->in + rq->decodedskip,
 		       rq->decodedlength - rq->decodedskip);
 		return 0;
diff --git a/fs/erofs/decompress.h b/fs/erofs/decompress.h
index 81d5fb8..4752f77 100644
--- a/fs/erofs/decompress.h
+++ b/fs/erofs/decompress.h
@@ -14,6 +14,9 @@
 	unsigned int decodedskip;
 	unsigned int inputsize, decodedlength;
 
+	/* cut point of interlaced uncompressed data */
+	unsigned int interlaced_offset;
+
 	/* indicate the algorithm will be used for decompression */
 	unsigned int alg;
 	bool partial_decoding;
diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h
index 6b62c7a..158e2c6 100644
--- a/fs/erofs/erofs_fs.h
+++ b/fs/erofs/erofs_fs.h
@@ -3,7 +3,7 @@
  * EROFS (Enhanced ROM File System) on-disk format definition
  *
  * Copyright (C) 2017-2018 HUAWEI, Inc.
- *             http://www.huawei.com/
+ *             https://www.huawei.com/
  * Copyright (C) 2021, Alibaba Cloud
  */
 #ifndef __EROFS_FS_H
@@ -18,33 +18,41 @@
 #define EROFS_SUPER_MAGIC_V1    0xE0F5E1E2
 #define EROFS_SUPER_OFFSET      1024
 
-#define EROFS_FEATURE_COMPAT_SB_CHKSUM		0x00000001
+#define EROFS_FEATURE_COMPAT_SB_CHKSUM          0x00000001
+#define EROFS_FEATURE_COMPAT_MTIME              0x00000002
 
 /*
  * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should
  * be incompatible with this kernel version.
  */
-#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING	0x00000001
+#define EROFS_FEATURE_INCOMPAT_ZERO_PADDING	0x00000001
 #define EROFS_FEATURE_INCOMPAT_COMPR_CFGS	0x00000002
 #define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER	0x00000002
 #define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE	0x00000004
 #define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE	0x00000008
+#define EROFS_FEATURE_INCOMPAT_COMPR_HEAD2	0x00000008
+#define EROFS_FEATURE_INCOMPAT_ZTAILPACKING	0x00000010
+#define EROFS_FEATURE_INCOMPAT_FRAGMENTS	0x00000020
+#define EROFS_FEATURE_INCOMPAT_DEDUPE		0x00000020
+#define EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES	0x00000040
 #define EROFS_ALL_FEATURE_INCOMPAT		\
-	(EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \
+	(EROFS_FEATURE_INCOMPAT_ZERO_PADDING | \
 	 EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \
 	 EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER | \
 	 EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \
-	 EROFS_FEATURE_INCOMPAT_DEVICE_TABLE)
+	 EROFS_FEATURE_INCOMPAT_DEVICE_TABLE | \
+	 EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 | \
+	 EROFS_FEATURE_INCOMPAT_ZTAILPACKING | \
+	 EROFS_FEATURE_INCOMPAT_FRAGMENTS | \
+	 EROFS_FEATURE_INCOMPAT_DEDUPE | \
+	 EROFS_FEATURE_INCOMPAT_XATTR_PREFIXES)
 
 #define EROFS_SB_EXTSLOT_SIZE	16
 
 struct erofs_deviceslot {
-	union {
-		u8 uuid[16];		/* used for device manager later */
-		u8 userdata[64];	/* digest(sha256), etc. */
-	} u;
-	__le32 blocks;			/* total fs blocks of this device */
-	__le32 mapped_blkaddr;		/* map starting at mapped_blkaddr */
+	u8 tag[64];		/* digest(sha256), etc. */
+	__le32 blocks;		/* total fs blocks of this device */
+	__le32 mapped_blkaddr;	/* map starting at mapped_blkaddr */
 	u8 reserved[56];
 };
 
@@ -55,14 +63,14 @@
 	__le32 magic;           /* file system magic number */
 	__le32 checksum;        /* crc32c(super_block) */
 	__le32 feature_compat;
-	__u8 blkszbits;         /* support block_size == PAGE_SIZE only */
+	__u8 blkszbits;         /* filesystem block size in bit shift */
 	__u8 sb_extslots;	/* superblock size = 128 + sb_extslots * 16 */
 
 	__le16 root_nid;	/* nid of root directory */
 	__le64 inos;            /* total valid ino # (== f_files - f_favail) */
 
-	__le64 build_time;      /* inode v1 time derivation */
-	__le32 build_time_nsec;	/* inode v1 time derivation in nano scale */
+	__le64 build_time;      /* compact inode time derivation */
+	__le32 build_time_nsec;	/* compact inode time derivation in ns scale */
 	__le32 blocks;          /* used for statfs */
 	__le32 meta_blkaddr;	/* start block address of metadata area */
 	__le32 xattr_blkaddr;	/* start block address of shared xattr area */
@@ -77,39 +85,38 @@
 	} __packed u1;
 	__le16 extra_devices;	/* # of devices besides the primary device */
 	__le16 devt_slotoff;	/* startoff = devt_slotoff * devt_slotsize */
-	__u8 reserved2[38];
+	__u8 dirblkbits;	/* directory block size in bit shift */
+	__u8 xattr_prefix_count;	/* # of long xattr name prefixes */
+	__le32 xattr_prefix_start;	/* start of long xattr prefixes */
+	__le64 packed_nid;	/* nid of the special packed inode */
+	__u8 reserved2[24];
 };
 
 /*
- * erofs inode datalayout (i_format in on-disk inode):
- * 0 - inode plain without inline data A:
- * inode, [xattrs], ... | ... | no-holed data
- * 1 - inode VLE compression B (legacy):
- * inode, [xattrs], extents ... | ...
- * 2 - inode plain with inline data C:
- * inode, [xattrs], last_inline_data, ... | ... | no-holed data
- * 3 - inode compression D:
- * inode, [xattrs], map_header, extents ... | ...
- * 4 - inode chunk-based E:
- * inode, [xattrs], chunk indexes ... | ...
+ * EROFS inode datalayout (i_format in on-disk inode):
+ * 0 - uncompressed flat inode without tail-packing inline data:
+ * 1 - compressed inode with non-compact indexes:
+ * 2 - uncompressed flat inode with tail-packing inline data:
+ * 3 - compressed inode with compact indexes:
+ * 4 - chunk-based inode with (optional) multi-device support:
  * 5~7 - reserved
  */
 enum {
 	EROFS_INODE_FLAT_PLAIN			= 0,
-	EROFS_INODE_FLAT_COMPRESSION_LEGACY	= 1,
+	EROFS_INODE_COMPRESSED_FULL		= 1,
 	EROFS_INODE_FLAT_INLINE			= 2,
-	EROFS_INODE_FLAT_COMPRESSION		= 3,
+	EROFS_INODE_COMPRESSED_COMPACT		= 3,
 	EROFS_INODE_CHUNK_BASED			= 4,
 	EROFS_INODE_DATALAYOUT_MAX
 };
 
 static inline bool erofs_inode_is_data_compressed(unsigned int datamode)
 {
-	return datamode == EROFS_INODE_FLAT_COMPRESSION ||
-		datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY;
+	return datamode == EROFS_INODE_COMPRESSED_COMPACT ||
+		datamode == EROFS_INODE_COMPRESSED_FULL;
 }
 
-/* bit definitions of inode i_advise */
+/* bit definitions of inode i_format */
 #define EROFS_I_VERSION_BITS            1
 #define EROFS_I_DATALAYOUT_BITS         3
 
@@ -127,11 +134,30 @@
 #define EROFS_CHUNK_FORMAT_ALL	\
 	(EROFS_CHUNK_FORMAT_BLKBITS_MASK | EROFS_CHUNK_FORMAT_INDEXES)
 
+/* 32-byte on-disk inode */
+#define EROFS_INODE_LAYOUT_COMPACT	0
+/* 64-byte on-disk inode */
+#define EROFS_INODE_LAYOUT_EXTENDED	1
+
 struct erofs_inode_chunk_info {
 	__le16 format;		/* chunk blkbits, etc. */
 	__le16 reserved;
 };
 
+union erofs_inode_i_u {
+	/* total compressed blocks for compressed inodes */
+	__le32 compressed_blocks;
+
+	/* block address for uncompressed flat inodes */
+	__le32 raw_blkaddr;
+
+	/* for device files, used to indicate old/new device # */
+	__le32 rdev;
+
+	/* for chunk-based files, it contains the summary info */
+	struct erofs_inode_chunk_info c;
+};
+
 /* 32-byte reduced form of an ondisk inode */
 struct erofs_inode_compact {
 	__le16 i_format;	/* inode format hints */
@@ -142,28 +168,14 @@
 	__le16 i_nlink;
 	__le32 i_size;
 	__le32 i_reserved;
-	union {
-		/* file total compressed blocks for data mapping 1 */
-		__le32 compressed_blocks;
-		__le32 raw_blkaddr;
+	union erofs_inode_i_u i_u;
 
-		/* for device files, used to indicate old/new device # */
-		__le32 rdev;
-
-		/* for chunk-based files, it contains the summary info */
-		struct erofs_inode_chunk_info c;
-	} i_u;
-	__le32 i_ino;           /* only used for 32-bit stat compatibility */
+	__le32 i_ino;		/* only used for 32-bit stat compatibility */
 	__le16 i_uid;
 	__le16 i_gid;
 	__le32 i_reserved2;
 };
 
-/* 32 bytes on-disk inode */
-#define EROFS_INODE_LAYOUT_COMPACT	0
-/* 64 bytes on-disk inode */
-#define EROFS_INODE_LAYOUT_EXTENDED	1
-
 /* 64-byte complete form of an ondisk inode */
 struct erofs_inode_extended {
 	__le16 i_format;	/* inode format hints */
@@ -173,33 +185,17 @@
 	__le16 i_mode;
 	__le16 i_reserved;
 	__le64 i_size;
-	union {
-		/* file total compressed blocks for data mapping 1 */
-		__le32 compressed_blocks;
-		__le32 raw_blkaddr;
+	union erofs_inode_i_u i_u;
 
-		/* for device files, used to indicate old/new device # */
-		__le32 rdev;
-
-		/* for chunk-based files, it contains the summary info */
-		struct erofs_inode_chunk_info c;
-	} i_u;
-
-	/* only used for 32-bit stat compatibility */
-	__le32 i_ino;
-
+	__le32 i_ino;		/* only used for 32-bit stat compatibility */
 	__le32 i_uid;
 	__le32 i_gid;
-	__le64 i_ctime;
-	__le32 i_ctime_nsec;
+	__le64 i_mtime;
+	__le32 i_mtime_nsec;
 	__le32 i_nlink;
 	__u8   i_reserved2[16];
 };
 
-#define EROFS_MAX_SHARED_XATTRS         (128)
-/* h_shared_count between 129 ... 255 are special # */
-#define EROFS_SHARED_XATTR_EXTENT       (255)
-
 /*
  * inline xattrs (n == i_xattr_icount):
  * erofs_xattr_ibody_header(1) + (n - 1) * 4 bytes
@@ -226,6 +222,13 @@
 #define EROFS_XATTR_INDEX_LUSTRE            5
 #define EROFS_XATTR_INDEX_SECURITY          6
 
+/*
+ * bit 7 of e_name_index is set when it refers to a long xattr name prefix,
+ * while the remained lower bits represent the index of the prefix.
+ */
+#define EROFS_XATTR_LONG_PREFIX		0x80
+#define EROFS_XATTR_LONG_PREFIX_MASK	0x7f
+
 /* xattr entry (for both inline & shared xattrs) */
 struct erofs_xattr_entry {
 	__u8   e_name_len;      /* length of name */
@@ -235,6 +238,12 @@
 	char   e_name[0];       /* attribute name */
 };
 
+/* long xattr name prefix */
+struct erofs_xattr_long_prefix {
+	__u8   base_index;	/* short xattr name prefix index */
+	char   infix[0];	/* infix apart from short prefix */
+};
+
 static inline unsigned int erofs_xattr_ibody_size(__le16 i_xattr_icount)
 {
 	if (!i_xattr_icount)
@@ -265,6 +274,29 @@
 	__le32 blkaddr;		/* start block address of this inode chunk */
 };
 
+/* dirent sorts in alphabet order, thus we can do binary search */
+struct erofs_dirent {
+	__le64 nid;     /* node number */
+	__le16 nameoff; /* start offset of file name */
+	__u8 file_type; /* file type */
+	__u8 reserved;  /* reserved */
+} __packed;
+
+/* file types used in inode_info->flags */
+enum {
+	EROFS_FT_UNKNOWN,
+	EROFS_FT_REG_FILE,
+	EROFS_FT_DIR,
+	EROFS_FT_CHRDEV,
+	EROFS_FT_BLKDEV,
+	EROFS_FT_FIFO,
+	EROFS_FT_SOCK,
+	EROFS_FT_SYMLINK,
+	EROFS_FT_MAX
+};
+
+#define EROFS_NAME_LEN      255
+
 /* maximum supported size of a physical compression cluster */
 #define Z_EROFS_PCLUSTER_MAX_SIZE	(1024 * 1024)
 
@@ -275,7 +307,7 @@
 	Z_EROFS_COMPRESSION_MAX
 };
 
-#define Z_EROFS_ALL_COMPR_ALGS		(1 << (Z_EROFS_COMPRESSION_MAX - 1))
+#define Z_EROFS_ALL_COMPR_ALGS		((1 << Z_EROFS_COMPRESSION_MAX) - 1)
 
 /* 14 bytes (+ length field = 16 bytes) */
 struct z_erofs_lz4_cfgs {
@@ -290,6 +322,7 @@
 	__le16 format;
 	u8 reserved[8];
 } __packed;
+
 #define Z_EROFS_LZMA_MAX_DICT_SIZE	(8 * Z_EROFS_PCLUSTER_MAX_SIZE)
 
 /*
@@ -298,13 +331,28 @@
  *                                  (4B) + 2B + (4B) if compacted 2B is on.
  * bit 1 : HEAD1 big pcluster (0 - off; 1 - on)
  * bit 2 : HEAD2 big pcluster (0 - off; 1 - on)
+ * bit 3 : tailpacking inline pcluster (0 - off; 1 - on)
+ * bit 4 : interlaced plain pcluster (0 - off; 1 - on)
+ * bit 5 : fragment pcluster (0 - off; 1 - on)
  */
 #define Z_EROFS_ADVISE_COMPACTED_2B		0x0001
 #define Z_EROFS_ADVISE_BIG_PCLUSTER_1		0x0002
 #define Z_EROFS_ADVISE_BIG_PCLUSTER_2		0x0004
+#define Z_EROFS_ADVISE_INLINE_PCLUSTER		0x0008
+#define Z_EROFS_ADVISE_INTERLACED_PCLUSTER	0x0010
+#define Z_EROFS_ADVISE_FRAGMENT_PCLUSTER	0x0020
 
+#define Z_EROFS_FRAGMENT_INODE_BIT              7
 struct z_erofs_map_header {
-	__le32	h_reserved1;
+	union {
+		/* fragment data offset in the packed inode */
+		__le32  h_fragmentoff;
+		struct {
+			__le16  h_reserved1;
+			/* indicates the encoded size of tailpacking data */
+			__le16  h_idata_size;
+		};
+	};
 	__le16	h_advise;
 	/*
 	 * bit 0-3 : algorithm type of head 1 (logical cluster type 01);
@@ -313,107 +361,85 @@
 	__u8	h_algorithmtype;
 	/*
 	 * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096;
-	 * bit 3-7 : reserved.
+	 * bit 3-6 : reserved;
+	 * bit 7   : move the whole file into packed inode or not.
 	 */
 	__u8	h_clusterbits;
 };
 
-#define Z_EROFS_VLE_LEGACY_HEADER_PADDING       8
-
 /*
- * Fixed-sized output compression ondisk Logical Extent cluster type:
- *    0 - literal (uncompressed) cluster
- *    1 - compressed cluster (for the head logical cluster)
- *    2 - compressed cluster (for the other logical clusters)
+ * On-disk logical cluster type:
+ *    0   - literal (uncompressed) lcluster
+ *    1,3 - compressed lcluster (for HEAD lclusters)
+ *    2   - compressed lcluster (for NONHEAD lclusters)
  *
  * In detail,
- *    0 - literal (uncompressed) cluster,
+ *    0 - literal (uncompressed) lcluster,
  *        di_advise = 0
- *        di_clusterofs = the literal data offset of the cluster
- *        di_blkaddr = the blkaddr of the literal cluster
+ *        di_clusterofs = the literal data offset of the lcluster
+ *        di_blkaddr = the blkaddr of the literal pcluster
  *
- *    1 - compressed cluster (for the head logical cluster)
- *        di_advise = 1
- *        di_clusterofs = the decompressed data offset of the cluster
- *        di_blkaddr = the blkaddr of the compressed cluster
+ *    1,3 - compressed lcluster (for HEAD lclusters)
+ *        di_advise = 1 or 3
+ *        di_clusterofs = the decompressed data offset of the lcluster
+ *        di_blkaddr = the blkaddr of the compressed pcluster
  *
- *    2 - compressed cluster (for the other logical clusters)
+ *    2 - compressed lcluster (for NONHEAD lclusters)
  *        di_advise = 2
  *        di_clusterofs =
- *           the decompressed data offset in its own head cluster
- *        di_u.delta[0] = distance to its corresponding head cluster
- *        di_u.delta[1] = distance to its corresponding tail cluster
- *                (di_advise could be 0, 1 or 2)
+ *           the decompressed data offset in its own HEAD lcluster
+ *        di_u.delta[0] = distance to this HEAD lcluster
+ *        di_u.delta[1] = distance to the next HEAD lcluster
  */
 enum {
-	Z_EROFS_VLE_CLUSTER_TYPE_PLAIN		= 0,
-	Z_EROFS_VLE_CLUSTER_TYPE_HEAD		= 1,
-	Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD	= 2,
-	Z_EROFS_VLE_CLUSTER_TYPE_RESERVED	= 3,
-	Z_EROFS_VLE_CLUSTER_TYPE_MAX
+	Z_EROFS_LCLUSTER_TYPE_PLAIN	= 0,
+	Z_EROFS_LCLUSTER_TYPE_HEAD1	= 1,
+	Z_EROFS_LCLUSTER_TYPE_NONHEAD	= 2,
+	Z_EROFS_LCLUSTER_TYPE_HEAD2	= 3,
+	Z_EROFS_LCLUSTER_TYPE_MAX
 };
 
-#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS        2
-#define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT         0
+#define Z_EROFS_LI_LCLUSTER_TYPE_BITS        2
+#define Z_EROFS_LI_LCLUSTER_TYPE_BIT         0
+
+/* (noncompact only, HEAD) This pcluster refers to partial decompressed data */
+#define Z_EROFS_LI_PARTIAL_REF		(1 << 15)
 
 /*
  * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the
  * compressed block count of a compressed extent (in logical clusters, aka.
  * block count of a pcluster).
  */
-#define Z_EROFS_VLE_DI_D0_CBLKCNT		(1 << 11)
+#define Z_EROFS_LI_D0_CBLKCNT		(1 << 11)
 
-struct z_erofs_vle_decompressed_index {
+struct z_erofs_lcluster_index {
 	__le16 di_advise;
-	/* where to decompress in the head cluster */
+	/* where to decompress in the head lcluster */
 	__le16 di_clusterofs;
 
 	union {
-		/* for the head cluster */
+		/* for the HEAD lclusters */
 		__le32 blkaddr;
 		/*
-		 * for the rest clusters
-		 * eg. for 4k page-sized cluster, maximum 4K*64k = 256M)
-		 * [0] - pointing to the head cluster
-		 * [1] - pointing to the tail cluster
+		 * for the NONHEAD lclusters
+		 * [0] - distance to its HEAD lcluster
+		 * [1] - distance to the next HEAD lcluster
 		 */
 		__le16 delta[2];
 	} di_u;
 };
 
-#define Z_EROFS_VLE_LEGACY_INDEX_ALIGN(size) \
-	(round_up(size, sizeof(struct z_erofs_vle_decompressed_index)) + \
-	 sizeof(struct z_erofs_map_header) + Z_EROFS_VLE_LEGACY_HEADER_PADDING)
-
-#define Z_EROFS_VLE_EXTENT_ALIGN(size) round_up(size, \
-	sizeof(struct z_erofs_vle_decompressed_index))
-
-/* dirent sorts in alphabet order, thus we can do binary search */
-struct erofs_dirent {
-	__le64 nid;     /* node number */
-	__le16 nameoff; /* start offset of file name */
-	__u8 file_type; /* file type */
-	__u8 reserved;  /* reserved */
-} __packed;
-
-/* file types used in inode_info->flags */
-enum {
-	EROFS_FT_UNKNOWN,
-	EROFS_FT_REG_FILE,
-	EROFS_FT_DIR,
-	EROFS_FT_CHRDEV,
-	EROFS_FT_BLKDEV,
-	EROFS_FT_FIFO,
-	EROFS_FT_SOCK,
-	EROFS_FT_SYMLINK,
-	EROFS_FT_MAX
-};
-
-#define EROFS_NAME_LEN      255
+#define Z_EROFS_FULL_INDEX_ALIGN(end)	\
+	(round_up(end, 8) + sizeof(struct z_erofs_map_header) + 8)
 
 /* check the EROFS on-disk layout strictly at compile time */
 static inline void erofs_check_ondisk_layout_definitions(void)
 {
+	const __le64 fmh __maybe_unused =
+		*(__le64 *)&(struct z_erofs_map_header) {
+			.h_clusterbits = 1 << Z_EROFS_FRAGMENT_INODE_BIT
+		};
+
 	BUILD_BUG_ON(sizeof(struct erofs_super_block) != 128);
 	BUILD_BUG_ON(sizeof(struct erofs_inode_compact) != 32);
 	BUILD_BUG_ON(sizeof(struct erofs_inode_extended) != 64);
@@ -422,15 +448,18 @@
 	BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_info) != 4);
 	BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) != 8);
 	BUILD_BUG_ON(sizeof(struct z_erofs_map_header) != 8);
-	BUILD_BUG_ON(sizeof(struct z_erofs_vle_decompressed_index) != 8);
+	BUILD_BUG_ON(sizeof(struct z_erofs_lcluster_index) != 8);
 	BUILD_BUG_ON(sizeof(struct erofs_dirent) != 12);
 	/* keep in sync between 2 index structures for better extendibility */
 	BUILD_BUG_ON(sizeof(struct erofs_inode_chunk_index) !=
-		     sizeof(struct z_erofs_vle_decompressed_index));
+		     sizeof(struct z_erofs_lcluster_index));
 	BUILD_BUG_ON(sizeof(struct erofs_deviceslot) != 128);
 
-	BUILD_BUG_ON(BIT(Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) <
-		     Z_EROFS_VLE_CLUSTER_TYPE_MAX - 1);
+	BUILD_BUG_ON(BIT(Z_EROFS_LI_LCLUSTER_TYPE_BITS) <
+		     Z_EROFS_LCLUSTER_TYPE_MAX - 1);
+	/* exclude old compiler versions like gcc 7.5.0 */
+	BUILD_BUG_ON(__builtin_constant_p(fmh) ?
+		     fmh != cpu_to_le64(1ULL << 63) : 0);
 }
 
 #endif
diff --git a/fs/erofs/fs.c b/fs/erofs/fs.c
index 8926975..7bd2e8f 100644
--- a/fs/erofs/fs.c
+++ b/fs/erofs/fs.c
@@ -25,8 +25,8 @@
 
 int erofs_blk_read(void *buf, erofs_blk_t start, u32 nblocks)
 {
-	return erofs_dev_read(0, buf, blknr_to_addr(start),
-			 blknr_to_addr(nblocks));
+	return erofs_dev_read(0, buf, erofs_pos(start),
+			 erofs_pos(nblocks));
 }
 
 int erofs_probe(struct blk_desc *fs_dev_desc,
@@ -52,7 +52,7 @@
 	struct fs_dirent dirent;
 
 	struct erofs_inode inode;
-	char dblk[EROFS_BLKSIZ];
+	char dblk[EROFS_MAX_BLOCK_SIZE];
 	unsigned int maxsize, de_end;
 	erofs_off_t pos;
 };
@@ -125,7 +125,7 @@
 		return 1;
 
 	if (!dirs->maxsize) {
-		dirs->maxsize = min_t(unsigned int, EROFS_BLKSIZ,
+		dirs->maxsize = min_t(unsigned int, EROFS_MAX_BLOCK_SIZE,
 				      dirs->inode.i_size - pos);
 
 		err = erofs_pread(&dirs->inode, dirs->dblk,
@@ -136,7 +136,7 @@
 		de = (struct erofs_dirent *)dirs->dblk;
 		dirs->de_end = le16_to_cpu(de->nameoff);
 		if (dirs->de_end < sizeof(struct erofs_dirent) ||
-		    dirs->de_end >= EROFS_BLKSIZ) {
+		    dirs->de_end >= EROFS_MAX_BLOCK_SIZE) {
 			erofs_err("invalid de[0].nameoff %u @ nid %llu",
 				  dirs->de_end, de->nid | 0ULL);
 			return -EFSCORRUPTED;
@@ -183,7 +183,7 @@
 
 	pos += sizeof(*de);
 	if (erofs_blkoff(pos) >= dirs->de_end) {
-		pos = blknr_to_addr(erofs_blknr(pos) + 1);
+		pos = erofs_pos(erofs_blknr(pos) + 1);
 		dirs->maxsize = 0;
 	}
 	dirs->pos = pos;
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 4af7c91..433a3c6 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -2,6 +2,7 @@
 #ifndef __EROFS_INTERNAL_H
 #define __EROFS_INTERNAL_H
 
+#include "linux/compat.h"
 #define __packed __attribute__((__packed__))
 
 #include <linux/stat.h>
@@ -30,8 +31,9 @@
 
 #define PAGE_MASK		(~(PAGE_SIZE - 1))
 
-#define LOG_BLOCK_SIZE          (12)
-#define EROFS_BLKSIZ            (1U << LOG_BLOCK_SIZE)
+#ifndef EROFS_MAX_BLOCK_SIZE
+#define EROFS_MAX_BLOCK_SIZE	PAGE_SIZE
+#endif
 
 #define EROFS_ISLOTBITS		5
 #define EROFS_SLOTSIZE		(1U << EROFS_ISLOTBITS)
@@ -44,11 +46,15 @@
 #define NULL_ADDR	((unsigned int)-1)
 #define NULL_ADDR_UL	((unsigned long)-1)
 
+/* global sbi */
+extern struct erofs_sb_info sbi;
+
-#define erofs_blknr(addr)       ((addr) / EROFS_BLKSIZ)
-#define erofs_blkoff(addr)      ((addr) % EROFS_BLKSIZ)
-#define blknr_to_addr(nr)       ((erofs_off_t)(nr) * EROFS_BLKSIZ)
+#define erofs_blksiz()		(1u << sbi.blkszbits)
+#define erofs_blknr(addr)       ((addr) >> sbi.blkszbits)
+#define erofs_blkoff(addr)      ((addr) & (erofs_blksiz() - 1))
+#define erofs_pos(nr)           ((erofs_off_t)(nr) << sbi.blkszbits)
 
-#define BLK_ROUND_UP(addr)	DIV_ROUND_UP(addr, EROFS_BLKSIZ)
+#define BLK_ROUND_UP(addr)	DIV_ROUND_UP(addr, 1u << sbi.blkszbits)
 
 struct erofs_buffer_head;
 
@@ -57,6 +63,8 @@
 	u32 mapped_blkaddr;
 };
 
+#define EROFS_PACKED_NID_UNALLOCATED	-1
+
 struct erofs_sb_info {
 	struct erofs_device_info *devs;
 
@@ -72,6 +80,7 @@
 	u32 build_time_nsec;
 
 	unsigned char islotbits;
+	unsigned char blkszbits;
 
 	/* what we really care is nid, rather than ino.. */
 	erofs_nid_t root_nid;
@@ -79,23 +88,29 @@
 	u64 inos;
 
 	u8 uuid[16];
+	char volume_name[16];
 
 	u16 available_compr_algs;
 	u16 lz4_max_distance;
+
 	u32 checksum;
 	u16 extra_devices;
 	union {
 		u16 devt_slotoff;		/* used for mkfs */
 		u16 device_id_mask;		/* used for others */
 	};
+	erofs_nid_t packed_nid;
+
+	u32 xattr_prefix_start;
+	u8 xattr_prefix_count;
 };
 
-/* global sbi */
-extern struct erofs_sb_info sbi;
+/* make sure that any user of the erofs headers has at least 64bit off_t type */
+extern int erofs_assert_largefile[sizeof(off_t) - 8];
 
 static inline erofs_off_t iloc(erofs_nid_t nid)
 {
-	return blknr_to_addr(sbi.meta_blkaddr) + (nid << sbi.islotbits);
+	return erofs_pos(sbi.meta_blkaddr) + (nid << sbi.islotbits);
 }
 
 #define EROFS_FEATURE_FUNCS(name, compat, feature) \
@@ -112,11 +127,15 @@
 	sbi.feature_##compat &= ~EROFS_FEATURE_##feature; \
 }
 
-EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
+EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_ZERO_PADDING)
 EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
 EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER)
 EROFS_FEATURE_FUNCS(chunked_file, incompat, INCOMPAT_CHUNKED_FILE)
 EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE)
+EROFS_FEATURE_FUNCS(ztailpacking, incompat, INCOMPAT_ZTAILPACKING)
+EROFS_FEATURE_FUNCS(fragments, incompat, INCOMPAT_FRAGMENTS)
+EROFS_FEATURE_FUNCS(dedupe, incompat, INCOMPAT_DEDUPE)
+EROFS_FEATURE_FUNCS(xattr_prefixes, incompat, INCOMPAT_XATTR_PREFIXES)
 EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
 
 #define EROFS_I_EA_INITED	(1 << 0)
@@ -130,6 +149,8 @@
 		unsigned int flags;
 		/* (mkfs.erofs) device ID containing source file */
 		u32 dev;
+		/* (mkfs.erofs) queued sub-directories blocking dump */
+		u32 subdirs_queued;
 	};
 	unsigned int i_count;
 	struct erofs_inode *i_parent;
@@ -140,8 +161,8 @@
 	u64 i_ino[2];
 	u32 i_uid;
 	u32 i_gid;
-	u64 i_ctime;
-	u32 i_ctime_nsec;
+	u64 i_mtime;
+	u32 i_mtime_nsec;
 	u32 i_nlink;
 
 	union {
@@ -154,20 +175,31 @@
 		};
 	} u;
 
+	char *i_srcpath;
+
 	unsigned char datalayout;
 	unsigned char inode_isize;
 	/* inline tail-end packing size */
 	unsigned short idata_size;
+	bool compressed_idata;
+	bool lazy_tailblock;
 
 	unsigned int xattr_isize;
 	unsigned int extent_isize;
 
+	unsigned int xattr_shared_count;
+	unsigned int *xattr_shared_xattrs;
+
 	erofs_nid_t nid;
 	struct erofs_buffer_head *bh;
 	struct erofs_buffer_head *bh_inline, *bh_data;
 
 	void *idata;
 
+	/* (ztailpacking) in order to recover uncompressed EOF data */
+	void *eof_tailraw;
+	unsigned int eof_tailrawsize;
+
 	union {
 		void *compressmeta;
 		void *chunkindexes;
@@ -176,8 +208,14 @@
 			uint8_t  z_algorithmtype[2];
 			uint8_t  z_logical_clusterbits;
 			uint8_t  z_physical_clusterblks;
+			uint64_t z_tailextent_headlcn;
+			unsigned int    z_idataoff;
+#define z_idata_size	idata_size
 		};
 	};
+	uint64_t capabilities;
+	erofs_off_t fragmentoff;
+	unsigned int fragment_size;
 };
 
 static inline bool is_inode_layout_compression(struct erofs_inode *inode)
@@ -216,6 +254,14 @@
 	};
 };
 
+static inline bool is_dot_dotdot_len(const char *name, unsigned int len)
+{
+	if (len >= 1 && name[0] != '.')
+		return false;
+
+	return len == 1 || (len == 2 && name[1] == '.');
+}
+
 static inline bool is_dot_dotdot(const char *name)
 {
 	if (name[0] != '.')
@@ -229,6 +275,8 @@
 	BH_Mapped,
 	BH_Encoded,
 	BH_FullMapped,
+	BH_Fragment,
+	BH_Partialref,
 };
 
 /* Has a disk mapping */
@@ -239,9 +287,13 @@
 #define EROFS_MAP_ENCODED	(1 << BH_Encoded)
 /* The length of extent is full */
 #define EROFS_MAP_FULL_MAPPED	(1 << BH_FullMapped)
+/* Located in the special packed inode */
+#define EROFS_MAP_FRAGMENT	(1 << BH_Fragment)
+/* The extent refers to partial decompressed data */
+#define EROFS_MAP_PARTIAL_REF	(1 << BH_Partialref)
 
 struct erofs_map_blocks {
-	char mpage[EROFS_BLKSIZ];
+	char mpage[EROFS_MAX_BLOCK_SIZE];
 
 	erofs_off_t m_pa, m_la;
 	u64 m_plen, m_llen;
@@ -257,9 +309,12 @@
  * approach instead if possible since it's more metadata lightweight.)
  */
 #define EROFS_GET_BLOCKS_FIEMAP	0x0002
+/* Used to map tail extent for tailpacking inline or fragment pcluster */
+#define EROFS_GET_BLOCKS_FINDTAIL	0x0008
 
 enum {
 	Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX,
+	Z_EROFS_COMPRESSION_INTERLACED,
 	Z_EROFS_COMPRESSION_RUNTIME_MAX
 };
 
@@ -274,6 +329,7 @@
 
 /* super.c */
 int erofs_read_superblock(void);
+void erofs_put_super(void);
 
 /* namei.c */
 int erofs_read_inode_from_disk(struct erofs_inode *vi);
@@ -283,9 +339,40 @@
 /* data.c */
 int erofs_pread(struct erofs_inode *inode, char *buf,
 		erofs_off_t count, erofs_off_t offset);
-int erofs_map_blocks(struct erofs_inode *inode,
-		     struct erofs_map_blocks *map, int flags);
-int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map);
+int erofs_map_blocks(struct erofs_inode *inode, struct erofs_map_blocks *map,
+		     int flags);
+int erofs_map_dev(struct erofs_map_dev *map);
+int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset,
+			size_t len);
+int z_erofs_read_one_data(struct erofs_inode *inode,
+			  struct erofs_map_blocks *map, char *raw, char *buffer,
+			  erofs_off_t skip, erofs_off_t length, bool trimmed);
+
+static inline int erofs_get_occupied_size(const struct erofs_inode *inode,
+					  erofs_off_t *size)
+{
+	*size = 0;
+	switch (inode->datalayout) {
+	case EROFS_INODE_FLAT_INLINE:
+	case EROFS_INODE_FLAT_PLAIN:
+	case EROFS_INODE_CHUNK_BASED:
+		*size = inode->i_size;
+		break;
+	case EROFS_INODE_COMPRESSED_FULL:
+	case EROFS_INODE_COMPRESSED_COMPACT:
+		*size = inode->u.i_blocks * erofs_blksiz();
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/* data.c */
+int erofs_getxattr(struct erofs_inode *vi, const char *name, char *buffer,
+		   size_t buffer_size);
+int erofs_listxattr(struct erofs_inode *vi, char *buffer, size_t buffer_size);
+
 /* zmap.c */
 int z_erofs_fill_inode(struct erofs_inode *vi);
 int z_erofs_map_blocks_iter(struct erofs_inode *vi,
diff --git a/fs/erofs/namei.c b/fs/erofs/namei.c
index d1d4757..bde995f 100644
--- a/fs/erofs/namei.c
+++ b/fs/erofs/namei.c
@@ -1,6 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0+
 #include "internal.h"
 
+#define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff)))
+static dev_t erofs_new_decode_dev(u32 dev)
+{
+	const unsigned int major = (dev & 0xfff00) >> 8;
+	const unsigned int minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+
+	return makedev(major, minor);
+}
+
 int erofs_read_inode_from_disk(struct erofs_inode *vi)
 {
 	int ret, ifmt;
@@ -26,7 +35,8 @@
 	case EROFS_INODE_LAYOUT_EXTENDED:
 		vi->inode_isize = sizeof(struct erofs_inode_extended);
 
-		ret = erofs_dev_read(0, buf + sizeof(*dic), inode_loc + sizeof(*dic),
+		ret = erofs_dev_read(0, buf + sizeof(*dic),
+				     inode_loc + sizeof(*dic),
 				     sizeof(*die) - sizeof(*dic));
 		if (ret < 0)
 			return -EIO;
@@ -43,7 +53,8 @@
 			break;
 		case S_IFCHR:
 		case S_IFBLK:
-			vi->u.i_rdev = 0;
+			vi->u.i_rdev =
+				erofs_new_decode_dev(le32_to_cpu(die->i_u.rdev));
 			break;
 		case S_IFIFO:
 		case S_IFSOCK:
@@ -57,8 +68,8 @@
 		vi->i_gid = le32_to_cpu(die->i_gid);
 		vi->i_nlink = le32_to_cpu(die->i_nlink);
 
-		vi->i_ctime = le64_to_cpu(die->i_ctime);
-		vi->i_ctime_nsec = le64_to_cpu(die->i_ctime_nsec);
+		vi->i_mtime = le64_to_cpu(die->i_mtime);
+		vi->i_mtime_nsec = le64_to_cpu(die->i_mtime_nsec);
 		vi->i_size = le64_to_cpu(die->i_size);
 		if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
 			/* fill chunked inode summary info */
@@ -77,7 +88,8 @@
 			break;
 		case S_IFCHR:
 		case S_IFBLK:
-			vi->u.i_rdev = 0;
+			vi->u.i_rdev =
+				erofs_new_decode_dev(le32_to_cpu(dic->i_u.rdev));
 			break;
 		case S_IFIFO:
 		case S_IFSOCK:
@@ -91,8 +103,8 @@
 		vi->i_gid = le16_to_cpu(dic->i_gid);
 		vi->i_nlink = le16_to_cpu(dic->i_nlink);
 
-		vi->i_ctime = sbi.build_time;
-		vi->i_ctime_nsec = sbi.build_time_nsec;
+		vi->i_mtime = sbi.build_time;
+		vi->i_mtime_nsec = sbi.build_time_nsec;
 
 		vi->i_size = le32_to_cpu(dic->i_size);
 		if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
@@ -111,10 +123,13 @@
 				  vi->u.chunkformat, vi->nid | 0ULL);
 			return -EOPNOTSUPP;
 		}
-		vi->u.chunkbits = LOG_BLOCK_SIZE +
+		vi->u.chunkbits = sbi.blkszbits +
 			(vi->u.chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
-	} else if (erofs_inode_is_data_compressed(vi->datalayout))
-		z_erofs_fill_inode(vi);
+	} else if (erofs_inode_is_data_compressed(vi->datalayout)) {
+		if (erofs_blksiz() != EROFS_MAX_BLOCK_SIZE)
+			return -EOPNOTSUPP;
+		return z_erofs_fill_inode(vi);
+	}
 	return 0;
 bogusimode:
 	erofs_err("bogus i_mode (%o) @ nid %llu", vi->i_mode, vi->nid | 0ULL);
@@ -163,12 +178,11 @@
 	unsigned int	ftype;
 };
 
-int erofs_namei(struct nameidata *nd,
-		const char *name, unsigned int len)
+int erofs_namei(struct nameidata *nd, const char *name, unsigned int len)
 {
 	erofs_nid_t nid = nd->nid;
 	int ret;
-	char buf[EROFS_BLKSIZ];
+	char buf[EROFS_MAX_BLOCK_SIZE];
 	struct erofs_inode vi = { .nid = nid };
 	erofs_off_t offset;
 
@@ -179,7 +193,7 @@
 	offset = 0;
 	while (offset < vi.i_size) {
 		erofs_off_t maxsize = min_t(erofs_off_t,
-					    vi.i_size - offset, EROFS_BLKSIZ);
+					    vi.i_size - offset, erofs_blksiz());
 		struct erofs_dirent *de = (void *)buf;
 		unsigned int nameoff;
 
@@ -189,7 +203,7 @@
 
 		nameoff = le16_to_cpu(de->nameoff);
 		if (nameoff < sizeof(struct erofs_dirent) ||
-		    nameoff >= PAGE_SIZE) {
+		    nameoff >= erofs_blksiz()) {
 			erofs_err("invalid de[0].nameoff %u @ nid %llu",
 				  nameoff, nid | 0ULL);
 			return -EFSCORRUPTED;
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 8277d9b..d339262 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -9,7 +9,7 @@
 	sbi->feature_incompat = feature;
 
 	/* check if current kernel meets all mandatory requirements */
-	if (feature & (~EROFS_ALL_FEATURE_INCOMPAT)) {
+	if (feature & ~EROFS_ALL_FEATURE_INCOMPAT) {
 		erofs_err("unidentified incompatible feature %x, please upgrade kernel version",
 			  feature & ~EROFS_ALL_FEATURE_INCOMPAT);
 		return false;
@@ -40,14 +40,18 @@
 
 	sbi->device_id_mask = roundup_pow_of_two(ondisk_extradevs + 1) - 1;
 	sbi->devs = calloc(ondisk_extradevs, sizeof(*sbi->devs));
+	if (!sbi->devs)
+		return -ENOMEM;
 	pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
 	for (i = 0; i < ondisk_extradevs; ++i) {
 		struct erofs_deviceslot dis;
 		int ret;
 
 		ret = erofs_dev_read(0, &dis, pos, sizeof(dis));
-		if (ret < 0)
+		if (ret < 0) {
+			free(sbi->devs);
 			return ret;
+		}
 
 		sbi->devs[i].mapped_blkaddr = dis.mapped_blkaddr;
 		sbi->total_blocks += dis.blocks;
@@ -58,42 +62,41 @@
 
 int erofs_read_superblock(void)
 {
-	char data[EROFS_BLKSIZ];
+	u8 data[EROFS_MAX_BLOCK_SIZE];
 	struct erofs_super_block *dsb;
-	unsigned int blkszbits;
 	int ret;
 
-	ret = erofs_blk_read(data, 0, 1);
+	ret = erofs_blk_read(data, 0, erofs_blknr(sizeof(data)));
 	if (ret < 0) {
-		erofs_dbg("cannot read erofs superblock: %d", ret);
+		erofs_err("cannot read erofs superblock: %d", ret);
 		return -EIO;
 	}
 	dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
 
 	ret = -EINVAL;
 	if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
-		erofs_dbg("cannot find valid erofs superblock");
+		erofs_err("cannot find valid erofs superblock");
 		return ret;
 	}
 
 	sbi.feature_compat = le32_to_cpu(dsb->feature_compat);
 
-	blkszbits = dsb->blkszbits;
-	/* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
-	if (blkszbits != LOG_BLOCK_SIZE) {
-		erofs_err("blksize %u isn't supported on this platform",
-			  1 << blkszbits);
+	sbi.blkszbits = dsb->blkszbits;
+	if (sbi.blkszbits < 9 ||
+	    sbi.blkszbits > ilog2(EROFS_MAX_BLOCK_SIZE)) {
+		erofs_err("blksize %llu isn't supported on this platform",
+			  erofs_blksiz() | 0ULL);
 		return ret;
-	}
-
-	if (!check_layout_compatibility(&sbi, dsb))
+	} else if (!check_layout_compatibility(&sbi, dsb)) {
 		return ret;
+	}
 
 	sbi.primarydevice_blocks = le32_to_cpu(dsb->blocks);
 	sbi.meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
 	sbi.xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
 	sbi.islotbits = EROFS_ISLOTBITS;
 	sbi.root_nid = le16_to_cpu(dsb->root_nid);
+	sbi.packed_nid = le64_to_cpu(dsb->packed_nid);
 	sbi.inos = le64_to_cpu(dsb->inos);
 	sbi.checksum = le32_to_cpu(dsb->checksum);
 
diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
index be2599a..4f64258 100644
--- a/fs/erofs/zmap.c
+++ b/fs/erofs/zmap.c
@@ -1,14 +1,19 @@
 // SPDX-License-Identifier: GPL-2.0+
 #include "internal.h"
 
+static int z_erofs_do_map_blocks(struct erofs_inode *vi,
+				 struct erofs_map_blocks *map,
+				 int flags);
+
 int z_erofs_fill_inode(struct erofs_inode *vi)
 {
 	if (!erofs_sb_has_big_pcluster() &&
-	    vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
+	    !erofs_sb_has_ztailpacking() && !erofs_sb_has_fragments() &&
+	    vi->datalayout == EROFS_INODE_COMPRESSED_FULL) {
 		vi->z_advise = 0;
 		vi->z_algorithmtype[0] = 0;
 		vi->z_algorithmtype[1] = 0;
-		vi->z_logical_clusterbits = LOG_BLOCK_SIZE;
+		vi->z_logical_clusterbits = sbi.blkszbits;
 
 		vi->flags |= EROFS_I_Z_INITED;
 	}
@@ -25,15 +30,23 @@
 	if (vi->flags & EROFS_I_Z_INITED)
 		return 0;
 
-	DBG_BUGON(!erofs_sb_has_big_pcluster() &&
-		  vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
 	pos = round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
-
 	ret = erofs_dev_read(0, buf, pos, sizeof(buf));
 	if (ret < 0)
 		return -EIO;
 
 	h = (struct z_erofs_map_header *)buf;
+	/*
+	 * if the highest bit of the 8-byte map header is set, the whole file
+	 * is stored in the packed inode. The rest bits keeps z_fragmentoff.
+	 */
+	if (h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT) {
+		vi->z_advise = Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
+		vi->fragmentoff = le64_to_cpu(*(__le64 *)h) ^ (1ULL << 63);
+		vi->z_tailextent_headlcn = 0;
+		goto out;
+	}
+
 	vi->z_advise = le16_to_cpu(h->h_advise);
 	vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
 	vi->z_algorithmtype[1] = h->h_algorithmtype >> 4;
@@ -44,14 +57,41 @@
 		return -EOPNOTSUPP;
 	}
 
-	vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7);
-	if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION &&
+	vi->z_logical_clusterbits = sbi.blkszbits + (h->h_clusterbits & 7);
+	if (vi->datalayout == EROFS_INODE_COMPRESSED_COMPACT &&
 	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^
 	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) {
 		erofs_err("big pcluster head1/2 of compact indexes should be consistent for nid %llu",
 			  vi->nid * 1ULL);
 		return -EFSCORRUPTED;
 	}
+
+	if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER) {
+		struct erofs_map_blocks map = { .index = UINT_MAX };
+
+		vi->idata_size = le16_to_cpu(h->h_idata_size);
+		ret = z_erofs_do_map_blocks(vi, &map,
+					    EROFS_GET_BLOCKS_FINDTAIL);
+		if (!map.m_plen ||
+		    erofs_blkoff(map.m_pa) + map.m_plen > erofs_blksiz()) {
+			erofs_err("invalid tail-packing pclustersize %llu",
+				  map.m_plen | 0ULL);
+			return -EFSCORRUPTED;
+		}
+		if (ret < 0)
+			return ret;
+	}
+	if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER &&
+	    !(h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT)) {
+		struct erofs_map_blocks map = { .index = UINT_MAX };
+
+		vi->fragmentoff = le32_to_cpu(h->h_fragmentoff);
+		ret = z_erofs_do_map_blocks(vi, &map,
+					    EROFS_GET_BLOCKS_FINDTAIL);
+		if (ret < 0)
+			return ret;
+	}
+out:
 	vi->flags |= EROFS_I_Z_INITED;
 	return 0;
 }
@@ -66,7 +106,9 @@
 	u8  type, headtype;
 	u16 clusterofs;
 	u16 delta[2];
-	erofs_blk_t pblk, compressedlcs;
+	erofs_blk_t pblk, compressedblks;
+	erofs_off_t nextpackoff;
+	bool partialref;
 };
 
 static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
@@ -93,11 +135,10 @@
 {
 	struct erofs_inode *const vi = m->inode;
 	const erofs_off_t ibase = iloc(vi->nid);
-	const erofs_off_t pos =
-		Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize +
-					       vi->xattr_isize) +
-		lcn * sizeof(struct z_erofs_vle_decompressed_index);
-	struct z_erofs_vle_decompressed_index *di;
+	const erofs_off_t pos = Z_EROFS_FULL_INDEX_ALIGN(ibase +
+			vi->inode_isize + vi->xattr_isize) +
+		lcn * sizeof(struct z_erofs_lcluster_index);
+	struct z_erofs_lcluster_index *di;
 	unsigned int advise, type;
 	int err;
 
@@ -105,29 +146,32 @@
 	if (err)
 		return err;
 
+	m->nextpackoff = pos + sizeof(struct z_erofs_lcluster_index);
 	m->lcn = lcn;
 	di = m->kaddr + erofs_blkoff(pos);
 
 	advise = le16_to_cpu(di->di_advise);
-	type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) &
-		((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1);
+	type = (advise >> Z_EROFS_LI_LCLUSTER_TYPE_BIT) &
+		((1 << Z_EROFS_LI_LCLUSTER_TYPE_BITS) - 1);
 	switch (type) {
-	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+	case Z_EROFS_LCLUSTER_TYPE_NONHEAD:
 		m->clusterofs = 1 << vi->z_logical_clusterbits;
 		m->delta[0] = le16_to_cpu(di->di_u.delta[0]);
-		if (m->delta[0] & Z_EROFS_VLE_DI_D0_CBLKCNT) {
+		if (m->delta[0] & Z_EROFS_LI_D0_CBLKCNT) {
 			if (!(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) {
 				DBG_BUGON(1);
 				return -EFSCORRUPTED;
 			}
-			m->compressedlcs = m->delta[0] &
-				~Z_EROFS_VLE_DI_D0_CBLKCNT;
+			m->compressedblks = m->delta[0] &
+				~Z_EROFS_LI_D0_CBLKCNT;
 			m->delta[0] = 1;
 		}
 		m->delta[1] = le16_to_cpu(di->di_u.delta[1]);
 		break;
-	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
-	case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+	case Z_EROFS_LCLUSTER_TYPE_PLAIN:
+	case Z_EROFS_LCLUSTER_TYPE_HEAD1:
+		if (advise & Z_EROFS_LI_PARTIAL_REF)
+			m->partialref = true;
 		m->clusterofs = le16_to_cpu(di->di_clusterofs);
 		m->pblk = le32_to_cpu(di->di_u.blkaddr);
 		break;
@@ -164,25 +208,25 @@
 		lo = decode_compactedbits(lclusterbits, lomask,
 					  in, encodebits * i, &type);
 
-		if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+		if (type != Z_EROFS_LCLUSTER_TYPE_NONHEAD)
 			return d1;
 		++d1;
 	} while (++i < vcnt);
 
-	/* vcnt - 1 (Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) item */
-	if (!(lo & Z_EROFS_VLE_DI_D0_CBLKCNT))
+	/* vcnt - 1 (Z_EROFS_LCLUSTER_TYPE_NONHEAD) item */
+	if (!(lo & Z_EROFS_LI_D0_CBLKCNT))
 		d1 += lo - 1;
 	return d1;
 }
 
 static int unpack_compacted_index(struct z_erofs_maprecorder *m,
 				  unsigned int amortizedshift,
-				  unsigned int eofs, bool lookahead)
+				  erofs_off_t pos, bool lookahead)
 {
 	struct erofs_inode *const vi = m->inode;
 	const unsigned int lclusterbits = vi->z_logical_clusterbits;
 	const unsigned int lomask = (1 << lclusterbits) - 1;
-	unsigned int vcnt, base, lo, encodebits, nblk;
+	unsigned int vcnt, base, lo, encodebits, nblk, eofs;
 	int i;
 	u8 *in, type;
 	bool big_pcluster;
@@ -194,8 +238,12 @@
 	else
 		return -EOPNOTSUPP;
 
+	/* it doesn't equal to round_up(..) */
+	m->nextpackoff = round_down(pos, vcnt << amortizedshift) +
+			 (vcnt << amortizedshift);
 	big_pcluster = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1;
 	encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt;
+	eofs = erofs_blkoff(pos);
 	base = round_down(eofs, vcnt << amortizedshift);
 	in = m->kaddr + base;
 
@@ -204,20 +252,19 @@
 	lo = decode_compactedbits(lclusterbits, lomask,
 				  in, encodebits * i, &type);
 	m->type = type;
-	if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
+	if (type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
 		m->clusterofs = 1 << lclusterbits;
 
 		/* figure out lookahead_distance: delta[1] if needed */
 		if (lookahead)
 			m->delta[1] = get_compacted_la_distance(lclusterbits,
-								encodebits,
-								vcnt, in, i);
-		if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) {
+								encodebits, vcnt, in, i);
+		if (lo & Z_EROFS_LI_D0_CBLKCNT) {
 			if (!big_pcluster) {
 				DBG_BUGON(1);
 				return -EFSCORRUPTED;
 			}
-			m->compressedlcs = lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT;
+			m->compressedblks = lo & ~Z_EROFS_LI_D0_CBLKCNT;
 			m->delta[0] = 1;
 			return 0;
 		} else if (i + 1 != (int)vcnt) {
@@ -231,9 +278,9 @@
 		 */
 		lo = decode_compactedbits(lclusterbits, lomask,
 					  in, encodebits * (i - 1), &type);
-		if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+		if (type != Z_EROFS_LCLUSTER_TYPE_NONHEAD)
 			lo = 0;
-		else if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT)
+		else if (lo & Z_EROFS_LI_D0_CBLKCNT)
 			lo = 1;
 		m->delta[0] = lo + 1;
 		return 0;
@@ -247,7 +294,7 @@
 			--i;
 			lo = decode_compactedbits(lclusterbits, lomask,
 						  in, encodebits * i, &type);
-			if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+			if (type == Z_EROFS_LCLUSTER_TYPE_NONHEAD)
 				i -= lo;
 
 			if (i >= 0)
@@ -259,13 +306,13 @@
 			--i;
 			lo = decode_compactedbits(lclusterbits, lomask,
 						  in, encodebits * i, &type);
-			if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
-				if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) {
+			if (type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
+				if (lo & Z_EROFS_LI_D0_CBLKCNT) {
 					--i;
-					nblk += lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT;
+					nblk += lo & ~Z_EROFS_LI_D0_CBLKCNT;
 					continue;
 				}
-				if (lo == 1) {
+				if (lo <= 1) {
 					DBG_BUGON(1);
 					/* --i; ++nblk;	continue; */
 					return -EFSCORRUPTED;
@@ -289,7 +336,7 @@
 	const erofs_off_t ebase = round_up(iloc(vi->nid) + vi->inode_isize +
 					   vi->xattr_isize, 8) +
 		sizeof(struct z_erofs_map_header);
-	const unsigned int totalidx = DIV_ROUND_UP(vi->i_size, EROFS_BLKSIZ);
+	const unsigned int totalidx = BLK_ROUND_UP(vi->i_size);
 	unsigned int compacted_4b_initial, compacted_2b;
 	unsigned int amortizedshift;
 	erofs_off_t pos;
@@ -307,7 +354,8 @@
 	if (compacted_4b_initial == 32 / 4)
 		compacted_4b_initial = 0;
 
-	if (vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B)
+	if ((vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) &&
+	    compacted_4b_initial < totalidx)
 		compacted_2b = rounddown(totalidx - compacted_4b_initial, 16);
 	else
 		compacted_2b = 0;
@@ -332,8 +380,7 @@
 	err = z_erofs_reload_indexes(m, erofs_blknr(pos));
 	if (err)
 		return err;
-	return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos),
-				      lookahead);
+	return unpack_compacted_index(m, amortizedshift, pos, lookahead);
 }
 
 static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m,
@@ -341,10 +388,10 @@
 {
 	const unsigned int datamode = m->inode->datalayout;
 
-	if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
+	if (datamode == EROFS_INODE_COMPRESSED_FULL)
 		return legacy_load_cluster_from_disk(m, lcn);
 
-	if (datamode == EROFS_INODE_FLAT_COMPRESSION)
+	if (datamode == EROFS_INODE_COMPRESSED_COMPACT)
 		return compacted_load_cluster_from_disk(m, lcn, lookahead);
 
 	return -EINVAL;
@@ -373,7 +420,7 @@
 		return err;
 
 	switch (m->type) {
-	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+	case Z_EROFS_LCLUSTER_TYPE_NONHEAD:
 		if (!m->delta[0]) {
 			erofs_err("invalid lookback distance 0 @ nid %llu",
 				  (unsigned long long)vi->nid);
@@ -381,8 +428,8 @@
 			return -EFSCORRUPTED;
 		}
 		return z_erofs_extent_lookback(m, m->delta[0]);
-	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
-	case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+	case Z_EROFS_LCLUSTER_TYPE_PLAIN:
+	case Z_EROFS_LCLUSTER_TYPE_HEAD1:
 		m->headtype = m->type;
 		map->m_la = (lcn << lclusterbits) | m->clusterofs;
 		break;
@@ -404,16 +451,17 @@
 	unsigned long lcn;
 	int err;
 
+	DBG_BUGON(m->type != Z_EROFS_LCLUSTER_TYPE_PLAIN &&
+		  m->type != Z_EROFS_LCLUSTER_TYPE_HEAD1);
+
-	DBG_BUGON(m->type != Z_EROFS_VLE_CLUSTER_TYPE_PLAIN &&
-		  m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD);
-	if (m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN ||
+	if (m->headtype == Z_EROFS_LCLUSTER_TYPE_PLAIN ||
 	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) {
 		map->m_plen = 1 << lclusterbits;
 		return 0;
 	}
 
 	lcn = m->lcn + 1;
-	if (m->compressedlcs)
+	if (m->compressedblks)
 		goto out;
 
 	err = z_erofs_load_cluster_from_disk(m, lcn, false);
@@ -422,28 +470,28 @@
 
 	/*
 	 * If the 1st NONHEAD lcluster has already been handled initially w/o
-	 * valid compressedlcs, which means at least it mustn't be CBLKCNT, or
+	 * valid compressedblks, which means at least it mustn't be CBLKCNT, or
 	 * an internal implemenatation error is detected.
 	 *
 	 * The following code can also handle it properly anyway, but let's
 	 * BUG_ON in the debugging mode only for developers to notice that.
 	 */
 	DBG_BUGON(lcn == initial_lcn &&
-		  m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD);
+		  m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD);
 
 	switch (m->type) {
-	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
-	case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+	case Z_EROFS_LCLUSTER_TYPE_PLAIN:
+	case Z_EROFS_LCLUSTER_TYPE_HEAD1:
 		/*
 		 * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type
 		 * rather than CBLKCNT, it's a 1 lcluster-sized pcluster.
 		 */
-		m->compressedlcs = 1;
+		m->compressedblks = 1 << (lclusterbits - sbi.blkszbits);
 		break;
-	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+	case Z_EROFS_LCLUSTER_TYPE_NONHEAD:
 		if (m->delta[0] != 1)
 			goto err_bonus_cblkcnt;
-		if (m->compressedlcs)
+		if (m->compressedblks)
 			break;
 		/* fallthrough */
 	default:
@@ -453,7 +501,7 @@
 		return -EFSCORRUPTED;
 	}
 out:
-	map->m_plen = m->compressedlcs << lclusterbits;
+	map->m_plen = m->compressedblks << sbi.blkszbits;
 	return 0;
 err_bonus_cblkcnt:
 	erofs_err("bogus CBLKCNT @ lcn %lu of nid %llu",
@@ -481,11 +529,11 @@
 		if (err)
 			return err;
 
-		if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
+		if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
 			DBG_BUGON(!m->delta[1] &&
 				  m->clusterofs != 1 << lclusterbits);
-		} else if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN ||
-			   m->type == Z_EROFS_VLE_CLUSTER_TYPE_HEAD) {
+		} else if (m->type == Z_EROFS_LCLUSTER_TYPE_PLAIN ||
+			   m->type == Z_EROFS_LCLUSTER_TYPE_HEAD1) {
 			/* go on until the next HEAD lcluster */
 			if (lcn != headlcn)
 				break;
@@ -504,10 +552,12 @@
 	return 0;
 }
 
-int z_erofs_map_blocks_iter(struct erofs_inode *vi,
-			    struct erofs_map_blocks *map,
-			    int flags)
+static int z_erofs_do_map_blocks(struct erofs_inode *vi,
+				 struct erofs_map_blocks *map,
+				 int flags)
 {
+	bool ztailpacking = vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER;
+	bool fragment = vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
 	struct z_erofs_maprecorder m = {
 		.inode = vi,
 		.map = map,
@@ -518,20 +568,8 @@
 	unsigned long initial_lcn;
 	unsigned long long ofs, end;
 
-	/* when trying to read beyond EOF, leave it unmapped */
-	if (map->m_la >= vi->i_size) {
-		map->m_llen = map->m_la + 1 - vi->i_size;
-		map->m_la = vi->i_size;
-		map->m_flags = 0;
-		goto out;
-	}
-
-	err = z_erofs_fill_inode_lazy(vi);
-	if (err)
-		goto out;
-
 	lclusterbits = vi->z_logical_clusterbits;
-	ofs = map->m_la;
+	ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? vi->i_size - 1 : map->m_la;
 	initial_lcn = ofs >> lclusterbits;
 	endoff = ofs & ((1 << lclusterbits) - 1);
 
@@ -539,11 +577,14 @@
 	if (err)
 		goto out;
 
+	if (ztailpacking && (flags & EROFS_GET_BLOCKS_FINDTAIL))
+		vi->z_idataoff = m.nextpackoff;
+
 	map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_ENCODED;
 	end = (m.lcn + 1ULL) << lclusterbits;
 	switch (m.type) {
-	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
-	case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+	case Z_EROFS_LCLUSTER_TYPE_PLAIN:
+	case Z_EROFS_LCLUSTER_TYPE_HEAD1:
 		if (endoff >= m.clusterofs) {
 			m.headtype = m.type;
 			map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
@@ -560,7 +601,7 @@
 		map->m_flags |= EROFS_MAP_FULL_MAPPED;
 		m.delta[0] = 1;
 		/* fallthrough */
-	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+	case Z_EROFS_LCLUSTER_TYPE_NONHEAD:
 		/* get the correspoinding first chunk */
 		err = z_erofs_extent_lookback(&m, m.delta[0]);
 		if (err)
@@ -572,18 +613,43 @@
 		err = -EOPNOTSUPP;
 		goto out;
 	}
-
+	if (m.partialref)
+		map->m_flags |= EROFS_MAP_PARTIAL_REF;
 	map->m_llen = end - map->m_la;
-	map->m_pa = blknr_to_addr(m.pblk);
-
-	err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
-	if (err)
-		goto out;
+	if (flags & EROFS_GET_BLOCKS_FINDTAIL) {
+		vi->z_tailextent_headlcn = m.lcn;
+		/* for non-compact indexes, fragmentoff is 64 bits */
+		if (fragment && vi->datalayout == EROFS_INODE_COMPRESSED_FULL)
+			vi->fragmentoff |= (u64)m.pblk << 32;
+	}
+	if (ztailpacking && m.lcn == vi->z_tailextent_headlcn) {
+		map->m_flags |= EROFS_MAP_META;
+		map->m_pa = vi->z_idataoff;
+		map->m_plen = vi->z_idata_size;
+	} else if (fragment && m.lcn == vi->z_tailextent_headlcn) {
+		map->m_flags |= EROFS_MAP_FRAGMENT;
+	} else {
+		map->m_pa = erofs_pos(m.pblk);
+		err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
+		if (err)
+			goto out;
+	}
 
-	if (m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN)
-		map->m_algorithmformat = Z_EROFS_COMPRESSION_SHIFTED;
-	else
+	if (m.headtype == Z_EROFS_LCLUSTER_TYPE_PLAIN) {
+		if (map->m_llen > map->m_plen) {
+			DBG_BUGON(1);
+			err = -EFSCORRUPTED;
+			goto out;
+		}
+		if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER)
+			map->m_algorithmformat =
+				Z_EROFS_COMPRESSION_INTERLACED;
+		else
+			map->m_algorithmformat =
+				Z_EROFS_COMPRESSION_SHIFTED;
+	} else {
 		map->m_algorithmformat = vi->z_algorithmtype[0];
+	}
 
 	if (flags & EROFS_GET_BLOCKS_FIEMAP) {
 		err = z_erofs_get_extent_decompressedlen(&m);
@@ -595,7 +661,38 @@
 	erofs_dbg("m_la %" PRIu64 " m_pa %" PRIu64 " m_llen %" PRIu64 " m_plen %" PRIu64 " m_flags 0%o",
 		  map->m_la, map->m_pa,
 		  map->m_llen, map->m_plen, map->m_flags);
+	return err;
+}
 
+int z_erofs_map_blocks_iter(struct erofs_inode *vi,
+			    struct erofs_map_blocks *map,
+			    int flags)
+{
+	int err = 0;
+
+	/* when trying to read beyond EOF, leave it unmapped */
+	if (map->m_la >= vi->i_size) {
+		map->m_llen = map->m_la + 1 - vi->i_size;
+		map->m_la = vi->i_size;
+		map->m_flags = 0;
+		goto out;
+	}
+
+	err = z_erofs_fill_inode_lazy(vi);
+	if (err)
+		goto out;
+
+	if ((vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) &&
+	    !vi->z_tailextent_headlcn) {
+		map->m_la = 0;
+		map->m_llen = vi->i_size;
+		map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_FULL_MAPPED |
+				EROFS_MAP_FRAGMENT;
+		goto out;
+	}
+
+	err = z_erofs_do_map_blocks(vi, map, flags);
+out:
 	DBG_BUGON(err < 0 && err != -ENOMEM);
 	return err;
 }
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 2da93da..d1476aa 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -8,6 +8,8 @@
  * 2003-03-10 - kharris@nexus-tech.net - ported to uboot
  */
 
+#define LOG_CATEGORY	LOGC_FS
+
 #include <common.h>
 #include <blk.h>
 #include <config.h>
@@ -97,8 +99,8 @@
 	/* Read the partition table, if present */
 	if (part_get_info(dev_desc, part_no, &info)) {
 		if (part_no != 0) {
-			printf("** Partition %d not valid on device %d **\n",
-					part_no, dev_desc->devnum);
+			log_err("Partition %d invalid on device %d\n", part_no,
+				dev_desc->devnum);
 			return -1;
 		}
 
@@ -168,7 +170,7 @@
 	__u32 ret = 0x00;
 
 	if (CHECK_CLUST(entry, mydata->fatsize)) {
-		printf("Error: Invalid FAT entry: 0x%08x\n", entry);
+		log_err("Invalid FAT entry: %#08x\n", entry);
 		return ret;
 	}
 
@@ -586,19 +588,19 @@
 	mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
 	mydata->clust_size = bs.cluster_size;
 	if (mydata->sect_size != cur_part_info.blksz) {
-		printf("Error: FAT sector size mismatch (fs=%hu, dev=%lu)\n",
-				mydata->sect_size, cur_part_info.blksz);
+		log_err("FAT sector size mismatch (fs=%u, dev=%lu)\n",
+			mydata->sect_size, cur_part_info.blksz);
 		return -1;
 	}
 	if (mydata->clust_size == 0) {
-		printf("Error: FAT cluster size not set\n");
+		log_err("FAT cluster size not set\n");
 		return -1;
 	}
 	if ((unsigned int)mydata->clust_size * mydata->sect_size >
 	    MAX_CLUSTSIZE) {
-		printf("Error: FAT cluster size too big (cs=%u, max=%u)\n",
-		       (unsigned int)mydata->clust_size * mydata->sect_size,
-		       MAX_CLUSTSIZE);
+		log_err("FAT cluster size too big (cs=%u, max=%u)\n",
+			(uint)mydata->clust_size * mydata->sect_size,
+			MAX_CLUSTSIZE);
 		return -1;
 	}
 
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index 413fc43..e2a9913 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -1571,8 +1571,9 @@
 	char *filename_copy, *dirname, *basename;
 
 	filename_copy = strdup(filename);
-	if (!filename_copy) {
-		printf("Error: allocating memory\n");
+	itr = malloc_cache_aligned(sizeof(fat_itr));
+	if (!itr || !filename_copy) {
+		printf("Error: out of memory\n");
 		ret = -ENOMEM;
 		goto exit;
 	}
@@ -1584,13 +1585,6 @@
 		goto exit;
 	}
 
-	itr = malloc_cache_aligned(sizeof(fat_itr));
-	if (!itr) {
-		printf("Error: allocating memory\n");
-		ret = -ENOMEM;
-		goto exit;
-	}
-
 	ret = fat_itr_root(itr, &fsdata);
 	if (ret)
 		goto exit;
@@ -1605,7 +1599,7 @@
 	}
 
 	if (!find_directory_entry(itr, basename)) {
-		printf("%s: doesn't exist\n", basename);
+		log_err("%s: doesn't exist (%d)\n", basename, -ENOENT);
 		ret = -ENOENT;
 		goto exit;
 	}
diff --git a/fs/fs.c b/fs/fs.c
index 8324b4a..2b815b1 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -13,6 +13,7 @@
 #include <env.h>
 #include <lmb.h>
 #include <log.h>
+#include <malloc.h>
 #include <mapmem.h>
 #include <part.h>
 #include <ext4fs.h>
@@ -26,6 +27,7 @@
 #include <asm/io.h>
 #include <div64.h>
 #include <linux/math64.h>
+#include <linux/sizes.h>
 #include <efi_loader.h>
 #include <squashfs.h>
 #include <erofs.h>
@@ -1008,3 +1010,59 @@
 	puts("\n");
 	return CMD_RET_SUCCESS;
 }
+
+int fs_read_alloc(const char *fname, ulong size, uint align, void **bufp)
+{
+	loff_t bytes_read;
+	ulong addr;
+	char *buf;
+	int ret;
+
+	buf = memalign(align, size + 1);
+	if (!buf)
+		return log_msg_ret("buf", -ENOMEM);
+	addr = map_to_sysmem(buf);
+
+	ret = fs_read(fname, addr, 0, size, &bytes_read);
+	if (ret) {
+		free(buf);
+		return log_msg_ret("read", ret);
+	}
+	if (size != bytes_read)
+		return log_msg_ret("bread", -EIO);
+	buf[size] = '\0';
+
+	*bufp = buf;
+
+	return 0;
+}
+
+int fs_load_alloc(const char *ifname, const char *dev_part_str,
+		  const char *fname, ulong max_size, ulong align, void **bufp,
+		  ulong *sizep)
+{
+	loff_t size;
+	void *buf;
+	int ret;
+
+	if (fs_set_blk_dev(ifname, dev_part_str, FS_TYPE_ANY))
+		return log_msg_ret("set", -ENOMEDIUM);
+
+	ret = fs_size(fname, &size);
+	if (ret)
+		return log_msg_ret("sz", -ENOENT);
+
+	if (size >= (max_size ?: SZ_1G))
+		return log_msg_ret("sz", -E2BIG);
+
+	if (fs_set_blk_dev(ifname, dev_part_str, FS_TYPE_ANY))
+		return log_msg_ret("set", -ENOMEDIUM);
+
+	ret = fs_read_alloc(fname, size, align, &buf);
+	if (ret)
+		return log_msg_ret("al", ret);
+	*sizep = size;
+	*bufp = buf;
+
+	return 0;
+}
diff --git a/fs/sandbox/host_bootdev.c b/fs/sandbox/host_bootdev.c
index 0d12ee4..3ef5362 100644
--- a/fs/sandbox/host_bootdev.c
+++ b/fs/sandbox/host_bootdev.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Bootdevice for MMC
+ * Bootdev for sandbox host
  *
  * Copyright 2021 Google LLC
  * Written by Simon Glass <sjg@chromium.org>
diff --git a/include/android_ab.h b/include/android_ab.h
index 3eb6112..1fee758 100644
--- a/include/android_ab.h
+++ b/include/android_ab.h
@@ -30,6 +30,7 @@
  * @param[in] part_info Place to store the partition information
  * Return: The slot number (>= 0) on success, or a negative on error
  */
-int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info);
+int ab_select_slot(struct blk_desc *dev_desc, struct disk_partition *part_info,
+                   bool dec_tries);
 
 #endif /* __ANDROID_AB_H */
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index a1e1b9d..8fc205d 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -301,6 +301,12 @@
 	 * @timebase_l: low 32 bits of timer
 	 */
 	unsigned int timebase_l;
+	/**
+	 * @malloc_start: start of malloc() region
+	 */
+#if CONFIG_IS_ENABLED(CMD_BDINFO_EXTRA)
+	unsigned long malloc_start;
+#endif
 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
 	/**
 	 * @malloc_base: base address of early malloc()
@@ -560,6 +566,13 @@
 #define gd_event_state()	NULL
 #endif
 
+#if CONFIG_IS_ENABLED(CMD_BDINFO_EXTRA)
+#define gd_malloc_start()		gd->malloc_start
+#define gd_set_malloc_start(_val)	gd->malloc_start = (_val)
+#else
+#define gd_malloc_start()	0
+#define gd_set_malloc_start(val)
+#endif
 /**
  * enum gd_flags - global data flags
  *
diff --git a/include/bloblist.h b/include/bloblist.h
index 2a2f170..7ea72c6 100644
--- a/include/bloblist.h
+++ b/include/bloblist.h
@@ -113,6 +113,7 @@
 	BLOBLISTT_PROJECT_AREA = 0x8000,
 	BLOBLISTT_U_BOOT_SPL_HANDOFF = 0x8000, /* Hand-off info from SPL */
 	BLOBLISTT_VBE		= 0x8001,	/* VBE per-phase state */
+	BLOBLISTT_U_BOOT_VIDEO = 0x8002, /* Video information from SPL */
 
 	/*
 	 * Vendor-specific tags are permitted here. Projects can be open source
diff --git a/include/bootdev.h b/include/bootdev.h
index e72ef36..1533adf 100644
--- a/include/bootdev.h
+++ b/include/bootdev.h
@@ -200,7 +200,7 @@
  * All fields in @bflow must be set up. Note that @bflow->dev is used to add the
  * bootflow to that device.
  *
- * @dev: Bootdevice device to add to
+ * @dev: Bootdev device to add to
  * @bflow: Bootflow to add. Note that fields within bflow must be allocated
  *	since this function takes over ownership of these. This functions makes
  *	a copy of @bflow itself (without allocating its fields again), so the
diff --git a/include/bootflow.h b/include/bootflow.h
index f20f575..4152577 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -58,7 +58,7 @@
  *
  * @bm_node: Points to siblings in the same bootdev
  * @glob_node: Points to siblings in the global list (all bootdev)
- * @dev: Bootdevice device which produced this bootflow
+ * @dev: Bootdev device which produced this bootflow
  * @blk: Block device which contains this bootflow, NULL if this is a network
  *	device or sandbox 'host' device
  * @part: Partition number (0 for whole device)
@@ -81,6 +81,8 @@
  * @fdt_size: Size of FDT file
  * @fdt_addr: Address of loaded fdt
  * @flags: Flags for the bootflow (see enum bootflow_flags_t)
+ * @cmdline: OS command line, or NULL if not known (allocated)
+ * @x86_setup: Pointer to x86 setup block inside @buf, NULL if not present
  */
 struct bootflow {
 	struct list_head bm_node;
@@ -104,6 +106,8 @@
 	int fdt_size;
 	ulong fdt_addr;
 	int flags;
+	char *cmdline;
+	char *x86_setup;
 };
 
 /**
@@ -440,4 +444,98 @@
 int bootflow_menu_run(struct bootstd_priv *std, bool text_mode,
 		      struct bootflow **bflowp);
 
+#define BOOTFLOWCL_EMPTY	((void *)1)
+
+/**
+ * cmdline_set_arg() - Update or read an argument in a cmdline string
+ *
+ * Handles updating a single arg in a cmdline string, returning it in a supplied
+ * buffer; also reading an arg from a cmdline string
+ *
+ * When updating, consecutive spaces are squashed as are spaces at the start and
+ * end.
+ *
+ * @buf: Working buffer to use (initial contents are ignored). Use NULL when
+ * reading
+ * @maxlen: Length of working buffer. Use 0 when reading
+ * @cmdline: Command line to update, in the form:
+ *
+ *	fred mary= jane=123 john="has spaces"
+ *
+ * @set_arg: Argument to set or read (may or may not exist)
+ * @new_val: Value for the new argument. May not include quotes (") but may
+ * include embedded spaces, in which case it will be quoted when added to the
+ * command line. Use NULL to delete the argument from @cmdline, BOOTFLOWCL_EMPTY
+ * to set it to an empty value (no '=' sign after arg), "" to add an '=' sign
+ * but with an empty value. Use NULL when reading.
+ * @posp: Ignored when setting an argument; when getting an argument, returns
+ * the start position of its value in @cmdline, after the first quote, if any
+ *
+ * Return:
+ * For updating:
+ *	length of new buffer (including \0 terminator) on success, -ENOENT if
+ *	@new_val is NULL and @set_arg does not exist in @from, -EINVAL if a
+ *	quoted arg-value in @from is not terminated with a quote, -EBADF if
+ *	@new_val has spaces but does not start and end with quotes (or it has
+ *	quotes in the middle of the string), -E2BIG if @maxlen is too small
+ * For reading:
+ *	length of arg value (excluding quotes), -ENOENT if not found
+ */
+int cmdline_set_arg(char *buf, int maxlen, const char *cmdline,
+		    const char *set_arg, const char *new_val, int *posp);
+
+/**
+ * bootflow_cmdline_set_arg() - Set a single argument for a bootflow
+ *
+ * Update the allocated cmdline and set the bootargs variable
+ *
+ * @bflow: Bootflow to update
+ * @arg: Argument to update (e.g. "console")
+ * @val: Value to set (e.g. "ttyS2") or NULL to delete the argument if present,
+ * "" to set it to an empty value (e.g. "console=") and BOOTFLOWCL_EMPTY to add
+ * it without any value ("initrd")
+ * @set_env: true to set the "bootargs" environment variable too
+ *
+ * Return: 0 if OK, -ENOMEM if out of memory
+ */
+int bootflow_cmdline_set_arg(struct bootflow *bflow, const char *arg,
+			     const char *val, bool set_env);
+
+/**
+ * cmdline_get_arg() - Read an argument from a cmdline
+ *
+ * @cmdline: Command line to read, in the form:
+ *
+ *	fred mary= jane=123 john="has spaces"
+ * @arg: Argument to read (may or may not exist)
+ * @posp: Returns position of argument (after any leading quote) if present
+ * Return: Length of argument value excluding quotes if found, -ENOENT if not
+ * found
+ */
+int cmdline_get_arg(const char *cmdline, const char *arg, int *posp);
+
+/**
+ * bootflow_cmdline_get_arg() - Read an argument from a cmdline
+ *
+ * @bootflow: Bootflow to read from
+ * @arg: Argument to read (may or may not exist)
+ * @valp: Returns a pointer to the argument (after any leading quote) if present
+ * Return: Length of argument value excluding quotes if found, -ENOENT if not
+ * found
+ */
+int bootflow_cmdline_get_arg(struct bootflow *bflow, const char *arg,
+			     const char **val);
+
+/**
+ * bootflow_cmdline_auto() - Automatically set a value for a known argument
+ *
+ * This handles a small number of known arguments, for Linux in particular. It
+ * adds suitable kernel parameters automatically, e.g. to enable the console.
+ *
+ * @bflow: Bootflow to update
+ * @arg: Name of argument to set (e.g. "earlycon" or "console")
+ * Return: 0 if OK -ve on error
+ */
+int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg);
+
 #endif
diff --git a/include/bootstd.h b/include/bootstd.h
index dddb3e1..7802564 100644
--- a/include/bootstd.h
+++ b/include/bootstd.h
@@ -69,7 +69,7 @@
 /**
  * bootstd_get_prefixes() - Get the filename-prefixes list
  *
- * This reads the prefixes, e.g. {"/", "/bpot", NULL}
+ * This reads the prefixes, e.g. {"/", "/boot", NULL}
  *
  * The list is alloced by the bootstd driver so should not be freed. That is the
  * reason for all the const stuff in the function signature
diff --git a/include/configs/arbel.h b/include/configs/arbel.h
index 8e27fb5..891257b 100644
--- a/include/configs/arbel.h
+++ b/include/configs/arbel.h
@@ -7,12 +7,13 @@
 #define __CONFIG_ARBEL_H
 
 #define CFG_SYS_SDRAM_BASE		0x0
-#define CFG_SYS_BOOTMAPSZ		(20 << 20)
+#define CFG_SYS_BOOTMAPSZ		(30 << 20)
+#define CFG_SYS_BOOTM_LEN		(20 << 20)
 #define CFG_SYS_INIT_RAM_ADDR	CFG_SYS_SDRAM_BASE
 #define CFG_SYS_INIT_RAM_SIZE	0x8000
 
 /* Default environemnt variables */
-#define CFG_EXTRA_ENV_SETTINGS   "uimage_flash_addr=80200000\0"   \
+#define CFG_EXTRA_ENV_SETTINGS   "uimage_flash_addr=80400000\0"   \
 		"stdin=serial\0"   \
 		"stdout=serial\0"   \
 		"stderr=serial\0"    \
diff --git a/include/configs/conga-qeval20-qa3-e3845.h b/include/configs/conga-qeval20-qa3-e3845.h
index 60617e6..03c364f 100644
--- a/include/configs/conga-qeval20-qa3-e3845.h
+++ b/include/configs/conga-qeval20-qa3-e3845.h
@@ -16,8 +16,6 @@
 					"stdout=serial\0" \
 					"stderr=serial\0"
 
-#define VIDEO_IO_OFFSET				0
-
 #undef CFG_EXTRA_ENV_SETTINGS
 #define CFG_EXTRA_ENV_SETTINGS				\
 	"kernel-ver=4.4.0-22\0"					\
diff --git a/include/configs/dfi-bt700.h b/include/configs/dfi-bt700.h
index 05389a43..be095e2 100644
--- a/include/configs/dfi-bt700.h
+++ b/include/configs/dfi-bt700.h
@@ -20,8 +20,6 @@
 					"stdout=serial\0" \
 					"stderr=serial\0"
 
-#define VIDEO_IO_OFFSET				0
-
 #undef CFG_EXTRA_ENV_SETTINGS
 #define CFG_EXTRA_ENV_SETTINGS				\
 	"kernel-ver=4.4.0-24\0"					\
diff --git a/include/configs/imx8mm_beacon.h b/include/configs/imx8mm_beacon.h
index d85ae21..fa20651 100644
--- a/include/configs/imx8mm_beacon.h
+++ b/include/configs/imx8mm_beacon.h
@@ -9,8 +9,17 @@
 #include <linux/sizes.h>
 #include <asm/arch/imx-regs.h>
 
+#define UBOOT_ITB_OFFSET			0x57C00
+#define FSPI_CONF_BLOCK_SIZE		0x1000
+#define UBOOT_ITB_OFFSET_FSPI  \
+	(UBOOT_ITB_OFFSET + FSPI_CONF_BLOCK_SIZE)
+#ifdef CONFIG_FSPI_CONF_HEADER
+#define CFG_SYS_UBOOT_BASE  \
+	(QSPI0_AMBA_BASE + UBOOT_ITB_OFFSET_FSPI)
+#else
 #define CFG_SYS_UBOOT_BASE	\
 	(QSPI0_AMBA_BASE + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR * 512)
+#endif
 
 #ifdef CONFIG_SPL_BUILD
 /* malloc f used before GD_FLG_FULL_MALLOC_INIT set */
@@ -19,56 +28,6 @@
 
 #endif
 
-/* Initial environment variables */
-#define CFG_EXTRA_ENV_SETTINGS		\
-	"script=boot.scr\0" \
-	"image=Image\0" \
-	"console=ttymxc1,115200\0" \
-	"fdt_addr=0x43000000\0"			\
-	"boot_fit=try\0" \
-	"fdt_file=" CONFIG_DEFAULT_FDT_FILE "\0" \
-	"initrd_addr=0x43800000\0"		\
-	"mmcdev=" __stringify(CONFIG_SYS_MMC_ENV_DEV) "\0" \
-	"mmcpart=1\0" \
-	"finduuid=part uuid mmc ${mmcdev}:2 uuid\0" \
-	"mmcautodetect=yes\0" \
-	"mmcargs=setenv bootargs console=${console},${baudrate}" \
-	" root=PARTUUID=${uuid} rootwait rw ${mtdparts} ${optargs}\0" \
-	"loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr}" \
-	" ${script};\0" \
-	"bootscript=echo Running bootscript from mmc ...; " \
-		"source\0" \
-	"loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
-	"loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
-	"mmcboot=echo Booting from mmc ...; " \
-		"run finduuid; " \
-		"run mmcargs; " \
-		"if run loadfdt; then " \
-			"booti ${loadaddr} - ${fdt_addr}; " \
-		"else " \
-			"echo WARN: Cannot load the DT; " \
-		"fi; " \
-	"netargs=setenv bootargs console=${console} " \
-		"root=/dev/nfs " \
-		"ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp\0" \
-	"netboot=echo Booting from net ...; " \
-		"run netargs;  " \
-		"if test ${ip_dyn} = yes; then " \
-			"setenv get_cmd dhcp; " \
-		"else " \
-			"setenv get_cmd tftp; " \
-		"fi; " \
-		"${get_cmd} ${loadaddr} ${image}; " \
-		"if test ${boot_fit} = yes || test ${boot_fit} = try; then " \
-			"bootm ${loadaddr}; " \
-		"else " \
-			"if ${get_cmd} ${fdt_addr} ${fdt_file}; then " \
-				"booti ${loadaddr} - ${fdt_addr}; " \
-			"else " \
-				"echo WARN: Cannot load the DT; " \
-			"fi; " \
-		"fi;\0"
-
 /* Link Definitions */
 
 #define CFG_SYS_INIT_RAM_ADDR        0x40000000
diff --git a/include/configs/imx8mm_venice.h b/include/configs/imx8mm_venice.h
index 5579a05..046d568 100644
--- a/include/configs/imx8mm_venice.h
+++ b/include/configs/imx8mm_venice.h
@@ -26,16 +26,16 @@
 	func(DHCP, dhcp, na)
 #include <config_distro_bootcmd.h>
 #define CFG_EXTRA_ENV_SETTINGS \
-	"splblk=0x42\0" \
 	BOOTENV
 
 #define CFG_SYS_INIT_RAM_ADDR        0x40000000
 #define CFG_SYS_INIT_RAM_SIZE        SZ_2M
 
+/* SDRAM configuration: 4GiB */
 #define CFG_SYS_SDRAM_BASE           0x40000000
-
-/* SDRAM configuration */
-#define PHYS_SDRAM                      0x40000000
-#define PHYS_SDRAM_SIZE			SZ_4G
+#define PHYS_SDRAM                   0x40000000
+#define PHYS_SDRAM_SIZE              0x80000000      /* 2 GB */
+#define PHYS_SDRAM_2                 0xC0000000
+#define PHYS_SDRAM_2_SIZE            0x80000000      /* 2 GB */
 
 #endif
diff --git a/include/configs/imx8mn_beacon.h b/include/configs/imx8mn_beacon.h
index 1880d03..699e209 100644
--- a/include/configs/imx8mn_beacon.h
+++ b/include/configs/imx8mn_beacon.h
@@ -12,67 +12,6 @@
 #define CFG_SYS_UBOOT_BASE	\
 	(QSPI0_AMBA_BASE + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR * 512)
 
-/* Initial environment variables */
-#define CFG_EXTRA_ENV_SETTINGS		\
-	"script=boot.scr\0" \
-	"image=Image\0" \
-	"ramdiskimage=rootfs.cpio.uboot\0" \
-	"console=ttymxc1,115200\0" \
-	"fdt_addr=0x43000000\0"			\
-	"ramdisk_addr=0x44000000\0" \
-	"boot_fdt=try\0" \
-	"fdt_file=" CONFIG_DEFAULT_FDT_FILE "\0" \
-	"initrd_addr=0x43800000\0"		\
-	"mmcdev=" __stringify(CONFIG_SYS_MMC_ENV_DEV) "\0" \
-	"mmcpart=1\0" \
-	"finduuid=part uuid mmc ${mmcdev}:2 uuid\0" \
-	"mmcautodetect=yes\0" \
-	"mmcargs=setenv bootargs console=${console} " \
-	" root=PARTUUID=${uuid} rootwait rw ${mtdparts} ${optargs}\0" \
-	"ramargs=setenv bootargs console=${console} root=/dev/ram rw " \
-	" ${optargs}\0" \
-	"loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};\0" \
-	"bootscript=echo Running bootscript from mmc ...; " \
-		"source\0" \
-	"loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
-	"loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
-	"loadramdisk=load mmc ${mmcdev} ${ramdisk_addr} ${ramdiskimage}\0"\
-	"mmcboot=echo Booting from mmc ...; " \
-		"run finduuid; run mmcargs; " \
-		"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
-			"if run loadfdt; then " \
-				"booti ${loadaddr} - ${fdt_addr}; " \
-			"else " \
-				"echo WARN: Cannot load the DT; " \
-			"fi; " \
-		"else " \
-			"echo wait for boot; " \
-		"fi;\0" \
-	"netargs=setenv bootargs console=${console} " \
-		"root=/dev/nfs " \
-		"ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp\0" \
-	"netboot=echo Booting from net ...; " \
-		"run netargs;  " \
-		"if test ${ip_dyn} = yes; then " \
-			"setenv get_cmd dhcp; " \
-		"else " \
-			"setenv get_cmd tftp; " \
-		"fi; " \
-		"${get_cmd} ${loadaddr} ${image}; " \
-		"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
-			"if ${get_cmd} ${fdt_addr} ${fdt_file}; then " \
-				"booti ${loadaddr} - ${fdt_addr}; " \
-			"else " \
-				"echo WARN: Cannot load the DT; " \
-			"fi; " \
-		"else " \
-			"booti; " \
-		"fi;\0" \
-	"ramboot=echo Booting from RAMdisk...; "\
-		"run loadimage; run loadfdt; fdt addr $fdt_addr; "\
-		"run loadramdisk; run ramargs; " \
-		"booti ${loadaddr} ${ramdisk_addr} ${fdt_addr} ${optargs}\0"
-
 /* Link Definitions */
 
 #define CFG_SYS_INIT_RAM_ADDR        0x40000000
diff --git a/include/configs/imx8mn_venice.h b/include/configs/imx8mn_venice.h
index 80c2df9..1cc054a 100644
--- a/include/configs/imx8mn_venice.h
+++ b/include/configs/imx8mn_venice.h
@@ -20,16 +20,16 @@
 	func(DHCP, dhcp, na)
 #include <config_distro_bootcmd.h>
 #define CFG_EXTRA_ENV_SETTINGS \
-	"splblk=0x40\0" \
 	BOOTENV
 
 #define CFG_SYS_INIT_RAM_ADDR        0x40000000
 #define CFG_SYS_INIT_RAM_SIZE        SZ_2M
 
+/* SDRAM configuration: 4GiB */
 #define CFG_SYS_SDRAM_BASE           0x40000000
-
-/* SDRAM configuration */
-#define PHYS_SDRAM                      0x40000000
-#define PHYS_SDRAM_SIZE			SZ_4G
+#define PHYS_SDRAM                   0x40000000
+#define PHYS_SDRAM_SIZE              0x80000000      /* 2 GB */
+#define PHYS_SDRAM_2                 0xC0000000
+#define PHYS_SDRAM_2_SIZE            0x80000000      /* 2 GB */
 
 #endif
diff --git a/include/configs/imx8mp_venice.h b/include/configs/imx8mp_venice.h
index 4b32d5a..47413ec 100644
--- a/include/configs/imx8mp_venice.h
+++ b/include/configs/imx8mp_venice.h
@@ -20,16 +20,16 @@
 	func(DHCP, dhcp, na)
 #include <config_distro_bootcmd.h>
 #define CFG_EXTRA_ENV_SETTINGS \
-	"splblk=0x40\0" \
 	BOOTENV
 
 #define CFG_SYS_INIT_RAM_ADDR        0x40000000
 #define CFG_SYS_INIT_RAM_SIZE        SZ_2M
 
+/* SDRAM configuration: 4GiB */
 #define CFG_SYS_SDRAM_BASE           0x40000000
-
-/* SDRAM configuration */
-#define PHYS_SDRAM                      0x40000000
-#define PHYS_SDRAM_SIZE			SZ_4G
+#define PHYS_SDRAM                   0x40000000
+#define PHYS_SDRAM_SIZE              0x80000000      /* 2 GB */
+#define PHYS_SDRAM_2                 0xC0000000
+#define PHYS_SDRAM_2_SIZE            0x80000000      /* 2 GB */
 
 #endif
diff --git a/include/configs/minnowmax.h b/include/configs/minnowmax.h
index 4a12c2f..842672d 100644
--- a/include/configs/minnowmax.h
+++ b/include/configs/minnowmax.h
@@ -17,6 +17,4 @@
 					"stderr=vidconsole,serial\0" \
 					"usb_pgood_delay=40\0"
 
-#define VIDEO_IO_OFFSET				0
-
 #endif	/* __CONFIG_H */
diff --git a/include/configs/poleg.h b/include/configs/poleg.h
index c3f1d33..1e96e83 100644
--- a/include/configs/poleg.h
+++ b/include/configs/poleg.h
@@ -27,6 +27,8 @@
 		"eth1addr=00:00:F7:A0:00:FD\0"   \
 		"eth2addr=00:00:F7:A0:00:FE\0"    \
 		"eth3addr=00:00:F7:A0:00:FF\0"    \
+		"console=ttyS0,115200n8\0" \
+		"earlycon=uart8250,mmio32,0xf0000000\0" \
 		"common_bootargs=setenv bootargs earlycon=${earlycon} root=/dev/ram "   \
 		"console=${console} mem=${mem} ramdisk_size=48000 basemac=${ethaddr}\0"    \
 		"sd_prog=fatload mmc 0 10000000 image-bmc; cp.b 10000000 80000000 ${filesize}\0"  \
diff --git a/include/configs/qemu-x86.h b/include/configs/qemu-x86.h
index 33263a4..3e52352 100644
--- a/include/configs/qemu-x86.h
+++ b/include/configs/qemu-x86.h
@@ -12,14 +12,6 @@
 
 #include <linux/sizes.h>
 
-#define BOOT_TARGET_DEVICES(func) \
-	func(USB, usb, 0) \
-	func(SCSI, scsi, 0) \
-	func(VIRTIO, virtio, 0) \
-	func(IDE, ide, 0) \
-	func(DHCP, dhcp, na)
-
-#include <config_distro_bootcmd.h>
 #include <configs/x86-common.h>
 
 #define CFG_STD_DEVICES_SETTINGS	"stdin=serial,i8042-kbd\0" \
diff --git a/include/configs/som-db5800-som-6867.h b/include/configs/som-db5800-som-6867.h
index b2e7aa1..5f7eabd 100644
--- a/include/configs/som-db5800-som-6867.h
+++ b/include/configs/som-db5800-som-6867.h
@@ -16,6 +16,4 @@
 					"stdout=serial,vidconsole\0" \
 					"stderr=serial,vidconsole\0"
 
-#define VIDEO_IO_OFFSET				0
-
 #endif	/* __CONFIG_H */
diff --git a/include/configs/theadorable-x86-common.h b/include/configs/theadorable-x86-common.h
index b23b878..46aef23 100644
--- a/include/configs/theadorable-x86-common.h
+++ b/include/configs/theadorable-x86-common.h
@@ -15,8 +15,6 @@
 					"stdout=serial\0" \
 					"stderr=serial\0"
 
-#define VIDEO_IO_OFFSET				0
-
 /* Environment settings */
 
 #undef CFG_EXTRA_ENV_SETTINGS
diff --git a/include/configs/x240.h b/include/configs/x240.h
new file mode 100644
index 0000000..3601df5
--- /dev/null
+++ b/include/configs/x240.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2022 Allied Telesis
+ */
+
+#ifndef __X240_H_
+#define __X240_H_
+
+#include <asm/arch/soc.h>
+
+/* additions for new ARM relocation support */
+#define CFG_SYS_SDRAM_BASE   0x200000000
+
+#define CFG_SYS_BAUDRATE_TABLE   { 9600, 19200, 38400, 57600, \
+				      115200, 230400, 460800, 921600 }
+
+/* Default Env vars */
+
+#define BOOT_TARGET_DEVICES(func) \
+	func(USB, usb, 0) \
+	func(DHCP, dhcp, na)
+
+#include <config_distro_bootcmd.h>
+
+#define CFG_EXTRA_ENV_SETTINGS   \
+	BOOTENV \
+	"kernel_addr_r=0x202000000\0" \
+	"fdt_addr_r=0x201000000\0"    \
+	"ramdisk_addr_r=0x206000000\0"    \
+	"fdtfile=marvell/" CONFIG_DEFAULT_DEVICE_TREE ".dtb\0"
+
+/*
+ * High Level Configuration Options (easy to change)
+ */
+#define CFG_SYS_TCLK     325000000
+
+#endif /* __X240_H_ */
diff --git a/include/configs/x86-chromebook.h b/include/configs/x86-chromebook.h
index 98abb00..6bf90c7 100644
--- a/include/configs/x86-chromebook.h
+++ b/include/configs/x86-chromebook.h
@@ -10,8 +10,6 @@
 #define CFG_X86_REFCODE_ADDR			0xffea0000
 #define CFG_X86_REFCODE_RUN_ADDR		0
 
-#define VIDEO_IO_OFFSET				0
-
 #define CFG_STD_DEVICES_SETTINGS	"stdin=usbkbd,i8042-kbd,serial\0" \
 					"stdout=vidconsole,serial\0" \
 					"stderr=vidconsole,serial\0"
diff --git a/include/dm/of.h b/include/dm/of.h
index fce7cef..b1c934f 100644
--- a/include/dm/of.h
+++ b/include/dm/of.h
@@ -63,6 +63,8 @@
 	struct device_node *sibling;
 };
 
+#define BAD_OF_ROOT	0xdead11e3
+
 #define OF_MAX_PHANDLE_ARGS 16
 
 /**
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 443db62..0f38b3e 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -353,6 +353,16 @@
 }
 
 /**
+ * oftree_dispose() - Dispose of an oftree
+ *
+ * This can be used to dispose of a tree that has been created (other than
+ * the control FDT which must not be disposed)
+ *
+ * @tree: Tree to dispose
+ */
+void oftree_dispose(oftree tree);
+
+/**
  * ofnode_name_eq() - Check if the node name is equivalent to a given name
  *                    ignoring the unit address
  *
diff --git a/include/dm/platform_data/serial_pl01x.h b/include/dm/platform_data/serial_pl01x.h
index e3d4e30..811697c 100644
--- a/include/dm/platform_data/serial_pl01x.h
+++ b/include/dm/platform_data/serial_pl01x.h
@@ -20,7 +20,11 @@
  * @skip_init: Don't attempt to change port configuration (also means @clock
  * is ignored)
  */
+#include <dt-structs.h>
 struct pl01x_serial_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_serial_pl01x dtplat;
+#endif
 	unsigned long base;
 	enum pl01x_type type;
 	unsigned int clock;
diff --git a/include/dm/platform_data/spi_pl022.h b/include/dm/platform_data/spi_pl022.h
deleted file mode 100644
index 7f74b3c..0000000
--- a/include/dm/platform_data/spi_pl022.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * (C) Copyright 2018
- * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com
- *
- * Structure for use with U_BOOT_DRVINFO for pl022 SPI devices or to use
- * in of_to_plat.
- */
-
-#ifndef __spi_pl022_h
-#define __spi_pl022_h
-
-#include <fdtdec.h>
-
-struct pl022_spi_pdata {
-	fdt_addr_t addr;
-	fdt_size_t size;
-	unsigned int freq;
-};
-
-#endif /* __spi_pl022_h */
diff --git a/include/dt-bindings/clock/imx8mp-clock.h b/include/dt-bindings/clock/imx8mp-clock.h
index 9d5cc2d..3f28ce6 100644
--- a/include/dt-bindings/clock/imx8mp-clock.h
+++ b/include/dt-bindings/clock/imx8mp-clock.h
@@ -324,8 +324,18 @@
 #define IMX8MP_CLK_CLKOUT2_SEL			317
 #define IMX8MP_CLK_CLKOUT2_DIV			318
 #define IMX8MP_CLK_CLKOUT2			319
-
-#define IMX8MP_CLK_END				320
+#define IMX8MP_CLK_USB_SUSP			320
+#define IMX8MP_CLK_AUDIO_AHB_ROOT		IMX8MP_CLK_AUDIO_ROOT
+#define IMX8MP_CLK_AUDIO_AXI_ROOT		321
+#define IMX8MP_CLK_SAI1_ROOT			322
+#define IMX8MP_CLK_SAI2_ROOT			323
+#define IMX8MP_CLK_SAI3_ROOT			324
+#define IMX8MP_CLK_SAI5_ROOT			325
+#define IMX8MP_CLK_SAI6_ROOT			326
+#define IMX8MP_CLK_SAI7_ROOT			327
+#define IMX8MP_CLK_PDM_ROOT			328
+#define IMX8MP_CLK_MEDIA_LDB_ROOT		329
+#define IMX8MP_CLK_END				330
 
 #define IMX8MP_CLK_AUDIOMIX_SAI1_IPG		0
 #define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1		1
diff --git a/include/efi_config.h b/include/efi_config.h
index 01ce9b2..d7c1601 100644
--- a/include/efi_config.h
+++ b/include/efi_config.h
@@ -105,11 +105,6 @@
 				      void (*item_data_print)(void *),
 				      char *(*item_choice)(void *));
 efi_status_t eficonfig_process_select_file(void *data);
-efi_status_t eficonfig_get_unused_bootoption(u16 *buf,
-					     efi_uintn_t buf_size, u32 *index);
-efi_status_t eficonfig_append_bootorder(u16 index);
-efi_status_t eficonfig_generate_media_device_boot_option(void);
-
 efi_status_t eficonfig_append_menu_entry(struct efimenu *efi_menu,
 					 char *title, eficonfig_entry_func func,
 					 void *data);
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 11e08a8..604fd76 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -517,6 +517,17 @@
 int efi_init_early(void);
 /* Initialize efi execution environment */
 efi_status_t efi_init_obj_list(void);
+/* Append new boot option in BootOrder variable */
+efi_status_t efi_bootmgr_append_bootorder(u16 index);
+/* Get unused "Boot####" index */
+efi_status_t efi_bootmgr_get_unused_bootoption(u16 *buf,
+					       efi_uintn_t buf_size, u32 *index);
+/* Generate the media device boot option */
+efi_status_t efi_bootmgr_update_media_device_boot_option(void);
+/* Delete selected boot option */
+efi_status_t efi_bootmgr_delete_boot_option(u16 boot_index);
+/* search the boot option index in BootOrder */
+bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index);
 /* Set up console modes */
 void efi_setup_console_size(void);
 /* Install device tree */
diff --git a/include/env_callback.h b/include/env_callback.h
index a9a14f2..23bc650 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -60,8 +60,10 @@
 #define NET6_CALLBACKS
 #endif
 
-#ifdef CONFIG_BOOTSTD
-#define BOOTSTD_CALLBACK	"bootmeths:bootmeths,"
+#ifdef CONFIG_BOOTSTD_FULL
+#define BOOTSTD_CALLBACK \
+	"bootmeths:bootmeths," \
+	"bootargs:bootargs,"
 #else
 #define BOOTSTD_CALLBACK
 #endif
diff --git a/include/expo.h b/include/expo.h
index d242f48..0b1d944 100644
--- a/include/expo.h
+++ b/include/expo.h
@@ -7,22 +7,31 @@
 #ifndef __SCENE_H
 #define __SCENE_H
 
+#include <dm/ofnode_decl.h>
 #include <linux/list.h>
 
 struct udevice;
+struct video_priv;
 
 /**
  * enum expoact_type - types of actions reported by the expo
  *
  * @EXPOACT_NONE: no action
- * @EXPOACT_POINT: menu item was highlighted (@id indicates which)
+ * @EXPOACT_POINT_OBJ: object was highlighted (@id indicates which)
+ * @EXPOACT_POINT_ITEM: menu item was highlighted (@id indicates which)
  * @EXPOACT_SELECT: menu item was selected (@id indicates which)
+ * @EXPOACT_OPEN: menu was opened, so an item can be selected (@id indicates
+ * which menu object)
+ * @EXPOACT_CLOSE: menu was closed (@id indicates which menu object)
  * @EXPOACT_QUIT: request to exit the menu
  */
 enum expoact_type {
 	EXPOACT_NONE,
-	EXPOACT_POINT,
+	EXPOACT_POINT_OBJ,
+	EXPOACT_POINT_ITEM,
 	EXPOACT_SELECT,
+	EXPOACT_OPEN,
+	EXPOACT_CLOSE,
 	EXPOACT_QUIT,
 };
 
@@ -30,7 +39,7 @@
  * struct expo_action - an action report by the expo
  *
  * @type: Action type (EXPOACT_NONE if there is no action)
- * @select: Used for EXPOACT_POINT and EXPOACT_SELECT
+ * @select: Used for EXPOACT_POINT_ITEM and EXPOACT_SELECT
  * @id: ID number of the object affected.
  */
 struct expo_action {
@@ -43,6 +52,19 @@
 };
 
 /**
+ * struct expo_theme - theme for the expo
+ *
+ * @font_size: Default font size for all text
+ * @menu_inset: Inset width (on each side and top/bottom) for menu items
+ * @menuitem_gap_y: Gap between menu items in pixels
+ */
+struct expo_theme {
+	u32 font_size;
+	u32 menu_inset;
+	u32 menuitem_gap_y;
+};
+
+/**
  * struct expo - information about an expo
  *
  * A group of scenes which can be presented to the user, typically to obtain
@@ -50,23 +72,29 @@
  *
  * @name: Name of the expo (allocated)
  * @display: Display to use (`UCLASS_VIDEO`), or NULL to use text mode
+ * @cons: Console to use (`UCLASS_VIDEO_CONSOLE`), or NULL to use text mode
  * @scene_id: Current scene ID (0 if none)
  * @next_id: Next ID number to use, for automatic allocation
  * @action: Action selected by user. At present only one is supported, with the
  * type set to EXPOACT_NONE if there is no action
  * @text_mode: true to use text mode for the menu (no vidconsole)
+ * @popup: true to use popup menus, instead of showing all items
  * @priv: Private data for the controller
+ * @theme: Information about fonts styles, etc.
  * @scene_head: List of scenes
  * @str_head: list of strings
  */
 struct expo {
 	char *name;
 	struct udevice *display;
+	struct udevice *cons;
 	uint scene_id;
 	uint next_id;
 	struct expo_action action;
 	bool text_mode;
+	bool popup;
 	void *priv;
+	struct expo_theme theme;
 	struct list_head scene_head;
 	struct list_head str_head;
 };
@@ -92,7 +120,8 @@
  * @expo: Expo this scene is part of
  * @name: Name of the scene (allocated)
  * @id: ID number of the scene
- * @title: Title of the scene (allocated)
+ * @title_id: String ID of title of the scene (allocated)
+ * @highlight_id: ID of highlighted object, if any
  * @sibling: Node to link this scene to its siblings
  * @obj_head: List of objects in the scene
  */
@@ -100,7 +129,8 @@
 	struct expo *expo;
 	char *name;
 	uint id;
-	char *title;
+	uint title_id;
+	uint highlight_id;
 	struct list_head sibling;
 	struct list_head obj_head;
 };
@@ -121,15 +151,43 @@
 };
 
 /**
+ * struct scene_dim - Dimensions of an object
+ *
+ * @x: x position, in pixels from left side
+ * @y: y position, in pixels from top
+ * @w: width, in pixels
+ * @h: height, in pixels
+ */
+struct scene_dim {
+	int x;
+	int y;
+	int w;
+	int h;
+};
+
+/**
+ * enum scene_obj_flags_t - flags for objects
+ *
+ * @SCENEOF_HIDE: object should be hidden
+ * @SCENEOF_POINT: object should be highlighted
+ * @SCENEOF_OPEN: object should be opened (e.g. menu is opened so that an option
+ * can be selected)
+ */
+enum scene_obj_flags_t {
+	SCENEOF_HIDE	= 1 << 0,
+	SCENEOF_POINT	= 1 << 1,
+	SCENEOF_OPEN	= 1 << 2,
+};
+
+/**
  * struct scene_obj - information about an object in a scene
  *
  * @scene: Scene that this object relates to
  * @name: Name of the object (allocated)
  * @id: ID number of the object
  * @type: Type of this object
- * @x: x position, in pixels from left side
- * @y: y position, in pixels from top
- * @hide: true if the object should be hidden
+ * @dim: Dimensions for this object
+ * @flags: Flags for this object
  * @sibling: Node to link this object to its siblings
  */
 struct scene_obj {
@@ -137,9 +195,8 @@
 	char *name;
 	uint id;
 	enum scene_obj_t type;
-	int x;
-	int y;
-	bool hide;
+	struct scene_dim dim;
+	int flags;
 	struct list_head sibling;
 };
 
@@ -256,6 +313,25 @@
 void expo_destroy(struct expo *exp);
 
 /**
+ * expo_set_dynamic_start() - Set the start of the 'dynamic' IDs
+ *
+ * It is common for a set of 'static' IDs to be used to refer to objects in the
+ * expo. These typically use an enum so that they are defined in sequential
+ * order.
+ *
+ * Dynamic IDs (for objects not in the enum) are intended to be used for
+ * objects to which the code does not need to refer. These are ideally located
+ * above the static IDs.
+ *
+ * Use this function to set the start of the dynamic range, making sure that the
+ * value is higher than all the statically allocated IDs.
+ *
+ * @exp: Expo to update
+ * @dyn_start: Start ID that expo should use for dynamic allocation
+ */
+void expo_set_dynamic_start(struct expo *exp, uint dyn_start);
+
+/**
  * expo_str() - add a new string to an expo
  *
  * @exp: Expo to update
@@ -285,6 +361,16 @@
 int expo_set_display(struct expo *exp, struct udevice *dev);
 
 /**
+ * expo_calc_dims() - Calculate the dimensions of the objects
+ *
+ * Updates the width and height of all objects based on their contents
+ *
+ * @exp: Expo to update
+ * Returns 0 if OK, -ENOTSUPP if there is no graphical console
+ */
+int expo_calc_dims(struct expo *exp);
+
+/**
  * expo_set_scene_id() - Set the current scene ID
  *
  * @exp: Expo to update
@@ -294,6 +380,14 @@
 int expo_set_scene_id(struct expo *exp, uint scene_id);
 
 /**
+ * expo_first_scene_id() - Get the ID of the first scene
+ *
+ * @exp: Expo to check
+ * Returns: Scene ID of first scene, or -ENOENT if there are no scenes
+ */
+int expo_first_scene_id(struct expo *exp);
+
+/**
  * expo_render() - render the expo on the display / console
  *
  * @exp: Expo to render
@@ -304,12 +398,12 @@
 int expo_render(struct expo *exp);
 
 /**
- * exp_set_text_mode() - Controls whether the expo renders in text mode
+ * expo_set_text_mode() - Controls whether the expo renders in text mode
  *
  * @exp: Expo to update
  * @text_mode: true to use text mode, false to use the console
  */
-void exp_set_text_mode(struct expo *exp, bool text_mode);
+void expo_set_text_mode(struct expo *exp, bool text_mode);
 
 /**
  * scene_new() - create a new scene in a expo
@@ -335,13 +429,43 @@
 struct scene *expo_lookup_scene_id(struct expo *exp, uint scene_id);
 
 /**
+ * scene_highlight_first() - Highlight the first item in a scene
+ *
+ * This highlights the first item, so that the user can see that it is pointed
+ * to
+ *
+ * @scn: Scene to update
+ */
+void scene_highlight_first(struct scene *scn);
+
+/**
+ * scene_set_highlight_id() - Set the object which is highlighted
+ *
+ * Sets a new object to highlight in the scene
+ *
+ * @scn: Scene to update
+ * @id: ID of object to highlight
+ */
+void scene_set_highlight_id(struct scene *scn, uint id);
+
+/**
+ * scene_set_open() - Set whether an item is open or not
+ *
+ * @scn: Scene to update
+ * @id: ID of object to update
+ * @open: true to open the object, false to close it
+ * Returns: 0 if OK, -ENOENT if @id is invalid
+ */
+int scene_set_open(struct scene *scn, uint id, bool open);
+
+/**
  * scene_title_set() - set the scene title
  *
  * @scn: Scene to update
- * @title: Title to set, NULL if none (this is allocated by this call)
- * Returns: 0 if OK, -ENOMEM if out of memory
+ * @title_id: Title ID to set
+ * Returns: 0 if OK
  */
-int scene_title_set(struct scene *scn, const char *title);
+int scene_title_set(struct scene *scn, uint title_id);
 
 /**
  * scene_obj_count() - Count the number of objects in a scene
@@ -426,6 +550,17 @@
 int scene_obj_set_pos(struct scene *scn, uint id, int x, int y);
 
 /**
+ * scene_obj_set_size() - Set the size of an object
+ *
+ * @scn: Scene to update
+ * @id: ID of object to update
+ * @w: width in pixels
+ * @h: height in pixels
+ * Returns: 0 if OK, -ENOENT if @id is invalid
+ */
+int scene_obj_set_size(struct scene *scn, uint id, int w, int h);
+
+/**
  * scene_obj_set_hide() - Set whether an object is hidden
  *
  * The update happens when the expo is next rendered.
@@ -519,4 +654,46 @@
  */
 int expo_action_get(struct expo *exp, struct expo_action *act);
 
+/**
+ * expo_apply_theme() - Apply a theme to an expo
+ *
+ * @exp: Expo to update
+ * @node: Node containing the theme
+ */
+int expo_apply_theme(struct expo *exp, ofnode node);
+
+/**
+ * expo_build() - Build an expo from an FDT description
+ *
+ * Build a complete expo from a description in the provided devicetree.
+ *
+ * See doc/developer/expo.rst for a description of the format
+ *
+ * @root: Root node for expo description
+ * @expp: Returns the new expo
+ * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
+ * error, -ENOENT if there is a references to a non-existent string
+ */
+int expo_build(ofnode root, struct expo **expp);
+
+/**
+ * cedit_arange() - Arrange objects in a configuration-editor scene
+ *
+ * @exp: Expo to update
+ * @vid_priv: Private info of the video device
+ * @scene_id: scene ID to arrange
+ * Returns: 0 if OK, -ve on error
+ */
+int cedit_arange(struct expo *exp, struct video_priv *vid_priv, uint scene_id);
+
+/**
+ * cedit_run() - Run a configuration editor
+ *
+ * This accepts input until the user quits with Escape
+ *
+ * @exp: Expo to use
+ * Returns: 0 if OK, -ve on error
+ */
+int cedit_run(struct expo *exp);
+
 #endif /*__SCENE_H */
diff --git a/include/firmware/imx/sci/rpc.h b/include/firmware/imx/sci/rpc.h
index 39de7f0..85af6f3 100644
--- a/include/firmware/imx/sci/rpc.h
+++ b/include/firmware/imx/sci/rpc.h
@@ -23,12 +23,12 @@
 #define RPC_FUNC(MSG)           ((MSG)->func)
 #define RPC_R8(MSG)             ((MSG)->func)
 #define RPC_I64(MSG, IDX)       ((s64)(RPC_U32((MSG), (IDX))) << 32ULL) | \
-				  (s64)(RPC_U32((MSG), (IDX) + 4U))
+				(s64)(RPC_U32((MSG), (IDX) + 4U))
 #define RPC_I32(MSG, IDX)       ((MSG)->DATA.i32[(IDX) / 4U])
 #define RPC_I16(MSG, IDX)       ((MSG)->DATA.i16[(IDX) / 2U])
 #define RPC_I8(MSG, IDX)        ((MSG)->DATA.i8[(IDX)])
 #define RPC_U64(MSG, IDX)       ((u64)(RPC_U32((MSG), (IDX))) << 32ULL) | \
-				  (u64)(RPC_U32((MSG), (IDX) + 4U))
+				(u64)(RPC_U32((MSG), (IDX) + 4U))
 #define RPC_U32(MSG, IDX)       ((MSG)->DATA.u32[(IDX) / 4U])
 #define RPC_U16(MSG, IDX)       ((MSG)->DATA.u16[(IDX) / 2U])
 #define RPC_U8(MSG, IDX)        ((MSG)->DATA.u8[(IDX)])
@@ -67,7 +67,9 @@
 #define PM_FUNC_SET_SYS_POWER_MODE		19U
 #define PM_FUNC_SET_PARTITION_POWER_MODE	1U
 #define PM_FUNC_GET_SYS_POWER_MODE		2U
+#define PM_FUNC_PARTITION_WAKE			28U
 #define PM_FUNC_SET_RESOURCE_POWER_MODE		3U
+#define PM_FUNC_SET_RESOURCE_POWER_MODE_ALL	22U
 #define PM_FUNC_GET_RESOURCE_POWER_MODE		4U
 #define PM_FUNC_REQ_LOW_POWER_MODE		16U
 #define PM_FUNC_REQ_CPU_LOW_POWER_MODE		20U
@@ -81,13 +83,16 @@
 #define PM_FUNC_GET_CLOCK_PARENT		15U
 #define PM_FUNC_RESET				13U
 #define PM_FUNC_RESET_REASON			10U
+#define PM_FUNC_GET_RESET_PART			26U
 #define PM_FUNC_BOOT				8U
+#define PM_FUNC_SET_BOOT_PARM			27U
 #define PM_FUNC_REBOOT				9U
 #define PM_FUNC_REBOOT_PARTITION		12U
+#define PM_FUNC_REBOOT_CONTINUE			25U
 #define PM_FUNC_CPU_START			11U
 #define PM_FUNC_CPU_RESET			23U
 #define PM_FUNC_RESOURCE_RESET			29U
-#define PM_FUNC_IS_PARTITION_STARTED 24U
+#define PM_FUNC_IS_PARTITION_STARTED		24U
 
 /* MISC RPC */
 #define MISC_FUNC_UNKNOWN			0
@@ -95,16 +100,10 @@
 #define MISC_FUNC_GET_CONTROL			2U
 #define MISC_FUNC_SET_MAX_DMA_GROUP		4U
 #define MISC_FUNC_SET_DMA_GROUP			5U
-#define MISC_FUNC_SECO_IMAGE_LOAD		8U
-#define MISC_FUNC_SECO_AUTHENTICATE		9U
-#define MISC_FUNC_SECO_FUSE_WRITE		20U
-#define MISC_FUNC_SECO_ENABLE_DEBUG		21U
-#define MISC_FUNC_SECO_FORWARD_LIFECYCLE	22U
-#define MISC_FUNC_SECO_RETURN_LIFECYCLE		23U
-#define MISC_FUNC_SECO_BUILD_INFO		24U
 #define MISC_FUNC_DEBUG_OUT			10U
 #define MISC_FUNC_WAVEFORM_CAPTURE		6U
 #define MISC_FUNC_BUILD_INFO			15U
+#define MISC_FUNC_API_VER			35U
 #define MISC_FUNC_UNIQUE_ID			19U
 #define MISC_FUNC_SET_ARI			3U
 #define MISC_FUNC_BOOT_STATUS			7U
@@ -114,8 +113,11 @@
 #define MISC_FUNC_SET_TEMP			12U
 #define MISC_FUNC_GET_TEMP			13U
 #define MISC_FUNC_GET_BOOT_DEV			16U
+#define MISC_FUNC_GET_BOOT_TYPE			33U
+#define MISC_FUNC_GET_BOOT_CONTAINER		36U
 #define MISC_FUNC_GET_BUTTON_STATUS		18U
-#define MISC_FUNC_GET_BOOT_CONTAINER	36U
+#define MISC_FUNC_ROMPATCH_CHECKSUM		26U
+#define MISC_FUNC_BOARD_IOCTL			34U
 
 /* PAD RPC */
 #define PAD_FUNC_UNKNOWN			0
@@ -160,6 +162,7 @@
 #define RM_FUNC_GET_RESOURCE_INFO		16U
 #define RM_FUNC_MEMREG_ALLOC			17U
 #define RM_FUNC_MEMREG_SPLIT			29U
+#define RM_FUNC_MEMREG_FRAG			32U
 #define RM_FUNC_MEMREG_FREE			18U
 #define RM_FUNC_FIND_MEMREG			30U
 #define RM_FUNC_ASSIGN_MEMREG			19U
@@ -190,6 +193,7 @@
 #define SECO_FUNC_UPDATE_MPMR 14U /* Index for seco_update_mpmr() RPC call */
 #define SECO_FUNC_GET_MP_SIGN 15U /* Index for seco_get_mp_sign() RPC call */
 #define SECO_FUNC_BUILD_INFO 16U /* Index for seco_build_info() RPC call */
+#define SECO_FUNC_V2X_BUILD_INFO 30U /* Index for sc_seco_v2x_build_info() RPC call */
 #define SECO_FUNC_CHIP_INFO 17U /* Index for seco_chip_info() RPC call */
 #define SECO_FUNC_ENABLE_DEBUG 18U /* Index for seco_enable_debug() RPC call */
 #define SECO_FUNC_GET_EVENT 19U /* Index for seco_get_event() RPC call */
@@ -210,6 +214,7 @@
 #define TIMER_FUNC_UNKNOWN 0 /* Unknown function */
 #define TIMER_FUNC_SET_WDOG_TIMEOUT 1U /* Index for sc_timer_set_wdog_timeout() RPC call */
 #define TIMER_FUNC_SET_WDOG_PRE_TIMEOUT 12U /* Index for sc_timer_set_wdog_pre_timeout() RPC call */
+#define TIMER_FUNC_SET_WDOG_WINDOW 19U /* Index for sc_timer_set_wdog_window() RPC call */
 #define TIMER_FUNC_START_WDOG 2U /* Index for sc_timer_start_wdog() RPC call */
 #define TIMER_FUNC_STOP_WDOG 3U /* Index for sc_timer_stop_wdog() RPC call */
 #define TIMER_FUNC_PING_WDOG 4U /* Index for sc_timer_ping_wdog() RPC call */
diff --git a/include/firmware/imx/sci/sci.h b/include/firmware/imx/sci/sci.h
index 61c8211..f832982 100644
--- a/include/firmware/imx/sci/sci.h
+++ b/include/firmware/imx/sci/sci.h
@@ -13,6 +13,7 @@
 #include <firmware/imx/sci/svc/pm/api.h>
 #include <firmware/imx/sci/svc/rm/api.h>
 #include <firmware/imx/sci/svc/seco/api.h>
+#include <firmware/imx/sci/svc/timer/api.h>
 #include <firmware/imx/sci/rpc.h>
 #include <dt-bindings/soc/imx_rsrc.h>
 #include <linux/errno.h>
@@ -73,6 +74,7 @@
 			   sc_pm_clk_parent_t parent);
 int sc_pm_cpu_start(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t enable,
 		    sc_faddr_t address);
+void sc_pm_reboot(sc_ipc_t ipc, sc_pm_reset_type_t type);
 sc_bool_t sc_pm_is_partition_started(sc_ipc_t ipc, sc_rm_pt_t pt);
 int sc_pm_resource_reset(sc_ipc_t ipc, sc_rsrc_t resource);
 
@@ -88,6 +90,7 @@
 int sc_misc_otp_fuse_read(sc_ipc_t ipc, u32 word, u32 *val);
 int sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_temp_t temp,
 		     s16 *celsius, s8 *tenths);
+void sc_misc_get_button_status(sc_ipc_t ipc, sc_bool_t *status);
 
 /* RM API */
 sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr);
@@ -117,6 +120,9 @@
 /* SMMU API */
 int sc_rm_set_master_sid(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_sid_t sid);
 
+/* Timer API */
+int sc_timer_set_wdog_window(sc_ipc_t ipc, sc_timer_wdog_time_t window);
+
 /* SECO API */
 int sc_seco_authenticate(sc_ipc_t ipc, sc_seco_auth_cmd_t cmd,
 			 sc_faddr_t addr);
@@ -124,6 +130,7 @@
 int sc_seco_chip_info(sc_ipc_t ipc, u16 *lc, u16 *monotonic, u32 *uid_l,
 		      u32 *uid_h);
 void sc_seco_build_info(sc_ipc_t ipc, u32 *version, u32 *commit);
+int sc_seco_v2x_build_info(sc_ipc_t ipc, u32 *version, u32 *commit);
 int sc_seco_get_event(sc_ipc_t ipc, u8 idx, u32 *event);
 int sc_seco_gen_key_blob(sc_ipc_t ipc, u32 id, sc_faddr_t load_addr,
 			 sc_faddr_t export_addr, u16 max_size);
@@ -374,6 +381,23 @@
 	return -EOPNOTSUPP;
 }
 
+static inline void sc_pm_reboot(sc_ipc_t ipc, sc_pm_reset_type_t type)
+{
+}
+
+static inline int sc_seco_v2x_build_info(sc_ipc_t ipc, u32 *version, u32 *commit)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline void sc_misc_get_button_status(sc_ipc_t ipc, sc_bool_t *status)
+{
+}
+
+static inline int sc_timer_set_wdog_window(sc_ipc_t ipc, sc_timer_wdog_time_t window)
+{
+	return -EOPNOTSUPP;
+}
 #endif
 
 #endif
diff --git a/include/firmware/imx/sci/svc/misc/api.h b/include/firmware/imx/sci/svc/misc/api.h
index 3629eb6..a4b92b8 100644
--- a/include/firmware/imx/sci/svc/misc/api.h
+++ b/include/firmware/imx/sci/svc/misc/api.h
@@ -5,27 +5,45 @@
 
 #ifndef SC_MISC_API_H
 #define SC_MISC_API_H
+/* Defines for type widths */
+#define SC_MISC_DMA_GRP_W       5U      /* Width of sc_misc_dma_group_t */
 
+/* Max DMA channel priority group */
+#define SC_MISC_DMA_GRP_MAX     31U
 /* Defines for sc_misc_boot_status_t */
 #define SC_MISC_BOOT_STATUS_SUCCESS	0U	/* Success */
 #define SC_MISC_BOOT_STATUS_SECURITY	1U	/* Security violation */
 
-/* Defines for sc_misc_seco_auth_cmd_t */
-#define SC_MISC_SECO_AUTH_SECO_FW	0U   /* SECO Firmware */
-#define SC_MISC_SECO_AUTH_HDMI_TX_FW	1U   /* HDMI TX Firmware */
-#define SC_MISC_SECO_AUTH_HDMI_RX_FW	2U   /* HDMI RX Firmware */
-
 /* Defines for sc_misc_temp_t */
-#define SC_MISC_TEMP			0U	/* Temp sensor */
-#define SC_MISC_TEMP_HIGH		1U	/* Temp high alarm */
-#define SC_MISC_TEMP_LOW		2U	/* Temp low alarm */
+#define SC_MISC_TEMP                    0U   /* Temp sensor */
+#define SC_MISC_TEMP_HIGH               1U   /* Temp high alarm */
+#define SC_MISC_TEMP_LOW                2U   /* Temp low alarm */
 
-/* Defines for sc_misc_seco_auth_cmd_t */
-#define SC_MISC_AUTH_CONTAINER	0U	/* Authenticate container */
-#define SC_MISC_VERIFY_IMAGE	1U	/* Verify image */
-#define SC_MISC_REL_CONTAINER	2U	/* Release container */
+/* Defines for sc_misc_bt_t */
+#define SC_MISC_BT_PRIMARY              0U   /* Primary boot */
+#define SC_MISC_BT_SECONDARY            1U   /* Secondary boot */
+#define SC_MISC_BT_RECOVERY             2U   /* Recovery boot */
+#define SC_MISC_BT_MANUFACTURE          3U   /* Manufacture boot */
+#define SC_MISC_BT_SERIAL               4U   /* Serial boot */
+/* Types */
 
+/*
+ * This type is used to store a DMA channel priority group.
+ */
+typedef u8 sc_misc_dma_group_t;
+
+/*
+ * This type is used report boot status.
+ */
 typedef u8 sc_misc_boot_status_t;
+
+/*
+ * This type is used report boot status.
+ */
 typedef u8 sc_misc_temp_t;
 
+/*
+ * This type is used report the boot type.
+ */
+typedef u8 sc_misc_bt_t;
 #endif /* SC_MISC_API_H */
diff --git a/include/firmware/imx/sci/svc/pm/api.h b/include/firmware/imx/sci/svc/pm/api.h
index 9008b85..d1b085d 100644
--- a/include/firmware/imx/sci/svc/pm/api.h
+++ b/include/firmware/imx/sci/svc/pm/api.h
@@ -6,6 +6,14 @@
 #ifndef SC_PM_API_H
 #define SC_PM_API_H
 
+#include <firmware/imx/sci/types.h>
+/* Defines for type widths */
+#define SC_PM_POWER_MODE_W      2U      /* Width of sc_pm_power_mode_t */
+#define SC_PM_CLOCK_MODE_W      3U      /* Width of sc_pm_clock_mode_t */
+#define SC_PM_RESET_TYPE_W      2U      /* Width of sc_pm_reset_type_t */
+#define SC_PM_RESET_REASON_W    4U      /* Width of sc_pm_reset_reason_t */
+/* Defines for ALL parameters */
+#define SC_PM_CLK_ALL   ((sc_pm_clk_t)UINT8_MAX)   /* All clocks */
 /* Defines for sc_pm_power_mode_t */
 #define SC_PM_PW_MODE_OFF	0U /* Power off */
 #define SC_PM_PW_MODE_STBY	1U /* Power in standby */
@@ -35,10 +43,96 @@
 #define SC_PM_CLK_MODE_AUTOGATE_HW	4U /* Clock is in HW autogate mode */
 #define SC_PM_CLK_MODE_AUTOGATE_SW_HW	5U /* Clock is in SW-HW autogate mode */
 
+/* Defines for sc_pm_clk_parent_t */
+#define SC_PM_PARENT_XTAL              0U    /*!< Parent is XTAL. */
+#define SC_PM_PARENT_PLL0              1U    /*!< Parent is PLL0 */
+#define SC_PM_PARENT_PLL1              2U    /*!< Parent is PLL1 or PLL0/2 */
+#define SC_PM_PARENT_PLL2              3U    /*!< Parent in PLL2 or PLL0/4 */
+#define SC_PM_PARENT_BYPS              4U    /*!< Parent is a bypass clock. */
+
+/* Defines for sc_pm_reset_type_t */
+#define SC_PM_RESET_TYPE_COLD          0U    /* Cold reset */
+#define SC_PM_RESET_TYPE_WARM          1U    /* Warm reset */
+#define SC_PM_RESET_TYPE_BOARD         2U    /* Board reset */
+
+/* Defines for sc_pm_reset_reason_t */
+#define SC_PM_RESET_REASON_POR         0U    /* Power on reset */
+#define SC_PM_RESET_REASON_JTAG        1U    /* JTAG reset */
+#define SC_PM_RESET_REASON_SW          2U    /* Software reset */
+#define SC_PM_RESET_REASON_WDOG        3U    /* Partition watchdog reset */
+#define SC_PM_RESET_REASON_LOCKUP      4U    /* SCU lockup reset */
+#define SC_PM_RESET_REASON_SNVS        5U    /* SNVS reset */
+#define SC_PM_RESET_REASON_TEMP        6U    /* Temp panic reset */
+#define SC_PM_RESET_REASON_MSI         7U    /* MSI reset */
+#define SC_PM_RESET_REASON_UECC        8U    /* ECC reset */
+#define SC_PM_RESET_REASON_SCFW_WDOG   9U    /* SCFW watchdog reset */
+#define SC_PM_RESET_REASON_ROM_WDOG    10U   /* SCU ROM watchdog reset */
+#define SC_PM_RESET_REASON_SECO        11U   /* SECO reset */
+#define SC_PM_RESET_REASON_SCFW_FAULT  12U   /* SCFW fault reset */
+
+/* Defines for sc_pm_sys_if_t */
+#define SC_PM_SYS_IF_INTERCONNECT       0U   /* System interconnect */
+#define SC_PM_SYS_IF_MU                 1U   /* AP -> SCU message units */
+#define SC_PM_SYS_IF_OCMEM              2U   /* On-chip memory (ROM/OCRAM) */
+#define SC_PM_SYS_IF_DDR                3U   /* DDR memory */
+
+/* Defines for sc_pm_wake_src_t */
+/* No wake source, used for self-kill */
+#define SC_PM_WAKE_SRC_NONE             0U
+/* Wakeup from SCU to resume CPU (IRQSTEER & GIC powered down) */
+#define SC_PM_WAKE_SRC_SCU              1U
+/* Wakeup from IRQSTEER to resume CPU (GIC powered down) */
+#define SC_PM_WAKE_SRC_IRQSTEER         2U
+/* Wakeup from IRQSTEER+GIC to wake CPU (GIC clock gated) */
+#define SC_PM_WAKE_SRC_IRQSTEER_GIC     3U
+/* Wakeup from GIC to wake CPU */
+#define SC_PM_WAKE_SRC_GIC              4U
+/* Types */
+
+/*
+ * This type is used to declare a power mode. Note resources only use
+ * SC_PM_PW_MODE_OFF and SC_PM_PW_MODE_ON. The other modes are used only
+ * as system power modes.
+ */
 typedef u8 sc_pm_power_mode_t;
+
+/*
+ * This type is used to declare a clock.
+ */
 typedef u8 sc_pm_clk_t;
+
+/*
+ * This type is used to declare a clock mode.
+ */
 typedef u8 sc_pm_clk_mode_t;
+
+/*
+ * This type is used to declare the clock parent.
+ */
 typedef u8 sc_pm_clk_parent_t;
+
+/*
+ * This type is used to declare clock rates.
+ */
 typedef u32 sc_pm_clock_rate_t;
 
+/*
+ * This type is used to declare a desired reset type.
+ */
+typedef u8 sc_pm_reset_type_t;
+
+/*
+ * This type is used to declare a reason for a reset.
+ */
+typedef u8 sc_pm_reset_reason_t;
+
+/*
+ * This type is used to specify a system-level interface to be power managed.
+ */
+typedef u8 sc_pm_sys_if_t;
+
+/*
+ * This type is used to specify a wake source for CPU resources.
+ */
+typedef u8 sc_pm_wake_src_t;
 #endif /* SC_PM_API_H */
diff --git a/include/firmware/imx/sci/svc/rm/api.h b/include/firmware/imx/sci/svc/rm/api.h
index 163d814..f4e9abc 100644
--- a/include/firmware/imx/sci/svc/rm/api.h
+++ b/include/firmware/imx/sci/svc/rm/api.h
@@ -38,32 +38,36 @@
 
 /* Types */
 
-/*!
+/*
  * This type is used to declare a resource partition.
  */
 typedef u8 sc_rm_pt_t;
 
-/*!
+/*
  * This type is used to declare a memory region.
  */
 typedef u8 sc_rm_mr_t;
 
-/*!
+/*
  * This type is used to declare a resource domain ID used by the
  * isolation HW.
  */
 typedef u8 sc_rm_did_t;
 
-/*!
+/*
  * This type is used to declare an SMMU StreamID.
  */
 typedef u16 sc_rm_sid_t;
 
-/*!
+/*
  * This type is a used to declare master transaction attributes.
  */
 typedef u8 sc_rm_spa_t;
 
+/*
+ * This type is used to declare a resource/memory region access permission.
+ * Refer to the XRDC2 Block Guide for more information.
+ */
 typedef u8 sc_rm_perm_t;
 
 #endif /* SC_RM_API_H */
diff --git a/include/firmware/imx/sci/svc/seco/api.h b/include/firmware/imx/sci/svc/seco/api.h
index 6e9c302..7d4b6b9 100644
--- a/include/firmware/imx/sci/svc/seco/api.h
+++ b/include/firmware/imx/sci/svc/seco/api.h
@@ -17,6 +17,7 @@
 #define SC_SECO_AUTH_SECO_FW            3U   /* SECO Firmware */
 #define SC_SECO_AUTH_HDMI_TX_FW         4U   /* HDMI TX Firmware */
 #define SC_SECO_AUTH_HDMI_RX_FW         5U   /* HDMI RX Firmware */
+#define SC_SECO_EVERIFY_IMAGE           6U   /* Enhanced verify image */
 
 #define SC_SECO_RNG_STAT_UNAVAILABLE    0U  /* Unable to initialize the RNG */
 #define SC_SECO_RNG_STAT_INPROGRESS     1U  /* Initialization is on-going */
@@ -24,12 +25,12 @@
 
 /* Types */
 
-/*!
+/*
  * This type is used to issue SECO authenticate commands.
  */
 typedef u8 sc_seco_auth_cmd_t;
 
-/*!
+/*
  * This type is used to return the RNG initialization status.
  */
 typedef u32 sc_seco_rng_stat_t;
diff --git a/include/firmware/imx/sci/svc/timer/api.h b/include/firmware/imx/sci/svc/timer/api.h
new file mode 100644
index 0000000..c2fe34a
--- /dev/null
+++ b/include/firmware/imx/sci/svc/timer/api.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier:     GPL-2.0+ */
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+#ifndef SC_TIMER_API_H
+#define SC_TIMER_API_H
+
+/* Defines */
+
+/* Defines for type widths */
+#define SC_TIMER_ACTION_W   3U      /* Width of sc_timer_wdog_action_t */
+
+/* Defines for sc_timer_wdog_action_t */
+#define SC_TIMER_WDOG_ACTION_PARTITION      0U   /* Reset partition */
+#define SC_TIMER_WDOG_ACTION_WARM           1U   /* Warm reset system */
+#define SC_TIMER_WDOG_ACTION_COLD           2U   /* Cold reset system */
+#define SC_TIMER_WDOG_ACTION_BOARD          3U   /* Reset board */
+#define SC_TIMER_WDOG_ACTION_IRQ            4U   /* Only generate IRQs */
+
+/* Types */
+
+/*
+ * This type is used to configure the watchdog action.
+ */
+typedef u8 sc_timer_wdog_action_t;
+
+/*
+ * This type is used to declare a watchdog time value in milliseconds.
+ */
+typedef u32 sc_timer_wdog_time_t;
+
+#endif /* SC_TIMER_API_H */
diff --git a/include/fs.h b/include/fs.h
index 8370d88..e341a0e 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -300,4 +300,42 @@
  */
 int do_fs_types(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]);
 
+/**
+ * fs_read_alloc() - Allocate space for a file and read it
+ *
+ * You must call fs_set_blk_dev() or a similar function before calling this,
+ * since that sets up the block device to use.
+ *
+ * The file is terminated with a nul character
+ *
+ * @fname: Filename to read
+ * @size: Size of file to read (must be correct!)
+ * @align: Alignment to use for memory allocation (0 for default)
+ * @bufp: On success, returns the allocated buffer with the nul-terminated file
+ *	in it
+ * Return: 0 if OK, -ENOMEM if out of memory, -EIO if read failed
+ */
+int fs_read_alloc(const char *fname, ulong size, uint align, void **bufp);
+
+/**
+ * fs_load_alloc() - Load a file into allocated space
+ *
+ * The file is terminated with a nul character
+ *
+ * @ifname: Interface name to read from (e.g. "mmc")
+ * @dev_part_str: Device and partition string (e.g. "1:2")
+ * @fname: Filename to read
+ * @max_size: Maximum allowed size for the file (use 0 for 1GB)
+ * @align: Alignment to use for memory allocation (0 for default)
+ * @bufp: On success, returns the allocated buffer with the nul-terminated file
+ *	in it
+ * @sizep: On success, returns the size of the file
+ * Return: 0 if OK, -ENOMEM if out of memory, -ENOENT if the file does not
+ * exist, -ENOMEDIUM if the device does not exist, -E2BIG if the file is too
+ * large (greater than @max_size), -EIO if read failed
+ */
+int fs_load_alloc(const char *ifname, const char *dev_part_str,
+		  const char *fname, ulong max_size, ulong align, void **bufp,
+		  ulong *sizep);
+
 #endif /* _FS_H */
diff --git a/include/fsl_sec.h b/include/fsl_sec.h
index d8861d1..9dad1d1 100644
--- a/include/fsl_sec.h
+++ b/include/fsl_sec.h
@@ -13,8 +13,8 @@
 #include <asm/io.h>
 
 #ifdef CONFIG_SYS_FSL_SEC_LE
-#define sec_in32(a)       in_le32((ulong *)(ulong)a)
-#define sec_out32(a, v)   out_le32((ulong *)(ulong)a, v)
+#define sec_in32(a)       in_le32((ulong *)(ulong)(a))
+#define sec_out32(a, v)   out_le32((ulong *)(ulong)(a), v)
 #define sec_in16(a)       in_le16(a)
 #define sec_clrbits32     clrbits_le32
 #define sec_setbits32     setbits_le32
diff --git a/include/imx_sip.h b/include/imx_sip.h
index ebbb3a1..8a5ca34 100644
--- a/include/imx_sip.h
+++ b/include/imx_sip.h
@@ -13,8 +13,8 @@
 #define IMX_SIP_BUILDINFO_GET_COMMITHASH	0x00
 
 #define IMX_SIP_SRC		0xC2000005
-#define IMX_SIP_SRC_M4_START	0x00
-#define IMX_SIP_SRC_M4_STARTED	0x01
-#define	IMX_SIP_SRC_M4_STOP	0x02
+#define IMX_SIP_SRC_MCU_START	0x00
+#define IMX_SIP_SRC_MCU_STARTED	0x01
+#define	IMX_SIP_SRC_MCU_STOP	0x02
 
 #endif
diff --git a/include/log.h b/include/log.h
index 3bab40b..6e84f080 100644
--- a/include/log.h
+++ b/include/log.h
@@ -102,6 +102,8 @@
 	LOGC_EVENT,
 	/** @LOGC_FS: Related to filesystems */
 	LOGC_FS,
+	/** @LOGC_EXPO: Related to expo handling */
+	LOGC_EXPO,
 	/** @LOGC_COUNT: Number of log categories */
 	LOGC_COUNT,
 	/** @LOGC_END: Sentinel value for lists of log categories */
diff --git a/include/mmc.h b/include/mmc.h
index b8fbff1..1022db3 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -558,6 +558,8 @@
 int mmc_reinit(struct mmc *mmc);
 int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt);
 int mmc_hs400_prepare_ddr(struct mmc *mmc);
+int mmc_send_stop_transmission(struct mmc *mmc, bool write);
+
 #else
 struct mmc_ops {
 	int (*send_cmd)(struct mmc *mmc,
diff --git a/include/of_live.h b/include/of_live.h
index f59d6af..05e86ac 100644
--- a/include/of_live.h
+++ b/include/of_live.h
@@ -36,4 +36,14 @@
  */
 int unflatten_device_tree(const void *blob, struct device_node **mynodes);
 
+/**
+ * of_live_free() - Dispose of a livetree
+ *
+ * This frees memory used by the tree, after which @root becomes invalid and
+ * cannot be used
+ *
+ * @root: Tree to dispose
+ */
+void of_live_free(struct device_node *root);
+
 #endif
diff --git a/include/part.h b/include/part.h
index be75c73..b19b33a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -105,7 +105,24 @@
 
 struct blk_desc *mg_disk_get_dev(int dev);
 
-/* disk/part.c */
+/**
+ * part_get_info_by_type() - Get partitions from a block device using a specific
+ * partition driver
+ *
+ * Each interface allocates its own devices and typically struct blk_desc is
+ * contained with the interface's data structure. There is no global
+ * numbering for block devices, so the interface name must be provided.
+ *
+ * @dev_desc:	Block device descriptor
+ * @part:	Partition number to read
+ * @part_type:	Partition driver to use, or PART_TYPE_UNKNOWN to automatically
+ *		choose a driver
+ * @info:	Returned partition information
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int part_get_info_by_type(struct blk_desc *dev_desc, int part, int part_type,
+			  struct disk_partition *info);
 int part_get_info(struct blk_desc *dev_desc, int part,
 		  struct disk_partition *info);
 /**
@@ -598,6 +615,15 @@
 	return ll_entry_start(struct part_driver, part_driver);
 }
 
+/**
+ * part_get_type_by_name() - Get partition type by name
+ *
+ * @name: Name of partition type to look up (not case-sensitive)
+ * Returns: Corresponding partition type (PART_TYPE_...) or PART_TYPE_UNKNOWN if
+ * not known
+ */
+int part_get_type_by_name(const char *name);
+
 #else
 static inline int part_driver_get_count(void)
 { return 0; }
diff --git a/include/test/cedit-test.h b/include/test/cedit-test.h
new file mode 100644
index 0000000..349df75
--- /dev/null
+++ b/include/test/cedit-test.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Binding shared between cedit.dtsi and test/boot/expo.c
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __cedit_test_h
+#define __cedit_test_h
+
+#define ID_PROMPT		1
+#define ID_SCENE1		2
+#define ID_SCENE1_TITLE		3
+
+#define ID_CPU_SPEED		4
+#define ID_CPU_SPEED_TITLE	5
+#define ID_CPU_SPEED_1		6
+#define ID_CPU_SPEED_2		7
+#define ID_CPU_SPEED_3		8
+
+#define ID_POWER_LOSS		9
+#define ID_AC_OFF		10
+#define ID_AC_ON		11
+#define ID_AC_MEMORY		12
+
+#define ID_DYNAMIC_START	13
+
+#endif
diff --git a/include/test/ut.h b/include/test/ut.h
index dddf9ad..ea6ee95 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -130,7 +130,7 @@
 									\
 	if (!(cond)) {							\
 		ut_fail(uts, __FILE__, __LINE__, __func__, #cond);	\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -142,7 +142,7 @@
 	if (!(cond)) {							\
 		ut_failf(uts, __FILE__, __LINE__, __func__, #cond,	\
 			 fmt, ##args);					\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -157,7 +157,7 @@
 			 #expr1 " == " #expr2,				\
 			 "Expected %#x (%d), got %#x (%d)",		\
 			 _val1, _val1, _val2, _val2);			\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -175,7 +175,7 @@
 			 (unsigned long long)_val1,			\
 			 (unsigned long long)_val2,			\
 			 (unsigned long long)_val2);			\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -189,7 +189,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 #expr1 " = " #expr2,				\
 			 "Expected \"%s\", got \"%s\"", _val1, _val2);	\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -208,7 +208,7 @@
 			 #expr1 " = " #expr2,				\
 			 "Expected \"%.*s\", got \"%.*s\"",		\
 			 _len, _val1, _len, _val2);			\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -228,7 +228,7 @@
 			 #expr1 " = " #expr2,				\
 			 "Expected \"%s\", got \"%s\"",			\
 			 __buf1, __buf2);				\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -242,7 +242,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 #expr1 " = " #expr2,				\
 			 "Expected %p, got %p", _val1, _val2);		\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -257,7 +257,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 #expr1 " = " #expr2,				\
 			 "Expected %lx, got %lx", _val1, _val2);	\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -271,7 +271,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 #expr " != NULL",				\
 			 "Expected NULL, got %p", _val);		\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -285,7 +285,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 #expr " = NULL",				\
 			 "Expected non-null, got NULL");		\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -300,7 +300,7 @@
 			 #expr " = NULL",				\
 			 "Expected pointer, got error %ld",		\
 			 PTR_ERR(_val));				\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -316,7 +316,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 "console", "\nExpected '%s',\n     got '%s'",	\
 			 uts->expect_str, uts->actual_str);		\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -329,7 +329,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 "console", "\nExpected '%s',\n     got '%s'",	\
 			 uts->expect_str, uts->actual_str);		\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -341,7 +341,7 @@
 	if (ut_check_skipline(uts)) {					\
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 "console", "\nExpected a line, got end");	\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -354,7 +354,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 "console", "\nExpected '%s',\n     got to '%s'", \
 			 uts->expect_str, uts->actual_str);		\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -367,7 +367,7 @@
 		ut_failf(uts, __FILE__, __LINE__, __func__,		\
 			 "console", "Expected no more output, got '%s'",\
 			 uts->actual_str);				\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
@@ -381,7 +381,7 @@
 			 "console",					\
 			"Expected dump of length %x bytes, got '%s'",	\
 			 total_bytes, uts->actual_str);			\
-		__ret = CMD_RET_FAILURE;				\
+		return CMD_RET_FAILURE;					\
 	}								\
 	__ret;								\
 })
diff --git a/include/video.h b/include/video.h
index 03434a8..9729fa3 100644
--- a/include/video.h
+++ b/include/video.h
@@ -134,6 +134,30 @@
 
 #define video_get_ops(dev)        ((struct video_ops *)(dev)->driver->ops)
 
+/**
+ * struct video_handoff - video information passed from SPL
+ *
+ * This is used when video is set up by SPL, to provide the details to U-Boot
+ * proper.
+ *
+ * @fb: Base address of frame buffer, 0 if not yet known
+ * @size: Frame-buffer size, in bytes
+ * @xsize:	Number of pixel columns (e.g. 1366)
+ * @ysize:	Number of pixels rows (e.g.. 768)
+ * @line_length:	Length of each frame buffer line, in bytes. This can be
+ *		set by the driver, but if not, the uclass will set it after
+ *		probing
+ * @bpix:	Encoded bits per pixel (enum video_log2_bpp)
+ */
+struct video_handoff {
+	u64 fb;
+	u32 size;
+	u16 xsize;
+	u16 ysize;
+	u32 line_length;
+	u8 bpix;
+};
+
 /** enum colour_idx - the 16 colors supported by consoles */
 enum colour_idx {
 	VID_BLACK = 0,
@@ -163,11 +187,11 @@
  * The caller has to guarantee that the color index is less than
  * VID_COLOR_COUNT.
  *
- * @priv	private data of the console device
- * @idx		color index
+ * @priv	private data of the video device (UCLASS_VIDEO)
+ * @idx		color index (e.g. VID_YELLOW)
  * Return:	color value
  */
-u32 video_index_to_colour(struct video_priv *priv, unsigned int idx);
+u32 video_index_to_colour(struct video_priv *priv, enum colour_idx idx);
 
 /**
  * video_reserve() - Reserve frame-buffer memory for video devices
@@ -205,6 +229,22 @@
 int video_fill(struct udevice *dev, u32 colour);
 
 /**
+ * video_fill_part() - Erase a region
+ *
+ * Erase a rectangle of the display within the given bounds.
+ *
+ * @dev:	Device to update
+ * @xstart:	X start position in pixels from the left
+ * @ystart:	Y start position in pixels from the top
+ * @xend:	X end position in pixels from the left
+ * @yend:	Y end position  in pixels from the top
+ * @colour:	Value to write
+ * Return: 0 if OK, -ENOSYS if the display depth is not supported
+ */
+int video_fill_part(struct udevice *dev, int xstart, int ystart, int xend,
+		    int yend, u32 colour);
+
+/**
  * video_sync() - Sync a device's frame buffer with its hardware
  *
  * @vid:	Device to sync
diff --git a/include/video_console.h b/include/video_console.h
index 3db9a7e..2694e44 100644
--- a/include/video_console.h
+++ b/include/video_console.h
@@ -72,6 +72,38 @@
 };
 
 /**
+ * struct vidconsole_colour - Holds colour information
+ *
+ * @colour_fg:	Foreground colour (pixel value)
+ * @colour_bg:	Background colour (pixel value)
+ */
+struct vidconsole_colour {
+	u32 colour_fg;
+	u32 colour_bg;
+};
+
+/**
+ * struct vidconsole_bbox - Bounding box of text
+ *
+ * This describes the bounding box of something, measured in pixels. The x0/y0
+ * pair is inclusive; the x1/y2 pair is exclusive, meaning that it is one pixel
+ * beyond the extent of the object
+ *
+ * @valid: Values are valid (bounding box is known)
+ * @x0: left x position, in pixels from left side
+ * @y0: top y position, in pixels from top
+ * @x1: right x position + 1
+ * @y1: botton y position + 1
+ */
+struct vidconsole_bbox {
+	bool valid;
+	int x0;
+	int y0;
+	int x1;
+	int y1;
+};
+
+/**
  * struct vidconsole_ops - Video console operations
  *
  * These operations work on either an absolute console position (measured
@@ -178,6 +210,20 @@
 	 * Returns: 0 on success, -ENOENT if no such font
 	 */
 	int (*select_font)(struct udevice *dev, const char *name, uint size);
+
+	/**
+	 * measure() - Measure the bounds of some text
+	 *
+	 * @dev:	Device to adjust
+	 * @name:	Font name to use (NULL to use default)
+	 * @size:	Font size to use (0 to use default)
+	 * @text:	Text to measure
+	 * @bbox:	Returns bounding box of text, assuming it is positioned
+	 *		at 0,0
+	 * Returns: 0 on success, -ENOENT if no such font
+	 */
+	int (*measure)(struct udevice *dev, const char *name, uint size,
+		       const char *text, struct vidconsole_bbox *bbox);
 };
 
 /* Get a pointer to the driver operations for a video console device */
@@ -204,6 +250,38 @@
  */
 int vidconsole_select_font(struct udevice *dev, const char *name, uint size);
 
+/*
+ * vidconsole_measure() - Measuring the bounding box of some text
+ *
+ * @dev: Console device to use
+ * @name: Font name, NULL for default
+ * @size: Font size, ignored if @name is NULL
+ * @text: Text to measure
+ * @bbox: Returns nounding box of text
+ * Returns: 0 if OK, -ve on error
+ */
+int vidconsole_measure(struct udevice *dev, const char *name, uint size,
+		       const char *text, struct vidconsole_bbox *bbox);
+
+/**
+ * vidconsole_push_colour() - Temporarily change the font colour
+ *
+ * @dev:	Device to adjust
+ * @fg:		Foreground colour to select
+ * @bg:		Background colour to select
+ * @old:	Place to store the current colour, so it can be restored
+ */
+void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg,
+			    enum colour_idx bg, struct vidconsole_colour *old);
+
+/**
+ * vidconsole_pop_colour() - Restore the original colour
+ *
+ * @dev:	Device to adjust
+ * @old:	Old colour to be restored
+ */
+void vidconsole_pop_colour(struct udevice *dev, struct vidconsole_colour *old);
+
 /**
  * vidconsole_putc_xy() - write a single character to a position
  *
diff --git a/lib/efi_loader/efi_acpi.c b/lib/efi_loader/efi_acpi.c
index 2ddc350..f755af7 100644
--- a/lib/efi_loader/efi_acpi.c
+++ b/lib/efi_loader/efi_acpi.c
@@ -10,6 +10,9 @@
 #include <log.h>
 #include <mapmem.h>
 #include <acpi/acpi_table.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
 
@@ -20,26 +23,28 @@
  */
 efi_status_t efi_acpi_register(void)
 {
-	/* Map within the low 32 bits, to allow for 32bit ACPI tables */
-	u64 acpi = U32_MAX;
+	ulong addr, start, end;
 	efi_status_t ret;
-	ulong addr;
 
-	/* Reserve 64kiB page for ACPI */
-	ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
-				 EFI_ACPI_RECLAIM_MEMORY, 16, &acpi);
+	/* Mark space used for tables */
+	start = ALIGN_DOWN(gd->arch.table_start, EFI_PAGE_MASK);
+	end = ALIGN(gd->arch.table_end, EFI_PAGE_MASK);
+	ret = efi_add_memory_map(start, end - start, EFI_ACPI_RECLAIM_MEMORY);
 	if (ret != EFI_SUCCESS)
 		return ret;
+	if (gd->arch.table_start_high) {
+		start = ALIGN_DOWN(gd->arch.table_start_high, EFI_PAGE_MASK);
+		end = ALIGN(gd->arch.table_end_high, EFI_PAGE_MASK);
+		ret = efi_add_memory_map(start, end - start,
+					 EFI_ACPI_RECLAIM_MEMORY);
+		if (ret != EFI_SUCCESS)
+			return ret;
+	}
 
-	/*
-	 * Generate ACPI tables - we know that efi_allocate_pages() returns
-	 * a 4k-aligned address, so it is safe to assume that
-	 * write_acpi_tables() will write the table at that address.
-	 */
-	addr = map_to_sysmem((void *)(ulong)acpi);
-	write_acpi_tables(addr);
+	addr = gd_acpi_start();
+	printf("EFI using ACPI tables at %lx\n", addr);
 
 	/* And expose them to our EFI payload */
 	return efi_install_configuration_table(&acpi_guid,
-					       (void *)(uintptr_t)acpi);
+					       (void *)(ulong)addr);
 }
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 7ac5f89..a40762c 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -344,3 +344,388 @@
 error:
 	return ret;
 }
+
+/**
+ * efi_bootmgr_enumerate_boot_option() - enumerate the possible bootable media
+ *
+ * @opt:		pointer to the media boot option structure
+ * @volume_handles:	pointer to the efi handles
+ * @count:		number of efi handle
+ * Return:		status code
+ */
+static efi_status_t efi_bootmgr_enumerate_boot_option(struct eficonfig_media_boot_option *opt,
+						      efi_handle_t *volume_handles,
+						      efi_status_t count)
+{
+	u32 i;
+	struct efi_handler *handler;
+	efi_status_t ret = EFI_SUCCESS;
+
+	for (i = 0; i < count; i++) {
+		u16 *p;
+		u16 dev_name[BOOTMENU_DEVICE_NAME_MAX];
+		char *optional_data;
+		struct efi_load_option lo;
+		char buf[BOOTMENU_DEVICE_NAME_MAX];
+		struct efi_device_path *device_path;
+		struct efi_device_path *short_dp;
+
+		ret = efi_search_protocol(volume_handles[i], &efi_guid_device_path, &handler);
+		if (ret != EFI_SUCCESS)
+			continue;
+		ret = efi_protocol_open(handler, (void **)&device_path,
+					efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+		if (ret != EFI_SUCCESS)
+			continue;
+
+		ret = efi_disk_get_device_name(volume_handles[i], buf, BOOTMENU_DEVICE_NAME_MAX);
+		if (ret != EFI_SUCCESS)
+			continue;
+
+		p = dev_name;
+		utf8_utf16_strncpy(&p, buf, strlen(buf));
+
+		/* prefer to short form device path */
+		short_dp = efi_dp_shorten(device_path);
+		if (short_dp)
+			device_path = short_dp;
+
+		lo.label = dev_name;
+		lo.attributes = LOAD_OPTION_ACTIVE;
+		lo.file_path = device_path;
+		lo.file_path_length = efi_dp_size(device_path) + sizeof(END);
+		/*
+		 * Set the dedicated guid to optional_data, it is used to identify
+		 * the boot option that automatically generated by the bootmenu.
+		 * efi_serialize_load_option() expects optional_data is null-terminated
+		 * utf8 string, so set the "1234567" string to allocate enough space
+		 * to store guid, instead of realloc the load_option.
+		 */
+		lo.optional_data = "1234567";
+		opt[i].size = efi_serialize_load_option(&lo, (u8 **)&opt[i].lo);
+		if (!opt[i].size) {
+			ret = EFI_OUT_OF_RESOURCES;
+			goto out;
+		}
+		/* set the guid */
+		optional_data = (char *)opt[i].lo + (opt[i].size - u16_strsize(u"1234567"));
+		memcpy(optional_data, &efi_guid_bootmenu_auto_generated, sizeof(efi_guid_t));
+	}
+
+out:
+	return ret;
+}
+
+/**
+ * efi_bootmgr_delete_invalid_boot_option() - delete non-existing boot option
+ *
+ * @opt:		pointer to the media boot option structure
+ * @count:		number of media boot option structure
+ * Return:		status code
+ */
+static efi_status_t efi_bootmgr_delete_invalid_boot_option(struct eficonfig_media_boot_option *opt,
+							   efi_status_t count)
+{
+	efi_uintn_t size;
+	void *load_option;
+	u32 i, list_size = 0;
+	struct efi_load_option lo;
+	u16 *var_name16 = NULL;
+	u16 varname[] = u"Boot####";
+	efi_status_t ret = EFI_SUCCESS;
+	u16 *delete_index_list = NULL, *p;
+	efi_uintn_t buf_size;
+
+	buf_size = 128;
+	var_name16 = malloc(buf_size);
+	if (!var_name16)
+		return EFI_OUT_OF_RESOURCES;
+
+	var_name16[0] = 0;
+	for (;;) {
+		int index;
+		efi_guid_t guid;
+		efi_uintn_t tmp;
+
+		ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
+		if (ret == EFI_NOT_FOUND) {
+			/*
+			 * EFI_NOT_FOUND indicates we retrieved all EFI variables.
+			 * This should be treated as success.
+			 */
+			ret = EFI_SUCCESS;
+			break;
+		}
+
+		if (ret != EFI_SUCCESS)
+			goto out;
+
+		if (!efi_varname_is_load_option(var_name16, &index))
+			continue;
+
+		efi_create_indexed_name(varname, sizeof(varname), "Boot", index);
+		load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
+		if (!load_option)
+			continue;
+
+		tmp = size;
+		ret = efi_deserialize_load_option(&lo, load_option, &size);
+		if (ret != EFI_SUCCESS)
+			goto next;
+
+		if (size >= sizeof(efi_guid_bootmenu_auto_generated) &&
+		    !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) {
+			for (i = 0; i < count; i++) {
+				if (opt[i].size == tmp &&
+				    memcmp(opt[i].lo, load_option, tmp) == 0) {
+					opt[i].exist = true;
+					break;
+				}
+			}
+
+			/*
+			 * The entire list of variables must be retrieved by
+			 * efi_get_next_variable_name_int() before deleting the invalid
+			 * boot option, just save the index here.
+			 */
+			if (i == count) {
+				p = realloc(delete_index_list, sizeof(u32) *
+					    (list_size + 1));
+				if (!p) {
+					ret = EFI_OUT_OF_RESOURCES;
+					goto out;
+				}
+				delete_index_list = p;
+				delete_index_list[list_size++] = index;
+			}
+		}
+next:
+		free(load_option);
+	}
+
+	/* delete all invalid boot options */
+	for (i = 0; i < list_size; i++) {
+		ret = efi_bootmgr_delete_boot_option(delete_index_list[i]);
+		if (ret != EFI_SUCCESS)
+			goto out;
+	}
+
+out:
+	free(var_name16);
+	free(delete_index_list);
+
+	return ret;
+}
+
+/**
+ * efi_bootmgr_get_unused_bootoption() - get unused "Boot####" index
+ *
+ * @buf:	pointer to the buffer to store boot option variable name
+ * @buf_size:	buffer size
+ * @index:	pointer to store the index in the BootOrder variable
+ * Return:	status code
+ */
+efi_status_t efi_bootmgr_get_unused_bootoption(u16 *buf, efi_uintn_t buf_size,
+					       unsigned int *index)
+{
+	u32 i;
+	efi_status_t ret;
+	efi_uintn_t size;
+
+	if (buf_size < u16_strsize(u"Boot####"))
+		return EFI_BUFFER_TOO_SMALL;
+
+	for (i = 0; i <= 0xFFFF; i++) {
+		size = 0;
+		efi_create_indexed_name(buf, buf_size, "Boot", i);
+		ret = efi_get_variable_int(buf, &efi_global_variable_guid,
+					   NULL, &size, NULL, NULL);
+		if (ret == EFI_BUFFER_TOO_SMALL)
+			continue;
+		else
+			break;
+	}
+
+	if (i > 0xFFFF)
+		return EFI_OUT_OF_RESOURCES;
+
+	*index = i;
+
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_bootmgr_append_bootorder() - append new boot option in BootOrder variable
+ *
+ * @index:	"Boot####" index to append to BootOrder variable
+ * Return:	status code
+ */
+efi_status_t efi_bootmgr_append_bootorder(u16 index)
+{
+	u16 *bootorder;
+	efi_status_t ret;
+	u16 *new_bootorder = NULL;
+	efi_uintn_t last, size, new_size;
+
+	/* append new boot option */
+	bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
+	last = size / sizeof(u16);
+	new_size = size + sizeof(u16);
+	new_bootorder = calloc(1, new_size);
+	if (!new_bootorder) {
+		ret = EFI_OUT_OF_RESOURCES;
+		goto out;
+	}
+	memcpy(new_bootorder, bootorder, size);
+	new_bootorder[last] = index;
+
+	ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
+				   EFI_VARIABLE_NON_VOLATILE |
+				   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				   EFI_VARIABLE_RUNTIME_ACCESS,
+				   new_size, new_bootorder, false);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+out:
+	free(bootorder);
+	free(new_bootorder);
+
+	return ret;
+}
+
+/**
+ * efi_bootmgr_delete_boot_option() - delete selected boot option
+ *
+ * @boot_index:	boot option index to delete
+ * Return:	status code
+ */
+efi_status_t efi_bootmgr_delete_boot_option(u16 boot_index)
+{
+	u16 *bootorder;
+	u16 varname[9];
+	efi_status_t ret;
+	unsigned int index;
+	efi_uintn_t num, size;
+
+	efi_create_indexed_name(varname, sizeof(varname),
+				"Boot", boot_index);
+	ret = efi_set_variable_int(varname, &efi_global_variable_guid,
+				   0, 0, NULL, false);
+	if (ret != EFI_SUCCESS) {
+		log_err("delete boot option(%ls) failed\n", varname);
+		return ret;
+	}
+
+	/* update BootOrder if necessary */
+	bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
+	if (!bootorder)
+		return EFI_SUCCESS;
+
+	num = size / sizeof(u16);
+	if (!efi_search_bootorder(bootorder, num, boot_index, &index))
+		return EFI_SUCCESS;
+
+	memmove(&bootorder[index], &bootorder[index + 1],
+		(num - index - 1) * sizeof(u16));
+	size -= sizeof(u16);
+	ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
+				   EFI_VARIABLE_NON_VOLATILE |
+				   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				   EFI_VARIABLE_RUNTIME_ACCESS,
+				   size, bootorder, false);
+
+	return ret;
+}
+
+/**
+ * efi_bootmgr_update_media_device_boot_option() - generate the media device boot option
+ *
+ * This function enumerates all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
+ * and generate the bootmenu entries.
+ * This function also provide the BOOT#### variable maintenance for
+ * the media device entries.
+ * - Automatically create the BOOT#### variable for the newly detected device,
+ * this BOOT#### variable is distinguished by the special GUID
+ * stored in the EFI_LOAD_OPTION.optional_data
+ * - If the device is not attached to the system, the associated BOOT#### variable
+ * is automatically deleted.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_bootmgr_update_media_device_boot_option(void)
+{
+	u32 i;
+	efi_status_t ret;
+	efi_uintn_t count;
+	efi_handle_t *volume_handles = NULL;
+	struct eficonfig_media_boot_option *opt = NULL;
+
+	ret = efi_locate_handle_buffer_int(BY_PROTOCOL,
+					   &efi_simple_file_system_protocol_guid,
+					   NULL, &count,
+					   (efi_handle_t **)&volume_handles);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	opt = calloc(count, sizeof(struct eficonfig_media_boot_option));
+	if (!opt) {
+		ret = EFI_OUT_OF_RESOURCES;
+		goto out;
+	}
+
+	/* enumerate all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL */
+	ret = efi_bootmgr_enumerate_boot_option(opt, volume_handles, count);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	/*
+	 * System hardware configuration may vary depending on the user setup.
+	 * The boot option is automatically added by the bootmenu.
+	 * If the device is not attached to the system, the boot option needs
+	 * to be deleted.
+	 */
+	ret = efi_bootmgr_delete_invalid_boot_option(opt, count);
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	/* add non-existent boot option */
+	for (i = 0; i < count; i++) {
+		u32 boot_index;
+		u16 var_name[9];
+
+		if (!opt[i].exist) {
+			ret = efi_bootmgr_get_unused_bootoption(var_name, sizeof(var_name),
+								&boot_index);
+			if (ret != EFI_SUCCESS)
+				goto out;
+
+			ret = efi_set_variable_int(var_name, &efi_global_variable_guid,
+						   EFI_VARIABLE_NON_VOLATILE |
+						   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+						   EFI_VARIABLE_RUNTIME_ACCESS,
+						   opt[i].size, opt[i].lo, false);
+			if (ret != EFI_SUCCESS)
+				goto out;
+
+			ret = efi_bootmgr_append_bootorder(boot_index);
+			if (ret != EFI_SUCCESS) {
+				efi_set_variable_int(var_name, &efi_global_variable_guid,
+						     0, 0, NULL, false);
+				goto out;
+			}
+		}
+	}
+
+out:
+	if (opt) {
+		for (i = 0; i < count; i++)
+			free(opt[i].lo);
+	}
+	free(opt);
+	efi_free_pool(volume_handles);
+
+	if (ret == EFI_NOT_FOUND)
+		return EFI_SUCCESS;
+	return ret;
+}
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index d5065f2..2ca7359 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -97,6 +97,12 @@
 					efi_handle_t driver_image_handle,
 					efi_handle_t child_handle);
 
+static
+efi_status_t EFIAPI efi_connect_controller(efi_handle_t controller_handle,
+					   efi_handle_t *driver_image_handle,
+					   struct efi_device_path *remain_device_path,
+					   bool recursive);
+
 /* Called on every callback entry */
 int __efi_entry_check(void)
 {
@@ -1298,7 +1304,7 @@
 				 const efi_guid_t *protocol,
 				 efi_handle_t child_handle)
 {
-	efi_uintn_t number_of_drivers;
+	efi_uintn_t number_of_drivers, tmp;
 	efi_handle_t *driver_handle_buffer;
 	efi_status_t r, ret;
 
@@ -1308,15 +1314,30 @@
 		return ret;
 	if (!number_of_drivers)
 		return EFI_SUCCESS;
-	ret = EFI_NOT_FOUND;
+
+	tmp = number_of_drivers;
 	while (number_of_drivers) {
-		r = EFI_CALL(efi_disconnect_controller(
+		ret = EFI_CALL(efi_disconnect_controller(
 				handle,
 				driver_handle_buffer[--number_of_drivers],
 				child_handle));
-		if (r == EFI_SUCCESS)
-			ret = r;
+		if (ret != EFI_SUCCESS)
+			goto reconnect;
+	}
+
+	free(driver_handle_buffer);
+	return ret;
+
+reconnect:
+	/* Reconnect all disconnected drivers */
+	for (; number_of_drivers < tmp; number_of_drivers++) {
+		r = EFI_CALL(efi_connect_controller(handle,
+						    &driver_handle_buffer[number_of_drivers],
+						    NULL, true));
+		if (r != EFI_SUCCESS)
+			EFI_PRINT("Failed to reconnect controller\n");
 	}
+
 	free(driver_handle_buffer);
 	return ret;
 }
@@ -1352,18 +1373,26 @@
 	r = efi_search_protocol(handle, protocol, &handler);
 	if (r != EFI_SUCCESS)
 		goto out;
+	if (handler->protocol_interface != protocol_interface)
+		return EFI_NOT_FOUND;
 	/* Disconnect controllers */
-	efi_disconnect_all_drivers(efiobj, protocol, NULL);
+	r = efi_disconnect_all_drivers(efiobj, protocol, NULL);
+	if (r != EFI_SUCCESS) {
+		r = EFI_ACCESS_DENIED;
+		goto out;
+	}
 	/* Close protocol */
 	list_for_each_entry_safe(item, pos, &handler->open_infos, link) {
 		if (item->info.attributes ==
 			EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL ||
 		    item->info.attributes == EFI_OPEN_PROTOCOL_GET_PROTOCOL ||
 		    item->info.attributes == EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
-			list_del(&item->link);
+			efi_delete_open_info(item);
 	}
+	/* if agents didn't close the protocols properly */
 	if (!list_empty(&handler->open_infos)) {
 		r =  EFI_ACCESS_DENIED;
+		EFI_CALL(efi_connect_controller(handle, NULL, NULL, true));
 		goto out;
 	}
 	r = efi_remove_protocol(handle, protocol, protocol_interface);
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 1f4ab2b..cdfd16e 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -257,3 +257,28 @@
 
 	return ret;
 }
+
+/**
+ * efi_search_bootorder() - search the boot option index in BootOrder
+ *
+ * @bootorder:	pointer to the BootOrder variable
+ * @num:	number of BootOrder entry
+ * @target:	target boot option index to search
+ * @index:	pointer to store the index of BootOrder variable
+ * Return:	true if exists, false otherwise
+ */
+bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index)
+{
+	u32 i;
+
+	for (i = 0; i < num; i++) {
+		if (target == bootorder[i]) {
+			if (index)
+				*index = i;
+
+			return true;
+		}
+	}
+
+	return false;
+}
diff --git a/lib/efi_selftest/efi_selftest_controllers.c b/lib/efi_selftest/efi_selftest_controllers.c
index 63e674b..02f1957 100644
--- a/lib/efi_selftest/efi_selftest_controllers.c
+++ b/lib/efi_selftest/efi_selftest_controllers.c
@@ -28,6 +28,7 @@
 static efi_handle_t handle_controller;
 static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS];
 static efi_handle_t handle_driver;
+static bool allow_removal;
 
 /*
  * Count child controllers
@@ -85,8 +86,8 @@
 			controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
 	switch (ret) {
 	case EFI_ACCESS_DENIED:
-	case EFI_ALREADY_STARTED:
 		return ret;
+	case EFI_ALREADY_STARTED:
 	case EFI_SUCCESS:
 		break;
 	default:
@@ -124,8 +125,8 @@
 			controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
 	switch (ret) {
 	case EFI_ACCESS_DENIED:
-	case EFI_ALREADY_STARTED:
 		return ret;
+	case EFI_ALREADY_STARTED:
 	case EFI_SUCCESS:
 		break;
 	default:
@@ -238,6 +239,9 @@
 	if (ret != EFI_SUCCESS)
 		efi_st_error("Cannot free buffer\n");
 
+	if (!allow_removal)
+		return EFI_DEVICE_ERROR;
+
 	/* Detach driver from controller */
 	ret = boottime->close_protocol(
 			controller_handle, &guid_controller,
@@ -342,6 +346,7 @@
 		return EFI_ST_FAILURE;
 	}
 	/* Destroy remaining child controllers and disconnect controller */
+	allow_removal = true;
 	ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("Failed to disconnect controller\n");
@@ -393,7 +398,40 @@
 		efi_st_error("Number of children %u != %u\n",
 			     (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
 	}
+
+	allow_removal = false;
+	/* Try to uninstall controller protocol using the wrong interface */
+	ret = boottime->uninstall_protocol_interface(handle_controller,
+						     &guid_controller,
+						     &interface1);
+	if (ret != EFI_NOT_FOUND) {
+		efi_st_error("Interface not checked when uninstalling protocol\n");
+		return EFI_ST_FAILURE;
+	}
+
+	/*
+	 * Uninstall a protocol while Disconnect controller won't
+	 * allow it.
+	 */
+	ret = boottime->uninstall_protocol_interface(handle_controller,
+						     &guid_controller,
+						     &interface2);
+	if (ret != EFI_ACCESS_DENIED) {
+		efi_st_error("Uninstall protocol interface failed\n");
+		return EFI_ST_FAILURE;
+	}
+	/*
+	 * Check number of child controllers and make sure children have
+	 * been reconnected
+	 */
+	ret = count_child_controllers(handle_controller, &guid_controller,
+				      &count);
+	if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
+		efi_st_error("Number of children %u != %u\n",
+			     (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
+	}
-	/* Uninstall controller protocol */
+
+	allow_removal = true;
 	ret = boottime->uninstall_protocol_interface(handle_controller,
 						     &guid_controller,
 						     &interface2);
diff --git a/lib/lzma/LzmaDec.c b/lib/lzma/LzmaDec.c
index 341149f..a90b35c 100644
--- a/lib/lzma/LzmaDec.c
+++ b/lib/lzma/LzmaDec.c
@@ -152,8 +152,7 @@
   const Byte *buf = p->buf;
   UInt32 range = p->range;
   UInt32 code = p->code;
-
-  schedule();
+  unsigned int loop = 0;
 
   do
   {
@@ -162,6 +161,9 @@
     unsigned ttt;
     unsigned posState = processedPos & pbMask;
 
+    if (!(loop++ & 1023))
+	    schedule();
+
     prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
     IF_BIT_0(prob)
     {
@@ -177,8 +179,6 @@
         state -= (state < 4) ? state : 3;
         symbol = 1;
 
-        schedule();
-
         do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
       }
       else
@@ -188,8 +188,6 @@
         state -= (state < 10) ? 3 : 6;
         symbol = 1;
 
-        schedule();
-
         do
         {
           unsigned bit;
@@ -321,8 +319,6 @@
               UInt32 mask = 1;
               unsigned i = 1;
 
-              schedule();
-
               do
               {
                 GET_BIT2(prob + i, i, ; , distance |= mask);
@@ -335,8 +331,6 @@
           {
             numDirectBits -= kNumAlignBits;
 
-            schedule();
-
             do
             {
               NORMALIZE
@@ -409,8 +403,6 @@
           const Byte *lim = dest + curLen;
           dicPos += curLen;
 
-          schedule();
-
           do
             *(dest) = (Byte)*(dest + src);
           while (++dest != lim);
@@ -418,8 +410,6 @@
         else
         {
 
-          schedule();
-
           do
           {
             dic[dicPos++] = dic[pos];
diff --git a/lib/of_live.c b/lib/of_live.c
index 1b5964d..25f7af6 100644
--- a/lib/of_live.c
+++ b/lib/of_live.c
@@ -287,9 +287,12 @@
 	debug("  size is %lx, allocating...\n", size);
 
 	/* Allocate memory for the expanded device tree */
-	mem = malloc(size + 4);
+	mem = memalign(__alignof__(struct device_node), size + 4);
 	memset(mem, '\0', size);
 
+	/* Set up value for dm_test_livetree_align() */
+	*(u32 *)mem = BAD_OF_ROOT;
+
 	*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
 
 	debug("  unflattening %p...\n", mem);
@@ -327,3 +330,9 @@
 
 	return ret;
 }
+
+void of_live_free(struct device_node *root)
+{
+	/* the tree is stored as a contiguous block of memory */
+	free(root);
+}
diff --git a/lib/uuid.c b/lib/uuid.c
index 96e1af3..ab30fbf 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -255,7 +255,7 @@
 		EFI_CERT_TYPE_PKCS7_GUID,
 	},
 #endif
-#ifdef CONFIG_EFI
+#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI)
 	{ "EFI_LZMA_COMPRESSED", EFI_LZMA_COMPRESSED },
 	{ "EFI_DXE_SERVICES", EFI_DXE_SERVICES },
 	{ "EFI_HOB_LIST", EFI_HOB_LIST },
diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c
index 30dfe15..8f767b7 100644
--- a/lib/zlib/inflate.c
+++ b/lib/zlib/inflate.c
@@ -455,8 +455,9 @@
                 if (copy > have) copy = have;
                 if (copy) {
                     if (state->head != Z_NULL &&
-                        state->head->extra != Z_NULL) {
-                        len = state->head->extra_len - state->length;
+                        state->head->extra != Z_NULL &&
+                        (len = state->head->extra_len - state->length) <
+                            state->head->extra_max) {
                         zmemcpy(state->head->extra + len, next,
                                 len + copy > state->head->extra_max ?
                                 state->head->extra_max - len : copy);
diff --git a/net/eth_bootdev.c b/net/eth_bootdev.c
index f7b4196..869adf8 100644
--- a/net/eth_bootdev.c
+++ b/net/eth_bootdev.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Bootdevice for ethernet (uses PXE)
+ * Bootdev for ethernet (uses PXE)
  *
  * Copyright 2021 Google LLC
  * Written by Simon Glass <sjg@chromium.org>
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 2b5f87d..8a4e090 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -226,6 +226,7 @@
 	ut_assert_nextlinen("Buffer:    ");
 	ut_assert_nextline("Size:      253 (595 bytes)");
 	ut_assert_nextline("OS:        Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)");
+	ut_assert_nextline("Cmdline:   (none)");
 	ut_assert_nextline("Logo:      (none)");
 	ut_assert_nextline("FDT:       <NULL>");
 	ut_assert_nextline("Error:     0");
@@ -682,3 +683,265 @@
 	return 0;
 }
 BOOTSTD_TEST(bootflow_menu_theme, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
+/**
+ * check_arg() - Check both the normal case and the buffer-overflow case
+ *
+ * @uts: Unit-test state
+ * @expect_ret: Expected return value (i.e. buffer length)
+ * @expect_str: String expected to be returned
+ * @buf: Buffer to use
+ * @from: Original cmdline to update
+ * @arg: Argument to update (e.g. "console")
+ * @val: Value to set (e.g. "ttyS2") or NULL to delete the argument if present,
+ * "" to set it to an empty value (e.g. "console=") and BOOTFLOWCL_EMPTY to add
+ * it without any value ("initrd")
+ */
+static int check_arg(struct unit_test_state *uts, int expect_ret,
+		     const char *expect_str, char *buf, const char *from,
+		     const char *arg, const char *val)
+{
+	/* check for writing outside the reported bounds */
+	buf[expect_ret] = '[';
+	ut_asserteq(expect_ret,
+		    cmdline_set_arg(buf, expect_ret, from, arg, val, NULL));
+	ut_asserteq_str(expect_str, buf);
+	ut_asserteq('[', buf[expect_ret]);
+
+	/* do the test again but with one less byte in the buffer */
+	ut_asserteq(-E2BIG, cmdline_set_arg(buf, expect_ret - 1, from, arg,
+					    val, NULL));
+
+	return 0;
+}
+
+/* Test of bootflow_cmdline_set_arg() */
+static int test_bootflow_cmdline_set(struct unit_test_state *uts)
+{
+	char buf[50];
+	const int size = sizeof(buf);
+
+	/*
+	 * note that buffer-overflow tests are immediately each test case, just
+	 * top keep the code together
+	 */
+
+	/* add an arg that doesn't already exist, starting from empty */
+	ut_asserteq(-ENOENT, cmdline_set_arg(buf, size, NULL, "me", NULL,
+					     NULL));
+
+	ut_assertok(check_arg(uts, 3, "me", buf, NULL, "me", BOOTFLOWCL_EMPTY));
+	ut_assertok(check_arg(uts, 4, "me=", buf, NULL, "me", ""));
+	ut_assertok(check_arg(uts, 8, "me=fred", buf, NULL, "me", "fred"));
+
+	/* add an arg that doesn't already exist, starting from non-empty */
+	ut_assertok(check_arg(uts, 11, "arg=123 me", buf, "arg=123", "me",
+			      BOOTFLOWCL_EMPTY));
+	ut_assertok(check_arg(uts, 12, "arg=123 me=", buf, "arg=123", "me",
+			      ""));
+	ut_assertok(check_arg(uts, 16, "arg=123 me=fred", buf, "arg=123", "me",
+			      "fred"));
+
+	/* update an arg at the start */
+	ut_assertok(check_arg(uts, 1, "", buf, "arg=123", "arg", NULL));
+	ut_assertok(check_arg(uts, 4, "arg", buf, "arg=123", "arg",
+			      BOOTFLOWCL_EMPTY));
+	ut_assertok(check_arg(uts, 5, "arg=", buf, "arg=123", "arg", ""));
+	ut_assertok(check_arg(uts, 6, "arg=1", buf, "arg=123", "arg", "1"));
+	ut_assertok(check_arg(uts, 9, "arg=1234", buf, "arg=123", "arg",
+			      "1234"));
+
+	/* update an arg at the end */
+	ut_assertok(check_arg(uts, 5, "mary", buf, "mary arg=123", "arg",
+			      NULL));
+	ut_assertok(check_arg(uts, 9, "mary arg", buf, "mary arg=123", "arg",
+			      BOOTFLOWCL_EMPTY));
+	ut_assertok(check_arg(uts, 10, "mary arg=", buf, "mary arg=123", "arg",
+			      ""));
+	ut_assertok(check_arg(uts, 11, "mary arg=1", buf, "mary arg=123", "arg",
+			      "1"));
+	ut_assertok(check_arg(uts, 14, "mary arg=1234", buf, "mary arg=123",
+			      "arg", "1234"));
+
+	/* update an arg in the middle */
+	ut_assertok(check_arg(uts, 16, "mary=abc john=2", buf,
+			      "mary=abc arg=123 john=2", "arg", NULL));
+	ut_assertok(check_arg(uts, 20, "mary=abc arg john=2", buf,
+			      "mary=abc arg=123 john=2", "arg",
+			      BOOTFLOWCL_EMPTY));
+	ut_assertok(check_arg(uts, 21, "mary=abc arg= john=2", buf,
+			      "mary=abc arg=123 john=2", "arg", ""));
+	ut_assertok(check_arg(uts, 22, "mary=abc arg=1 john=2", buf,
+			      "mary=abc arg=123 john=2", "arg", "1"));
+	ut_assertok(check_arg(uts, 25, "mary=abc arg=1234 john=2", buf,
+			      "mary=abc arg=123 john=2", "arg", "1234"));
+
+	/* handle existing args with quotes */
+	ut_assertok(check_arg(uts, 16, "mary=\"abc\" john", buf,
+			      "mary=\"abc\" arg=123 john", "arg", NULL));
+
+	/* handle existing args with quoted spaces */
+	ut_assertok(check_arg(uts, 20, "mary=\"abc def\" john", buf,
+			      "mary=\"abc def\" arg=123 john", "arg", NULL));
+
+	ut_assertok(check_arg(uts, 34, "mary=\"abc def\" arg=123 john def=4",
+			      buf, "mary=\"abc def\" arg=123 john", "def",
+			      "4"));
+
+	/* quote at the start */
+	ut_asserteq(-EBADF, cmdline_set_arg(buf, size,
+					    "mary=\"abc def\" arg=\"123 456\"",
+					    "arg", "\"4 5 6", NULL));
+
+	/* quote at the end */
+	ut_asserteq(-EBADF, cmdline_set_arg(buf, size,
+					    "mary=\"abc def\" arg=\"123 456\"",
+					    "arg", "4 5 6\"", NULL));
+
+	/* quote in the middle */
+	ut_asserteq(-EBADF, cmdline_set_arg(buf, size,
+					    "mary=\"abc def\" arg=\"123 456\"",
+					    "arg", "\"4 \"5 6\"", NULL));
+
+	/* handle updating a quoted arg */
+	ut_assertok(check_arg(uts, 27, "mary=\"abc def\" arg=\"4 5 6\"", buf,
+			      "mary=\"abc def\" arg=\"123 456\"", "arg",
+			      "4 5 6"));
+
+	/* changing a quoted arg to a non-quoted arg */
+	ut_assertok(check_arg(uts, 23, "mary=\"abc def\" arg=789", buf,
+			      "mary=\"abc def\" arg=\"123 456\"", "arg",
+			      "789"));
+
+	/* changing a non-quoted arg to a quoted arg */
+	ut_assertok(check_arg(uts, 29, "mary=\"abc def\" arg=\"456 789\"", buf,
+			      "mary=\"abc def\" arg=123", "arg", "456 789"));
+
+	/* handling of spaces */
+	ut_assertok(check_arg(uts, 8, "arg=123", buf, " ", "arg", "123"));
+	ut_assertok(check_arg(uts, 8, "arg=123", buf, "   ", "arg", "123"));
+	ut_assertok(check_arg(uts, 13, "john arg=123", buf, " john  ", "arg",
+			      "123"));
+	ut_assertok(check_arg(uts, 13, "john arg=123", buf, " john  arg=123  ",
+			      "arg", "123"));
+	ut_assertok(check_arg(uts, 18, "john arg=123 mary", buf,
+			      " john  arg=123 mary ", "arg", "123"));
+
+	/* unchanged arg */
+	ut_assertok(check_arg(uts, 3, "me", buf, "me", "me", BOOTFLOWCL_EMPTY));
+
+	/* arg which starts with the same name */
+	ut_assertok(check_arg(uts, 28, "mary=abc johnathon=2 john=3", buf,
+			      "mary=abc johnathon=2 john=1", "john", "3"));
+
+	return 0;
+}
+BOOTSTD_TEST(test_bootflow_cmdline_set, 0);
+
+/* Test of bootflow_cmdline_set_arg() */
+static int bootflow_set_arg(struct unit_test_state *uts)
+{
+	struct bootflow s_bflow, *bflow = &s_bflow;
+	ulong mem_start;
+
+	ut_assertok(env_set("bootargs", NULL));
+
+	mem_start = ut_check_delta(0);
+
+	/* Do a simple sanity check. Rely on bootflow_cmdline() for the rest */
+	bflow->cmdline = NULL;
+	ut_assertok(bootflow_cmdline_set_arg(bflow, "fred", "123", false));
+	ut_asserteq_str(bflow->cmdline, "fred=123");
+
+	ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", "and here", false));
+	ut_asserteq_str(bflow->cmdline, "fred=123 mary=\"and here\"");
+
+	ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", NULL, false));
+	ut_asserteq_str(bflow->cmdline, "fred=123");
+	ut_assertok(bootflow_cmdline_set_arg(bflow, "fred", NULL, false));
+	ut_asserteq_ptr(bflow->cmdline, NULL);
+
+	ut_asserteq(0, ut_check_delta(mem_start));
+
+	ut_assertok(bootflow_cmdline_set_arg(bflow, "mary", "here", true));
+	ut_asserteq_str("mary=here", env_get("bootargs"));
+	ut_assertok(env_set("bootargs", NULL));
+
+	return 0;
+}
+BOOTSTD_TEST(bootflow_set_arg, 0);
+
+/* Test of bootflow_cmdline_get_arg() */
+static int bootflow_cmdline_get(struct unit_test_state *uts)
+{
+	int pos;
+
+	/* empty string */
+	ut_asserteq(-ENOENT, cmdline_get_arg("", "fred", &pos));
+
+	/* arg with empty value */
+	ut_asserteq(0, cmdline_get_arg("fred= mary", "fred", &pos));
+	ut_asserteq(5, pos);
+
+	/* arg with a value */
+	ut_asserteq(2, cmdline_get_arg("fred=23", "fred", &pos));
+	ut_asserteq(5, pos);
+
+	/* arg with a value */
+	ut_asserteq(3, cmdline_get_arg("mary=1 fred=234", "fred", &pos));
+	ut_asserteq(12, pos);
+
+	/* arg with a value, after quoted arg */
+	ut_asserteq(3, cmdline_get_arg("mary=\"1 2\" fred=234", "fred", &pos));
+	ut_asserteq(16, pos);
+
+	/* arg in the middle */
+	ut_asserteq(0, cmdline_get_arg("mary=\"1 2\" fred john=23", "fred",
+				       &pos));
+	ut_asserteq(15, pos);
+
+	/* quoted arg */
+	ut_asserteq(3, cmdline_get_arg("mary=\"1 2\" fred=\"3 4\" john=23",
+				       "fred", &pos));
+	ut_asserteq(17, pos);
+
+	/* args starting with the same prefix */
+	ut_asserteq(1, cmdline_get_arg("mary=abc johnathon=3 john=1", "john",
+				       &pos));
+	ut_asserteq(26, pos);
+
+	return 0;
+}
+BOOTSTD_TEST(bootflow_cmdline_get, 0);
+
+static int bootflow_cmdline(struct unit_test_state *uts)
+{
+	ut_assertok(run_command("bootflow scan mmc", 0));
+	ut_assertok(run_command("bootflow sel 0", 0));
+	console_record_reset_enable();
+
+	ut_asserteq(1, run_command("bootflow cmdline get fred", 0));
+	ut_assert_nextline("Argument not found");
+	ut_assert_console_end();
+
+	ut_asserteq(0, run_command("bootflow cmdline set fred 123", 0));
+	ut_asserteq(0, run_command("bootflow cmdline get fred", 0));
+	ut_assert_nextline("123");
+
+	ut_asserteq(0, run_command("bootflow cmdline set mary abc", 0));
+	ut_asserteq(0, run_command("bootflow cmdline get mary", 0));
+	ut_assert_nextline("abc");
+
+	ut_asserteq(0, run_command("bootflow cmdline delete fred", 0));
+	ut_asserteq(1, run_command("bootflow cmdline get fred", 0));
+	ut_assert_nextline("Argument not found");
+
+	ut_asserteq(0, run_command("bootflow cmdline clear mary", 0));
+	ut_asserteq(0, run_command("bootflow cmdline get mary", 0));
+	ut_assert_nextline_empty();
+
+	ut_assert_console_end();
+
+	return 0;
+}
+BOOTSTD_TEST(bootflow_cmdline, 0);
diff --git a/test/boot/expo.c b/test/boot/expo.c
index 7104dff..3898f85 100644
--- a/test/boot/expo.c
+++ b/test/boot/expo.c
@@ -5,6 +5,7 @@
  */
 
 #include <common.h>
+#include <command.h>
 #include <dm.h>
 #include <expo.h>
 #include <menu.h>
@@ -13,6 +14,7 @@
 #include <test/suites.h>
 #include <test/ut.h>
 #include "bootstd_common.h"
+#include <test/cedit-test.h>
 #include "../../boot/scene_internal.h"
 
 enum {
@@ -28,6 +30,8 @@
 	OBJ_MENU_TITLE,
 
 	/* strings */
+	STR_SCENE_TITLE,
+
 	STR_TEXT,
 	STR_TEXT2,
 	STR_MENU_TITLE,
@@ -120,7 +124,7 @@
 	struct expo *exp;
 	ulong start_mem;
 	char name[100];
-	int id;
+	int id, title_id;
 
 	start_mem = ut_check_free();
 
@@ -141,21 +145,20 @@
 	ut_asserteq_str(SCENE_NAME1, scn->name);
 
 	/* Set the title */
-	strcpy(name, SCENE_TITLE);
-	ut_assertok(scene_title_set(scn, name));
-	*name = '\0';
-	ut_assertnonnull(scn->title);
-	ut_asserteq_str(SCENE_TITLE, scn->title);
+	title_id = expo_str(exp, "title", STR_SCENE_TITLE, SCENE_TITLE);
+	ut_assert(title_id >= 0);
 
-	/* Use an allocated ID */
+	/* Use an allocated ID - this will be allocated after the title str */
 	scn = NULL;
 	id = scene_new(exp, SCENE_NAME2, 0, &scn);
 	ut_assertnonnull(scn);
-	ut_asserteq(SCENE2, id);
-	ut_asserteq(SCENE2 + 1, exp->next_id);
+	ut_assertok(scene_title_set(scn, title_id));
+	ut_asserteq(STR_SCENE_TITLE + 1, id);
+	ut_asserteq(STR_SCENE_TITLE + 2, exp->next_id);
 	ut_asserteq_ptr(exp, scn->expo);
 
 	ut_asserteq_str(SCENE_NAME2, scn->name);
+	ut_asserteq(title_id, scn->title_id);
 
 	expo_destroy(exp);
 
@@ -225,7 +228,7 @@
 }
 BOOTSTD_TEST(expo_object, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
 
-/* Check setting object attributes */
+/* Check setting object attributes and using themes */
 static int expo_object_attr(struct unit_test_state *uts)
 {
 	struct scene_obj_menu *menu;
@@ -235,6 +238,7 @@
 	struct expo *exp;
 	ulong start_mem;
 	char name[100];
+	ofnode node;
 	char *data;
 	int id;
 
@@ -249,8 +253,8 @@
 	ut_assert(id > 0);
 
 	ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 123, 456));
-	ut_asserteq(123, img->obj.x);
-	ut_asserteq(456, img->obj.y);
+	ut_asserteq(123, img->obj.dim.x);
+	ut_asserteq(456, img->obj.dim.y);
 
 	ut_asserteq(-ENOENT, scene_obj_set_pos(scn, OBJ_TEXT2, 0, 0));
 
@@ -272,6 +276,11 @@
 	ut_asserteq(-ENOENT, scene_menu_set_title(scn, OBJ_TEXT2, OBJ_TEXT));
 	ut_asserteq(-EINVAL, scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT2));
 
+	node = ofnode_path("/bootstd/theme");
+	ut_assert(ofnode_valid(node));
+	ut_assertok(expo_apply_theme(exp, node));
+	ut_asserteq(30, txt->font_size);
+
 	expo_destroy(exp);
 
 	ut_assertok(ut_check_delta(start_mem));
@@ -306,8 +315,8 @@
 	ut_asserteq(0, menu->pointer_id);
 
 	ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400));
-	ut_asserteq(50, menu->obj.x);
-	ut_asserteq(400, menu->obj.y);
+	ut_asserteq(50, menu->obj.dim.x);
+	ut_asserteq(400, menu->obj.dim.y);
 
 	id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE,
 			   "Main Menu", &tit);
@@ -347,29 +356,31 @@
 	ut_asserteq(desc_id, item->desc_id);
 	ut_asserteq(preview_id, item->preview_id);
 
-	/* adding an item should cause the first item to become current */
+	ut_assertok(scene_arrange(scn));
+
+	/* arranging the scene should cause the first item to become current */
 	ut_asserteq(id, menu->cur_item_id);
 
 	/* the title should be at the top */
-	ut_asserteq(menu->obj.x, tit->obj.x);
-	ut_asserteq(menu->obj.y, tit->obj.y);
+	ut_asserteq(menu->obj.dim.x, tit->obj.dim.x);
+	ut_asserteq(menu->obj.dim.y, tit->obj.dim.y);
 
 	/* the first item should be next */
-	ut_asserteq(menu->obj.x, name1->obj.x);
-	ut_asserteq(menu->obj.y + 32, name1->obj.y);
+	ut_asserteq(menu->obj.dim.x, name1->obj.dim.x);
+	ut_asserteq(menu->obj.dim.y + 32, name1->obj.dim.y);
 
-	ut_asserteq(menu->obj.x + 230, key1->obj.x);
-	ut_asserteq(menu->obj.y + 32, key1->obj.y);
+	ut_asserteq(menu->obj.dim.x + 230, key1->obj.dim.x);
+	ut_asserteq(menu->obj.dim.y + 32, key1->obj.dim.y);
 
-	ut_asserteq(menu->obj.x + 200, ptr->obj.x);
-	ut_asserteq(menu->obj.y + 32, ptr->obj.y);
+	ut_asserteq(menu->obj.dim.x + 200, ptr->obj.dim.x);
+	ut_asserteq(menu->obj.dim.y + 32, ptr->obj.dim.y);
 
-	ut_asserteq(menu->obj.x + 280, desc1->obj.x);
-	ut_asserteq(menu->obj.y + 32, desc1->obj.y);
+	ut_asserteq(menu->obj.dim.x + 280, desc1->obj.dim.x);
+	ut_asserteq(menu->obj.dim.y + 32, desc1->obj.dim.y);
 
-	ut_asserteq(-4, prev1->obj.x);
-	ut_asserteq(menu->obj.y + 32, prev1->obj.y);
-	ut_asserteq(false, prev1->obj.hide);
+	ut_asserteq(-4, prev1->obj.dim.x);
+	ut_asserteq(menu->obj.dim.y + 32, prev1->obj.dim.y);
+	ut_asserteq(true, prev1->obj.flags & SCENEOF_HIDE);
 
 	expo_destroy(exp);
 
@@ -470,6 +481,48 @@
 	/* render without a scene */
 	ut_asserteq(-ECHILD, expo_render(exp));
 
+	ut_assertok(expo_calc_dims(exp));
+	ut_assertok(scene_arrange(scn));
+
+	/* check dimensions of text */
+	obj = scene_obj_find(scn, OBJ_TEXT, SCENEOBJT_NONE);
+	ut_assertnonnull(obj);
+	ut_asserteq(400, obj->dim.x);
+	ut_asserteq(100, obj->dim.y);
+	ut_asserteq(126, obj->dim.w);
+	ut_asserteq(40, obj->dim.h);
+
+	/* check dimensions of image */
+	obj = scene_obj_find(scn, OBJ_LOGO, SCENEOBJT_NONE);
+	ut_assertnonnull(obj);
+	ut_asserteq(50, obj->dim.x);
+	ut_asserteq(20, obj->dim.y);
+	ut_asserteq(160, obj->dim.w);
+	ut_asserteq(160, obj->dim.h);
+
+	/* check dimensions of menu labels - both should be the same width */
+	obj = scene_obj_find(scn, ITEM1_LABEL, SCENEOBJT_NONE);
+	ut_assertnonnull(obj);
+	ut_asserteq(50, obj->dim.x);
+	ut_asserteq(436, obj->dim.y);
+	ut_asserteq(29, obj->dim.w);
+	ut_asserteq(18, obj->dim.h);
+
+	obj = scene_obj_find(scn, ITEM2_LABEL, SCENEOBJT_NONE);
+	ut_assertnonnull(obj);
+	ut_asserteq(50, obj->dim.x);
+	ut_asserteq(454, obj->dim.y);
+	ut_asserteq(29, obj->dim.w);
+	ut_asserteq(18, obj->dim.h);
+
+	/* check dimensions of menu */
+	obj = scene_obj_find(scn, OBJ_MENU, SCENEOBJT_NONE);
+	ut_assertnonnull(obj);
+	ut_asserteq(50, obj->dim.x);
+	ut_asserteq(400, obj->dim.y);
+	ut_asserteq(160, obj->dim.w);
+	ut_asserteq(160, obj->dim.h);
+
 	/* render it */
 	expo_set_scene_id(exp, SCENE1);
 	ut_assertok(expo_render(exp));
@@ -479,16 +532,16 @@
 
 	ut_assertok(expo_action_get(exp, &act));
 
-	ut_asserteq(EXPOACT_POINT, act.type);
+	ut_asserteq(EXPOACT_POINT_ITEM, act.type);
 	ut_asserteq(ITEM2, act.select.id);
 	ut_assertok(expo_render(exp));
 
 	/* make sure only the preview for the second item is shown */
 	obj = scene_obj_find(scn, ITEM1_PREVIEW, SCENEOBJT_NONE);
-	ut_asserteq(true, obj->hide);
+	ut_asserteq(true, obj->flags & SCENEOF_HIDE);
 
 	obj = scene_obj_find(scn, ITEM2_PREVIEW, SCENEOBJT_NONE);
-	ut_asserteq(false, obj->hide);
+	ut_asserteq(false, obj->flags & SCENEOF_HIDE);
 
 	/* select it */
 	ut_assertok(expo_send_key(exp, BKEY_SELECT));
@@ -504,7 +557,7 @@
 	ut_assert_console_end();
 
 	/* now try in text mode */
-	exp_set_text_mode(exp, true);
+	expo_set_text_mode(exp, true);
 	ut_assertok(expo_render(exp));
 
 	ut_assert_nextline("U-Boot    :    Boot Menu");
@@ -519,7 +572,7 @@
 
 	ut_assertok(expo_action_get(exp, &act));
 
-	ut_asserteq(EXPOACT_POINT, act.type);
+	ut_asserteq(EXPOACT_POINT_ITEM, act.type);
 	ut_asserteq(ITEM1, act.select.id);
 
 	ut_assertok(expo_render(exp));
@@ -537,3 +590,125 @@
 	return 0;
 }
 BOOTSTD_TEST(expo_render_image, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
+/* Check building an expo from a devicetree description */
+static int expo_test_build(struct unit_test_state *uts)
+{
+	struct scene_obj_menu *menu;
+	struct scene_menitem *item;
+	struct scene_obj_txt *txt;
+	struct scene_obj *obj;
+	struct scene *scn;
+	struct expo *exp;
+	int count;
+	ofnode node;
+
+	node = ofnode_path("/cedit");
+	ut_assert(ofnode_valid(node));
+	ut_assertok(expo_build(node, &exp));
+
+	ut_asserteq_str("name", exp->name);
+	ut_asserteq(0, exp->scene_id);
+	ut_asserteq(ID_DYNAMIC_START + 20, exp->next_id);
+	ut_asserteq(false, exp->popup);
+
+	/* check the scene */
+	scn = expo_lookup_scene_id(exp, ID_SCENE1);
+	ut_assertnonnull(scn);
+	ut_asserteq_str("main", scn->name);
+	ut_asserteq(ID_SCENE1, scn->id);
+	ut_asserteq(ID_DYNAMIC_START + 1, scn->title_id);
+	ut_asserteq(0, scn->highlight_id);
+
+	/* check the title */
+	txt = scene_obj_find(scn, scn->title_id, SCENEOBJT_NONE);
+	ut_assertnonnull(txt);
+	obj = &txt->obj;
+	ut_asserteq_ptr(scn, obj->scene);
+	ut_asserteq_str("title", obj->name);
+	ut_asserteq(scn->title_id, obj->id);
+	ut_asserteq(SCENEOBJT_TEXT, obj->type);
+	ut_asserteq(0, obj->flags);
+	ut_asserteq_str("Test Configuration", expo_get_str(exp, txt->str_id));
+
+	/* check the menu */
+	menu = scene_obj_find(scn, ID_CPU_SPEED, SCENEOBJT_NONE);
+	obj = &menu->obj;
+	ut_asserteq_ptr(scn, obj->scene);
+	ut_asserteq_str("cpu-speed", obj->name);
+	ut_asserteq(ID_CPU_SPEED, obj->id);
+	ut_asserteq(SCENEOBJT_MENU, obj->type);
+	ut_asserteq(0, obj->flags);
+
+	txt = scene_obj_find(scn, menu->title_id, SCENEOBJT_NONE);
+	ut_asserteq_str("CPU speed", expo_get_str(exp, txt->str_id));
+
+	ut_asserteq(0, menu->cur_item_id);
+	ut_asserteq(0, menu->pointer_id);
+
+	/* check the items */
+	item = list_first_entry(&menu->item_head, struct scene_menitem,
+				sibling);
+	ut_asserteq_str("00", item->name);
+	ut_asserteq(ID_CPU_SPEED_1, item->id);
+	ut_asserteq(0, item->key_id);
+	ut_asserteq(0, item->desc_id);
+	ut_asserteq(0, item->preview_id);
+	ut_asserteq(0, item->flags);
+
+	txt = scene_obj_find(scn, item->label_id, SCENEOBJT_NONE);
+	ut_asserteq_str("2 GHz", expo_get_str(exp, txt->str_id));
+
+	count = 0;
+	list_for_each_entry(item, &menu->item_head, sibling)
+		count++;
+	ut_asserteq(3, count);
+
+	expo_destroy(exp);
+
+	return 0;
+}
+BOOTSTD_TEST(expo_test_build, UT_TESTF_DM);
+
+/* Check the cedit command */
+static int expo_cedit(struct unit_test_state *uts)
+{
+	extern struct expo *cur_exp;
+	struct scene_obj_menu *menu;
+	struct scene_obj_txt *txt;
+	struct expo *exp;
+	struct scene *scn;
+
+	if (!IS_ENABLED(CONFIG_CMD_CEDIT))
+		return -EAGAIN;
+
+	ut_assertok(run_command("cedit load hostfs - cedit.dtb", 0));
+
+	console_record_reset_enable();
+
+	/*
+	 * ^N  Move down to second menu
+	 * ^M  Open menu
+	 * ^N  Move down to second item
+	 * ^M  Select item
+	 * \e  Quit
+	 */
+	console_in_puts("\x0e\x0d\x0e\x0d\e");
+	ut_assertok(run_command("cedit run", 0));
+
+	exp = cur_exp;
+	scn = expo_lookup_scene_id(exp, exp->scene_id);
+	ut_assertnonnull(scn);
+
+	menu = scene_obj_find(scn, scn->highlight_id, SCENEOBJT_NONE);
+	ut_assertnonnull(menu);
+
+	txt = scene_obj_find(scn, menu->title_id, SCENEOBJT_NONE);
+	ut_assertnonnull(txt);
+	ut_asserteq_str("AC Power", expo_get_str(exp, txt->str_id));
+
+	ut_asserteq(ID_AC_ON, menu->cur_item_id);
+
+	return 0;
+}
+BOOTSTD_TEST(expo_cedit, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
diff --git a/test/boot/files/expo_layout.dts b/test/boot/files/expo_layout.dts
new file mode 100644
index 0000000..55d5c91
--- /dev/null
+++ b/test/boot/files/expo_layout.dts
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sample expo screen layout
+ */
+
+/dts-v1/;
+
+/*
+enum {
+	ZERO,
+	ID_PROMPT,
+
+	ID_SCENE1,
+	ID_SCENE1_TITLE,
+
+	ID_CPU_SPEED,
+	ID_CPU_SPEED_TITLE,
+	ID_CPU_SPEED_1,
+	ID_CPU_SPEED_2,
+	ID_CPU_SPEED_3,
+
+	ID_POWER_LOSS,
+	ID_AC_OFF,
+	ID_AC_ON,
+	ID_AC_MEMORY,
+
+	ID_DYNAMIC_START,
+};
+*/
+
+/ {
+	dynamic-start = <ID_DYNAMIC_START>;
+
+	scenes {
+		main {
+			id = <ID_SCENE1>;
+
+			/* value refers to the matching id in /strings */
+			title-id = <ID_SCENE1_TITLE>;
+
+			/* simple string is used as it is */
+			prompt = "UP and DOWN to choose, ENTER to select";
+
+			/* defines a menu within the scene */
+			cpu-speed {
+				type = "menu";
+				id = <ID_CPU_SPEED>;
+
+				/*
+				 * has both string and ID. The string is ignored
+				 * if the ID is present and points to a string
+				 */
+				title = "CPU speed";
+				title-id = <ID_CPU_SPEED_TITLE>;
+
+				/* menu items as simple strings */
+				item-label = "2 GHz", "2.5 GHz", "3 GHz";
+
+				/* IDs for the menu items */
+				item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
+					ID_CPU_SPEED_3>;
+			};
+
+			power-loss {
+				type = "menu";
+				id = <ID_POWER_LOSS>;
+
+				title = "AC Power";
+				item-label = "Always Off", "Always On",
+					"Memory";
+
+				item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
+			};
+		};
+	};
+
+	strings {
+		title {
+			id = <ID_SCENE1_TITLE>;
+			value = "Test Configuration";
+			value-es = "configuración de prueba";
+		};
+	};
+};
diff --git a/test/cmd/bdinfo.c b/test/cmd/bdinfo.c
index 9068df7..8c09281 100644
--- a/test/cmd/bdinfo.c
+++ b/test/cmd/bdinfo.c
@@ -16,6 +16,7 @@
 #include <env.h>
 #include <lmb.h>
 #include <net.h>
+#include <serial.h>
 #include <video.h>
 #include <vsprintf.h>
 #include <asm/cache.h>
@@ -27,19 +28,25 @@
 /* Declare a new bdinfo test */
 #define BDINFO_TEST(_name, _flags)	UNIT_TEST(_name, _flags, bdinfo_test)
 
-static void bdinfo_test_num_l(struct unit_test_state *uts,
-			      const char *name, ulong value)
+static int test_num_l(struct unit_test_state *uts, const char *name,
+		      ulong value)
 {
-	ut_assert_nextline("%-12s= 0x%0*lx", name, 2 * (int)sizeof(value), value);
+	ut_assert_nextline("%-12s= 0x%0*lx", name, 2 * (int)sizeof(value),
+			   value);
+
+	return 0;
 }
 
-static void bdinfo_test_num_ll(struct unit_test_state *uts,
-			       const char *name, unsigned long long value)
+static int test_num_ll(struct unit_test_state *uts, const char *name,
+		       unsigned long long value)
 {
-	ut_assert_nextline("%-12s= 0x%.*llx", name, 2 * (int)sizeof(ulong), value);
+	ut_assert_nextline("%-12s= 0x%.*llx", name, 2 * (int)sizeof(ulong),
+			   value);
+
+	return 0;
 }
 
-static void test_eth(struct unit_test_state *uts)
+static int test_eth(struct unit_test_state *uts)
 {
 	const int idx = eth_get_dev_index();
 	uchar enetaddr[6];
@@ -59,9 +66,11 @@
 	else
 		ut_assert_nextline("%-12s= %pM", name, enetaddr);
 	ut_assert_nextline("IP addr     = %s", env_get("ipaddr"));
+
+	return 0;
 }
 
-static void test_video_info(struct unit_test_state *uts)
+static int test_video_info(struct unit_test_state *uts)
 {
 	const struct udevice *dev;
 	struct uclass *uc;
@@ -73,22 +82,25 @@
 			struct video_priv *upriv = dev_get_uclass_priv(dev);
 			struct video_uc_plat *plat = dev_get_uclass_plat(dev);
 
-			bdinfo_test_num_ll(uts, "FB base", (ulong)upriv->fb);
+			ut_assertok(test_num_ll(uts, "FB base",
+						(ulong)upriv->fb));
 			if (upriv->copy_fb) {
-				bdinfo_test_num_ll(uts, "FB copy",
-						   (ulong)upriv->copy_fb);
-				bdinfo_test_num_l(uts, " copy size",
-						  plat->copy_size);
+				ut_assertok(test_num_ll(uts, "FB copy",
+							(ulong)upriv->copy_fb));
+				ut_assertok(test_num_l(uts, " copy size",
+						       plat->copy_size));
 			}
 			ut_assert_nextline("%-12s= %dx%dx%d", "FB size",
 					   upriv->xsize, upriv->ysize,
 					   1 << upriv->bpix);
 		}
 	}
+
+	return 0;
 }
 
-static void lmb_test_dump_region(struct unit_test_state *uts,
-				 struct lmb_region *rgn, char *name)
+static int lmb_test_dump_region(struct unit_test_state *uts,
+				struct lmb_region *rgn, char *name)
 {
 	unsigned long long base, size, end;
 	enum lmb_flags flags;
@@ -105,13 +117,17 @@
 		ut_assert_nextline(" %s[%d]\t[0x%llx-0x%llx], 0x%08llx bytes flags: %x",
 				   name, i, base, end, size, flags);
 	}
+
+	return 0;
 }
 
-static void lmb_test_dump_all(struct unit_test_state *uts, struct lmb *lmb)
+static int lmb_test_dump_all(struct unit_test_state *uts, struct lmb *lmb)
 {
 	ut_assert_nextline("lmb_dump_all:");
 	lmb_test_dump_region(uts, &lmb->memory, "memory");
 	lmb_test_dump_region(uts, &lmb->reserved, "reserved");
+
+	return 0;
 }
 
 static int bdinfo_test_move(struct unit_test_state *uts)
@@ -123,44 +139,48 @@
 	ut_assertok(console_record_reset_enable());
 	ut_assertok(run_commandf("bdinfo"));
 
-	bdinfo_test_num_l(uts, "boot_params", 0);
+	ut_assertok(test_num_l(uts, "boot_params", 0));
 
 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
 		if (bd->bi_dram[i].size) {
-			bdinfo_test_num_l(uts, "DRAM bank",  i);
-			bdinfo_test_num_ll(uts, "-> start", bd->bi_dram[i].start);
-			bdinfo_test_num_ll(uts, "-> size", bd->bi_dram[i].size);
+			ut_assertok(test_num_l(uts, "DRAM bank", i));
+			ut_assertok(test_num_ll(uts, "-> start",
+						bd->bi_dram[i].start));
+			ut_assertok(test_num_ll(uts, "-> size",
+						bd->bi_dram[i].size));
 		}
 	}
 
 	/* CONFIG_SYS_HAS_SRAM testing not supported */
-	bdinfo_test_num_l(uts, "flashstart", 0);
-	bdinfo_test_num_l(uts, "flashsize", 0);
-	bdinfo_test_num_l(uts, "flashoffset", 0);
+	ut_assertok(test_num_l(uts, "flashstart", 0));
+	ut_assertok(test_num_l(uts, "flashsize", 0));
+	ut_assertok(test_num_l(uts, "flashoffset", 0));
 	ut_assert_nextline("baudrate    = %lu bps",
 			   env_get_ulong("baudrate", 10, 1234));
-	bdinfo_test_num_l(uts, "relocaddr", gd->relocaddr);
-	bdinfo_test_num_l(uts, "reloc off", gd->reloc_off);
+	ut_assertok(test_num_l(uts, "relocaddr", gd->relocaddr));
+	ut_assertok(test_num_l(uts, "reloc off", gd->reloc_off));
 	ut_assert_nextline("%-12s= %u-bit", "Build", (uint)sizeof(void *) * 8);
 
 	if (IS_ENABLED(CONFIG_CMD_NET))
-		test_eth(uts);
+		ut_assertok(test_eth(uts));
 
 	/*
 	 * Make sure environment variable "fdtcontroladdr" address
 	 * matches mapped control DT address.
 	 */
 	ut_assert(map_to_sysmem(gd->fdt_blob) == env_get_hex("fdtcontroladdr", 0x1234));
-	bdinfo_test_num_l(uts, "fdt_blob", (ulong)map_to_sysmem(gd->fdt_blob));
-	bdinfo_test_num_l(uts, "new_fdt", (ulong)map_to_sysmem(gd->new_fdt));
-	bdinfo_test_num_l(uts, "fdt_size", (ulong)gd->fdt_size);
+	ut_assertok(test_num_l(uts, "fdt_blob",
+			       (ulong)map_to_sysmem(gd->fdt_blob)));
+	ut_assertok(test_num_l(uts, "new_fdt",
+			       (ulong)map_to_sysmem(gd->new_fdt)));
+	ut_assertok(test_num_l(uts, "fdt_size", (ulong)gd->fdt_size));
 
 	if (IS_ENABLED(CONFIG_VIDEO))
 		test_video_info(uts);
 
 	/* The gd->multi_dtb_fit may not be available, hence, #if below. */
 #if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
-	bdinfo_test_num_l(uts, "multi_dtb_fit", (ulong)gd->multi_dtb_fit);
+	ut_assertok(test_num_l(uts, "multi_dtb_fit", (ulong)gd->multi_dtb_fit));
 #endif
 
 	if (IS_ENABLED(CONFIG_LMB) && gd->fdt_blob) {
@@ -172,6 +192,26 @@
 			ut_assert_nextline("devicetree  = %s", fdtdec_get_srcname());
 	}
 
+	if (IS_ENABLED(CONFIG_DM_SERIAL)) {
+		struct serial_device_info info;
+
+		ut_assertnonnull(gd->cur_serial_dev);
+		ut_assertok(serial_getinfo(gd->cur_serial_dev, &info));
+
+		ut_assertok(test_num_l(uts, "serial addr", info.addr));
+		ut_assertok(test_num_l(uts, " width", info.reg_width));
+		ut_assertok(test_num_l(uts, " shift", info.reg_shift));
+		ut_assertok(test_num_l(uts, " offset", info.reg_offset));
+		ut_assertok(test_num_l(uts, " clock", info.clock));
+	}
+
+	if (IS_ENABLED(CONFIG_CMD_BDINFO_EXTRA)) {
+		ut_assert_nextlinen("stack ptr");
+		ut_assertok(test_num_ll(uts, "ram_top ptr",
+					(unsigned long long)gd->ram_top));
+		ut_assertok(test_num_l(uts, "malloc base", gd_malloc_start()));
+	}
+
 	ut_assertok(ut_check_console_end(uts));
 
 	return 0;
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index 818f715..77eb524 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -609,3 +609,41 @@
 	return 0;
 }
 DM_TEST(dm_test_acpi_cmd_items, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Test 'acpi set' command */
+static int dm_test_acpi_cmd_set(struct unit_test_state *uts)
+{
+	struct acpi_ctx ctx;
+	ulong addr;
+	void *buf;
+
+	gd_set_acpi_start(0);
+
+	console_record_reset();
+	ut_asserteq(0, gd_acpi_start());
+	ut_assertok(run_command("acpi set", 0));
+	ut_assert_nextline("ACPI pointer: 0");
+
+	buf = memalign(16, BUF_SIZE);
+	ut_assertnonnull(buf);
+	addr = map_to_sysmem(buf);
+	ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr));
+
+	ut_assertok(acpi_write_dev_tables(&ctx));
+
+	ut_assertok(run_command("acpi set", 0));
+	ut_assert_nextline("ACPI pointer: %lx", addr);
+
+	ut_assertok(run_command("acpi set 0", 0));
+	ut_assert_nextline("Setting ACPI pointer to 0");
+	ut_asserteq(0, gd_acpi_start());
+
+	ut_assertok(run_commandf("acpi set %lx", addr));
+	ut_assert_nextline("Setting ACPI pointer to %lx", addr);
+	ut_asserteq(addr, gd_acpi_start());
+
+	ut_assert_console_end();
+
+	return 0;
+}
+DM_TEST(dm_test_acpi_cmd_set, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c
index 473a8ce..6fbebc7 100644
--- a/test/dm/ofnode.c
+++ b/test/dm/ofnode.c
@@ -1240,3 +1240,48 @@
 	return 0;
 }
 DM_TEST(dm_test_ofnode_copy_props_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT);
+
+/* check that the livetree is aligned to a structure boundary */
+static int dm_test_livetree_align(struct unit_test_state *uts)
+{
+	const int align = __alignof__(struct unit_test_state);
+	struct device_node *node;
+	u32 *sentinel;
+	ulong start;
+
+	start = (ulong)gd_of_root();
+	ut_asserteq(start, ALIGN(start, align));
+
+	node = gd_of_root();
+	sentinel = (void *)node - sizeof(u32);
+
+	/*
+	 * The sentinel should be overwritten with the root node. If it isn't,
+	 * then the root node is not at the very start of the livetree memory
+	 * area, and free(root) will fail to free the memory used by the
+	 * livetree.
+	 */
+	ut_assert(*sentinel != BAD_OF_ROOT);
+
+	return 0;
+}
+DM_TEST(dm_test_livetree_align, UT_TESTF_LIVE_TREE);
+
+/* check that it is possible to load an arbitrary livetree */
+static int dm_test_livetree_ensure(struct unit_test_state *uts)
+{
+	oftree tree;
+	ofnode node;
+
+	/* read from other.dtb */
+	ut_assertok(test_load_other_fdt(uts));
+	tree = oftree_from_fdt(uts->other_fdt);
+	ut_assert(oftree_valid(tree));
+	node = oftree_path(tree, "/node/subnode");
+	ut_assert(ofnode_valid(node));
+	ut_asserteq_str("sandbox-other2",
+			ofnode_read_string(node, "compatible"));
+
+	return 0;
+}
+DM_TEST(dm_test_livetree_ensure, 0);
diff --git a/test/dm/part.c b/test/dm/part.c
index 35e99ee..d6e4345 100644
--- a/test/dm/part.c
+++ b/test/dm/part.c
@@ -17,10 +17,12 @@
 	struct blk_desc *mmc_dev_desc;
 	struct disk_partition part_info;
 
-	ut_asserteq(expected,
-		    part_get_info_by_dev_and_name_or_num("mmc", part_str,
-							 &mmc_dev_desc,
-							 &part_info, whole));
+	int ret = part_get_info_by_dev_and_name_or_num("mmc", part_str,
+						       &mmc_dev_desc,
+						       &part_info, whole);
+
+	ut_assertf(expected == ret, "test(%d, \"%s\", %d) == %d", expected,
+		   part_str, whole, ret);
 	return 0;
 }
 
@@ -76,15 +78,15 @@
 	test(-EINVAL, "#test1", true);
 	test(1, "2", false);
 	test(1, "2", true);
-	test(-ENOENT, "1:0", false);
-	test(0, "1:0", true);
-	test(1, "1:1", false);
-	test(2, "1:2", false);
-	test(1, "1.0", false);
-	test(0, "1.0:0", true);
-	test(1, "1.0:1", false);
-	test(2, "1.0:2", false);
-	test(-EINVAL, "1#bogus", false);
+	test(-ENOENT, "2:0", false);
+	test(0, "2:0", true);
+	test(1, "2:1", false);
+	test(2, "2:2", false);
+	test(1, "2.0", false);
+	test(0, "2.0:0", true);
+	test(1, "2.0:1", false);
+	test(2, "2.0:2", false);
+	test(-EINVAL, "2#bogus", false);
 	test(1, "2#test1", false);
 	test(2, "2#test2", false);
 	ret = 0;
@@ -106,3 +108,90 @@
 	return 0;
 }
 DM_TEST(dm_test_part_bootable, UT_TESTF_SCAN_FDT);
+
+static int do_get_info_test(struct unit_test_state *uts,
+			    struct blk_desc *dev_desc, int part, int part_type,
+			    struct disk_partition const *reference)
+{
+	struct disk_partition p;
+	int ret;
+
+	memset(&p, 0, sizeof(p));
+
+	ret = part_get_info_by_type(dev_desc, part, part_type, &p);
+	printf("part_get_info_by_type(%d, 0x%x) = %d\n", part, part_type, ret);
+	if (ut_assertok(ret)) {
+		return 0;
+	}
+
+	ut_asserteq(reference->start, p.start);
+	ut_asserteq(reference->size, p.size);
+	ut_asserteq(reference->sys_ind, p.sys_ind);
+
+	return 0;
+}
+
+static int dm_test_part_get_info_by_type(struct unit_test_state *uts)
+{
+	char str_disk_guid[UUID_STR_LEN + 1];
+	struct blk_desc *mmc_dev_desc;
+	struct disk_partition gpt_parts[] = {
+		{
+			.start = 48, /* GPT data takes up the first 34 blocks or so */
+			.size = 1,
+			.name = "test1",
+			.sys_ind = 0,
+		},
+		{
+			.start = 49,
+			.size = 1,
+			.name = "test2",
+			.sys_ind = 0,
+		},
+	};
+	struct disk_partition mbr_parts[] = {
+		{
+			.start = 1,
+			.size = 33,
+			.name = "gpt",
+			.sys_ind = EFI_PMBR_OSTYPE_EFI_GPT,
+		},
+		{
+			.start = 48,
+			.size = 1,
+			.name = "test1",
+			.sys_ind = 0x83,
+		},
+	};
+
+	ut_asserteq(2, blk_get_device_by_str("mmc", "2", &mmc_dev_desc));
+	if (CONFIG_IS_ENABLED(RANDOM_UUID)) {
+		gen_rand_uuid_str(gpt_parts[0].uuid, UUID_STR_FORMAT_STD);
+		gen_rand_uuid_str(gpt_parts[1].uuid, UUID_STR_FORMAT_STD);
+		gen_rand_uuid_str(str_disk_guid, UUID_STR_FORMAT_STD);
+	}
+	ut_assertok(gpt_restore(mmc_dev_desc, str_disk_guid, gpt_parts,
+				ARRAY_SIZE(gpt_parts)));
+
+	ut_assertok(write_mbr_partitions(mmc_dev_desc, mbr_parts,
+					 ARRAY_SIZE(mbr_parts), 0));
+
+#define get_info_test(_part, _part_type, _reference) \
+	ut_assertok(do_get_info_test(uts, mmc_dev_desc, _part, _part_type, \
+				     _reference))
+
+	for (int i = 0; i < ARRAY_SIZE(gpt_parts); i++) {
+		get_info_test(i + 1, PART_TYPE_UNKNOWN, &gpt_parts[i]);
+	}
+
+	for (int i = 0; i < ARRAY_SIZE(mbr_parts); i++) {
+		get_info_test(i + 1, PART_TYPE_DOS, &mbr_parts[i]);
+	}
+
+	for (int i = 0; i < ARRAY_SIZE(gpt_parts); i++) {
+		get_info_test(i + 1, PART_TYPE_EFI, &gpt_parts[i]);
+	}
+
+	return 0;
+}
+DM_TEST(dm_test_part_get_info_by_type, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/dm/video.c b/test/dm/video.c
index 3077815..0534ee9 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -556,7 +556,7 @@
 	ut_assertok(video_get_nologo(uts, &dev));
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
-	ut_asserteq(12237, compress_frame_buffer(uts, dev));
+	ut_asserteq(12174, compress_frame_buffer(uts, dev));
 
 	return 0;
 }
@@ -577,7 +577,7 @@
 	ut_assertok(video_get_nologo(uts, &dev));
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
-	ut_asserteq(35030, compress_frame_buffer(uts, dev));
+	ut_asserteq(34287, compress_frame_buffer(uts, dev));
 
 	return 0;
 }
@@ -598,7 +598,7 @@
 	ut_assertok(video_get_nologo(uts, &dev));
 	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
 	vidconsole_put_string(con, test_string);
-	ut_asserteq(29018, compress_frame_buffer(uts, dev));
+	ut_asserteq(29471, compress_frame_buffer(uts, dev));
 
 	return 0;
 }
diff --git a/test/py/tests/test_cat/conftest.py b/test/py/tests/test_cat/conftest.py
index fc396f5..320e7eb 100644
--- a/test/py/tests/test_cat/conftest.py
+++ b/test/py/tests/test_cat/conftest.py
@@ -32,4 +32,5 @@
         pytest.skip('Setup failed')
     finally:
         shutil.rmtree(mnt_point)
-        os.remove(image_path)
+        if os.path.exists(image_path):
+            os.remove(image_path)
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index 0b45863..aa1d477 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -282,6 +282,15 @@
         copy_prepared_image(cons, mmc_dev, fname)
 
 
+def setup_cedit_file(cons):
+    infname = os.path.join(cons.config.source_dir,
+                           'test/boot/files/expo_layout.dts')
+    expo_tool = os.path.join(cons.config.source_dir, 'tools/expo.py')
+    outfname = 'cedit.dtb'
+    u_boot_utils.run_and_log(
+        cons, f'{expo_tool} -e {infname} -l {infname} -o {outfname}')
+
+
 @pytest.mark.buildconfigspec('ut_dm')
 def test_ut_dm_init(u_boot_console):
     """Initialize data for ut dm tests."""
@@ -319,6 +328,7 @@
 
     setup_bootflow_image(u_boot_console)
     setup_bootmenu_image(u_boot_console)
+    setup_cedit_file(u_boot_console)
 
     # Restart so that the new mmc1.img is picked up
     u_boot_console.restart_uboot()
diff --git a/test/py/tests/test_xxd/conftest.py b/test/py/tests/test_xxd/conftest.py
index f35b8f1..47c7cce 100644
--- a/test/py/tests/test_xxd/conftest.py
+++ b/test/py/tests/test_xxd/conftest.py
@@ -32,4 +32,5 @@
         pytest.skip('Setup failed')
     finally:
         shutil.rmtree(mnt_point)
-        os.remove(image_path)
+        if os.path.exists(image_path):
+            os.remove(image_path)
diff --git a/test/test-main.c b/test/test-main.c
index 2a3b2ba..778bf0a 100644
--- a/test/test-main.c
+++ b/test/test-main.c
@@ -476,7 +476,8 @@
 	 *   (for sandbox we handle this by copying the tree, but not for other
 	 *    boards)
 	 */
-	if (!(test->flags & UT_TESTF_LIVE_TREE) &&
+	if ((test->flags & UT_TESTF_SCAN_FDT) &&
+	    !(test->flags & UT_TESTF_LIVE_TREE) &&
 	    (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) ||
 	     !(test->flags & UT_TESTF_OTHER_FDT)) &&
 	    (!runs || ut_test_run_on_flattree(test)) &&
diff --git a/tools/binman/control.py b/tools/binman/control.py
index 68597c4..7e2dd35 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -9,7 +9,7 @@
 import glob
 try:
     import importlib.resources
-except ImportError:
+except ImportError:  # pragma: no cover
     # for Python 3.6
     import importlib_resources
 import os
diff --git a/tools/expo.py b/tools/expo.py
new file mode 100755
index 0000000..c6eb87a
--- /dev/null
+++ b/tools/expo.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0+
+
+"""
+Expo utility - used for testing of expo features
+
+Copyright 2023 Google LLC
+Written by Simon Glass <sjg@chromium.org>
+"""
+
+import argparse
+import collections
+import io
+import re
+import subprocess
+import sys
+
+#from u_boot_pylib import cros_subprocess
+from u_boot_pylib import tools
+
+# Parse:
+#	SCENE1		= 7,
+# or	SCENE2,
+RE_ENUM = re.compile(r'(\S*)(\s*= (\d))?,')
+
+# Parse #define <name>  "string"
+RE_DEF = re.compile(r'#define (\S*)\s*"(.*)"')
+
+def calc_ids(fname):
+    """Figure out the value of the enums in a C file
+
+    Args:
+        fname (str): Filename to parse
+
+    Returns:
+        OrderedDict():
+            key (str): enum name
+            value (int or str):
+                Value of enum, if int
+                Value of #define, if string
+    """
+    vals = collections.OrderedDict()
+    with open(fname, 'r', encoding='utf-8') as inf:
+        in_enum = False
+        cur_id = 0
+        for line in inf.readlines():
+            line = line.strip()
+            if line == 'enum {':
+                in_enum = True
+                continue
+            if in_enum and line == '};':
+                in_enum = False
+
+            if in_enum:
+                if not line or line.startswith('/*'):
+                    continue
+                m_enum = RE_ENUM.match(line)
+                if m_enum.group(3):
+                    cur_id = int(m_enum.group(3))
+                vals[m_enum.group(1)] = cur_id
+                cur_id += 1
+            else:
+                m_def = RE_DEF.match(line)
+                if m_def:
+                    vals[m_def.group(1)] = tools.to_bytes(m_def.group(2))
+
+    return vals
+
+
+def run_expo(args):
+    """Run the expo program"""
+    ids = calc_ids(args.enum_fname)
+
+    indata = tools.read_file(args.layout)
+
+    outf = io.BytesIO()
+
+    for name, val in ids.items():
+        if isinstance(val, int):
+            outval = b'%d' % val
+        else:
+            outval = b'"%s"' % val
+        find_str = r'\b%s\b' % name
+        indata = re.sub(tools.to_bytes(find_str), outval, indata)
+
+    outf.write(indata)
+    data = outf.getvalue()
+
+    with open('/tmp/asc', 'wb') as outf:
+        outf.write(data)
+    proc = subprocess.run('dtc', input=data, capture_output=True, check=True)
+    edtb = proc.stdout
+    if proc.stderr:
+        print(proc.stderr)
+        return 1
+    tools.write_file(args.outfile, edtb)
+    return 0
+
+
+def parse_args(argv):
+    """Parse the command-line arguments
+
+    Args:
+        argv (list of str): List of string arguments
+
+    Returns:
+        tuple: (options, args) with the command-line options and arugments.
+            options provides access to the options (e.g. option.debug)
+            args is a list of string arguments
+    """
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-e', '--enum-fname', type=str,
+        help='C file containing enum declaration for expo items')
+    parser.add_argument('-l', '--layout', type=str,
+        help='Devicetree file source .dts for expo layout')
+    parser.add_argument('-o', '--outfile', type=str,
+        help='Filename to write expo layout dtb')
+
+    return parser.parse_args(argv)
+
+def start_expo():
+    """Start the expo program"""
+    args = parse_args(sys.argv[1:])
+
+    ret_code = run_expo(args)
+    sys.exit(ret_code)
+
+
+if __name__ == "__main__":
+    start_expo()