Merge patch series "configs: ti: Enable basic settings for SystemReady ACS"

Jonathan Humphreys <j-humphreys@ti.com> says:

Set basic settings needed for System Ready IR ACS testing, for several TI SoC
based platforms: AM64, AM62, AM62p, BeaglePlay, J7, and BeagleboneAI.

For AM64, AM62, and AM62p, also includes some config cleanup.  Should be no
functional change.
diff --git a/Kconfig b/Kconfig
index 75f9563..82df59f 100644
--- a/Kconfig
+++ b/Kconfig
@@ -715,6 +715,20 @@
 	  A static value for the CPU frequency.  Note that if not required
 	  for a given SoC, this can be left at 0.
 
+config HAS_LDR
+	bool
+	help
+	  Enables building .ldr targets for U-Boot and SPL. This does not
+	  automatically build any additional targets with make or buildman.
+
+config LDR_CPU
+	string "CPU name to be passed to LDR utility."
+	depends on HAS_LDR
+	help
+	  Set the CPU name for the -T parameter in the LDR utility.  This is
+	  generally used on processors from Analog Devices, but may be also
+	  be useful for other vendors.
+
 source "api/Kconfig"
 
 endmenu		# General setup
diff --git a/Makefile b/Makefile
index 1069adc..7321fe1 100644
--- a/Makefile
+++ b/Makefile
@@ -1360,7 +1360,7 @@
 
 u-boot.ldr:	u-boot
 		$(CREATE_LDR_ENV)
-		$(LDR) -T $(CONFIG_CPU) -c $@ $< $(LDR_FLAGS)
+		$(LDR) -T $(CONFIG_LDR_CPU) -c $@ $< $(LDR_FLAGS)
 		$(BOARD_SIZE_CHECK)
 
 # binman
diff --git a/arch/Kconfig b/arch/Kconfig
index f9aaf37..abd406d 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -254,7 +254,6 @@
 	imply CMD_PCI
 	imply CMD_SF
 	imply CMD_SF_TEST
-	imply CMD_ZBOOT
 	imply DM_GPIO
 	imply DM_KEYBOARD
 	imply DM_MMC
diff --git a/arch/arc/lib/Makefile b/arch/arc/lib/Makefile
index 0eb44bc..bde1c3d 100644
--- a/arch/arc/lib/Makefile
+++ b/arch/arc/lib/Makefile
@@ -12,6 +12,6 @@
 obj-y += ints_low.o
 obj-y += init_helpers.o
 
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 
 lib-$(CONFIG_USE_PRIVATE_LIBGCC) += _millicodethunk.o libgcc2.o
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4cdf08d..23ee252 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1321,6 +1321,14 @@
 	select SPL_DM_SPI_FLASH if SPL_DM_SPI
 	select SPL_DM_MAILBOX if SPL
 	imply SPL_FIRMWARE if SPL
+	imply SPL_FS_FAT if SPL
+	imply SPL_LIBCOMMON_SUPPORT if SPL
+	imply SPL_LIBDISK_SUPPORT if SPL
+	imply SPL_LIBGENERIC_SUPPORT if SPL
+	imply SPL_MMC if SPL && MMC_SDHCI_ZYNQ
+	imply SPL_SERIAL if SPL
+	imply SPL_SPI if SPL && ZYNQ_QSPI
+	imply SPL_SPI_FLASH_SUPPORT if SPL && ZYNQ_QSPI
 	select SPL_SEPARATE_BSS if SPL
 	select SUPPORT_SPL
 	imply ZYNQMP_IPI if DM_MAILBOX
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index 6973340..57d06f0 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -326,6 +326,8 @@
 		/* Going one level down */
 		if (pte_type(&table[i]) == PTE_TYPE_FAULT)
 			set_pte_table(&table[i], create_table());
+		else if (pte_type(&table[i]) != PTE_TYPE_TABLE)
+			split_block(&table[i], level);
 
 		next_table = (u64 *)(table[i] & GENMASK_ULL(47, PAGE_SHIFT));
 		next_size = min(map_size - (virt & (map_size - 1)), size);
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 2634bb4..08dfbdd 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -1353,7 +1353,6 @@
 			      k3-am625-r5-sk.dtb \
 			      k3-am625-beagleplay.dtb \
 			      k3-am625-r5-beagleplay.dtb \
-			      k3-am625-verdin-wifi-dev.dtb \
 			      k3-am625-verdin-r5.dtb \
 			      k3-am625-phyboard-lyra-rdk.dtb \
 			      k3-am625-r5-phycore-som-2gb.dtb
diff --git a/arch/arm/dts/k3-am62-verdin-dev.dtsi b/arch/arm/dts/k3-am62-verdin-dev.dtsi
deleted file mode 100644
index 6701cb8..0000000
--- a/arch/arm/dts/k3-am62-verdin-dev.dtsi
+++ /dev/null
@@ -1,240 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/*
- * Copyright 2023 Toradex
- *
- * Common dtsi for Verdin AM62 SoM on Development carrier board
- *
- * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62
- * https://www.toradex.com/products/carrier-board/verdin-development-board-kit
- */
-
-/ {
-	sound {
-		compatible = "simple-audio-card";
-		simple-audio-card,bitclock-master = <&codec_dai>;
-		simple-audio-card,format = "i2s";
-		simple-audio-card,frame-master = <&codec_dai>;
-		simple-audio-card,name = "verdin-nau8822";
-		simple-audio-card,routing =
-			"Headphones", "LHP",
-			"Headphones", "RHP",
-			"Speaker", "LSPK",
-			"Speaker", "RSPK",
-			"Line Out", "AUXOUT1",
-			"Line Out", "AUXOUT2",
-			"LAUX", "Line In",
-			"RAUX", "Line In",
-			"LMICP", "Mic In",
-			"RMICP", "Mic In";
-		simple-audio-card,widgets =
-			"Headphones", "Headphones",
-			"Line Out", "Line Out",
-			"Speaker", "Speaker",
-			"Microphone", "Mic In",
-			"Line", "Line In";
-
-		codec_dai: simple-audio-card,codec {
-			clocks = <&audio_refclk1>;
-			sound-dai = <&nau8822_1a>;
-		};
-
-		simple-audio-card,cpu {
-			sound-dai = <&mcasp0>;
-		};
-	};
-};
-
-/* Verdin ETHs */
-&cpsw3g {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_rgmii1>, <&pinctrl_rgmii2>;
-	status = "okay";
-};
-
-/* MDIO, shared by Verdin ETH_1 (On-module PHY) and Verdin ETH_2_RGMII */
-&cpsw3g_mdio {
-	status = "okay";
-
-	cpsw3g_phy1: ethernet-phy@7 {
-		compatible = "ethernet-phy-ieee802.3-c22";
-		reg = <7>;
-		interrupt-parent = <&main_gpio0>;
-		interrupts = <38 IRQ_TYPE_EDGE_FALLING>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_eth2_rgmii_int>;
-		micrel,led-mode = <0>;
-	};
-};
-
-/* Verdin ETH_1 (On-module PHY) */
-&cpsw_port1 {
-	status = "okay";
-};
-
-/* Verdin ETH_2_RGMII */
-&cpsw_port2 {
-	phy-handle = <&cpsw3g_phy1>;
-	phy-mode = "rgmii-rxid";
-	status = "okay";
-};
-
-/* Verdin PWM_1, PWM_2 */
-&epwm0 {
-	status = "okay";
-};
-
-/* Verdin PWM_3_DSI */
-&epwm1 {
-	status = "okay";
-};
-
-&main_gpio0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_ctrl_sleep_moci>,
-		    <&pinctrl_gpio_5>,
-		    <&pinctrl_gpio_6>,
-		    <&pinctrl_gpio_7>,
-		    <&pinctrl_gpio_8>;
-};
-
-/* Verdin I2C_1 */
-&main_i2c1 {
-	status = "okay";
-
-	/* Audio Codec */
-	nau8822_1a: audio-codec@1a {
-		compatible = "nuvoton,nau8822";
-		reg = <0x1a>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_i2s1_mclk>;
-		#sound-dai-cells = <0>;
-	};
-
-	/* IO Expander */
-	gpio_expander_21: gpio@21 {
-		compatible = "nxp,pcal6416";
-		reg = <0x21>;
-		#gpio-cells = <2>;
-		gpio-controller;
-	};
-
-	/* Current measurement into module VCC */
-	hwmon@40 {
-		compatible = "ti,ina219";
-		reg = <0x40>;
-		shunt-resistor = <10000>;
-	};
-
-	/* Temperature sensor */
-	sensor@4f {
-		compatible = "ti,tmp75c";
-		reg = <0x4f>;
-	};
-
-	/* EEPROM */
-	eeprom@57 {
-		compatible = "st,24c02", "atmel,24c02";
-		reg = <0x57>;
-		pagesize = <16>;
-	};
-};
-
-/* Verdin I2C_2_DSI */
-&main_i2c2 {
-	status = "okay";
-};
-
-/* Verdin I2C_4_CSI */
-&main_i2c3 {
-	status = "okay";
-};
-
-/* Verdin CAN_1 */
-&main_mcan0 {
-	status = "okay";
-};
-
-/* Verdin SPI_1 */
-&main_spi1 {
-	status = "okay";
-};
-
-/* Verdin UART_3 */
-&main_uart0 {
-	status = "okay";
-};
-
-/* Verdin UART_1, connector X50 through RS485 transceiver. */
-&main_uart1 {
-	linux,rs485-enabled-at-boot-time;
-	rs485-rx-during-tx;
-	status = "okay";
-};
-
-/* Verdin I2S_1 */
-&mcasp0 {
-	status = "okay";
-};
-
-&mcu_gpio0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_gpio_1>,
-		    <&pinctrl_gpio_2>,
-		    <&pinctrl_gpio_3>,
-		    <&pinctrl_gpio_4>;
-};
-
-/* Verdin I2C_3_HDMI */
-&mcu_i2c0 {
-	status = "okay";
-};
-
-/* Verdin CAN_2 */
-&mcu_mcan0 {
-	status = "okay";
-};
-
-/* Verdin UART_4 */
-&mcu_uart0 {
-	status = "okay";
-};
-
-/* Verdin QSPI_1 */
-&ospi0 {
-	status = "okay";
-};
-
-/* Verdin SD_1 */
-&sdhci1 {
-	ti,driver-strength-ohm = <33>;
-	status = "okay";
-};
-
-/* Verdin USB_1 */
-&usbss0 {
-	status = "okay";
-};
-
-&usb0 {
-	status = "okay";
-};
-
-/* Verdin USB_2 */
-&usbss1 {
-	status = "okay";
-};
-
-&usb1 {
-	status = "okay";
-};
-
-/* Verdin CTRL_WAKE1_MICO# */
-&verdin_gpio_keys {
-	status = "okay";
-};
-
-/* Verdin UART_2 */
-&wkup_uart0 {
-	/* FIXME: WKUP UART0 is used by DM firmware */
-	status = "reserved";
-};
diff --git a/arch/arm/dts/k3-am62-verdin-wifi.dtsi b/arch/arm/dts/k3-am62-verdin-wifi.dtsi
deleted file mode 100644
index a6808b1..0000000
--- a/arch/arm/dts/k3-am62-verdin-wifi.dtsi
+++ /dev/null
@@ -1,45 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/*
- * Copyright 2023 Toradex
- *
- * Common dtsi for Verdin AM62 SoM WB variant
- *
- * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62
- */
-
-/ {
-	wifi_pwrseq: wifi-pwrseq {
-		compatible = "mmc-pwrseq-simple";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_wifi_en>;
-		reset-gpios = <&main_gpio0 22 GPIO_ACTIVE_LOW>;
-	};
-};
-
-/* On-module Wi-Fi */
-&sdhci2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_sdhci2>;
-	bus-width = <4>;
-	cap-power-off-card;
-	keep-power-in-suspend;
-	mmc-pwrseq = <&wifi_pwrseq>;
-	non-removable;
-	ti,fails-without-test-cd;
-	ti,driver-strength-ohm = <50>;
-	vmmc-supply = <&reg_3v3>;
-	status = "okay";
-};
-
-/* On-module Bluetooth */
-&main_uart5 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart5>;
-	uart-has-rtscts;
-	status = "okay";
-
-	bluetooth {
-		compatible = "nxp,88w8987-bt";
-		fw-init-baudrate = <3000000>;
-	};
-};
diff --git a/arch/arm/dts/k3-am62-verdin.dtsi b/arch/arm/dts/k3-am62-verdin.dtsi
deleted file mode 100644
index 5db52f2..0000000
--- a/arch/arm/dts/k3-am62-verdin.dtsi
+++ /dev/null
@@ -1,1443 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/*
- * Copyright 2023 Toradex
- *
- * Common dtsi for Verdin AM62 SoM
- *
- * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62
- */
-
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/interrupt-controller/arm-gic.h>
-#include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/net/ti-dp83867.h>
-
-/ {
-	chosen {
-		stdout-path = "serial2:115200n8";
-	};
-
-	aliases {
-		can0 = &main_mcan0;
-		can1 = &mcu_mcan0;
-		ethernet0 = &cpsw_port1;
-		ethernet1 = &cpsw_port2;
-		i2c0 = &main_i2c0;
-		i2c1 = &main_i2c1;
-		i2c2 = &main_i2c2;
-		i2c3 = &mcu_i2c0;
-		i2c4 = &main_i2c3;
-		mmc0 = &sdhci0;
-		mmc1 = &sdhci1;
-		mmc2 = &sdhci2;
-		rtc0 = &rtc_i2c;
-		rtc1 = &wkup_rtc0;
-		serial0 = &main_uart1;
-		serial1 = &wkup_uart0;
-		serial2 = &main_uart0;
-		serial3 = &mcu_uart0;
-		serial4 = &main_uart5;
-		usb0 = &usb0;
-		usb1 = &usb1;
-	};
-
-	verdin_gpio_keys: gpio-keys {
-		compatible = "gpio-keys";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_ctrl_wake1_mico>;
-		status = "disabled";
-
-		verdin_key_wakeup: key-wakeup {
-			debounce-interval = <10>;
-			/* Verdin CTRL_WAKE1_MICO# (SODIMM 252) */
-			gpios = <&main_gpio0 32 GPIO_ACTIVE_LOW>;
-			label = "Wake-Up";
-			linux,code = <KEY_WAKEUP>;
-			wakeup-source;
-		};
-	};
-
-	memory@80000000 {
-		device_type = "memory";
-		reg = <0x00000000 0x80000000 0x00000000 0x40000000>; /* 1G RAM */
-	};
-
-	opp-table {
-		/* Add 1.4GHz OPP. Requires VDD_CORE to be at 0.85V */
-		opp-1400000000 {
-			opp-hz = /bits/ 64 <1400000000>;
-			opp-supported-hw = <0x01 0x0004>;
-			clock-latency-ns = <6000000>;
-		};
-	};
-
-	/* Module Power Supply */
-	reg_vsodimm: regulator-vsodimm {
-		compatible = "regulator-fixed";
-		regulator-name = "+V_SODIMM";
-	};
-
-	/* Non PMIC On-module Supplies */
-	reg_3v3: regulator-3v3 {
-		compatible = "regulator-fixed";
-		regulator-max-microvolt = <3300000>;
-		regulator-min-microvolt = <3300000>;
-		regulator-name = "On-module +V3.3";
-		vin-supply = <&reg_vsodimm>;
-	};
-
-	reg_1v2_dsi: regulator-1v2-dsi {
-		compatible = "regulator-fixed";
-		regulator-max-microvolt = <1200000>;
-		regulator-min-microvolt = <1200000>;
-		regulator-name = "On-module +V1.2_DSI";
-		vin-supply = <&reg_1v8>;
-	};
-
-	/* Enabled by +V1.2_DSI */
-	reg_1v8_dsi: regulator-1v8-dsi {
-		compatible = "regulator-fixed";
-		regulator-max-microvolt = <1800000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-name = "On-module +V1.8_DSI";
-		vin-supply = <&reg_1v8>;
-	};
-
-	/* Enabled by +V2.5_ETH */
-	reg_1v0_eth: regulator-1v0-eth {
-		compatible = "regulator-fixed";
-		regulator-max-microvolt = <1000000>;
-		regulator-min-microvolt = <1000000>;
-		regulator-name = "On-module +V1.0_ETH";
-		vin-supply = <&reg_1v8>;
-	};
-
-	/* Enabled by +V2.5_ETH */
-	reg_1v8_eth: regulator-1v8-eth {
-		compatible = "regulator-fixed";
-		regulator-max-microvolt = <1800000>;
-		regulator-min-microvolt = <1800000>;
-		regulator-name = "On-module +V1.8_ETH";
-		vin-supply = <&reg_1v8>;
-	};
-
-	/* Verdin SD_1 Power Supply */
-	reg_sdhc1_vmmc: regulator-sdhci1 {
-		compatible = "regulator-fixed";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_sd1_pwr_en>;
-		enable-active-high;
-		/* Verdin SD_1_PWR_EN (SODIMM 76) */
-		gpio = <&main_gpio0 29 GPIO_ACTIVE_HIGH>;
-		off-on-delay-us = <100000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-min-microvolt = <3300000>;
-		regulator-name = "+V3.3_SD";
-		startup-delay-us = <2000>;
-	};
-
-	reg_sdhc1_vqmmc: regulator-sdhci1-vqmmc {
-		compatible = "regulator-gpio";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_vsel_sd>;
-		/* PMIC_VSEL_SD */
-		gpios = <&main_gpio0 21 GPIO_ACTIVE_HIGH>;
-		regulator-name = "LDO1-VSEL-SD (PMIC)";
-		regulator-min-microvolt = <1800000>;
-		regulator-max-microvolt = <3300000>;
-		states = <1800000 0x0>,
-			 <3300000 0x1>;
-		vin-supply = <&reg_sd_3v3_1v8>;
-	};
-
-	reserved-memory {
-		#address-cells = <2>;
-		#size-cells = <2>;
-		ranges;
-
-		secure_tfa_ddr: tfa@9e780000 {
-			reg = <0x00 0x9e780000 0x00 0x80000>;
-			alignment = <0x1000>;
-			no-map;
-		};
-
-		secure_ddr: optee@9e800000 {
-			reg = <0x00 0x9e800000 0x00 0x01800000>; /* for OP-TEE */
-			alignment = <0x1000>;
-			no-map;
-		};
-
-		wkup_r5fss0_core0_dma_memory_region: r5f-dma-memory@9db00000 {
-			compatible = "shared-dma-pool";
-			reg = <0x00 0x9db00000 0x00 0xc00000>;
-			no-map;
-		};
-	};
-};
-
-&main_pmx0 {
-	/* Verdin PWM_1 */
-	pinctrl_epwm0_a: main-epwm0a-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01b4, PIN_OUTPUT, 2) /* (A13) SPI0_CS0.EHRPWM0_A */ /* SODIMM 15 */
-		>;
-	};
-
-	/* Verdin PWM_2 */
-	pinctrl_epwm0_b: main-epwm0b-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01b8, PIN_OUTPUT, 2) /* (C13) SPI0_CS1.EHRPWM0_B */ /* SODIMM 16 */
-		>;
-	};
-
-	/* Verdin PWM_3_DSI */
-	pinctrl_epwm1_a: main-epwm1a-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01bc, PIN_OUTPUT, 2) /* (A14) SPI0_CLK.EHRPWM1_A */ /* SODIMM 19 */
-		>;
-	};
-
-	/* Verdin QSPI_1_CLK as GPIO (conflict with Verdin QSPI_1 interface) */
-	pinctrl_qspi1_clk_gpio: main-gpio0-0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0000, PIN_INPUT, 7) /* (H24) OSPI0_CLK.GPIO0_0 */ /* SODIMM 52 */
-		>;
-	};
-
-	/* Verdin QSPI_1_IO0 as GPIO (conflict with Verdin QSPI_1 interface) */
-	pinctrl_qspi1_io0_gpio: main-gpio0-3-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x000c, PIN_INPUT, 7) /* (E25) OSPI0_D0.GPIO0_3 */ /* SODIMM 56 */
-		>;
-	};
-
-	/* Verdin QSPI_1_IO1 as GPIO (conflict with Verdin QSPI_1 interface) */
-	pinctrl_qspi1_io1_gpio: main-gpio0-4-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0010, PIN_INPUT, 7) /* (G24) OSPI0_D1.GPIO0_4 */ /* SODIMM 58 */
-		>;
-	};
-
-	/* Verdin QSPI_1_IO2 as GPIO (conflict with Verdin QSPI_1 interface) */
-	pinctrl_qspi1_io2_gpio: main-gpio0-5-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0014, PIN_INPUT, 7) /* (F25) OSPI0_D2.GPIO0_5 */ /* SODIMM 60 */
-		>;
-	};
-
-	/* Verdin QSPI_1_IO3 as GPIO (conflict with Verdin QSPI_1 interface) */
-	pinctrl_qspi1_io3_gpio: main-gpio0-6-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0018, PIN_INPUT, 7) /* (F24) OSPI0_D3.GPIO0_6 */ /* SODIMM 62 */
-		>;
-	};
-
-	/* Verdin QSPI_1_CS# as GPIO (conflict with Verdin QSPI_1 interface) */
-	pinctrl_qspi1_cs_gpio: main-gpio0-11-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x002c, PIN_INPUT, 7) /* (F23) OSPI0_CSn0.GPIO0_11 */ /* SODIMM 54 */
-		>;
-	};
-
-	/* Verdin QSPI_1_CS2# as GPIO (conflict with Verdin QSPI_1 interface) */
-	pinctrl_qspi1_cs2_gpio: main-gpio0-12-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0030, PIN_INPUT, 7) /* (G21) OSPI0_CSn1.GPIO0_12 */ /* SODIMM 64 */
-		>;
-	};
-
-	/* WiFi_W_WKUP_HOST# */
-	pinctrl_wifi_w_wkup_host: main-gpio0-15-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x003c, PIN_INPUT, 7) /* (M25) GPMC0_AD0.GPIO0_15 */ /* SODIMM 174 */
-		>;
-	};
-
-	/* WiFi_BT_WKUP_HOST# */
-	pinctrl_bt_wkup_host: main-gpio0-16-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0040, PIN_INPUT, 7) /* (N23) GPMC0_AD1.GPIO0_16 */ /* SODIMM 172 */
-		>;
-	};
-
-	/* PMIC_ETH_RESET# */
-	pinctrl_eth_reset: main-gpio0-17-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0044, PIN_INPUT, 7) /* (N24) GPMC0_AD2.GPIO0_17 */
-		>;
-	};
-
-	/* PMIC_BRIDGE_RESET# */
-	pinctrl_bridge_reset: main-gpio0-20-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0050, PIN_INPUT, 7) /* (P22) GPMC0_AD5.GPIO0_20 */
-		>;
-	};
-
-	/* PMIC_VSEL_SD */
-	pinctrl_vsel_sd: main-gpio0-21-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0054, PIN_INPUT, 7) /* (P21) GPMC0_AD6.GPIO0_21 */
-		>;
-	};
-
-	/* PMIC_EN_WIFI */
-	pinctrl_wifi_en: main-gpio0-22-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0058, PIN_INPUT, 7) /* (R23) GPMC0_AD7.GPIO0_22 */
-		>;
-	};
-
-	/* PMIC_ETH_INT# */
-	pinctrl_eth_int: main-gpio0-25-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0064, PIN_INPUT_PULLUP, 7) /* (T25) GPMC0_AD10.GPIO0_25 */
-		>;
-	};
-
-	/* WiFi_WKUP_BT# */
-	pinctrl_wifi_wkup_bt: main-gpio0-26-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0068, PIN_INPUT, 7) /* (R21) GPMC0_AD11.GPIO0_26 */
-		>;
-	};
-
-	/* WiFi_WKUP_WLAN# */
-	pinctrl_wifi_wkup_wlan: main-gpio0-27-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x006c, PIN_INPUT, 7) /* (T22) GPMC0_AD12.GPIO0_27 */
-		>;
-	};
-
-	/* Verdin SD_1_PWR_EN */
-	pinctrl_sd1_pwr_en: main-gpio0-29-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0074, PIN_INPUT, 7) /* (U25) GPMC0_AD14.GPIO0_29 */ /* SODIMM 76 */
-		>;
-	};
-
-	/* Verdin DSI_1_BKL_EN */
-	pinctrl_dsi1_bkl_en: main-gpio0-30-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0078, PIN_INPUT, 7) /* (U24) GPMC0_AD15.GPIO0_30 */ /* SODIMM 21 */
-		>;
-	};
-
-	/* Verdin CTRL_SLEEP_MOCI# */
-	pinctrl_ctrl_sleep_moci: main-gpio0-31-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x007c, PIN_INPUT, 7) /* (P25) GPMC0_CLK.GPIO0_31 */ /* SODIMM 256 */
-		>;
-	};
-
-	/* Verdin CTRL_WAKE1_MICO# */
-	pinctrl_ctrl_wake1_mico: main-gpio0-32-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0084, PIN_INPUT_PULLUP, 7) /* (L23) GPMC0_ADVn_ALE.GPIO0_32 */ /* SODIMM 252 */
-		>;
-	};
-
-	/* Verdin I2S_2_D_OUT as GPIO (conflict with Verdin I2S_2 interface) */
-	pinctrl_i2s_2_d_out_gpio: main-gpio0-34-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x008c, PIN_INPUT, 7) /* (L25) GPMC0_WEn.GPIO0_34 */ /* SODIMM 46 */
-		>;
-	};
-
-	/* Verdin I2S_2_BCLK as GPIO (conflict with Verdin I2S_2 interface) */
-	pinctrl_i2s_2_bclk_gpio: main-gpio0-35-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0090, PIN_INPUT, 7) /* (M24) GPMC0_BE0n_CLE.GPIO0_35 */ /* SODIMM 42 */
-		>;
-	};
-
-	/* Verdin GPIO_6 */
-	pinctrl_gpio_6: main-gpio0-36-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0094, PIN_INPUT, 7) /* (N20) GPMC0_BE1n.GPIO0_36 */ /* SODIMM 218 */
-		>;
-	};
-
-	/* Verdin ETH_2_RGMII_INT# */
-	pinctrl_eth2_rgmii_int: main-gpio0-38-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x009c, PIN_INPUT, 7) /* (V25) GPMC0_WAIT1.GPIO0_38 */ /* SODIMM 189 */
-		>;
-	};
-
-	/* Verdin GPIO_5 */
-	pinctrl_gpio_5: main-gpio0-40-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x00a4, PIN_INPUT, 7) /* (M22) GPMC0_DIR.GPIO0_40 */ /* SODIMM 216 */
-		>;
-	};
-
-	/* Verdin GPIO_7 */
-	pinctrl_gpio_7: main-gpio0-41-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x00a8, PIN_INPUT, 7) /* (M21) GPMC0_CSn0.GPIO0_41 */ /* SODIMM 220 */
-		>;
-	};
-
-	/* Verdin GPIO_8 */
-	pinctrl_gpio_8: main-gpio0-42-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x00ac, PIN_INPUT, 7) /* (L21) GPMC0_CSn1.GPIO0_42 */ /* SODIMM 222 */
-		>;
-	};
-
-	/* Verdin USB_1_OC# */
-	pinctrl_usb1_oc: main-gpio0-71-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0124, PIN_INPUT, 7) /* (A23) MMC2_SDCD.GPIO0_71 */ /* SODIMM 157 */
-		>;
-	};
-
-	/* Verdin USB_2_OC# */
-	pinctrl_usb2_oc: main-gpio0-72-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0128, PIN_INPUT, 7) /* (B23) MMC2_SDWP.GPIO0_72 */ /* SODIMM 187 */
-		>;
-	};
-
-	/* Verdin PWM_3_DSI as GPIO */
-	pinctrl_pwm3_dsi_gpio: main-gpio1-17-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01bc, PIN_INPUT, 7) /* (A14) SPI0_CLK.GPIO1_17 */ /* SODIMM 19 */
-		>;
-	};
-
-	/* Verdin QSPI_1_DQS as GPIO */
-	pinctrl_qspi1_dqs_gpio: main-gpio1-18-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01c0, PIN_INPUT, 7) /* (B13) SPI0_D0.GPIO1_18 */ /* SODIMM 66 */
-		>;
-	};
-
-	/* Verdin USB_1_ID */
-	pinctrl_usb0_id: main-gpio1-19-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01c4, PIN_INPUT, 7) /* (B14) SPI0_D1.GPIO1_19 */ /* SODIMM 161 */
-		>;
-	};
-
-	/* Verdin DSI_1_INT# (pulled-up as active-low) */
-	pinctrl_dsi1_int: main-gpio1-49-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0244, PIN_INPUT_PULLUP, 7) /* (C17) MMC1_SDWP.GPIO1_49 */ /* SODIMM 17 */
-		>;
-	};
-
-	/* On-module I2C - PMIC_I2C */
-	pinctrl_i2c0: main-i2c0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01e0, PIN_INPUT, 0) /* (B16) I2C0_SCL */ /* PMIC_I2C_SCL */
-			AM62X_IOPAD(0x01e4, PIN_INPUT, 0) /* (A16) I2C0_SDA */ /* PMIC_I2C_SDA */
-		>;
-	};
-
-	/* Verdin I2C_1 */
-	pinctrl_i2c1: main-i2c1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01e8, PIN_INPUT_PULLUP, 0) /* (B17) I2C1_SCL */ /* SODIMM 14 */
-			AM62X_IOPAD(0x01ec, PIN_INPUT_PULLUP, 0) /* (A17) I2C1_SDA */ /* SODIMM 12 */
-		>;
-	};
-
-	/* Verdin I2C_2_DSI */
-	pinctrl_i2c2: main-i2c2-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x00b0, PIN_INPUT, 1) /* (K22) GPMC0_CSn2.I2C2_SCL */ /* SODIMM 55 */
-			AM62X_IOPAD(0x00b4, PIN_INPUT, 1) /* (K24) GPMC0_CSn3.I2C2_SDA */ /* SODIMM 53 */
-		>;
-	};
-
-	/* Verdin I2C_4_CSI */
-	pinctrl_i2c3: main-i2c3-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01d0, PIN_INPUT, 2) /* (A15) UART0_CTSn.I2C3_SCL */ /* SODIMM 95 */
-			AM62X_IOPAD(0x01d4, PIN_INPUT, 2) /* (B15) UART0_RTSn.I2C3_SDA */ /* SODIMM 93 */
-		>;
-	};
-
-	/* I2S_1_MCLK */
-	pinctrl_i2s1_mclk: main-system-audio-ext-reflock1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x00a0, PIN_OUTPUT, 1) /* (K25) GPMC0_WPn.AUDIO_EXT_REFCLK1 */ /* SODIMM 38 */
-		>;
-	};
-
-	/* Verdin I2S_1 */
-	pinctrl_mcasp0: main-mcasp0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01a4, PIN_INPUT,  0) /* (B20) MCASP0_ACLKX */ /* SODIMM 30 */
-			AM62X_IOPAD(0x01a8, PIN_INPUT,  0) /* (D20) MCASP0_AFSX  */ /* SODIMM 32 */
-			AM62X_IOPAD(0x01a0, PIN_OUTPUT, 0) /* (E18) MCASP0_AXR0  */ /* SODIMM 34 */
-			AM62X_IOPAD(0x019c, PIN_INPUT,  0) /* (B18) MCASP0_AXR1  */ /* SODIMM 36 */
-		>;
-	};
-
-	/* Verdin I2S_2 */
-	pinctrl_mcasp1: main-mcasp1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0090, PIN_INPUT,  2) /* (M24) GPMC0_BE0n_CLE.MCASP1_ACLKX */ /* SODIMM 42 */
-			AM62X_IOPAD(0x0098, PIN_INPUT,  2) /* (U23) GPMC0_WAIT0.MCASP1_AFSX     */ /* SODIMM 44 */
-			AM62X_IOPAD(0x008c, PIN_OUTPUT, 2) /* (L25) GPMC0_WEn.MCASP1_AXR0       */ /* SODIMM 46 */
-			AM62X_IOPAD(0x0088, PIN_INPUT,  2) /* (L24) GPMC0_OEn_REn.MCASP1_AXR1   */ /* SODIMM 48 */
-		>;
-	};
-
-	/* Verdin CAN_1 */
-	pinctrl_mcan0: main-mcan0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01dc, PIN_INPUT,  0) /* (E15) MCAN0_RX */ /* SODIMM 22 */
-			AM62X_IOPAD(0x01d8, PIN_OUTPUT, 0) /* (C15) MCAN0_TX */ /* SODIMM 20 */
-		>;
-	};
-
-	/* MDIO, shared by Verdin ETH_1 (On-module PHY) and Verdin ETH_2_RGMII */
-	pinctrl_mdio: main-mdio1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x160, PIN_OUTPUT, 0) /* (AD24) MDIO0_MDC  */ /* ETH_1_MDC,  SODIMM 193 */
-			AM62X_IOPAD(0x15c, PIN_INPUT, 0)  /* (AB22) MDIO0_MDIO */ /* ETH_1_MDIO, SODIMM 191 */
-		>;
-	};
-
-	/* On-module eMMC */
-	pinctrl_sdhci0: main-mmc0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x220, PIN_INPUT, 0) /*  (Y3) MMC0_CMD  */
-			AM62X_IOPAD(0x218, PIN_INPUT, 0) /* (AB1) MMC0_CLK  */
-			AM62X_IOPAD(0x214, PIN_INPUT, 0) /* (AA2) MMC0_DAT0 */
-			AM62X_IOPAD(0x210, PIN_INPUT, 0) /* (AA1) MMC0_DAT1 */
-			AM62X_IOPAD(0x20c, PIN_INPUT, 0) /* (AA3) MMC0_DAT2 */
-			AM62X_IOPAD(0x208, PIN_INPUT, 0) /*  (Y4) MMC0_DAT3 */
-			AM62X_IOPAD(0x204, PIN_INPUT, 0) /* (AB2) MMC0_DAT4 */
-			AM62X_IOPAD(0x200, PIN_INPUT, 0) /* (AC1) MMC0_DAT5 */
-			AM62X_IOPAD(0x1fc, PIN_INPUT, 0) /* (AD2) MMC0_DAT6 */
-			AM62X_IOPAD(0x1f8, PIN_INPUT, 0) /* (AC2) MMC0_DAT7 */
-		>;
-	};
-
-	/* Verdin SD_1 */
-	pinctrl_sdhci1: main-mmc1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x23c, PIN_INPUT,        0) /* (A21) MMC1_CMD  */ /* SODIMM 74 */
-			AM62X_IOPAD(0x234, PIN_INPUT,        0) /* (B22) MMC1_CLK  */ /* SODIMM 78 */
-			AM62X_IOPAD(0x230, PIN_INPUT,        0) /* (A22) MMC1_DAT0 */ /* SODIMM 80 */
-			AM62X_IOPAD(0x22c, PIN_INPUT,        0) /* (B21) MMC1_DAT1 */ /* SODIMM 82 */
-			AM62X_IOPAD(0x228, PIN_INPUT,        0) /* (C21) MMC1_DAT2 */ /* SODIMM 70 */
-			AM62X_IOPAD(0x224, PIN_INPUT,        0) /* (D22) MMC1_DAT3 */ /* SODIMM 72 */
-			AM62X_IOPAD(0x240, PIN_INPUT_PULLUP, 0) /* (D17) MMC1_SDCD */ /* SODIMM 84 */
-		>;
-	};
-
-	/* On-module Wi-Fi on WB SKUs, module-specific SDIO otherwise */
-	pinctrl_sdhci2: main-mmc2-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x120, PIN_INPUT, 0) /* (C24) MMC2_CMD   */ /* WiFi_SDIO_CMD   */
-			AM62X_IOPAD(0x118, PIN_INPUT, 0) /* (D25) MMC2_CLK   */ /* WiFi_SDIO_CLK   */
-			AM62X_IOPAD(0x114, PIN_INPUT, 0) /* (B24) MMC2_DAT0  */ /* WiFi_SDIO_DATA0 */
-			AM62X_IOPAD(0x110, PIN_INPUT, 0) /* (C25) MMC2_DAT1  */ /* WiFi_SDIO_DATA1 */
-			AM62X_IOPAD(0x10c, PIN_INPUT, 0) /* (E23) MMC2_DAT2  */ /* WiFi_SDIO_DATA2 */
-			AM62X_IOPAD(0x108, PIN_INPUT, 0) /* (D24) MMC2_DAT3  */ /* WiFi_SDIO_DATA3 */
-			AM62X_IOPAD(0x11c, PIN_INPUT, 0) /* (#N/A) MMC2_CLKB */
-		>;
-	};
-
-	/* Verdin QSPI_1 */
-	pinctrl_ospi0: main-ospi0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0000, PIN_OUTPUT, 0) /* (H24) OSPI0_CLK  */ /* SODIMM 52 */
-			AM62X_IOPAD(0x002c, PIN_OUTPUT, 0) /* (F23) OSPI0_CSn0 */ /* SODIMM 54 */
-			AM62X_IOPAD(0x0030, PIN_OUTPUT, 0) /* (G21) OSPI0_CSn1 */ /* SODIMM 64 */
-			AM62X_IOPAD(0x000c, PIN_INPUT, 0)  /* (E25) OSPI0_D0   */ /* SODIMM 56 */
-			AM62X_IOPAD(0x0010, PIN_INPUT, 0)  /* (G24) OSPI0_D1   */ /* SODIMM 58 */
-			AM62X_IOPAD(0x0014, PIN_INPUT, 0)  /* (F25) OSPI0_D2   */ /* SODIMM 60 */
-			AM62X_IOPAD(0x0018, PIN_INPUT, 0)  /* (F24) OSPI0_D3   */ /* SODIMM 62 */
-		>;
-	};
-
-	/* Verdin ETH_1 RGMII (On-module PHY) */
-	pinctrl_rgmii1: main-rgmii1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x14c, PIN_INPUT,  0) /* (AB17) RGMII1_RD0    */
-			AM62X_IOPAD(0x150, PIN_INPUT,  0) /* (AC17) RGMII1_RD1    */
-			AM62X_IOPAD(0x154, PIN_INPUT,  0) /* (AB16) RGMII1_RD2    */
-			AM62X_IOPAD(0x158, PIN_INPUT,  0) /* (AA15) RGMII1_RD3    */
-			AM62X_IOPAD(0x148, PIN_INPUT,  0) /* (AD17) RGMII1_RXC    */
-			AM62X_IOPAD(0x144, PIN_INPUT,  0) /* (AE17) RGMII1_RX_CTL */
-			AM62X_IOPAD(0x134, PIN_OUTPUT, 0) /* (AE20) RGMII1_TD0    */
-			AM62X_IOPAD(0x138, PIN_OUTPUT, 0) /* (AD20) RGMII1_TD1    */
-			AM62X_IOPAD(0x13c, PIN_OUTPUT, 0) /* (AE18) RGMII1_TD2    */
-			AM62X_IOPAD(0x140, PIN_OUTPUT, 0) /* (AD18) RGMII1_TD3    */
-			AM62X_IOPAD(0x130, PIN_OUTPUT, 0) /* (AE19) RGMII1_TXC    */
-			AM62X_IOPAD(0x12c, PIN_OUTPUT, 0) /* (AD19) RGMII1_TX_CTL */
-		>;
-	};
-
-	/* Verdin ETH_2 RGMII */
-	pinctrl_rgmii2: main-rgmii2-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x184, PIN_INPUT,  0) /* (AE23) RGMII2_RD0    */ /* SODIMM 201 */
-			AM62X_IOPAD(0x188, PIN_INPUT,  0) /* (AB20) RGMII2_RD1    */ /* SODIMM 203 */
-			AM62X_IOPAD(0x18c, PIN_INPUT,  0) /* (AC21) RGMII2_RD2    */ /* SODIMM 205 */
-			AM62X_IOPAD(0x190, PIN_INPUT,  0) /* (AE22) RGMII2_RD3    */ /* SODIMM 207 */
-			AM62X_IOPAD(0x180, PIN_INPUT,  0) /* (AD23) RGMII2_RXC    */ /* SODIMM 197 */
-			AM62X_IOPAD(0x17c, PIN_INPUT,  0) /* (AD22) RGMII2_RX_CTL */ /* SODIMM 199 */
-			AM62X_IOPAD(0x16c, PIN_OUTPUT, 0) /*  (Y18) RGMII2_TD0    */ /* SODIMM 221 */
-			AM62X_IOPAD(0x170, PIN_OUTPUT, 0) /* (AA18) RGMII2_TD1    */ /* SODIMM 219 */
-			AM62X_IOPAD(0x174, PIN_OUTPUT, 0) /* (AD21) RGMII2_TD2    */ /* SODIMM 217 */
-			AM62X_IOPAD(0x178, PIN_OUTPUT, 0) /* (AC20) RGMII2_TD3    */ /* SODIMM 215 */
-			AM62X_IOPAD(0x168, PIN_OUTPUT, 0) /* (AE21) RGMII2_TXC    */ /* SODIMM 213 */
-			AM62X_IOPAD(0x164, PIN_OUTPUT, 0) /* (AA19) RGMII2_TX_CTL */ /* SODIMM 211 */
-		>;
-	};
-
-	/* Verdin SPI_1 */
-	pinctrl_spi1: main-spi1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0020, PIN_INPUT, 1) /* (J25) OSPI0_D5.SPI1_CLK */ /* SODIMM 196 */
-			AM62X_IOPAD(0x001c, PIN_INPUT, 1) /* (J23) OSPI0_D4.SPI1_CS0 */ /* SODIMM 202 */
-			AM62X_IOPAD(0x0024, PIN_INPUT, 1) /* (H25) OSPI0_D6.SPI1_D0  */ /* SODIMM 200 */
-			AM62X_IOPAD(0x0028, PIN_INPUT, 1) /* (J22) OSPI0_D7.SPI1_D1  */ /* SODIMM 198 */
-		>;
-	};
-
-	/* ETH_25MHz_CLK */
-	pinctrl_eth_clock: main-system-clkout0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01f0, PIN_OUTPUT_PULLUP, 5) /* (A18) EXT_REFCLK1.CLKOUT0 */
-		>;
-	};
-
-	/* PMIC_EXTINT# */
-	pinctrl_pmic_extint: main-system-extint-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x01f4, PIN_INPUT, 0) /* (D16) EXTINTn */
-		>;
-	};
-
-	/* Verdin UART_3, used as the Linux console */
-	pinctrl_uart0: main-uart0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x1c8, PIN_INPUT_PULLUP, 0) /* (D14) UART0_RXD */ /* SODIMM 147 */
-			AM62X_IOPAD(0x1cc, PIN_OUTPUT,       0) /* (E14) UART0_TXD */ /* SODIMM 149 */
-		>;
-	};
-
-	/* Verdin UART_1 */
-	pinctrl_uart1: main-uart1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0194, PIN_INPUT_PULLUP, 2) /* (B19) MCASP0_AXR3.UART1_CTSn */ /* SODIMM 135 */
-			AM62X_IOPAD(0x0198, PIN_OUTPUT,       2) /* (A19) MCASP0_AXR2.UART1_RTSn */ /* SODIMM 133 */
-			AM62X_IOPAD(0x01ac, PIN_INPUT_PULLUP, 2) /* (E19) MCASP0_AFSR.UART1_RXD  */ /* SODIMM 129 */
-			AM62X_IOPAD(0x01b0, PIN_OUTPUT,       2) /* (A20) MCASP0_ACLKR.UART1_TXD */ /* SODIMM 131 */
-		>;
-	};
-
-	/* Bluetooth on WB SKUs, module-specific UART otherwise */
-	pinctrl_uart5: main-uart5-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0008, PIN_INPUT_PULLUP, 5) /* (J24) OSPI0_DQS.UART5_CTSn    */ /* WiFi_UART_CTS */
-			AM62X_IOPAD(0x0004, PIN_OUTPUT,       5) /* (G25) OSPI0_LBCLKO.UART5_RTSn */ /* WiFi_UART_RTS */
-			AM62X_IOPAD(0x0034, PIN_INPUT_PULLUP, 5) /* (H21) OSPI0_CSn2.UART5_RXD    */ /* WiFi_UART_RXD */
-			AM62X_IOPAD(0x0038, PIN_OUTPUT,       5) /* (E24) OSPI0_CSn3.UART5_TXD    */ /* WiFi_UART_TXD */
-		>;
-	};
-
-	/* Verdin USB_1 */
-	pinctrl_usb0: main-usb0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0254, PIN_OUTPUT, 0) /* (C20) USB0_DRVVBUS */ /* SODIMM 155 */
-		>;
-	};
-
-	/* Verdin USB_2 */
-	pinctrl_usb1: main-usb1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0258, PIN_OUTPUT, 0) /* (F18) USB1_DRVVBUS */ /* SODIMM 185 */
-		>;
-	};
-
-	/* DSS VOUT0 RGB */
-	pinctrl_parallel_rgb: main-vout-default-pins {
-		pinctrl-single,pins = <
-			AM62X_IOPAD(0x0100, PIN_OUTPUT, 0) /* (AC25) VOUT0_VSYNC            */
-			AM62X_IOPAD(0x00f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC            */
-			AM62X_IOPAD(0x0104, PIN_OUTPUT, 0) /* (AC24) VOUT0_PCLK             */
-			AM62X_IOPAD(0x00fc, PIN_OUTPUT, 0) /*  (Y20) VOUT0_DE               */
-			AM62X_IOPAD(0x00b8, PIN_OUTPUT, 0) /*  (U22) VOUT0_DATA0            */
-			AM62X_IOPAD(0x00bc, PIN_OUTPUT, 0) /*  (V24) VOUT0_DATA1            */
-			AM62X_IOPAD(0x00c0, PIN_OUTPUT, 0) /*  (W25) VOUT0_DATA2            */
-			AM62X_IOPAD(0x00c4, PIN_OUTPUT, 0) /*  (W24) VOUT0_DATA3            */
-			AM62X_IOPAD(0x00c8, PIN_OUTPUT, 0) /*  (Y25) VOUT0_DATA4            */
-			AM62X_IOPAD(0x00cc, PIN_OUTPUT, 0) /*  (Y24) VOUT0_DATA5            */
-			AM62X_IOPAD(0x00d0, PIN_OUTPUT, 0) /*  (Y23) VOUT0_DATA6            */
-			AM62X_IOPAD(0x00d4, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA7            */
-			AM62X_IOPAD(0x00d8, PIN_OUTPUT, 0) /*  (V21) VOUT0_DATA8            */
-			AM62X_IOPAD(0x00dc, PIN_OUTPUT, 0) /*  (W21) VOUT0_DATA9            */
-			AM62X_IOPAD(0x00e0, PIN_OUTPUT, 0) /*  (V20) VOUT0_DATA10           */
-			AM62X_IOPAD(0x00e4, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA11           */
-			AM62X_IOPAD(0x00e8, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA12           */
-			AM62X_IOPAD(0x00ec, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA13           */
-			AM62X_IOPAD(0x00f0, PIN_OUTPUT, 0) /*  (Y22) VOUT0_DATA14           */
-			AM62X_IOPAD(0x00f4, PIN_OUTPUT, 0) /* (AA21) VOUT0_DATA15           */
-			AM62X_IOPAD(0x005c, PIN_OUTPUT, 1) /*  (R24) GPMC0_AD8.VOUT0_DATA16 */
-			AM62X_IOPAD(0x0060, PIN_OUTPUT, 1) /*  (R25) GPMC0_AD9.VOUT0_DATA17 */
-		>;
-	};
-};
-
-&mcu_pmx0 {
-	/* Verdin PCIE_1_RESET# */
-	pinctrl_pcie_1_reset: mcu-gpio0-0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x0000, PIN_INPUT, 7) /* (E8) MCU_SPI0_CS0.MCU_GPIO0_0 */ /* SODIMM 244 */
-		>;
-	};
-
-	/* Verdin GPIO_1 */
-	pinctrl_gpio_1: mcu-gpio0-1-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x0004, PIN_INPUT, 7) /* (B8) MCU_SPI0_CS1.MCU_GPIO0_1 */ /* SODIMM 206 */
-		>;
-	};
-
-	/* Verdin GPIO_2 */
-	pinctrl_gpio_2: mcu-gpio0-2-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x0008, PIN_INPUT, 7) /* (A7) MCU_SPI0_CLK.MCU_GPIO0_2 */ /* SODIMM 208 */
-		>;
-	};
-
-	/* Verdin GPIO_3 */
-	pinctrl_gpio_3: mcu-gpio0-3-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x000c, PIN_INPUT, 7) /* (D9) MCU_SPI0_D0.MCU_GPIO0_3 */ /* SODIMM 210 */
-		>;
-	};
-
-	/* Verdin GPIO_4 */
-	pinctrl_gpio_4: mcu-gpio0-4-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x0010, PIN_INPUT, 7) /* (C9) MCU_SPI0_D1.MCU_GPIO0_4 */ /* SODIMM 212 */
-		>;
-	};
-
-	/* Verdin I2C_3_HDMI */
-	pinctrl_mcu_i2c0: mcu-i2c0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x0044, PIN_INPUT, 0) /*  (A8) MCU_I2C0_SCL */ /* SODIMM 59 */
-			AM62X_MCU_IOPAD(0x0048, PIN_INPUT, 0) /* (D10) MCU_I2C0_SDA */ /* SODIMM 57 */
-		>;
-	};
-
-	/* Verdin CAN_2 */
-	pinctrl_mcu_mcan0: mcu-mcan0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x0038, PIN_INPUT,  0) /* (B3) MCU_MCAN0_RX */ /* SODIMM 26 */
-			AM62X_MCU_IOPAD(0x0034, PIN_OUTPUT, 0) /* (D6) MCU_MCAN0_TX */ /* SODIMM 24 */
-		>;
-	};
-
-	/* Verdin UART_4 - Reserved to Cortex-M4 */
-	pinctrl_mcu_uart0: mcu-uart0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x0014, PIN_INPUT_PULLUP, 0) /* (B5) MCU_UART0_RXD */ /* SODIMM 151 */
-			AM62X_MCU_IOPAD(0x0018, PIN_OUTPUT,       0) /* (A5) MCU_UART0_TXD */ /* SODIMM 153 */
-		>;
-	};
-
-	/* Verdin CSI_1_MCLK */
-	pinctrl_csi1_mclk: wkup-clkout0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x0084, PIN_OUTPUT, 0) /* (A12) WKUP_CLKOUT0 */ /* SODIMM 91 */
-		>;
-	};
-
-	/* Verdin UART_2 */
-	pinctrl_wkup_uart0: wkup-uart0-default-pins {
-		pinctrl-single,pins = <
-			AM62X_MCU_IOPAD(0x002c, PIN_INPUT_PULLUP, 0) /* (C6) WKUP_UART0_CTSn */ /* SODIMM 143 */
-			AM62X_MCU_IOPAD(0x0030, PIN_OUTPUT,       0) /* (A4) WKUP_UART0_RTSn */ /* SODIMM 141 */
-			AM62X_MCU_IOPAD(0x0024, PIN_INPUT_PULLUP, 0) /* (B4) WKUP_UART0_RXD  */ /* SODIMM 137 */
-			AM62X_MCU_IOPAD(0x0028, PIN_OUTPUT,       0) /* (C5) WKUP_UART0_TXD  */ /* SODIMM 139 */
-		>;
-	};
-};
-
-/* VERDIN I2S_1_MCLK */
-&audio_refclk1 {
-	assigned-clock-rates = <25000000>;
-};
-
-&cpsw3g {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_rgmii1>;
-	status = "disabled";
-};
-
-/* Verdin ETH_1 (On-module PHY) */
-&cpsw_port1 {
-	phy-handle = <&cpsw3g_phy0>;
-	phy-mode = "rgmii-rxid";
-	status = "disabled";
-};
-
-/* Verdin ETH_2_RGMII */
-&cpsw_port2 {
-	status = "disabled";
-};
-
-/* MDIO, shared by Verdin ETH_1 (On-module PHY) and Verdin ETH_2_RGMII */
-&cpsw3g_mdio {
-	assigned-clocks = <&k3_clks 157 20>;
-	assigned-clock-parents = <&k3_clks 157 22>;
-	assigned-clock-rates = <25000000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_eth_clock>, <&pinctrl_mdio>;
-	status = "disabled";
-
-	cpsw3g_phy0: ethernet-phy@0 {
-		compatible = "ethernet-phy-id2000.a231";
-		reg = <0>;
-		interrupt-parent = <&main_gpio0>;
-		interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_eth_int>, <&pinctrl_eth_reset>;
-		reset-gpios = <&main_gpio0 17 GPIO_ACTIVE_LOW>;
-		reset-assert-us = <10>;
-		reset-deassert-us = <1000>;
-		ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
-		ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_00_NS>;
-	};
-};
-
-&dss {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_parallel_rgb>;
-	status = "disabled";
-};
-
-&dss_ports {
-	#address-cells = <1>;
-	#size-cells = <0>;
-
-	/* VP2: DPI Output */
-	port@1 {
-		reg = <1>;
-
-		dpi_out: endpoint {
-			remote-endpoint = <&rgb_in>;
-		};
-	};
-};
-
-/* Verdin PWM_1, PWM_2 */
-&epwm0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_epwm0_a>, <&pinctrl_epwm0_b>;
-	status = "disabled";
-};
-
-/* Verdin PWM_3_DSI */
-&epwm1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_epwm1_a>;
-	status = "disabled";
-};
-
-&main_gpio0 {
-	gpio-line-names =
-		"SODIMM_52", /* 0 */
-		"",
-		"",
-		"SODIMM_56",
-		"SODIMM_58",
-		"SODIMM_60",
-		"SODIMM_62",
-		"",
-		"",
-		"",
-		"", /* 10 */
-		"SODIMM_54",
-		"SODIMM_64",
-		"",
-		"",
-		"SODIMM_174",
-		"SODIMM_172",
-		"",
-		"",
-		"",
-		"", /* 20 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"SODIMM_76",
-		"SODIMM_21", /* 30 */
-		"SODIMM_256",
-		"SODIMM_252",
-		"",
-		"SODIMM_46",
-		"SODIMM_42",
-		"SODIMM_218",
-		"",
-		"SODIMM_189",
-		"",
-		"SODIMM_216", /* 40 */
-		"SODIMM_220",
-		"SODIMM_222",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 50 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 60 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 70 */
-		"SODIMM_157",
-		"SODIMM_187",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 80 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"";
-
-	verdin_ctrl_sleep_moci: ctrl-sleep-moci-hog {
-		gpio-hog;
-		/* Verdin CTRL_SLEEP_MOCI# (SODIMM 256) */
-		gpios = <31 GPIO_ACTIVE_HIGH>;
-		line-name = "CTRL_SLEEP_MOCI#";
-		output-high;
-	};
-};
-
-&main_gpio1 {
-	gpio-line-names =
-		"", /* 0 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 10 */
-		"",
-		"",
-		"",
-		"",
-		"SODIMM_15",
-		"SODIMM_16",
-		"SODIMM_19",
-		"SODIMM_66",
-		"SODIMM_161",
-		"", /* 20 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 30 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 40 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"SODIMM_17",
-		"", /* 50 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 60 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 70 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"", /* 80 */
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"";
-};
-
-/* On-module I2C - PMIC_I2C */
-&main_i2c0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c0>;
-	clock-frequency = <400000>;
-	status = "okay";
-
-	dsi_bridge: dsi@e {
-		compatible = "toshiba,tc358778";
-		reg = <0xe>;
-		assigned-clocks = <&k3_clks 157 20>;
-		assigned-clock-parents = <&k3_clks 157 22>;
-		assigned-clock-rates = <25000000>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_bridge_reset>;
-		clocks = <&k3_clks 157 20>;
-		clock-names = "refclk";
-		reset-gpios = <&main_gpio0 20 GPIO_ACTIVE_LOW>;
-		vddc-supply = <&reg_1v2_dsi>;
-		vddmipi-supply = <&reg_1v2_dsi>;
-		vddio-supply = <&reg_1v8_dsi>;
-		status = "disabled";
-
-		dsi_bridge_ports: ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
-
-			port@0 {
-				reg = <0>;
-
-				rgb_in: endpoint {
-					data-lines = <18>;
-					remote-endpoint = <&dpi_out>;
-				};
-			};
-
-			port@1 {
-				reg = <1>;
-			};
-		};
-	};
-
-	pmic@30 {
-		compatible = "ti,tps65219";
-		reg = <0x30>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_pmic_extint>;
-		interrupt-parent = <&gic500>;
-		interrupts = <GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>;
-
-		buck1-supply = <&reg_vsodimm>;
-		buck2-supply = <&reg_vsodimm>;
-		buck3-supply = <&reg_vsodimm>;
-		ldo1-supply = <&reg_3v3>;
-		ldo2-supply = <&reg_1v8>;
-		ldo3-supply = <&reg_3v3>;
-		ldo4-supply = <&reg_3v3>;
-		system-power-controller;
-		ti,power-button;
-
-		regulators {
-			reg_vdd_core: buck1 {
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-max-microvolt = <850000>;
-				regulator-min-microvolt = <850000>;
-				regulator-name = "+VDD_CORE (PMIC BUCK1)";
-			};
-
-			reg_1v8: buck2 {
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-max-microvolt = <1800000>;
-				regulator-min-microvolt = <1800000>;
-				regulator-name = "+V1.8 (PMIC BUCK2)"; /* On-module and SODIMM 214 */
-			};
-
-			reg_vdd_ddr: buck3 {
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-max-microvolt = <1100000>;
-				regulator-min-microvolt = <1100000>;
-				regulator-name = "+VDD_DDR (PMIC BUCK3)";
-			};
-
-			reg_sd_3v3_1v8: ldo1 {
-				regulator-allow-bypass;
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-max-microvolt = <3300000>;
-				regulator-min-microvolt = <3300000>;
-				regulator-name = "+V3.3_1.8_SD (PMIC LDO1)";
-			};
-
-			reg_vddr_core: ldo2 {
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-max-microvolt = <850000>;
-				regulator-min-microvolt = <850000>;
-				regulator-name = "+VDDR_CORE (PMIC LDO2)";
-			};
-
-			reg_1v8a: ldo3 {
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-max-microvolt = <1800000>;
-				regulator-min-microvolt = <1800000>;
-				regulator-name = "+V1.8A (PMIC LDO3)";
-			};
-
-			reg_eth_2v5: ldo4 {
-				regulator-always-on;
-				regulator-boot-on;
-				regulator-max-microvolt = <2500000>;
-				regulator-min-microvolt = <2500000>;
-				regulator-name = "+V2.5_ETH (PMIC LDO4)";
-			};
-		};
-	};
-
-	rtc_i2c: rtc@32 {
-		compatible = "epson,rx8130";
-		reg = <0x32>;
-	};
-
-	sensor@48 {
-		compatible = "ti,tmp1075";
-		reg = <0x48>;
-	};
-
-	adc@49 {
-		compatible = "ti,ads1015";
-		reg = <0x49>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		/* Verdin PMIC_I2C (ADC_4 - ADC_3) */
-		channel@0 {
-			reg = <0>;
-			ti,datarate = <4>;
-			ti,gain = <2>;
-		};
-
-		/* Verdin PMIC_I2C (ADC_4 - ADC_1) */
-		channel@1 {
-			reg = <1>;
-			ti,datarate = <4>;
-			ti,gain = <2>;
-		};
-
-		/* Verdin PMIC_I2C (ADC_3 - ADC_1) */
-		channel@2 {
-			reg = <2>;
-			ti,datarate = <4>;
-			ti,gain = <2>;
-		};
-
-		/* Verdin PMIC_I2C (ADC_2 - ADC_1) */
-		channel@3 {
-			reg = <3>;
-			ti,datarate = <4>;
-			ti,gain = <2>;
-		};
-
-		/* Verdin PMIC_I2C ADC_4 */
-		channel@4 {
-			reg = <4>;
-			ti,datarate = <4>;
-			ti,gain = <2>;
-		};
-
-		/* Verdin PMIC_I2C ADC_3 */
-		channel@5 {
-			reg = <5>;
-			ti,datarate = <4>;
-			ti,gain = <2>;
-		};
-
-		/* Verdin PMIC_I2C ADC_2 */
-		channel@6 {
-			reg = <6>;
-			ti,datarate = <4>;
-			ti,gain = <2>;
-		};
-
-		/* Verdin PMIC_I2C ADC_1 */
-		channel@7 {
-			reg = <7>;
-			ti,datarate = <4>;
-			ti,gain = <2>;
-		};
-	};
-
-	eeprom@50 {
-		compatible = "st,24c02", "atmel,24c02";
-		pagesize = <16>;
-		reg = <0x50>;
-	};
-};
-
-/* Verdin I2C_1 */
-&main_i2c1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c1>;
-	status = "disabled";
-};
-
-/* Verdin I2C_2_DSI */
-&main_i2c2 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c2>;
-	status = "disabled";
-};
-
-/* Verdin I2C_4_CSI */
-&main_i2c3 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c3>;
-	status = "disabled";
-};
-
-&mailbox0_cluster0 {
-	mbox_m4_0: mbox-m4-0 {
-		ti,mbox-rx = <0 0 0>;
-		ti,mbox-tx = <1 0 0>;
-	};
-};
-
-/* Verdin CAN_1 */
-&main_mcan0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_mcan0>;
-	status = "disabled";
-};
-
-/* Verdin SPI_1 */
-&main_spi1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_spi1>;
-	ti,pindir-d0-out-d1-in;
-	status = "disabled";
-};
-
-/* Verdin UART_3, used as the Linux console */
-&main_uart0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart0>;
-	status = "disabled";
-};
-
-/* Verdin UART_1 */
-&main_uart1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart1>;
-	status = "disabled";
-};
-
-/* Verdin I2S_1 */
-&mcasp0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_mcasp0>;
-	op-mode = <0>; /* I2S mode */
-	serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
-	       1 2 0 0
-	       0 0 0 0
-	       0 0 0 0
-	       0 0 0 0
-	>;
-	tdm-slots = <2>;
-	rx-num-evt = <32>;
-	tx-num-evt = <32>;
-	#sound-dai-cells = <0>;
-	status = "disabled";
-};
-
-/* Verdin I2S_2 */
-&mcasp1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_mcasp1>;
-	op-mode = <0>; /* I2S mode */
-	serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
-	       1 2 0 0
-	       0 0 0 0
-	       0 0 0 0
-	       0 0 0 0
-	>;
-	tdm-slots = <2>;
-	rx-num-evt = <32>;
-	tx-num-evt = <32>;
-	#sound-dai-cells = <0>;
-	status = "disabled";
-};
-
-/* Verdin I2C_3_HDMI */
-&mcu_i2c0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_mcu_i2c0>;
-	status = "disabled";
-};
-
-&mcu_gpio0 {
-	gpio-line-names =
-		"SODIMM_244",
-		"SODIMM_206",
-		"SODIMM_208",
-		"SODIMM_210",
-		"SODIMM_212",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"",
-		"";
-};
-
-/* Verdin CAN_2 */
-&mcu_mcan0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_mcu_mcan0>;
-	status = "disabled";
-};
-
-/* Verdin UART_4 - Cortex-M4 UART */
-&mcu_uart0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_mcu_uart0>;
-	status = "disabled";
-};
-
-/* Verdin QSPI_1 */
-&ospi0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_ospi0>;
-	status = "disabled";
-};
-
-/* On-module eMMC */
-&sdhci0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_sdhci0>;
-	non-removable;
-	ti,driver-strength-ohm = <50>;
-	status = "okay";
-};
-
-/* Verdin SD_1 */
-&sdhci1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_sdhci1>;
-	disable-wp;
-	ti,driver-strength-ohm = <50>;
-	vmmc-supply = <&reg_sdhc1_vmmc>;
-	vqmmc-supply = <&reg_sdhc1_vqmmc>;
-	status = "disabled";
-};
-
-/* Verdin USB_1 */
-&usbss0 {
-	ti,vbus-divider;
-	status = "disabled";
-};
-
-/* TODO: role swich using ID pin */
-&usb0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_usb0>, <&pinctrl_usb0_id>;
-	status = "disabled";
-};
-
-/* Verdin USB_2 */
-&usbss1 {
-	ti,vbus-divider;
-	status = "disabled";
-};
-
-&usb1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_usb1>;
-	dr_mode = "host";
-	status = "disabled";
-};
-
-/* Verdin UART_2 */
-&wkup_uart0 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_wkup_uart0>;
-	status = "disabled";
-};
diff --git a/arch/arm/dts/k3-am625-beagleplay-u-boot.dtsi b/arch/arm/dts/k3-am625-beagleplay-u-boot.dtsi
index cca0f44..fb20320 100644
--- a/arch/arm/dts/k3-am625-beagleplay-u-boot.dtsi
+++ b/arch/arm/dts/k3-am625-beagleplay-u-boot.dtsi
@@ -41,13 +41,6 @@
 	clock-frequency = <25000000>;
 };
 
-&dmsc {
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
-};
-
 &sd_pins_default {
 	/* Force to use SDCD card detect pin */
 	pinctrl-single,pins = <
diff --git a/arch/arm/dts/k3-am625-phyboard-lyra-rdk-u-boot.dtsi b/arch/arm/dts/k3-am625-phyboard-lyra-rdk-u-boot.dtsi
index f6138f3..9416228 100644
--- a/arch/arm/dts/k3-am625-phyboard-lyra-rdk-u-boot.dtsi
+++ b/arch/arm/dts/k3-am625-phyboard-lyra-rdk-u-boot.dtsi
@@ -42,13 +42,6 @@
 	bootph-all;
 };
 
-&dmsc {
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
-};
-
 &fss {
 	bootph-all;
 };
diff --git a/arch/arm/dts/k3-am625-sk-binman.dtsi b/arch/arm/dts/k3-am625-sk-binman.dtsi
index 5b058bd..dfd38d6 100644
--- a/arch/arm/dts/k3-am625-sk-binman.dtsi
+++ b/arch/arm/dts/k3-am625-sk-binman.dtsi
@@ -151,11 +151,107 @@
 			filename = "ti-dm/am62xx/ipc_echo_testb_mcu1_0_release_strip.xer5f";
 		};
 	};
+
+	tifsstub-hs {
+		filename = "tifsstub.bin_hs";
+		ti-secure-rom {
+			content = <&tifsstub_hs_cert>;
+			core = "secure";
+			load = <0x40000>;
+			sw-rev = <CONFIG_K3_X509_SWRV>;
+			keyfile = "custMpk.pem";
+			countersign;
+			tifsstub;
+		};
+		tifsstub_hs_cert: tifsstub-hs-cert.bin {
+			filename = "ti-sysfw/ti-fs-stub-firmware-am62x-hs-cert.bin";
+			type = "blob-ext";
+			optional;
+		};
+		tifsstub_hs_enc: tifsstub-hs-enc.bin {
+			filename = "ti-sysfw/ti-fs-stub-firmware-am62x-hs-enc.bin";
+			type = "blob-ext";
+			optional;
+		};
+	};
+
+	tifsstub-fs {
+		filename = "tifsstub.bin_fs";
+		tifsstub_fs_cert: tifsstub-fs-cert.bin {
+			filename = "ti-sysfw/ti-fs-stub-firmware-am62x-hs-cert.bin";
+			type = "blob-ext";
+			optional;
+		};
+		tifsstub_fs_enc: tifsstub-fs-enc.bin {
+			filename = "ti-sysfw/ti-fs-stub-firmware-am62x-hs-enc.bin";
+			type = "blob-ext";
+			optional;
+		};
+
+	};
+
+	tifsstub-gp {
+		filename = "tifsstub.bin_gp";
+		ti-secure-rom {
+			content = <&tifsstub_gp>;
+			core = "secure";
+			load = <0x60000>;
+			sw-rev = <CONFIG_K3_X509_SWRV>;
+			keyfile = "ti-degenerate-key.pem";
+			tifsstub;
+		};
+		tifsstub_gp: tifsstub-gp.bin {
+			filename = "ti-sysfw/ti-fs-stub-firmware-am62x-gp.bin";
+			type = "blob-ext";
+			optional;
+		};
+	};
+
 	ti-spl {
 		insert-template = <&ti_spl_template>;
 
 		fit {
 			images {
+
+				tifsstub-hs {
+					description = "TIFSSTUB";
+					type = "firmware";
+					arch = "arm32";
+					compression = "none";
+					os = "tifsstub-hs";
+					load = <0x9dc00000>;
+					entry = <0x9dc00000>;
+					blob-ext {
+						filename = "tifsstub.bin_hs";
+					};
+				};
+
+				tifsstub-fs {
+					description = "TIFSSTUB";
+					type = "firmware";
+					arch = "arm32";
+					compression = "none";
+					os = "tifsstub-fs";
+					load = <0x9dc00000>;
+					entry = <0x9dc00000>;
+					blob-ext {
+						filename = "tifsstub.bin_fs";
+					};
+				};
+
+				tifsstub-gp {
+					description = "TIFSSTUB";
+					type = "firmware";
+					arch = "arm32";
+					compression = "none";
+					os = "tifsstub-gp";
+					load = <0x9dc00000>;
+					entry = <0x9dc00000>;
+					blob-ext {
+						filename = "tifsstub.bin_gp";
+					};
+				};
+
 				dm {
 					ti-secure {
 						content = <&dm>;
@@ -189,7 +285,8 @@
 				conf-0 {
 					description = "k3-am625-sk";
 					firmware = "atf";
-					loadables = "tee", "dm", "spl";
+					loadables = "tee", "tifsstub-hs", "tifsstub-fs",
+					"tifsstub-gp", "dm", "spl";
 					fdt = "fdt-0";
 				};
 			};
@@ -247,6 +344,45 @@
 		fit {
 			images {
 
+				tifsstub-hs {
+					description = "tifsstub";
+					type = "firmware";
+					arch = "arm32";
+					compression = "none";
+					os = "tifsstub-hs";
+					load = <0x9dc00000>;
+					entry = <0x9dc00000>;
+					blob-ext {
+						filename = "tifsstub.bin_hs";
+					};
+				};
+
+				tifsstub-fs {
+					description = "tifsstub";
+					type = "firmware";
+					arch = "arm32";
+					compression = "none";
+					os = "tifsstub-fs";
+					load = <0x9dc00000>;
+					entry = <0x9dc00000>;
+					blob-ext {
+						filename = "tifsstub.bin_fs";
+					};
+				};
+
+				tifsstub-gp {
+					description = "tifsstub";
+					type = "firmware";
+					arch = "arm32";
+					compression = "none";
+					os = "tifsstub-gp";
+					load = <0x9dc00000>;
+					entry = <0x9dc00000>;
+					blob-ext {
+						filename = "tifsstub.bin_gp";
+					};
+				};
+
 				dm {
 					ti-dm {
 						filename = "ti-dm.bin";
@@ -270,7 +406,8 @@
 				conf-0 {
 					description = "k3-am625-sk";
 					firmware = "atf";
-					loadables = "tee", "dm", "spl";
+					loadables = "tee", "tifsstub-hs", "tifsstub-fs",
+						  "tifsstub-gp", "dm", "spl";
 					fdt = "fdt-0";
 				};
 			};
diff --git a/arch/arm/dts/k3-am625-verdin-wifi-dev-binman.dtsi b/arch/arm/dts/k3-am625-verdin-wifi-dev-binman.dtsi
index 4e37048..6f58450 100644
--- a/arch/arm/dts/k3-am625-verdin-wifi-dev-binman.dtsi
+++ b/arch/arm/dts/k3-am625-verdin-wifi-dev-binman.dtsi
@@ -140,7 +140,7 @@
 
 #ifdef CONFIG_TARGET_VERDIN_AM62_A53
 
-#define SPL_VERDIN_AM62_DTB "spl/dts/k3-am625-verdin-wifi-dev.dtb"
+#define SPL_VERDIN_AM62_DTB "spl/dts/ti/k3-am625-verdin-wifi-dev.dtb"
 #define VERDIN_AM62_DTB "u-boot.dtb"
 
 &binman {
diff --git a/arch/arm/dts/k3-am625-verdin-wifi-dev-u-boot.dtsi b/arch/arm/dts/k3-am625-verdin-wifi-dev-u-boot.dtsi
index 28b697b..7fe7ae4 100644
--- a/arch/arm/dts/k3-am625-verdin-wifi-dev-u-boot.dtsi
+++ b/arch/arm/dts/k3-am625-verdin-wifi-dev-u-boot.dtsi
@@ -85,13 +85,6 @@
 	bootph-all;
 };
 
-&dmsc {
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
-};
-
 &fss {
 	bootph-all;
 };
diff --git a/arch/arm/dts/k3-am625-verdin-wifi-dev.dts b/arch/arm/dts/k3-am625-verdin-wifi-dev.dts
deleted file mode 100644
index 4b657d6..0000000
--- a/arch/arm/dts/k3-am625-verdin-wifi-dev.dts
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-/*
- * Copyright 2023 Toradex
- *
- * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62
- * https://www.toradex.com/products/carrier-board/verdin-development-board-kit
- */
-
-/dts-v1/;
-
-#include "k3-am625.dtsi"
-#include "k3-am62-verdin.dtsi"
-#include "k3-am62-verdin-wifi.dtsi"
-#include "k3-am62-verdin-dev.dtsi"
-
-/ {
-	model = "Toradex Verdin AM62 WB on Verdin Development Board";
-	compatible = "toradex,verdin-am62-wifi-dev",
-		     "toradex,verdin-am62-wifi",
-		     "toradex,verdin-am62",
-		     "ti,am625";
-};
diff --git a/arch/arm/dts/k3-am62a7-sk-u-boot.dtsi b/arch/arm/dts/k3-am62a7-sk-u-boot.dtsi
index 31b89b4..c42dec1 100644
--- a/arch/arm/dts/k3-am62a7-sk-u-boot.dtsi
+++ b/arch/arm/dts/k3-am62a7-sk-u-boot.dtsi
@@ -119,10 +119,6 @@
 
 &dmsc {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &vdd_mmc1 {
diff --git a/arch/arm/dts/k3-am62p5-sk-u-boot.dtsi b/arch/arm/dts/k3-am62p5-sk-u-boot.dtsi
index c166d65..cf087c6 100644
--- a/arch/arm/dts/k3-am62p5-sk-u-boot.dtsi
+++ b/arch/arm/dts/k3-am62p5-sk-u-boot.dtsi
@@ -15,9 +15,4 @@
 
 &dmsc {
 	bootph-pre-ram;
-
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-pre-ram;
-	};
 };
diff --git a/arch/arm/dts/k3-am642-evm-u-boot.dtsi b/arch/arm/dts/k3-am642-evm-u-boot.dtsi
index ee66567..705b3ba 100644
--- a/arch/arm/dts/k3-am642-evm-u-boot.dtsi
+++ b/arch/arm/dts/k3-am642-evm-u-boot.dtsi
@@ -23,13 +23,6 @@
 	bootph-all;
 };
 
-&dmsc {
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
-};
-
 &sdhci0 {
 	bootph-all;
 };
diff --git a/arch/arm/dts/k3-am642-phyboard-electra-rdk-u-boot.dtsi b/arch/arm/dts/k3-am642-phyboard-electra-rdk-u-boot.dtsi
index 5dfc40a..4677c35 100644
--- a/arch/arm/dts/k3-am642-phyboard-electra-rdk-u-boot.dtsi
+++ b/arch/arm/dts/k3-am642-phyboard-electra-rdk-u-boot.dtsi
@@ -29,10 +29,6 @@
 
 &dmsc {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &dmss {
diff --git a/arch/arm/dts/k3-am642-sk-u-boot.dtsi b/arch/arm/dts/k3-am642-sk-u-boot.dtsi
index 7e6b298..6fcb11b 100644
--- a/arch/arm/dts/k3-am642-sk-u-boot.dtsi
+++ b/arch/arm/dts/k3-am642-sk-u-boot.dtsi
@@ -15,13 +15,6 @@
 	clock-frequency = <200000000>;
 };
 
-&dmsc {
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
-};
-
 &sdhci0 {
 	status = "disabled";
 };
diff --git a/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi b/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi
index d53f133..b6d2c81 100644
--- a/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi
+++ b/arch/arm/dts/k3-am65-iot2050-common-u-boot.dtsi
@@ -99,10 +99,6 @@
 
 &dmsc {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &k3_pds {
diff --git a/arch/arm/dts/k3-am68-sk-base-board-u-boot.dtsi b/arch/arm/dts/k3-am68-sk-base-board-u-boot.dtsi
index 4f34347..b8fc62f 100644
--- a/arch/arm/dts/k3-am68-sk-base-board-u-boot.dtsi
+++ b/arch/arm/dts/k3-am68-sk-base-board-u-boot.dtsi
@@ -51,10 +51,6 @@
 
 &sms {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &main_pmx0 {
diff --git a/arch/arm/dts/k3-am69-sk-u-boot.dtsi b/arch/arm/dts/k3-am69-sk-u-boot.dtsi
index bed330e..4a82d2f 100644
--- a/arch/arm/dts/k3-am69-sk-u-boot.dtsi
+++ b/arch/arm/dts/k3-am69-sk-u-boot.dtsi
@@ -23,13 +23,6 @@
 	bootph-pre-ram;
 };
 
-&sms {
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-pre-ram;
-	};
-};
-
 #ifdef CONFIG_TARGET_J784S4_A72_EVM
 
 #define SPL_AM69_SK_DTB "spl/dts/ti/k3-am69-sk.dtb"
diff --git a/arch/arm/dts/k3-j7200-common-proc-board-u-boot.dtsi b/arch/arm/dts/k3-j7200-common-proc-board-u-boot.dtsi
index c9fee0e..485f17c 100644
--- a/arch/arm/dts/k3-j7200-common-proc-board-u-boot.dtsi
+++ b/arch/arm/dts/k3-j7200-common-proc-board-u-boot.dtsi
@@ -57,10 +57,6 @@
 
 &dmsc {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &k3_pds {
diff --git a/arch/arm/dts/k3-j721e-beagleboneai64-u-boot.dtsi b/arch/arm/dts/k3-j721e-beagleboneai64-u-boot.dtsi
index 116ee37..e202ae1 100644
--- a/arch/arm/dts/k3-j721e-beagleboneai64-u-boot.dtsi
+++ b/arch/arm/dts/k3-j721e-beagleboneai64-u-boot.dtsi
@@ -92,10 +92,6 @@
 
 &dmsc {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &k3_pds {
diff --git a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi
index 9433f3b..aa919b4 100644
--- a/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi
+++ b/arch/arm/dts/k3-j721e-common-proc-board-u-boot.dtsi
@@ -47,10 +47,6 @@
 
 &dmsc {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &k3_pds {
diff --git a/arch/arm/dts/k3-j721e-sk-u-boot.dtsi b/arch/arm/dts/k3-j721e-sk-u-boot.dtsi
index 8b20555..8f4f944 100644
--- a/arch/arm/dts/k3-j721e-sk-u-boot.dtsi
+++ b/arch/arm/dts/k3-j721e-sk-u-boot.dtsi
@@ -47,10 +47,6 @@
 
 &dmsc {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &k3_pds {
diff --git a/arch/arm/dts/k3-j721s2-common-proc-board-u-boot.dtsi b/arch/arm/dts/k3-j721s2-common-proc-board-u-boot.dtsi
index a3ebf59..19b2d48 100644
--- a/arch/arm/dts/k3-j721s2-common-proc-board-u-boot.dtsi
+++ b/arch/arm/dts/k3-j721s2-common-proc-board-u-boot.dtsi
@@ -51,10 +51,6 @@
 
 &sms {
 	bootph-all;
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-all;
-	};
 };
 
 &main_pmx0 {
diff --git a/arch/arm/dts/k3-j784s4-evm-u-boot.dtsi b/arch/arm/dts/k3-j784s4-evm-u-boot.dtsi
index ac74978..8f03073 100644
--- a/arch/arm/dts/k3-j784s4-evm-u-boot.dtsi
+++ b/arch/arm/dts/k3-j784s4-evm-u-boot.dtsi
@@ -22,10 +22,3 @@
 		    "tchanrt", "rflow";
 	bootph-pre-ram;
 };
-
-&sms {
-	k3_sysreset: sysreset-controller {
-		compatible = "ti,sci-sysreset";
-		bootph-pre-ram;
-	};
-};
diff --git a/arch/arm/dts/zynqmp-mini-nand.dts b/arch/arm/dts/zynqmp-mini-nand.dts
index e0517cf..5889d43 100644
--- a/arch/arm/dts/zynqmp-mini-nand.dts
+++ b/arch/arm/dts/zynqmp-mini-nand.dts
@@ -50,6 +50,12 @@
 			#size-cells = <1>;
 			arasan,has-mdma;
 			num-cs = <2>;
+			nand@0 {
+				reg = <0>;
+				#address-cells = <2>;
+				#size-cells = <1>;
+				nand-ecc-mode = "hw";
+			};
 		};
 	};
 };
diff --git a/arch/arm/dts/zynqmp-sc-revB.dts b/arch/arm/dts/zynqmp-sc-revB.dts
index 8517bda..c1d713b 100644
--- a/arch/arm/dts/zynqmp-sc-revB.dts
+++ b/arch/arm/dts/zynqmp-sc-revB.dts
@@ -49,7 +49,7 @@
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
-		fwuen {
+		key-fwuen {
 			label = "sw16";
 			gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
 			linux,code = <BTN_MISC>;
@@ -192,7 +192,7 @@
 	status = "okay";
 	/* QSPI should also have PINCTRL setup */
 	flash@0 {
-		compatible = "mt25qu512a", "m25p80", "jedec,spi-nor"; /* mt25qu512abb8e12 512Mib */
+		compatible = "m25p80", "jedec,spi-nor"; /* mt25qu512abb8e12 512Mib */
 		#address-cells = <1>;
 		#size-cells = <1>;
 		reg = <0>;
diff --git a/arch/arm/dts/zynqmp-sck-kd-g-revA.dtso b/arch/arm/dts/zynqmp-sck-kd-g-revA.dtso
index 5202b7c..1727a1c 100644
--- a/arch/arm/dts/zynqmp-sck-kd-g-revA.dtso
+++ b/arch/arm/dts/zynqmp-sck-kd-g-revA.dtso
@@ -356,6 +356,8 @@
 
 &uart0 {
 	status = "okay";
+	rts-gpios = <&gpio 72 GPIO_ACTIVE_HIGH>;
+	linux,rs485-enabled-at-boot-time;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart0_default>;
 	assigned-clock-rates = <100000000>;
diff --git a/arch/arm/dts/zynqmp-sck-kr-g-revB.dtso b/arch/arm/dts/zynqmp-sck-kr-g-revB.dtso
index 6c29f65..0a0cbd2 100644
--- a/arch/arm/dts/zynqmp-sck-kr-g-revB.dtso
+++ b/arch/arm/dts/zynqmp-sck-kr-g-revB.dtso
@@ -66,6 +66,18 @@
 		#clock-cells = <0>;
 		clock-frequency = <74250000>;
 	};
+
+	dpcon {
+		compatible = "dp-connector";
+		label = "P11";
+		type = "full-size";
+
+		port {
+			dpcon_in: endpoint {
+				remote-endpoint = <&dpsub_dp_out>;
+			};
+		};
+	};
 };
 
 &i2c1 { /* I2C_SCK C26/C27 - MIO from SOM */
@@ -130,6 +142,14 @@
 	phy-names = "dp-phy0";
 	phys = <&psgtr 1 PHY_TYPE_DP 0 1>;
 	assigned-clock-rates = <27000000>, <25000000>, <300000000>;
+
+	ports {
+		port@5 {
+			dpsub_dp_out: endpoint {
+				remote-endpoint = <&dpcon_in>;
+			};
+		};
+	};
 };
 
 &zynqmp_dpdma {
diff --git a/arch/arm/dts/zynqmp-sck-kv-g-revA.dtso b/arch/arm/dts/zynqmp-sck-kv-g-revA.dtso
index 6d0d5c4..561b546 100644
--- a/arch/arm/dts/zynqmp-sck-kv-g-revA.dtso
+++ b/arch/arm/dts/zynqmp-sck-kv-g-revA.dtso
@@ -342,6 +342,7 @@
 			slew-rate = <SLEW_RATE_SLOW>;
 			power-source = <IO_STANDARD_LVCMOS18>;
 			bias-disable;
+			output-enable;
 		};
 
 		conf-cd {
diff --git a/arch/arm/dts/zynqmp-sck-kv-g-revB.dtso b/arch/arm/dts/zynqmp-sck-kv-g-revB.dtso
index a4b4465..64683e0 100644
--- a/arch/arm/dts/zynqmp-sck-kv-g-revB.dtso
+++ b/arch/arm/dts/zynqmp-sck-kv-g-revB.dtso
@@ -63,6 +63,18 @@
 		#clock-cells = <0>;
 		clock-frequency = <27000000>;
 	};
+
+	dpcon {
+		compatible = "dp-connector";
+		label = "P11";
+		type = "full-size";
+
+		port {
+			dpcon_in: endpoint {
+				remote-endpoint = <&dpsub_dp_out>;
+			};
+		};
+	};
 };
 
 &i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */
@@ -97,6 +109,14 @@
 	phy-names = "dp-phy0", "dp-phy1";
 	phys = <&psgtr 1 PHY_TYPE_DP 0 0>, <&psgtr 0 PHY_TYPE_DP 1 0>;
 	assigned-clock-rates = <27000000>, <25000000>, <300000000>;
+
+	ports {
+		port@5 {
+			dpsub_dp_out: endpoint {
+				remote-endpoint = <&dpcon_in>;
+			};
+		};
+	};
 };
 
 &zynqmp_dpdma {
@@ -329,6 +349,7 @@
 			slew-rate = <SLEW_RATE_SLOW>;
 			power-source = <IO_STANDARD_LVCMOS18>;
 			bias-disable;
+			output-enable;
 		};
 
 		conf-cd {
diff --git a/arch/arm/dts/zynqmp-vp-x-a2785-00-revA.dts b/arch/arm/dts/zynqmp-vp-x-a2785-00-revA.dts
index 2a3bbe1..b626d1a 100644
--- a/arch/arm/dts/zynqmp-vp-x-a2785-00-revA.dts
+++ b/arch/arm/dts/zynqmp-vp-x-a2785-00-revA.dts
@@ -47,7 +47,7 @@
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
-		j383 {
+		key-j383 {
 			label = "j383";
 			gpios = <&gpio 10 GPIO_ACTIVE_HIGH>;
 			linux,code = <BTN_MISC>;
diff --git a/arch/arm/dts/zynqmp-vpk120-revA.dts b/arch/arm/dts/zynqmp-vpk120-revA.dts
index e0e4f1b..e063288 100644
--- a/arch/arm/dts/zynqmp-vpk120-revA.dts
+++ b/arch/arm/dts/zynqmp-vpk120-revA.dts
@@ -47,7 +47,7 @@
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
-		sw16 {
+		button-16 {
 			label = "sw16";
 			gpios = <&gpio 10 GPIO_ACTIVE_HIGH>;
 			linux,code = <BTN_MISC>;
diff --git a/arch/arm/dts/zynqmp-zc1751-xm017-dc3.dts b/arch/arm/dts/zynqmp-zc1751-xm017-dc3.dts
index b97f7ee..48ab619 100644
--- a/arch/arm/dts/zynqmp-zc1751-xm017-dc3.dts
+++ b/arch/arm/dts/zynqmp-zc1751-xm017-dc3.dts
@@ -136,8 +136,7 @@
 		reg = <0x0>;
 		#address-cells = <0x2>;
 		#size-cells = <0x1>;
-		nand-ecc-mode = "soft";
-		nand-ecc-algo = "bch";
+		nand-ecc-mode = "hw";
 		nand-rb = <0>;
 		label = "main-storage-0";
 		nand-ecc-step-size = <1024>;
@@ -173,8 +172,7 @@
 		reg = <0x1>;
 		#address-cells = <0x2>;
 		#size-cells = <0x1>;
-		nand-ecc-mode = "soft";
-		nand-ecc-algo = "bch";
+		nand-ecc-mode = "hw";
 		nand-rb = <0>;
 		label = "main-storage-1";
 		nand-ecc-step-size = <1024>;
diff --git a/arch/arm/dts/zynqmp-zcu208-revA.dts b/arch/arm/dts/zynqmp-zcu208-revA.dts
index b4e2474..a113e47 100644
--- a/arch/arm/dts/zynqmp-zcu208-revA.dts
+++ b/arch/arm/dts/zynqmp-zcu208-revA.dts
@@ -46,7 +46,7 @@
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
-		sw19 {
+		switch-19 {
 			label = "sw19";
 			gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
 			linux,code = <KEY_DOWN>;
diff --git a/arch/arm/dts/zynqmp-zcu216-revA.dts b/arch/arm/dts/zynqmp-zcu216-revA.dts
index 6f593e8..4d7d5d2 100644
--- a/arch/arm/dts/zynqmp-zcu216-revA.dts
+++ b/arch/arm/dts/zynqmp-zcu216-revA.dts
@@ -46,7 +46,7 @@
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
-		sw19 {
+		switch-19 {
 			label = "sw19";
 			gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
 			linux,code = <KEY_DOWN>;
diff --git a/arch/arm/dts/zynqmp-zcu670-revA.dts b/arch/arm/dts/zynqmp-zcu670-revA.dts
index 7f70904..def3b53 100644
--- a/arch/arm/dts/zynqmp-zcu670-revA.dts
+++ b/arch/arm/dts/zynqmp-zcu670-revA.dts
@@ -49,7 +49,7 @@
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
-		sw1 {
+		switch-1 {
 			label = "sw1";
 			gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
 			linux,code = <BTN_MISC>;
diff --git a/arch/arm/dts/zynqmp-zcu670-revB.dts b/arch/arm/dts/zynqmp-zcu670-revB.dts
index 0adb206..41f9a23 100644
--- a/arch/arm/dts/zynqmp-zcu670-revB.dts
+++ b/arch/arm/dts/zynqmp-zcu670-revB.dts
@@ -49,7 +49,7 @@
 	gpio-keys {
 		compatible = "gpio-keys";
 		autorepeat;
-		sw1 {
+		switch-1 {
 			label = "sw1";
 			gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
 			linux,code = <BTN_MISC>;
diff --git a/arch/arm/dts/zynqmp.dtsi b/arch/arm/dts/zynqmp.dtsi
index b50b83b..53a606c 100644
--- a/arch/arm/dts/zynqmp.dtsi
+++ b/arch/arm/dts/zynqmp.dtsi
@@ -168,7 +168,7 @@
 		bootph-all;
 	};
 
-	pmu {
+	pmu: pmu {
 		compatible = "arm,armv8-pmuv3";
 		interrupt-parent = <&gic>;
 		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
@@ -1001,14 +1001,14 @@
 				status = "disabled";
 				reg = <0x0 0xfe200000 0x0 0x40000>;
 				interrupt-parent = <&gic>;
-				interrupt-names = "host", "peripheral", "otg";
+				interrupt-names = "host", "peripheral", "otg", "wakeup";
 				interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+					     <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
 				/* iommus = <&smmu 0x860>; */
 				snps,quirk-frame-length-adjustment = <0x20>;
 				clock-names = "ref";
-				snps,enable_guctl1_ipd_quirk;
 				snps,resume-hs-terminations;
 				/* dma-coherent; */
 			};
@@ -1033,14 +1033,14 @@
 				status = "disabled";
 				reg = <0x0 0xfe300000 0x0 0x40000>;
 				interrupt-parent = <&gic>;
-				interrupt-names = "host", "peripheral", "otg";
+				interrupt-names = "host", "peripheral", "otg", "wakeup";
 				interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
 					     <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
-					     <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+					     <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+					     <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
 				/* iommus = <&smmu 0x861>; */
 				snps,quirk-frame-length-adjustment = <0x20>;
 				clock-names = "ref";
-				snps,enable_guctl1_ipd_quirk;
 				snps,resume-hs-terminations;
 				/* dma-coherent; */
 			};
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 67275fb..b55167e 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -31,7 +31,7 @@
 obj-$(CONFIG_CPU_V7M) += cmd_boot.o
 obj-$(CONFIG_OF_LIBFDT) += bootm-fdt.o
 obj-$(CONFIG_CMD_BOOTI) += bootm.o image.o
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-$(CONFIG_CMD_BOOTZ) += bootm.o zimage.o
 else
 obj-$(CONFIG_$(SPL_TPL_)FRAMEWORK) += spl.o
diff --git a/arch/arm/mach-k3/Makefile b/arch/arm/mach-k3/Makefile
index 6ee9864..1bd5233 100644
--- a/arch/arm/mach-k3/Makefile
+++ b/arch/arm/mach-k3/Makefile
@@ -25,3 +25,4 @@
 obj-$(CONFIG_SOC_K3_AM62P5) += am62p5_init.o
 endif
 obj-y += common.o security.o
+obj-$(CONFIG_SOC_K3_AM625) += am62x/
diff --git a/arch/arm/mach-k3/am625_init.c b/arch/arm/mach-k3/am625_init.c
index 6c96e88..668f9a5 100644
--- a/arch/arm/mach-k3/am625_init.c
+++ b/arch/arm/mach-k3/am625_init.c
@@ -14,6 +14,7 @@
 #include <dm.h>
 #include <dm/uclass-internal.h>
 #include <dm/pinctrl.h>
+#include <dm/ofnode.h>
 
 #define RTC_BASE_ADDRESS		0x2b1f0000
 #define REG_K3RTC_S_CNT_LSW		(RTC_BASE_ADDRESS + 0x18)
@@ -24,6 +25,9 @@
 #define K3RTC_KICK0_UNLOCK_VALUE	0x83e70b13
 #define K3RTC_KICK1_UNLOCK_VALUE	0x95a4f1e0
 
+/* TISCI DEV ID for A53 Clock */
+#define AM62X_DEV_A53SS0_CORE_0_DEV_ID 135
+
 /*
  * This uninitialized global variable would normal end up in the .bss section,
  * but the .bss is cleared between writing and reading this variable, so move
@@ -111,6 +115,62 @@
 	writel(K3RTC_KICK0_UNLOCK_VALUE, REG_K3RTC_KICK0);
 	writel(K3RTC_KICK1_UNLOCK_VALUE, REG_K3RTC_KICK1);
 }
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int get_a53_cpu_clock_index(ofnode node)
+{
+	int count, i;
+	struct ofnode_phandle_args *args;
+	ofnode clknode;
+
+	clknode = ofnode_path("/bus@f0000/system-controller@44043000/clock-controller");
+	if (!ofnode_valid(clknode))
+		return -1;
+
+	count = ofnode_count_phandle_with_args(node,  "assigned-clocks", "#clock-cells", 0);
+
+	for (i  = 0; i < count; i++) {
+		if (!ofnode_parse_phandle_with_args(node, "assigned-clocks",
+						    "#clock-cells", 0, i, args)) {
+			if (ofnode_equal(clknode, args->node) &&
+			    args->args[0] == AM62X_DEV_A53SS0_CORE_0_DEV_ID)
+				return i;
+		}
+	}
+
+	return -1;
+}
+
+static void fixup_a53_cpu_freq_by_speed_grade(void)
+{
+	int index, size;
+	u32 *rates;
+	ofnode node;
+
+	node =  ofnode_path("/a53@0");
+	if (!ofnode_valid(node))
+		return;
+
+	rates = fdt_getprop_w(ofnode_to_fdt(node), ofnode_to_offset(node),
+			      "assigned-clock-rates", &size);
+
+	index = get_a53_cpu_clock_index(node);
+
+	if (!rates || index < 0 || index >= (size / sizeof(u32))) {
+		printf("Wrong A53 assigned-clocks configuration\n");
+		return;
+	}
+
+	rates[index] = cpu_to_fdt32(k3_get_a53_max_frequency());
+
+	printf("Changed A53 CPU frequency to %dHz (%c grade) in DT\n",
+	       k3_get_a53_max_frequency(), k3_get_speed_grade());
+}
+#else
+static void fixup_a53_cpu_freq_by_speed_grade(void)
+{
+}
+#endif
 
 void board_init_f(ulong dummy)
 {
@@ -176,6 +236,14 @@
 	}
 
 	/*
+	 * Relocate boot information to OCRAM (after TIFS has opend this
+	 * region for us) so the next bootloader stages can keep access to
+	 * primary vs backup bootmodes.
+	 */
+	if (IS_ENABLED(CONFIG_CPU_V7R))
+		writel(bootindex, K3_BOOT_PARAM_TABLE_INDEX_OCRAM);
+
+	/*
 	 * Force probe of clk_k3 driver here to ensure basic default clock
 	 * configuration is always done.
 	 */
@@ -210,6 +278,8 @@
 			panic("DRAM init failed: %d\n", ret);
 	}
 	spl_enable_cache();
+
+	fixup_a53_cpu_freq_by_speed_grade();
 }
 
 u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device)
@@ -235,100 +305,7 @@
 	}
 }
 
-static u32 __get_backup_bootmedia(u32 devstat)
-{
-	u32 bkup_bootmode = (devstat & MAIN_DEVSTAT_BACKUP_BOOTMODE_MASK) >>
-				MAIN_DEVSTAT_BACKUP_BOOTMODE_SHIFT;
-	u32 bkup_bootmode_cfg =
-			(devstat & MAIN_DEVSTAT_BACKUP_BOOTMODE_CFG_MASK) >>
-				MAIN_DEVSTAT_BACKUP_BOOTMODE_CFG_SHIFT;
-
-	switch (bkup_bootmode) {
-	case BACKUP_BOOT_DEVICE_UART:
-		return BOOT_DEVICE_UART;
-
-	case BACKUP_BOOT_DEVICE_USB:
-		return BOOT_DEVICE_USB;
-
-	case BACKUP_BOOT_DEVICE_ETHERNET:
-		return BOOT_DEVICE_ETHERNET;
-
-	case BACKUP_BOOT_DEVICE_MMC:
-		if (bkup_bootmode_cfg)
-			return BOOT_DEVICE_MMC2;
-		return BOOT_DEVICE_MMC1;
-
-	case BACKUP_BOOT_DEVICE_SPI:
-		return BOOT_DEVICE_SPI;
-
-	case BACKUP_BOOT_DEVICE_I2C:
-		return BOOT_DEVICE_I2C;
-
-	case BACKUP_BOOT_DEVICE_DFU:
-		if (bkup_bootmode_cfg & MAIN_DEVSTAT_BACKUP_USB_MODE_MASK)
-			return BOOT_DEVICE_USB;
-		return BOOT_DEVICE_DFU;
-	};
-
-	return BOOT_DEVICE_RAM;
-}
-
-static u32 __get_primary_bootmedia(u32 devstat)
-{
-	u32 bootmode = (devstat & MAIN_DEVSTAT_PRIMARY_BOOTMODE_MASK) >>
-				MAIN_DEVSTAT_PRIMARY_BOOTMODE_SHIFT;
-	u32 bootmode_cfg = (devstat & MAIN_DEVSTAT_PRIMARY_BOOTMODE_CFG_MASK) >>
-				MAIN_DEVSTAT_PRIMARY_BOOTMODE_CFG_SHIFT;
-
-	switch (bootmode) {
-	case BOOT_DEVICE_OSPI:
-		fallthrough;
-	case BOOT_DEVICE_QSPI:
-		fallthrough;
-	case BOOT_DEVICE_XSPI:
-		fallthrough;
-	case BOOT_DEVICE_SPI:
-		return BOOT_DEVICE_SPI;
-
-	case BOOT_DEVICE_ETHERNET_RGMII:
-		fallthrough;
-	case BOOT_DEVICE_ETHERNET_RMII:
-		return BOOT_DEVICE_ETHERNET;
-
-	case BOOT_DEVICE_EMMC:
-		return BOOT_DEVICE_MMC1;
-
-	case BOOT_DEVICE_MMC:
-		if ((bootmode_cfg & MAIN_DEVSTAT_PRIMARY_MMC_PORT_MASK) >>
-				MAIN_DEVSTAT_PRIMARY_MMC_PORT_SHIFT)
-			return BOOT_DEVICE_MMC2;
-		return BOOT_DEVICE_MMC1;
-
-	case BOOT_DEVICE_DFU:
-		if ((bootmode_cfg & MAIN_DEVSTAT_PRIMARY_USB_MODE_MASK) >>
-		    MAIN_DEVSTAT_PRIMARY_USB_MODE_SHIFT)
-			return BOOT_DEVICE_USB;
-		return BOOT_DEVICE_DFU;
-
-	case BOOT_DEVICE_NOBOOT:
-		return BOOT_DEVICE_RAM;
-	}
-
-	return bootmode;
-}
-
 u32 spl_boot_device(void)
 {
-	u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT);
-	u32 bootmedia;
-
-	if (bootindex == K3_PRIMARY_BOOTMODE)
-		bootmedia = __get_primary_bootmedia(devstat);
-	else
-		bootmedia = __get_backup_bootmedia(devstat);
-
-	debug("am625_init: %s: devstat = 0x%x bootmedia = 0x%x bootindex = %d\n",
-	      __func__, devstat, bootmedia, bootindex);
-
-	return bootmedia;
+	return get_boot_device();
 }
diff --git a/arch/arm/mach-k3/am62x/Kconfig b/arch/arm/mach-k3/am62x/Kconfig
index 7c9bac2..9786751 100644
--- a/arch/arm/mach-k3/am62x/Kconfig
+++ b/arch/arm/mach-k3/am62x/Kconfig
@@ -48,6 +48,7 @@
 	select ARM64
 	select BINMAN
 	select OF_SYSTEM_SETUP
+	imply OF_UPSTREAM
 
 config TARGET_VERDIN_AM62_R5
 	bool "Toradex Verdin AM62 running on R5"
diff --git a/arch/arm/mach-k3/am62x/Makefile b/arch/arm/mach-k3/am62x/Makefile
new file mode 100644
index 0000000..acf09c3
--- /dev/null
+++ b/arch/arm/mach-k3/am62x/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier:	GPL-2.0+
+obj-y += boot.o
diff --git a/arch/arm/mach-k3/am62x/boot.c b/arch/arm/mach-k3/am62x/boot.c
new file mode 100644
index 0000000..132b42f
--- /dev/null
+++ b/arch/arm/mach-k3/am62x/boot.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/am62_spl.h>
+
+static u32 __get_backup_bootmedia(u32 devstat)
+{
+	u32 bkup_bootmode = (devstat & MAIN_DEVSTAT_BACKUP_BOOTMODE_MASK) >>
+				MAIN_DEVSTAT_BACKUP_BOOTMODE_SHIFT;
+	u32 bkup_bootmode_cfg =
+			(devstat & MAIN_DEVSTAT_BACKUP_BOOTMODE_CFG_MASK) >>
+				MAIN_DEVSTAT_BACKUP_BOOTMODE_CFG_SHIFT;
+
+	switch (bkup_bootmode) {
+	case BACKUP_BOOT_DEVICE_UART:
+		return BOOT_DEVICE_UART;
+
+	case BACKUP_BOOT_DEVICE_USB:
+		return BOOT_DEVICE_USB;
+
+	case BACKUP_BOOT_DEVICE_ETHERNET:
+		return BOOT_DEVICE_ETHERNET;
+
+	case BACKUP_BOOT_DEVICE_MMC:
+		if (bkup_bootmode_cfg)
+			return BOOT_DEVICE_MMC2;
+		return BOOT_DEVICE_MMC1;
+
+	case BACKUP_BOOT_DEVICE_SPI:
+		return BOOT_DEVICE_SPI;
+
+	case BACKUP_BOOT_DEVICE_I2C:
+		return BOOT_DEVICE_I2C;
+
+	case BACKUP_BOOT_DEVICE_DFU:
+		if (bkup_bootmode_cfg & MAIN_DEVSTAT_BACKUP_USB_MODE_MASK)
+			return BOOT_DEVICE_USB;
+		return BOOT_DEVICE_DFU;
+	};
+
+	return BOOT_DEVICE_RAM;
+}
+
+static u32 __get_primary_bootmedia(u32 devstat)
+{
+	u32 bootmode = (devstat & MAIN_DEVSTAT_PRIMARY_BOOTMODE_MASK) >>
+				MAIN_DEVSTAT_PRIMARY_BOOTMODE_SHIFT;
+	u32 bootmode_cfg = (devstat & MAIN_DEVSTAT_PRIMARY_BOOTMODE_CFG_MASK) >>
+				MAIN_DEVSTAT_PRIMARY_BOOTMODE_CFG_SHIFT;
+
+	switch (bootmode) {
+	case BOOT_DEVICE_OSPI:
+		fallthrough;
+	case BOOT_DEVICE_QSPI:
+		fallthrough;
+	case BOOT_DEVICE_XSPI:
+		fallthrough;
+	case BOOT_DEVICE_SPI:
+		return BOOT_DEVICE_SPI;
+
+	case BOOT_DEVICE_ETHERNET_RGMII:
+		fallthrough;
+	case BOOT_DEVICE_ETHERNET_RMII:
+		return BOOT_DEVICE_ETHERNET;
+
+	case BOOT_DEVICE_EMMC:
+		return BOOT_DEVICE_MMC1;
+
+	case BOOT_DEVICE_MMC:
+		if ((bootmode_cfg & MAIN_DEVSTAT_PRIMARY_MMC_PORT_MASK) >>
+				MAIN_DEVSTAT_PRIMARY_MMC_PORT_SHIFT)
+			return BOOT_DEVICE_MMC2;
+		return BOOT_DEVICE_MMC1;
+
+	case BOOT_DEVICE_DFU:
+		if ((bootmode_cfg & MAIN_DEVSTAT_PRIMARY_USB_MODE_MASK) >>
+		    MAIN_DEVSTAT_PRIMARY_USB_MODE_SHIFT)
+			return BOOT_DEVICE_USB;
+		return BOOT_DEVICE_DFU;
+
+	case BOOT_DEVICE_NOBOOT:
+		return BOOT_DEVICE_RAM;
+	}
+
+	return bootmode;
+}
+
+u32 get_boot_device(void)
+{
+	u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT);
+	u32 bootmode = *(u32 *)(K3_BOOT_PARAM_TABLE_INDEX_OCRAM);
+	u32 bootmedia;
+
+	if (bootmode == K3_PRIMARY_BOOTMODE)
+		bootmedia = __get_primary_bootmedia(devstat);
+	else
+		bootmedia = __get_backup_bootmedia(devstat);
+
+	debug("%s: devstat = 0x%x bootmedia = 0x%x bootmode = %d\n",
+	      __func__, devstat, bootmedia, bootmode);
+
+	return bootmedia;
+}
diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index b0fb87b..1a269d6 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -24,6 +24,7 @@
 #include <asm/io.h>
 #include <fs_loader.h>
 #include <fs.h>
+#include <efi_loader.h>
 #include <env.h>
 #include <elf.h>
 #include <soc.h>
@@ -270,6 +271,17 @@
 			printf("Failed to probe am65_cpsw_nuss driver\n");
 	}
 
+	if (IS_ENABLED(CONFIG_TI_ICSSG_PRUETH)) {
+		struct udevice *dev;
+		int ret;
+
+		ret = uclass_get_device_by_driver(UCLASS_MISC,
+						  DM_DRIVER_GET(prueth),
+						  &dev);
+		if (ret)
+			printf("Failed to probe prueth driver\n");
+	}
+
 	/* Default FIT boot on HS-SE devices */
 	if (get_device_type() == K3_DEVICE_TYPE_HS_SE)
 		env_set("boot_fit", "1");
@@ -296,3 +308,14 @@
 		writel(qos_data[i].val, (uintptr_t)qos_data[i].reg);
 }
 #endif
+
+void efi_add_known_memory(void)
+{
+	if (IS_ENABLED(CONFIG_EFI_LOADER))
+		/*
+		 * Memory over ram_top can be used by various firmware
+		 * Declare to EFI only memory area below ram_top
+		 */
+		efi_add_memory_map(gd->ram_base, gd->ram_top - gd->ram_base,
+				   EFI_CONVENTIONAL_MEMORY);
+}
diff --git a/arch/arm/mach-k3/include/mach/am62_hardware.h b/arch/arm/mach-k3/include/mach/am62_hardware.h
index 264f8a4..bcbc482 100644
--- a/arch/arm/mach-k3/include/mach/am62_hardware.h
+++ b/arch/arm/mach-k3/include/mach/am62_hardware.h
@@ -83,6 +83,7 @@
 #define CTRLMMR_DBOUNCE_CFG(index)		(MCU_CTRL_MMR0_BASE + 0x4080 + (index * 4))
 
 #define ROM_EXTENDED_BOOT_DATA_INFO		0x43c3f1e0
+#define K3_BOOT_PARAM_TABLE_INDEX_OCRAM		0x7000F290
 
 #define TI_SRAM_SCRATCH_BOARD_EEPROM_START	0x43c30000
 
@@ -122,6 +123,21 @@
 	}
 }
 
+static inline int k3_get_a53_max_frequency(void)
+{
+	switch (k3_get_speed_grade()) {
+	case 'K':
+		return 800000000;
+	case 'S':
+		return 1000000000;
+	case 'T':
+		return 1250000000;
+	case 'G':
+	default:
+		return 300000000;
+	}
+}
+
 static inline int k3_has_pru(void)
 {
 	u32 full_devid = readl(CTRLMMR_WKUP_JTAG_DEVICE_ID);
diff --git a/arch/arm/mach-k3/include/mach/hardware.h b/arch/arm/mach-k3/include/mach/hardware.h
index af982e7..c724450 100644
--- a/arch/arm/mach-k3/include/mach/hardware.h
+++ b/arch/arm/mach-k3/include/mach/hardware.h
@@ -107,4 +107,5 @@
 	u32 num_components;
 };
 
+u32 get_boot_device(void);
 #endif /* _ASM_ARCH_HARDWARE_H_ */
diff --git a/arch/arm/mach-k3/r5/common.c b/arch/arm/mach-k3/r5/common.c
index c02f8d3..0f6c294 100644
--- a/arch/arm/mach-k3/r5/common.c
+++ b/arch/arm/mach-k3/r5/common.c
@@ -24,6 +24,9 @@
 	IMAGE_ID_OPTEE,
 	IMAGE_ID_SPL,
 	IMAGE_ID_DM_FW,
+	IMAGE_ID_TIFSSTUB_HS,
+	IMAGE_ID_TIFSSTUB_FS,
+	IMAGE_ID_T,
 	IMAGE_AMT,
 };
 
@@ -33,6 +36,9 @@
 	"tee",
 	"U-Boot",
 	"DM",
+	"tifsstub-hs",
+	"tifsstub-fs",
+	"tifsstub-gp",
 };
 #endif
 
@@ -314,6 +320,24 @@
 			break;
 		}
 	}
+
+	if (i < IMAGE_AMT && i > IMAGE_ID_DM_FW) {
+		int device_type = get_device_type();
+
+		if ((device_type == K3_DEVICE_TYPE_HS_SE &&
+		     strcmp(os, "tifsstub-hs")) ||
+		   (device_type == K3_DEVICE_TYPE_HS_FS &&
+		     strcmp(os, "tifsstub-fs")) ||
+		   (device_type == K3_DEVICE_TYPE_GP &&
+		     strcmp(os, "tifsstub-gp"))) {
+			*p_size = 0;
+		} else {
+			debug("tifsstub-type: %s\n", os);
+		}
+
+		return;
+	}
+
 	/*
 	 * Only DM and the DTBs are being authenticated here,
 	 * rest will be authenticated when A72 cluster is up
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index 1008232..6b6a162 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -90,6 +90,14 @@
 	imply FPGA_SOCFPGA
 	imply SPL_USE_TINY_PRINTF
 
+config SOCFPGA_ARRIA10_ALWAYS_REPROGRAM
+	bool "Always reprogram Arria 10 FPGA"
+	depends on TARGET_SOCFPGA_ARRIA10
+	help
+	  Arria 10 FPGA is only programmed during the cold boot.
+	  This option forces the FPGA to be reprogrammed every reboot,
+	  allowing to change the bitstream and apply it with warm reboot.
+
 config TARGET_SOCFPGA_CYCLONE5
 	bool
 	select TARGET_SOCFPGA_GEN5
diff --git a/arch/arm/mach-socfpga/spl_a10.c b/arch/arm/mach-socfpga/spl_a10.c
index 9edbbf4..3981d2d 100644
--- a/arch/arm/mach-socfpga/spl_a10.c
+++ b/arch/arm/mach-socfpga/spl_a10.c
@@ -122,7 +122,10 @@
 	arch_early_init_r();
 
 	/* If the full FPGA is already loaded, ie.from EPCQ, config fpga pins */
-	if (is_fpgamgr_user_mode()) {
+	if ((IS_ENABLED(CONFIG_SOCFPGA_ARRIA10_ALWAYS_REPROGRAM) &&
+	     is_regular_boot_valid()) ||
+	    (!IS_ENABLED(CONFIG_SOCFPGA_ARRIA10_ALWAYS_REPROGRAM) &&
+	     is_fpgamgr_user_mode())) {
 		ret = config_pins(gd->fdt_blob, "shared");
 		if (ret)
 			return;
@@ -130,7 +133,8 @@
 		ret = config_pins(gd->fdt_blob, "fpga");
 		if (ret)
 			return;
-	} else if (!is_fpgamgr_early_user_mode()) {
+	} else if (IS_ENABLED(CONFIG_SOCFPGA_ARRIA10_ALWAYS_REPROGRAM) ||
+		   !is_fpgamgr_early_user_mode()) {
 		/* Program IOSSM(early IO release) or full FPGA */
 		fpgamgr_program(buf, FPGA_BUFSIZ, 0);
 
diff --git a/arch/arm/mach-uniphier/dram_init.c b/arch/arm/mach-uniphier/dram_init.c
index 7f27531..e6f1286 100644
--- a/arch/arm/mach-uniphier/dram_init.c
+++ b/arch/arm/mach-uniphier/dram_init.c
@@ -265,14 +265,15 @@
 	if (uniphier_get_soc_id() == UNIPHIER_LD20_ID)
 		gd->ram_size -= 64;
 
+	/* map all the DRAM regions */
+	uniphier_mem_map_init(gd->ram_base, prev_top - gd->ram_base);
+
 	return 0;
 }
 
 int dram_init_banksize(void)
 {
 	struct uniphier_dram_map dram_map[3] = {};
-	unsigned long base, top;
-	bool valid_bank_found = false;
 	int ret, i;
 
 	ret = uniphier_dram_map_get(dram_map);
@@ -287,18 +288,7 @@
 
 		if (!dram_map[i].size)
 			continue;
-
-		if (!valid_bank_found)
-			base = dram_map[i].base;
-		top = dram_map[i].base + dram_map[i].size;
-		valid_bank_found = true;
 	}
 
-	if (!valid_bank_found)
-		return -EINVAL;
-
-	/* map all the DRAM regions */
-	uniphier_mem_map_init(base, top - base);
-
 	return 0;
 }
diff --git a/arch/arm/mach-zynqmp/Kconfig b/arch/arm/mach-zynqmp/Kconfig
index 6a7be0b..0d2238a 100644
--- a/arch/arm/mach-zynqmp/Kconfig
+++ b/arch/arm/mach-zynqmp/Kconfig
@@ -1,29 +1,5 @@
 if ARCH_ZYNQMP
 
-config SPL_FS_FAT
-	default y
-
-config SPL_LIBCOMMON_SUPPORT
-	default y
-
-config SPL_LIBDISK_SUPPORT
-	default y
-
-config SPL_LIBGENERIC_SUPPORT
-	default y
-
-config SPL_MMC
-	default y if MMC_SDHCI_ZYNQ
-
-config SPL_SERIAL
-	default y
-
-config SPL_SPI_FLASH_SUPPORT
-	default y if ZYNQ_QSPI
-
-config SPL_SPI
-	default y if ZYNQ_QSPI
-
 config SYS_BOARD
 	string "Board name"
 	default "zynqmp"
@@ -135,7 +111,8 @@
 
 config SPL_ZYNQMP_PSU_INIT_ENABLED
 	bool "Include psu_init in SPL"
-	default y if SPL
+	depends on SPL
+	default y
 	select BOARD_EARLY_INIT_F
 	help
 	  Include psu_init by default in SPL.
diff --git a/arch/arm/mach-zynqmp/spl.c b/arch/arm/mach-zynqmp/spl.c
index a0f35f3..979ff3a 100644
--- a/arch/arm/mach-zynqmp/spl.c
+++ b/arch/arm/mach-zynqmp/spl.c
@@ -9,6 +9,7 @@
 #include <image.h>
 #include <init.h>
 #include <log.h>
+#include <semihosting.h>
 #include <spl.h>
 #include <linux/delay.h>
 
@@ -66,6 +67,11 @@
 }
 #endif
 
+static u32 jtag_boot_device(void)
+{
+	return semihosting_enabled() ? BOOT_DEVICE_SMH : BOOT_DEVICE_RAM;
+}
+
 void board_boot_order(u32 *spl_boot_list)
 {
 	spl_boot_list[0] = spl_boot_device();
@@ -75,7 +81,7 @@
 	if (spl_boot_list[0] == BOOT_DEVICE_MMC2)
 		spl_boot_list[1] = BOOT_DEVICE_MMC1;
 
-	spl_boot_list[2] = BOOT_DEVICE_RAM;
+	spl_boot_list[2] = jtag_boot_device();
 }
 
 u32 spl_boot_device(void)
@@ -85,19 +91,20 @@
 
 #if defined(CONFIG_SPL_ZYNQMP_ALT_BOOTMODE_ENABLED)
 	/* Change default boot mode at run-time */
+	reg = CONFIG_SPL_ZYNQMP_ALT_BOOTMODE;
 	writel(CONFIG_SPL_ZYNQMP_ALT_BOOTMODE << BOOT_MODE_ALT_SHIFT,
 	       &crlapb_base->boot_mode);
-#endif
-
+#else
 	reg = readl(&crlapb_base->boot_mode);
 	if (reg >> BOOT_MODE_ALT_SHIFT)
 		reg >>= BOOT_MODE_ALT_SHIFT;
+#endif
 
 	bootmode = reg & BOOT_MODES_MASK;
 
 	switch (bootmode) {
 	case JTAG_MODE:
-		return BOOT_DEVICE_RAM;
+		return jtag_boot_device();
 #ifdef CONFIG_SPL_MMC
 	case SD_MODE1:
 	case SD1_LSHFT_MODE: /* not working on silicon v1 */
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile
index 6e1fd93..5ccd954 100644
--- a/arch/m68k/lib/Makefile
+++ b/arch/m68k/lib/Makefile
@@ -8,7 +8,7 @@
 lib-$(CONFIG_USE_PRIVATE_LIBGCC) += lshrdi3.o muldi3.o ashldi3.o ashrdi3.o
 
 obj-y	+= bdinfo.o
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-y	+= cache.o
 obj-y	+= interrupts.o
 obj-y	+= time.o
diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile
index dfd8135..2f23482 100644
--- a/arch/microblaze/lib/Makefile
+++ b/arch/microblaze/lib/Makefile
@@ -3,6 +3,6 @@
 # (C) Copyright 2003-2006
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-$(CONFIG_CMD_BDI) += bdinfo.o
 obj-y	+= muldi3.o
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 1621cc9..4386eb4 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -10,7 +10,7 @@
 obj-y	+= stack.o
 obj-y	+= traps.o
 
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-$(CONFIG_CMD_GO) += boot.o
 obj-$(CONFIG_SPL_BUILD) += spl.o
 
diff --git a/arch/nios2/lib/Makefile b/arch/nios2/lib/Makefile
index a9f3c71..68a5ca0 100644
--- a/arch/nios2/lib/Makefile
+++ b/arch/nios2/lib/Makefile
@@ -4,5 +4,5 @@
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
 obj-y	+= cache.o
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-y	+= libgcc.o
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index bb819dc..dcce983 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -34,7 +34,7 @@
 endif
 obj-y	+= reloc.o
 
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-y	+= cache.o
 obj-y	+= extable.o
 obj-y	+= interrupts.o
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 6c26f91f..7e20ef6 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -22,6 +22,7 @@
 
 config TARGET_QEMU_VIRT
 	bool "Support QEMU Virt Board"
+	select BOARD_LATE_INIT
 
 config TARGET_SIFIVE_UNLEASHED
 	bool "Support SiFive Unleashed Board"
@@ -93,6 +94,7 @@
 
 # platform-specific options below
 source "arch/riscv/cpu/andesv5/Kconfig"
+source "arch/riscv/cpu/cv1800b/Kconfig"
 source "arch/riscv/cpu/fu540/Kconfig"
 source "arch/riscv/cpu/fu740/Kconfig"
 source "arch/riscv/cpu/generic/Kconfig"
@@ -119,6 +121,26 @@
 
 endchoice
 
+config FRAMEPOINTER
+	bool "Build with frame pointer for stack unwinding"
+	help
+	  Choose this option to use the frame pointer so the stack can be
+	  unwound if needed. This is useful for tracing where faults came
+	  from as the source may be several functions back
+
+	  If you say Y here, then the code size will be increased due to
+	  having to store the fp.
+
+config SPL_FRAMEPOINTER
+	bool "Build SPL with frame pointer for stack unwinding"
+	help
+	  Choose this option to use the frame pointer so the stack can be
+	  unwound if needed. This is useful for tracing where faults came
+	  from as the source may be several functions back
+
+	  If you say Y here, then the code size will be increased due to
+	  having to store the fp.
+
 choice
 	prompt "Code Model"
 	default CMODEL_MEDLOW
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index b3ef870..c36a853 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -48,6 +48,10 @@
 ARCH_FLAGS = -march=$(RISCV_MARCH) -mabi=$(ABI) \
 	     -mcmodel=$(CMODEL)
 
+ifeq ($(CONFIG_$(SPL_)FRAMEPOINTER),y)
+	ARCH_FLAGS += -fno-omit-frame-pointer
+endif
+
 PLATFORM_CPPFLAGS	+= $(ARCH_FLAGS)
 CFLAGS_EFI		+= $(ARCH_FLAGS)
 
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index ecfefa1..affe700 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -38,35 +38,51 @@
 #if CONFIG_IS_ENABLED(RISCV_MMODE)
 	return csr_read(CSR_MISA) & (1 << (ext - 'a'));
 #elif CONFIG_CPU
+	char sext[2] = {ext};
 	struct udevice *dev;
-	char desc[32];
-	int i;
+	const char *isa;
+	int ret, i;
 
 	uclass_find_first_device(UCLASS_CPU, &dev);
 	if (!dev) {
 		debug("unable to find the RISC-V cpu device\n");
 		return false;
 	}
-	if (!cpu_get_desc(dev, desc, sizeof(desc))) {
-		/*
-		 * skip the first 4 characters (rv32|rv64)
-		 */
-		for (i = 4; i < sizeof(desc); i++) {
-			switch (desc[i]) {
-			case 's':
-			case 'x':
-			case 'z':
-			case '_':
-			case '\0':
-				/*
-				 * Any of these characters mean the single
-				 * letter extensions have all been consumed.
-				 */
-				return false;
-			default:
-				if (desc[i] == ext)
-					return true;
-			}
+
+	ret = dev_read_stringlist_search(dev, "riscv,isa-extensions", sext);
+	if (ret >= 0)
+		return true;
+
+	/*
+	 * Only if the property is not found (ENODATA) is the fallback to
+	 * riscv,isa used, otherwise the extension is not present in this
+	 * CPU.
+	 */
+	if (ret != -ENODATA)
+		return false;
+
+	isa = dev_read_string(dev, "riscv,isa");
+	if (!isa)
+		return false;
+
+	/*
+	 * Skip the first 4 characters (rv32|rv64).
+	 */
+	for (i = 4; i < sizeof(isa); i++) {
+		switch (isa[i]) {
+		case 's':
+		case 'x':
+		case 'z':
+		case '_':
+		case '\0':
+			/*
+			 * Any of these characters mean the single
+			 * letter extensions have all been consumed.
+			 */
+			return false;
+		default:
+			if (isa[i] == ext)
+				return true;
 		}
 	}
 
diff --git a/arch/riscv/cpu/cv1800b/Kconfig b/arch/riscv/cpu/cv1800b/Kconfig
new file mode 100644
index 0000000..7225b12
--- /dev/null
+++ b/arch/riscv/cpu/cv1800b/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+
+config SOPHGO_CV1800B
+	bool
+	select ARCH_EARLY_INIT_R
+	select SYS_CACHE_SHIFT_6
+	imply CPU
+	imply CPU_RISCV
+	imply RISCV_TIMER
+	imply CMD_CPU
diff --git a/arch/riscv/cpu/cv1800b/Makefile b/arch/riscv/cpu/cv1800b/Makefile
new file mode 100644
index 0000000..95beb34
--- /dev/null
+++ b/arch/riscv/cpu/cv1800b/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+
+obj-y += dram.o
+obj-y += cpu.o
+obj-y += cache.o
diff --git a/arch/riscv/cpu/cv1800b/cache.c b/arch/riscv/cpu/cv1800b/cache.c
new file mode 100644
index 0000000..b8051e2
--- /dev/null
+++ b/arch/riscv/cpu/cv1800b/cache.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#include <cpu_func.h>
+
+/*
+ * dcache.ipa rs1 (invalidate)
+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
+ *   0000001    01010      rs1       000      00000  0001011
+ *
+ * dcache.cpa rs1 (clean)
+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
+ *   0000001    01001      rs1       000      00000  0001011
+ *
+ * dcache.cipa rs1 (clean then invalidate)
+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
+ *   0000001    01011      rs1       000      00000  0001011
+ *
+ * sync.s
+ * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 |
+ *   0000000    11001     00000      000      00000  0001011
+ */
+#define DCACHE_IPA_A0	".long 0x02a5000b"
+#define DCACHE_CPA_A0	".long 0x0295000b"
+#define DCACHE_CIPA_A0	".long 0x02b5000b"
+
+#define SYNC_S		".long 0x0190000b"
+
+void invalidate_dcache_range(unsigned long start, unsigned long end)
+{
+	register unsigned long i asm("a0") = start & ~(CONFIG_SYS_CACHELINE_SIZE - 1);
+	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
+		__asm__ __volatile__(DCACHE_IPA_A0);
+	__asm__ __volatile__(SYNC_S);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long end)
+{
+	register unsigned long i asm("a0") = start & ~(CONFIG_SYS_CACHELINE_SIZE - 1);
+	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
+		__asm__ __volatile__(DCACHE_CPA_A0);
+	__asm__ __volatile__(SYNC_S);
+}
diff --git a/arch/riscv/cpu/cv1800b/cpu.c b/arch/riscv/cpu/cv1800b/cpu.c
new file mode 100644
index 0000000..233a6a3
--- /dev/null
+++ b/arch/riscv/cpu/cv1800b/cpu.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+int cleanup_before_linux(void)
+{
+	return 0;
+}
diff --git a/arch/riscv/cpu/cv1800b/dram.c b/arch/riscv/cpu/cv1800b/dram.c
new file mode 100644
index 0000000..91007c0
--- /dev/null
+++ b/arch/riscv/cpu/cv1800b/dram.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <fdtdec.h>
+#include <init.h>
+#include <asm/global_data.h>
+#include <linux/sizes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+	return fdtdec_setup_mem_size_base();
+}
+
+int dram_init_banksize(void)
+{
+	return fdtdec_setup_memory_banksize();
+}
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 6cecadf..a9e1935 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -418,6 +418,7 @@
  */
 	mv	a0, s3			/* gd_t */
 	mv	a1, s4			/* dest_addr */
+	mv	s0, zero		/* fp == NULL */
 
 /*
  * jump to it ...
diff --git a/arch/riscv/dts/cv1800b-milkv-duo.dts b/arch/riscv/dts/cv1800b-milkv-duo.dts
index 3af9e34..94e64dd 100644
--- a/arch/riscv/dts/cv1800b-milkv-duo.dts
+++ b/arch/riscv/dts/cv1800b-milkv-duo.dts
@@ -33,6 +33,14 @@
 	clock-frequency = <25000000>;
 };
 
+&sdhci0 {
+	status = "okay";
+	bus-width = <4>;
+	no-1-8-v;
+	no-mmc;
+	no-sdio;
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/riscv/dts/cv1800b.dtsi b/arch/riscv/dts/cv1800b.dtsi
index 165e9e3..baf6418 100644
--- a/arch/riscv/dts/cv1800b.dtsi
+++ b/arch/riscv/dts/cv1800b.dtsi
@@ -16,3 +16,7 @@
 &clint {
 	compatible = "sophgo,cv1800b-clint", "thead,c900-clint";
 };
+
+&clk {
+	compatible = "sophgo,cv1800-clk";
+};
diff --git a/arch/riscv/dts/cv18xx.dtsi b/arch/riscv/dts/cv18xx.dtsi
index 2d6f4a4..ec99c4d 100644
--- a/arch/riscv/dts/cv18xx.dtsi
+++ b/arch/riscv/dts/cv18xx.dtsi
@@ -45,6 +45,13 @@
 		#clock-cells = <0>;
 	};
 
+	sdhci_clk: sdhci-clock {
+		compatible = "fixed-clock";
+		clock-frequency = <375000000>;
+		clock-output-names = "sdhci_clk";
+		#clock-cells = <0>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		interrupt-parent = <&plic>;
@@ -53,6 +60,12 @@
 		dma-noncoherent;
 		ranges;
 
+		clk: clock-controller@3002000 {
+			reg = <0x03002000 0x1000>;
+			clocks = <&osc>;
+			#clock-cells = <1>;
+		};
+
 		gpio0: gpio@3020000 {
 			compatible = "snps,dw-apb-gpio";
 			reg = <0x3020000 0x1000>;
@@ -175,6 +188,15 @@
 			status = "disabled";
 		};
 
+		sdhci0: mmc@4310000 {
+			compatible = "sophgo,cv1800b-dwcmshc";
+			reg = <0x4310000 0x1000>;
+			interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&sdhci_clk>;
+			clock-names = "core";
+			status = "disabled";
+		};
+
 		plic: interrupt-controller@70000000 {
 			reg = <0x70000000 0x4000000>;
 			interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>;
diff --git a/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi
index f2c6bec..e11babc 100644
--- a/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi
+++ b/arch/riscv/dts/jh7110-starfive-visionfive-2.dtsi
@@ -298,7 +298,7 @@
 	pinctrl-0 = <&mmc1_pins>;
 	no-sdio;
 	no-mmc;
-	broken-cd;
+	cd-gpios = <&sysgpio 41 GPIO_ACTIVE_LOW>;
 	cap-sd-highspeed;
 	post-power-on-delay-ms = <200>;
 	status = "okay";
diff --git a/arch/riscv/dts/xilinx-mbv32.dts b/arch/riscv/dts/xilinx-mbv32.dts
index 94e42c2..48ee115 100644
--- a/arch/riscv/dts/xilinx-mbv32.dts
+++ b/arch/riscv/dts/xilinx-mbv32.dts
@@ -8,6 +8,9 @@
  */
 
 /dts-v1/;
+
+#include "binman.dtsi"
+
 / {
 	#address-cells = <1>;
 	#size-cells = <1>;
diff --git a/arch/riscv/include/asm/arch-jh7110/eeprom.h b/arch/riscv/include/asm/arch-jh7110/eeprom.h
index d2776d5..62d184a 100644
--- a/arch/riscv/include/asm/arch-jh7110/eeprom.h
+++ b/arch/riscv/include/asm/arch-jh7110/eeprom.h
@@ -12,4 +12,13 @@
 u8 get_pcb_revision_from_eeprom(void);
 u32 get_ddr_size_from_eeprom(void);
 
+/**
+ * get_product_id_from_eeprom - get product ID string
+ *
+ * A string like "VF7110A1-2228-D008E000-00000001" is returned.
+ *
+ * Return:	product ID string
+ */
+const char *get_product_id_from_eeprom(void);
+
 #endif /* _ASM_RISCV_EEPROM_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 9a05b66..0b2c88d 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -6,7 +6,7 @@
 # Copyright (C) 2017 Andes Technology Corporation
 # Rick Chen, Andes Technology Corporation <rick@andestech.com>
 
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-$(CONFIG_CMD_BOOTI) += bootm.o image.o
 obj-$(CONFIG_CMD_GO) += boot.o
 obj-y	+= cache.o
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index a26ccc7..7350e2c 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -60,6 +60,40 @@
 #endif
 }
 
+#if defined(CONFIG_FRAMEPOINTER) || defined(CONFIG_SPL_FRAMEPOINTER)
+static void show_backtrace(struct pt_regs *regs)
+{
+	uintptr_t *fp = (uintptr_t *)regs->s0;
+	unsigned count = 0;
+	ulong ra;
+
+	printf("backtrace:\n");
+
+	/* there are a few entry points where the s0 register is
+	 * set to gd, so to avoid changing those, just abort if
+	 * the value is the same */
+	while (fp != NULL && fp != (uintptr_t *)gd) {
+		ra = fp[-1];
+		printf("backtrace %2d: FP: " REG_FMT " RA: " REG_FMT,
+		       count, (ulong)fp, ra);
+
+		if (gd && gd->flags & GD_FLG_RELOC)
+			printf(" - RA: " REG_FMT " reloc adjusted\n",
+			ra - gd->reloc_off);
+		else
+			printf("\n");
+
+		fp = (uintptr_t *)fp[-2];
+		count++;
+	}
+}
+#else
+static void show_backtrace(struct pt_regs *regs)
+{
+	printf("No backtrace support enabled\n");
+}
+#endif
+
 /**
  * instr_len() - get instruction length
  *
@@ -131,6 +165,7 @@
 		       epc - gd->reloc_off, regs->ra - gd->reloc_off);
 
 	show_regs(regs);
+	show_backtrace(regs);
 	show_code(epc);
 	show_efi_loaded_images(epc);
 	panic("\n");
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 0ce77de..1c8353d 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -58,10 +58,15 @@
 	bool "Reset on crash"
 	help
 	  If an illegal instruction or an illegal memory access occurs, the
-	  sandbox by default writes a crash dump and exits. If you set this
-	  flag, the sandbox is reset instead. This may be useful when running
-	  test suites like the UEFI self certification test which continue
-	  with the next test after a crash.
+	  sandbox exits with an error by default.
+
+	  If the u-boot binary is invoked with --signals (or -S), U-Boot will
+	  handle the signal writing a crash dump before exiting.
+
+	  If you additionally set the CONFIG_SANDBOX_CRASH_RESET flag, the
+	  sandbox is reset after writing the crash dump. This may be useful
+	  when running test suites like the UEFI self certification test which
+	  continue with the next test after a crash.
 
 config SANDBOX_BITS_PER_LONG
 	int
diff --git a/arch/sandbox/cpu/eth-raw-os.c b/arch/sandbox/cpu/eth-raw-os.c
index 92c35ae..39ea3b3 100644
--- a/arch/sandbox/cpu/eth-raw-os.c
+++ b/arch/sandbox/cpu/eth-raw-os.c
@@ -105,7 +105,12 @@
 
 	/* Make the socket non-blocking */
 	flags = fcntl(priv->sd, F_GETFL, 0);
-	fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK);
+	ret = fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK);
+	if (ret == -1) {
+		printf("Failed to make socket non-blocking: %d %s\n", errno,
+		       strerror(errno));
+		return -errno;
+	}
 
 	/* Enable promiscuous mode to receive responses meant for us */
 	mr.mr_ifindex = device->sll_ifindex;
@@ -172,7 +177,12 @@
 
 	/* Make the socket non-blocking */
 	flags = fcntl(priv->sd, F_GETFL, 0);
-	fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK);
+	ret = fcntl(priv->sd, F_SETFL, flags | O_NONBLOCK);
+	if (ret == -1) {
+		printf("Failed to make socket non-blocking: %d %s\n", errno,
+		       strerror(errno));
+		return -errno;
+	}
 
 	/* Include the UDP/IP headers on send and receive */
 	ret = setsockopt(priv->sd, IPPROTO_IP, IP_HDRINCL, &one,
diff --git a/arch/sandbox/lib/Makefile b/arch/sandbox/lib/Makefile
index a2bc5a7..c4924b2 100644
--- a/arch/sandbox/lib/Makefile
+++ b/arch/sandbox/lib/Makefile
@@ -7,5 +7,5 @@
 
 obj-y	+= fdt_fixup.o interrupts.o sections.o
 obj-$(CONFIG_PCI)	+= pci_io.o
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-$(CONFIG_CMD_BOOTZ) += bootm.o
diff --git a/arch/sandbox/lib/bootm.c b/arch/sandbox/lib/bootm.c
index 8dbcd9f..44ba8b5 100644
--- a/arch/sandbox/lib/bootm.c
+++ b/arch/sandbox/lib/bootm.c
@@ -85,5 +85,7 @@
 int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
 		bool force_reloc)
 {
-	return 0;
+	log_err("Booting is not supported on the sandbox.\n");
+
+	return 1;
 }
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index e7520a3..8c3c302 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -6,7 +6,7 @@
 extra-y	+= start.o
 
 obj-y	+= board.o
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 obj-y	+= time.o
 obj-$(CONFIG_CMD_SH_ZIMAGEBOOT) += zimageboot.o
 
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 99e59d9..23a1e21 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -723,6 +723,14 @@
 	hex
 	default 0x10000
 
+config X86_HARDFP
+	bool "Support hardware floating point"
+	help
+	  U-Boot generally does not make use of floating point. Where this is
+	  needed, it can be enabled using this option. This adjusts the
+	  start-up code for 64-bit mode and changes the compiler options for
+	  64-bit to enable SSE.
+
 config HAVE_ITSS
 	bool "Enable ITSS"
 	help
@@ -1053,4 +1061,12 @@
 	  display, memory and build information. It is stored in
 	  struct sysinfo_t after parsing by get_coreboot_info().
 
+config ZBOOT
+	bool "Support the zImage format"
+	default y
+	help
+	  Enable this to support booting the x86-specific zImage format. This
+	  uses a special, binary format containing information about the Linux
+	  format to boot.
+
 endmenu
diff --git a/arch/x86/config.mk b/arch/x86/config.mk
index 26ec1af..2e3a711 100644
--- a/arch/x86/config.mk
+++ b/arch/x86/config.mk
@@ -27,9 +27,13 @@
 PLATFORM_CPPFLAGS += -march=i386 -m32
 else
 PLATFORM_CPPFLAGS += $(if $(CONFIG_SPL_BUILD),,-fpic) -fno-common -march=core2 -m64
+
+ifndef CONFIG_X86_HARDFP
 PLATFORM_CPPFLAGS += -mno-mmx -mno-sse
 endif
 
+endif # IS_32BIT
+
 PLATFORM_RELFLAGS += -fdata-sections -ffunction-sections -fvisibility=hidden
 
 KBUILD_LDFLAGS += -Bsymbolic -Bsymbolic-functions
diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c
index 2647bff..5ea746e 100644
--- a/arch/x86/cpu/x86_64/cpu.c
+++ b/arch/x86/cpu/x86_64/cpu.c
@@ -10,6 +10,7 @@
 #include <init.h>
 #include <asm/cpu.h>
 #include <asm/global_data.h>
+#include <asm/processor-flags.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -39,11 +40,22 @@
 	return 0;
 }
 
+/* enable SSE features for hardware floating point */
+static void setup_sse_features(void)
+{
+	asm ("mov %%cr4, %%rax\n" \
+	"or  %0, %%rax\n" \
+	"mov %%rax, %%cr4\n" \
+	: : "i" (X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT) : "eax");
+}
+
 int x86_cpu_reinit_f(void)
 {
 	/* set the vendor to Intel so that native_calibrate_tsc() works */
 	gd->arch.x86_vendor = X86_VENDOR_INTEL;
 	gd->arch.has_mtrr = true;
+	if (IS_ENABLED(CONFIG_X86_HARDFP))
+		setup_sse_features();
 
 	return 0;
 }
diff --git a/arch/x86/dts/coreboot.dts b/arch/x86/dts/coreboot.dts
index dfce7c2..b867468 100644
--- a/arch/x86/dts/coreboot.dts
+++ b/arch/x86/dts/coreboot.dts
@@ -46,6 +46,16 @@
 		compatible = "coreboot-fb";
 	};
 
+	bootstd {
+		compatible = "u-boot,boot-std";
+
+		theme {
+			font-size = <30>;
+			menu-inset = <3>;
+			menuitem-gap-y = <1>;
+		};
+	};
+
 	sysinfo {
 		compatible = "coreboot,sysinfo";
 	};
diff --git a/arch/x86/include/asm/zimage.h b/arch/x86/include/asm/zimage.h
index 655675b..8b54260 100644
--- a/arch/x86/include/asm/zimage.h
+++ b/arch/x86/include/asm/zimage.h
@@ -30,6 +30,78 @@
 #define BZIMAGE_LOAD_ADDR  0x100000
 #define ZIMAGE_LOAD_ADDR   0x10000
 
+enum {
+	ZBOOT_STATE_START	= BIT(0),
+	ZBOOT_STATE_LOAD	= BIT(1),
+	ZBOOT_STATE_SETUP	= BIT(2),
+	ZBOOT_STATE_INFO	= BIT(3),
+	ZBOOT_STATE_GO		= BIT(4),
+
+	/* This one doesn't execute automatically, so stop the count before 5 */
+	ZBOOT_STATE_DUMP	= BIT(5),
+	ZBOOT_STATE_COUNT	= 5,
+};
+
+/**
+ * struct zboot_state - Current state of the boot
+ *
+ * @bzimage_addr: Address of the bzImage to boot, or 0 if the image has already
+ *	been loaded and does not exist (as a cohesive whole) in memory
+ * @bzimage_size: Size of the bzImage, or 0 to detect this
+ * @initrd_addr: Address of the initial ramdisk, or 0 if none
+ * @initrd_size: Size of the initial ramdisk, or 0 if none
+ * @load_address: Address where the bzImage is moved before booting, either
+ *	BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR
+ *	This is set up when loading the zimage
+ * @base_ptr: Pointer to the boot parameters, typically at address
+ *	DEFAULT_SETUP_BASE
+ *	This is set up when loading the zimage
+ * @cmdline: Environment variable containing the 'override' command line, or
+ *	NULL to use the one in the setup block
+ */
+struct zboot_state {
+	ulong bzimage_addr;
+	ulong bzimage_size;
+	ulong initrd_addr;
+	ulong initrd_size;
+	ulong load_address;
+	struct boot_params *base_ptr;
+	const char *cmdline;
+};
+
+extern struct zboot_state state;
+
+/**
+ * zimage_dump() - Dump information about a zimage
+ *
+ * @base_ptr: Pointer to the boot parameters
+ * @show_cmdline: true to show the kernel command line
+ */
+void zimage_dump(struct boot_params *base_ptr, bool show_cmdline);
+
+/**
+ * zboot_load() - Load a zimage
+ *
+ * Load the zimage into the correct place
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int zboot_load(void);
+
+/**
+ * zboot_setup() - Set up the zboot image reeady for booting
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int zboot_setup(void);
+
+/**
+ * zboot_go() - Start the image
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int zboot_go(void);
+
 /**
  * load_zimage() - Load a zImage or bzImage
  *
@@ -62,4 +134,29 @@
 int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
 		 ulong initrd_addr, ulong initrd_size, ulong cmdline_force);
 
+/**
+ * zboot_start() - Prepare to boot a zimage
+ *
+ * Record information about a zimage so it can be booted
+ *
+ * @bzimage_addr: Address of the bzImage to boot
+ * @bzimage_size: Size of the bzImage, or 0 to detect this
+ * @initrd_addr: Address of the initial ramdisk, or 0 if none
+ * @initrd_size: Size of the initial ramdisk, or 0 if none
+ * @base_addr: If non-zero, this indicates that the boot parameters have already
+ *	been loaded by the caller to this address, so the load_zimage() call
+ *	in zboot_load() will be skipped when booting
+ * @cmdline: Environment variable containing the 'override' command line, or
+ *	NULL to use the one in the setup block
+ */
+void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr,
+		 ulong initrd_size, ulong base_addr, const char *cmdline);
+
+/**
+ * zboot_info() - Show simple info about a zimage
+ *
+ * Shows wherer the kernel was loaded and also the setup base
+ */
+void zboot_info(void);
+
 #endif
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 90a7618..94aa335 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -16,7 +16,7 @@
 endif
 
 ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 endif
 obj-y	+= cmd_boot.o
 obj-$(CONFIG_$(SPL_)COREBOOT_SYSINFO)	+= coreboot/
@@ -48,7 +48,7 @@
 endif
 obj-y	+= tables.o
 ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_CMD_ZBOOT)	+= zimage.o
+obj-$(CONFIG_ZBOOT) += zimage.o
 endif
 obj-$(CONFIG_USE_HOB) += hob.o
 ifndef CONFIG_TPL_BUILD
diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c
index c15f11f..4e4cf18 100644
--- a/arch/x86/lib/spl.c
+++ b/arch/x86/lib/spl.c
@@ -283,7 +283,7 @@
 {
 	int ret;
 
-	printf("Jumping to 64-bit U-Boot: Note many features are missing\n");
+	printf("Jumping to 64-bit U-Boot\n");
 	ret = cpu_jump_to_64bit_uboot(spl_image->entry_point);
 	debug("ret=%d\n", ret);
 	hang();
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index a41e1cc..d740387 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -56,41 +56,8 @@
 
 #define COMMAND_LINE_SIZE	2048
 
-/**
- * struct zboot_state - Current state of the boot
- *
- * @bzimage_addr: Address of the bzImage to boot
- * @bzimage_size: Size of the bzImage, or 0 to detect this
- * @initrd_addr: Address of the initial ramdisk, or 0 if none
- * @initrd_size: Size of the initial ramdisk, or 0 if none
- * @load_address: Address where the bzImage is moved before booting, either
- *	BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR
- * @base_ptr: Pointer to the boot parameters, typically at address
- *	DEFAULT_SETUP_BASE
- * @cmdline: Environment variable containing the 'override' command line, or
- *	NULL to use the one in the setup block
- */
-struct zboot_state {
-	ulong bzimage_addr;
-	ulong bzimage_size;
-	ulong initrd_addr;
-	ulong initrd_size;
-	ulong load_address;
-	struct boot_params *base_ptr;
-	char *cmdline;
-} state;
-
-enum {
-	ZBOOT_STATE_START	= BIT(0),
-	ZBOOT_STATE_LOAD	= BIT(1),
-	ZBOOT_STATE_SETUP	= BIT(2),
-	ZBOOT_STATE_INFO	= BIT(3),
-	ZBOOT_STATE_GO		= BIT(4),
-
-	/* This one doesn't execute automatically, so stop the count before 5 */
-	ZBOOT_STATE_DUMP	= BIT(5),
-	ZBOOT_STATE_COUNT	= 5,
-};
+/* Current state of the boot */
+struct zboot_state state;
 
 static void build_command_line(char *command_line, int auto_boot)
 {
@@ -400,56 +367,10 @@
 	return 0;
 }
 
-static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc,
-			  char *const argv[])
-{
-	const char *s;
-
-	memset(&state, '\0', sizeof(state));
-	if (argc >= 2) {
-		/* argv[1] holds the address of the bzImage */
-		s = argv[1];
-	} else {
-		s = env_get("fileaddr");
-	}
-
-	if (s)
-		state.bzimage_addr = hextoul(s, NULL);
-
-	if (argc >= 3) {
-		/* argv[2] holds the size of the bzImage */
-		state.bzimage_size = hextoul(argv[2], NULL);
-	}
-
-	if (argc >= 4)
-		state.initrd_addr = hextoul(argv[3], NULL);
-	if (argc >= 5)
-		state.initrd_size = hextoul(argv[4], NULL);
-	if (argc >= 6) {
-		/*
-		 * When the base_ptr is passed in, we assume that the image is
-		 * already loaded at the address given by argv[1] and therefore
-		 * the original bzImage is somewhere else, or not accessible.
-		 * In any case, we don't need access to the bzImage since all
-		 * the processing is assumed to be done.
-		 *
-		 * So set the base_ptr to the given address, use this arg as the
-		 * load address and set bzimage_addr to 0 so we know that it
-		 * cannot be proceesed (or processed again).
-		 */
-		state.base_ptr = (void *)hextoul(argv[5], NULL);
-		state.load_address = state.bzimage_addr;
-		state.bzimage_addr = 0;
-	}
-	if (argc >= 7)
-		state.cmdline = env_get(argv[6]);
-
-	return 0;
-}
-
-static int zboot_load(void)
+int zboot_load(void)
 {
 	struct boot_params *base_ptr;
+	int ret;
 
 	if (state.base_ptr) {
 		struct boot_params *from = (struct boot_params *)state.base_ptr;
@@ -469,23 +390,16 @@
 	}
 	state.base_ptr = 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;
+	ret = env_set_hex("zbootbase", map_to_sysmem(state.base_ptr));
+	if (!ret)
+		ret = env_set_hex("zbootaddr", state.load_address);
+	if (ret)
+		return ret;
 
 	return 0;
 }
 
-static int zboot_setup(void)
+int zboot_setup(void)
 {
 	struct boot_params *base_ptr = state.base_ptr;
 	int ret;
@@ -499,33 +413,7 @@
 	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;
-
-	if (!base_ptr) {
-		printf("base is not set: use 'zboot load' first\n");
-		return CMD_RET_FAILURE;
-	}
-	if (zboot_setup()) {
-		puts("Setting up boot parameters failed ...\n");
-		return CMD_RET_FAILURE;
-	}
-
-	return 0;
-}
-
-static int do_zboot_info(struct cmd_tbl *cmdtp, int flag, int argc,
-			 char *const argv[])
-{
-	printf("Kernel loaded at %08lx, setup_base=%p\n",
-	       state.load_address, state.base_ptr);
-
-	return 0;
-}
-
-static int zboot_go(void)
+int zboot_go(void)
 {
 	struct boot_params *params = state.base_ptr;
 	struct setup_header *hdr = &params->hdr;
@@ -549,35 +437,12 @@
 	return ret;
 }
 
-static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
-		       char *const argv[])
+int zboot_run(ulong addr, ulong size, ulong initrd, ulong initrd_size,
+	      ulong base, char *cmdline)
 {
 	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;
-
+	zboot_start(addr, size, initrd, initrd_size, base, cmdline);
 	ret = zboot_load();
 	if (ret)
 		return log_msg_ret("ld", ret);
@@ -586,7 +451,7 @@
 		return log_msg_ret("set", ret);
 	ret = zboot_go();
 	if (ret)
-		return log_msg_ret("set", ret);
+		return log_msg_ret("go", ret);
 
 	return -EFAULT;
 }
@@ -776,97 +641,25 @@
 		print_num("Kernel info offset", hdr->kernel_info_offset);
 }
 
-static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc,
-			 char *const argv[])
+void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr,
+		 ulong initrd_size, ulong base_addr, const char *cmdline)
 {
-	struct boot_params *base_ptr = state.base_ptr;
-
-	if (argc > 1)
-		base_ptr = (void *)hextoul(argv[1], NULL);
-	if (!base_ptr) {
-		printf("No zboot setup_base\n");
-		return CMD_RET_FAILURE;
-	}
-	zimage_dump(base_ptr, true);
-
-	return 0;
-}
-
-/* Note: This defines the complete_zboot() function */
-U_BOOT_SUBCMDS(zboot,
-	U_BOOT_CMD_MKENT(start, 8, 1, do_zboot_start, "", ""),
-	U_BOOT_CMD_MKENT(load, 1, 1, do_zboot_load, "", ""),
-	U_BOOT_CMD_MKENT(setup, 1, 1, do_zboot_setup, "", ""),
-	U_BOOT_CMD_MKENT(info, 1, 1, do_zboot_info, "", ""),
-	U_BOOT_CMD_MKENT(go, 1, 1, do_zboot_go, "", ""),
-	U_BOOT_CMD_MKENT(dump, 2, 1, do_zboot_dump, "", ""),
-)
-
-int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc,
-		    char *const argv[], int state_mask)
-{
-	int i;
-
-	for (i = 0; i < ZBOOT_STATE_COUNT; i++) {
-		struct cmd_tbl *cmd = &zboot_subcmds[i];
-		int mask = 1 << i;
-		int ret;
+	memset(&state, '\0', sizeof(state));
 
-		if (mask & state_mask) {
-			ret = cmd->cmd(cmd, flag, argc, argv);
-			if (ret)
-				return ret;
-		}
+	state.bzimage_size = bzimage_size;
+	state.initrd_addr = initrd_addr;
+	state.initrd_size = initrd_size;
+	if (base_addr) {
+		state.base_ptr = map_sysmem(base_addr, 0);
+		state.load_address = bzimage_addr;
+	} else {
+		state.bzimage_addr = bzimage_addr;
 	}
-
-	return 0;
+	state.cmdline = cmdline;
 }
 
-int do_zboot_parent(struct cmd_tbl *cmdtp, int flag, int argc,
-		    char *const argv[], int *repeatable)
+void zboot_info(void)
 {
-	/* determine if we have a sub command */
-	if (argc > 1) {
-		char *endp;
-
-		hextoul(argv[1], &endp);
-		/*
-		 * endp pointing to nul means that argv[1] was just a valid
-		 * number, so pass it along to the normal processing
-		 */
-		if (*endp)
-			return do_zboot(cmdtp, flag, argc, argv, repeatable);
-	}
-
-	do_zboot_states(cmdtp, flag, argc, argv, ZBOOT_STATE_START |
-			ZBOOT_STATE_LOAD | ZBOOT_STATE_SETUP |
-			ZBOOT_STATE_INFO | ZBOOT_STATE_GO);
-
-	return CMD_RET_FAILURE;
+	printf("Kernel loaded at %08lx, setup_base=%p\n",
+	       state.load_address, state.base_ptr);
 }
-
-U_BOOT_CMDREP_COMPLETE(
-	zboot, 8, do_zboot_parent, "Boot bzImage",
-	"[addr] [size] [initrd addr] [initrd size] [setup] [cmdline]\n"
-	"      addr -        The optional starting address of the bzimage.\n"
-	"                    If not set it defaults to the environment\n"
-	"                    variable \"fileaddr\".\n"
-	"      size -        The optional size of the bzimage. Defaults to\n"
-	"                    zero.\n"
-	"      initrd addr - The address of the initrd image to use, if any.\n"
-	"      initrd size - The size of the initrd image to use, if any.\n"
-	"      setup -       The address of the kernel setup region, if this\n"
-	"                    is not at addr\n"
-	"      cmdline -     Environment variable containing the kernel\n"
-	"                    command line, to override U-Boot's normal\n"
-	"                    cmdline generation\n"
-	"\n"
-	"Sub-commands to do part of the zboot sequence:\n"
-	"\tstart [addr [arg ...]] - specify arguments\n"
-	"\tload   - load OS image\n"
-	"\tsetup  - set up table\n"
-	"\tinfo   - show summary info\n"
-	"\tgo     - start OS\n"
-	"\tdump [addr]    - dump info (optional address of boot params)",
-	complete_zboot
-);
diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile
index ad4fe32..bb9157f 100644
--- a/arch/xtensa/lib/Makefile
+++ b/arch/xtensa/lib/Makefile
@@ -3,6 +3,6 @@
 # (C) Copyright 2007 - 2013 Tensilica Inc.
 # (C) Copyright 2014 - 2016 Cadence Design Systems Inc.
 
-obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_BOOTM) += bootm.o
 
 obj-y	+= cache.o misc.o relocate.o time.o
diff --git a/board/emulation/qemu-riscv/qemu-riscv.c b/board/emulation/qemu-riscv/qemu-riscv.c
index 181abbb..173245b 100644
--- a/board/emulation/qemu-riscv/qemu-riscv.c
+++ b/board/emulation/qemu-riscv/qemu-riscv.c
@@ -31,12 +31,6 @@
 
 int board_init(void)
 {
-	/*
-	 * Make sure virtio bus is enumerated so that peripherals
-	 * on the virtio bus can be discovered by their drivers
-	 */
-	virtio_init();
-
 	return 0;
 }
 
@@ -46,6 +40,12 @@
 	if (CONFIG_IS_ENABLED(USB_KEYBOARD))
 		usb_init();
 
+	/*
+	 * Make sure virtio bus is enumerated so that peripherals
+	 * on the virtio bus can be discovered by their drivers
+	 */
+	virtio_init();
+
 	return 0;
 }
 
diff --git a/board/emulation/qemu-x86/Kconfig b/board/emulation/qemu-x86/Kconfig
index 9a06118..b2a4e08 100644
--- a/board/emulation/qemu-x86/Kconfig
+++ b/board/emulation/qemu-x86/Kconfig
@@ -18,7 +18,8 @@
 	select X86_RESET_VECTOR
 	select QEMU
 	select QFW_PIO if CMD_QFW
-	select BOARD_ROMSIZE_KB_1024
+	select BOARD_ROMSIZE_KB_1024 if TARGET_QEMU_X86
+	select BOARD_ROMSIZE_KB_2048 if TARGET_QEMU_X86_64
 	imply VIRTIO_PCI
 	imply VIRTIO_NET
 	imply VIRTIO_BLK
diff --git a/board/phytec/phycore_am62x/phycore-am62x.c b/board/phytec/phycore_am62x/phycore-am62x.c
index 91a2401..618b4c3 100644
--- a/board/phytec/phycore_am62x/phycore-am62x.c
+++ b/board/phytec/phycore_am62x/phycore-am62x.c
@@ -57,3 +57,67 @@
 	       MCU_CTRL_DEVICE_CLKOUT_32K_CTRL);
 }
 #endif
+
+#if IS_ENABLED(CONFIG_ENV_IS_IN_FAT) || IS_ENABLED(CONFIG_ENV_IS_IN_MMC)
+int mmc_get_env_dev(void)
+{
+	u32 boot_device = get_boot_device();
+
+	switch (boot_device) {
+	case BOOT_DEVICE_MMC1:
+		return 0;
+	case BOOT_DEVICE_MMC2:
+		return 1;
+	};
+
+	return CONFIG_SYS_MMC_ENV_DEV;
+}
+#endif
+
+enum env_location env_get_location(enum env_operation op, int prio)
+{
+	u32 boot_device = get_boot_device();
+
+	if (prio)
+		return ENVL_UNKNOWN;
+
+	switch (boot_device) {
+	case BOOT_DEVICE_MMC1:
+	case BOOT_DEVICE_MMC2:
+		if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
+			return ENVL_FAT;
+		if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
+			return ENVL_MMC;
+	case BOOT_DEVICE_SPI:
+		if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
+			return ENVL_SPI_FLASH;
+	default:
+		return ENVL_NOWHERE;
+	};
+}
+
+#if IS_ENABLED(CONFIG_BOARD_LATE_INIT)
+int board_late_init(void)
+{
+	u32 boot_device = get_boot_device();
+
+	switch (boot_device) {
+	case BOOT_DEVICE_MMC1:
+		env_set_ulong("mmcdev", 0);
+		env_set("boot", "mmc");
+		break;
+	case BOOT_DEVICE_MMC2:
+		env_set_ulong("mmcdev", 1);
+		env_set("boot", "mmc");
+		break;
+	case BOOT_DEVICE_SPI:
+		env_set("boot", "spi");
+		break;
+	case BOOT_DEVICE_ETHERNET:
+		env_set("boot", "net");
+		break;
+	};
+
+	return 0;
+}
+#endif
diff --git a/board/sophgo/milkv_duo/Kconfig b/board/sophgo/milkv_duo/Kconfig
index 2a458f2..040a748 100644
--- a/board/sophgo/milkv_duo/Kconfig
+++ b/board/sophgo/milkv_duo/Kconfig
@@ -7,7 +7,7 @@
 	default "sophgo"
 
 config SYS_CPU
-	default "generic"
+	default "cv1800b"
 
 config SYS_CONFIG_NAME
 	default "milkv_duo"
@@ -23,6 +23,6 @@
 
 config BOARD_SPECIFIC_OPTIONS
 	def_bool y
-	select GENERIC_RISCV
+	select SOPHGO_CV1800B
 
 endif
diff --git a/board/starfive/visionfive2/spl.c b/board/starfive/visionfive2/spl.c
index 1b49945..45848db 100644
--- a/board/starfive/visionfive2/spl.c
+++ b/board/starfive/visionfive2/spl.c
@@ -4,7 +4,6 @@
  * Author: Yanhong Wang<yanhong.wang@starfivetech.com>
  */
 
-#include <common.h>
 #include <asm/arch/eeprom.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/regs.h>
@@ -27,6 +26,26 @@
 	const char *value;
 };
 
+static const struct starfive_vf2_pro milk_v_mars[] = {
+	{"/soc/ethernet@16030000", "starfive,tx-use-rgmii-clk", NULL},
+	{"/soc/ethernet@16040000", "starfive,tx-use-rgmii-clk", NULL},
+
+	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
+		"motorcomm,tx-clk-adj-enabled", NULL},
+	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
+		"motorcomm,tx-clk-100-inverted", NULL},
+	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
+		"motorcomm,tx-clk-1000-inverted", NULL},
+	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
+		"motorcomm,rx-clk-drv-microamp", "3970"},
+	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
+		"motorcomm,rx-data-drv-microamp", "2910"},
+	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
+		"rx-internal-delay-ps", "1900"},
+	{"/soc/ethernet@16030000/mdio/ethernet-phy@0",
+		"tx-internal-delay-ps", "1500"},
+};
+
 static const struct starfive_vf2_pro starfive_vera[] = {
 	{"/soc/ethernet@16030000/mdio/ethernet-phy@0", "rx-internal-delay-ps",
 		"1900"},
@@ -67,6 +86,49 @@
 		"tx-internal-delay-ps", "0"},
 };
 
+void spl_fdt_fixup_mars(void *fdt)
+{
+	static const char compat[] = "milkv,mars\0starfive,jh7110";
+	u32 phandle;
+	u8 i;
+	int offset;
+	int ret;
+
+	fdt_setprop(fdt, fdt_path_offset(fdt, "/"), "compatible", compat, sizeof(compat));
+	fdt_setprop_string(fdt, fdt_path_offset(fdt, "/"), "model",
+			   "Milk-V Mars");
+
+	/* gmac0 */
+	offset = fdt_path_offset(fdt, "/soc/clock-controller@17000000");
+	phandle = fdt_get_phandle(fdt, offset);
+	offset = fdt_path_offset(fdt, "/soc/ethernet@16030000");
+
+	fdt_setprop_u32(fdt, offset, "assigned-clocks", phandle);
+	fdt_appendprop_u32(fdt, offset, "assigned-clocks", JH7110_AONCLK_GMAC0_TX);
+	fdt_setprop_u32(fdt, offset,  "assigned-clock-parents", phandle);
+	fdt_appendprop_u32(fdt, offset,  "assigned-clock-parents",
+			   JH7110_AONCLK_GMAC0_RMII_RTX);
+
+	/* gmac1 */
+	fdt_setprop_string(fdt, fdt_path_offset(fdt, "/soc/ethernet@16040000"),
+			   "status", "disabled");
+
+	for (i = 0; i < ARRAY_SIZE(milk_v_mars); i++) {
+		offset = fdt_path_offset(fdt, milk_v_mars[i].path);
+
+		if (milk_v_mars[i].value)
+			ret = fdt_setprop_u32(fdt, offset, milk_v_mars[i].name,
+					      dectoul(milk_v_mars[i].value, NULL));
+		else
+			ret = fdt_setprop_empty(fdt, offset, milk_v_mars[i].name);
+
+		if (ret) {
+			pr_err("%s set prop %s fail.\n", __func__, milk_v_mars[i].name);
+				break;
+		}
+	}
+}
+
 void spl_fdt_fixup_version_a(void *fdt)
 {
 	static const char compat[] = "starfive,visionfive-2-v1.2a\0starfive,jh7110";
@@ -167,22 +229,34 @@
 void spl_perform_fixups(struct spl_image_info *spl_image)
 {
 	u8 version;
+	const char *product_id;
 
-	version = get_pcb_revision_from_eeprom();
-	switch (version) {
-	case 'a':
-	case 'A':
-		spl_fdt_fixup_version_a(spl_image->fdt_addr);
-		break;
+	product_id = get_product_id_from_eeprom();
+	if (!product_id) {
+		pr_err("Can't read EEPROM\n");
+		return;
+	}
+	if (!strncmp(product_id, "MARS", 4)) {
+		spl_fdt_fixup_mars(spl_image->fdt_addr);
+	} else if (!strncmp(product_id, "VF7110", 6)) {
+		version = get_pcb_revision_from_eeprom();
+		switch (version) {
+		case 'a':
+		case 'A':
+			spl_fdt_fixup_version_a(spl_image->fdt_addr);
+			break;
 
-	case 'b':
-	case 'B':
-	default:
-		spl_fdt_fixup_version_b(spl_image->fdt_addr);
+		case 'b':
+		case 'B':
+		default:
+			spl_fdt_fixup_version_b(spl_image->fdt_addr);
 		break;
+		};
+	} else {
+		pr_err("Unknown product %s\n", product_id);
 	};
 
-	/* Update the memory size which read form eeprom or DT */
+	/* Update the memory size which read from eeprom or DT */
 	fdt_fixup_memory(spl_image->fdt_addr, 0x40000000, gd->ram_size);
 }
 
diff --git a/board/starfive/visionfive2/starfive_visionfive2.c b/board/starfive/visionfive2/starfive_visionfive2.c
index 78e118d..a86bca5 100644
--- a/board/starfive/visionfive2/starfive_visionfive2.c
+++ b/board/starfive/visionfive2/starfive_visionfive2.c
@@ -4,11 +4,11 @@
  * Author: Yanhong Wang<yanhong.wang@starfivetech.com>
  */
 
-#include <common.h>
 #include <cpu_func.h>
 #include <dm.h>
 #include <fdt_support.h>
 #include <env.h>
+#include <log.h>
 #include <asm/arch/eeprom.h>
 #include <asm/io.h>
 #include <asm/sections.h>
@@ -17,6 +17,8 @@
 DECLARE_GLOBAL_DATA_PTR;
 #define JH7110_L2_PREFETCHER_BASE_ADDR		0x2030000
 #define JH7110_L2_PREFETCHER_HART_OFFSET	0x2000
+#define FDTFILE_MILK_V_MARS \
+	"starfive/jh7110-milkv-mars.dtb"
 #define FDTFILE_VISIONFIVE2_1_2A \
 	"starfive/jh7110-starfive-visionfive-2-v1.2a.dtb"
 #define FDTFILE_VISIONFIVE2_1_3B \
@@ -48,20 +50,38 @@
 {
 	u8 version;
 	const char *fdtfile;
+	const char *product_id;
 
-	version = get_pcb_revision_from_eeprom();
-	switch (version) {
-	case 'a':
-	case 'A':
-		fdtfile = FDTFILE_VISIONFIVE2_1_2A;
-	        break;
+	fdtfile = env_get("fdtfile");
+	if (fdtfile)
+		return;
 
-	case 'b':
-	case 'B':
-	default:
-		fdtfile = FDTFILE_VISIONFIVE2_1_3B;
-	        break;
-	};
+	product_id = get_product_id_from_eeprom();
+	if (!product_id) {
+		log_err("Can't read EEPROM\n");
+		return;
+	}
+	if (!strncmp(product_id, "MARS", 4)) {
+		fdtfile = FDTFILE_MILK_V_MARS;
+	} else if (!strncmp(product_id, "VF7110", 6)) {
+		version = get_pcb_revision_from_eeprom();
+
+		switch (version) {
+		case 'a':
+		case 'A':
+			fdtfile = FDTFILE_VISIONFIVE2_1_2A;
+			break;
+
+		case 'b':
+		case 'B':
+		default:
+			fdtfile = FDTFILE_VISIONFIVE2_1_3B;
+			break;
+		}
+	} else {
+		log_err("Unknown product\n");
+		return;
+	}
 
 	env_set("fdtfile", fdtfile);
 }
diff --git a/board/starfive/visionfive2/visionfive2-i2c-eeprom.c b/board/starfive/visionfive2/visionfive2-i2c-eeprom.c
index c36de1a..ddef7d6 100644
--- a/board/starfive/visionfive2/visionfive2-i2c-eeprom.c
+++ b/board/starfive/visionfive2/visionfive2-i2c-eeprom.c
@@ -4,7 +4,6 @@
  * Author: Yanhong Wang<yanhong.wang@starfivetech.com>
  */
 
-#include <common.h>
 #include <command.h>
 #include <env.h>
 #include <i2c.h>
@@ -405,6 +404,14 @@
 	update_crc();
 }
 
+const char *get_product_id_from_eeprom(void)
+{
+	if (read_eeprom())
+		return NULL;
+
+	return pbuf.eeprom.atom1.data.pstr;
+}
+
 int do_mac(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	char *cmd;
diff --git a/board/toradex/verdin-am62/MAINTAINERS b/board/toradex/verdin-am62/MAINTAINERS
index 4e75980..3e30d1d 100644
--- a/board/toradex/verdin-am62/MAINTAINERS
+++ b/board/toradex/verdin-am62/MAINTAINERS
@@ -1,12 +1,8 @@
 Verdin AM62
 F:	arch/arm/dts/k3-am625-verdin-lpddr4-1600MTs.dtsi
 F:	arch/arm/dts/k3-am625-verdin-r5.dts
-F:	arch/arm/dts/k3-am625-verdin-wifi-dev.dts
 F:	arch/arm/dts/k3-am625-verdin-wifi-dev-binman.dtsi
 F:	arch/arm/dts/k3-am625-verdin-wifi-dev-u-boot.dtsi
-F:	arch/arm/dts/k3-am62-verdin-dev.dtsi
-F:	arch/arm/dts/k3-am62-verdin.dtsi
-F:	arch/arm/dts/k3-am62-verdin-wifi.dtsi
 F:	board/toradex/verdin-am62/
 F:	configs/verdin-am62_a53_defconfig
 F:	configs/verdin-am62_r5_defconfig
diff --git a/board/xilinx/Kconfig b/board/xilinx/Kconfig
index 843198f..5c4ad8f 100644
--- a/board/xilinx/Kconfig
+++ b/board/xilinx/Kconfig
@@ -45,6 +45,7 @@
 	default 0x1000 if ARCH_VERSAL || ARCH_VERSAL_NET
 	default 0x8000 if MICROBLAZE
 	default 0x100000 if ARCH_ZYNQ || ARCH_ZYNQMP
+	default 0x23000000 if TARGET_XILINX_MBV
 	depends on OF_BOARD || OF_SEPARATE
 	help
 	  Offset in the memory where the board configuration DTB is placed.
diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c
index 9641ed3..b47d2d2 100644
--- a/board/xilinx/common/board.c
+++ b/board/xilinx/common/board.c
@@ -12,6 +12,7 @@
 #include <env.h>
 #include <image.h>
 #include <init.h>
+#include <jffs2/load_kernel.h>
 #include <lmb.h>
 #include <log.h>
 #include <asm/global_data.h>
@@ -20,6 +21,7 @@
 #include <i2c.h>
 #include <linux/sizes.h>
 #include <malloc.h>
+#include <mtd_node.h>
 #include "board.h"
 #include <dm.h>
 #include <i2c_eeprom.h>
@@ -43,7 +45,7 @@
 		.image_index = 1,
 	},
 #endif
-#if defined(XILINX_UBOOT_IMAGE_GUID)
+#if defined(XILINX_UBOOT_IMAGE_GUID) && defined(CONFIG_SPL_FS_LOAD_PAYLOAD_NAME)
 	{
 		.image_type_id = XILINX_UBOOT_IMAGE_GUID,
 		.fw_name = u"XILINX-UBOOT",
@@ -103,10 +105,14 @@
 	for (i = 0; i < size; i++) {
 		byte = eeprom[i];
 
-		/* Remove all non printable chars but ignore MAC address */
-		if ((i < offsetof(struct xilinx_legacy_format, eth_mac) ||
-		     i >= offsetof(struct xilinx_legacy_format, unused1)) &&
-		     (byte < '!' || byte > '~')) {
+		/* Ignore MAC address */
+		if (i >= offsetof(struct xilinx_legacy_format, eth_mac) &&
+		    i < offsetof(struct xilinx_legacy_format, unused1)) {
+			continue;
+		}
+
+		/* Remove all non printable chars */
+		if (byte < '!' || byte > '~') {
 			eeprom[i] = 0;
 			continue;
 		}
@@ -358,6 +364,14 @@
 	void *fdt_blob;
 
 	*err = 0;
+
+	if (IS_ENABLED(CONFIG_TARGET_XILINX_MBV)) {
+		fdt_blob = (void *)CONFIG_XILINX_OF_BOARD_DTB_ADDR;
+
+		if (fdt_magic(fdt_blob) == FDT_MAGIC)
+			return fdt_blob;
+	}
+
 	if (!IS_ENABLED(CONFIG_SPL_BUILD) &&
 	    !IS_ENABLED(CONFIG_VERSAL_NO_DDR) &&
 	    !IS_ENABLED(CONFIG_ZYNQMP_NO_DDR)) {
@@ -693,6 +707,13 @@
 	u8 buf[MAX_RAND_SIZE];
 	int nodeoffset, ret;
 
+	static const struct node_info nodes[] = {
+		{ "arm,pl353-nand-r2p1", MTD_DEV_TYPE_NAND, },
+	};
+
+	if (IS_ENABLED(CONFIG_FDT_FIXUP_PARTITIONS) && IS_ENABLED(CONFIG_NAND_ZYNQ))
+		fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
+
 	if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) {
 		debug("No RNG device\n");
 		return 0;
diff --git a/board/xilinx/mbv/Kconfig b/board/xilinx/mbv/Kconfig
index d2dec39..a3a6f21 100644
--- a/board/xilinx/mbv/Kconfig
+++ b/board/xilinx/mbv/Kconfig
@@ -10,15 +10,25 @@
 	default "generic"
 
 config TEXT_BASE
-	default 0x80000000 if !RISCV_SMODE
-	default 0x80400000 if RISCV_SMODE && ARCH_RV32I
+	default 0x21200000
+
+config SPL_TEXT_BASE
+	default 0x20000000
+
+config SPL_OPENSBI_LOAD_ADDR
+	hex
+	default 0x20200000
 
 config BOARD_SPECIFIC_OPTIONS
 	def_bool y
 	select GENERIC_RISCV
+	select SUPPORT_SPL
 	imply BOARD_LATE_INIT
+	imply SPL_RAM_SUPPORT
+	imply SPL_RAM_DEVICE
 	imply CMD_SBI
 	imply CMD_PING
+	imply OF_HAS_PRIOR_STAGE
 
 source "board/xilinx/Kconfig"
 
diff --git a/board/xilinx/mbv/board.c b/board/xilinx/mbv/board.c
index ccf4395..c478f7e 100644
--- a/board/xilinx/mbv/board.c
+++ b/board/xilinx/mbv/board.c
@@ -5,7 +5,17 @@
  * Michal Simek <michal.simek@amd.com>
  */
 
+#include <spl.h>
+
 int board_init(void)
 {
 	return 0;
 }
+
+#ifdef CONFIG_SPL
+u32 spl_boot_device(void)
+{
+	/* RISC-V QEMU only supports RAM as SPL boot device */
+	return BOOT_DEVICE_RAM;
+}
+#endif
diff --git a/board/xilinx/versal-net/board.c b/board/xilinx/versal-net/board.c
index 990ca16..da03024 100644
--- a/board/xilinx/versal-net/board.c
+++ b/board/xilinx/versal-net/board.c
@@ -371,3 +371,35 @@
 void reset_cpu(void)
 {
 }
+
+#if defined(CONFIG_ENV_IS_NOWHERE)
+enum env_location env_get_location(enum env_operation op, int prio)
+{
+	u8 bootmode = versal_net_get_bootmode();
+
+	if (prio)
+		return ENVL_UNKNOWN;
+
+	switch (bootmode) {
+	case EMMC_MODE:
+	case SD_MODE:
+	case SD1_LSHFT_MODE:
+	case SD_MODE1:
+		if (IS_ENABLED(CONFIG_ENV_IS_IN_FAT))
+			return ENVL_FAT;
+		if (IS_ENABLED(CONFIG_ENV_IS_IN_EXT4))
+			return ENVL_EXT4;
+		return ENVL_NOWHERE;
+	case OSPI_MODE:
+	case QSPI_MODE_24BIT:
+	case QSPI_MODE_32BIT:
+		if (IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH))
+			return ENVL_SPI_FLASH;
+		return ENVL_NOWHERE;
+	case JTAG_MODE:
+	case SELECTMAP_MODE:
+	default:
+		return ENVL_NOWHERE;
+	}
+}
+#endif
diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c
index 8c2e614..4f6d561 100644
--- a/board/xilinx/versal/board.c
+++ b/board/xilinx/versal/board.c
@@ -291,6 +291,7 @@
 {
 }
 
+#if defined(CONFIG_ENV_IS_NOWHERE)
 enum env_location env_get_location(enum env_operation op, int prio)
 {
 	u32 bootmode = versal_get_bootmode();
@@ -320,3 +321,4 @@
 		return ENVL_NOWHERE;
 	}
 }
+#endif
diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c
index ba49eb7..f370fb7 100644
--- a/board/xilinx/zynqmp/zynqmp.c
+++ b/board/xilinx/zynqmp/zynqmp.c
@@ -588,6 +588,7 @@
 	return bootseq;
 }
 
+#if defined(CONFIG_ENV_IS_NOWHERE)
 enum env_location env_get_location(enum env_operation op, int prio)
 {
 	u32 bootmode = zynqmp_get_bootmode();
@@ -621,11 +622,37 @@
 		return ENVL_NOWHERE;
 	}
 }
+#endif
 
 #if defined(CONFIG_SET_DFU_ALT_INFO)
 
 #define DFU_ALT_BUF_LEN		SZ_1K
 
+static void mtd_found_part(u32 *base, u32 *size)
+{
+	struct mtd_info *part, *mtd;
+
+	mtd_probe_devices();
+
+	mtd = get_mtd_device_nm("nor0");
+	if (!IS_ERR_OR_NULL(mtd)) {
+		list_for_each_entry(part, &mtd->partitions, node) {
+			debug("0x%012llx-0x%012llx : \"%s\"\n",
+			      part->offset, part->offset + part->size,
+			      part->name);
+
+			if (*base >= part->offset &&
+			    *base < part->offset + part->size) {
+				debug("Found my partition: %d/%s\n",
+				      part->index, part->name);
+				*base = part->offset;
+				*size = part->size;
+				break;
+			}
+		}
+	}
+}
+
 void set_dfu_alt_info(char *interface, char *devstr)
 {
 	int multiboot, bootseq = 0, len = 0;
@@ -661,21 +688,38 @@
 		len += snprintf(buf + len, DFU_ALT_BUF_LEN, ".bin fat %d 1",
 			       bootseq);
 #if defined(CONFIG_SPL_FS_LOAD_PAYLOAD_NAME)
-		len += snprintf(buf + len, DFU_ALT_BUF_LEN, ";%s fat %d 1",
-			       CONFIG_SPL_FS_LOAD_PAYLOAD_NAME, bootseq);
+		if (strlen(CONFIG_SPL_FS_LOAD_PAYLOAD_NAME))
+			len += snprintf(buf + len, DFU_ALT_BUF_LEN,
+					";%s fat %d 1",
+					CONFIG_SPL_FS_LOAD_PAYLOAD_NAME,
+					bootseq);
 #endif
 		break;
 	case QSPI_MODE_24BIT:
 	case QSPI_MODE_32BIT:
-		len += snprintf(buf + len, DFU_ALT_BUF_LEN,
-			       "sf 0:0=boot.bin raw %x 0x1500000",
-			       multiboot * SZ_32K);
+		{
+			u32 base = multiboot * SZ_32K;
+			u32 size = 0x1500000;
+			u32 limit = size;
+
+			mtd_found_part(&base, &limit);
+
+#if defined(CONFIG_SYS_SPI_U_BOOT_OFFS)
+			size = limit;
+			limit = CONFIG_SYS_SPI_U_BOOT_OFFS;
+#endif
+
+			len += snprintf(buf + len, DFU_ALT_BUF_LEN,
+					"sf 0:0=boot.bin raw 0x%x 0x%x",
+					base, limit);
 #if defined(CONFIG_SPL_FS_LOAD_PAYLOAD_NAME) && defined(CONFIG_SYS_SPI_U_BOOT_OFFS)
-		len += snprintf(buf + len, DFU_ALT_BUF_LEN,
-			       ";%s raw 0x%x 0x500000",
-			       CONFIG_SPL_FS_LOAD_PAYLOAD_NAME,
-			       multiboot * SZ_32K + CONFIG_SYS_SPI_U_BOOT_OFFS);
+			if (strlen(CONFIG_SPL_FS_LOAD_PAYLOAD_NAME))
+				len += snprintf(buf + len, DFU_ALT_BUF_LEN,
+						";%s raw 0x%x 0x%x",
+						CONFIG_SPL_FS_LOAD_PAYLOAD_NAME,
+						base + limit, size - limit);
 #endif
+		}
 		break;
 	default:
 		return;
diff --git a/board/xilinx/zynqmp/zynqmp_kria.env b/board/xilinx/zynqmp/zynqmp_kria.env
index 0f940bd..846eceb 100644
--- a/board/xilinx/zynqmp/zynqmp_kria.env
+++ b/board/xilinx/zynqmp/zynqmp_kria.env
@@ -17,6 +17,7 @@
 bootcmd_usb1=devnum=1; run usb_boot
 bootcmd_usb2=devnum=2; run usb_boot
 bootcmd_usb3=devnum=3; run usb_boot
+bootcmd_usb4=devnum=4; run usb_boot
 bootdelay=2
 bootfstype=fat
 bootm_low=0
@@ -44,7 +45,8 @@
 preboot=setenv boot_targets; setenv modeboot; run board_setup
 
 # SOM specific boot methods
-som_cc_boot=if test ${card1_name} = SCK-KV-G; then setenv boot_targets mmc1 usb0 usb1 usb2 usb3 pxe dhcp && run distro_bootcmd; elif test ${card1_name} = SCK-KR-G; then setenv boot_targets usb0 usb1 usb2 usb3 pxe dhcp && run distro_bootcmd; else test ${card1_name} = SCK-KD-G; setenv boot_targets usb0 usb1 usb2 usb3 pxe dhcp && run distro_bootcmd; fi;"
+usb_boot_devices='usb0 usb1 usb2 usb3 usb4'
+som_cc_boot=if test ${card1_name} = SCK-KV-G; then setenv boot_targets mmc1 ${usb_boot_devices} pxe dhcp jtag && run distro_bootcmd; elif test ${card1_name} = SCK-KR-G; then setenv boot_targets ${usb_boot_devices} pxe dhcp jtag && run distro_bootcmd; else test ${card1_name} = SCK-KD-G; setenv boot_targets ${usb_boot_devices} pxe dhcp jtag && run distro_bootcmd; fi;"
 som_mmc_boot=setenv boot_targets mmc0 && run distro_bootcmd
 
 k26_starter=SMK-K26-XCL2G
diff --git a/boot/Kconfig b/boot/Kconfig
index d9a6c27..777e408 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -2,39 +2,6 @@
 
 menu "Boot images"
 
-config ANDROID_BOOT_IMAGE
-	bool "Android Boot Images"
-	default y if FASTBOOT
-	help
-	  This enables support for booting images which use the Android
-	  image format header.
-
-config TIMESTAMP
-	bool "Show image date and time when displaying image information"
-	default y if CMD_DATE
-	help
-	  When CONFIG_TIMESTAMP is selected, the timestamp (date and time) of
-	  an image is printed by image commands like bootm or iminfo. This
-	  is shown as 'Timestamp: xxx' and 'Created: xxx'. If this option is
-	  enabled, then U-Boot requires FITs to have a timestamp. If a FIT is
-	  loaded that does not, the message 'Wrong FIT format: no timestamp'
-	  is shown.
-
-config BUTTON_CMD
-	bool "Support for running a command if a button is held during boot"
-	depends on CMDLINE
-	depends on BUTTON
-	help
-	  For many embedded devices it's useful to enter a special flashing mode
-	  such as fastboot mode when a button is held during boot. This option
-	  allows arbitrary commands to be assigned to specific buttons. These will
-	  be run after "preboot" if the button is held. Configuration is done via
-	  the environment variables "button_cmd_N_name" and "button_cmd_N" where n is
-	  the button number (starting from 0). e.g:
-
-	    "button_cmd_0_name=vol_down"
-	    "button_cmd_0=fastboot usb 0"
-
 menuconfig FIT
 	bool "Flattened Image Tree (FIT)"
 	select HASH
@@ -721,6 +688,100 @@
 
 endif # BOOTSTD
 
+config BOOTM
+	bool "Support booting an application image from memory"
+	default y
+	help
+	  This is the main boot implementation in U-Boot, supporting a wide
+	  variety of features including FIT and legacy-image boot, kernel and
+	  FDT selection, setting up of the command line for the OS and many
+	  other features.
+
+	  This option should normally be enabled. It is used to implement the
+	  'bootm' command.
+
+config BOOTM_LINUX
+	bool "Support booting Linux OS images"
+	depends on BOOTM || CMD_BOOTZ || CMD_BOOTI
+	default y
+	help
+	  Support booting the Linux kernel directly via a command such as bootm
+	  or booti or bootz.
+
+config BOOTM_NETBSD
+	bool "Support booting NetBSD (non-EFI) loader images"
+	depends on BOOTM
+	default y
+	help
+	  Support booting NetBSD via the bootm command.
+
+config BOOTM_OPENRTOS
+	bool "Support booting OPENRTOS / FreeRTOS images"
+	depends on BOOTM
+	help
+	  Support booting OPENRTOS / FreeRTOS via the bootm command.
+
+config BOOTM_OSE
+	bool "Support booting Enea OSE images"
+	depends on (ARM && (ARM64 || CPU_V7A || CPU_V7R) || SANDBOX || PPC || X86)
+	depends on BOOTM
+	help
+	  Support booting Enea OSE images via the bootm command.
+
+config BOOTM_PLAN9
+	bool "Support booting Plan9 OS images"
+	depends on BOOTM
+	default y
+	help
+	  Support booting Plan9 images via the bootm command.
+
+config BOOTM_RTEMS
+	bool "Support booting RTEMS OS images"
+	depends on BOOTM
+	default y
+	help
+	  Support booting RTEMS images via the bootm command.
+
+config BOOTM_VXWORKS
+	bool "Support booting VxWorks OS images"
+	depends on BOOTM
+	default y
+	help
+	  Support booting VxWorks images via the bootm command.
+
+config ANDROID_BOOT_IMAGE
+	bool "Android Boot Images"
+	default y if FASTBOOT
+	help
+	  This enables support for booting images which use the Android
+	  image format header.
+
+config TIMESTAMP
+	bool "Show image date and time when displaying image information"
+	default y if CMD_DATE
+	help
+	  When CONFIG_TIMESTAMP is selected, the timestamp (date and time) of
+	  an image is printed by image commands like bootm or iminfo. This
+	  is shown as 'Timestamp: xxx' and 'Created: xxx'. If this option is
+	  enabled, then U-Boot requires FITs to have a timestamp. If a FIT is
+	  loaded that does not, the message 'Wrong FIT format: no timestamp'
+	  is shown.
+
+config BUTTON_CMD
+	bool "Support for running a command if a button is held during boot"
+	depends on CMDLINE
+	depends on BUTTON
+	help
+	  For many embedded devices it's useful to enter a special flashing mode
+	  such as fastboot mode when a button is held during boot. This option
+	  allows arbitrary commands to be assigned to specific buttons. These will
+	  be run after "preboot" if the button is held. Configuration is done via
+	  the environment variables "button_cmd_N_name" and "button_cmd_N" where n is
+	  the button number (starting from 0). e.g:
+
+	    "button_cmd_0_name=vol_down"
+	    "button_cmd_0=fastboot usb 0"
+
 config LEGACY_IMAGE_FORMAT
 	bool "Enable support for the legacy image format"
 	default y if !FIT_SIGNATURE && !TI_SECURE_DEVICE
@@ -765,7 +826,7 @@
 
 config SYS_BOOTM_LEN
 	hex "Maximum size of a decompresed OS image"
-	depends on CMD_BOOTM || CMD_BOOTI || CMD_BOOTZ || \
+	depends on BOOTM || CMD_BOOTI || CMD_BOOTZ || \
 		LEGACY_IMAGE_FORMAT || SPL_LEGACY_IMAGE_FORMAT
 	default 0x4000000 if PPC || ARM64
 	default 0x1000000 if X86 || ARCH_MX6 || ARCH_MX7
diff --git a/boot/Makefile b/boot/Makefile
index 84ccfea..bf767fd 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -6,7 +6,7 @@
 ifndef CONFIG_SPL_BUILD
 
 obj-$(CONFIG_BOOT_RETRY) += bootretry.o
-obj-$(CONFIG_CMD_BOOTM) += bootm.o bootm_os.o
+obj-$(CONFIG_BOOTM) += bootm.o bootm_os.o
 obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o
 obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o
 
diff --git a/boot/bootm.c b/boot/bootm.c
index d071537..032f5a4 100644
--- a/boot/bootm.c
+++ b/boot/bootm.c
@@ -242,13 +242,13 @@
 #ifdef CONFIG_LMB
 static void boot_start_lmb(struct bootm_headers *images)
 {
-	ulong		mem_start;
+	phys_addr_t	mem_start;
 	phys_size_t	mem_size;
 
 	mem_start = env_get_bootm_low();
 	mem_size = env_get_bootm_size();
 
-	lmb_init_and_reserve_range(&images->lmb, (phys_addr_t)mem_start,
+	lmb_init_and_reserve_range(&images->lmb, mem_start,
 				   mem_size, NULL);
 }
 #else
diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c
index cd72db8..f015f2e 100644
--- a/boot/bootmeth_cros.c
+++ b/boot/bootmeth_cros.c
@@ -432,9 +432,9 @@
 	}
 
 	if (IS_ENABLED(CONFIG_X86)) {
-		ret = zboot_start(map_to_sysmem(bflow->buf), bflow->size, 0, 0,
-				  map_to_sysmem(bflow->x86_setup),
-				  bflow->cmdline);
+		ret = zboot_run(map_to_sysmem(bflow->buf), bflow->size, 0, 0,
+				map_to_sysmem(bflow->x86_setup),
+				bflow->cmdline);
 	} else {
 		ret = bootm_boot_start(map_to_sysmem(bflow->buf),
 				       bflow->cmdline);
diff --git a/boot/fdt_support.c b/boot/fdt_support.c
index 090d82e..9844c70 100644
--- a/boot/fdt_support.c
+++ b/boot/fdt_support.c
@@ -17,6 +17,7 @@
 #include <linux/ctype.h>
 #include <linux/types.h>
 #include <asm/global_data.h>
+#include <asm/unaligned.h>
 #include <linux/libfdt.h>
 #include <fdt_support.h>
 #include <exports.h>
@@ -421,13 +422,13 @@
 
 	for (i = 0; i < n; i++) {
 		if (address_cells == 2)
-			*(fdt64_t *)p = cpu_to_fdt64(address[i]);
+			put_unaligned_be64(address[i], p);
 		else
 			*(fdt32_t *)p = cpu_to_fdt32(address[i]);
 		p += 4 * address_cells;
 
 		if (size_cells == 2)
-			*(fdt64_t *)p = cpu_to_fdt64(size[i]);
+			put_unaligned_be64(size[i], p);
 		else
 			*(fdt32_t *)p = cpu_to_fdt32(size[i]);
 		p += 4 * size_cells;
diff --git a/boot/image-board.c b/boot/image-board.c
index 75f6906..09b6e4e 100644
--- a/boot/image-board.c
+++ b/boot/image-board.c
@@ -107,14 +107,12 @@
 }
 U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);
 
-ulong env_get_bootm_low(void)
+phys_addr_t env_get_bootm_low(void)
 {
 	char *s = env_get("bootm_low");
 
-	if (s) {
-		ulong tmp = hextoul(s, NULL);
-		return tmp;
-	}
+	if (s)
+		return simple_strtoull(s, NULL, 16);
 
 #if defined(CFG_SYS_SDRAM_BASE)
 	return CFG_SYS_SDRAM_BASE;
@@ -127,14 +125,12 @@
 
 phys_size_t env_get_bootm_size(void)
 {
-	phys_size_t tmp, size;
-	phys_addr_t start;
+	phys_addr_t start, low;
+	phys_size_t size;
 	char *s = env_get("bootm_size");
 
-	if (s) {
-		tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
-		return tmp;
-	}
+	if (s)
+		return simple_strtoull(s, NULL, 16);
 
 	start = gd->ram_base;
 	size = gd->ram_size;
@@ -144,22 +140,19 @@
 
 	s = env_get("bootm_low");
 	if (s)
-		tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
+		low = simple_strtoull(s, NULL, 16);
 	else
-		tmp = start;
+		low = start;
 
-	return size - (tmp - start);
+	return size - (low - start);
 }
 
 phys_size_t env_get_bootm_mapsize(void)
 {
-	phys_size_t tmp;
 	char *s = env_get("bootm_mapsize");
 
-	if (s) {
-		tmp = (phys_size_t)simple_strtoull(s, NULL, 16);
-		return tmp;
-	}
+	if (s)
+		return simple_strtoull(s, NULL, 16);
 
 #if defined(CFG_SYS_BOOTMAPSZ)
 	return CFG_SYS_BOOTMAPSZ;
@@ -538,7 +531,7 @@
 		      ulong *initrd_start, ulong *initrd_end)
 {
 	char	*s;
-	ulong	initrd_high;
+	phys_addr_t initrd_high;
 	int	initrd_copy_to_ram = 1;
 
 	s = env_get("initrd_high");
@@ -553,8 +546,8 @@
 		initrd_high = env_get_bootm_mapsize() + env_get_bootm_low();
 	}
 
-	debug("## initrd_high = 0x%08lx, copy_to_ram = %d\n",
-	      initrd_high, initrd_copy_to_ram);
+	debug("## initrd_high = 0x%llx, copy_to_ram = %d\n",
+	      (u64)initrd_high, initrd_copy_to_ram);
 
 	if (rd_data) {
 		if (!initrd_copy_to_ram) {	/* zero-copy ramdisk support */
diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index 5e4aa9d..2b92bda 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -160,9 +160,11 @@
 {
 	void	*fdt_blob = *of_flat_tree;
 	void	*of_start = NULL;
-	u64	start, size, usable;
+	phys_addr_t start, size, usable;
 	char	*fdt_high;
-	ulong	mapsize, low;
+	phys_addr_t addr;
+	phys_addr_t low;
+	phys_size_t mapsize;
 	ulong	of_len = 0;
 	int	bank;
 	int	err;
@@ -185,7 +187,6 @@
 	fdt_high = env_get("fdt_high");
 	if (fdt_high) {
 		ulong desired_addr = hextoul(fdt_high, NULL);
-		ulong addr;
 
 		if (desired_addr == ~0UL) {
 			/* All ones means use fdt in place */
@@ -217,14 +218,14 @@
 			if (start + size < low)
 				continue;
 
-			usable = min(start + size, (u64)(low + mapsize));
-
 			/*
 			 * At least part of this DRAM bank is usable, try
-			 * using it for LMB allocation.
+			 * using the DRAM bank up to 'usable' address limit
+			 * for LMB allocation.
 			 */
-			of_start = map_sysmem((ulong)lmb_alloc_base(lmb,
-				    of_len, 0x1000, usable), of_len);
+			usable = min(start + size, low + mapsize);
+			addr = lmb_alloc_base(lmb, of_len, 0x1000, usable);
+			of_start = map_sysmem(addr, of_len);
 			/* Allocation succeeded, use this block. */
 			if (of_start != NULL)
 				break;
@@ -233,7 +234,7 @@
 			 * Reduce the mapping size in the next bank
 			 * by the size of attempt in current bank.
 			 */
-			mapsize -= usable - max(start, (u64)low);
+			mapsize -= usable - max(start, low);
 			if (!mapsize)
 				break;
 		}
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index 9620562..d5e1bea 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -5,6 +5,7 @@
  */
 
 #include <common.h>
+#include <bootm.h>
 #include <command.h>
 #include <dm.h>
 #include <env.h>
@@ -470,6 +471,220 @@
 #endif
 
 /**
+ * calc_fdt_fname() - Figure out the filename to use for the FDT
+ *
+ * Determine the path to the FDT filename, based on the "fdtfile" environment
+ * variable. Use <soc>-<board>.dtb as a fallback
+ *
+ * @fdtdir: Directory to use for the FDT file
+ * Return: allocated filename (including directory), or NULL if out of memory
+ */
+static char *calc_fdt_fname(const char *fdtdir)
+{
+	char *fdtfile;
+	char *f1, *f2, *f3, *f4, *slash;
+	int len;
+
+	f1 = env_get("fdtfile");
+	if (f1) {
+		f2 = "";
+		f3 = "";
+		f4 = "";
+	} else {
+		/*
+		 * For complex cases where this code doesn't generate the
+		 * correct filename, the board code should set $fdtfile during
+		 * early boot, or the boot scripts should set $fdtfile before
+		 * invoking "pxe" or "sysboot".
+		 */
+		f1 = env_get("soc");
+		f2 = "-";
+		f3 = env_get("board");
+		f4 = ".dtb";
+		if (!f1) {
+			f1 = "";
+			f2 = "";
+		}
+		if (!f3) {
+			f2 = "";
+			f3 = "";
+		}
+	}
+
+	len = strlen(fdtdir);
+	if (!len)
+		slash = "./";
+	else if (fdtdir[len - 1] != '/')
+		slash = "/";
+	else
+		slash = "";
+
+	len = strlen(fdtdir) + strlen(slash) + strlen(f1) + strlen(f2) +
+		strlen(f3) + strlen(f4) + 1;
+	fdtfile = malloc(len);
+	if (!fdtfile) {
+		printf("malloc fail (FDT filename)\n");
+		return NULL;
+	}
+
+	snprintf(fdtfile, len, "%s%s%s%s%s%s", fdtdir, slash, f1, f2, f3, f4);
+
+	return fdtfile;
+}
+
+/**
+ * label_run_boot() - Run the correct boot procedure
+ *
+ * fdt usage is optional:
+ * It handles the following scenarios.
+ *
+ * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is
+ * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to
+ * bootm, and adjust argc appropriately.
+ *
+ * If retrieve fails and no exact fdt blob is specified in pxe file with
+ * "fdt" label, try Scenario 2.
+ *
+ * Scenario 2: If there is an fdt_addr specified, pass it along to
+ * bootm, and adjust argc appropriately.
+ *
+ * Scenario 3: If there is an fdtcontroladdr specified, pass it along to
+ * bootm, and adjust argc appropriately, unless the image type is fitImage.
+ *
+ * Scenario 4: fdt blob is not available.
+ *
+ * @ctx: PXE context
+ * @label: Label to process
+ * @kernel_addr: string containing the kernel address / config
+ * @initrd_str: string containing the initrd address / size
+ * @initrd_addr_str: initrd address, or NULL if none
+ * @initrd_filesize: initrd size in bytes; only valid if initrd_addr_str is not
+ *	NULL
+ * Returns does not return on success, otherwise returns 0 if a localboot
+ *	label was processed, or 1 on error
+ */
+static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label,
+			  char *kernel_addr, char *initrd_str,
+			  char *initrd_addr_str, char *initrd_filesize)
+{
+	struct bootm_info bmi;
+	const char *fdt_addr;
+	ulong kernel_addr_r;
+	void *buf;
+	int ret;
+
+	if (IS_ENABLED(CONFIG_BOOTM))
+		bootm_init(&bmi);
+
+	fdt_addr = env_get("fdt_addr_r");
+
+	/* For FIT, the label can be identical to kernel one */
+	if (label->fdt && !strcmp(label->kernel_label, label->fdt)) {
+		fdt_addr = kernel_addr;
+	/* if fdt label is defined then get fdt from server */
+	} else if (fdt_addr) {
+		char *fdtfile = NULL;
+		char *fdtfilefree = NULL;
+
+		if (label->fdt) {
+			if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
+				if (strcmp("-", label->fdt))
+					fdtfile = label->fdt;
+			} else {
+				fdtfile = label->fdt;
+			}
+		} else if (label->fdtdir) {
+			fdtfilefree = calc_fdt_fname(label->fdtdir);
+			if (!fdtfilefree)
+				return -ENOMEM;
+			fdtfile = fdtfilefree;
+		}
+
+		if (fdtfile) {
+			int err = get_relfile_envaddr(ctx, fdtfile,
+						      "fdt_addr_r", NULL);
+
+			free(fdtfilefree);
+			if (err < 0) {
+				fdt_addr = NULL;
+
+				if (label->fdt) {
+					printf("Skipping %s for failure retrieving FDT\n",
+					       label->name);
+					return -ENOENT;
+				}
+
+				if (label->fdtdir) {
+					printf("Skipping fdtdir %s for failure retrieving dts\n",
+						label->fdtdir);
+				}
+			}
+
+			if (label->kaslrseed)
+				label_boot_kaslrseed();
+
+#ifdef CONFIG_OF_LIBFDT_OVERLAY
+			if (label->fdtoverlays)
+				label_boot_fdtoverlay(ctx, label);
+#endif
+		} else {
+			fdt_addr = NULL;
+		}
+	}
+
+	bmi.addr_img = kernel_addr;
+
+	if (initrd_addr_str)
+		bmi.conf_ramdisk = initrd_str;
+
+	if (!fdt_addr) {
+		if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
+			if (strcmp("-", label->fdt))
+				fdt_addr = env_get("fdt_addr");
+		} else {
+			fdt_addr = env_get("fdt_addr");
+		}
+	}
+
+	kernel_addr_r = genimg_get_kernel_addr(kernel_addr);
+	buf = map_sysmem(kernel_addr_r, 0);
+
+	if (!fdt_addr && genimg_get_format(buf) != IMAGE_FORMAT_FIT) {
+		if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
+			if (strcmp("-", label->fdt))
+				fdt_addr = env_get("fdtcontroladdr");
+		} else {
+			fdt_addr = env_get("fdtcontroladdr");
+		}
+	}
+
+	bmi.conf_fdt = fdt_addr;
+
+	/* Try bootm for legacy and FIT format image */
+	if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID &&
+	    IS_ENABLED(CONFIG_BOOTM))
+		ret = bootm_run(&bmi);
+	/* Try booting an AArch64 Linux kernel image */
+	else if (IS_ENABLED(CONFIG_BOOTM))
+		ret = booti_run(&bmi);
+	/* Try booting a Image */
+	else if (IS_ENABLED(CONFIG_BOOTM))
+		ret = bootz_run(&bmi);
+	/* Try booting an x86_64 Linux kernel image */
+	else if (IS_ENABLED(CONFIG_ZBOOT))
+		ret = zboot_run(hextoul(kernel_addr, NULL), 0,
+				initrd_addr_str ?
+					hextoul(initrd_addr_str, NULL) : 0,
+				initrd_addr_str ?
+					hextoul(initrd_filesize, NULL) : 0,
+				0, NULL);
+
+	unmap_sysmem(buf);
+
+	return 0;
+}
+
+/**
  * label_boot() - Boot according to the contents of a pxe_label
  *
  * If we can't boot for any reason, we return.  A successful boot never
@@ -491,8 +706,6 @@
  */
 static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
 {
-	char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
-	char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL };
 	char *kernel_addr = NULL;
 	char *initrd_addr_str = NULL;
 	char initrd_filesize[10];
@@ -500,11 +713,7 @@
 	char mac_str[29] = "";
 	char ip_str[68] = "";
 	char *fit_addr = NULL;
-	int bootm_argc = 2;
-	int zboot_argc = 3;
-	int len = 0;
-	ulong kernel_addr_r;
-	void *buf;
+	int ret;
 
 	label_print(label);
 
@@ -545,9 +754,10 @@
 
 	/* For FIT, the label can be identical to kernel one */
 	if (label->initrd && !strcmp(label->kernel_label, label->initrd)) {
-		initrd_addr_str =  kernel_addr;
+		initrd_addr_str = kernel_addr;
 	} else if (label->initrd) {
 		ulong size;
+
 		if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r",
 					&size) < 0) {
 			printf("Skipping %s for failure retrieving initrd\n",
@@ -593,7 +803,7 @@
 		}
 
 		if (label->append)
-			strncpy(bootargs, label->append, sizeof(bootargs));
+			strlcpy(bootargs, label->append, sizeof(bootargs));
 
 		strcat(bootargs, ip_str);
 		strcat(bootargs, mac_str);
@@ -604,180 +814,8 @@
 		printf("append: %s\n", finalbootargs);
 	}
 
-	/*
-	 * fdt usage is optional:
-	 * It handles the following scenarios.
-	 *
-	 * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is
-	 * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to
-	 * bootm, and adjust argc appropriately.
-	 *
-	 * If retrieve fails and no exact fdt blob is specified in pxe file with
-	 * "fdt" label, try Scenario 2.
-	 *
-	 * Scenario 2: If there is an fdt_addr specified, pass it along to
-	 * bootm, and adjust argc appropriately.
-	 *
-	 * Scenario 3: If there is an fdtcontroladdr specified, pass it along to
-	 * bootm, and adjust argc appropriately, unless the image type is fitImage.
-	 *
-	 * Scenario 4: fdt blob is not available.
-	 */
-	bootm_argv[3] = env_get("fdt_addr_r");
-
-	/* For FIT, the label can be identical to kernel one */
-	if (label->fdt && !strcmp(label->kernel_label, label->fdt)) {
-		bootm_argv[3] = kernel_addr;
-	/* if fdt label is defined then get fdt from server */
-	} else if (bootm_argv[3]) {
-		char *fdtfile = NULL;
-		char *fdtfilefree = NULL;
-
-		if (label->fdt) {
-			if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
-				if (strcmp("-", label->fdt))
-					fdtfile = label->fdt;
-			} else {
-				fdtfile = label->fdt;
-			}
-		} else if (label->fdtdir) {
-			char *f1, *f2, *f3, *f4, *slash;
-
-			f1 = env_get("fdtfile");
-			if (f1) {
-				f2 = "";
-				f3 = "";
-				f4 = "";
-			} else {
-				/*
-				 * For complex cases where this code doesn't
-				 * generate the correct filename, the board
-				 * code should set $fdtfile during early boot,
-				 * or the boot scripts should set $fdtfile
-				 * before invoking "pxe" or "sysboot".
-				 */
-				f1 = env_get("soc");
-				f2 = "-";
-				f3 = env_get("board");
-				f4 = ".dtb";
-				if (!f1) {
-					f1 = "";
-					f2 = "";
-				}
-				if (!f3) {
-					f2 = "";
-					f3 = "";
-				}
-			}
-
-			len = strlen(label->fdtdir);
-			if (!len)
-				slash = "./";
-			else if (label->fdtdir[len - 1] != '/')
-				slash = "/";
-			else
-				slash = "";
-
-			len = strlen(label->fdtdir) + strlen(slash) +
-				strlen(f1) + strlen(f2) + strlen(f3) +
-				strlen(f4) + 1;
-			fdtfilefree = malloc(len);
-			if (!fdtfilefree) {
-				printf("malloc fail (FDT filename)\n");
-				goto cleanup;
-			}
-
-			snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
-				 label->fdtdir, slash, f1, f2, f3, f4);
-			fdtfile = fdtfilefree;
-		}
-
-		if (fdtfile) {
-			int err = get_relfile_envaddr(ctx, fdtfile,
-						      "fdt_addr_r", NULL);
-
-			free(fdtfilefree);
-			if (err < 0) {
-				bootm_argv[3] = NULL;
-
-				if (label->fdt) {
-					printf("Skipping %s for failure retrieving FDT\n",
-					       label->name);
-					goto cleanup;
-				}
-
-				if (label->fdtdir) {
-					printf("Skipping fdtdir %s for failure retrieving dts\n",
-						label->fdtdir);
-				}
-			}
-
-			if (label->kaslrseed)
-				label_boot_kaslrseed();
-
-#ifdef CONFIG_OF_LIBFDT_OVERLAY
-			if (label->fdtoverlays)
-				label_boot_fdtoverlay(ctx, label);
-#endif
-		} else {
-			bootm_argv[3] = NULL;
-		}
-	}
-
-	bootm_argv[1] = kernel_addr;
-	zboot_argv[1] = kernel_addr;
-
-	if (initrd_addr_str) {
-		bootm_argv[2] = initrd_str;
-		bootm_argc = 3;
-
-		zboot_argv[3] = initrd_addr_str;
-		zboot_argv[4] = initrd_filesize;
-		zboot_argc = 5;
-	}
-
-	if (!bootm_argv[3]) {
-		if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
-			if (strcmp("-", label->fdt))
-				bootm_argv[3] = env_get("fdt_addr");
-		} else {
-			bootm_argv[3] = env_get("fdt_addr");
-		}
-	}
-
-	kernel_addr_r = genimg_get_kernel_addr(kernel_addr);
-	buf = map_sysmem(kernel_addr_r, 0);
-
-	if (!bootm_argv[3] && genimg_get_format(buf) != IMAGE_FORMAT_FIT) {
-		if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
-			if (strcmp("-", label->fdt))
-				bootm_argv[3] = env_get("fdtcontroladdr");
-		} else {
-			bootm_argv[3] = env_get("fdtcontroladdr");
-		}
-	}
-
-	if (bootm_argv[3]) {
-		if (!bootm_argv[2])
-			bootm_argv[2] = "-";
-		bootm_argc = 4;
-	}
-
-	/* Try bootm for legacy and FIT format image */
-	if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID &&
-            IS_ENABLED(CONFIG_CMD_BOOTM))
-		do_bootm(ctx->cmdtp, 0, bootm_argc, bootm_argv);
-	/* Try booting an AArch64 Linux kernel image */
-	else if (IS_ENABLED(CONFIG_CMD_BOOTI))
-		do_booti(ctx->cmdtp, 0, bootm_argc, bootm_argv);
-	/* Try booting a Image */
-	else if (IS_ENABLED(CONFIG_CMD_BOOTZ))
-		do_bootz(ctx->cmdtp, 0, bootm_argc, bootm_argv);
-	/* Try booting an x86_64 Linux kernel image */
-	else if (IS_ENABLED(CONFIG_CMD_ZBOOT))
-		do_zboot_parent(ctx->cmdtp, 0, zboot_argc, zboot_argv, NULL);
-
-	unmap_sysmem(buf);
+	ret = label_run_boot(ctx, label, kernel_addr, initrd_str,
+			     initrd_addr_str, initrd_filesize);
 
 cleanup:
 	free(fit_addr);
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 61e280f..8eeb99e 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -262,6 +262,7 @@
 
 config CMD_BOOTM
 	bool "bootm"
+	depends on BOOTM
 	default y
 	help
 	  Boot an application image from the memory.
@@ -333,48 +334,6 @@
 	help
 	  Boot an AArch64 Linux Kernel image from memory.
 
-config BOOTM_LINUX
-	bool "Support booting Linux OS images"
-	depends on CMD_BOOTM || CMD_BOOTZ || CMD_BOOTI
-	default y
-	help
-	  Support booting the Linux kernel directly via a command such as bootm
-	  or booti or bootz.
-
-config BOOTM_NETBSD
-	bool "Support booting NetBSD (non-EFI) loader images"
-	depends on CMD_BOOTM
-	default y
-	help
-	  Support booting NetBSD via the bootm command.
-
-config BOOTM_OPENRTOS
-	bool "Support booting OPENRTOS / FreeRTOS images"
-	depends on CMD_BOOTM
-	help
-	  Support booting OPENRTOS / FreeRTOS via the bootm command.
-
-config BOOTM_OSE
-	bool "Support booting Enea OSE images"
-	depends on (ARM && (ARM64 || CPU_V7A || CPU_V7R) || SANDBOX || PPC || X86)
-	depends on CMD_BOOTM
-	help
-	  Support booting Enea OSE images via the bootm command.
-
-config BOOTM_PLAN9
-	bool "Support booting Plan9 OS images"
-	depends on CMD_BOOTM
-	default y
-	help
-	  Support booting Plan9 images via the bootm command.
-
-config BOOTM_RTEMS
-	bool "Support booting RTEMS OS images"
-	depends on CMD_BOOTM
-	default y
-	help
-	  Support booting RTEMS images via the bootm command.
-
 config CMD_SEAMA
 	bool "Support read SEAMA NAND images"
 	depends on MTD_RAW_NAND
@@ -391,13 +350,6 @@
 	  is used to boot. Updating the parameters is not currently
 	  supported.
 
-config BOOTM_VXWORKS
-	bool "Support booting VxWorks OS images"
-	depends on CMD_BOOTM
-	default y
-	help
-	  Support booting VxWorks images via the bootm command.
-
 config CMD_BOOTEFI
 	bool "bootefi"
 	depends on EFI_LOADER
@@ -612,6 +564,8 @@
 
 config CMD_ZBOOT
 	bool "zboot - x86 boot command"
+	depends on ZBOOT
+	default y
 	help
 	  With x86 machines it is common to boot a bzImage file which
 	  contains both a kernel and a setup.bin file. The latter includes
@@ -1407,6 +1361,13 @@
 	help
 	  MTD commands support.
 
+config CMD_MTD_OTP
+	bool "mtd otp"
+	depends on CMD_MTD
+	select HEXDUMP
+	help
+	  MTD commands for OTP access.
+
 config CMD_MUX
 	bool "mux"
 	depends on MULTIPLEXER
@@ -2878,8 +2839,8 @@
 	  Enables a command to control using of function tracing within
 	  U-Boot. This allows recording of call traces including timing
 	  information. The command can write data to memory for exporting
-	  for analysis (e.g. using bootchart). See doc/README.trace for full
-	  details.
+	  for analysis (e.g. using bootchart). See doc/develop/trace.rst
+	  for full details.
 
 config CMD_AVB
 	bool "avb - Android Verified Boot 2.0 operations"
diff --git a/cmd/booti.c b/cmd/booti.c
index 898df0f..b9637b3 100644
--- a/cmd/booti.c
+++ b/cmd/booti.c
@@ -74,7 +74,7 @@
 	unmap_sysmem((void *)ld);
 
 	ret = booti_setup(ld, &relocated_addr, &image_size, false);
-	if (ret || IS_ENABLED(CONFIG_SANDBOX))
+	if (ret)
 		return 1;
 
 	/* Handle BOOTM_STATE_LOADOS */
diff --git a/cmd/fastboot.c b/cmd/fastboot.c
index c3c1923..792e83d 100644
--- a/cmd/fastboot.c
+++ b/cmd/fastboot.c
@@ -159,7 +159,7 @@
 		return CMD_RET_USAGE;
 	}
 
-	fastboot_init((void *)buf_addr, buf_size);
+	fastboot_init(buf_addr, buf_size);
 
 	if (!strcmp(argv[1], "udp"))
 		return do_fastboot_udp(argc, argv, buf_addr, buf_size);
diff --git a/cmd/mtd.c b/cmd/mtd.c
index 9083a68..9189f45 100644
--- a/cmd/mtd.c
+++ b/cmd/mtd.c
@@ -11,6 +11,9 @@
 #include <command.h>
 #include <common.h>
 #include <console.h>
+#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
+#include <hexdump.h>
+#endif
 #include <malloc.h>
 #include <mapmem.h>
 #include <mtd.h>
@@ -202,6 +205,221 @@
 	return true;
 }
 
+#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
+static int do_mtd_otp_read(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	struct mtd_info *mtd;
+	size_t retlen;
+	off_t from;
+	size_t len;
+	bool user;
+	int ret;
+	u8 *buf;
+
+	if (argc != 5)
+		return CMD_RET_USAGE;
+
+	if (!strcmp(argv[2], "u"))
+		user = true;
+	else if (!strcmp(argv[2], "f"))
+		user = false;
+	else
+		return CMD_RET_USAGE;
+
+	mtd = get_mtd_by_name(argv[1]);
+	if (IS_ERR_OR_NULL(mtd))
+		return CMD_RET_FAILURE;
+
+	from = simple_strtoul(argv[3], NULL, 0);
+	len = simple_strtoul(argv[4], NULL, 0);
+
+	ret = CMD_RET_FAILURE;
+
+	buf = malloc(len);
+	if (!buf)
+		goto put_mtd;
+
+	printf("Reading %s OTP from 0x%lx, %zu bytes\n",
+	       user ? "user" : "factory", from, len);
+
+	if (user)
+		ret = mtd_read_user_prot_reg(mtd, from, len, &retlen, buf);
+	else
+		ret = mtd_read_fact_prot_reg(mtd, from, len, &retlen, buf);
+	if (ret) {
+		free(buf);
+		pr_err("OTP read failed: %d\n", ret);
+		ret = CMD_RET_FAILURE;
+		goto put_mtd;
+	}
+
+	if (retlen != len)
+		pr_err("OTP read returns %zu, but %zu expected\n",
+		       retlen, len);
+
+	print_hex_dump("", 0, 16, 1, buf, retlen, true);
+
+	free(buf);
+
+	ret = CMD_RET_SUCCESS;
+
+put_mtd:
+	put_mtd_device(mtd);
+
+	return ret;
+}
+
+static int do_mtd_otp_lock(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	struct mtd_info *mtd;
+	off_t from;
+	size_t len;
+	int ret;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	mtd = get_mtd_by_name(argv[1]);
+	if (IS_ERR_OR_NULL(mtd))
+		return CMD_RET_FAILURE;
+
+	from = simple_strtoul(argv[2], NULL, 0);
+	len = simple_strtoul(argv[3], NULL, 0);
+
+	ret = mtd_lock_user_prot_reg(mtd, from, len);
+	if (ret) {
+		pr_err("OTP lock failed: %d\n", ret);
+		ret = CMD_RET_FAILURE;
+		goto put_mtd;
+	}
+
+	ret = CMD_RET_SUCCESS;
+
+put_mtd:
+	put_mtd_device(mtd);
+
+	return ret;
+}
+
+static int do_mtd_otp_write(struct cmd_tbl *cmdtp, int flag, int argc,
+			    char *const argv[])
+{
+	struct mtd_info *mtd;
+	size_t retlen;
+	size_t binlen;
+	u8 *binbuf;
+	off_t from;
+	int ret;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	mtd = get_mtd_by_name(argv[1]);
+	if (IS_ERR_OR_NULL(mtd))
+		return CMD_RET_FAILURE;
+
+	from = simple_strtoul(argv[2], NULL, 0);
+	binlen = strlen(argv[3]) / 2;
+
+	ret = CMD_RET_FAILURE;
+	binbuf = malloc(binlen);
+	if (!binbuf)
+		goto put_mtd;
+
+	hex2bin(binbuf, argv[3], binlen);
+
+	printf("Will write:\n");
+
+	print_hex_dump("", 0, 16, 1, binbuf, binlen, true);
+
+	printf("to 0x%lx\n", from);
+
+	printf("Continue (y/n)?\n");
+
+	if (confirm_yesno() != 1) {
+		pr_err("OTP write canceled\n");
+		ret = CMD_RET_SUCCESS;
+		goto put_mtd;
+	}
+
+	ret = mtd_write_user_prot_reg(mtd, from, binlen, &retlen, binbuf);
+	if (ret) {
+		pr_err("OTP write failed: %d\n", ret);
+		ret = CMD_RET_FAILURE;
+		goto put_mtd;
+	}
+
+	if (retlen != binlen)
+		pr_err("OTP write returns %zu, but %zu expected\n",
+		       retlen, binlen);
+
+	ret = CMD_RET_SUCCESS;
+
+put_mtd:
+	free(binbuf);
+	put_mtd_device(mtd);
+
+	return ret;
+}
+
+static int do_mtd_otp_info(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	struct otp_info otp_info;
+	struct mtd_info *mtd;
+	size_t retlen;
+	bool user;
+	int ret;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	if (!strcmp(argv[2], "u"))
+		user = true;
+	else if (!strcmp(argv[2], "f"))
+		user = false;
+	else
+		return CMD_RET_USAGE;
+
+	mtd = get_mtd_by_name(argv[1]);
+	if (IS_ERR_OR_NULL(mtd))
+		return CMD_RET_FAILURE;
+
+	if (user)
+		ret = mtd_get_user_prot_info(mtd, sizeof(otp_info), &retlen,
+					     &otp_info);
+	else
+		ret = mtd_get_fact_prot_info(mtd, sizeof(otp_info), &retlen,
+					     &otp_info);
+	if (ret) {
+		pr_err("OTP info failed: %d\n", ret);
+		ret = CMD_RET_FAILURE;
+		goto put_mtd;
+	}
+
+	if (retlen != sizeof(otp_info)) {
+		pr_err("OTP info returns %zu, but %zu expected\n",
+		       retlen, sizeof(otp_info));
+		ret = CMD_RET_FAILURE;
+		goto put_mtd;
+	}
+
+	printf("%s OTP region info:\n", user ? "User" : "Factory");
+	printf("\tstart: %u\n", otp_info.start);
+	printf("\tlength: %u\n", otp_info.length);
+	printf("\tlocked: %u\n", otp_info.locked);
+
+	ret = CMD_RET_SUCCESS;
+
+put_mtd:
+	put_mtd_device(mtd);
+
+	return ret;
+}
+#endif
+
 static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc,
 		       char *const argv[])
 {
@@ -551,6 +769,12 @@
 	"\n"
 	"Specific functions:\n"
 	"mtd bad                               <name>\n"
+#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
+	"mtd otpread                           <name> [u|f] <off> <size>\n"
+	"mtd otpwrite                          <name> <off> <hex string>\n"
+	"mtd otplock                           <name> <off> <size>\n"
+	"mtd otpinfo                           <name> [u|f]\n"
+#endif
 	"\n"
 	"With:\n"
 	"\t<name>: NAND partition/chip name (or corresponding DM device name or OF path)\n"
@@ -561,10 +785,20 @@
 	"\t<size>: length of the operation in bytes (default: the entire device)\n"
 	"\t\t* must be a multiple of a block for erase\n"
 	"\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n"
+#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
+	"\t<hex string>: hex string without '0x' and spaces. Example: ABCD1234\n"
+	"\t[u|f]: user or factory OTP region\n"
+#endif
 	"\n"
 	"The .dontskipff option forces writing empty pages, don't use it if unsure.\n");
 
 U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text,
+#if CONFIG_IS_ENABLED(CMD_MTD_OTP)
+		U_BOOT_SUBCMD_MKENT(otpread, 5, 1, do_mtd_otp_read),
+		U_BOOT_SUBCMD_MKENT(otpwrite, 4, 1, do_mtd_otp_write),
+		U_BOOT_SUBCMD_MKENT(otplock, 4, 1, do_mtd_otp_lock),
+		U_BOOT_SUBCMD_MKENT(otpinfo, 3, 1, do_mtd_otp_info),
+#endif
 		U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list),
 		U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io,
 					     mtd_name_complete),
diff --git a/cmd/sf.c b/cmd/sf.c
index 730996c..e386689 100644
--- a/cmd/sf.c
+++ b/cmd/sf.c
@@ -135,8 +135,9 @@
 	}
 	flash = NULL;
 	if (use_dt) {
-		spi_flash_probe_bus_cs(bus, cs, &new);
-		flash = dev_get_uclass_priv(new);
+		ret = spi_flash_probe_bus_cs(bus, cs, &new);
+		if (!ret)
+			flash = dev_get_uclass_priv(new);
 	} else {
 		flash = spi_flash_probe(bus, cs, speed, mode);
 	}
diff --git a/cmd/sysboot.c b/cmd/sysboot.c
index 63a7806..d14c570 100644
--- a/cmd/sysboot.c
+++ b/cmd/sysboot.c
@@ -77,6 +77,10 @@
 
 	if (argc < 6) {
 		filename = env_get("bootfile");
+		if (!filename) {
+			printf("Specify a filename or set the ${bootfile} environment variable\n");
+			return 1;
+		}
 	} else {
 		filename = argv[5];
 		env_set("bootfile", filename);
diff --git a/cmd/x86/Makefile b/cmd/x86/Makefile
index 5f82204..b1f39d3 100644
--- a/cmd/x86/Makefile
+++ b/cmd/x86/Makefile
@@ -5,3 +5,4 @@
 obj-$(CONFIG_CMD_EXCEPTION) += exception.o
 obj-$(CONFIG_USE_HOB) += hob.o
 obj-$(CONFIG_HAVE_FSP) += fsp.o
+obj-$(CONFIG_CMD_ZBOOT) += zboot.o
diff --git a/cmd/x86/zboot.c b/cmd/x86/zboot.c
new file mode 100644
index 0000000..addf28c
--- /dev/null
+++ b/cmd/x86/zboot.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
+ */
+
+#include <command.h>
+#include <mapmem.h>
+#include <vsprintf.h>
+#include <asm/zimage.h>
+
+static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc,
+			  char *const argv[])
+{
+	ulong bzimage_addr = 0, bzimage_size, initrd_addr, initrd_size;
+	ulong base_addr;
+	const char *s, *cmdline;
+
+	/* argv[1] holds the address of the bzImage */
+	s = cmd_arg1(argc, argv) ? : env_get("fileaddr");
+	if (s)
+		bzimage_addr = hextoul(s, NULL);
+	bzimage_size = argc > 2 ? hextoul(argv[2], NULL) : 0;
+	initrd_addr = argc > 3 ? hextoul(argv[3], NULL) : 0;
+	initrd_size = argc > 4 ? hextoul(argv[4], NULL) : 0;
+	base_addr = argc > 5 ? hextoul(argv[5], NULL) : 0;
+	cmdline = argc > 6 ? env_get(argv[6]) : NULL;
+
+	zboot_start(bzimage_addr, bzimage_size, initrd_addr, initrd_size,
+		    base_addr, cmdline);
+
+	return 0;
+}
+
+static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	int ret;
+
+	ret = zboot_load();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc,
+			  char *const argv[])
+{
+	if (!state.base_ptr) {
+		printf("base is not set: use 'zboot load' first\n");
+		return CMD_RET_FAILURE;
+	}
+	if (zboot_setup()) {
+		puts("Setting up boot parameters failed ...\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (zboot_setup())
+		return CMD_RET_FAILURE;
+
+	return 0;
+}
+
+static int do_zboot_info(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	zboot_info();
+
+	return 0;
+}
+
+static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
+		       char *const argv[])
+{
+	int ret;
+
+	ret = zboot_go();
+	if (ret) {
+		printf("Kernel returned! (err=%d)\n", ret);
+		return CMD_RET_FAILURE;
+	}
+
+	return 0;
+}
+
+static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	struct boot_params *base_ptr = state.base_ptr;
+
+	if (argc > 1)
+		base_ptr = (void *)hextoul(argv[1], NULL);
+	if (!base_ptr) {
+		printf("No zboot setup_base\n");
+		return CMD_RET_FAILURE;
+	}
+	zimage_dump(base_ptr, true);
+
+	return 0;
+}
+
+/* Note: This defines the complete_zboot() function */
+U_BOOT_SUBCMDS(zboot,
+	U_BOOT_CMD_MKENT(start, 8, 1, do_zboot_start, "", ""),
+	U_BOOT_CMD_MKENT(load, 1, 1, do_zboot_load, "", ""),
+	U_BOOT_CMD_MKENT(setup, 1, 1, do_zboot_setup, "", ""),
+	U_BOOT_CMD_MKENT(info, 1, 1, do_zboot_info, "", ""),
+	U_BOOT_CMD_MKENT(go, 1, 1, do_zboot_go, "", ""),
+	U_BOOT_CMD_MKENT(dump, 2, 1, do_zboot_dump, "", ""),
+)
+
+int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[], int state_mask)
+{
+	int ret;
+
+	if (flag & ZBOOT_STATE_START)
+		ret = do_zboot_start(cmdtp, flag, argc, argv);
+	if (!ret && (flag & ZBOOT_STATE_LOAD))
+		ret = do_zboot_load(cmdtp, flag, argc, argv);
+	if (!ret && (flag & ZBOOT_STATE_SETUP))
+		ret = do_zboot_setup(cmdtp, flag, argc, argv);
+	if (!ret && (flag & ZBOOT_STATE_INFO))
+		ret = do_zboot_info(cmdtp, flag, argc, argv);
+	if (!ret && (flag & ZBOOT_STATE_GO))
+		ret = do_zboot_go(cmdtp, flag, argc, argv);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int do_zboot_parent(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[], int *repeatable)
+{
+	/* determine if we have a sub command */
+	if (argc > 1) {
+		char *endp;
+
+		hextoul(argv[1], &endp);
+		/*
+		 * endp pointing to nul means that argv[1] was just a valid
+		 * number, so pass it along to the normal processing
+		 */
+		if (*endp)
+			return do_zboot(cmdtp, flag, argc, argv, repeatable);
+	}
+
+	do_zboot_states(cmdtp, flag, argc, argv, ZBOOT_STATE_START |
+			ZBOOT_STATE_LOAD | ZBOOT_STATE_SETUP |
+			ZBOOT_STATE_INFO | ZBOOT_STATE_GO);
+
+	return CMD_RET_FAILURE;
+}
+
+U_BOOT_CMDREP_COMPLETE(
+	zboot, 8, do_zboot_parent, "Boot bzImage",
+	"[addr] [size] [initrd addr] [initrd size] [setup] [cmdline]\n"
+	"      addr -        The optional starting address of the bzimage.\n"
+	"                    If not set it defaults to the environment\n"
+	"                    variable \"fileaddr\".\n"
+	"      size -        The optional size of the bzimage. Defaults to\n"
+	"                    zero.\n"
+	"      initrd addr - The address of the initrd image to use, if any.\n"
+	"      initrd size - The size of the initrd image to use, if any.\n"
+	"      setup -       The address of the kernel setup region, if this\n"
+	"                    is not at addr\n"
+	"      cmdline -     Environment variable containing the kernel\n"
+	"                    command line, to override U-Boot's normal\n"
+	"                    cmdline generation\n"
+	"\n"
+	"Sub-commands to do part of the zboot sequence:\n"
+	"\tstart [addr [arg ...]] - specify arguments\n"
+	"\tload   - load OS image\n"
+	"\tsetup  - set up table\n"
+	"\tinfo   - show summary info\n"
+	"\tgo     - start OS\n"
+	"\tdump [addr]    - dump info (optional address of boot params)",
+	complete_zboot
+);
diff --git a/common/board_f.c b/common/board_f.c
index 8bada6f..039d6d7 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -718,6 +718,7 @@
 	return 0;
 }
 
+void mcheck_on_ramrelocation(size_t offset);
 static int setup_reloc(void)
 {
 	if (!(gd->flags & GD_FLG_SKIP_RELOC)) {
@@ -743,6 +744,9 @@
 	if (gd->flags & GD_FLG_SKIP_RELOC) {
 		debug("Skipping relocation due to flag\n");
 	} else {
+#ifdef MCHECK_HEAP_PROTECTION
+		mcheck_on_ramrelocation(gd->reloc_off);
+#endif
 		debug("Relocation Offset is: %08lx\n", gd->reloc_off);
 		debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
 		      gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
diff --git a/common/cli.c b/common/cli.c
index a349382..1c33daf 100644
--- a/common/cli.c
+++ b/common/cli.c
@@ -11,6 +11,7 @@
 #define pr_fmt(fmt) "cli: %s: " fmt, __func__
 
 #include <common.h>
+#include <ansi.h>
 #include <bootstage.h>
 #include <cli.h>
 #include <cli_hush.h>
@@ -336,4 +337,7 @@
 #if defined(CONFIG_HUSH_INIT_VAR)
 	hush_init_var();
 #endif
+
+	if (CONFIG_IS_ENABLED(VIDEO_ANSI))
+		printf(ANSI_CURSOR_SHOW "\n");
 }
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index de3f042..a061621 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -32,6 +32,21 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifdef MCHECK_HEAP_PROTECTION
+ #define STATIC_IF_MCHECK static
+ #undef MALLOC_COPY
+ #undef MALLOC_ZERO
+static inline void MALLOC_ZERO(void *p, size_t sz) { memset(p, 0, sz); }
+static inline void MALLOC_COPY(void *dest, const void *src, size_t sz) { memcpy(dest, src, sz); }
+#else
+ #define STATIC_IF_MCHECK
+ #define mALLOc_impl mALLOc
+ #define fREe_impl fREe
+ #define rEALLOc_impl rEALLOc
+ #define mEMALIGn_impl mEMALIGn
+ #define cALLOc_impl cALLOc
+#endif
+
 /*
   Emulation of sbrk for WIN32
   All code within the ifdef WIN32 is untested by me.
@@ -1270,10 +1285,11 @@
 
 */
 
+STATIC_IF_MCHECK
 #if __STD_C
-Void_t* mALLOc(size_t bytes)
+Void_t* mALLOc_impl(size_t bytes)
 #else
-Void_t* mALLOc(bytes) size_t bytes;
+Void_t* mALLOc_impl(bytes) size_t bytes;
 #endif
 {
   mchunkptr victim;                  /* inspected/selected chunk */
@@ -1555,10 +1571,11 @@
 */
 
 
+STATIC_IF_MCHECK
 #if __STD_C
-void fREe(Void_t* mem)
+void fREe_impl(Void_t* mem)
 #else
-void fREe(mem) Void_t* mem;
+void fREe_impl(mem) Void_t* mem;
 #endif
 {
   mchunkptr p;         /* chunk corresponding to mem */
@@ -1696,10 +1713,11 @@
 */
 
 
+STATIC_IF_MCHECK
 #if __STD_C
-Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+Void_t* rEALLOc_impl(Void_t* oldmem, size_t bytes)
 #else
-Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+Void_t* rEALLOc_impl(oldmem, bytes) Void_t* oldmem; size_t bytes;
 #endif
 {
   INTERNAL_SIZE_T    nb;      /* padded request size */
@@ -1725,7 +1743,7 @@
 
 #ifdef REALLOC_ZERO_BYTES_FREES
   if (!bytes) {
-	fREe(oldmem);
+	fREe_impl(oldmem);
 	return NULL;
   }
 #endif
@@ -1733,7 +1751,7 @@
   if ((long)bytes < 0) return NULL;
 
   /* realloc of null is supposed to be same as malloc */
-  if (oldmem == NULL) return mALLOc(bytes);
+  if (oldmem == NULL) return mALLOc_impl(bytes);
 
 #if CONFIG_IS_ENABLED(SYS_MALLOC_F)
 	if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
@@ -1758,7 +1776,7 @@
     /* Note the extra SIZE_SZ overhead. */
     if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
     /* Must alloc, copy, free. */
-    newmem = mALLOc(bytes);
+    newmem = mALLOc_impl(bytes);
     if (!newmem)
 	return NULL; /* propagate failure */
     MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
@@ -1869,7 +1887,7 @@
 
     /* Must allocate */
 
-    newmem = mALLOc (bytes);
+    newmem = mALLOc_impl (bytes);
 
     if (newmem == NULL)  /* propagate failure */
       return NULL;
@@ -1886,7 +1904,7 @@
 
     /* Otherwise copy, free, and exit */
     MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
-    fREe(oldmem);
+    fREe_impl(oldmem);
     return newmem;
   } else {
     VALGRIND_RESIZEINPLACE_BLOCK(oldmem, 0, bytes, SIZE_SZ);
@@ -1905,7 +1923,7 @@
     set_inuse_bit_at_offset(remainder, remainder_size);
     VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(remainder), remainder_size, SIZE_SZ,
 			      false);
-    fREe(chunk2mem(remainder)); /* let free() deal with it */
+    fREe_impl(chunk2mem(remainder)); /* let free() deal with it */
   }
   else
   {
@@ -1939,10 +1957,11 @@
 */
 
 
+STATIC_IF_MCHECK
 #if __STD_C
-Void_t* mEMALIGn(size_t alignment, size_t bytes)
+Void_t* mEMALIGn_impl(size_t alignment, size_t bytes)
 #else
-Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+Void_t* mEMALIGn_impl(alignment, bytes) size_t alignment; size_t bytes;
 #endif
 {
   INTERNAL_SIZE_T    nb;      /* padded  request size */
@@ -1965,7 +1984,7 @@
 
   /* If need less alignment than we give anyway, just relay to malloc */
 
-  if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+  if (alignment <= MALLOC_ALIGNMENT) return mALLOc_impl(bytes);
 
   /* Otherwise, ensure that it is at least a minimum chunk size */
 
@@ -1974,7 +1993,7 @@
   /* Call malloc with worst case padding to hit alignment. */
 
   nb = request2size(bytes);
-  m  = (char*)(mALLOc(nb + alignment + MINSIZE));
+  m  = (char*)(mALLOc_impl(nb + alignment + MINSIZE));
 
   /*
   * The attempt to over-allocate (with a size large enough to guarantee the
@@ -1990,7 +2009,7 @@
      * Use bytes not nb, since mALLOc internally calls request2size too, and
      * each call increases the size to allocate, to account for the header.
      */
-    m  = (char*)(mALLOc(bytes));
+    m  = (char*)(mALLOc_impl(bytes));
     /* Aligned -> return it */
     if ((((unsigned long)(m)) % alignment) == 0)
       return m;
@@ -1998,10 +2017,10 @@
      * Otherwise, try again, requesting enough extra space to be able to
      * acquire alignment.
      */
-    fREe(m);
+    fREe_impl(m);
     /* Add in extra bytes to match misalignment of unexpanded allocation */
     extra = alignment - (((unsigned long)(m)) % alignment);
-    m  = (char*)(mALLOc(bytes + extra));
+    m  = (char*)(mALLOc_impl(bytes + extra));
     /*
      * m might not be the same as before. Validate that the previous value of
      * extra still works for the current value of m.
@@ -2010,7 +2029,7 @@
     if (m) {
       extra2 = alignment - (((unsigned long)(m)) % alignment);
       if (extra2 > extra) {
-        fREe(m);
+        fREe_impl(m);
         m = NULL;
       }
     }
@@ -2060,7 +2079,7 @@
     set_head(newp, newsize | PREV_INUSE);
     set_inuse_bit_at_offset(newp, newsize);
     set_head_size(p, leadsize);
-    fREe(chunk2mem(p));
+    fREe_impl(chunk2mem(p));
     p = newp;
     VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(p), bytes, SIZE_SZ, false);
 
@@ -2078,7 +2097,7 @@
     set_head_size(p, nb);
     VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(remainder), remainder_size, SIZE_SZ,
 			      false);
-    fREe(chunk2mem(remainder));
+    fREe_impl(chunk2mem(remainder));
   }
 
   check_inuse_chunk(p);
@@ -2126,10 +2145,11 @@
 
 */
 
+STATIC_IF_MCHECK
 #if __STD_C
-Void_t* cALLOc(size_t n, size_t elem_size)
+Void_t* cALLOc_impl(size_t n, size_t elem_size)
 #else
-Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+Void_t* cALLOc_impl(n, elem_size) size_t n; size_t elem_size;
 #endif
 {
   mchunkptr p;
@@ -2145,7 +2165,7 @@
   INTERNAL_SIZE_T oldtopsize = chunksize(top);
 #endif
 #endif
-  Void_t* mem = mALLOc (sz);
+  Void_t* mem = mALLOc_impl (sz);
 
   if ((long)n < 0) return NULL;
 
@@ -2204,6 +2224,90 @@
 }
 #endif
 
+
+#ifdef MCHECK_HEAP_PROTECTION
+ #include "mcheck_core.inc.h"
+ #if !__STD_C
+  #error "must have __STD_C"
+ #endif
+
+Void_t *mALLOc(size_t bytes)
+{
+	mcheck_pedantic_prehook();
+	size_t fullsz = mcheck_alloc_prehook(bytes);
+	void *p = mALLOc_impl(fullsz);
+
+	if (!p)
+		return p;
+	return mcheck_alloc_posthook(p, bytes);
+}
+
+void fREe(Void_t *mem) { fREe_impl(mcheck_free_prehook(mem)); }
+
+Void_t *rEALLOc(Void_t *oldmem, size_t bytes)
+{
+	mcheck_pedantic_prehook();
+	if (bytes == 0) {
+		if (oldmem)
+			fREe(oldmem);
+		return NULL;
+	}
+
+	if (oldmem == NULL)
+		return mALLOc(bytes);
+
+	void *p = mcheck_reallocfree_prehook(oldmem);
+	size_t newsz = mcheck_alloc_prehook(bytes);
+
+	p = rEALLOc_impl(p, newsz);
+	if (!p)
+		return p;
+	return mcheck_alloc_noclean_posthook(p, bytes);
+}
+
+Void_t *mEMALIGn(size_t alignment, size_t bytes)
+{
+	mcheck_pedantic_prehook();
+	size_t fullsz = mcheck_memalign_prehook(alignment, bytes);
+	void *p = mEMALIGn_impl(alignment, fullsz);
+
+	if (!p)
+		return p;
+	return mcheck_memalign_posthook(alignment, p, bytes);
+}
+
+// pvALLOc, vALLOc - redirect to mEMALIGn, defined here, so they need no wrapping.
+
+Void_t *cALLOc(size_t n, size_t elem_size)
+{
+	mcheck_pedantic_prehook();
+	// NB: here is no overflow check.
+	size_t fullsz = mcheck_alloc_prehook(n * elem_size);
+	void *p = cALLOc_impl(1, fullsz);
+
+	if (!p)
+		return p;
+	return mcheck_alloc_noclean_posthook(p, n * elem_size);
+}
+
+// mcheck API {
+int mcheck_pedantic(mcheck_abortfunc_t f)
+{
+	mcheck_initialize(f, 1);
+	return 0;
+}
+
+int mcheck(mcheck_abortfunc_t f)
+{
+	mcheck_initialize(f, 0);
+	return 0;
+}
+
+void mcheck_check_all(void) { mcheck_pedantic_check(); }
+
+enum mcheck_status mprobe(void *__ptr) { return mcheck_mprobe(__ptr); }
+// mcheck API }
+#endif
 
 
 /*
diff --git a/common/mcheck_core.inc.h b/common/mcheck_core.inc.h
new file mode 100644
index 0000000..6902140
--- /dev/null
+++ b/common/mcheck_core.inc.h
@@ -0,0 +1,304 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Written by Eugene Uriev, based on glibc 2.0 prototype of Mike Haertel.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ * <https://www.gnu.org/licenses/>
+ */
+
+/*
+ * TL;DR: this is a porting of glibc mcheck into U-Boot
+ *
+ * This file contains no entities for external linkage.
+ * So mcheck protection may be used in parallel, e.g. for "malloc_simple(..)" and "malloc(..)".
+ * To do so, the file should be shared/include twice, - without linkage conflicts.
+ * I.e. "core"-part is shared as a source, but not as a binary.
+ * Maybe some optimization here make sense, to engage more binary sharing too.
+ * But, currently I strive to keep it as simple, as possible.
+ * And this, programmers'-only, mode don't pretend to be main.
+ *
+ * This library is aware of U-Boot specific. It's also aware of ARM alignment concerns.
+ * Unlike glibc-clients, U-Boot has limited malloc-usage, and only one thread.
+ * So it's better to make the protection heavier.
+ * Thus overflow canary here is greater, than glibc's one. Underflow canary is bigger too.
+ * U-Boot also allows to use fixed-size heap-registry, instead of double-linked list in glibc.
+ *
+ * Heavy canary allows to catch not only memset(..)-errors,
+ * but overflow/underflow of struct-array access:
+ *	{
+ *		struct mystruct* p = malloc(sizeof(struct mystruct) * N);
+ *		p[-1].field1 = 0;
+ *		p[N].field2 = 13;
+ *	}
+ * TODO: In order to guarantee full coverage of that kind of errors, a user can add variable-size
+ *       canaries here. So pre- and post-canary with size >= reqested_size, could be provided
+ *       (with the price of 3x heap-usage). Therefore, it would catch 100% of changes beyond
+ *       an array, for index(+1/-1) errors.
+ *
+ * U-Boot is a BL, not an OS with a lib. Activity of the library is set not in runtime,
+ * rather in compile-time, by MCHECK_HEAP_PROTECTION macro. That guarantees that
+ * we haven't missed first malloc.
+ */
+
+/*
+ * Testing
+ *  This library had been successfully tested for U-Boot @ ARM SoC chip / 64bits.
+ *  Proven for both default and pedantic mode: confirms U-Boot to be clean, and catches
+ *  intentional/testing corruptions. Working with malloc_trim is not tested.
+ */
+#ifndef _MCHECKCORE_INC_H
+#define _MCHECKCORE_INC_H      1
+#include "mcheck.h"
+
+#if defined(MCHECK_HEAP_PROTECTION)
+#define mcheck_flood memset
+
+// these are from /dev/random:
+#define MAGICWORD	0x99ccf430fa562a05ULL
+#define MAGICFREE	0x4875e63c0c6fc08eULL
+#define MAGICTAIL	0x918dbcd7df78dcd6ULL
+#define MALLOCFLOOD	((char)0xb6)
+#define FREEFLOOD	((char)0xf5)
+#define PADDINGFLOOD	((char)0x58)
+
+// my normal run demands 4427-6449 chunks:
+#define REGISTRY_SZ	6608
+#define CANARY_DEPTH	2
+
+// avoid problems with BSS at early stage:
+static char mcheck_pedantic_flag __section(".data") = 0;
+static void *mcheck_registry[REGISTRY_SZ] __section(".data") = {0};
+static size_t mcheck_chunk_count __section(".data") = 0;
+static size_t mcheck_chunk_count_max __section(".data") = 0;
+
+typedef unsigned long long mcheck_elem;
+typedef struct {
+	mcheck_elem elems[CANARY_DEPTH];
+} mcheck_canary;
+struct mcheck_hdr {
+	size_t size; /* Exact size requested by user.  */
+	size_t aln_skip; /* Ignored bytes, before the mcheck_hdr, to fulfill alignment */
+	mcheck_canary canary; /* Magic number to check header integrity.  */
+};
+
+static void mcheck_default_abort(enum mcheck_status status, const void *p)
+{
+	const char *msg;
+
+	switch (status) {
+	case MCHECK_OK:
+		msg = "memory is consistent, library is buggy\n";
+		break;
+	case MCHECK_HEAD:
+		msg = "memory clobbered before allocated block\n";
+		break;
+	case MCHECK_TAIL:
+		msg = "memory clobbered past end of allocated block\n";
+		break;
+	case MCHECK_FREE:
+		msg = "block freed twice\n";
+		break;
+	default:
+		msg = "bogus mcheck_status, library is buggy\n";
+		break;
+	}
+	printf("\n\nmcheck: %p:%s!!! [%zu]\n\n", p, msg, mcheck_chunk_count_max);
+}
+
+static mcheck_abortfunc_t mcheck_abortfunc = &mcheck_default_abort;
+
+static inline size_t allign_size_up(size_t sz, size_t grain)
+{
+	return (sz + grain - 1) & ~(grain - 1);
+}
+
+#define mcheck_allign_customer_size(SZ) allign_size_up(SZ, sizeof(mcheck_elem))
+#define mcheck_evaluate_memalign_prefix_size(ALIGN) allign_size_up(sizeof(struct mcheck_hdr), ALIGN)
+
+static enum mcheck_status mcheck_OnNok(enum mcheck_status status, const void *p)
+{
+	(*mcheck_abortfunc)(status, p);
+	return status;
+}
+
+static enum mcheck_status mcheck_checkhdr(const struct mcheck_hdr *hdr)
+{
+	int i;
+
+	for (i = 0; i < CANARY_DEPTH; ++i)
+		if (hdr->canary.elems[i] == MAGICFREE)
+			return mcheck_OnNok(MCHECK_FREE, hdr + 1);
+
+	for (i = 0; i < CANARY_DEPTH; ++i)
+		if (hdr->canary.elems[i] != MAGICWORD)
+			return mcheck_OnNok(MCHECK_HEAD, hdr + 1);
+
+	const size_t payload_size = hdr->size;
+	const size_t payload_size_aligned = mcheck_allign_customer_size(payload_size);
+	const size_t padd_size = payload_size_aligned - hdr->size;
+
+	const char *payload = (const char *)&hdr[1];
+
+	for (i = 0; i < padd_size; ++i)
+		if (payload[payload_size + i] != PADDINGFLOOD)
+			return mcheck_OnNok(MCHECK_TAIL, hdr + 1);
+
+	const mcheck_canary *tail = (const mcheck_canary *)&payload[payload_size_aligned];
+
+	for (i = 0; i < CANARY_DEPTH; ++i)
+		if (tail->elems[i] != MAGICTAIL)
+			return mcheck_OnNok(MCHECK_TAIL, hdr + 1);
+	return MCHECK_OK;
+}
+
+enum { KEEP_CONTENT = 0, CLEAN_CONTENT, ANY_ALIGNMENT = 1 };
+static void *mcheck_free_helper(void *ptr, int clean_content)
+{
+	if (!ptr)
+		return ptr;
+
+	struct mcheck_hdr *hdr = &((struct mcheck_hdr *)ptr)[-1];
+	int i;
+
+	mcheck_checkhdr(hdr);
+	for (i = 0; i < CANARY_DEPTH; ++i)
+		hdr->canary.elems[i] = MAGICFREE;
+
+	if (clean_content)
+		mcheck_flood(ptr, FREEFLOOD, mcheck_allign_customer_size(hdr->size));
+
+	for (i = 0; i < REGISTRY_SZ; ++i)
+		if (mcheck_registry[i] == hdr) {
+			mcheck_registry[i] = 0;
+			break;
+		}
+
+	--mcheck_chunk_count;
+	return (char *)hdr - hdr->aln_skip;
+}
+
+static void *mcheck_free_prehook(void *ptr) { return mcheck_free_helper(ptr, CLEAN_CONTENT); }
+static void *mcheck_reallocfree_prehook(void *ptr) { return mcheck_free_helper(ptr, KEEP_CONTENT); }
+
+static size_t mcheck_alloc_prehook(size_t sz)
+{
+	sz = mcheck_allign_customer_size(sz);
+	return sizeof(struct mcheck_hdr) + sz + sizeof(mcheck_canary);
+}
+
+static void *mcheck_allocated_helper(void *altoghether_ptr, size_t customer_sz,
+				     size_t alignment, int clean_content)
+{
+	const size_t slop = alignment ?
+		mcheck_evaluate_memalign_prefix_size(alignment) - sizeof(struct mcheck_hdr) : 0;
+	struct mcheck_hdr *hdr = (struct mcheck_hdr *)((char *)altoghether_ptr + slop);
+	int i;
+
+	hdr->size = customer_sz;
+	hdr->aln_skip = slop;
+	for (i = 0; i < CANARY_DEPTH; ++i)
+		hdr->canary.elems[i] = MAGICWORD;
+
+	char *payload = (char *)&hdr[1];
+
+	if (clean_content)
+		mcheck_flood(payload, MALLOCFLOOD, customer_sz);
+
+	const size_t customer_size_aligned = mcheck_allign_customer_size(customer_sz);
+
+	mcheck_flood(payload + customer_sz, PADDINGFLOOD, customer_size_aligned - customer_sz);
+
+	mcheck_canary *tail = (mcheck_canary *)&payload[customer_size_aligned];
+
+	for (i = 0; i < CANARY_DEPTH; ++i)
+		tail->elems[i] = MAGICTAIL;
+
+	++mcheck_chunk_count;
+	if (mcheck_chunk_count > mcheck_chunk_count_max)
+		mcheck_chunk_count_max = mcheck_chunk_count;
+
+	for (i = 0; i < REGISTRY_SZ; ++i)
+		if (!mcheck_registry[i]) {
+			mcheck_registry[i] = hdr;
+			return payload; // normal end
+		}
+
+	static char *overflow_msg = "\n\n\nERROR: mcheck registry overflow, pedantic check would be incomplete!!\n\n\n\n";
+
+	printf("%s", overflow_msg);
+	overflow_msg = "(mcheck registry full)";
+	return payload;
+}
+
+static void *mcheck_alloc_posthook(void *altoghether_ptr, size_t customer_sz)
+{
+	return mcheck_allocated_helper(altoghether_ptr, customer_sz, ANY_ALIGNMENT, CLEAN_CONTENT);
+}
+
+static void *mcheck_alloc_noclean_posthook(void *altoghether_ptr, size_t customer_sz)
+{
+	return mcheck_allocated_helper(altoghether_ptr, customer_sz, ANY_ALIGNMENT, KEEP_CONTENT);
+}
+
+static size_t mcheck_memalign_prehook(size_t alig, size_t sz)
+{
+	return mcheck_evaluate_memalign_prefix_size(alig) + sz + sizeof(mcheck_canary);
+}
+
+static void *mcheck_memalign_posthook(size_t alignment, void *altoghether_ptr, size_t customer_sz)
+{
+	return mcheck_allocated_helper(altoghether_ptr, customer_sz, alignment, CLEAN_CONTENT);
+}
+
+static enum mcheck_status mcheck_mprobe(void *ptr)
+{
+	struct mcheck_hdr *hdr = &((struct mcheck_hdr *)ptr)[-1];
+
+	return mcheck_checkhdr(hdr);
+}
+
+static void mcheck_pedantic_check(void)
+{
+	int i;
+
+	for (i = 0; i < REGISTRY_SZ; ++i)
+		if (mcheck_registry[i])
+			mcheck_checkhdr(mcheck_registry[i]);
+}
+
+static void mcheck_pedantic_prehook(void)
+{
+	if (mcheck_pedantic_flag)
+		mcheck_pedantic_check();
+}
+
+static void mcheck_initialize(mcheck_abortfunc_t new_func, char pedantic_flag)
+{
+	mcheck_abortfunc = (new_func) ? new_func : &mcheck_default_abort;
+	mcheck_pedantic_flag = pedantic_flag;
+}
+
+void mcheck_on_ramrelocation(size_t offset)
+{
+	char *p;
+	int i;
+	// Simple, but inaccurate strategy: drop the pre-reloc heap
+	for (i = 0; i < REGISTRY_SZ; ++i)
+		if ((p = mcheck_registry[i]) != NULL ) {
+			printf("mcheck, WRN: forgetting %p chunk\n", p);
+			mcheck_registry[i] = 0;
+		}
+
+	mcheck_chunk_count = 0;
+}
+#endif
+#endif
diff --git a/common/usb.c b/common/usb.c
index 836506d..99e6b85 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -28,6 +28,7 @@
 #include <common.h>
 #include <command.h>
 #include <dm.h>
+#include <dm/device_compat.h>
 #include <log.h>
 #include <malloc.h>
 #include <memalign.h>
@@ -1084,6 +1085,54 @@
 	return 0;
 }
 
+static int usb_device_is_ignored(u16 id_vendor, u16 id_product)
+{
+	ulong vid, pid;
+	char *end;
+	const char *cur = NULL;
+
+	/* ignore list depends on env support */
+	if (!CONFIG_IS_ENABLED(ENV_SUPPORT))
+		return 0;
+
+	cur = env_get("usb_ignorelist");
+
+	/* parse "usb_ignorelist" strictly */
+	while (cur && cur[0] != '\0') {
+		vid = simple_strtoul(cur, &end, 0);
+		/*
+		 * If strtoul did not parse a single digit or the next char is
+		 * not ':' the ignore list is malformed.
+		 */
+		if (cur == end || end[0] != ':')
+			return -EINVAL;
+
+		cur = end + 1;
+		pid = simple_strtoul(cur, &end, 0);
+		/* Consider '*' as wildcard for the product ID */
+		if (cur == end && end[0] == '*') {
+			pid = U16_MAX + 1;
+			end++;
+		}
+		/*
+		 * The ignore list is malformed if no product ID / wildcard was
+		 * parsed or entries are not separated by ',' or terminated with
+		 * '\0'.
+		 */
+		if (cur == end || (end[0] != ',' && end[0] != '\0'))
+			return -EINVAL;
+
+		if (id_vendor == vid && (pid > U16_MAX || id_product == pid))
+			return -ENODEV;
+
+		if (end[0] == '\0')
+			break;
+		cur = end + 1;
+	}
+
+	return 0;
+}
+
 int usb_select_config(struct usb_device *dev)
 {
 	unsigned char *tmpbuf = NULL;
@@ -1099,6 +1148,27 @@
 	le16_to_cpus(&dev->descriptor.idProduct);
 	le16_to_cpus(&dev->descriptor.bcdDevice);
 
+	/* ignore devices from usb_ignorelist */
+	err = usb_device_is_ignored(dev->descriptor.idVendor,
+				    dev->descriptor.idProduct);
+	if (err == -ENODEV) {
+		debug("Ignoring USB device 0x%x:0x%x\n",
+			dev->descriptor.idVendor, dev->descriptor.idProduct);
+		return err;
+	} else if (err == -EINVAL) {
+		/*
+		 * Continue on "usb_ignorelist" parsing errors. The list is
+		 * parsed for each device returning the error would result in
+		 * ignoring all USB devices.
+		 * Since the parsing error is independent of the probed device
+		 * report errors with printf instead of dev_err.
+		 */
+		printf("usb_ignorelist parse error in \"%s\"\n",
+		       env_get("usb_ignorelist"));
+	} else if (err < 0) {
+		return err;
+	}
+
 	/*
 	 * Kingston DT Ultimate 32GB USB 3.0 seems to be extremely sensitive
 	 * about this first Get Descriptor request. If there are any other
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 4cbc9ac..820f591 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -24,6 +24,18 @@
 #include <usb.h>
 
 /*
+ * USB vendor and product IDs used for quirks.
+ */
+#define USB_VENDOR_ID_APPLE	0x05ac
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021			0x029c
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021	0x029a
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021		0x029f
+
+#define USB_VENDOR_ID_KEYCHRON	0x3434
+
+#define USB_HID_QUIRK_POLL_NO_REPORT_IDLE	BIT(0)
+
+/*
  * If overwrite_console returns 1, the stdin, stderr and stdout
  * are switched to the serial port, else the settings in the
  * environment are used
@@ -106,6 +118,8 @@
 	unsigned long	last_report;
 	struct int_queue *intq;
 
+	uint32_t	ifnum;
+
 	uint32_t	repeat_delay;
 
 	uint32_t	usb_in_pointer;
@@ -150,8 +164,8 @@
  */
 static void usb_kbd_setled(struct usb_device *dev)
 {
-	struct usb_interface *iface = &dev->config.if_desc[0];
 	struct usb_kbd_pdata *data = dev->privptr;
+	struct usb_interface *iface = &dev->config.if_desc[data->ifnum];
 	ALLOC_ALIGN_BUFFER(uint32_t, leds, 1, USB_DMA_MINALIGN);
 
 	*leds = data->flags & USB_KBD_LEDMASK;
@@ -365,7 +379,7 @@
 #if defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)
 	struct usb_interface *iface;
 	struct usb_kbd_pdata *data = dev->privptr;
-	iface = &dev->config.if_desc[0];
+	iface = &dev->config.if_desc[data->ifnum];
 	usb_get_report(dev, iface->desc.bInterfaceNumber,
 		       1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE);
 	if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) {
@@ -464,6 +478,7 @@
 	struct usb_interface *iface;
 	struct usb_endpoint_descriptor *ep;
 	struct usb_kbd_pdata *data;
+	unsigned int quirks = 0;
 	int epNum;
 
 	if (dev->descriptor.bNumConfigurations != 1)
@@ -496,6 +511,15 @@
 
 	debug("USB KBD: found interrupt EP: 0x%x\n", ep->bEndpointAddress);
 
+	switch (dev->descriptor.idVendor) {
+	case USB_VENDOR_ID_APPLE:
+	case USB_VENDOR_ID_KEYCHRON:
+		quirks |= USB_HID_QUIRK_POLL_NO_REPORT_IDLE;
+		break;
+	default:
+		break;
+	}
+
 	data = malloc(sizeof(struct usb_kbd_pdata));
 	if (!data) {
 		printf("USB KBD: Error allocating private data\n");
@@ -509,6 +533,8 @@
 	data->new = memalign(USB_DMA_MINALIGN,
 		roundup(USB_KBD_BOOT_REPORT_SIZE, USB_DMA_MINALIGN));
 
+	data->ifnum = ifnum;
+
 	/* Insert private data into USB device structure */
 	dev->privptr = data;
 
@@ -534,6 +560,14 @@
 	usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0);
 #endif
 
+	/*
+	 * Apple and Keychron keyboards do not report the device state. Reports
+	 * are only returned during key presses.
+	 */
+	if (quirks & USB_HID_QUIRK_POLL_NO_REPORT_IDLE) {
+		debug("USB KBD: quirk: skip testing device state\n");
+		return 1;
+	}
 	debug("USB KBD: enable interrupt pipe...\n");
 #ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
 	data->intq = create_int_queue(dev, data->intpipe, 1,
@@ -561,10 +595,17 @@
 {
 	char *stdinname;
 	struct stdio_dev usb_kbd_dev;
+	unsigned int ifnum;
+	unsigned int max_ifnum = min((unsigned int)USB_MAX_ACTIVE_INTERFACES,
+				     (unsigned int)dev->config.no_of_if);
 	int error;
 
 	/* Try probing the keyboard */
-	if (usb_kbd_probe_dev(dev, 0) != 1)
+	for (ifnum = 0; ifnum < max_ifnum; ifnum++) {
+		if (usb_kbd_probe_dev(dev, ifnum) == 1)
+			break;
+	}
+	if (ifnum >= max_ifnum)
 		return -ENOENT;
 
 	/* Register the keyboard */
@@ -731,6 +772,18 @@
 		.bInterfaceSubClass = USB_SUB_HID_BOOT,
 		.bInterfaceProtocol = USB_PROT_HID_KEYBOARD,
 	},
+	{
+		USB_DEVICE(USB_VENDOR_ID_APPLE,
+			   USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
+	},
+	{
+		USB_DEVICE(USB_VENDOR_ID_APPLE,
+			   USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
+	},
+	{
+		USB_DEVICE(USB_VENDOR_ID_APPLE,
+			   USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
+	},
 	{ }		/* Terminating entry */
 };
 
diff --git a/configs/am62px_evm_a53_defconfig b/configs/am62px_evm_a53_defconfig
index 65dfda1..638d2e9 100644
--- a/configs/am62px_evm_a53_defconfig
+++ b/configs/am62px_evm_a53_defconfig
@@ -70,6 +70,7 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_CMD_MTDPARTS=y
 CONFIG_CMD_UBI=y
+CONFIG_MMC_SPEED_MODE_SET=y
 CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
 CONFIG_OF_UPSTREAM=y
diff --git a/configs/am62x_evm_a53_defconfig b/configs/am62x_evm_a53_defconfig
index d650b85..6b37f8b 100644
--- a/configs/am62x_evm_a53_defconfig
+++ b/configs/am62x_evm_a53_defconfig
@@ -33,7 +33,7 @@
 CONFIG_SPL_LOAD_FIT_ADDRESS=0x81000000
 CONFIG_BOOTSTD_FULL=y
 CONFIG_SYS_BOOTM_LEN=0x800000
-CONFIG_BOOTCOMMAND="run envboot; bootflow scan -lb"
+CONFIG_BOOTCOMMAND="run findfdt; run envboot; bootflow scan -lb"
 CONFIG_BOARD_LATE_INIT=y
 CONFIG_SPL_MAX_SIZE=0x58000
 CONFIG_SPL_SYS_REPORT_STACK_F_USAGE=y
@@ -52,6 +52,7 @@
 CONFIG_CMD_BOOTEFI_SELFTEST=y
 CONFIG_CMD_NVEDIT_EFI=y
 CONFIG_CMD_MMC=y
+CONFIG_MMC_SPEED_MODE_SET=y
 CONFIG_CMD_EFIDEBUG=y
 CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
diff --git a/configs/am64x_evm_a53_defconfig b/configs/am64x_evm_a53_defconfig
index 61b498b..8b0ccba 100644
--- a/configs/am64x_evm_a53_defconfig
+++ b/configs/am64x_evm_a53_defconfig
@@ -75,6 +75,7 @@
 CONFIG_CMD_TIME=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
+CONFIG_MMC_SPEED_MODE_SET=y
 CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
 CONFIG_OF_UPSTREAM=y
diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig
index 500335f..3afa80f 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -73,6 +73,7 @@
 CONFIG_MTDIDS_DEFAULT="nor0=47040000.spi.0"
 CONFIG_MTDPARTS_DEFAULT="mtdparts=47040000.spi.0:512k(ospi.tiboot3),2m(ospi.tispl),4m(ospi.u-boot),128k(ospi.env),128k(ospi.env.backup),1m(ospi.sysfw),-@8m(ospi.rootfs)"
 CONFIG_CMD_UBI=y
+CONFIG_MMC_SPEED_MODE_SET=y
 # CONFIG_ISO_PARTITION is not set
 CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
diff --git a/configs/colibri_vf_defconfig b/configs/colibri_vf_defconfig
index a5e6bcb..0249dc3 100644
--- a/configs/colibri_vf_defconfig
+++ b/configs/colibri_vf_defconfig
@@ -17,6 +17,7 @@
 CONFIG_ENV_VARS_UBOOT_CONFIG=y
 CONFIG_HAS_BOARD_SIZE_LIMIT=y
 CONFIG_BOARD_SIZE_LIMIT=520192
+# CONFIG_BOOTM is not set
 CONFIG_BOOTDELAY=1
 CONFIG_FDT_FIXUP_PARTITIONS=y
 CONFIG_USE_BOOTCOMMAND=y
@@ -33,7 +34,6 @@
 # CONFIG_SYS_LONGHELP is not set
 CONFIG_SYS_PROMPT="Colibri VFxx # "
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 CONFIG_CMD_BOOTZ=y
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_IMI is not set
diff --git a/configs/coreboot64_defconfig b/configs/coreboot64_defconfig
index dab5eaf..da42ad0 100644
--- a/configs/coreboot64_defconfig
+++ b/configs/coreboot64_defconfig
@@ -16,6 +16,7 @@
 CONFIG_SHOW_BOOT_PROGRESS=y
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
+CONFIG_BOOTCOMMAND="bootflow scan -l; if bootflow menu; then cls; bootflow boot; fi"
 CONFIG_SYS_PBSIZE=532
 CONFIG_PRE_CONSOLE_BUFFER=y
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
@@ -59,6 +60,7 @@
 CONFIG_SOUND=y
 CONFIG_SOUND_I8254=y
 CONFIG_VIDEO_COPY=y
+CONFIG_CONSOLE_TRUETYPE=y
 CONFIG_CONSOLE_SCROLL_LINES=5
 CONFIG_SPL_ACPI=y
 CONFIG_CMD_DHRYSTONE=y
diff --git a/configs/coreboot_defconfig b/configs/coreboot_defconfig
index c846dfc..0b103ef 100644
--- a/configs/coreboot_defconfig
+++ b/configs/coreboot_defconfig
@@ -14,6 +14,7 @@
 CONFIG_SHOW_BOOT_PROGRESS=y
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
+CONFIG_BOOTCOMMAND="bootflow scan -l; if bootflow menu; then cls; bootflow boot; fi"
 CONFIG_PRE_CONSOLE_BUFFER=y
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_LOG=y
@@ -53,6 +54,7 @@
 CONFIG_SOUND=y
 CONFIG_SOUND_I8254=y
 CONFIG_VIDEO_COPY=y
+CONFIG_CONSOLE_TRUETYPE=y
 CONFIG_CONSOLE_SCROLL_LINES=5
 CONFIG_CMD_DHRYSTONE=y
 # CONFIG_GZIP is not set
diff --git a/configs/iot_devkit_defconfig b/configs/iot_devkit_defconfig
index c492005..d02a28a 100644
--- a/configs/iot_devkit_defconfig
+++ b/configs/iot_devkit_defconfig
@@ -14,12 +14,12 @@
 CONFIG_SYS_CLK_FREQ=16000000
 CONFIG_SYS_LOAD_ADDR=0x30000000
 CONFIG_LOCALVERSION="-iotdk-1.0"
+# CONFIG_BOOTM is not set
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
 CONFIG_SYS_CBSIZE=256
 CONFIG_SYS_PBSIZE=280
 CONFIG_SYS_PROMPT="IoTDK# "
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_XIMG is not set
 # CONFIG_CMD_LOADB is not set
diff --git a/configs/milkv_duo_defconfig b/configs/milkv_duo_defconfig
index 548adf1..e8413d7 100644
--- a/configs/milkv_duo_defconfig
+++ b/configs/milkv_duo_defconfig
@@ -17,6 +17,16 @@
 CONFIG_SYS_PBSIZE=544
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="milkv_duo# "
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
 CONFIG_ENV_OVERWRITE=y
+CONFIG_MMC=y
+CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_MMC_UHS_SUPPORT=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ADMA=y
+CONFIG_MMC_SDHCI_CV1800B=y
 CONFIG_SYS_NS16550=y
 CONFIG_SYS_NS16550_MEM32=y
diff --git a/configs/mx6memcal_defconfig b/configs/mx6memcal_defconfig
index 7f11e6f..6c5481c 100644
--- a/configs/mx6memcal_defconfig
+++ b/configs/mx6memcal_defconfig
@@ -14,6 +14,7 @@
 CONFIG_SPL=y
 CONFIG_SYS_MEMTEST_START=0x10000000
 CONFIG_SYS_MEMTEST_END=0x20000000
+# CONFIG_BOOTM is not set
 CONFIG_SUPPORT_RAW_INITRD=y
 CONFIG_SYS_PBSIZE=528
 CONFIG_SPL_SYS_MALLOC=y
@@ -21,7 +22,6 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_MAXARGS=32
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_IMI is not set
 # CONFIG_CMD_XIMG is not set
diff --git a/configs/phycore_am62x_a53_defconfig b/configs/phycore_am62x_a53_defconfig
index 552b7e9..08a2532 100644
--- a/configs/phycore_am62x_a53_defconfig
+++ b/configs/phycore_am62x_a53_defconfig
@@ -33,6 +33,7 @@
 CONFIG_SYS_BOOTM_LEN=0x800000
 CONFIG_BOOTCOMMAND="run mmcboot; bootflow scan -lb"
 CONFIG_DEFAULT_FDT_FILE="oftree"
+CONFIG_BOARD_LATE_INIT=y
 CONFIG_SPL_MAX_SIZE=0x58000
 CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
 CONFIG_SPL_BSS_START_ADDR=0x80c80000
diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig
index 451af0b..008eb46 100644
--- a/configs/qemu-x86_64_defconfig
+++ b/configs/qemu-x86_64_defconfig
@@ -6,7 +6,7 @@
 CONFIG_MAX_CPUS=2
 CONFIG_SPL_DM_SPI=y
 CONFIG_DEFAULT_DEVICE_TREE="qemu-x86_i440fx"
-CONFIG_SPL_TEXT_BASE=0xfffd8000
+CONFIG_SPL_TEXT_BASE=0xfffd4000
 CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000
 CONFIG_DEBUG_UART_BASE=0x3f8
 CONFIG_DEBUG_UART_CLOCK=1843200
@@ -17,7 +17,7 @@
 CONFIG_SMP=y
 CONFIG_GENERATE_PIRQ_TABLE=y
 CONFIG_GENERATE_MP_TABLE=y
-CONFIG_X86_OFFSET_U_BOOT=0xfff00000
+CONFIG_X86_OFFSET_U_BOOT=0xffe00000
 CONFIG_SYS_MONITOR_BASE=0x01110000
 CONFIG_FIT=y
 CONFIG_SPL_LOAD_FIT=y
@@ -80,6 +80,7 @@
 CONFIG_SYS_NS16550_PORT_MAPPED=y
 CONFIG_SPI=y
 CONFIG_USB_KEYBOARD=y
+CONFIG_CONSOLE_TRUETYPE=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
 CONFIG_FRAMEBUFFER_VESA_MODE_USER=y
 CONFIG_FRAMEBUFFER_VESA_MODE=0x144
diff --git a/configs/qemu-x86_defconfig b/configs/qemu-x86_defconfig
index b2a221b..947d15c 100644
--- a/configs/qemu-x86_defconfig
+++ b/configs/qemu-x86_defconfig
@@ -57,6 +57,7 @@
 CONFIG_SYS_NS16550_PORT_MAPPED=y
 CONFIG_SPI=y
 CONFIG_USB_KEYBOARD=y
+CONFIG_CONSOLE_TRUETYPE=y
 CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
 CONFIG_FRAMEBUFFER_VESA_MODE_USER=y
 CONFIG_FRAMEBUFFER_VESA_MODE=0x144
diff --git a/configs/socfpga_chameleonv3_defconfig b/configs/socfpga_chameleonv3_defconfig
index 6ea61ca..7506aa8 100644
--- a/configs/socfpga_chameleonv3_defconfig
+++ b/configs/socfpga_chameleonv3_defconfig
@@ -7,6 +7,7 @@
 CONFIG_SPL_TEXT_BASE=0xFFE00000
 CONFIG_SPL_DRIVERS_MISC=y
 CONFIG_TARGET_SOCFPGA_CHAMELEONV3=y
+CONFIG_SOCFPGA_ARRIA10_ALWAYS_REPROGRAM=y
 CONFIG_SPL_FS_FAT=y
 CONFIG_FIT=y
 CONFIG_SPL_FIT=y
diff --git a/configs/starfive_visionfive2_defconfig b/configs/starfive_visionfive2_defconfig
index 7a3f1d4..fa80d48 100644
--- a/configs/starfive_visionfive2_defconfig
+++ b/configs/starfive_visionfive2_defconfig
@@ -40,7 +40,6 @@
 CONFIG_BOOTARGS="console=ttyS0,115200 debug rootwait earlycon=sbi"
 CONFIG_USE_PREBOOT=y
 CONFIG_PREBOOT="nvme scan; usb start; setenv fdt_addr ${fdtcontroladdr}; fdt addr ${fdtcontroladdr};"
-CONFIG_DEFAULT_FDT_FILE="starfive/jh7110-starfive-visionfive-2.dtb"
 CONFIG_SYS_CBSIZE=256
 CONFIG_SYS_PBSIZE=276
 CONFIG_DISPLAY_CPUINFO=y
diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig
index b54d2ce..5de482a 100644
--- a/configs/tools-only_defconfig
+++ b/configs/tools-only_defconfig
@@ -12,10 +12,10 @@
 # CONFIG_BOOTSTD_FULL is not set
 # CONFIG_BOOTMETH_CROS is not set
 # CONFIG_BOOTMETH_VBE is not set
+# CONFIG_BOOTM is not set
 CONFIG_USE_BOOTCOMMAND=y
 CONFIG_BOOTCOMMAND="run distro_bootcmd"
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_EXTENSION is not set
diff --git a/configs/verdin-am62_a53_defconfig b/configs/verdin-am62_a53_defconfig
index 15424fe..633e9c7 100644
--- a/configs/verdin-am62_a53_defconfig
+++ b/configs/verdin-am62_a53_defconfig
@@ -14,7 +14,7 @@
 CONFIG_ENV_SIZE=0x2000
 CONFIG_ENV_OFFSET=0xFFFFDE00
 CONFIG_DM_GPIO=y
-CONFIG_DEFAULT_DEVICE_TREE="k3-am625-verdin-wifi-dev"
+CONFIG_DEFAULT_DEVICE_TREE="ti/k3-am625-verdin-wifi-dev"
 CONFIG_SPL_TEXT_BASE=0x80080000
 CONFIG_OF_LIBFDT_OVERLAY=y
 CONFIG_DM_RESET=y
diff --git a/configs/xilinx_mbv32_defconfig b/configs/xilinx_mbv32_defconfig
index 2689495..4113409 100644
--- a/configs/xilinx_mbv32_defconfig
+++ b/configs/xilinx_mbv32_defconfig
@@ -1,30 +1,43 @@
 CONFIG_RISCV=y
-CONFIG_TEXT_BASE=0x21200000
-CONFIG_SYS_MALLOC_LEN=0x800000
+CONFIG_SYS_MALLOC_LEN=0xe00000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
-CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x20200000
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x21200000
 CONFIG_ENV_SIZE=0x20000
 CONFIG_DEFAULT_DEVICE_TREE="xilinx-mbv32"
+CONFIG_SPL_STACK=0x20200000
+CONFIG_SPL_SIZE_LIMIT=0x40000
+CONFIG_SPL=y
 CONFIG_DEBUG_UART_BASE=0x40600000
 CONFIG_DEBUG_UART_CLOCK=1000000
 CONFIG_SYS_CLK_FREQ=100000000
 CONFIG_BOOT_SCRIPT_OFFSET=0x0
-CONFIG_SYS_LOAD_ADDR=0x80200000
+CONFIG_SYS_LOAD_ADDR=0x20200000
 CONFIG_DEBUG_UART=y
 CONFIG_TARGET_XILINX_MBV=y
+# CONFIG_SPL_SMP is not set
+CONFIG_REMAKE_ELF=y
 CONFIG_FIT=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x20200000
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_DISPLAY_CPUINFO=y
 CONFIG_DISPLAY_BOARDINFO=y
 # CONFIG_BOARD_LATE_INIT is not set
+CONFIG_SPL_MAX_SIZE=0x40000
+CONFIG_SPL_BSS_START_ADDR=0x24000000
+CONFIG_SPL_BSS_MAX_SIZE=0x80000
+# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
+CONFIG_SPL_SYS_MALLOC=y
+CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
 # CONFIG_CMD_MII is not set
 CONFIG_CMD_TIMER=y
-CONFIG_OF_EMBED=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DM_MTD=y
 CONFIG_DEBUG_UART_ANNOUNCE=y
 CONFIG_DEBUG_UART_SKIP_INIT=y
 CONFIG_XILINX_UARTLITE=y
 CONFIG_XILINX_TIMER=y
+# CONFIG_BINMAN_FDT is not set
 CONFIG_PANIC_HANG=y
+CONFIG_SPL_GZIP=y
diff --git a/configs/xilinx_mbv32_smode_defconfig b/configs/xilinx_mbv32_smode_defconfig
index c724d1b..9938147 100644
--- a/configs/xilinx_mbv32_smode_defconfig
+++ b/configs/xilinx_mbv32_smode_defconfig
@@ -1,27 +1,40 @@
 CONFIG_RISCV=y
-CONFIG_TEXT_BASE=0x21200000
-CONFIG_SYS_MALLOC_LEN=0x800000
+CONFIG_SYS_MALLOC_LEN=0xe00000
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
-CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x20200000
+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x21200000
 CONFIG_ENV_SIZE=0x20000
 CONFIG_DEFAULT_DEVICE_TREE="xilinx-mbv32"
+CONFIG_SPL_STACK=0x20200000
+CONFIG_SPL_SIZE_LIMIT=0x40000
+CONFIG_SPL=y
 CONFIG_DEBUG_UART_BASE=0x40600000
 CONFIG_DEBUG_UART_CLOCK=1000000
 CONFIG_SYS_CLK_FREQ=100000000
 CONFIG_BOOT_SCRIPT_OFFSET=0x0
-CONFIG_SYS_LOAD_ADDR=0x80200000
+CONFIG_SYS_LOAD_ADDR=0x20200000
 CONFIG_TARGET_XILINX_MBV=y
+CONFIG_SPL_OPENSBI_LOAD_ADDR=0x20100000
 CONFIG_RISCV_SMODE=y
+# CONFIG_SPL_SMP is not set
+CONFIG_REMAKE_ELF=y
 CONFIG_FIT=y
+CONFIG_SPL_LOAD_FIT_ADDRESS=0x20200000
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_DISPLAY_CPUINFO=y
 CONFIG_DISPLAY_BOARDINFO=y
 # CONFIG_BOARD_LATE_INIT is not set
+CONFIG_SPL_MAX_SIZE=0x40000
+CONFIG_SPL_BSS_START_ADDR=0x24000000
+CONFIG_SPL_BSS_MAX_SIZE=0x80000
+# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
+CONFIG_SPL_SYS_MALLOC=y
+CONFIG_SPL_SYS_MALLOC_SIZE=0x800000
+CONFIG_SPL_OPENSBI_SCRATCH_OPTIONS=0x2
 # CONFIG_CMD_MII is not set
 CONFIG_CMD_TIMER=y
-CONFIG_OF_EMBED=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DM_MTD=y
 CONFIG_DEBUG_UART_UARTLITE=y
 CONFIG_DEBUG_UART_ANNOUNCE=y
@@ -29,4 +42,6 @@
 CONFIG_XILINX_UARTLITE=y
 # CONFIG_RISCV_TIMER is not set
 CONFIG_XILINX_TIMER=y
+# CONFIG_BINMAN_FDT is not set
 CONFIG_PANIC_HANG=y
+CONFIG_SPL_GZIP=y
diff --git a/configs/xilinx_versal_mini_defconfig b/configs/xilinx_versal_mini_defconfig
index 9d3924c..143d262 100644
--- a/configs/xilinx_versal_mini_defconfig
+++ b/configs/xilinx_versal_mini_defconfig
@@ -18,6 +18,7 @@
 CONFIG_SYS_MEMTEST_END=0x00001000
 # CONFIG_EXPERT is not set
 CONFIG_REMAKE_ELF=y
+# CONFIG_BOOTM is not set
 # CONFIG_LEGACY_IMAGE_FORMAT is not set
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CBSIZE=1024
@@ -33,7 +34,6 @@
 CONFIG_SYS_PROMPT="Versal> "
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_mini_emmc0_defconfig b/configs/xilinx_versal_mini_emmc0_defconfig
index 5c949e3..b0e3462 100644
--- a/configs/xilinx_versal_mini_emmc0_defconfig
+++ b/configs/xilinx_versal_mini_emmc0_defconfig
@@ -15,6 +15,7 @@
 CONFIG_SYS_LOAD_ADDR=0x8000000
 # CONFIG_EXPERT is not set
 CONFIG_REMAKE_ELF=y
+# CONFIG_BOOTM is not set
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CBSIZE=1024
 CONFIG_SYS_PBSIZE=1049
@@ -30,7 +31,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_mini_emmc1_defconfig b/configs/xilinx_versal_mini_emmc1_defconfig
index 04cba5b..559b32c 100644
--- a/configs/xilinx_versal_mini_emmc1_defconfig
+++ b/configs/xilinx_versal_mini_emmc1_defconfig
@@ -15,6 +15,7 @@
 CONFIG_SYS_LOAD_ADDR=0x8000000
 # CONFIG_EXPERT is not set
 CONFIG_REMAKE_ELF=y
+# CONFIG_BOOTM is not set
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CBSIZE=1024
 CONFIG_SYS_PBSIZE=1049
@@ -30,7 +31,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_mini_ospi_defconfig b/configs/xilinx_versal_mini_ospi_defconfig
index 7a11035..c02c6ba 100644
--- a/configs/xilinx_versal_mini_ospi_defconfig
+++ b/configs/xilinx_versal_mini_ospi_defconfig
@@ -19,6 +19,7 @@
 CONFIG_LTO=y
 # CONFIG_EXPERT is not set
 CONFIG_REMAKE_ELF=y
+# CONFIG_BOOTM is not set
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 # CONFIG_DISPLAY_CPUINFO is not set
@@ -31,7 +32,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_mini_qspi_defconfig b/configs/xilinx_versal_mini_qspi_defconfig
index 58945a1..4d4b59a 100644
--- a/configs/xilinx_versal_mini_qspi_defconfig
+++ b/configs/xilinx_versal_mini_qspi_defconfig
@@ -17,6 +17,7 @@
 CONFIG_LTO=y
 # CONFIG_EXPERT is not set
 CONFIG_REMAKE_ELF=y
+# CONFIG_BOOTM is not set
 # CONFIG_AUTOBOOT is not set
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
 CONFIG_LOGLEVEL=0
@@ -32,7 +33,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_net_mini_defconfig b/configs/xilinx_versal_net_mini_defconfig
index 7dac1ec..317fc8e 100644
--- a/configs/xilinx_versal_net_mini_defconfig
+++ b/configs/xilinx_versal_net_mini_defconfig
@@ -20,6 +20,7 @@
 CONFIG_SYS_MEMTEST_END=0x00001000
 # CONFIG_EXPERT is not set
 CONFIG_REMAKE_ELF=y
+# CONFIG_BOOTM is not set
 # CONFIG_LEGACY_IMAGE_FORMAT is not set
 # CONFIG_AUTOBOOT is not set
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
@@ -33,7 +34,6 @@
 CONFIG_SYS_PROMPT="Versal NET> "
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_net_mini_emmc_defconfig b/configs/xilinx_versal_net_mini_emmc_defconfig
index fc88eee..31c4432 100644
--- a/configs/xilinx_versal_net_mini_emmc_defconfig
+++ b/configs/xilinx_versal_net_mini_emmc_defconfig
@@ -25,7 +25,7 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
+# CONFIG_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_net_mini_ospi_defconfig b/configs/xilinx_versal_net_mini_ospi_defconfig
index d78c9f8..d0d91f9 100644
--- a/configs/xilinx_versal_net_mini_ospi_defconfig
+++ b/configs/xilinx_versal_net_mini_ospi_defconfig
@@ -30,7 +30,7 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
+# CONFIG_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_net_mini_qspi_defconfig b/configs/xilinx_versal_net_mini_qspi_defconfig
index b0567f8..48b6d86 100644
--- a/configs/xilinx_versal_net_mini_qspi_defconfig
+++ b/configs/xilinx_versal_net_mini_qspi_defconfig
@@ -31,7 +31,7 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
+# CONFIG_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_versal_net_virt_defconfig b/configs/xilinx_versal_net_virt_defconfig
index 29cebe2..40c6a29 100644
--- a/configs/xilinx_versal_net_virt_defconfig
+++ b/configs/xilinx_versal_net_virt_defconfig
@@ -60,6 +60,9 @@
 CONFIG_OF_BOARD=y
 CONFIG_DTB_RESELECT=y
 CONFIG_MULTI_DTB_FIT=y
+CONFIG_ENV_IS_NOWHERE=y
+CONFIG_ENV_IS_IN_FAT=y
+CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/xilinx_zynqmp_kria_defconfig b/configs/xilinx_zynqmp_kria_defconfig
index 7cb8b62..7af8b27 100644
--- a/configs/xilinx_zynqmp_kria_defconfig
+++ b/configs/xilinx_zynqmp_kria_defconfig
@@ -155,7 +155,6 @@
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_ZYNQ=y
 CONFIG_DM_MTD=y
-CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_SPI_FLASH_MTD=y
diff --git a/configs/xilinx_zynqmp_mini_defconfig b/configs/xilinx_zynqmp_mini_defconfig
index 7fdd2ee..40d4a4a 100644
--- a/configs/xilinx_zynqmp_mini_defconfig
+++ b/configs/xilinx_zynqmp_mini_defconfig
@@ -13,6 +13,7 @@
 CONFIG_SYS_MEMTEST_START=0x00000000
 CONFIG_SYS_MEMTEST_END=0x00001000
 CONFIG_REMAKE_ELF=y
+# CONFIG_BOOTM is not set
 # CONFIG_LEGACY_IMAGE_FORMAT is not set
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CBSIZE=1024
@@ -26,7 +27,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_zynqmp_mini_emmc0_defconfig b/configs/xilinx_zynqmp_mini_emmc0_defconfig
index bf34832..9cccf5d 100644
--- a/configs/xilinx_zynqmp_mini_emmc0_defconfig
+++ b/configs/xilinx_zynqmp_mini_emmc0_defconfig
@@ -17,6 +17,7 @@
 CONFIG_REMAKE_ELF=y
 # CONFIG_MP is not set
 CONFIG_FIT=y
+# CONFIG_BOOTM is not set
 CONFIG_SUPPORT_RAW_INITRD=y
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CBSIZE=1024
@@ -37,7 +38,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_zynqmp_mini_emmc1_defconfig b/configs/xilinx_zynqmp_mini_emmc1_defconfig
index af70ccf..3919e23 100644
--- a/configs/xilinx_zynqmp_mini_emmc1_defconfig
+++ b/configs/xilinx_zynqmp_mini_emmc1_defconfig
@@ -17,6 +17,7 @@
 CONFIG_REMAKE_ELF=y
 # CONFIG_MP is not set
 CONFIG_FIT=y
+# CONFIG_BOOTM is not set
 CONFIG_SUPPORT_RAW_INITRD=y
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CBSIZE=1024
@@ -37,7 +38,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/xilinx_zynqmp_mini_nand_defconfig b/configs/xilinx_zynqmp_mini_nand_defconfig
index d2e920f..ae0c3ae 100644
--- a/configs/xilinx_zynqmp_mini_nand_defconfig
+++ b/configs/xilinx_zynqmp_mini_nand_defconfig
@@ -13,6 +13,7 @@
 CONFIG_REMAKE_ELF=y
 # CONFIG_MP is not set
 CONFIG_FIT=y
+# CONFIG_BOOTM is not set
 CONFIG_SUPPORT_RAW_INITRD=y
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CBSIZE=1024
@@ -27,7 +28,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_GO is not set
 # CONFIG_CMD_RUN is not set
diff --git a/configs/xilinx_zynqmp_mini_nand_single_defconfig b/configs/xilinx_zynqmp_mini_nand_single_defconfig
index 31f6473..15d471c 100644
--- a/configs/xilinx_zynqmp_mini_nand_single_defconfig
+++ b/configs/xilinx_zynqmp_mini_nand_single_defconfig
@@ -13,6 +13,7 @@
 CONFIG_REMAKE_ELF=y
 # CONFIG_MP is not set
 CONFIG_FIT=y
+# CONFIG_BOOTM is not set
 CONFIG_SUPPORT_RAW_INITRD=y
 # CONFIG_AUTOBOOT is not set
 CONFIG_SYS_CBSIZE=1024
@@ -27,7 +28,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_GO is not set
 # CONFIG_CMD_RUN is not set
diff --git a/configs/xilinx_zynqmp_mini_qspi_defconfig b/configs/xilinx_zynqmp_mini_qspi_defconfig
index 096feeb..071784c 100644
--- a/configs/xilinx_zynqmp_mini_qspi_defconfig
+++ b/configs/xilinx_zynqmp_mini_qspi_defconfig
@@ -19,6 +19,7 @@
 CONFIG_SYS_LOAD_ADDR=0x8000000
 # CONFIG_EXPERT is not set
 CONFIG_REMAKE_ELF=y
+# CONFIG_BOOTM is not set
 # CONFIG_LEGACY_IMAGE_FORMAT is not set
 # CONFIG_AUTOBOOT is not set
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
@@ -41,7 +42,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_BOOTI is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
diff --git a/configs/zynq_cse_nand_defconfig b/configs/zynq_cse_nand_defconfig
index 0dbc804..982777b 100644
--- a/configs/zynq_cse_nand_defconfig
+++ b/configs/zynq_cse_nand_defconfig
@@ -19,6 +19,7 @@
 CONFIG_REMAKE_ELF=y
 CONFIG_SYS_CUSTOM_LDSCRIPT=y
 CONFIG_SYS_LDSCRIPT="arch/arm/mach-zynq/u-boot.lds"
+# CONFIG_BOOTM is not set
 # CONFIG_AUTOBOOT is not set
 CONFIG_USE_PREBOOT=y
 CONFIG_SYS_CBSIZE=1024
@@ -43,7 +44,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
 # CONFIG_CMD_GO is not set
diff --git a/configs/zynq_cse_nor_defconfig b/configs/zynq_cse_nor_defconfig
index d95f760..7d70dae 100644
--- a/configs/zynq_cse_nor_defconfig
+++ b/configs/zynq_cse_nor_defconfig
@@ -19,6 +19,7 @@
 CONFIG_REMAKE_ELF=y
 CONFIG_SYS_CUSTOM_LDSCRIPT=y
 CONFIG_SYS_LDSCRIPT="arch/arm/mach-zynq/u-boot.lds"
+# CONFIG_BOOTM is not set
 # CONFIG_AUTOBOOT is not set
 CONFIG_USE_PREBOOT=y
 CONFIG_SYS_CBSIZE=1024
@@ -43,7 +44,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
 # CONFIG_CMD_GO is not set
diff --git a/configs/zynq_cse_qspi_defconfig b/configs/zynq_cse_qspi_defconfig
index dd7f978..c7477aa 100644
--- a/configs/zynq_cse_qspi_defconfig
+++ b/configs/zynq_cse_qspi_defconfig
@@ -25,6 +25,7 @@
 CONFIG_REMAKE_ELF=y
 CONFIG_SYS_CUSTOM_LDSCRIPT=y
 CONFIG_SYS_LDSCRIPT="arch/arm/mach-zynq/u-boot.lds"
+# CONFIG_BOOTM is not set
 # CONFIG_AUTOBOOT is not set
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
 CONFIG_USE_PREBOOT=y
@@ -52,7 +53,6 @@
 # CONFIG_CMD_BDI is not set
 # CONFIG_CMD_CONSOLE is not set
 # CONFIG_CMD_BOOTD is not set
-# CONFIG_CMD_BOOTM is not set
 # CONFIG_CMD_ELF is not set
 # CONFIG_CMD_FDT is not set
 # CONFIG_CMD_GO is not set
diff --git a/disk/part.c b/disk/part.c
index 36b8820..2bee669 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -14,6 +14,7 @@
 #include <malloc.h>
 #include <part.h>
 #include <ubifs_uboot.h>
+#include <dm/uclass.h>
 
 #undef	PART_DEBUG
 
@@ -305,50 +306,8 @@
 	CONFIG_IS_ENABLED(ISO_PARTITION) || \
 	CONFIG_IS_ENABLED(AMIGA_PARTITION) || \
 	CONFIG_IS_ENABLED(EFI_PARTITION)
-	puts ("\nPartition Map for ");
-	switch (desc->uclass_id) {
-	case UCLASS_IDE:
-		puts ("IDE");
-		break;
-	case UCLASS_AHCI:
-		puts ("SATA");
-		break;
-	case UCLASS_SCSI:
-		puts ("SCSI");
-		break;
-	case UCLASS_USB:
-		puts ("USB");
-		break;
-	case UCLASS_MMC:
-		puts ("MMC");
-		break;
-	case UCLASS_HOST:
-		puts ("HOST");
-		break;
-	case UCLASS_NVME:
-		puts ("NVMe");
-		break;
-	case UCLASS_PVBLOCK:
-		puts("PV BLOCK");
-		break;
-	case UCLASS_RKMTD:
-		puts("RKMTD");
-		break;
-	case UCLASS_VIRTIO:
-		puts("VirtIO");
-		break;
-	case UCLASS_EFI_MEDIA:
-		puts("EFI");
-		break;
-	case UCLASS_BLKMAP:
-		puts("BLKMAP");
-		break;
-	default:
-		printf("UNKNOWN(%d)", desc->uclass_id);
-		break;
-	}
-	printf (" device %d  --   Partition Type: %s\n\n",
-			desc->devnum, type);
+	printf("\nPartition Map for %s device %d  --   Partition Type: %s\n\n",
+	       uclass_get_name(desc->uclass_id), desc->devnum, type);
 #endif /* any CONFIG_..._PARTITION */
 }
 
@@ -717,8 +676,11 @@
 	for (i = 1; i < part_drv->max_entries; i++) {
 		ret = part_drv->get_info(desc, i, info);
 		if (ret != 0) {
-			/* no more entries in table */
-			break;
+			/*
+			 * Partition with this index can't be obtained, but
+			 * further partitions might be, so keep checking.
+			 */
+			continue;
 		}
 		if (strcmp(name, (const char *)info->name) == 0) {
 			/* matched */
diff --git a/doc/android/fastboot.rst b/doc/android/fastboot.rst
index 05d8f77..9e337ca 100644
--- a/doc/android/fastboot.rst
+++ b/doc/android/fastboot.rst
@@ -128,6 +128,7 @@
 
 When executing the fastboot ``boot`` command, if ``fastboot_bootcmd`` is set
 then that will be executed in place of ``bootm <CONFIG_FASTBOOT_BUF_ADDR>``.
+This is supported if CONFIG_CMDLINE is enabled, which it normally is.
 
 Partition Names
 ---------------
diff --git a/doc/board/emulation/qemu-x86.rst b/doc/board/emulation/qemu-x86.rst
index c604e42..4eeba46 100644
--- a/doc/board/emulation/qemu-x86.rst
+++ b/doc/board/emulation/qemu-x86.rst
@@ -134,7 +134,7 @@
 
    U-Boot SPL 2023.07 (Jul 23 2023 - 08:00:12 -0600)
    Trying to boot from SPI
-   Jumping to 64-bit U-Boot: Note many features are missing
+   Jumping to 64-bit U-Boot
 
 
    U-Boot 2023.07 (Jul 23 2023 - 08:00:12 -0600)
diff --git a/doc/board/starfive/index.rst b/doc/board/starfive/index.rst
index 0c52dc7..2762bf7 100644
--- a/doc/board/starfive/index.rst
+++ b/doc/board/starfive/index.rst
@@ -6,4 +6,5 @@
 .. toctree::
    :maxdepth: 1
 
+   milk-v_mars.rst
    visionfive2
diff --git a/doc/board/starfive/milk-v_mars.rst b/doc/board/starfive/milk-v_mars.rst
new file mode 100644
index 0000000..554932e
--- /dev/null
+++ b/doc/board/starfive/milk-v_mars.rst
@@ -0,0 +1,111 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Milk-V Mars
+===========
+
+U-Boot for the Milk-V Mars uses the same U-Boot binaries as the VisionFive 2
+board. In U-Boot SPL the actual board is detected and the device-tree patched
+accordingly.
+
+Building
+~~~~~~~~
+
+1. Add the RISC-V toolchain to your PATH.
+2. Setup ARCH & cross compilation environment variable:
+
+.. code-block:: none
+
+   export CROSS_COMPILE=<riscv64 toolchain prefix>
+
+The M-mode software OpenSBI provides the supervisor binary interface (SBI) and
+is responsible for the switch to S-Mode. It is a prerequisite to build U-Boot.
+Support for the JH7110 was introduced in OpenSBI 1.2. It is recommended to use
+a current release.
+
+.. code-block:: console
+
+	git clone https://github.com/riscv/opensbi.git
+	cd opensbi
+	make PLATFORM=generic FW_TEXT_START=0x40000000 FW_OPTIONS=0
+
+Now build the U-Boot SPL and U-Boot proper.
+
+.. code-block:: console
+
+	cd <U-Boot-dir>
+	make starfive_visionfive2_defconfig
+	make OPENSBI=$(opensbi_dir)/build/platform/generic/firmware/fw_dynamic.bin
+
+This will generate the U-Boot SPL image (spl/u-boot-spl.bin.normal.out) as well
+as the FIT image (u-boot.itb) with OpenSBI and U-Boot.
+
+Device-tree selection
+~~~~~~~~~~~~~~~~~~~~~
+
+Depending on the board version U-Boot set variable $fdtfile to either
+starfive/jh7110-starfive-visionfive-2-v1.2a.dtb or
+starfive/jh7110-starfive-visionfive-2-v1.3b.dtb.
+
+To overrule this selection the variable can be set manually and saved in the
+environment
+
+::
+
+    setenv fdtfile my_device-tree.dtb
+    env save
+
+or the configuration variable CONFIG_DEFAULT_FDT_FILE can be used to set to
+provide a default value.
+
+Boot source selection
+~~~~~~~~~~~~~~~~~~~~~
+
+The board provides the DIP switches MSEL[1:0] to select the boot device out of
+SPI flash, eMMC, SD-card, UART. To select booting from SD-card set the DIP
+switches MSEL[1:0] to 10.
+
+Preparing the SD-Card
+~~~~~~~~~~~~~~~~~~~~~
+
+The device firmware loads U-Boot SPL (u-boot-spl.bin.normal.out) from the
+partition with type GUID 2E54B353-1271-4842-806F-E436D6AF6985. You are free
+to choose any partition number.
+
+With the default configuration U-Boot SPL loads the U-Boot FIT image
+(u-boot.itb) from partition 2 (CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION=0x2).
+When formatting it is recommended to use GUID
+BC13C2FF-59E6-4262-A352-B275FD6F7172 for this partition.
+
+The FIT image (u-boot.itb) is a combination of OpenSBI's fw_dynamic.bin,
+u-boot-nodtb.bin and the device tree blob.
+
+Format the SD card (make sure the disk has GPT, otherwise use gdisk to switch)
+
+.. code-block:: bash
+
+	sudo sgdisk --clear \
+	  --set-alignment=2 \
+	  --new=1:4096:8191 --change-name=1:spl --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985\
+	  --new=2:8192:16383 --change-name=2:uboot --typecode=2:BC13C2FF-59E6-4262-A352-B275FD6F7172  \
+	  --new=3:16384:1654784 --change-name=3:system --typecode=3:EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 \
+	  /dev/sdb
+
+Copy U-Boot to the SD card
+
+.. code-block:: bash
+
+	sudo dd if=u-boot-spl.bin.normal.out of=/dev/sdb1
+	sudo dd if=u-boot.itb of=/dev/sdb2
+
+	sudo mount /dev/sdb3 /mnt/
+	sudo cp u-boot-spl.bin.normal.out /mnt/
+	sudo cp u-boot.itb /mnt/
+	sudo cp Image.gz /mnt/
+	sudo cp initramfs.cpio.gz /mnt/
+	sudo cp jh7110-starfive-visionfive-2.dtb /mnt/
+	sudo umount /mnt
+
+Booting
+~~~~~~~
+
+Once you plugin the sdcard and power up, you should see the U-Boot prompt.
diff --git a/doc/board/starfive/visionfive2.rst b/doc/board/starfive/visionfive2.rst
index abda8ac..2c68df3 100644
--- a/doc/board/starfive/visionfive2.rst
+++ b/doc/board/starfive/visionfive2.rst
@@ -71,6 +71,24 @@
 This will generate the U-Boot SPL image (spl/u-boot-spl.bin.normal.out) as well
 as the FIT image (u-boot.itb) with OpenSBI and U-Boot.
 
+Device-tree selection
+~~~~~~~~~~~~~~~~~~~~~
+
+Depending on the board version U-Boot set variable $fdtfile to either
+starfive/jh7110-starfive-visionfive-2-v1.2a.dtb or
+starfive/jh7110-starfive-visionfive-2-v1.3b.dtb.
+
+To overrule this selection the variable can be set manually and saved in the
+environment
+
+::
+
+    setenv fdtfile my_device-tree.dtb
+    env save
+
+or the configuration variable CONFIG_DEFAULT_FDT_FILE can be used to provide
+a default value.
+
 Flashing
 ~~~~~~~~
 
diff --git a/doc/build/docker.rst b/doc/build/docker.rst
index 953d1b2..45659b3 100644
--- a/doc/build/docker.rst
+++ b/doc/build/docker.rst
@@ -11,4 +11,4 @@
 
 .. code-block:: bash
 
-    sudo docker pull trini/u-boot-gitlab-ci-runner:bionic-20200807-02Sep2020
+    sudo docker pull trini/u-boot-gitlab-ci-runner:jammy-20240227-14Mar2024
diff --git a/doc/build/gen_compile_commands.rst b/doc/build/gen_compile_commands.rst
index 50305ce..d503764 100644
--- a/doc/build/gen_compile_commands.rst
+++ b/doc/build/gen_compile_commands.rst
@@ -42,7 +42,7 @@
 other than it's default one (compile_commands.json).
 
 Compatible IDEs
-===============
+---------------
 
 Several popular integrated development environments (IDEs) support the use
 of JSON compilation databases for C/C++ development, making it easier to
@@ -73,7 +73,7 @@
 code navigation.
 
 Usage
-=====
+-----
 
 For further details on the script's options, please refer to its help message,
 as in the example below.
diff --git a/doc/develop/tests_sandbox.rst b/doc/develop/tests_sandbox.rst
index bfd3bdb..7292307 100644
--- a/doc/develop/tests_sandbox.rst
+++ b/doc/develop/tests_sandbox.rst
@@ -28,8 +28,8 @@
 
      - test/image/test-imagetools.sh - multi-file images
      - test/py/tests/test-fit.py     - FIT images
-  - tracing: test/trace/test-trace.sh tests the tracing system (see
-      README.trace)
+  - tracing: test/trace/test-trace.sh tests the tracing system
+    (see :doc:`trace`).
   - verified boot: test/py/tests/test_vboot.py
 
 If you change or enhance any U-Boot subsystem, you should write or expand a
diff --git a/doc/device-tree-bindings/sysreset/ti,sci-sysreset.txt b/doc/device-tree-bindings/sysreset/ti,sci-sysreset.txt
deleted file mode 100644
index 02704c6..0000000
--- a/doc/device-tree-bindings/sysreset/ti,sci-sysreset.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-Texas Instruments TI SCI System Reset Controller
-================================================
-
-Some TI SoCs contain a system controller (like the SYSFW, etc...) that is
-responsible for controlling the state of the IPs that are present.
-Communication between the host processor running an OS and the system
-controller happens through a protocol known as TI SCI [1].
-
-[1] http://processors.wiki.ti.com/index.php/TISCI
-
-System Reset Controller Node
-============================
-The sysreset controller node represents the reset for the overall SoC
-which is managed by the SYSFW. Because this relies on the TI SCI protocol
-to communicate with the SYSFW it must be a child of the sysfw node.
-
-Required Properties:
---------------------
- - compatible: Must be "ti,sci-sysreset"
-
-Example (AM65x):
-----------------
-	sysfw: sysfw {
-		compatible = "ti,am654-system-controller";
-		...
-		k3_sysreset: sysreset-controller {
-			compatible = "ti,sci-sysreset";
-		};
-	};
diff --git a/doc/sphinx/requirements.txt b/doc/sphinx/requirements.txt
index 840c6ce..5b4df36 100644
--- a/doc/sphinx/requirements.txt
+++ b/doc/sphinx/requirements.txt
@@ -3,7 +3,7 @@
 certifi==2023.11.17
 charset-normalizer==3.3.2
 docutils==0.20.1
-idna==3.6
+idna==3.7
 imagesize==1.4.1
 Jinja2==3.1.3
 MarkupSafe==2.1.3
diff --git a/doc/usage/environment.rst b/doc/usage/environment.rst
index ebf75fa..7d4b448 100644
--- a/doc/usage/environment.rst
+++ b/doc/usage/environment.rst
@@ -366,6 +366,19 @@
     This means the count of blocks we can receive before
     sending ack to server.
 
+usb_ignorelist
+    Ignore USB devices to prevent binding them to an USB device driver. This can
+    be used to ignore devices are for some reason undesirable or causes crashes
+    u-boot's USB stack.
+    An example for undesired behavior is the keyboard emulation of security keys
+    like Yubikeys. U-boot currently supports only a single USB keyboard device
+    so try to probe an useful keyboard device. The default environment blocks
+    Yubico devices as common devices emulating keyboards.
+    Devices are matched by idVendor and idProduct. The variable contains a comma
+    separated list of idVendor:idProduct pairs as hexadecimal numbers joined
+    by a colon. '*' functions as a wildcard for idProduct to block all devices
+    with the specified idVendor.
+
 vlan
     When set to a value < 4095 the traffic over
     Ethernet is encapsulated/received over 802.1q
diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c
index ce10d79..f0cb797 100644
--- a/drivers/clk/imx/clk-imx93.c
+++ b/drivers/clk/imx/clk-imx93.c
@@ -289,7 +289,7 @@
 	clk_dm(IMX93_CLK_SYS_PLL_PFD2_DIV2,
 	       imx_clk_fixed_factor("sys_pll_pfd2_div2", "sys_pll_pfd2", 1, 2));
 
-	base = (void *)ANATOP_BASE_ADDR;
+	anatop_base = (void *)ANATOP_BASE_ADDR;
 
 	clk_dm(IMX93_CLK_ARM_PLL,
 	       imx_clk_fracn_gppll_integer("arm_pll", "clock-osc-24m",
diff --git a/drivers/cpu/imx9_cpu.c b/drivers/cpu/imx9_cpu.c
deleted file mode 100644
index 66534fe..0000000
--- a/drivers/cpu/imx9_cpu.c
+++ /dev/null
@@ -1,224 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2019 NXP
- */
-
-#include <common.h>
-#include <cpu.h>
-#include <dm.h>
-#include <thermal.h>
-#include <asm/global_data.h>
-#include <asm/system.h>
-#include <firmware/linux/imx/sci/sci.h>
-#include <asm/arch/sys_proto.h>
-#include <asm/arch-imx/cpu.h>
-#include <asm/armv8/cpu.h>
-#include <linux/bitops.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-struct cpu_imx_plat {
-	const char *name;
-	const char *rev;
-	const char *type;
-	u32 cpu_rsrc;
-	u32 cpurev;
-	u32 freq_mhz;
-	u32 mpidr;
-};
-
-const char *get_imx9_type(u32 imxtype)
-{
-	switch (imxtype) {
-	case MXC_CPU_IMX93:
-		return "93";
-	default:
-		return "??";
-	}
-}
-
-const char *get_imx9_rev(u32 rev)
-{
-	switch (rev) {
-	case CHIP_REV_1_0:
-		return "1.";
-	case CHIP_REV_B:
-		return "B";
-	case CHIP_REV_C:
-		return "C";
-	default:
-		return "?";
-	}
-}
-
-static void set_core_data(struct udevice *dev)
-{
-	struct cpu_imx_plat *plat = dev_get_plat(dev);
-
-	if (device_is_compatible(dev, "arm,cortex-a35"))
-		plat->name = "A35";
-	else
-		plat->name = "?";
-}
-
-#if IS_ENABLED(CONFIG_IMX_SCU_THERMAL)
-static int cpu_imx_get_temp(struct cpu_imx_plat *plat)
-{
-	struct udevice *thermal_dev;
-	int cpu_tmp, ret;
-	int idx = 1; /* use "cpu-thermal0" device */
-
-	if (plat->cpu_rsrc == SC_R_A72)
-		idx = 2; /* use "cpu-thermal1" device */
-
-	ret = uclass_get_device(UCLASS_THERMAL, idx, &thermal_dev);
-	if (!ret) {
-		ret = thermal_get_temp(thermal_dev, &cpu_tmp);
-		if (ret)
-			return 0xdeadbeef;
-	} else {
-		return 0xdeadbeef;
-	}
-
-	return cpu_tmp;
-}
-#else
-static int cpu_imx_get_temp(struct cpu_imx_plat *plat)
-{
-	return 0;
-}
-#endif
-
-int cpu_imx_get_desc(const struct udevice *dev, char *buf, int size)
-{
-	struct cpu_imx_plat *plat = dev_get_plat(dev);
-	int ret, temp;
-
-	if (size < 100)
-		return -ENOSPC;
-
-	ret = snprintf(buf, size, "NXP i.MX8%s Rev%s %s at %u MHz",
-		       plat->type, plat->rev, plat->name, plat->freq_mhz);
-
-	if (IS_ENABLED(CONFIG_IMX_SCU_THERMAL)) {
-		temp = cpu_imx_get_temp(plat);
-		buf = buf + ret;
-		size = size - ret;
-		if (temp != 0xdeadbeef)
-			ret = snprintf(buf, size, " at %dC", temp);
-		else
-			ret = snprintf(buf, size, " - invalid sensor data");
-	}
-
-	snprintf(buf + ret, size - ret, "\n");
-
-	return 0;
-}
-
-static int cpu_imx_get_info(const struct udevice *dev, struct cpu_info *info)
-{
-	struct cpu_imx_plat *plat = dev_get_plat(dev);
-
-	info->cpu_freq = plat->freq_mhz * 1000;
-	info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
-	return 0;
-}
-
-static int cpu_imx_get_count(const struct udevice *dev)
-{
-	ofnode node;
-	int num = 0;
-
-	ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
-		const char *device_type;
-
-		if (!ofnode_is_enabled(node))
-			continue;
-
-		device_type = ofnode_read_string(node, "device_type");
-		if (!device_type)
-			continue;
-
-		if (!strcmp(device_type, "cpu"))
-			num++;
-	}
-
-	return num;
-}
-
-static int cpu_imx_get_vendor(const struct udevice *dev,  char *buf, int size)
-{
-	snprintf(buf, size, "NXP");
-	return 0;
-}
-
-static int cpu_imx_is_current(struct udevice *dev)
-{
-	struct cpu_imx_plat *plat = dev_get_plat(dev);
-
-	if (plat->mpidr == (read_mpidr() & 0xffff))
-		return 1;
-
-	return 0;
-}
-
-static const struct cpu_ops cpu_imx9_ops = {
-	.get_desc	= cpu_imx_get_desc,
-	.get_info	= cpu_imx_get_info,
-	.get_count	= cpu_imx_get_count,
-	.get_vendor	= cpu_imx_get_vendor,
-	.is_current	= cpu_imx_is_current,
-};
-
-static const struct udevice_id cpu_imx9_ids[] = {
-	{ .compatible = "arm,cortex-a35" },
-	{ .compatible = "arm,cortex-a53" },
-	{ .compatible = "arm,cortex-a72" },
-	{ }
-};
-
-static ulong imx9_get_cpu_rate(struct udevice *dev)
-{
-	struct cpu_imx_plat *plat = dev_get_plat(dev);
-	ulong rate;
-	int ret;
-
-	ret = sc_pm_get_clock_rate(-1, plat->cpu_rsrc, SC_PM_CLK_CPU,
-				   (sc_pm_clock_rate_t *)&rate);
-	if (ret) {
-		printf("Could not read CPU frequency: %d\n", ret);
-		return 0;
-	}
-
-	return rate;
-}
-
-static int imx9_cpu_probe(struct udevice *dev)
-{
-	struct cpu_imx_plat *plat = dev_get_plat(dev);
-	u32 cpurev;
-
-	set_core_data(dev);
-	cpurev = get_cpu_rev();
-	plat->cpurev = cpurev;
-	plat->rev = get_imx9_rev(cpurev & 0xFFF);
-	plat->type = get_imx9_type((cpurev & 0xFF000) >> 12);
-	plat->freq_mhz = imx9_get_cpu_rate(dev) / 1000000;
-	plat->mpidr = dev_read_addr(dev);
-	if (plat->mpidr == FDT_ADDR_T_NONE) {
-		printf("%s: Failed to get CPU reg property\n", __func__);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-U_BOOT_DRIVER(cpu_imx9_drv) = {
-	.name		= "imx9x_cpu",
-	.id		= UCLASS_CPU,
-	.of_match	= cpu_imx9_ids,
-	.ops		= &cpu_imx9_ops,
-	.probe		= imx9_cpu_probe,
-	.plat_auto	= sizeof(struct cpu_imx_plat),
-	.flags		= DM_FLAG_PRE_RELOC,
-};
diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c
index 5d1026b..9b1950e 100644
--- a/drivers/cpu/riscv_cpu.c
+++ b/drivers/cpu/riscv_cpu.c
@@ -21,13 +21,13 @@
 
 static int riscv_cpu_get_desc(const struct udevice *dev, char *buf, int size)
 {
-	const char *isa;
+	const char *cpu;
 
-	isa = dev_read_string(dev, "riscv,isa");
-	if (size < (strlen(isa) + 1))
+	cpu = dev_read_string(dev, "compatible");
+	if (size < (strlen(cpu) + 1))
 		return -ENOSPC;
 
-	strcpy(buf, isa);
+	strcpy(buf, cpu);
 
 	return 0;
 }
diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig
index 5e5855a..d6e2be0 100644
--- a/drivers/fastboot/Kconfig
+++ b/drivers/fastboot/Kconfig
@@ -1,5 +1,4 @@
 menu "Fastboot support"
-	depends on CMDLINE
 
 config FASTBOOT
 	bool
@@ -13,6 +12,10 @@
 	  More information about the protocol and usecases:
 	  https://android.googlesource.com/platform/system/core/+/refs/heads/master/fastboot/
 
+	  Note that enabling CMDLINE is recommended since fastboot allows U-Boot
+	  commands to be executed on request. The CMDLINE option is required
+	  for anything other than simply booting the OS.
+
 config USB_FUNCTION_FASTBOOT
 	bool "Enable USB fastboot gadget"
 	depends on USB_GADGET
diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c
index f95f4e4..b8782bf 100644
--- a/drivers/fastboot/fb_command.c
+++ b/drivers/fastboot/fb_command.c
@@ -11,6 +11,7 @@
 #include <fastboot-internal.h>
 #include <fb_mmc.h>
 #include <fb_nand.h>
+#include <mapmem.h>
 #include <part.h>
 #include <stdlib.h>
 #include <linux/printk.h>
@@ -278,6 +279,7 @@
 {
 #define BYTES_PER_DOT	0x20000
 	u32 pre_dot_num, now_dot_num;
+	void *buf;
 
 	if (fastboot_data_len == 0 ||
 	    (fastboot_bytes_received + fastboot_data_len) >
@@ -287,8 +289,10 @@
 		return;
 	}
 	/* Download data to fastboot_buf_addr */
-	memcpy(fastboot_buf_addr + fastboot_bytes_received,
+	buf = map_sysmem(fastboot_buf_addr, 0);
+	memcpy(buf + fastboot_bytes_received,
 	       fastboot_data, fastboot_data_len);
+	unmap_sysmem(buf);
 
 	pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT;
 	fastboot_bytes_received += fastboot_data_len;
@@ -331,13 +335,16 @@
  */
 static void __maybe_unused flash(char *cmd_parameter, char *response)
 {
+	void *buf = map_sysmem(fastboot_buf_addr, 0);
+
 	if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
-		fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr,
-					 image_size, response);
+		fastboot_mmc_flash_write(cmd_parameter, buf, image_size,
+					 response);
 
 	if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_NAND))
-		fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr,
-					  image_size, response);
+		fastboot_nand_flash_write(cmd_parameter, buf, image_size,
+					  response);
+	unmap_sysmem(buf);
 }
 
 /**
diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c
index 3576b06..5959545 100644
--- a/drivers/fastboot/fb_common.c
+++ b/drivers/fastboot/fb_common.c
@@ -11,6 +11,7 @@
  */
 
 #include <bcb.h>
+#include <bootm.h>
 #include <common.h>
 #include <command.h>
 #include <env.h>
@@ -20,7 +21,7 @@
 /**
  * fastboot_buf_addr - base address of the fastboot download buffer
  */
-void *fastboot_buf_addr;
+ulong fastboot_buf_addr;
 
 /**
  * fastboot_buf_size - size of the fastboot download buffer
@@ -142,22 +143,19 @@
  */
 void fastboot_boot(void)
 {
-	char *s;
+	char *s = NULL;
 
-	s = env_get("fastboot_bootcmd");
-	if (s) {
-		run_command(s, CMD_FLAG_ENV);
-	} else if (IS_ENABLED(CONFIG_CMD_BOOTM)) {
-		static char boot_addr_start[20];
-		static char *const bootm_args[] = {
-			"bootm", boot_addr_start, NULL
-		};
+	if (IS_ENABLED(CONFIG_CMDLINE)) {
+		s = env_get("fastboot_bootcmd");
+		if (s)
+			run_command(s, CMD_FLAG_ENV);
+	}
 
-		snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
-			 "0x%p", fastboot_buf_addr);
-		printf("Booting kernel at %s...\n\n\n", boot_addr_start);
+	if (!s && IS_ENABLED(CONFIG_BOOTM)) {
+		int ret;
 
-		do_bootm(NULL, 0, 2, bootm_args);
+		printf("Booting kernel at %lx...\n\n\n", fastboot_buf_addr);
+		ret = bootm_boot_start(fastboot_buf_addr, NULL);
 
 		/*
 		 * This only happens if image is somehow faulty so we start
@@ -214,16 +212,9 @@
 	fastboot_progress_callback = progress;
 }
 
-/*
- * fastboot_init() - initialise new fastboot protocol session
- *
- * @buf_addr: Pointer to download buffer, or NULL for default
- * @buf_size: Size of download buffer, or zero for default
- */
-void fastboot_init(void *buf_addr, u32 buf_size)
+void fastboot_init(ulong buf_addr, u32 buf_size)
 {
-	fastboot_buf_addr = buf_addr ? buf_addr :
-				       (void *)CONFIG_FASTBOOT_BUF_ADDR;
+	fastboot_buf_addr = buf_addr ? buf_addr : CONFIG_FASTBOOT_BUF_ADDR;
 	fastboot_buf_size = buf_size ? buf_size : CONFIG_FASTBOOT_BUF_SIZE;
 	fastboot_set_progress_callback(NULL);
 }
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index ee09218..6c581b9 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -16,6 +16,7 @@
 #include <dm/device.h>
 #include <dm/device_compat.h>
 #include <dm/devres.h>
+#include <dm/lists.h>
 #include <linux/bitops.h>
 #include <linux/compat.h>
 #include <linux/err.h>
@@ -2840,6 +2841,12 @@
 
 	INIT_LIST_HEAD(&info->dev_list);
 
+	if (IS_ENABLED(CONFIG_SYSRESET_TI_SCI)) {
+		ret = device_bind_driver(dev, "ti-sci-sysreset", "sysreset", NULL);
+		if (ret)
+			dev_warn(dev, "cannot bind SYSRESET (ret = %d)\n", ret);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpio/imx_rgpio2p.c b/drivers/gpio/imx_rgpio2p.c
index 175e460..3227a8d 100644
--- a/drivers/gpio/imx_rgpio2p.c
+++ b/drivers/gpio/imx_rgpio2p.c
@@ -21,6 +21,12 @@
 
 #define GPIO_PER_BANK			32
 
+struct imx_rgpio2p_soc_data {
+	bool have_dual_base;
+};
+
+#define IMX8ULP_GPIO_BASE_OFF	0x40
+
 struct imx_rgpio2p_data {
 	struct gpio_regs *regs;
 };
@@ -165,6 +171,9 @@
 static int imx_rgpio2p_bind(struct udevice *dev)
 {
 	struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
+	struct imx_rgpio2p_soc_data *data =
+		(struct imx_rgpio2p_soc_data *)dev_get_driver_data(dev);
+	bool dual_base = data->have_dual_base;
 	fdt_addr_t addr;
 
 	/*
@@ -176,9 +185,26 @@
 	if (plat)
 		return 0;
 
-	addr = devfdt_get_addr_index(dev, 1);
-	if (addr == FDT_ADDR_T_NONE)
-		return -EINVAL;
+	/*
+	 * Handle legacy compatible combinations which used two reg values
+	 * for the i.MX8ULP and i.MX93.
+	 */
+	if (device_is_compatible(dev, "fsl,imx7ulp-gpio") &&
+	    (device_is_compatible(dev, "fsl,imx93-gpio") ||
+	    (device_is_compatible(dev, "fsl,imx8ulp-gpio"))))
+		dual_base = true;
+
+	if (dual_base) {
+		addr = devfdt_get_addr_index(dev, 1);
+		if (addr == FDT_ADDR_T_NONE)
+			return -EINVAL;
+	} else {
+		addr = devfdt_get_addr_index(dev, 0);
+		if (addr == FDT_ADDR_T_NONE)
+			return -EINVAL;
+
+		addr += IMX8ULP_GPIO_BASE_OFF;
+	}
 
 	/*
 	 * TODO:
@@ -202,9 +228,17 @@
 	return 0;
 }
 
+static struct imx_rgpio2p_soc_data imx7ulp_data = {
+	.have_dual_base = true,
+};
+
+static struct imx_rgpio2p_soc_data imx8ulp_data = {
+	.have_dual_base = false,
+};
 
 static const struct udevice_id imx_rgpio2p_ids[] = {
-	{ .compatible = "fsl,imx7ulp-gpio" },
+	{ .compatible = "fsl,imx7ulp-gpio", .data = (ulong)&imx7ulp_data },
+	{ .compatible = "fsl,imx8ulp-gpio", .data = (ulong)&imx8ulp_data },
 	{ }
 };
 
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 9e82990..e53d52c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -91,4 +91,4 @@
 obj-$(CONFIG_ESM_K3) += k3_esm.o
 obj-$(CONFIG_ESM_PMIC) += esm_pmic.o
 obj-$(CONFIG_SL28CPLD) += sl28cpld.o
-obj-$(CONFIG_SPL_SOCFPGA_SEC_REG) += socfpga_dtreg.o
+obj-$(CONFIG_SPL_SOCFPGA_DT_REG) += socfpga_dtreg.o
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index cef0579..06e32e7 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -20,11 +20,19 @@
 
 config MMC_PWRSEQ
 	bool "HW reset support for eMMC"
-	depends on PWRSEQ
+	depends on PWRSEQ && DM_GPIO
 	help
-	  Ths select Hardware reset support aka pwrseq-emmc for eMMC
+	  This select Hardware reset support aka pwrseq-emmc for eMMC
 	  devices.
 
+config SPL_MMC_PWRSEQ
+	bool "HW reset support for eMMC in SPL"
+	depends on SPL_PWRSEQ && SPL_DM_GPIO
+	default y if MMC_PWRSEQ
+	help
+	  This select Hardware reset support aka pwrseq-emmc for eMMC
+	  devices in SPL.
+
 config MMC_BROKEN_CD
 	bool "Poll for broken card detection case"
 	help
@@ -79,11 +87,12 @@
 
 config ARM_PL180_MMCI
 	bool "ARM AMBA Multimedia Card Interface and compatible support"
+	depends on DM_MMC
 	help
 	  This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
 	  Interface (PL180, PL181 and compatible) support.
 	  If you have an ARM(R) platform with a Multimedia Card slot,
-	  say Y or M here.
+	  say Y here.
 
 config MMC_QUIRKS
 	bool "Enable quirks"
@@ -568,6 +577,19 @@
 
 	  If unsure, say N.
 
+config MMC_SDHCI_CV1800B
+	bool "SDHCI support for the CV1800B SD/SDIO/eMMC controller"
+	depends on BLK && DM_MMC
+	depends on MMC_SDHCI
+	depends on OF_CONTROL
+	help
+	  This selects the CV1800B SD/SDIO/eMMC driver.
+
+	  If you have a controller with this interface,
+	  say Y here.
+
+	  If unsure, say N.
+
 config MMC_SDHCI_AM654
 	bool "SDHCI Controller on TI's Am654 devices"
 	depends on ARCH_K3
@@ -586,7 +608,7 @@
 	  This selects the iProc SD/MMC controller.
 
 	  If you have a Broadcom IPROC platform with SD or MMC devices,
-	  say Y or M here.
+	  say Y here.
 
 	  If unsure, say N.
 
@@ -597,7 +619,7 @@
 	help
 	  This selects the Secure Digital Host Controller Interface (SDHCI)
 	  Needed by some Fujitsu/Socionext SoC for MMC / SD / SDIO support.
-	  If you have a controller with this interface, say Y or M here.
+	  If you have a controller with this interface, say Y here.
 	  If unsure, say N.
 
 config MMC_SDHCI_KONA
@@ -791,7 +813,7 @@
 	help
 	  This selects support for the SD/MMC controller on STM32H7 SoCs.
 	  If you have a board based on such a SoC and with a SD/MMC slot,
-	  say Y or M here.
+	  say Y here.
 
 config FTSDC010
 	bool "Ftsdc010 SD/MMC controller Support"
@@ -811,7 +833,7 @@
 	depends on OF_CONTROL
 	help
 	  This selects the MediaTek(R) Secure digital and Multimedia card Interface.
-	  If you have a machine with a integrated SD/MMC card reader, say Y or M here.
+	  If you have a machine with a integrated SD/MMC card reader, say Y here.
 	  This is needed if support for any SD/SDIO/MMC devices is required.
 	  If unsure, say N.
 
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index e9cf1fc..72c3fb6 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -11,7 +11,7 @@
 endif
 
 obj-$(CONFIG_$(SPL_TPL_)MMC_WRITE) += mmc_write.o
-obj-$(CONFIG_MMC_PWRSEQ) += mmc-pwrseq.o
+obj-$(CONFIG_$(SPL_)MMC_PWRSEQ) += mmc-pwrseq.o
 obj-$(CONFIG_MMC_SDHCI_ADMA_HELPERS) += sdhci-adma.o
 
 ifndef CONFIG_$(SPL_)BLK
@@ -60,6 +60,7 @@
 obj-$(CONFIG_MMC_SDHCI_BCM2835)		+= bcm2835_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_BCMSTB)		+= bcmstb_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_CADENCE)		+= sdhci-cadence.o
+obj-$(CONFIG_MMC_SDHCI_CV1800B)		+= cv1800b_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_AM654)		+= am654_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_IPROC)		+= iproc_sdhci.o
 obj-$(CONFIG_MMC_SDHCI_KONA)		+= kona_sdhci.o
diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c
index 05595bd..2139fea 100644
--- a/drivers/mmc/am654_sdhci.c
+++ b/drivers/mmc/am654_sdhci.c
@@ -390,7 +390,7 @@
 	for (itap = 0; itap < ITAP_MAX; itap++) {
 		am654_sdhci_write_itapdly(plat, itap);
 
-		cur_val = !mmc_send_tuning(mmc, opcode, NULL);
+		cur_val = !mmc_send_tuning(mmc, opcode);
 		if (cur_val && !prev_val)
 			pass_window = itap;
 
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index 5cf5502..2666b65 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -18,6 +18,7 @@
 #include <malloc.h>
 #include <mmc.h>
 #include <dm/device_compat.h>
+#include <dm.h>
 
 #include <asm/io.h>
 #include <asm-generic/gpio.h>
@@ -25,8 +26,6 @@
 #include "arm_pl180_mmci.h"
 #include <linux/delay.h>
 
-#ifdef CONFIG_DM_MMC
-#include <dm.h>
 #define MMC_CLOCK_MAX	48000000
 #define MMC_CLOCK_MIN	400000
 
@@ -34,7 +33,6 @@
 	struct mmc_config cfg;
 	struct mmc mmc;
 };
-#endif
 
 static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
 {
@@ -355,68 +353,9 @@
 	writel(sdi_clkcr, &host->base->clock);
 	udelay(CLK_CHANGE_DELAY);
 
-	return 0;
-}
-
-#ifndef CONFIG_DM_MMC
-/* MMC uses open drain drivers in the enumeration phase */
-static int mmc_host_reset(struct mmc *dev)
-{
-	struct pl180_mmc_host *host = dev->priv;
-
-	writel(host->pwr_init, &host->base->power);
-
-	return 0;
-}
-
-static const struct mmc_ops arm_pl180_mmci_ops = {
-	.send_cmd = host_request,
-	.set_ios = host_set_ios,
-	.init = mmc_host_reset,
-};
-
-/*
- * mmc_host_init - initialize the mmc controller.
- * Set initial clock and power for mmc slot.
- * Initialize mmc struct and register with mmc framework.
- */
-
-int arm_pl180_mmci_init(struct pl180_mmc_host *host, struct mmc **mmc)
-{
-	u32 sdi_u32;
-
-	writel(host->pwr_init, &host->base->power);
-	writel(host->clkdiv_init, &host->base->clock);
-	udelay(CLK_CHANGE_DELAY);
-
-	/* Disable mmc interrupts */
-	sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK;
-	writel(sdi_u32, &host->base->mask0);
-
-	host->cfg.name = host->name;
-	host->cfg.ops = &arm_pl180_mmci_ops;
-
-	/* TODO remove the duplicates */
-	host->cfg.host_caps = host->caps;
-	host->cfg.voltages = host->voltages;
-	host->cfg.f_min = host->clock_min;
-	host->cfg.f_max = host->clock_max;
-	if (host->b_max != 0)
-		host->cfg.b_max = host->b_max;
-	else
-		host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
-
-	*mmc = mmc_create(&host->cfg, host);
-	if (!*mmc)
-		return -1;
-	debug("registered mmc interface number is:%d\n",
-	      (*mmc)->block_dev.devnum);
-
 	return 0;
 }
-#endif
 
-#ifdef CONFIG_DM_MMC
 static void arm_pl180_mmc_init(struct pl180_mmc_host *host)
 {
 	u32 sdi_u32;
@@ -477,7 +416,7 @@
 		host->version2 = true;
 		break;
 	default:
-		host->version2 = true;
+		host->version2 = false; /* ARM variant */
 	}
 
 	gpio_request_by_name(dev, "cd-gpios", 0, &host->cd_gpio, GPIOD_IS_IN);
@@ -561,4 +500,3 @@
 	.priv_auto	= sizeof(struct pl180_mmc_host),
 	.plat_auto	= sizeof(struct arm_pl180_mmc_plat),
 };
-#endif
diff --git a/drivers/mmc/cv1800b_sdhci.c b/drivers/mmc/cv1800b_sdhci.c
new file mode 100644
index 0000000..9af6b97
--- /dev/null
+++ b/drivers/mmc/cv1800b_sdhci.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2024, Kongyang Liu <seashell11234455@gmail.com>
+ */
+
+#include <dm.h>
+#include <mmc.h>
+#include <sdhci.h>
+#include <linux/delay.h>
+
+#define SDHCI_PHY_TX_RX_DLY  0x240
+#define MMC_MAX_CLOCK        375000000
+#define TUNE_MAX_PHCODE      128
+
+struct cv1800b_sdhci_plat {
+	struct mmc_config cfg;
+	struct mmc mmc;
+};
+
+static void cv1800b_set_tap_delay(struct sdhci_host *host, u16 tap)
+{
+	sdhci_writel(host, tap << 16, SDHCI_PHY_TX_RX_DLY);
+}
+
+static void cv1800b_sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
+	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask)
+		udelay(10);
+}
+
+static int cv1800b_execute_tuning(struct mmc *mmc, u8 opcode)
+{
+	struct sdhci_host *host = dev_get_priv(mmc->dev);
+
+	u16 tap;
+
+	int current_size = 0;
+	int max_size = 0;
+	int max_window = 0;
+
+	for (tap = 0; tap < TUNE_MAX_PHCODE; tap++) {
+		cv1800b_set_tap_delay(host, tap);
+
+		if (mmc_send_tuning(host->mmc, opcode)) {
+			current_size = 0;
+		} else {
+			current_size++;
+			if (current_size > max_size) {
+				max_size = current_size;
+				max_window = tap;
+			}
+		}
+	}
+
+	cv1800b_sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
+	cv1800b_set_tap_delay(host, max_window - max_size / 2);
+
+	return 0;
+}
+
+const struct sdhci_ops cv1800b_sdhci_sd_ops = {
+	.platform_execute_tuning = cv1800b_execute_tuning,
+};
+
+static int cv1800b_sdhci_bind(struct udevice *dev)
+{
+	struct cv1800b_sdhci_plat *plat = dev_get_plat(dev);
+
+	return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static int cv1800b_sdhci_probe(struct udevice *dev)
+{
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct cv1800b_sdhci_plat *plat = dev_get_plat(dev);
+	struct sdhci_host *host = dev_get_priv(dev);
+	int ret;
+
+	host->name = dev->name;
+	host->ioaddr = devfdt_get_addr_ptr(dev);
+
+	upriv->mmc = &plat->mmc;
+	host->mmc = &plat->mmc;
+	host->mmc->priv = host;
+	host->mmc->dev = dev;
+	host->ops = &cv1800b_sdhci_sd_ops;
+	host->max_clk = MMC_MAX_CLOCK;
+
+	ret = mmc_of_parse(dev, &plat->cfg);
+	if (ret)
+		return ret;
+
+	ret = sdhci_setup_cfg(&plat->cfg, host, 0, 200000);
+	if (ret)
+		return ret;
+
+	return sdhci_probe(dev);
+}
+
+static const struct udevice_id cv1800b_sdhci_match[] = {
+	{ .compatible = "sophgo,cv1800b-dwcmshc" },
+	{ }
+};
+
+U_BOOT_DRIVER(cv1800b_sdhci) = {
+	.name = "sdhci-cv1800b",
+	.id = UCLASS_MMC,
+	.of_match = cv1800b_sdhci_match,
+	.bind = cv1800b_sdhci_bind,
+	.probe = cv1800b_sdhci_probe,
+	.priv_auto = sizeof(struct sdhci_host),
+	.plat_auto = sizeof(struct cv1800b_sdhci_plat),
+	.ops = &sdhci_ops,
+};
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 400066f..e103664 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -262,8 +262,8 @@
 
 	while (dwmci_readl(host, DWMCI_STATUS) & DWMCI_BUSY) {
 		if (get_timer(start) > timeout) {
-			debug("%s: Timeout on data busy\n", __func__);
-			return -ETIMEDOUT;
+			debug("%s: Timeout on data busy, continue anyway\n", __func__);
+			break;
 		}
 	}
 
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index d506666..d44dfa5 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -1123,7 +1123,7 @@
 	esdhc_write32(&regs->irqstaten, IRQSTATEN_BRR);
 
 	for (i = 0; i < MAX_TUNING_LOOP; i++) {
-		mmc_send_tuning(mmc, opcode, NULL);
+		mmc_send_tuning(mmc, opcode);
 		mdelay(1);
 
 		val = esdhc_read32(&regs->autoc12err);
diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c
index 7c39c86..b74c014 100644
--- a/drivers/mmc/fsl_esdhc_imx.c
+++ b/drivers/mmc/fsl_esdhc_imx.c
@@ -882,7 +882,7 @@
 		esdhc_write32(&regs->mixctrl, val);
 
 		/* We are using STD tuning, no need to check return value */
-		mmc_send_tuning(mmc, opcode, NULL);
+		mmc_send_tuning(mmc, opcode);
 
 		ctrl = esdhc_read32(&regs->autoc12err);
 		if ((!(ctrl & MIX_CTRL_EXE_TUNE)) &&
diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c
index 71962cd..dc02104 100644
--- a/drivers/mmc/hi6220_dw_mmc.c
+++ b/drivers/mmc/hi6220_dw_mmc.c
@@ -5,15 +5,24 @@
  */
 
 #include <common.h>
+#include <clk.h>
 #include <dm.h>
 #include <dwmmc.h>
 #include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
+#include <reset.h>
 #include <asm/global_data.h>
+#include <dm/device_compat.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+enum hi6220_dwmmc_clk_type {
+	HI6220_DWMMC_CLK_BIU,
+	HI6220_DWMMC_CLK_CIU,
+	HI6220_DWMMC_CLK_CNT,
+};
+
 struct hi6220_dwmmc_plat {
 	struct mmc_config cfg;
 	struct mmc mmc;
@@ -21,18 +30,43 @@
 
 struct hi6220_dwmmc_priv_data {
 	struct dwmci_host host;
+	struct clk *clks[HI6220_DWMMC_CLK_CNT];
+	struct reset_ctl_bulk rsts;
 };
 
 struct hisi_mmc_data {
 	unsigned int clock;
 	bool use_fifo;
+	u32 fifoth_val;
 };
 
 static int hi6220_dwmmc_of_to_plat(struct udevice *dev)
 {
 	struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev);
 	struct dwmci_host *host = &priv->host;
+	int ret;
+
+	if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) {
+		priv->clks[HI6220_DWMMC_CLK_BIU] = devm_clk_get(dev, "biu");
+		if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_BIU])) {
+			ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_BIU]);
+			dev_err(dev, "Failed to get BIU clock(ret = %d).\n", ret);
+			return log_msg_ret("clk", ret);
+		}
 
+		priv->clks[HI6220_DWMMC_CLK_CIU] = devm_clk_get(dev, "ciu");
+		if (IS_ERR(priv->clks[HI6220_DWMMC_CLK_CIU])) {
+			ret = PTR_ERR(priv->clks[HI6220_DWMMC_CLK_CIU]);
+			dev_err(dev, "Failed to get CIU clock(ret = %d).\n", ret);
+			return log_msg_ret("clk", ret);
+		}
+
+		ret = reset_get_bulk(dev, &priv->rsts);
+		if (ret) {
+			dev_err(dev, "Failed to get resets(ret = %d)", ret);
+			return log_msg_ret("rst", ret);
+		}
+	}
 	host->name = dev->name;
 	host->ioaddr = dev_read_addr_ptr(dev);
 	host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
@@ -56,16 +90,43 @@
 	struct hi6220_dwmmc_priv_data *priv = dev_get_priv(dev);
 	struct dwmci_host *host = &priv->host;
 	struct hisi_mmc_data *mmc_data;
+	int ret;
 
 	mmc_data = (struct hisi_mmc_data *)dev_get_driver_data(dev);
 
-	/* Use default bus speed due to absence of clk driver */
 	host->bus_hz = mmc_data->clock;
+	if (CONFIG_IS_ENABLED(CLK) && CONFIG_IS_ENABLED(DM_RESET)) {
+		ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_BIU]);
+		if (ret) {
+			dev_err(dev, "Failed to enable biu clock(ret = %d).\n", ret);
+			return log_msg_ret("clk", ret);
+		}
+
+		ret = clk_prepare_enable(priv->clks[HI6220_DWMMC_CLK_CIU]);
+		if (ret) {
+			dev_err(dev, "Failed to enable ciu clock(ret = %d).\n", ret);
+			return log_msg_ret("clk", ret);
+		}
+
+		ret = reset_deassert_bulk(&priv->rsts);
+		if (ret) {
+			dev_err(dev, "Failed to deassert resets(ret = %d).\n", ret);
+			return log_msg_ret("rst", ret);
+		}
+
+		host->bus_hz = clk_get_rate(priv->clks[HI6220_DWMMC_CLK_CIU]);
+		if (host->bus_hz <= 0) {
+			dev_err(dev, "Failed to get ciu clock rate(ret = %d).\n", ret);
+			return log_msg_ret("clk", ret);
+		}
+	}
+	dev_dbg(dev, "bus clock rate: %d.\n", host->bus_hz);
 
 	dwmci_setup_cfg(&plat->cfg, host, host->bus_hz, 400000);
 	host->mmc = &plat->mmc;
 
 	host->fifo_mode = mmc_data->use_fifo;
+	host->fifoth_val = mmc_data->fifoth_val;
 	host->mmc->priv = &priv->host;
 	upriv->mmc = host->mmc;
 	host->mmc->dev = dev;
@@ -95,13 +156,20 @@
 	.use_fifo = false,
 };
 
+static const struct hisi_mmc_data hi3798mv2x_mmc_data = {
+	.clock = 50000000,
+	.use_fifo = false,
+	// FIFO depth is 256
+	.fifoth_val = MSIZE(4) | RX_WMARK(0x7f) | TX_WMARK(0x80),
+};
+
 static const struct udevice_id hi6220_dwmmc_ids[] = {
 	{ .compatible = "hisilicon,hi6220-dw-mshc",
 	  .data = (ulong)&hi6220_mmc_data },
 	{ .compatible = "hisilicon,hi3798cv200-dw-mshc",
 	  .data = (ulong)&hi6220_mmc_data },
 	{ .compatible = "hisilicon,hi3798mv200-dw-mshc",
-	  .data = (ulong)&hi6220_mmc_data },
+	  .data = (ulong)&hi3798mv2x_mmc_data },
 	{ .compatible = "hisilicon,hi3660-dw-mshc",
 	  .data = (ulong)&hi3660_mmc_data },
 	{ }
diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c
index fcf4f03..0825c0a 100644
--- a/drivers/mmc/meson_gx_mmc.c
+++ b/drivers/mmc/meson_gx_mmc.c
@@ -288,7 +288,7 @@
 
 	mmc_set_clock(mmc, cfg->f_min, MMC_CLK_ENABLE);
 
-#ifdef CONFIG_MMC_PWRSEQ
+#if CONFIG_IS_ENABLED(MMC_PWRSEQ)
 	/* Enable power if needed */
 	ret = mmc_pwrseq_get_power(dev, cfg);
 	if (!ret) {
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 3284568..1e03901 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -124,7 +124,13 @@
 
 int mmc_execute_tuning(struct mmc *mmc, uint opcode)
 {
-	return dm_mmc_execute_tuning(mmc->dev, opcode);
+	int ret;
+
+	mmc->tuning = true;
+	ret = dm_mmc_execute_tuning(mmc->dev, opcode);
+	mmc->tuning = false;
+
+	return ret;
 }
 #endif
 
@@ -494,10 +500,7 @@
 	if (ret) {
 		debug("Probing %s failed (err=%d)\n", dev->name, ret);
 
-		if (CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) ||
-		    CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) ||
-		    CONFIG_IS_ENABLED(MMC_HS400_SUPPORT))
-			mmc_deinit(mmc);
+		mmc_deinit(mmc);
 
 		return ret;
 	}
@@ -505,9 +508,6 @@
 	return 0;
 }
 
-#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
-    CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
-    CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
 static int mmc_blk_remove(struct udevice *dev)
 {
 	struct udevice *mmc_dev = dev_get_parent(dev);
@@ -516,7 +516,6 @@
 
 	return mmc_deinit(mmc);
 }
-#endif
 
 static const struct blk_ops mmc_blk_ops = {
 	.read	= mmc_bread,
@@ -532,12 +531,8 @@
 	.id		= UCLASS_BLK,
 	.ops		= &mmc_blk_ops,
 	.probe		= mmc_blk_probe,
-#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
-    CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
-    CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
 	.remove		= mmc_blk_remove,
 	.flags		= DM_FLAG_OS_PREPARE,
-#endif
 };
 #endif /* CONFIG_BLK */
 
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index d96db7a..7b068c7 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -360,7 +360,7 @@
 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
 };
 
-int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
+int mmc_send_tuning(struct mmc *mmc, u32 opcode)
 {
 	struct mmc_cmd cmd;
 	struct mmc_data data;
@@ -1570,13 +1570,20 @@
 	return 0;
 }
 #endif
-/* frequency bases */
-/* divided by 10 to be nice to platforms without floating point */
+/*
+ * TRAN_SPEED bits 0:2 encode the frequency unit:
+ * 0 = 100KHz, 1 = 1MHz, 2 = 10MHz, 3 = 100MHz, values 4 - 7 are reserved.
+ * The values in fbase[] are divided by 10 to avoid floats in multiplier[].
+ */
 static const int fbase[] = {
 	10000,
 	100000,
 	1000000,
 	10000000,
+	0,	/* reserved */
+	0,	/* reserved */
+	0,	/* reserved */
+	0,	/* reserved */
 };
 
 /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
@@ -2027,9 +2034,9 @@
 	mmc_set_clock(mmc, mmc->tran_speed, false);
 
 	/* execute tuning if needed */
-	mmc->hs400_tuning = 1;
+	mmc->hs400_tuning = true;
 	err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
-	mmc->hs400_tuning = 0;
+	mmc->hs400_tuning = false;
 	if (err) {
 		debug("tuning failed\n");
 		return err;
@@ -2250,6 +2257,16 @@
 
 	return -ENOTSUPP;
 }
+#else
+static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
+{
+	return 0;
+};
+
+static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
+{
+	return 0;
+};
 #endif
 
 #if CONFIG_IS_ENABLED(MMC_TINY)
@@ -2560,6 +2577,8 @@
 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
 
 	mmc->legacy_speed = freq * mult;
+	if (!mmc->legacy_speed)
+		log_debug("TRAN_SPEED: reserved value");
 	mmc_select_mode(mmc, MMC_LEGACY);
 
 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
@@ -3010,13 +3029,15 @@
 	return err;
 }
 
-#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
-    CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
-    CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
 int mmc_deinit(struct mmc *mmc)
 {
 	u32 caps_filtered;
 
+	if (!CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) &&
+	    !CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) &&
+	    !CONFIG_IS_ENABLED(MMC_HS400_SUPPORT))
+		return 0;
+
 	if (!mmc->has_init)
 		return 0;
 
@@ -3034,7 +3055,6 @@
 		return mmc_select_mode_and_width(mmc, caps_filtered);
 	}
 }
-#endif
 
 int mmc_set_dsr(struct mmc *mmc, u16 val)
 {
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
index 5a0c61d..296aaee 100644
--- a/drivers/mmc/mtk-sd.c
+++ b/drivers/mmc/mtk-sd.c
@@ -1131,7 +1131,7 @@
 				i << PAD_CMD_TUNE_RX_DLY3_S);
 
 		for (j = 0; j < 3; j++) {
-			mmc_send_tuning(mmc, opcode, &cmd_err);
+			cmd_err = mmc_send_tuning(mmc, opcode);
 			if (!cmd_err) {
 				cmd_delay |= (1 << i);
 			} else {
@@ -1181,7 +1181,7 @@
 				i << MSDC_PAD_TUNE_CMDRDLY_S);
 
 		for (j = 0; j < 3; j++) {
-			mmc_send_tuning(mmc, opcode, &cmd_err);
+			cmd_err = mmc_send_tuning(mmc, opcode);
 			if (!cmd_err) {
 				rise_delay |= (1 << i);
 			} else {
@@ -1203,7 +1203,7 @@
 				i << MSDC_PAD_TUNE_CMDRDLY_S);
 
 		for (j = 0; j < 3; j++) {
-			mmc_send_tuning(mmc, opcode, &cmd_err);
+			cmd_err = mmc_send_tuning(mmc, opcode);
 			if (!cmd_err) {
 				fall_delay |= (1 << i);
 			} else {
@@ -1238,7 +1238,7 @@
 		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M,
 				i << MSDC_PAD_TUNE_CMDRRDLY_S);
 
-		mmc_send_tuning(mmc, opcode, &cmd_err);
+		cmd_err = mmc_send_tuning(mmc, opcode);
 		if (!cmd_err)
 			internal_delay |= (1 << i);
 	}
@@ -1264,7 +1264,6 @@
 	struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0, };
 	u8 final_delay, final_maxlen;
 	void __iomem *tune_reg = &host->base->pad_tune;
-	int cmd_err;
 	int i, ret;
 
 	if (host->dev_comp->pad_tune0)
@@ -1277,10 +1276,10 @@
 		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M,
 				i << MSDC_PAD_TUNE_DATRRDLY_S);
 
-		ret = mmc_send_tuning(mmc, opcode, &cmd_err);
+		ret = mmc_send_tuning(mmc, opcode);
 		if (!ret) {
 			rise_delay |= (1 << i);
-		} else if (cmd_err) {
+		} else {
 			/* in this case, retune response is needed */
 			ret = msdc_tune_response(dev, opcode);
 			if (ret)
@@ -1300,10 +1299,10 @@
 		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M,
 				i << MSDC_PAD_TUNE_DATRRDLY_S);
 
-		ret = mmc_send_tuning(mmc, opcode, &cmd_err);
+		ret = mmc_send_tuning(mmc, opcode);
 		if (!ret) {
 			fall_delay |= (1 << i);
-		} else if (cmd_err) {
+		} else {
 			/* in this case, retune response is needed */
 			ret = msdc_tune_response(dev, opcode);
 			if (ret)
@@ -1362,7 +1361,7 @@
 	for (i = 0; i < PAD_DELAY_MAX; i++) {
 		msdc_set_cmd_delay(host, i);
 		msdc_set_data_delay(host, i);
-		ret = mmc_send_tuning(mmc, opcode, NULL);
+		ret = mmc_send_tuning(mmc, opcode);
 		if (!ret)
 			rise_delay |= (1 << i);
 	}
@@ -1378,7 +1377,7 @@
 	for (i = 0; i < PAD_DELAY_MAX; i++) {
 		msdc_set_cmd_delay(host, i);
 		msdc_set_data_delay(host, i);
-		ret = mmc_send_tuning(mmc, opcode, NULL);
+		ret = mmc_send_tuning(mmc, opcode);
 		if (!ret)
 			fall_delay |= (1 << i);
 	}
diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c
index 4ee62df..7f9c4f4 100644
--- a/drivers/mmc/octeontx_hsmmc.c
+++ b/drivers/mmc/octeontx_hsmmc.c
@@ -1653,6 +1653,12 @@
 	return err;
 }
 
+static int octeontx_mmc_send_tuning(struct mmc *mmc, u32 opcode, int *error)
+{
+	*error = 0;
+	return mmc_send_tuning(mmc, opcode);
+}
+
 static int octeontx_mmc_test_get_ext_csd(struct mmc *mmc, u32 opcode,
 					 int *statp)
 {
@@ -2006,7 +2012,7 @@
 	{ "CMD_IN", 48, octeontx_mmc_test_cmd, MMC_CMD_SEND_STATUS,
 	  false, false, false, 2, },
 /*	{ "CMD_OUT", 32, octeontx_mmc_test_cmd, MMC_CMD_SEND_STATUS, },*/
-	{ "DATA_IN(HS200)", 16, mmc_send_tuning,
+	{ "DATA_IN(HS200)", 16, octeontx_mmc_send_tuning,
 		MMC_CMD_SEND_TUNING_BLOCK_HS200, false, true, false, 2, },
 	{ "DATA_IN", 16, octeontx_mmc_test_get_ext_csd, 0, false, false,
 	  true, 2, },
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index a2595d1..99f21b2 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -666,7 +666,7 @@
 	while (phase_delay <= MAX_PHASE_DELAY) {
 		omap_hsmmc_set_dll(mmc, phase_delay);
 
-		cur_match = !mmc_send_tuning(mmc, opcode, NULL);
+		cur_match = !mmc_send_tuning(mmc, opcode);
 
 		if (cur_match) {
 			if (prev_match) {
@@ -731,7 +731,7 @@
 	 */
 	for (i = 3; i <= 10; i++) {
 		omap_hsmmc_set_dll(mmc, phase_delay + i);
-		if (mmc_send_tuning(mmc, opcode, NULL)) {
+		if (mmc_send_tuning(mmc, opcode)) {
 			if (temperature < 10000)
 				phase_delay += i + 6;
 			else if (temperature < 20000)
@@ -749,7 +749,7 @@
 
 	for (i = 2; i >= -10; i--) {
 		omap_hsmmc_set_dll(mmc, phase_delay + i);
-		if (mmc_send_tuning(mmc, opcode, NULL)) {
+		if (mmc_send_tuning(mmc, opcode)) {
 			if (temperature < 10000)
 				phase_delay += i + 12;
 			else if (temperature < 20000)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 20b1e92..23db2a7 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -568,8 +568,8 @@
 	struct mmc *mmc = upriv->mmc;
 	unsigned int tap_num;
 	unsigned int taps = 0;
-	int i, ret = 0;
-	u32 caps;
+	int i, ret = 0, sret;
+	u32 caps, reg;
 
 	/* Only supported on Renesas RCar */
 	if (!(priv->caps & TMIO_SD_CAP_RCAR_UHS))
@@ -605,15 +605,15 @@
 		caps = priv->caps;
 		priv->caps &= ~TMIO_SD_CAP_DMA_INTERNAL;
 
-		ret = mmc_send_tuning(mmc, opcode, NULL);
+		ret = mmc_send_tuning(mmc, opcode);
 
 		priv->caps = caps;
 
 		if (ret == 0)
 			taps |= BIT(i);
 
-		ret = renesas_sdhi_compare_scc_data(priv);
-		if (ret == 0)
+		reg = renesas_sdhi_compare_scc_data(priv);
+		if (reg == 0)
 			priv->smpcmp |= BIT(i);
 
 		mdelay(1);
@@ -624,9 +624,9 @@
 		 * 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);
+			sret = mmc_send_stop_transmission(mmc, false);
+			if (sret < 0)
+				dev_dbg(dev, "Tuning abort fail (%d)\n", sret);
 		}
 	}
 
@@ -798,9 +798,12 @@
 #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
     CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
     CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
 	struct tmio_sd_priv *priv = dev_get_priv(dev);
+	struct mmc *mmc = upriv->mmc;
 
-	renesas_sdhi_check_scc_error(dev);
+	if (!mmc->tuning)
+		renesas_sdhi_check_scc_error(dev);
 
 	if (cmd->cmdidx == MMC_CMD_SEND_STATUS)
 		renesas_sdhi_adjust_hs400_mode_enable(priv);
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index 72c820e..ad4529d 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -145,7 +145,7 @@
 
 	host->fifo_mode = priv->fifo_mode;
 
-#ifdef CONFIG_MMC_PWRSEQ
+#if CONFIG_IS_ENABLED(MMC_PWRSEQ)
 	/* Enable power if needed */
 	ret = mmc_pwrseq_get_power(dev, &plat->cfg);
 	if (!ret) {
diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c
index 327a05a..c0a9f60 100644
--- a/drivers/mmc/sdhci-cadence.c
+++ b/drivers/mmc/sdhci-cadence.c
@@ -224,7 +224,7 @@
 
 	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
 		if (sdhci_cdns_set_tune_val(plat, i) ||
-		    mmc_send_tuning(mmc, opcode, NULL)) { /* bad */
+		    mmc_send_tuning(mmc, opcode)) { /* bad */
 			cur_streak = 0;
 		} else { /* good */
 			cur_streak++;
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c
index 890c496..719c483 100644
--- a/drivers/mmc/tmio-common.c
+++ b/drivers/mmc/tmio-common.c
@@ -299,7 +299,13 @@
 	struct tmio_sd_priv *priv = dev_get_priv(dev);
 	long wait = 1000000 + 10 * blocks;
 
-	while (!(tmio_sd_readl(priv, TMIO_SD_DMA_INFO1) & flag)) {
+	for (;;) {
+		if (tmio_sd_readl(priv, TMIO_SD_DMA_INFO1) & flag)
+			break;
+
+		if (tmio_sd_readl(priv, TMIO_SD_INFO1) & TMIO_SD_INFO1_CMP)
+			break;
+
 		if (wait-- < 0) {
 			dev_err(dev, "timeout during DMA\n");
 			return -ETIMEDOUT;
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index bb9994b..9f3f126 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -1,6 +1,6 @@
-
 menuconfig MTD_RAW_NAND
 	bool "Raw NAND Device Support"
+
 if MTD_RAW_NAND
 
 config SYS_NAND_SELF_INIT
@@ -49,12 +49,12 @@
 	depends on NAND_ARASAN || NAND_DAVINCI || NAND_KIRKWOOD
 
 config DM_NAND_ATMEL
-       bool "Support Atmel NAND controller with DM support"
-       select SYS_NAND_SELF_INIT
-       imply SYS_NAND_USE_FLASH_BBT
-       help
-         Enable this driver for NAND flash platforms using an Atmel NAND
-         controller.
+	bool "Support Atmel NAND controller with DM support"
+	select SYS_NAND_SELF_INIT
+	imply SYS_NAND_USE_FLASH_BBT
+	help
+	  Enable this driver for NAND flash platforms using an Atmel NAND
+	  controller.
 
 config NAND_ATMEL
 	bool "Support Atmel NAND controller"
@@ -133,35 +133,35 @@
 	  Enable support for broadcom nand driver on bcm6753.
 
 config NAND_BRCMNAND_68360
-       bool "Support Broadcom NAND controller on bcm68360"
-       depends on NAND_BRCMNAND && BCM6856
-       help
-         Enable support for broadcom nand driver on bcm68360.
+	bool "Support Broadcom NAND controller on bcm68360"
+	depends on NAND_BRCMNAND && BCM6856
+	help
+	  Enable support for broadcom nand driver on bcm68360.
 
 config NAND_BRCMNAND_6838
-       bool "Support Broadcom NAND controller on bcm6838"
-       depends on NAND_BRCMNAND && ARCH_BMIPS && SOC_BMIPS_BCM6838
-       help
-         Enable support for broadcom nand driver on bcm6838.
+	bool "Support Broadcom NAND controller on bcm6838"
+	depends on NAND_BRCMNAND && ARCH_BMIPS && SOC_BMIPS_BCM6838
+	help
+	  Enable support for broadcom nand driver on bcm6838.
 
 config NAND_BRCMNAND_6858
-       bool "Support Broadcom NAND controller on bcm6858"
-       depends on NAND_BRCMNAND && BCM6858
-       help
-         Enable support for broadcom nand driver on bcm6858.
+	bool "Support Broadcom NAND controller on bcm6858"
+	depends on NAND_BRCMNAND && BCM6858
+	help
+	  Enable support for broadcom nand driver on bcm6858.
 
 config NAND_BRCMNAND_63158
-       bool "Support Broadcom NAND controller on bcm63158"
-       depends on NAND_BRCMNAND && BCM63158
-       help
-         Enable support for broadcom nand driver on bcm63158.
+	bool "Support Broadcom NAND controller on bcm63158"
+	depends on NAND_BRCMNAND && BCM63158
+	help
+	  Enable support for broadcom nand driver on bcm63158.
 
 config NAND_BRCMNAND_IPROC
-       bool "Support Broadcom NAND controller on the iproc family"
-       depends on NAND_BRCMNAND
-       help
-         Enable support for broadcom nand driver on the Broadcom
-         iproc family such as Northstar (BCM5301x, BCM4708...)
+	bool "Support Broadcom NAND controller on the iproc family"
+	depends on NAND_BRCMNAND
+	help
+	  Enable support for broadcom nand driver on the Broadcom
+	  iproc family such as Northstar (BCM5301x, BCM4708...)
 
 config NAND_DAVINCI
 	bool "Support TI Davinci NAND controller"
@@ -413,10 +413,10 @@
 if NAND_VF610_NFC
 
 config NAND_VF610_NFC_DT
-        bool "Support Vybrid's vf610 NAND controller as a DT device"
-        depends on OF_CONTROL && DM_MTD
-        help
-          Enable the driver for Vybrid's vf610 NAND flash on platforms
+	bool "Support Vybrid's vf610 NAND controller as a DT device"
+	depends on OF_CONTROL && DM_MTD
+	help
+	  Enable the driver for Vybrid's vf610 NAND flash on platforms
 	  using device tree.
 
 choice
@@ -472,11 +472,11 @@
 	select SPL_NAND_SUPPORT
 	select SPL_SYS_NAND_SELF_INIT
 	imply CMD_NAND
-	---help---
-	Enable support for NAND. This option enables the standard and
-	SPL drivers.
-	The SPL driver only supports reading from the NAND using DMA
-	transfers.
+	help
+	  Enable support for NAND. This option enables the standard and
+	  SPL drivers.
+	  The SPL driver only supports reading from the NAND using DMA
+	  transfers.
 
 if NAND_SUNXI
 
@@ -504,6 +504,15 @@
 	  controller. This uses the hardware ECC for read and
 	  write operations.
 
+config NAND_MESON
+	bool "Meson NAND support"
+	select SYS_NAND_SELF_INIT
+	depends on DM_MTD && ARCH_MESON
+	imply CMD_NAND
+	help
+	  This enables Nand driver support for Meson raw NAND flash
+	  controller.
+
 config NAND_MXC
 	bool "MXC NAND support"
 	depends on CPU_ARM926EJS || CPU_ARM1136 || MX5
@@ -577,16 +586,16 @@
 	select SYS_NAND_SELF_INIT
 	imply CMD_NAND
 	help
-	 This enables Nand flash controller hardware found on the OcteonTX
-	 processors.
+	  This enables Nand flash controller hardware found on the OcteonTX
+	  processors.
 
 config NAND_OCTEONTX_HW_ECC
 	bool "Support Hardware ECC for OcteonTX NAND controller"
 	depends on NAND_OCTEONTX
 	default y
 	help
-	 This enables Hardware BCH engine found on the OcteonTX processors to
-	 support ECC for NAND flash controller.
+	  This enables Hardware BCH engine found on the OcteonTX processors to
+	  support ECC for NAND flash controller.
 
 config NAND_STM32_FMC2
 	bool "Support for NAND controller on STM32MP SoCs"
@@ -751,37 +760,37 @@
 config SYS_NAND_U_BOOT_LOCATIONS
 	bool "Define U-Boot binaries locations in NAND"
 	help
-	Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig.
-	This option should not be enabled when compiling U-Boot for boards
-	defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/<board>.h
-	file.
+	  Enable CONFIG_SYS_NAND_U_BOOT_OFFS though Kconfig.
+	  This option should not be enabled when compiling U-Boot for boards
+	  defining CONFIG_SYS_NAND_U_BOOT_OFFS in their include/configs/<board>.h
+	  file.
 
 config SYS_NAND_U_BOOT_OFFS
 	hex "Location in NAND to read U-Boot from"
 	default 0x800000 if NAND_SUNXI
 	depends on SYS_NAND_U_BOOT_LOCATIONS
 	help
-	Set the offset from the start of the nand where u-boot should be
-	loaded from.
+	  Set the offset from the start of the nand where u-boot should be
+	  loaded from.
 
 config SYS_NAND_U_BOOT_OFFS_REDUND
 	hex "Location in NAND to read U-Boot from"
 	default SYS_NAND_U_BOOT_OFFS
 	depends on SYS_NAND_U_BOOT_LOCATIONS
 	help
-	Set the offset from the start of the nand where the redundant u-boot
-	should be loaded from.
+	  Set the offset from the start of the nand where the redundant u-boot
+	  should be loaded from.
 
 config SPL_NAND_AM33XX_BCH
 	bool "Enables SPL-NAND driver which supports ELM based"
 	depends on SPL_NAND_SUPPORT && NAND_OMAP_GPMC && !OMAP34XX
 	default y
-        help
+	help
 	  Hardware ECC correction. This is useful for platforms which have ELM
 	  hardware engine and use NAND boot mode.
 	  Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine,
 	  so those platforms should use CONFIG_SPL_NAND_SIMPLE for enabling
-          SPL-NAND driver with software ECC correction support.
+	  SPL-NAND driver with software ECC correction support.
 
 config SPL_NAND_DENALI
 	bool "Support Denali NAND controller for SPL"
@@ -810,6 +819,6 @@
 	bool "In SPL, read the OOB first and then the data from NAND"
 	depends on SPL_NAND_SIMPLE
 
-endif
+endif	# if SPL
 
-endif   # if NAND
+endif	# if MTD_RAW_NAND
diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile
index ddbba89..46fead6 100644
--- a/drivers/mtd/nand/raw/Makefile
+++ b/drivers/mtd/nand/raw/Makefile
@@ -61,6 +61,7 @@
 obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o
 obj-$(CONFIG_NAND_LPC32XX_SLC) += lpc32xx_nand_slc.o
 obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o
+obj-$(CONFIG_NAND_MESON) += meson_nand.o
 obj-$(CONFIG_NAND_MXC) += mxc_nand.o
 obj-$(CONFIG_NAND_MXS) += mxs_nand.o
 obj-$(CONFIG_NAND_MXS_DT) += mxs_nand_dt.o
diff --git a/drivers/mtd/nand/raw/arasan_nfc.c b/drivers/mtd/nand/raw/arasan_nfc.c
index 1476640..ffcd963 100644
--- a/drivers/mtd/nand/raw/arasan_nfc.c
+++ b/drivers/mtd/nand/raw/arasan_nfc.c
@@ -1232,7 +1232,8 @@
 	struct nand_config *nand = &info->config;
 	struct mtd_info *mtd;
 	ofnode child;
-	int err = -1;
+	int ret;
+	const char *str;
 
 	info->reg = dev_read_addr_ptr(dev);
 	mtd = nand_to_mtd(nand_chip);
@@ -1258,11 +1259,18 @@
 	writel(0x0, &info->reg->pgm_reg);
 
 	/* first scan to find the device and get the page size */
-	if (nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL)) {
+	ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);
+	if (ret) {
 		printf("%s: nand_scan_ident failed\n", __func__);
-		goto fail;
+		return ret;
 	}
 
+	str = ofnode_read_string(nand_chip->flash_node, "nand-ecc-mode");
+	if (!str || strcmp(str, "hw") != 0) {
+		printf("%s ecc mode is not supported\n", str);
+		return -EINVAL;
+	}
+
 	nand_chip->ecc.mode = NAND_ECC_HW;
 	nand_chip->ecc.hwctl = NULL;
 	nand_chip->ecc.read_page = arasan_nand_read_page_hwecc;
@@ -1282,26 +1290,26 @@
 		nand_chip->ecc.bytes = 0;
 		nand_chip->ecc.layout = &ondie_nand_oob_64;
 	} else {
-		if (arasan_nand_ecc_init(mtd)) {
+		ret = arasan_nand_ecc_init(mtd);
+		if (ret) {
 			printf("%s: nand_ecc_init failed\n", __func__);
-			goto fail;
+			return ret;
 		}
 	}
 
-	if (nand_scan_tail(mtd)) {
+	ret = nand_scan_tail(mtd);
+	if (ret) {
 		printf("%s: nand_scan_tail failed\n", __func__);
-		goto fail;
+		return ret;
 	}
 
-	if (nand_register(0, mtd)) {
+	ret = nand_register(0, mtd);
+	if (ret) {
 		printf("Nand Register Fail\n");
-		goto fail;
+		return ret;
 	}
 
-	return 0;
-fail:
-	free(nand);
-	return err;
+	return ret;
 }
 
 static const struct udevice_id arasan_nand_dt_ids[] = {
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
index 0e04414..ee4ec6d 100644
--- a/drivers/mtd/nand/raw/atmel/nand-controller.c
+++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
@@ -1267,7 +1267,7 @@
 		return ret;
 
 	/*
-	 * The write cycle timing is directly matching tWC, but is also
+	 * The read cycle timing is directly matching tRC, but is also
 	 * dependent on the setup and hold timings we calculated earlier,
 	 * which gives:
 	 *
@@ -1429,8 +1429,6 @@
 	return nc->caps->ops->setup_data_interface(nand, csline, conf);
 }
 
-#define NAND_KEEP_TIMINGS       0x00800000
-
 static void atmel_nand_init(struct atmel_nand_controller *nc,
 			    struct atmel_nand *nand)
 {
diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c
new file mode 100644
index 0000000..12499a7
--- /dev/null
+++ b/drivers/mtd/nand/raw/meson_nand.c
@@ -0,0 +1,1247 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Amlogic Meson Nand Flash Controller Driver
+ *
+ * Copyright (c) 2018 Amlogic, inc.
+ * Author: Liang Yang <liang.yang@amlogic.com>
+ *
+ * Copyright (c) 2023 SaluteDevices, Inc.
+ * Author: Arseniy Krasnov <avkrasnov@salutedevices.com>
+ */
+
+#include <nand.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/ofnode.h>
+#include <dm/uclass.h>
+#include <linux/bug.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/sizes.h>
+
+#define NFC_CMD_IDLE			(0xc << 14)
+#define NFC_CMD_CLE			(0x5 << 14)
+#define NFC_CMD_ALE			(0x6 << 14)
+#define NFC_CMD_DWR			(0x4 << 14)
+#define NFC_CMD_DRD			(0x8 << 14)
+#define NFC_CMD_ADL			((0 << 16) | (3 << 20))
+#define NFC_CMD_ADH			((1 << 16) | (3 << 20))
+#define NFC_CMD_AIL			((2 << 16) | (3 << 20))
+#define NFC_CMD_AIH			((3 << 16) | (3 << 20))
+#define NFC_CMD_SEED			((8 << 16) | (3 << 20))
+#define NFC_CMD_M2N			((0 << 17) | (2 << 20))
+#define NFC_CMD_N2M			((1 << 17) | (2 << 20))
+#define NFC_CMD_RB			BIT(20)
+#define NFC_CMD_SCRAMBLER_ENABLE	BIT(19)
+#define NFC_CMD_SCRAMBLER_DISABLE	0
+#define NFC_CMD_SHORTMODE_DISABLE	0
+#define NFC_CMD_RB_INT			BIT(14)
+#define NFC_CMD_RB_INT_NO_PIN		((0xb << 10) | BIT(18) | BIT(16))
+
+#define NFC_CMD_GET_SIZE(x)	(((x) >> 22) & GENMASK(4, 0))
+
+#define NFC_REG_CMD		0x00
+#define NFC_REG_CFG		0x04
+#define NFC_REG_DADR		0x08
+#define NFC_REG_IADR		0x0c
+#define NFC_REG_BUF		0x10
+#define NFC_REG_INFO		0x14
+#define NFC_REG_DC		0x18
+#define NFC_REG_ADR		0x1c
+#define NFC_REG_DL		0x20
+#define NFC_REG_DH		0x24
+#define NFC_REG_CADR		0x28
+#define NFC_REG_SADR		0x2c
+#define NFC_REG_PINS		0x30
+#define NFC_REG_VER		0x38
+
+#define CMDRWGEN(cmd_dir, ran, bch, short_mode, page_size, pages)	\
+	(								\
+		(cmd_dir)			|			\
+		(ran)				|			\
+		((bch) << 14)			|			\
+		((short_mode) << 13)		|			\
+		(((page_size) & 0x7f) << 6)	|			\
+		((pages) & 0x3f)					\
+	)
+
+#define GENCMDDADDRL(adl, addr)		((adl) | ((addr) & 0xffff))
+#define GENCMDDADDRH(adh, addr)		((adh) | (((addr) >> 16) & 0xffff))
+#define GENCMDIADDRL(ail, addr)		((ail) | ((addr) & 0xffff))
+#define GENCMDIADDRH(aih, addr)		((aih) | (((addr) >> 16) & 0xffff))
+
+#define DMA_DIR(dir)		((dir) ? NFC_CMD_N2M : NFC_CMD_M2N)
+
+#define ECC_CHECK_RETURN_FF	-1
+
+#define NAND_CE0		(0xe << 10)
+#define NAND_CE1		(0xd << 10)
+
+#define DMA_BUSY_TIMEOUT_US	1000000
+#define CMD_DRAIN_TIMEOUT_US	1000
+#define ECC_POLL_TIMEOUT_US	15
+
+#define MAX_CE_NUM		2
+
+/* eMMC clock register, misc control */
+#define CLK_SELECT_NAND		BIT(31)
+#define CLK_ALWAYS_ON_NAND	BIT(24)
+#define CLK_ENABLE_VALUE	0x245
+
+#define DIRREAD			1
+#define DIRWRITE		0
+
+#define ECC_PARITY_BCH8_512B	14
+#define ECC_COMPLETE            BIT(31)
+#define ECC_ERR_CNT(x)		(((x) >> 24) & GENMASK(5, 0))
+#define ECC_ZERO_CNT(x)		(((x) >> 16) & GENMASK(5, 0))
+#define ECC_UNCORRECTABLE	0x3f
+
+#define PER_INFO_BYTE		8
+
+#define NFC_SEND_CMD(host, cmd) \
+	(writel((cmd), (host)->reg_base + NFC_REG_CMD))
+
+#define NFC_GET_CMD(host) \
+	(readl((host)->reg_base + NFC_REG_CMD))
+
+#define NFC_CMDFIFO_SIZE(host)	((NFC_GET_CMD((host)) >> 22) & GENMASK(4, 0))
+
+#define NFC_CMD_MAKE_IDLE(ce, delay)	((ce) | NFC_CMD_IDLE | ((delay) & 0x3ff))
+#define NFC_CMD_MAKE_DRD(ce, size)	((ce) | NFC_CMD_DRD | (size))
+#define NFC_CMD_MAKE_DWR(ce, data)	((ce) | NFC_CMD_DWR | ((data) & 0xff))
+#define NFC_CMD_MAKE_CLE(ce, cmd_val)	((ce) | NFC_CMD_CLE | ((cmd_val) & 0xff))
+#define NFC_CMD_MAKE_ALE(ce, addr)	((ce) | NFC_CMD_ALE | ((addr) & 0xff))
+
+#define NAND_TWB_TIME_CYCLE	10
+
+#define NFC_DEV_READY_TICK_MAX	5000
+
+/* Both values are recommended by vendor, as the most
+ * tested with almost all SLC NAND flash. Second value
+ * could be calculated dynamically from timing parameters,
+ * but we need both values for initial start of the NAND
+ * controller (e.g. before NAND subsystem processes timings),
+ * so use hardcoded constants.
+ */
+#define NFC_DEFAULT_BUS_CYCLE	6
+#define NFC_DEFAULT_BUS_TIMING	7
+
+#define NFC_SEED_OFFSET		0xc2
+#define NFC_SEED_MASK		0x7fff
+
+#define DMA_ADDR_ALIGN		8
+
+struct meson_nfc_nand_chip {
+	struct list_head node;
+	struct nand_chip nand;
+
+	u32 bch_mode;
+	u8 *data_buf;
+	__le64 *info_buf;
+	u32 nsels;
+	u8 sels[];
+};
+
+struct meson_nfc_param {
+	u32 chip_select;
+	u32 rb_select;
+};
+
+struct meson_nfc {
+	void __iomem *reg_base;
+	void __iomem *reg_clk;
+	struct list_head chips;
+	struct meson_nfc_param param;
+	struct udevice *dev;
+	dma_addr_t daddr;
+	dma_addr_t iaddr;
+	u32 data_bytes;
+	u32 info_bytes;
+	u64 assigned_cs;
+};
+
+struct meson_nand_ecc {
+	u32 bch;
+	u32 strength;
+	u32 size;
+};
+
+enum {
+	NFC_ECC_BCH8_512 = 1,
+	NFC_ECC_BCH8_1K,
+	NFC_ECC_BCH24_1K,
+	NFC_ECC_BCH30_1K,
+	NFC_ECC_BCH40_1K,
+	NFC_ECC_BCH50_1K,
+	NFC_ECC_BCH60_1K,
+};
+
+#define MESON_ECC_DATA(b, s, sz) { .bch = (b), .strength = (s), .size = (sz) }
+
+static struct meson_nand_ecc meson_ecc[] = {
+	MESON_ECC_DATA(NFC_ECC_BCH8_512, 8,  512),
+	MESON_ECC_DATA(NFC_ECC_BCH8_1K,  8,  1024),
+};
+
+static int meson_nand_calc_ecc_bytes(int step_size, int strength)
+{
+	int ecc_bytes;
+
+	if (step_size == 512 && strength == 8)
+		return ECC_PARITY_BCH8_512B;
+
+	ecc_bytes = DIV_ROUND_UP(strength * fls(step_size * 8), 8);
+	ecc_bytes = ALIGN(ecc_bytes, 2);
+
+	return ecc_bytes;
+}
+
+static struct meson_nfc_nand_chip *to_meson_nand(struct nand_chip *nand)
+{
+	return container_of(nand, struct meson_nfc_nand_chip, nand);
+}
+
+static void meson_nfc_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+
+	nfc->param.chip_select = meson_chip->sels[chip] ? NAND_CE1 : NAND_CE0;
+}
+
+static void meson_nfc_cmd_idle(struct meson_nfc *nfc, u32 time)
+{
+	writel(NFC_CMD_MAKE_IDLE(nfc->param.chip_select, time),
+	       nfc->reg_base + NFC_REG_CMD);
+}
+
+static void meson_nfc_cmd_seed(const struct meson_nfc *nfc, u32 seed)
+{
+	writel(NFC_CMD_SEED | (NFC_SEED_OFFSET + (seed & NFC_SEED_MASK)),
+	       nfc->reg_base + NFC_REG_CMD);
+}
+
+static void meson_nfc_cmd_access(struct nand_chip *nand, bool raw, bool dir,
+				 int scrambler)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	const struct meson_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
+	const struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	u32 bch = meson_chip->bch_mode, cmd;
+	int len = mtd->writesize, pagesize, pages;
+
+	pagesize = nand->ecc.size;
+
+	if (raw) {
+		len = mtd->writesize + mtd->oobsize;
+		cmd = len | scrambler | DMA_DIR(dir);
+		writel(cmd, nfc->reg_base + NFC_REG_CMD);
+		return;
+	}
+
+	pages = len / nand->ecc.size;
+
+	cmd = CMDRWGEN(DMA_DIR(dir), scrambler, bch,
+		       NFC_CMD_SHORTMODE_DISABLE, pagesize, pages);
+
+	writel(cmd, nfc->reg_base + NFC_REG_CMD);
+}
+
+static void meson_nfc_drain_cmd(struct meson_nfc *nfc)
+{
+	/*
+	 * Insert two commands to make sure all valid commands are finished.
+	 *
+	 * The Nand flash controller is designed as two stages pipleline -
+	 *  a) fetch and b) execute.
+	 * There might be cases when the driver see command queue is empty,
+	 * but the Nand flash controller still has two commands buffered,
+	 * one is fetched into NFC request queue (ready to run), and another
+	 * is actively executing. So pushing 2 "IDLE" commands guarantees that
+	 * the pipeline is emptied.
+	 */
+	meson_nfc_cmd_idle(nfc, 0);
+	meson_nfc_cmd_idle(nfc, 0);
+}
+
+static int meson_nfc_wait_cmd_finish(const struct meson_nfc *nfc,
+				     unsigned int timeout_us)
+{
+	u32 cmd_size = 0;
+
+	/* wait cmd fifo is empty */
+	return readl_relaxed_poll_timeout(nfc->reg_base + NFC_REG_CMD, cmd_size,
+					  !NFC_CMD_GET_SIZE(cmd_size),
+					  timeout_us);
+}
+
+static int meson_nfc_wait_dma_finish(struct meson_nfc *nfc)
+{
+	meson_nfc_drain_cmd(nfc);
+
+	return meson_nfc_wait_cmd_finish(nfc, DMA_BUSY_TIMEOUT_US);
+}
+
+static u8 *meson_nfc_oob_ptr(struct nand_chip *nand, int i)
+{
+	const struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	int len;
+
+	len = nand->ecc.size * (i + 1) + (nand->ecc.bytes + 2) * i;
+
+	return meson_chip->data_buf + len;
+}
+
+static u8 *meson_nfc_data_ptr(struct nand_chip *nand, int i)
+{
+	const struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	int len, temp;
+
+	temp = nand->ecc.size + nand->ecc.bytes;
+	len = (temp + 2) * i;
+
+	return meson_chip->data_buf + len;
+}
+
+static void meson_nfc_get_data_oob(struct nand_chip *nand,
+				   u8 *buf, u8 *oobbuf)
+{
+	u8 *dsrc, *osrc;
+	int i, oob_len;
+
+	oob_len = nand->ecc.bytes + 2;
+	for (i = 0; i < nand->ecc.steps; i++) {
+		if (buf) {
+			dsrc = meson_nfc_data_ptr(nand, i);
+			memcpy(buf, dsrc, nand->ecc.size);
+			buf += nand->ecc.size;
+		}
+
+		if (oobbuf) {
+			osrc = meson_nfc_oob_ptr(nand, i);
+			memcpy(oobbuf, osrc, oob_len);
+			oobbuf += oob_len;
+		}
+	}
+}
+
+static void meson_nfc_set_data_oob(struct nand_chip *nand,
+				   const u8 *buf, u8 *oobbuf)
+{
+	int i, oob_len;
+
+	oob_len = nand->ecc.bytes + 2;
+	for (i = 0; i < nand->ecc.steps; i++) {
+		u8 *osrc;
+
+		if (buf) {
+			u8 *dsrc;
+
+			dsrc = meson_nfc_data_ptr(nand, i);
+			memcpy(dsrc, buf, nand->ecc.size);
+			buf += nand->ecc.size;
+		}
+
+		osrc = meson_nfc_oob_ptr(nand, i);
+		memcpy(osrc, oobbuf, oob_len);
+		oobbuf += oob_len;
+	}
+}
+
+static void meson_nfc_set_user_byte(struct nand_chip *nand, const u8 *oob_buf)
+{
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	int i, count;
+
+	for (i = 0, count = 0; i < nand->ecc.steps; i++, count += (2 + nand->ecc.bytes)) {
+		__le64 *info = &meson_chip->info_buf[i];
+
+		*info |= oob_buf[count];
+		*info |= oob_buf[count + 1] << 8;
+	}
+}
+
+static void meson_nfc_get_user_byte(struct nand_chip *nand, u8 *oob_buf)
+{
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	int i, count;
+
+	for (i = 0, count = 0; i < nand->ecc.steps; i++, count += (2 + nand->ecc.bytes)) {
+		const __le64 *info = &meson_chip->info_buf[i];
+
+		oob_buf[count] = *info;
+		oob_buf[count + 1] = *info >> 8;
+	}
+}
+
+static int meson_nfc_ecc_correct(struct nand_chip *nand, u32 *bitflips,
+				 u64 *correct_bitmap)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	int ret = 0, i;
+
+	for (i = 0; i < nand->ecc.steps; i++) {
+		struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+		const __le64 *info = &meson_chip->info_buf[i];
+
+		if (ECC_ERR_CNT(*info) != ECC_UNCORRECTABLE) {
+			mtd->ecc_stats.corrected += ECC_ERR_CNT(*info);
+			*bitflips = max_t(u32, *bitflips, ECC_ERR_CNT(*info));
+			*correct_bitmap |= BIT_ULL(i);
+			continue;
+		}
+
+		if ((nand->options & NAND_NEED_SCRAMBLING) &&
+		    ECC_ZERO_CNT(*info) < nand->ecc.strength) {
+			mtd->ecc_stats.corrected += ECC_ZERO_CNT(*info);
+			*bitflips = max_t(u32, *bitflips,
+					  ECC_ZERO_CNT(*info));
+			ret = ECC_CHECK_RETURN_FF;
+		} else {
+			ret = -EBADMSG;
+		}
+	}
+
+	return ret;
+}
+
+static int meson_nfc_dma_buffer_setup(struct nand_chip *nand, void *databuf,
+				      int datalen, void *infobuf, int infolen,
+				      enum dma_data_direction dir)
+{
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+	int ret;
+	u32 cmd;
+
+	nfc->daddr = dma_map_single(databuf, datalen, DMA_BIDIRECTIONAL);
+	ret = dma_mapping_error(nfc->dev, nfc->daddr);
+	if (ret)
+		return ret;
+
+	cmd = GENCMDDADDRL(NFC_CMD_ADL, nfc->daddr);
+	writel(cmd, nfc->reg_base + NFC_REG_CMD);
+
+	cmd = GENCMDDADDRH(NFC_CMD_ADH, nfc->daddr);
+	writel(cmd, nfc->reg_base + NFC_REG_CMD);
+
+	if (infobuf) {
+		nfc->iaddr = dma_map_single(infobuf, infolen,
+					    DMA_BIDIRECTIONAL);
+		ret = dma_mapping_error(nfc->dev, nfc->iaddr);
+		if (ret) {
+			dma_unmap_single(nfc->daddr, datalen, dir);
+			return ret;
+		}
+
+		nfc->info_bytes = infolen;
+		cmd = GENCMDIADDRL(NFC_CMD_AIL, nfc->iaddr);
+		writel(cmd, nfc->reg_base + NFC_REG_CMD);
+
+		cmd = GENCMDIADDRH(NFC_CMD_AIH, nfc->iaddr);
+		writel(cmd, nfc->reg_base + NFC_REG_CMD);
+	}
+
+	return 0;
+}
+
+static void meson_nfc_dma_buffer_release(struct nand_chip *nand,
+					 int datalen, int infolen,
+					 enum dma_data_direction dir)
+{
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+
+	dma_unmap_single(nfc->daddr, datalen, dir);
+
+	if (infolen) {
+		dma_unmap_single(nfc->iaddr, infolen, dir);
+		nfc->info_bytes = 0;
+	}
+}
+
+static void meson_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int size)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	u8 *dma_buf;
+	int ret;
+	u32 cmd;
+
+	if ((uintptr_t)buf % DMA_ADDR_ALIGN) {
+		unsigned long tmp_addr;
+
+		dma_buf = dma_alloc_coherent(size, &tmp_addr);
+		if (!dma_buf)
+			return;
+	} else {
+		dma_buf = buf;
+	}
+
+	ret = meson_nfc_dma_buffer_setup(nand, dma_buf, size, meson_chip->info_buf,
+					 PER_INFO_BYTE, DMA_FROM_DEVICE);
+	if (ret) {
+		pr_err("Failed to setup DMA buffer %p/%p\n", dma_buf,
+		       meson_chip->info_buf);
+		return;
+	}
+
+	cmd = NFC_CMD_N2M | size;
+	writel(cmd, nfc->reg_base + NFC_REG_CMD);
+
+	meson_nfc_drain_cmd(nfc);
+	meson_nfc_wait_cmd_finish(nfc, CMD_DRAIN_TIMEOUT_US);
+	meson_nfc_dma_buffer_release(nand, size, PER_INFO_BYTE, DMA_FROM_DEVICE);
+
+	if (buf != dma_buf) {
+		memcpy(buf, dma_buf, size);
+		dma_free_coherent(dma_buf);
+	}
+}
+
+static void meson_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int size)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+	u8 *dma_buf;
+	int ret;
+	u32 cmd;
+
+	if ((uintptr_t)buf % DMA_ADDR_ALIGN) {
+		unsigned long tmp_addr;
+
+		dma_buf = dma_alloc_coherent(size, &tmp_addr);
+		if (!dma_buf)
+			return;
+
+		memcpy(dma_buf, buf, size);
+	} else {
+		dma_buf = (u8 *)buf;
+	}
+
+	ret = meson_nfc_dma_buffer_setup(nand, (void *)dma_buf, size, NULL,
+					 0, DMA_TO_DEVICE);
+	if (ret) {
+		pr_err("Failed to setup DMA buffer %p\n", dma_buf);
+		return;
+	}
+
+	cmd = NFC_CMD_M2N | size;
+	writel(cmd, nfc->reg_base + NFC_REG_CMD);
+
+	meson_nfc_drain_cmd(nfc);
+	meson_nfc_wait_cmd_finish(nfc, CMD_DRAIN_TIMEOUT_US);
+	meson_nfc_dma_buffer_release(nand, size, 0, DMA_TO_DEVICE);
+
+	if (buf != dma_buf)
+		dma_free_coherent(dma_buf);
+}
+
+static int meson_nfc_write_page_sub(struct nand_chip *nand,
+				    int page, bool raw)
+{
+	const struct mtd_info *mtd = nand_to_mtd(nand);
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+	int data_len, info_len;
+	int ret;
+	u32 cmd;
+
+	data_len =  mtd->writesize + mtd->oobsize;
+	info_len = nand->ecc.steps * PER_INFO_BYTE;
+
+	ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf,
+					 data_len, meson_chip->info_buf,
+					 info_len, DMA_TO_DEVICE);
+	if (ret) {
+		pr_err("Failed to setup DMA buffer %p/%p\n",
+		       meson_chip->data_buf, meson_chip->info_buf);
+		return ret;
+	}
+
+	if (nand->options & NAND_NEED_SCRAMBLING) {
+		meson_nfc_cmd_seed(nfc, page);
+		meson_nfc_cmd_access(nand, raw, DIRWRITE,
+				     NFC_CMD_SCRAMBLER_ENABLE);
+	} else {
+		meson_nfc_cmd_access(nand, raw, DIRWRITE,
+				     NFC_CMD_SCRAMBLER_DISABLE);
+	}
+
+	cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_PAGEPROG;
+	writel(cmd, nfc->reg_base + NFC_REG_CMD);
+
+	meson_nfc_dma_buffer_release(nand, data_len, info_len, DMA_TO_DEVICE);
+
+	return 0;
+}
+
+static int meson_nfc_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				    const u8 *buf, int oob_required, int page)
+{
+	meson_nfc_set_data_oob(chip, buf, oob_required ? chip->oob_poi : NULL);
+
+	return meson_nfc_write_page_sub(chip, page, true);
+}
+
+static int meson_nfc_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+				      const u8 *buf, int oob_required, int page)
+{
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(chip);
+
+	if (buf)
+		memcpy(meson_chip->data_buf, buf, mtd->writesize);
+
+	memset(meson_chip->info_buf, 0, chip->ecc.steps * PER_INFO_BYTE);
+
+	if (oob_required)
+		meson_nfc_set_user_byte(chip, chip->oob_poi);
+
+	return meson_nfc_write_page_sub(chip, page, false);
+}
+
+static void meson_nfc_check_ecc_pages_valid(struct meson_nfc *nfc,
+					    struct nand_chip *nand, bool raw)
+{
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	__le64 *info;
+	u32 neccpages;
+	int ret;
+
+	neccpages = raw ? 1 : nand->ecc.steps;
+	info = &meson_chip->info_buf[neccpages - 1];
+	do {
+		udelay(ECC_POLL_TIMEOUT_US);
+		/* info is updated by nfc dma engine*/
+		rmb();
+		invalidate_dcache_range(nfc->iaddr, nfc->iaddr + nfc->info_bytes);
+		ret = *info & ECC_COMPLETE;
+	} while (!ret);
+}
+
+static int meson_nfc_read_page_sub(struct nand_chip *nand,
+				   int page, bool raw)
+{
+	struct mtd_info *mtd = nand_to_mtd(nand);
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	u32 data_len, info_len;
+	int ret;
+
+	data_len = mtd->writesize + mtd->oobsize;
+	info_len = nand->ecc.steps * PER_INFO_BYTE;
+
+	ret = meson_nfc_dma_buffer_setup(nand, meson_chip->data_buf, data_len,
+					 meson_chip->info_buf, info_len,
+					 DMA_FROM_DEVICE);
+	if (ret)
+		return ret;
+
+	if (nand->options & NAND_NEED_SCRAMBLING) {
+		meson_nfc_cmd_seed(nfc, page);
+		meson_nfc_cmd_access(nand, raw, DIRREAD,
+				     NFC_CMD_SCRAMBLER_ENABLE);
+	} else {
+		meson_nfc_cmd_access(nand, raw, DIRREAD,
+				     NFC_CMD_SCRAMBLER_DISABLE);
+	}
+
+	meson_nfc_wait_dma_finish(nfc);
+	meson_nfc_check_ecc_pages_valid(nfc, nand, raw);
+
+	meson_nfc_dma_buffer_release(nand, data_len, info_len,
+				     DMA_FROM_DEVICE);
+
+	return 0;
+}
+
+static int meson_nfc_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				   u8 *buf, int oob_required, int page)
+{
+	int ret;
+
+	ret = meson_nfc_read_page_sub(chip, page, true);
+	if (ret)
+		return ret;
+
+	meson_nfc_get_data_oob(chip, buf, oob_required ? chip->oob_poi : NULL);
+
+	return 0;
+}
+
+static int meson_nfc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+				     u8 *buf, int oob_required, int page)
+{
+	const struct meson_nfc_nand_chip *meson_chip = to_meson_nand(chip);
+	u64 correct_bitmap = 0;
+	u32 bitflips = 0;
+	int ret;
+
+	ret = meson_nfc_read_page_sub(chip, page, false);
+	if (ret)
+		return ret;
+
+	if (oob_required)
+		meson_nfc_get_user_byte(chip, chip->oob_poi);
+
+	ret = meson_nfc_ecc_correct(chip, &bitflips, &correct_bitmap);
+
+	if (ret == ECC_CHECK_RETURN_FF) {
+		if (buf)
+			memset(buf, 0xff, mtd->writesize);
+
+		if (oob_required)
+			memset(chip->oob_poi, 0xff, mtd->oobsize);
+	} else if (ret < 0) {
+		struct nand_ecc_ctrl *ecc;
+		int i;
+
+		if ((chip->options & NAND_NEED_SCRAMBLING) || !buf) {
+			mtd->ecc_stats.failed++;
+			return bitflips;
+		}
+
+		chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+		ret = meson_nfc_read_page_raw(mtd, chip, buf, 1, page);
+		if (ret)
+			return ret;
+
+		ecc = &chip->ecc;
+
+		for (i = 0; i < chip->ecc.steps ; i++) {
+			u8 *data = buf + i * ecc->size;
+			u8 *oob = chip->oob_poi + i * (ecc->bytes + 2);
+
+			if (correct_bitmap & BIT_ULL(i))
+				continue;
+
+			ret = nand_check_erased_ecc_chunk(data,	ecc->size,
+							  oob, ecc->bytes + 2,
+							  NULL, 0,
+							  ecc->strength);
+			if (ret < 0) {
+				mtd->ecc_stats.failed++;
+			} else {
+				mtd->ecc_stats.corrected += ret;
+				bitflips =  max_t(u32, bitflips, ret);
+			}
+		}
+	} else if (buf && buf != meson_chip->data_buf) {
+		memcpy(buf, meson_chip->data_buf, mtd->writesize);
+	}
+
+	return bitflips;
+}
+
+static int meson_nfc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				  int page)
+{
+	int ret;
+
+	ret = nand_read_page_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	return meson_nfc_read_page_raw(mtd, chip, NULL, 1, page);
+}
+
+static int meson_nfc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			      int page)
+{
+	int ret;
+
+	ret = nand_read_page_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	return meson_nfc_read_page_hwecc(mtd, chip, NULL, 1, page);
+}
+
+static int meson_nfc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
+				   int page)
+{
+	int ret;
+
+	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	ret = meson_nfc_write_page_raw(mtd, chip, NULL, 1, page);
+	if (ret)
+		return ret;
+
+	return nand_prog_page_end_op(chip);
+}
+
+static int meson_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+			       int page)
+{
+	int ret;
+
+	ret = nand_prog_page_begin_op(chip, page, 0, NULL, 0);
+	if (ret)
+		return ret;
+
+	ret = meson_nfc_write_page_hwecc(mtd, chip, NULL, 1, page);
+	if (ret)
+		return ret;
+
+	return nand_prog_page_end_op(chip);
+}
+
+static void meson_nfc_nand_cmd_function(struct mtd_info *mtd, unsigned int command,
+					int column, int page_addr)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+
+	chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+
+	if (column != -1 || page_addr != -1) {
+		int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
+
+		/* Serially input address */
+		if (column != -1) {
+			/* Adjust columns for 16 bit buswidth */
+			if (chip->options & NAND_BUSWIDTH_16 &&
+			    !nand_opcode_8bits(command))
+				column >>= 1;
+
+			chip->cmd_ctrl(mtd, column, ctrl);
+			ctrl &= ~NAND_CTRL_CHANGE;
+			/* Only output a single addr cycle for 8bits
+			 * opcodes.
+			 */
+			if (!nand_opcode_8bits(command))
+				chip->cmd_ctrl(mtd, column >> 8, ctrl);
+		}
+
+		if (page_addr != -1) {
+			chip->cmd_ctrl(mtd, page_addr, ctrl);
+			chip->cmd_ctrl(mtd, page_addr >> 8, NAND_NCE |
+							    NAND_ALE);
+			/* One more address cycle for devices > 128MiB */
+			if (chip->chipsize > SZ_128M)
+				chip->cmd_ctrl(mtd, page_addr >> 16,
+					       NAND_NCE | NAND_ALE);
+		}
+
+		switch (command) {
+		case NAND_CMD_READ0:
+			chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
+				       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
+			fallthrough;
+		case NAND_CMD_PARAM:
+			nand_wait_ready(mtd);
+			nand_exit_status_op(chip);
+		}
+	}
+}
+
+static void meson_nfc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		cmd = NFC_CMD_MAKE_CLE(nfc->param.chip_select, cmd);
+	else
+		cmd = NFC_CMD_MAKE_ALE(nfc->param.chip_select, cmd);
+
+	writel(cmd, nfc->reg_base + NFC_REG_CMD);
+}
+
+static void meson_nfc_wait_cmd_fifo(struct meson_nfc *nfc)
+{
+	while ((NFC_GET_CMD(nfc) >> 22) & GENMASK(4, 0))
+		;
+}
+
+static u8 meson_nfc_nand_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+
+	writel(NFC_CMD_MAKE_DRD(nfc->param.chip_select, 0), nfc->reg_base + NFC_REG_CMD);
+
+	meson_nfc_cmd_idle(nfc, NAND_TWB_TIME_CYCLE);
+	meson_nfc_cmd_idle(nfc, 0);
+	meson_nfc_cmd_idle(nfc, 0);
+
+	meson_nfc_wait_cmd_fifo(nfc);
+
+	return readl(nfc->reg_base + NFC_REG_BUF);
+}
+
+static void meson_nfc_nand_write_byte(struct mtd_info *mtd, u8 val)
+{
+	struct nand_chip *nand = mtd_to_nand(mtd);
+	struct meson_nfc *nfc = nand_get_controller_data(nand);
+
+	meson_nfc_cmd_idle(nfc, NAND_TWB_TIME_CYCLE);
+
+	writel(NFC_CMD_MAKE_DWR(nfc->param.chip_select, val), nfc->reg_base + NFC_REG_CMD);
+
+	meson_nfc_cmd_idle(nfc, NAND_TWB_TIME_CYCLE);
+	meson_nfc_cmd_idle(nfc, 0);
+	meson_nfc_cmd_idle(nfc, 0);
+
+	meson_nfc_wait_cmd_fifo(nfc);
+}
+
+static int meson_nfc_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd_to_nand(mtd);
+	unsigned int time_out_cnt = 0;
+
+	chip->select_chip(mtd, 0);
+
+	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+
+	do {
+		int status;
+
+		status = (int)chip->read_byte(mtd);
+		if (status & NAND_STATUS_READY)
+			break;
+	} while (time_out_cnt++ < NFC_DEV_READY_TICK_MAX);
+
+	return time_out_cnt != NFC_DEV_READY_TICK_MAX;
+}
+
+static int meson_chip_buffer_init(struct nand_chip *nand)
+{
+	const struct mtd_info *mtd = nand_to_mtd(nand);
+	struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+	u32 page_bytes, info_bytes, nsectors;
+	unsigned long tmp_addr;
+
+	nsectors = mtd->writesize / nand->ecc.size;
+
+	page_bytes =  mtd->writesize + mtd->oobsize;
+	info_bytes = nsectors * PER_INFO_BYTE;
+
+	meson_chip->data_buf = dma_alloc_coherent(page_bytes, &tmp_addr);
+	if (!meson_chip->data_buf)
+		return -ENOMEM;
+
+	meson_chip->info_buf = dma_alloc_coherent(info_bytes, &tmp_addr);
+	if (!meson_chip->info_buf) {
+		dma_free_coherent(meson_chip->data_buf);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static const int axg_stepinfo_strengths[] = { 8 };
+static const struct nand_ecc_step_info axg_stepinfo_1024 = {
+	.stepsize = 1024,
+	.strengths = axg_stepinfo_strengths,
+	.nstrengths = ARRAY_SIZE(axg_stepinfo_strengths)
+};
+
+static const struct nand_ecc_step_info axg_stepinfo_512 = {
+	.stepsize = 512,
+	.strengths = axg_stepinfo_strengths,
+	.nstrengths = ARRAY_SIZE(axg_stepinfo_strengths)
+};
+
+static const struct nand_ecc_step_info axg_stepinfo[] = { axg_stepinfo_1024, axg_stepinfo_512 };
+
+static const struct nand_ecc_caps meson_axg_ecc_caps = {
+	.stepinfos = axg_stepinfo,
+	.nstepinfos = ARRAY_SIZE(axg_stepinfo),
+	.calc_ecc_bytes = meson_nand_calc_ecc_bytes,
+};
+
+/*
+ * OOB layout:
+ *
+ * For ECC with 512 bytes step size:
+ * 0x00: AA AA BB BB BB BB BB BB BB BB BB BB BB BB BB BB
+ * 0x10: AA AA CC CC CC CC CC CC CC CC CC CC CC CC CC CC
+ * 0x20:
+ * 0x30:
+ *
+ * For ECC with 1024 bytes step size:
+ * 0x00: AA AA BB BB BB BB BB BB BB BB BB BB BB BB BB BB
+ * 0x10: AA AA CC CC CC CC CC CC CC CC CC CC CC CC CC CC
+ * 0x20: AA AA DD DD DD DD DD DD DD DD DD DD DD DD DD DD
+ * 0x30: AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE
+ *
+ * AA - user bytes.
+ * BB, CC, DD, EE - ECC code bytes for each step.
+ */
+static struct nand_ecclayout nand_oob;
+
+static void meson_nfc_init_nand_oob(struct nand_chip *nand)
+{
+	int section_size = 2 + nand->ecc.bytes;
+	int i;
+	int k;
+
+	nand_oob.eccbytes = nand->ecc.steps * nand->ecc.bytes;
+	k = 0;
+
+	for (i = 0; i < nand->ecc.steps; i++) {
+		int j;
+
+		for (j = 0; j < nand->ecc.bytes; j++)
+			nand_oob.eccpos[k++] = (i * section_size) + 2 + j;
+
+		nand_oob.oobfree[i].offset = (i * section_size);
+		nand_oob.oobfree[i].length = 2;
+	}
+
+	nand_oob.oobavail = 2 * nand->ecc.steps;
+	nand->ecc.layout = &nand_oob;
+}
+
+static int meson_nfc_init_ecc(struct nand_chip *nand, ofnode node)
+{
+	const struct mtd_info *mtd = nand_to_mtd(nand);
+	int ret;
+	int i;
+
+	ret = nand_check_ecc_caps(nand, &meson_axg_ecc_caps, mtd->oobsize - 2);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ARRAY_SIZE(meson_ecc); i++) {
+		if (meson_ecc[i].strength == nand->ecc.strength &&
+		    meson_ecc[i].size == nand->ecc.size) {
+			struct meson_nfc_nand_chip *meson_chip = to_meson_nand(nand);
+
+			nand->ecc.steps = mtd->writesize / nand->ecc.size;
+			meson_chip->bch_mode = meson_ecc[i].bch;
+
+			meson_nfc_init_nand_oob(nand);
+
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int meson_nfc_nand_chip_init(struct udevice *dev, struct meson_nfc *nfc,
+				    ofnode node)
+{
+	struct meson_nfc_nand_chip *meson_chip;
+	struct nand_chip *nand;
+	struct mtd_info *mtd;
+	u32 cs[MAX_CE_NUM];
+	u32 nsels;
+	int ret;
+	int i;
+
+	if (!ofnode_get_property(node, "reg", &nsels)) {
+		dev_err(dev, "\"reg\" property is not found\n");
+		return -ENODEV;
+	}
+
+	nsels /= sizeof(u32);
+	if (nsels >= MAX_CE_NUM) {
+		dev_err(dev, "invalid size of CS array, max is %d\n",
+			MAX_CE_NUM);
+		return -EINVAL;
+	}
+
+	ret = ofnode_read_u32_array(node, "reg", cs, nsels);
+	if (ret < 0) {
+		dev_err(dev, "failed to read \"reg\" property\n");
+		return ret;
+	}
+
+	for (i = 0; i < nsels; i++) {
+		if (test_and_set_bit(cs[i], &nfc->assigned_cs)) {
+			dev_err(dev, "CS %d already assigned\n", cs[i]);
+			return -EINVAL;
+		}
+	}
+
+	meson_chip = malloc(sizeof(*meson_chip) + nsels * sizeof(meson_chip->sels[0]));
+	if (!meson_chip) {
+		dev_err(dev, "failed to allocate memory for chip\n");
+		return -ENOMEM;
+	}
+
+	meson_chip->nsels = nsels;
+	nand = &meson_chip->nand;
+
+	nand->flash_node = node;
+	nand_set_controller_data(nand, nfc);
+	/* Set the driver entry points for MTD */
+	nand->cmdfunc = meson_nfc_nand_cmd_function;
+	nand->cmd_ctrl = meson_nfc_cmd_ctrl;
+	nand->select_chip = meson_nfc_nand_select_chip;
+	nand->read_byte = meson_nfc_nand_read_byte;
+	nand->write_byte = meson_nfc_nand_write_byte;
+	nand->dev_ready = meson_nfc_dev_ready;
+
+	/* Buffer read/write routines */
+	nand->read_buf = meson_nfc_read_buf;
+	nand->write_buf = meson_nfc_write_buf;
+	nand->options |= NAND_NO_SUBPAGE_WRITE;
+
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.hwctl = NULL;
+	nand->ecc.read_page = meson_nfc_read_page_hwecc;
+	nand->ecc.write_page = meson_nfc_write_page_hwecc;
+	nand->ecc.read_page_raw = meson_nfc_read_page_raw;
+	nand->ecc.write_page_raw = meson_nfc_write_page_raw;
+
+	nand->ecc.read_oob = meson_nfc_read_oob;
+	nand->ecc.write_oob = meson_nfc_write_oob;
+	nand->ecc.read_oob_raw = meson_nfc_read_oob_raw;
+	nand->ecc.write_oob_raw = meson_nfc_write_oob_raw;
+
+	nand->ecc.algo = NAND_ECC_BCH;
+
+	mtd = nand_to_mtd(nand);
+
+	ret = nand_scan_ident(mtd, 1, NULL);
+	if (ret) {
+		dev_err(dev, "'nand_scan_ident()' failed: %d\n", ret);
+		goto err_chip_free;
+	}
+
+	ret = meson_nfc_init_ecc(nand, node);
+	if (ret) {
+		dev_err(dev, "failed to init ECC settings: %d\n", ret);
+		goto err_chip_free;
+	}
+
+	ret = meson_chip_buffer_init(nand);
+	if (ret) {
+		dev_err(dev, "failed to init DMA buffers: %d\n", ret);
+		goto err_chip_free;
+	}
+
+	/* 'nand_scan_tail()' needs ECC parameters to be already
+	 * set and correct.
+	 */
+	ret = nand_scan_tail(mtd);
+	if (ret) {
+		dev_err(dev, "'nand_scan_tail()' failed: %d\n", ret);
+		goto err_chip_buf_free;
+	}
+
+	ret = nand_register(0, mtd);
+	if (ret) {
+		dev_err(dev, "'nand_register()' failed: %d\n", ret);
+		goto err_chip_buf_free;
+	}
+
+	list_add_tail(&meson_chip->node, &nfc->chips);
+
+	return 0;
+
+err_chip_buf_free:
+	dma_free_coherent(meson_chip->info_buf);
+	dma_free_coherent(meson_chip->data_buf);
+
+err_chip_free:
+	free(meson_chip);
+
+	return ret;
+}
+
+static int meson_nfc_nand_chips_init(struct udevice *dev,
+				     struct meson_nfc *nfc)
+{
+	ofnode parent = dev_ofnode(dev);
+	ofnode node;
+
+	ofnode_for_each_subnode(node, parent) {
+		int ret = meson_nfc_nand_chip_init(dev, nfc, node);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void meson_nfc_clk_init(struct meson_nfc *nfc)
+{
+	u32 bus_cycle = NFC_DEFAULT_BUS_CYCLE;
+	u32 bus_timing = NFC_DEFAULT_BUS_TIMING;
+	u32 bus_cfg_val;
+
+	writel(CLK_ALWAYS_ON_NAND | CLK_SELECT_NAND | CLK_ENABLE_VALUE, nfc->reg_clk);
+	writel(0, nfc->reg_base + NFC_REG_CFG);
+
+	bus_cfg_val = (((bus_cycle - 1) & 31) | ((bus_timing & 31) << 5));
+	writel(bus_cfg_val, nfc->reg_base + NFC_REG_CFG);
+	writel(BIT(31), nfc->reg_base + NFC_REG_CMD);
+}
+
+static int meson_probe(struct udevice *dev)
+{
+	struct meson_nfc *nfc = dev_get_priv(dev);
+	void *addr;
+	int ret;
+
+	addr = dev_read_addr_ptr(dev);
+	if (!addr) {
+		dev_err(dev, "base register address not found\n");
+		return -EINVAL;
+	}
+
+	nfc->reg_base = addr;
+
+	addr = dev_read_addr_index_ptr(dev, 1);
+	if (!addr) {
+		dev_err(dev, "clk register address not found\n");
+		return -EINVAL;
+	}
+
+	nfc->reg_clk = addr;
+	nfc->dev = dev;
+
+	meson_nfc_clk_init(nfc);
+
+	ret = meson_nfc_nand_chips_init(dev, nfc);
+	if (ret) {
+		dev_err(nfc->dev, "failed to init chips\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id meson_nand_dt_ids[] = {
+	{.compatible = "amlogic,meson-axg-nfc",},
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(meson_nand) = {
+	.name = "meson_nand",
+	.id = UCLASS_MTD,
+	.of_match = meson_nand_dt_ids,
+	.probe = meson_probe,
+	.priv_auto = sizeof(struct meson_nfc),
+};
+
+void board_nand_init(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device_by_driver(UCLASS_MTD,
+					  DM_DRIVER_GET(meson_nand), &dev);
+
+	if (ret && ret != -ENODEV)
+		pr_err("Failed to initialize: %d\n", ret);
+}
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index c40a0f2..688d17b 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4118,7 +4118,7 @@
  */
 void nand_decode_ext_id(struct nand_chip *chip)
 {
-	struct mtd_info *mtd = &chip->mtd;
+	struct mtd_info *mtd = nand_to_mtd(chip);
 	int extid;
 	/* The 3rd id byte holds MLC / multichip data */
 	chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
@@ -4185,7 +4185,7 @@
  */
 static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
 {
-	struct mtd_info *mtd = &chip->mtd;
+	struct mtd_info *mtd = nand_to_mtd(chip);
 
 	mtd->erasesize = type->erasesize;
 	mtd->writesize = type->pagesize;
@@ -4265,7 +4265,7 @@
 int nand_detect(struct nand_chip *chip, int *maf_id,
 		int *dev_id, struct nand_flash_dev *type)
 {
-	struct mtd_info *mtd = &chip->mtd;
+	struct mtd_info *mtd = nand_to_mtd(chip);
 	const struct nand_manufacturer *manufacturer_desc;
 	int busw, ret;
 	u8 *id_data = chip->id.data;
diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index f172f47..65b836b 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
 spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o
-spinand-objs += toshiba.o winbond.o
+spinand-objs += toshiba.o winbond.o xtx.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 8ca3345..62c28aa 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -829,6 +829,7 @@
 	&toshiba_spinand_manufacturer,
 	&winbond_spinand_manufacturer,
 	&esmt_c8_spinand_manufacturer,
+	&xtx_spinand_manufacturer,
 };
 
 static int spinand_manufacturer_match(struct spinand_device *spinand,
diff --git a/drivers/mtd/nand/spi/xtx.c b/drivers/mtd/nand/spi/xtx.c
new file mode 100644
index 0000000..aee1849
--- /dev/null
+++ b/drivers/mtd/nand/spi/xtx.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author:
+ * Felix Matouschek <felix@matouschek.org>
+ */
+
+#include <linux/bitfield.h>
+#ifndef __UBOOT__
+#include <linux/device.h>
+#include <linux/kernel.h>
+#endif
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_XTX	0x0B
+
+#define XT26G0XA_STATUS_ECC_MASK	GENMASK(5, 2)
+#define XT26G0XA_STATUS_ECC_NO_DETECTED	(0 << 2)
+#define XT26G0XA_STATUS_ECC_8_CORRECTED	(3 << 4)
+#define XT26G0XA_STATUS_ECC_UNCOR_ERROR	(2 << 4)
+
+#define XT26XXXD_STATUS_ECC3_ECC2_MASK	    GENMASK(7, 6)
+#define XT26XXXD_STATUS_ECC_NO_DETECTED     (0)
+#define XT26XXXD_STATUS_ECC_1_7_CORRECTED   (1)
+#define XT26XXXD_STATUS_ECC_8_CORRECTED     (3)
+#define XT26XXXD_STATUS_ECC_UNCOR_ERROR     (2)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = 48;
+	region->length = 16;
+
+	return 0;
+}
+
+static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = 1;
+	region->length = 47;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
+	.ecc = xt26g0xa_ooblayout_ecc,
+	.rfree = xt26g0xa_ooblayout_free,
+};
+
+static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
+				   u8 status)
+{
+	status = status & XT26G0XA_STATUS_ECC_MASK;
+
+	switch (status) {
+	case XT26G0XA_STATUS_ECC_NO_DETECTED:
+		return 0;
+	case XT26G0XA_STATUS_ECC_8_CORRECTED:
+		return 8;
+	case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+	default:
+		break;
+	}
+
+	/* At this point values greater than (2 << 4) are invalid  */
+	if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR)
+		return -EINVAL;
+
+	/* (1 << 2) through (7 << 2) are 1-7 corrected errors */
+	return status >> 2;
+}
+
+static int xt26xxxd_ooblayout_ecc(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = mtd->oobsize / 2;
+	region->length = mtd->oobsize / 2;
+
+	return 0;
+}
+
+static int xt26xxxd_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	region->offset = 2;
+	region->length = mtd->oobsize / 2 - 2;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops xt26xxxd_ooblayout = {
+	.ecc = xt26xxxd_ooblayout_ecc,
+	.rfree = xt26xxxd_ooblayout_free,
+};
+
+static int xt26xxxd_ecc_get_status(struct spinand_device *spinand,
+				   u8 status)
+{
+	switch (FIELD_GET(STATUS_ECC_MASK, status)) {
+	case XT26XXXD_STATUS_ECC_NO_DETECTED:
+		return 0;
+	case XT26XXXD_STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+	case XT26XXXD_STATUS_ECC_1_7_CORRECTED:
+		return 4 + FIELD_GET(XT26XXXD_STATUS_ECC3_ECC2_MASK, status);
+	case XT26XXXD_STATUS_ECC_8_CORRECTED:
+		return 8;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct spinand_info xtx_spinand_table[] = {
+	SPINAND_INFO("XT26G01A",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
+				     xt26g0xa_ecc_get_status)),
+	SPINAND_INFO("XT26G02A",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
+				     xt26g0xa_ecc_get_status)),
+	SPINAND_INFO("XT26G04A",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3),
+		     NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
+				     xt26g0xa_ecc_get_status)),
+	SPINAND_INFO("XT26G01D",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x31),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+				     xt26xxxd_ecc_get_status)),
+	SPINAND_INFO("XT26G11D",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x34),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+				     xt26xxxd_ecc_get_status)),
+	SPINAND_INFO("XT26Q01D",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51),
+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+				     xt26xxxd_ecc_get_status)),
+	SPINAND_INFO("XT26G02D",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x32),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+				     xt26xxxd_ecc_get_status)),
+	SPINAND_INFO("XT26G12D",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x35),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+				     xt26xxxd_ecc_get_status)),
+	SPINAND_INFO("XT26Q02D",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+				     xt26xxxd_ecc_get_status)),
+	SPINAND_INFO("XT26G04D",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x33),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+				     xt26xxxd_ecc_get_status)),
+	SPINAND_INFO("XT26Q04D",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x53),
+		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(8, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     0,
+		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
+				     xt26xxxd_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer xtx_spinand_manufacturer = {
+	.id = SPINAND_MFR_XTX,
+	.name = "XTX",
+	.chips = xtx_spinand_table,
+	.nchips = ARRAY_SIZE(xtx_spinand_table),
+	.ops = &xtx_spinand_manuf_ops,
+};
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index c222197..4c1642b 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -352,6 +352,11 @@
 	       (phydev->duplex) ? "full" : "half",
 	       (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
 
+#ifdef CONFIG_ARCH_NPCM8XX
+	/* Pass all Multicast Frames */
+	setbits_le32(&mac_p->framefilt, BIT(4));
+
+#endif
 	return 0;
 }
 
@@ -554,6 +559,11 @@
 	ulong desc_start = (ulong)desc_p;
 	ulong desc_end = desc_start +
 		roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
+	ulong data_start = desc_p->dmamac_addr;
+	ulong data_end = data_start + roundup(CFG_ETH_BUFSIZE, ARCH_DMA_MINALIGN);
+
+	/* Invalidate the descriptor buffer data */
+	invalidate_dcache_range(data_start, data_end);
 
 	/*
 	 * Make the current descriptor valid again and go to
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 9b3bce1..67d80d9 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -159,7 +159,7 @@
 
 	ret = eqos_mdio_wait_idle(eqos);
 	if (ret) {
-		pr_err("MDIO not idle at entry");
+		pr_err("MDIO not idle at entry\n");
 		return ret;
 	}
 
@@ -179,7 +179,7 @@
 
 	ret = eqos_mdio_wait_idle(eqos);
 	if (ret) {
-		pr_err("MDIO read didn't complete");
+		pr_err("MDIO read didn't complete\n");
 		return ret;
 	}
 
@@ -203,7 +203,7 @@
 
 	ret = eqos_mdio_wait_idle(eqos);
 	if (ret) {
-		pr_err("MDIO not idle at entry");
+		pr_err("MDIO not idle at entry\n");
 		return ret;
 	}
 
@@ -225,7 +225,7 @@
 
 	ret = eqos_mdio_wait_idle(eqos);
 	if (ret) {
-		pr_err("MDIO read didn't complete");
+		pr_err("MDIO read didn't complete\n");
 		return ret;
 	}
 
@@ -242,37 +242,37 @@
 
 	ret = clk_enable(&eqos->clk_slave_bus);
 	if (ret < 0) {
-		pr_err("clk_enable(clk_slave_bus) failed: %d", ret);
+		pr_err("clk_enable(clk_slave_bus) failed: %d\n", ret);
 		goto err;
 	}
 
 	ret = clk_enable(&eqos->clk_master_bus);
 	if (ret < 0) {
-		pr_err("clk_enable(clk_master_bus) failed: %d", ret);
+		pr_err("clk_enable(clk_master_bus) failed: %d\n", ret);
 		goto err_disable_clk_slave_bus;
 	}
 
 	ret = clk_enable(&eqos->clk_rx);
 	if (ret < 0) {
-		pr_err("clk_enable(clk_rx) failed: %d", ret);
+		pr_err("clk_enable(clk_rx) failed: %d\n", ret);
 		goto err_disable_clk_master_bus;
 	}
 
 	ret = clk_enable(&eqos->clk_ptp_ref);
 	if (ret < 0) {
-		pr_err("clk_enable(clk_ptp_ref) failed: %d", ret);
+		pr_err("clk_enable(clk_ptp_ref) failed: %d\n", ret);
 		goto err_disable_clk_rx;
 	}
 
 	ret = clk_set_rate(&eqos->clk_ptp_ref, 125 * 1000 * 1000);
 	if (ret < 0) {
-		pr_err("clk_set_rate(clk_ptp_ref) failed: %d", ret);
+		pr_err("clk_set_rate(clk_ptp_ref) failed: %d\n", ret);
 		goto err_disable_clk_ptp_ref;
 	}
 
 	ret = clk_enable(&eqos->clk_tx);
 	if (ret < 0) {
-		pr_err("clk_enable(clk_tx) failed: %d", ret);
+		pr_err("clk_enable(clk_tx) failed: %d\n", ret);
 		goto err_disable_clk_ptp_ref;
 	}
 #endif
@@ -305,26 +305,26 @@
 
 	ret = clk_enable(&eqos->clk_master_bus);
 	if (ret < 0) {
-		pr_err("clk_enable(clk_master_bus) failed: %d", ret);
+		pr_err("clk_enable(clk_master_bus) failed: %d\n", ret);
 		goto err;
 	}
 
 	ret = clk_enable(&eqos->clk_rx);
 	if (ret < 0) {
-		pr_err("clk_enable(clk_rx) failed: %d", ret);
+		pr_err("clk_enable(clk_rx) failed: %d\n", ret);
 		goto err_disable_clk_master_bus;
 	}
 
 	ret = clk_enable(&eqos->clk_tx);
 	if (ret < 0) {
-		pr_err("clk_enable(clk_tx) failed: %d", ret);
+		pr_err("clk_enable(clk_tx) failed: %d\n", ret);
 		goto err_disable_clk_rx;
 	}
 
 	if (clk_valid(&eqos->clk_ck) && !eqos->clk_ck_enabled) {
 		ret = clk_enable(&eqos->clk_ck);
 		if (ret < 0) {
-			pr_err("clk_enable(clk_ck) failed: %d", ret);
+			pr_err("clk_enable(clk_ck) failed: %d\n", ret);
 			goto err_disable_clk_tx;
 		}
 		eqos->clk_ck_enabled = true;
@@ -390,7 +390,7 @@
 
 	ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
 	if (ret < 0) {
-		pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", ret);
+		pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d\n", ret);
 		return ret;
 	}
 
@@ -398,13 +398,13 @@
 
 	ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
 	if (ret < 0) {
-		pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", ret);
+		pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d\n", ret);
 		return ret;
 	}
 
 	ret = reset_assert(&eqos->reset_ctl);
 	if (ret < 0) {
-		pr_err("reset_assert() failed: %d", ret);
+		pr_err("reset_assert() failed: %d\n", ret);
 		return ret;
 	}
 
@@ -412,7 +412,7 @@
 
 	ret = reset_deassert(&eqos->reset_ctl);
 	if (ret < 0) {
-		pr_err("reset_deassert() failed: %d", ret);
+		pr_err("reset_deassert() failed: %d\n", ret);
 		return ret;
 	}
 
@@ -448,14 +448,14 @@
 	ret = wait_for_bit_le32(&eqos->tegra186_regs->auto_cal_status,
 				EQOS_AUTO_CAL_STATUS_ACTIVE, true, 10, false);
 	if (ret) {
-		pr_err("calibrate didn't start");
+		pr_err("calibrate didn't start\n");
 		goto failed;
 	}
 
 	ret = wait_for_bit_le32(&eqos->tegra186_regs->auto_cal_status,
 				EQOS_AUTO_CAL_STATUS_ACTIVE, false, 10, false);
 	if (ret) {
-		pr_err("calibrate didn't finish");
+		pr_err("calibrate didn't finish\n");
 		goto failed;
 	}
 
@@ -586,13 +586,13 @@
 		rate = 2.5 * 1000 * 1000;
 		break;
 	default:
-		pr_err("invalid speed %d", eqos->phy->speed);
+		pr_err("invalid speed %d\n", eqos->phy->speed);
 		return -EINVAL;
 	}
 
 	ret = clk_set_rate(&eqos->clk_tx, rate);
 	if (ret < 0) {
-		pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret);
+		pr_err("clk_set_rate(tx_clk, %lu) failed: %d\n", rate, ret);
 		return ret;
 	}
 #endif
@@ -613,7 +613,7 @@
 	else
 		ret = eqos_set_half_duplex(dev);
 	if (ret < 0) {
-		pr_err("eqos_set_*_duplex() failed: %d", ret);
+		pr_err("eqos_set_*_duplex() failed: %d\n", ret);
 		return ret;
 	}
 
@@ -631,32 +631,32 @@
 		ret = eqos_set_mii_speed_10(dev);
 		break;
 	default:
-		pr_err("invalid speed %d", eqos->phy->speed);
+		pr_err("invalid speed %d\n", eqos->phy->speed);
 		return -EINVAL;
 	}
 	if (ret < 0) {
-		pr_err("eqos_set_*mii_speed*() failed: %d", ret);
+		pr_err("eqos_set_*mii_speed*() failed: %d\n", ret);
 		return ret;
 	}
 
 	if (en_calibration) {
 		ret = eqos->config->ops->eqos_calibrate_pads(dev);
 		if (ret < 0) {
-			pr_err("eqos_calibrate_pads() failed: %d",
+			pr_err("eqos_calibrate_pads() failed: %d\n",
 			       ret);
 			return ret;
 		}
 	} else {
 		ret = eqos->config->ops->eqos_disable_calibration(dev);
 		if (ret < 0) {
-			pr_err("eqos_disable_calibration() failed: %d",
+			pr_err("eqos_disable_calibration() failed: %d\n",
 			       ret);
 			return ret;
 		}
 	}
 	ret = eqos->config->ops->eqos_set_tx_clk_speed(dev);
 	if (ret < 0) {
-		pr_err("eqos_set_tx_clk_speed() failed: %d", ret);
+		pr_err("eqos_set_tx_clk_speed() failed: %d\n", ret);
 		return ret;
 	}
 
@@ -755,7 +755,7 @@
 
 	ret = eqos->config->ops->eqos_start_resets(dev);
 	if (ret < 0) {
-		pr_err("eqos_start_resets() failed: %d", ret);
+		pr_err("eqos_start_resets() failed: %d\n", ret);
 		goto err;
 	}
 
@@ -773,13 +773,13 @@
 				EQOS_DMA_MODE_SWR, false,
 				eqos->config->swr_wait, false);
 	if (ret) {
-		pr_err("EQOS_DMA_MODE_SWR stuck");
+		pr_err("EQOS_DMA_MODE_SWR stuck\n");
 		goto err_stop_resets;
 	}
 
 	ret = eqos->config->ops->eqos_calibrate_pads(dev);
 	if (ret < 0) {
-		pr_err("eqos_calibrate_pads() failed: %d", ret);
+		pr_err("eqos_calibrate_pads() failed: %d\n", ret);
 		goto err_stop_resets;
 	}
 
@@ -812,7 +812,7 @@
 		}
 
 		if (!eqos->phy) {
-			pr_err("phy_connect() failed");
+			pr_err("phy_connect() failed\n");
 			ret = -ENODEV;
 			goto err_stop_resets;
 		}
@@ -820,7 +820,7 @@
 		if (eqos->max_speed) {
 			ret = phy_set_supported(eqos->phy, eqos->max_speed);
 			if (ret) {
-				pr_err("phy_set_supported() failed: %d", ret);
+				pr_err("phy_set_supported() failed: %d\n", ret);
 				goto err_shutdown_phy;
 			}
 		}
@@ -828,26 +828,26 @@
 		eqos->phy->node = eqos->phy_of_node;
 		ret = phy_config(eqos->phy);
 		if (ret < 0) {
-			pr_err("phy_config() failed: %d", ret);
+			pr_err("phy_config() failed: %d\n", ret);
 			goto err_shutdown_phy;
 		}
 	}
 
 	ret = phy_startup(eqos->phy);
 	if (ret < 0) {
-		pr_err("phy_startup() failed: %d", ret);
+		pr_err("phy_startup() failed: %d\n", ret);
 		goto err_shutdown_phy;
 	}
 
 	if (!eqos->phy->link) {
-		pr_err("No link");
+		pr_err("No link\n");
 		ret = -EAGAIN;
 		goto err_shutdown_phy;
 	}
 
 	ret = eqos_adjust_link(dev);
 	if (ret < 0) {
-		pr_err("eqos_adjust_link() failed: %d", ret);
+		pr_err("eqos_adjust_link() failed: %d\n", ret);
 		goto err_shutdown_phy;
 	}
 
@@ -1090,7 +1090,7 @@
 err_stop_resets:
 	eqos->config->ops->eqos_stop_resets(dev);
 err:
-	pr_err("FAILED: %d", ret);
+	pr_err("FAILED: %d\n", ret);
 	return ret;
 }
 
@@ -1217,7 +1217,7 @@
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	u32 idx, idx_mask = eqos->desc_per_cacheline - 1;
 	uchar *packet_expected;
-	struct eqos_desc *rx_desc;
+	struct eqos_desc *rx_desc = NULL;
 
 	debug("%s(packet=%p, length=%d)\n", __func__, packet, length);
 
@@ -1361,7 +1361,7 @@
 
 	ret = reset_get_by_name(dev, "eqos", &eqos->reset_ctl);
 	if (ret) {
-		pr_err("reset_get_by_name(rst) failed: %d", ret);
+		pr_err("reset_get_by_name(rst) failed: %d\n", ret);
 		return ret;
 	}
 
@@ -1369,37 +1369,37 @@
 				   &eqos->phy_reset_gpio,
 				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
 	if (ret) {
-		pr_err("gpio_request_by_name(phy reset) failed: %d", ret);
+		pr_err("gpio_request_by_name(phy reset) failed: %d\n", ret);
 		goto err_free_reset_eqos;
 	}
 
 	ret = clk_get_by_name(dev, "slave_bus", &eqos->clk_slave_bus);
 	if (ret) {
-		pr_err("clk_get_by_name(slave_bus) failed: %d", ret);
+		pr_err("clk_get_by_name(slave_bus) failed: %d\n", ret);
 		goto err_free_gpio_phy_reset;
 	}
 
 	ret = clk_get_by_name(dev, "master_bus", &eqos->clk_master_bus);
 	if (ret) {
-		pr_err("clk_get_by_name(master_bus) failed: %d", ret);
+		pr_err("clk_get_by_name(master_bus) failed: %d\n", ret);
 		goto err_free_gpio_phy_reset;
 	}
 
 	ret = clk_get_by_name(dev, "rx", &eqos->clk_rx);
 	if (ret) {
-		pr_err("clk_get_by_name(rx) failed: %d", ret);
+		pr_err("clk_get_by_name(rx) failed: %d\n", ret);
 		goto err_free_gpio_phy_reset;
 	}
 
 	ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref);
 	if (ret) {
-		pr_err("clk_get_by_name(ptp_ref) failed: %d", ret);
+		pr_err("clk_get_by_name(ptp_ref) failed: %d\n", ret);
 		goto err_free_gpio_phy_reset;
 	}
 
 	ret = clk_get_by_name(dev, "tx", &eqos->clk_tx);
 	if (ret) {
-		pr_err("clk_get_by_name(tx) failed: %d", ret);
+		pr_err("clk_get_by_name(tx) failed: %d\n", ret);
 		goto err_free_gpio_phy_reset;
 	}
 
@@ -1436,19 +1436,19 @@
 
 	ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
 	if (ret) {
-		pr_err("clk_get_by_name(master_bus) failed: %d", ret);
+		pr_err("clk_get_by_name(master_bus) failed: %d\n", ret);
 		goto err_probe;
 	}
 
 	ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx);
 	if (ret) {
-		pr_err("clk_get_by_name(rx) failed: %d", ret);
+		pr_err("clk_get_by_name(rx) failed: %d\n", ret);
 		goto err_probe;
 	}
 
 	ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx);
 	if (ret) {
-		pr_err("clk_get_by_name(tx) failed: %d", ret);
+		pr_err("clk_get_by_name(tx) failed: %d\n", ret);
 		goto err_probe;
 	}
 
@@ -1502,7 +1502,7 @@
 
 	eqos->regs = dev_read_addr(dev);
 	if (eqos->regs == FDT_ADDR_T_NONE) {
-		pr_err("dev_read_addr() failed");
+		pr_err("dev_read_addr() failed\n");
 		return -ENODEV;
 	}
 	eqos->mac_regs = (void *)(eqos->regs + EQOS_MAC_REGS_BASE);
@@ -1514,19 +1514,19 @@
 
 	ret = eqos_probe_resources_core(dev);
 	if (ret < 0) {
-		pr_err("eqos_probe_resources_core() failed: %d", ret);
+		pr_err("eqos_probe_resources_core() failed: %d\n", ret);
 		return ret;
 	}
 
 	ret = eqos->config->ops->eqos_probe_resources(dev);
 	if (ret < 0) {
-		pr_err("eqos_probe_resources() failed: %d", ret);
+		pr_err("eqos_probe_resources() failed: %d\n", ret);
 		goto err_remove_resources_core;
 	}
 
 	ret = eqos->config->ops->eqos_start_clks(dev);
 	if (ret < 0) {
-		pr_err("eqos_start_clks() failed: %d", ret);
+		pr_err("eqos_start_clks() failed: %d\n", ret);
 		goto err_remove_resources_tegra;
 	}
 
@@ -1536,7 +1536,7 @@
 	if (!eqos->mii) {
 		eqos->mii = mdio_alloc();
 		if (!eqos->mii) {
-			pr_err("mdio_alloc() failed");
+			pr_err("mdio_alloc() failed\n");
 			ret = -ENOMEM;
 			goto err_stop_clks;
 		}
@@ -1547,7 +1547,7 @@
 
 		ret = mdio_register(eqos->mii);
 		if (ret < 0) {
-			pr_err("mdio_register() failed: %d", ret);
+			pr_err("mdio_register() failed: %d\n", ret);
 			goto err_free_mdio;
 		}
 	}
diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig
index 72eccc9..ddfa95a 100644
--- a/drivers/net/ti/Kconfig
+++ b/drivers/net/ti/Kconfig
@@ -57,3 +57,16 @@
 	help
 	  This driver supports the TI CPSW MDIO interface found in various
 	  TI SoCs.
+
+config TI_ICSSG_PRUETH
+	bool "TI Gigabit PRU Ethernet driver"
+	depends on ARCH_K3
+	imply DM_MDIO
+	imply MISC_INIT_R
+	imply MISC
+	imply MDIO_TI_CPSW
+	select PHYLIB
+	select FS_LOADER
+	help
+	  Support Gigabit Ethernet ports over the ICSSG PRU Subsystem
+	  This subsystem is available starting with the AM65 platform.
diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile
index 30c4c4b..b2b3aa3 100644
--- a/drivers/net/ti/Makefile
+++ b/drivers/net/ti/Makefile
@@ -7,3 +7,4 @@
 obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o cpsw_mdio.o
 obj-$(CONFIG_TI_AM65_CPSW_NUSS) += am65-cpsw-nuss.o
 obj-$(CONFIG_MDIO_TI_CPSW) += cpsw_mdio.o
+obj-$(CONFIG_TI_ICSSG_PRUETH) += icssg_prueth.o icssg_classifier.o icssg_config.o icssg_queues.o
diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c
index d68ed67..b151e25 100644
--- a/drivers/net/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ti/am65-cpsw-nuss.c
@@ -664,7 +664,7 @@
 	struct am65_cpsw_priv *priv = dev_get_priv(dev);
 	struct eth_pdata *pdata = dev_get_plat(dev);
 	struct am65_cpsw_common *cpsw_common;
-	char portname[15];
+	char portname[32];
 	int ret;
 
 	priv->dev = dev;
@@ -672,7 +672,7 @@
 	cpsw_common = dev_get_priv(dev->parent);
 	priv->cpsw_common = cpsw_common;
 
-	sprintf(portname, "%s%s", dev->parent->name, dev->name);
+	snprintf(portname, sizeof(portname), "%s%s", dev->parent->name, dev->name);
 	device_set_name(dev, portname);
 
 	ret = am65_cpsw_ofdata_parse_phy(dev);
diff --git a/drivers/net/ti/icss_mii_rt.h b/drivers/net/ti/icss_mii_rt.h
new file mode 100644
index 0000000..fd95d4d
--- /dev/null
+++ b/drivers/net/ti/icss_mii_rt.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* PRU-ICSS MII_RT register definitions
+ *
+ * Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#ifndef __NET_PRUSS_MII_RT_H__
+#define __NET_PRUSS_MII_RT_H__
+
+#include <regmap.h>
+
+/* PRUSS_MII_RT Registers */
+#define PRUSS_MII_RT_RXCFG0		0x0
+#define PRUSS_MII_RT_RXCFG1		0x4
+#define PRUSS_MII_RT_TXCFG0		0x10
+#define PRUSS_MII_RT_TXCFG1		0x14
+#define PRUSS_MII_RT_TX_CRC0		0x20
+#define PRUSS_MII_RT_TX_CRC1		0x24
+#define PRUSS_MII_RT_TX_IPG0		0x30
+#define PRUSS_MII_RT_TX_IPG1		0x34
+#define PRUSS_MII_RT_PRS0		0x38
+#define PRUSS_MII_RT_PRS1		0x3c
+#define PRUSS_MII_RT_RX_FRMS0		0x40
+#define PRUSS_MII_RT_RX_FRMS1		0x44
+#define PRUSS_MII_RT_RX_PCNT0		0x48
+#define PRUSS_MII_RT_RX_PCNT1		0x4c
+#define PRUSS_MII_RT_RX_ERR0		0x50
+#define PRUSS_MII_RT_RX_ERR1		0x54
+
+/* PRUSS_MII_RT_RXCFG0/1 bits */
+#define PRUSS_MII_RT_RXCFG_RX_ENABLE		BIT(0)
+#define PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS	BIT(1)
+#define PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE	BIT(2)
+#define PRUSS_MII_RT_RXCFG_RX_MUX_SEL		BIT(3)
+#define PRUSS_MII_RT_RXCFG_RX_L2_EN		BIT(4)
+#define PRUSS_MII_RT_RXCFG_RX_BYTE_SWAP		BIT(5)
+#define PRUSS_MII_RT_RXCFG_RX_AUTO_FWD_PRE	BIT(6)
+#define PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS	BIT(9)
+
+/* PRUSS_MII_RT_TXCFG0/1 bits */
+#define PRUSS_MII_RT_TXCFG_TX_ENABLE		BIT(0)
+#define PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE	BIT(1)
+#define PRUSS_MII_RT_TXCFG_TX_EN_MODE		BIT(2)
+#define PRUSS_MII_RT_TXCFG_TX_BYTE_SWAP		BIT(3)
+#define PRUSS_MII_RT_TXCFG_TX_MUX_SEL		BIT(8)
+#define PRUSS_MII_RT_TXCFG_PRE_TX_AUTO_SEQUENCE	BIT(9)
+#define PRUSS_MII_RT_TXCFG_PRE_TX_AUTO_ESC_ERR	BIT(10)
+#define PRUSS_MII_RT_TXCFG_TX_32_MODE_EN	BIT(11)
+#define PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN	BIT(12)	/* SR2.0 onwards */
+
+#define PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT	16
+#define PRUSS_MII_RT_TXCFG_TX_START_DELAY_MASK	GENMASK(25, 16)
+
+#define PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT	28
+#define PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_MASK	GENMASK(30, 28)
+
+/* PRUSS_MII_RT_TX_IPG0/1 bits */
+#define PRUSS_MII_RT_TX_IPG_IPG_SHIFT	0
+#define PRUSS_MII_RT_TX_IPG_IPG_MASK	GENMASK(9, 0)
+
+/* PRUSS_MII_RT_PRS0/1 bits */
+#define PRUSS_MII_RT_PRS_COL	BIT(0)
+#define PRUSS_MII_RT_PRS_CRS	BIT(1)
+
+/* PRUSS_MII_RT_RX_FRMS0/1 bits */
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM_SHIFT	0
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK	GENMASK(15, 0)
+
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_SHIFT	16
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK	GENMASK(31, 16)
+
+/* Min/Max in MII_RT_RX_FRMS */
+/* For EMAC and Switch */
+#define PRUSS_MII_RT_RX_FRMS_MAX	(VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+#define PRUSS_MII_RT_RX_FRMS_MIN_FRM	(64)
+
+/* for HSR and PRP */
+#define PRUSS_MII_RT_RX_FRMS_MAX_FRM_LRE	(PRUSS_MII_RT_RX_FRMS_MAX + \
+						 ICSS_LRE_TAG_RCT_SIZE)
+/* PRUSS_MII_RT_RX_PCNT0/1 bits */
+#define PRUSS_MII_RT_RX_PCNT_MIN_PCNT_SHIFT	0
+#define PRUSS_MII_RT_RX_PCNT_MIN_PCNT_MASK	GENMASK(3, 0)
+
+#define PRUSS_MII_RT_RX_PCNT_MAX_PCNT_SHIFT	4
+#define PRUSS_MII_RT_RX_PCNT_MAX_PCNT_MASK	GENMASK(7, 4)
+
+/* PRUSS_MII_RT_RX_ERR0/1 bits */
+#define PRUSS_MII_RT_RX_ERR_MIN_PCNT_ERR	BIT(0)
+#define PRUSS_MII_RT_RX_ERR_MAX_PCNT_ERR	BIT(1)
+#define PRUSS_MII_RT_RX_ERR_MIN_FRM_ERR		BIT(2)
+#define PRUSS_MII_RT_RX_ERR_MAX_FRM_ERR		BIT(3)
+
+#define ICSSG_CFG_OFFSET	0
+#define RGMII_CFG_OFFSET	4
+
+/* Constant to choose between MII0 and MII1 */
+#define ICSS_MII0	0
+#define ICSS_MII1	1
+
+/* ICSSG_CFG Register bits */
+#define ICSSG_CFG_SGMII_MODE	BIT(16)
+#define ICSSG_CFG_TX_PRU_EN	BIT(11)
+#define ICSSG_CFG_RX_SFD_TX_SOF_EN	BIT(10)
+#define ICSSG_CFG_RTU_PRU_PSI_SHARE_EN	BIT(9)
+#define ICSSG_CFG_IEP1_TX_EN	BIT(8)
+#define ICSSG_CFG_MII1_MODE	GENMASK(6, 5)
+#define ICSSG_CFG_MII1_MODE_SHIFT	5
+#define ICSSG_CFG_MII0_MODE	GENMASK(4, 3)
+#define ICSSG_CFG_MII0_MODE_SHIFT	3
+#define ICSSG_CFG_RX_L2_G_EN	BIT(2)
+#define ICSSG_CFG_TX_L2_EN	BIT(1)
+#define ICSSG_CFG_TX_L1_EN	BIT(0)
+
+enum mii_mode { MII_MODE_MII = 0, MII_MODE_RGMII, MII_MODE_SGMII };
+
+/* RGMII CFG Register bits */
+#define RGMII_CFG_INBAND_EN_MII0	BIT(16)
+#define RGMII_CFG_GIG_EN_MII0	BIT(17)
+#define RGMII_CFG_INBAND_EN_MII1	BIT(20)
+#define RGMII_CFG_GIG_EN_MII1	BIT(21)
+#define RGMII_CFG_FULL_DUPLEX_MII0	BIT(18)
+#define RGMII_CFG_FULL_DUPLEX_MII1	BIT(22)
+#define RGMII_CFG_SPEED_MII0	GENMASK(2, 1)
+#define RGMII_CFG_SPEED_MII1	GENMASK(6, 5)
+#define RGMII_CFG_SPEED_MII0_SHIFT	1
+#define RGMII_CFG_SPEED_MII1_SHIFT	5
+#define RGMII_CFG_FULLDUPLEX_MII0	BIT(3)
+#define RGMII_CFG_FULLDUPLEX_MII1	BIT(7)
+#define RGMII_CFG_FULLDUPLEX_MII0_SHIFT	3
+#define RGMII_CFG_FULLDUPLEX_MII1_SHIFT	7
+#define RGMII_CFG_SPEED_10M	0
+#define RGMII_CFG_SPEED_100M	1
+#define RGMII_CFG_SPEED_1G	2
+
+static inline void icssg_mii_update_ipg(struct regmap *mii_rt, int mii, u32 ipg)
+{
+	u32 val;
+
+	if (mii == ICSS_MII0) {
+		regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG0, ipg);
+	} else {
+		/* Errata workaround: IEP1 is not read by h/w unless IEP0 is written */
+		regmap_read(mii_rt, PRUSS_MII_RT_TX_IPG0, &val);
+		regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG1, ipg);
+		regmap_write(mii_rt, PRUSS_MII_RT_TX_IPG0, val);
+	}
+}
+
+static inline void icssg_update_rgmii_cfg(struct regmap *miig_rt, int speed,
+					  bool full_duplex, int slice, struct prueth_priv *priv)
+{
+	u32 gig_en_mask, gig_val = 0, full_duplex_mask, full_duplex_val = 0;
+	u32 inband_en_mask, inband_val = 0;
+
+	gig_en_mask = (slice == ICSS_MII0) ? RGMII_CFG_GIG_EN_MII0 :
+					RGMII_CFG_GIG_EN_MII1;
+	if (speed == SPEED_1000)
+		gig_val = gig_en_mask;
+	regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, gig_en_mask, gig_val);
+
+	inband_en_mask = (slice == ICSS_MII0) ? RGMII_CFG_INBAND_EN_MII0 :
+					RGMII_CFG_INBAND_EN_MII1;
+	if (speed == SPEED_10 && phy_interface_is_rgmii(priv->phydev))
+		inband_val = inband_en_mask;
+	regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, inband_en_mask, inband_val);
+
+	full_duplex_mask = (slice == ICSS_MII0) ? RGMII_CFG_FULL_DUPLEX_MII0 :
+					   RGMII_CFG_FULL_DUPLEX_MII1;
+	if (full_duplex)
+		full_duplex_val = full_duplex_mask;
+	regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, full_duplex_mask,
+			   full_duplex_val);
+}
+
+static inline void icssg_miig_set_interface_mode(struct regmap *miig_rt, int mii, int phy_if)
+{
+	u32 val, mask, shift;
+
+	mask = mii == ICSS_MII0 ? ICSSG_CFG_MII0_MODE : ICSSG_CFG_MII1_MODE;
+	shift =  mii == ICSS_MII0 ? ICSSG_CFG_MII0_MODE_SHIFT : ICSSG_CFG_MII1_MODE_SHIFT;
+
+	val = MII_MODE_RGMII;
+	if (phy_if == PHY_INTERFACE_MODE_MII)
+		val = MII_MODE_MII;
+
+	val <<= shift;
+	regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, mask, val);
+	regmap_read(miig_rt, ICSSG_CFG_OFFSET, &val);
+}
+
+#endif /* __NET_PRUSS_MII_RT_H__ */
diff --git a/drivers/net/ti/icssg_classifier.c b/drivers/net/ti/icssg_classifier.c
new file mode 100644
index 0000000..e510a1c
--- /dev/null
+++ b/drivers/net/ti/icssg_classifier.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments ICSSG Ethernet Driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <dm/ofnode.h>
+#include <regmap.h>
+
+#define ICSSG_NUM_CLASSIFIERS	16
+#define ICSSG_NUM_FT1_SLOTS	8
+#define ICSSG_NUM_FT3_SLOTS	16
+
+#define ICSSG_NUM_CLASSIFIERS_IN_USE	1
+
+/* Filter 1 - FT1 */
+#define FT1_NUM_SLOTS	8
+#define FT1_SLOT_SIZE	0x10	/* bytes */
+
+/* offsets from FT1 slot base i.e. slot 1 start */
+#define FT1_DA0		0x0
+#define FT1_DA1		0x4
+#define FT1_DA0_MASK	0x8
+#define FT1_DA1_MASK	0xc
+
+#define FT1_N_REG(slize, n, reg)	(offs[slice].ft1_slot_base + FT1_SLOT_SIZE * (n) + (reg))
+
+#define FT1_LEN_MASK	GENMASK(19, 16)
+#define FT1_LEN_SHIFT	16
+#define FT1_LEN(len)	(((len) << FT1_LEN_SHIFT) & FT1_LEN_MASK)
+
+#define FT1_START_MASK	GENMASK(14, 0)
+#define FT1_START(start)	((start) & FT1_START_MASK)
+
+#define FT1_MATCH_SLOT(n)	(GENMASK(23, 16) & (BIT(n) << 16))
+
+enum ft1_cfg_type {
+	FT1_CFG_TYPE_DISABLED = 0,
+	FT1_CFG_TYPE_EQ,
+	FT1_CFG_TYPE_GT,
+	FT1_CFG_TYPE_LT,
+};
+
+#define FT1_CFG_SHIFT(n)	(2 * (n))
+#define FT1_CFG_MASK(n)	(0x3 << FT1_CFG_SHIFT((n)))
+
+/* Filter 3 -  FT3 */
+#define FT3_NUM_SLOTS	16
+#define FT3_SLOT_SIZE	0x20	/* bytes */
+
+/* offsets from FT3 slot n's base */
+#define FT3_START	0
+#define FT3_START_AUTO	0x4
+#define FT3_START_OFFSET	0x8
+#define FT3_JUMP_OFFSET	0xc
+#define FT3_LEN		0x10
+#define FT3_CFG		0x14
+#define FT3_T		0x18
+#define FT3_T_MASK	0x1c
+
+#define FT3_N_REG(slize, n, reg)	\
+	(offs[slice].ft3_slot_base + FT3_SLOT_SIZE * (n) + (reg))
+
+/* offsets from rx_class n's base */
+#define RX_CLASS_AND_EN	0
+#define RX_CLASS_OR_EN	0x4
+
+#define RX_CLASS_NUM_SLOTS	16
+#define RX_CLASS_EN_SIZE	0x8	/* bytes */
+
+#define RX_CLASS_N_REG(slice, n, reg)	\
+	(offs[slice].rx_class_base + RX_CLASS_EN_SIZE * (n) + (reg))
+
+/* RX Class Gates */
+#define RX_CLASS_GATES_SIZE	0x4	/* bytes */
+
+#define RX_CLASS_GATES_N_REG(slice, n)	\
+	(offs[slice].rx_class_gates_base + RX_CLASS_GATES_SIZE * (n))
+
+#define RX_CLASS_GATES_ALLOW_MASK	BIT(6)
+#define RX_CLASS_GATES_RAW_MASK		BIT(5)
+#define RX_CLASS_GATES_PHASE_MASK	BIT(4)
+
+/* RX Class traffic data matching bits */
+#define RX_CLASS_FT_UC		BIT(31)
+#define RX_CLASS_FT_MC		BIT(30)
+#define RX_CLASS_FT_BC		BIT(29)
+#define RX_CLASS_FT_FW		BIT(28)
+#define RX_CLASS_FT_RCV		BIT(27)
+#define RX_CLASS_FT_VLAN	BIT(26)
+#define RX_CLASS_FT_DA_P	BIT(25)
+#define RX_CLASS_FT_DA_I	BIT(24)
+#define RX_CLASS_FT_FT1_MATCH_MASK	GENMASK(23, 16)
+#define RX_CLASS_FT_FT1_MATCH_SHIFT	16
+#define RX_CLASS_FT_FT3_MATCH_MASK	GENMASK(15, 0)
+#define RX_CLASS_FT_FT3_MATCH_SHIFT	0
+
+#define RX_CLASS_FT_FT1_MATCH(slot)	\
+	((BIT(slot) << RX_CLASS_FT_FT1_MATCH_SHIFT) & \
+	RX_CLASS_FT_FT1_MATCH_MASK)
+
+enum rx_class_sel_type {
+	RX_CLASS_SEL_TYPE_OR = 0,
+	RX_CLASS_SEL_TYPE_AND = 1,
+	RX_CLASS_SEL_TYPE_OR_AND_AND = 2,
+	RX_CLASS_SEL_TYPE_OR_OR_AND = 3,
+};
+
+#define FT1_CFG_SHIFT(n)	(2 * (n))
+#define FT1_CFG_MASK(n)		(0x3 << FT1_CFG_SHIFT((n)))
+
+#define RX_CLASS_SEL_SHIFT(n)	(2 * (n))
+#define RX_CLASS_SEL_MASK(n)	(0x3 << RX_CLASS_SEL_SHIFT((n)))
+
+#define ICSSG_CFG_OFFSET	0
+#define MAC_INTERFACE_0		0x18
+#define MAC_INTERFACE_1		0x1c
+
+#define ICSSG_CFG_RX_L2_G_EN	BIT(2)
+
+/* these are register offsets per PRU */
+struct miig_rt_offsets {
+	u32 mac0;
+	u32 mac1;
+	u32 ft1_start_len;
+	u32 ft1_cfg;
+	u32 ft1_slot_base;
+	u32 ft3_slot_base;
+	u32 ft3_p_base;
+	u32 ft_rx_ptr;
+	u32 rx_class_base;
+	u32 rx_class_cfg1;
+	u32 rx_class_cfg2;
+	u32 rx_class_gates_base;
+	u32 rx_green;
+	u32 rx_rate_cfg_base;
+	u32 rx_rate_src_sel0;
+	u32 rx_rate_src_sel1;
+	u32 tx_rate_cfg_base;
+	u32 stat_base;
+	u32 tx_hsr_tag;
+	u32 tx_hsr_seq;
+	u32 tx_vlan_type;
+	u32 tx_vlan_ins;
+};
+
+static struct miig_rt_offsets offs[] = {
+	/* PRU0 */
+	{
+		0x8,
+		0xc,
+		0x80,
+		0x84,
+		0x88,
+		0x108,
+		0x308,
+		0x408,
+		0x40c,
+		0x48c,
+		0x490,
+		0x494,
+		0x4d4,
+		0x4e4,
+		0x504,
+		0x508,
+		0x50c,
+		0x54c,
+		0x63c,
+		0x640,
+		0x644,
+		0x648,
+	},
+	/* PRU1 */
+	{
+		0x10,
+		0x14,
+		0x64c,
+		0x650,
+		0x654,
+		0x6d4,
+		0x8d4,
+		0x9d4,
+		0x9d8,
+		0xa58,
+		0xa5c,
+		0xa60,
+		0xaa0,
+		0xab0,
+		0xad0,
+		0xad4,
+		0xad8,
+		0xb18,
+		0xc08,
+		0xc0c,
+		0xc10,
+		0xc14,
+	},
+};
+
+static inline u32 addr_to_da0(const u8 *addr)
+{
+	return (u32)(addr[0] | addr[1] << 8 |
+		addr[2] << 16 | addr[3] << 24);
+};
+
+static inline u32 addr_to_da1(const u8 *addr)
+{
+	return (u32)(addr[4] | addr[5] << 8);
+};
+
+static void rx_class_ft1_set_start_len(struct regmap *miig_rt, int slice,
+				       u16 start, u8 len)
+{
+	u32 offset, val;
+
+	offset = offs[slice].ft1_start_len;
+	val = FT1_LEN(len) | FT1_START(start);
+	regmap_write(miig_rt, offset, val);
+}
+
+static void rx_class_ft1_set_da(struct regmap *miig_rt, int slice,
+				int n, const u8 *addr)
+{
+	u32 offset;
+
+	offset = FT1_N_REG(slice, n, FT1_DA0);
+	regmap_write(miig_rt, offset, addr_to_da0(addr));
+	offset = FT1_N_REG(slice, n, FT1_DA1);
+	regmap_write(miig_rt, offset, addr_to_da1(addr));
+}
+
+static void rx_class_ft1_set_da_mask(struct regmap *miig_rt, int slice,
+				     int n, const u8 *addr)
+{
+	u32 offset;
+
+	offset = FT1_N_REG(slice, n, FT1_DA0_MASK);
+	regmap_write(miig_rt, offset, addr_to_da0(addr));
+	offset = FT1_N_REG(slice, n, FT1_DA1_MASK);
+	regmap_write(miig_rt, offset, addr_to_da1(addr));
+}
+
+static void rx_class_ft1_cfg_set_type(struct regmap *miig_rt, int slice, int n,
+				      enum ft1_cfg_type type)
+{
+	u32 offset;
+
+	offset = offs[slice].ft1_cfg;
+	regmap_update_bits(miig_rt, offset, FT1_CFG_MASK(n),
+			   type << FT1_CFG_SHIFT(n));
+}
+
+static void rx_class_sel_set_type(struct regmap *miig_rt, int slice, int n,
+				  enum rx_class_sel_type type)
+{
+	u32 offset;
+
+	offset = offs[slice].rx_class_cfg1;
+	regmap_update_bits(miig_rt, offset, RX_CLASS_SEL_MASK(n),
+			   type << RX_CLASS_SEL_SHIFT(n));
+}
+
+static void rx_class_set_and(struct regmap *miig_rt, int slice, int n,
+			     u32 data)
+{
+	u32 offset;
+
+	offset = RX_CLASS_N_REG(slice, n, RX_CLASS_AND_EN);
+	regmap_write(miig_rt, offset, data);
+}
+
+static void rx_class_set_or(struct regmap *miig_rt, int slice, int n,
+			    u32 data)
+{
+	u32 offset;
+
+	offset = RX_CLASS_N_REG(slice, n, RX_CLASS_OR_EN);
+	regmap_write(miig_rt, offset, data);
+}
+
+void icssg_class_set_host_mac_addr(struct regmap *miig_rt, u8 *mac)
+{
+	regmap_write(miig_rt, MAC_INTERFACE_0, addr_to_da0(mac));
+	regmap_write(miig_rt, MAC_INTERFACE_1, addr_to_da1(mac));
+}
+
+void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac)
+{
+	regmap_write(miig_rt, offs[slice].mac0, addr_to_da0(mac));
+	regmap_write(miig_rt, offs[slice].mac1, addr_to_da1(mac));
+}
+
+void icssg_class_disable_n(struct regmap *miig_rt, int slice, int n)
+{
+	u32 data, offset;
+
+	/* AND_EN = 0 */
+	rx_class_set_and(miig_rt, slice, n, 0);
+	/* OR_EN = 0 */
+	rx_class_set_or(miig_rt, slice, n, 0);
+
+	/* set CFG1 to OR */
+	rx_class_sel_set_type(miig_rt, slice, n, RX_CLASS_SEL_TYPE_OR);
+
+	/* configure gate */
+	offset = RX_CLASS_GATES_N_REG(slice, n);
+	regmap_read(miig_rt, offset, &data);
+	/* clear class_raw so we go through filters */
+	data &= ~RX_CLASS_GATES_RAW_MASK;
+	/* set allow and phase mask */
+	data |= RX_CLASS_GATES_ALLOW_MASK | RX_CLASS_GATES_PHASE_MASK;
+	regmap_write(miig_rt, offset, data);
+}
+
+/* disable all RX traffic */
+void icssg_class_disable(struct regmap *miig_rt, int slice)
+{
+	int n;
+
+	/* Enable RX_L2_G */
+	regmap_update_bits(miig_rt, ICSSG_CFG_OFFSET, ICSSG_CFG_RX_L2_G_EN,
+			   ICSSG_CFG_RX_L2_G_EN);
+
+	for (n = 0; n < ICSSG_NUM_CLASSIFIERS; n++)
+		icssg_class_disable_n(miig_rt, slice, n);
+
+	/* FT1 Disabled */
+	for (n = 0; n < ICSSG_NUM_FT1_SLOTS; n++) {
+		u8 addr[] = { 0, 0, 0, 0, 0, 0, };
+
+		rx_class_ft1_cfg_set_type(miig_rt, slice, n,
+					  FT1_CFG_TYPE_DISABLED);
+		rx_class_ft1_set_da(miig_rt, slice, n, addr);
+		rx_class_ft1_set_da_mask(miig_rt, slice, n, addr);
+	}
+
+	/* clear CFG2 */
+	regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0);
+}
+
+void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti)
+{
+	u32 data;
+
+	/* defaults */
+	icssg_class_disable(miig_rt, slice);
+
+	/* Setup Classifier */
+	/* match on Broadcast or MAC_PRU address */
+	data = RX_CLASS_FT_BC | RX_CLASS_FT_DA_P;
+
+	/* multicast? */
+	if (allmulti)
+		data |= RX_CLASS_FT_MC;
+
+	rx_class_set_or(miig_rt, slice, 0, data);
+
+	/* set CFG1 for OR_OR_AND for classifier */
+	rx_class_sel_set_type(miig_rt, slice, 0,
+			      RX_CLASS_SEL_TYPE_OR_OR_AND);
+
+	/* clear CFG2 */
+	regmap_write(miig_rt, offs[slice].rx_class_cfg2, 0);
+}
+
+/* required for SR2 for SAV check */
+void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr)
+{
+	u8 mask_addr[] = { 0, 0, 0, 0, 0, 0, };
+
+	rx_class_ft1_set_start_len(miig_rt, slice, 6, 6);
+	rx_class_ft1_set_da(miig_rt, slice, 0, mac_addr);
+	rx_class_ft1_set_da_mask(miig_rt, slice, 0, mask_addr);
+	rx_class_ft1_cfg_set_type(miig_rt, slice, 0, FT1_CFG_TYPE_EQ);
+}
diff --git a/drivers/net/ti/icssg_config.c b/drivers/net/ti/icssg_config.c
new file mode 100644
index 0000000..5f132d0
--- /dev/null
+++ b/drivers/net/ti/icssg_config.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ICSSG Ethernet driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <phy.h>
+#include "icssg_prueth.h"
+#include "icssg_switch_map.h"
+#include "icss_mii_rt.h"
+#include <dm/device_compat.h>
+#include <linux/iopoll.h>
+
+/* TX IPG Values to be set for 100M and 1G link speeds.  These values are
+ * in ocp_clk cycles. So need change if ocp_clk is changed for a specific
+ * h/w design.
+ */
+
+/* SR2.0 IPG is in rgmii_clk (125MHz) clock cycles + 1 */
+#define MII_RT_TX_IPG_100M      0x17
+#define MII_RT_TX_IPG_1G        0xb
+
+#define	ICSSG_QUEUES_MAX		64
+#define	ICSSG_QUEUE_OFFSET		0xd00
+#define	ICSSG_QUEUE_PEEK_OFFSET		0xe00
+#define	ICSSG_QUEUE_CNT_OFFSET		0xe40
+#define	ICSSG_QUEUE_RESET_OFFSET	0xf40
+
+#define	ICSSG_NUM_TX_QUEUES	8
+
+#define	RECYCLE_Q_SLICE0	16
+#define	RECYCLE_Q_SLICE1	17
+
+#define	ICSSG_NUM_OTHER_QUEUES	5	/* port, host and special queues */
+
+#define	PORT_HI_Q_SLICE0	32
+#define	PORT_LO_Q_SLICE0	33
+#define	HOST_HI_Q_SLICE0	34
+#define	HOST_LO_Q_SLICE0	35
+#define	HOST_SPL_Q_SLICE0	40	/* Special Queue */
+
+#define	PORT_HI_Q_SLICE1	36
+#define	PORT_LO_Q_SLICE1	37
+#define	HOST_HI_Q_SLICE1	38
+#define	HOST_LO_Q_SLICE1	39
+#define	HOST_SPL_Q_SLICE1	41	/* Special Queue */
+
+#define MII_RXCFG_DEFAULT	(PRUSS_MII_RT_RXCFG_RX_ENABLE | \
+				 PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | \
+				 PRUSS_MII_RT_RXCFG_RX_L2_EN | \
+				 PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS)
+
+#define MII_TXCFG_DEFAULT	(PRUSS_MII_RT_TXCFG_TX_ENABLE | \
+				 PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | \
+				 PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | \
+				 PRUSS_MII_RT_TXCFG_TX_IPG_WIRE_CLK_EN)
+
+#define ICSSG_CFG_DEFAULT	(ICSSG_CFG_TX_L1_EN | \
+				 ICSSG_CFG_TX_L2_EN | ICSSG_CFG_RX_L2_G_EN | \
+				 ICSSG_CFG_TX_PRU_EN | /* SR2.0 only */ \
+				 ICSSG_CFG_SGMII_MODE)
+
+#define FDB_GEN_CFG1		0x60
+#define SMEM_VLAN_OFFSET	8
+#define SMEM_VLAN_OFFSET_MASK	GENMASK(25, 8)
+
+#define FDB_GEN_CFG2		0x64
+#define FDB_VLAN_EN		BIT(6)
+#define FDB_HOST_EN		BIT(2)
+#define FDB_PRU1_EN		BIT(1)
+#define FDB_PRU0_EN		BIT(0)
+#define FDB_EN_ALL		(FDB_PRU0_EN | FDB_PRU1_EN | \
+				 FDB_HOST_EN | FDB_VLAN_EN)
+
+struct map {
+	int queue;
+	u32 pd_addr_start;
+	u32 flags;
+	bool special;
+};
+
+struct map hwq_map[2][ICSSG_NUM_OTHER_QUEUES] = {
+	{
+		{ PORT_HI_Q_SLICE0, PORT_DESC0_HI, 0x200000, 0 },
+		{ PORT_LO_Q_SLICE0, PORT_DESC0_LO, 0, 0 },
+		{ HOST_HI_Q_SLICE0, HOST_DESC0_HI, 0x200000, 0 },
+		{ HOST_LO_Q_SLICE0, HOST_DESC0_LO, 0, 0 },
+		{ HOST_SPL_Q_SLICE0, HOST_SPPD0, 0x400000, 1 },
+	},
+	{
+		{ PORT_HI_Q_SLICE1, PORT_DESC1_HI, 0xa00000, 0 },
+		{ PORT_LO_Q_SLICE1, PORT_DESC1_LO, 0x800000, 0 },
+		{ HOST_HI_Q_SLICE1, HOST_DESC1_HI, 0xa00000, 0 },
+		{ HOST_LO_Q_SLICE1, HOST_DESC1_LO, 0x800000, 0 },
+		{ HOST_SPL_Q_SLICE1, HOST_SPPD1, 0xc00000, 1 },
+	},
+};
+
+static void icssg_config_mii_init(struct prueth_priv *priv, int slice)
+{
+	struct prueth *prueth = priv->prueth;
+	struct regmap *mii_rt = prueth->mii_rt;
+	u32 txcfg_reg, pcnt_reg;
+	u32 txcfg;
+
+	txcfg_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_TXCFG0 :
+				       PRUSS_MII_RT_TXCFG1;
+	pcnt_reg = (slice == ICSS_MII0) ? PRUSS_MII_RT_RX_PCNT0 :
+				       PRUSS_MII_RT_RX_PCNT1;
+
+	txcfg = MII_TXCFG_DEFAULT;
+
+	if (prueth->phy_interface == PHY_INTERFACE_MODE_MII && slice == ICSS_MII0)
+		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+	else if (prueth->phy_interface != PHY_INTERFACE_MODE_MII && slice == ICSS_MII1)
+		txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL;
+
+	regmap_write(mii_rt, txcfg_reg, txcfg);
+	regmap_write(mii_rt, pcnt_reg, 0x1);
+}
+
+static void icssg_miig_queues_init(struct prueth_priv *priv, int slice)
+{
+	struct prueth *prueth = priv->prueth;
+	void __iomem *smem = (void __iomem *)prueth->shram.pa;
+	struct regmap *miig_rt = prueth->miig_rt;
+	int queue = 0, i, j;
+	u8 pd[ICSSG_SPECIAL_PD_SIZE];
+	u32 *pdword;
+
+	/* reset hwqueues */
+	if (slice)
+		queue = ICSSG_NUM_TX_QUEUES;
+
+	for (i = 0; i < ICSSG_NUM_TX_QUEUES; i++) {
+		regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
+		queue++;
+	}
+
+	queue = slice ? RECYCLE_Q_SLICE1 : RECYCLE_Q_SLICE0;
+	regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET, queue);
+
+	for (i = 0; i < ICSSG_NUM_OTHER_QUEUES; i++) {
+		regmap_write(miig_rt, ICSSG_QUEUE_RESET_OFFSET,
+			     hwq_map[slice][i].queue);
+	}
+
+	/* initialize packet descriptors in SMEM */
+	/* push pakcet descriptors to hwqueues */
+
+	pdword = (u32 *)pd;
+	for (j = 0; j < ICSSG_NUM_OTHER_QUEUES; j++) {
+		struct map *mp;
+		int pd_size, num_pds;
+		u32 pdaddr;
+
+		mp = &hwq_map[slice][j];
+		if (mp->special) {
+			pd_size = ICSSG_SPECIAL_PD_SIZE;
+			num_pds = ICSSG_NUM_SPECIAL_PDS;
+		} else	{
+			pd_size = ICSSG_NORMAL_PD_SIZE;
+			num_pds = ICSSG_NUM_NORMAL_PDS;
+		}
+
+		for (i = 0; i < num_pds; i++) {
+			memset(pd, 0, pd_size);
+
+			pdword[0] &= cpu_to_le32(ICSSG_FLAG_MASK);
+			pdword[0] |= cpu_to_le32(mp->flags);
+			pdaddr = mp->pd_addr_start + i * pd_size;
+
+			memcpy_toio(smem + pdaddr, pd, pd_size);
+			queue = mp->queue;
+			regmap_write(miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue,
+				     pdaddr);
+		}
+	}
+}
+
+void icssg_config_ipg(struct prueth_priv *priv, int speed, int mii)
+{
+	struct prueth *prueth = priv->prueth;
+
+	switch (speed) {
+	case SPEED_1000:
+		icssg_mii_update_ipg(prueth->mii_rt, mii, MII_RT_TX_IPG_1G);
+		break;
+	case SPEED_100:
+		icssg_mii_update_ipg(prueth->mii_rt, mii, MII_RT_TX_IPG_100M);
+		break;
+	default:
+		/* Other links speeds not supported */
+		pr_err("Unsupported link speed\n");
+		return;
+	}
+}
+
+static void emac_r30_cmd_init(struct prueth_priv *priv)
+{
+	struct prueth *prueth = priv->prueth;
+	struct icssg_r30_cmd *p;
+	int i;
+
+	p = (struct icssg_r30_cmd *)(prueth->dram[priv->port_id].pa + MGR_R30_CMD_OFFSET);
+
+	for (i = 0; i < 4; i++)
+		writel(EMAC_NONE, &p->cmd[i]);
+}
+
+static int emac_r30_is_done(struct prueth_priv *priv)
+{
+	struct prueth *prueth = priv->prueth;
+	const struct icssg_r30_cmd *p;
+	int i;
+	u32 cmd;
+
+	p = (const struct icssg_r30_cmd *)(prueth->dram[priv->port_id].pa + MGR_R30_CMD_OFFSET);
+
+	for (i = 0; i < 4; i++) {
+		cmd = readl(&p->cmd[i]);
+		if (cmd != EMAC_NONE)
+			return 0;
+	}
+
+	return 1;
+}
+
+static int prueth_emac_buffer_setup(struct prueth_priv *priv)
+{
+	struct prueth *prueth = priv->prueth;
+	struct icssg_buffer_pool_cfg *bpool_cfg;
+	struct icssg_rxq_ctx *rxq_ctx;
+	int slice = priv->port_id;
+	u32 addr;
+	int i;
+
+	/* Layout to have 64KB aligned buffer pool
+	 * |BPOOL0|BPOOL1|RX_CTX0|RX_CTX1|
+	 */
+
+	addr = lower_32_bits(prueth->sram_pa);
+	if (slice)
+		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+
+	if (addr % SZ_64K) {
+		dev_warn(prueth->dev, "buffer pool needs to be 64KB aligned\n");
+		return -EINVAL;
+	}
+
+	bpool_cfg = (struct icssg_buffer_pool_cfg *)(prueth->dram[priv->port_id].pa + BUFFER_POOL_0_ADDR_OFFSET);
+	/* workaround for f/w bug. bpool 0 needs to be initilalized */
+	bpool_cfg[0].addr = cpu_to_le32(addr);
+	bpool_cfg[0].len = 0;
+
+	for (i = PRUETH_EMAC_BUF_POOL_START;
+	     i < (PRUETH_EMAC_BUF_POOL_START + PRUETH_NUM_BUF_POOLS);
+	     i++) {
+		bpool_cfg[i].addr = cpu_to_le32(addr);
+		bpool_cfg[i].len = cpu_to_le32(PRUETH_EMAC_BUF_POOL_SIZE);
+		addr += PRUETH_EMAC_BUF_POOL_SIZE;
+	}
+
+	if (!slice)
+		addr += PRUETH_NUM_BUF_POOLS * PRUETH_EMAC_BUF_POOL_SIZE;
+	else
+		addr += PRUETH_EMAC_RX_CTX_BUF_SIZE * 2;
+
+	rxq_ctx = (struct icssg_rxq_ctx *)(prueth->dram[priv->port_id].pa + HOST_RX_Q_PRE_CONTEXT_OFFSET);
+
+	for (i = 0; i < 3; i++)
+		rxq_ctx->start[i] = cpu_to_le32(addr);
+
+	addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+	rxq_ctx->end = cpu_to_le32(addr);
+
+	/* Express RX buffer queue */
+	rxq_ctx = (struct icssg_rxq_ctx *)(prueth->dram[priv->port_id].pa + HOST_RX_Q_EXP_CONTEXT_OFFSET);
+	for (i = 0; i < 3; i++)
+		rxq_ctx->start[i] = cpu_to_le32(addr);
+
+	addr += PRUETH_EMAC_RX_CTX_BUF_SIZE;
+	rxq_ctx->end = cpu_to_le32(addr);
+
+	return 0;
+}
+
+static void icssg_init_emac_mode(struct prueth *prueth)
+{
+	u8 mac[6] = { 0 };
+
+	regmap_update_bits(prueth->miig_rt, FDB_GEN_CFG1, SMEM_VLAN_OFFSET_MASK, 0);
+	regmap_write(prueth->miig_rt, FDB_GEN_CFG2, 0);
+	/* Clear host MAC address */
+	icssg_class_set_host_mac_addr(prueth->miig_rt, mac);
+}
+
+int icssg_config(struct prueth_priv *priv)
+{
+	struct prueth *prueth = priv->prueth;
+	void *config = (void *)(prueth->dram[priv->port_id].pa + ICSSG_CONFIG_OFFSET);
+	u8 *cfg_byte_ptr = config;
+	struct icssg_flow_cfg *flow_cfg;
+	u32 mask;
+	int ret;
+
+	int slice = priv->port_id;
+
+	icssg_init_emac_mode(prueth);
+
+	memset_io(config, 0, TAS_GATE_MASK_LIST0);
+	icssg_miig_queues_init(priv, slice);
+
+	prueth->speed = SPEED_1000;
+	prueth->duplex = DUPLEX_FULL;
+	if (!phy_interface_is_rgmii(priv->phydev)) {
+		prueth->speed = SPEED_100;
+		prueth->duplex = DUPLEX_FULL;
+	}
+
+	regmap_update_bits(prueth->miig_rt, ICSSG_CFG_OFFSET,
+			   ICSSG_CFG_DEFAULT, ICSSG_CFG_DEFAULT);
+	icssg_miig_set_interface_mode(prueth->miig_rt, ICSS_MII0, prueth->phy_interface);
+	icssg_miig_set_interface_mode(prueth->miig_rt, ICSS_MII1, prueth->phy_interface);
+	icssg_config_mii_init(priv, slice);
+
+	icssg_config_ipg(priv, SPEED_1000, slice);
+	icssg_update_rgmii_cfg(prueth->miig_rt, SPEED_1000, true, slice, priv);
+
+	/* set GPI mode */
+	pruss_cfg_gpimode(prueth->pruss, slice, PRUSS_GPI_MODE_MII);
+
+	/* enable XFR shift for PRU and RTU */
+	mask = PRUSS_SPP_XFER_SHIFT_EN | PRUSS_SPP_RTU_XFR_SHIFT_EN;
+	pruss_cfg_update(prueth->pruss, PRUSS_CFG_SPP, mask, mask);
+
+	flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
+	flow_cfg->rx_base_flow = prueth->dma_rx.id;
+	flow_cfg->mgm_base_flow = 0;
+	*(cfg_byte_ptr + SPL_PKT_DEFAULT_PRIORITY) = 0;
+	*(cfg_byte_ptr + QUEUE_NUM_UNTAGGED) = 0x0;
+
+	ret = prueth_emac_buffer_setup(priv);
+
+	if (ret)
+		return ret;
+
+	emac_r30_cmd_init(priv);
+	return 0;
+}
+
+/* commands to program ICSSG R30 registers */
+static struct icssg_r30_cmd emac_r32_bitmask[] = {
+	{{0xffff0004, 0xffff0100, 0xffff0004, EMAC_NONE}},	/* EMAC_PORT_DISABLE */
+	{{0xfffb0040, 0xfeff0200, 0xfeff0200, EMAC_NONE}},	/* EMAC_PORT_BLOCK */
+	{{0xffbb0000, 0xfcff0000, 0xdcfb0000, EMAC_NONE}},	/* EMAC_PORT_FORWARD */
+	{{0xffbb0000, 0xfcff0000, 0xfcff2000, EMAC_NONE}},	/* EMAC_PORT_FORWARD_WO_LEARNING */
+	{{0xffff0001, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT ALL */
+	{{0xfffe0002, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT TAGGED */
+	{{0xfffc0000, EMAC_NONE,  EMAC_NONE, EMAC_NONE}},	/* ACCEPT UNTAGGED and PRIO */
+	{{EMAC_NONE,  0xffff0020, EMAC_NONE, EMAC_NONE}},	/* TAS Trigger List change */
+	{{EMAC_NONE,  0xdfff1000, EMAC_NONE, EMAC_NONE}},	/* TAS set state ENABLE*/
+	{{EMAC_NONE,  0xefff2000, EMAC_NONE, EMAC_NONE}},	/* TAS set state RESET*/
+	{{EMAC_NONE,  0xcfff0000, EMAC_NONE, EMAC_NONE}},	/* TAS set state DISABLE*/
+	{{EMAC_NONE,  EMAC_NONE,  0xffff0400, EMAC_NONE}},	/* UC flooding ENABLE*/
+	{{EMAC_NONE,  EMAC_NONE,  0xfbff0000, EMAC_NONE}},	/* UC flooding DISABLE*/
+	{{EMAC_NONE,  EMAC_NONE,  0xffff0800, EMAC_NONE}},	/* MC flooding ENABLE*/
+	{{EMAC_NONE,  EMAC_NONE,  0xf7ff0000, EMAC_NONE}},	/* MC flooding DISABLE*/
+	{{EMAC_NONE,  0xffff4000, EMAC_NONE, EMAC_NONE}},	/* Preemption on Tx ENABLE*/
+	{{EMAC_NONE,  0xbfff0000, EMAC_NONE, EMAC_NONE}}	/* Preemption on Tx DISABLE*/
+};
+
+int emac_set_port_state(struct prueth_priv *priv,
+			enum icssg_port_state_cmd cmd)
+{
+	struct prueth *prueth = priv->prueth;
+	struct icssg_r30_cmd *p;
+	int ret = -ETIMEDOUT;
+	int timeout = 10;
+	int i;
+
+	p = (struct icssg_r30_cmd *)(prueth->dram[priv->port_id].pa + MGR_R30_CMD_OFFSET);
+
+	if (cmd >= ICSSG_EMAC_PORT_MAX_COMMANDS) {
+		dev_err(prueth->dev, "invalid port command\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 4; i++)
+		writel(emac_r32_bitmask[cmd].cmd[i], &p->cmd[i]);
+
+	/* wait for done */
+	while (timeout) {
+		if (emac_r30_is_done(priv)) {
+			ret = 0;
+			break;
+		}
+
+		udelay(2000);
+		timeout--;
+	}
+
+	if (ret == -ETIMEDOUT)
+		dev_err(prueth->dev, "timeout waiting for command done\n");
+
+	return ret;
+}
+
+int icssg_send_fdb_msg(struct prueth_priv *priv, struct mgmt_cmd *cmd,
+		       struct mgmt_cmd_rsp *rsp)
+{
+	struct prueth *prueth = priv->prueth;
+	int slice = priv->port_id;
+	int ret, addr;
+
+	addr = icssg_queue_pop(prueth, slice == 0 ?
+			       ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1);
+	if (addr < 0)
+		return addr;
+
+	/* First 4 bytes have FW owned buffer linking info which should
+	 * not be touched
+	 */
+	memcpy_toio((void __iomem *)prueth->shram.pa + addr + 4, cmd, sizeof(*cmd));
+	icssg_queue_push(prueth, slice == 0 ?
+			 ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr);
+	ret = read_poll_timeout(icssg_queue_pop, addr, addr >= 0,
+				2000, 20000000, prueth, slice == 0 ?
+				ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1);
+
+	if (ret) {
+		dev_err(prueth->dev, "Timedout sending HWQ message\n");
+		return ret;
+	}
+
+	memcpy_fromio(rsp, (void __iomem *)prueth->shram.pa + addr, sizeof(*rsp));
+	/* Return buffer back for to pool */
+	icssg_queue_push(prueth, slice == 0 ?
+			 ICSSG_RSP_PUSH_SLICE0 : ICSSG_RSP_PUSH_SLICE1, addr);
+
+	return 0;
+}
+
+int emac_fdb_flow_id_updated(struct prueth_priv *priv)
+{
+	struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 };
+	struct prueth *prueth = priv->prueth;
+	struct mgmt_cmd fdb_cmd = { 0 };
+	int slice = priv->port_id;
+	int ret = 0;
+
+	fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER;
+	fdb_cmd.type   = ICSSG_FW_MGMT_FDB_CMD_TYPE_RX_FLOW;
+	fdb_cmd.seqnum = ++(prueth->icssg_hwcmdseq);
+	fdb_cmd.param  = 0;
+
+	fdb_cmd.param |= (slice << 4);
+	fdb_cmd.cmd_args[0] = 0;
+
+	ret = icssg_send_fdb_msg(priv, &fdb_cmd, &fdb_cmd_rsp);
+	if (ret)
+		return ret;
+
+	if (fdb_cmd.seqnum != fdb_cmd_rsp.seqnum) {
+		dev_err(prueth->dev, "seqnum doesn't match, cmd.seqnum %d != rsp.seqnum %d\n",
+			fdb_cmd.seqnum, fdb_cmd_rsp.seqnum);
+		return -EINVAL;
+	}
+
+	if (fdb_cmd_rsp.status == 1)
+		return 0;
+
+	return -EINVAL;
+}
diff --git a/drivers/net/ti/icssg_config.h b/drivers/net/ti/icssg_config.h
new file mode 100644
index 0000000..d388484
--- /dev/null
+++ b/drivers/net/ti/icssg_config.h
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_CONFIG_H
+#define __NET_TI_ICSSG_CONFIG_H
+
+struct icssg_buffer_pool_cfg {
+	__le32  addr;
+	__le32  len;
+} __packed;
+
+struct icssg_flow_cfg {
+	__le16 rx_base_flow;
+	__le16 mgm_base_flow;
+} __packed;
+
+/* Config area lies in shared RAM */
+#define ICSSG_CONFIG_OFFSET_SLICE0   0
+#define ICSSG_CONFIG_OFFSET_SLICE1   0x8000
+
+/* pstate speed/duplex command to set speed and duplex settings
+ * in firmware.
+ * Command format : 0x8102ssPN. ss - sequence number: currently not
+ * used by driver, P - port number: For switch, N - Speed/Duplex state
+ * - Possible values of N:
+ * 0x0 - 10Mbps/Half duplex ;
+ * 0x8 - 10Mbps/Full duplex ;
+ * 0x2 - 100Mbps/Half duplex;
+ * 0xa - 100Mbps/Full duplex;
+ * 0xc - 1Gbps/Full duplex;
+ * NOTE: The above are same as bits [3..1](slice 0) or bits [8..6](slice 1) of
+ * RGMII CFG register. So suggested to read the register to populate the command
+ * bits.
+ */
+#define ICSSG_PSTATE_SPEED_DUPLEX_CMD	0x81020000
+#define ICSSG_PSTATE_FULL_DUPLEX	BIT(3)
+#define ICSSG_PSTATE_SPEED_100		BIT(1)
+#define ICSSG_PSTATE_SPEED_1000		BIT(2)
+
+/* Flow IDs used in config structure to firmware. Should match with
+ * flow_id in struct dma for rx channels.
+ */
+#define ICSSG_RX_CHAN_FLOW_ID		0 /* flow id for host port */
+#define ICSSG_RX_MGM_CHAN_FLOW_ID	1 /* flow id for command response */
+
+/* Used to notify the FW of the current link speed */
+#define PORT_LINK_SPEED_OFFSET			   0x00A8
+
+#define FW_LINK_SPEED_1G                           (0x00)
+#define FW_LINK_SPEED_100M                         (0x01)
+#define FW_LINK_SPEED_10M                          (0x02)
+#define FW_LINK_SPEED_HD                           (0x80)
+
+#define PRUETH_PKT_TYPE_CMD	0x10
+#define PRUETH_NAV_PS_DATA_SIZE	16	/* Protocol specific data size */
+#define PRUETH_NAV_SW_DATA_SIZE	16	/* SW related data size */
+#define PRUETH_MAX_RX_FLOWS	1	/* excluding default flow */
+#define PRUETH_RX_FLOW_DATA	0	/* FIXME: f/w bug to change to highest priority flow */
+
+#define PRUETH_EMAC_BUF_POOL_SIZE	SZ_8K
+#define PRUETH_EMAC_POOLS_PER_SLICE	24
+#define PRUETH_EMAC_BUF_POOL_START	8
+#define PRUETH_NUM_BUF_POOLS	8
+#define PRUETH_EMAC_RX_CTX_BUF_SIZE	SZ_16K	/* per slice */
+#define MSMC_RAM_SIZE	(2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \
+			      PRUETH_EMAC_RX_CTX_BUF_SIZE))
+
+struct icssg_rxq_ctx {
+	__le32 start[3];
+	__le32 end;
+} __packed;
+
+/* Load time Fiwmware Configuration */
+
+#define ICSSG_FW_MGMT_CMD_HEADER	0x81
+#define ICSSG_FW_MGMT_FDB_CMD_TYPE	0x03
+#define ICSSG_FW_MGMT_CMD_TYPE		0x04
+#define ICSSG_FW_MGMT_PKT		0x80000000
+#define ICSSG_FW_MGMT_FDB_CMD_TYPE_RX_FLOW	0x05
+
+struct icssg_r30_cmd {
+	u32 cmd[4];
+} __packed;
+
+enum icssg_port_state_cmd {
+	ICSSG_EMAC_PORT_DISABLE = 0,
+	ICSSG_EMAC_PORT_BLOCK,
+	ICSSG_EMAC_PORT_FORWARD,
+	ICSSG_EMAC_PORT_FORWARD_WO_LEARNING,
+	ICSSG_EMAC_PORT_ACCEPT_ALL,
+	ICSSG_EMAC_PORT_ACCEPT_TAGGED,
+	ICSSG_EMAC_PORT_ACCEPT_UNTAGGED_N_PRIO,
+	ICSSG_EMAC_PORT_TAS_TRIGGER,
+	ICSSG_EMAC_PORT_TAS_ENABLE,
+	ICSSG_EMAC_PORT_TAS_RESET,
+	ICSSG_EMAC_PORT_TAS_DISABLE,
+	ICSSG_EMAC_PORT_UC_FLOODING_ENABLE,
+	ICSSG_EMAC_PORT_UC_FLOODING_DISABLE,
+	ICSSG_EMAC_PORT_MC_FLOODING_ENABLE,
+	ICSSG_EMAC_PORT_MC_FLOODING_DISABLE,
+	ICSSG_EMAC_PORT_PREMPT_TX_ENABLE,
+	ICSSG_EMAC_PORT_PREMPT_TX_DISABLE,
+	ICSSG_EMAC_PORT_MAX_COMMANDS
+};
+
+#define EMAC_NONE           0xffff0000
+#define EMAC_PRU0_P_DI      0xffff0004
+#define EMAC_PRU1_P_DI      0xffff0040
+#define EMAC_TX_P_DI        0xffff0100
+
+#define EMAC_PRU0_P_EN      0xfffb0000
+#define EMAC_PRU1_P_EN      0xffbf0000
+#define EMAC_TX_P_EN        0xfeff0000
+
+#define EMAC_P_BLOCK        0xffff0040
+#define EMAC_TX_P_BLOCK     0xffff0200
+#define EMAC_P_UNBLOCK      0xffbf0000
+#define EMAC_TX_P_UNBLOCK   0xfdff0000
+#define EMAC_LEAN_EN        0xfff70000
+#define EMAC_LEAN_DI        0xffff0008
+
+#define EMAC_ACCEPT_ALL     0xffff0001
+#define EMAC_ACCEPT_TAG     0xfffe0002
+#define EMAC_ACCEPT_PRIOR   0xfffc0000
+
+/* Config area lies in DRAM */
+#define ICSSG_CONFIG_OFFSET			0x0
+
+#define ICSSG_NUM_NORMAL_PDS	64
+#define ICSSG_NUM_SPECIAL_PDS	16
+
+#define ICSSG_NORMAL_PD_SIZE	8
+#define ICSSG_SPECIAL_PD_SIZE	20
+
+#define ICSSG_FLAG_MASK		0xff00ffff
+
+struct icssg_setclock_desc {
+	u8 request;
+	u8 restore;
+	u8 acknowledgment;
+	u8 cmp_status;
+	u32 margin;
+	u32 cyclecounter0_set;
+	u32 cyclecounter1_set;
+	u32 iepcount_set;
+	u32 rsvd1;
+	u32 rsvd2;
+	u32 CMP0_current;
+	u32 iepcount_current;
+	u32 difference;
+	u32 cyclecounter0_new;
+	u32 cyclecounter1_new;
+	u32 CMP0_new;
+} __packed;
+
+struct mgmt_cmd {
+	u8 param;
+	u8 seqnum;
+	u8 type;
+	u8 header;
+	u32 cmd_args[3];
+} __packed;
+
+struct mgmt_cmd_rsp {
+	u32 reserved;
+	u8 status;
+	u8 seqnum;
+	u8 type;
+	u8 header;
+	u32 cmd_args[3];
+} __packed;
+
+#define ICSSG_CMD_POP_SLICE0	56
+#define ICSSG_CMD_POP_SLICE1	60
+
+#define ICSSG_CMD_PUSH_SLICE0	57
+#define ICSSG_CMD_PUSH_SLICE1	61
+
+#define ICSSG_RSP_POP_SLICE0	58
+#define ICSSG_RSP_POP_SLICE1	62
+
+#define ICSSG_RSP_PUSH_SLICE0	56
+#define ICSSG_RSP_PUSH_SLICE1	60
+
+#define ICSSG_TS_POP_SLICE0	59
+#define ICSSG_TS_POP_SLICE1	63
+
+#define ICSSG_TS_PUSH_SLICE0	40
+#define ICSSG_TS_PUSH_SLICE1	41
+
+#endif /* __NET_TI_ICSSG_CONFIG_H */
diff --git a/drivers/net/ti/icssg_prueth.c b/drivers/net/ti/icssg_prueth.c
new file mode 100644
index 0000000..2639f96
--- /dev/null
+++ b/drivers/net/ti/icssg_prueth.c
@@ -0,0 +1,691 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments K3 AM65 PRU Ethernet Driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <clk.h>
+#include <dm/lists.h>
+#include <dm/device.h>
+#include <dma-uclass.h>
+#include <dm/of_access.h>
+#include <dm/pinctrl.h>
+#include <fs_loader.h>
+#include <miiphy.h>
+#include <net.h>
+#include <phy.h>
+#include <power-domain.h>
+#include <linux/soc/ti/ti-udma.h>
+#include <regmap.h>
+#include <remoteproc.h>
+#include <syscon.h>
+#include <soc.h>
+#include <linux/pruss_driver.h>
+#include <dm/device_compat.h>
+
+#include "icssg_prueth.h"
+#include "icss_mii_rt.h"
+
+#define ICSS_SLICE0     0
+#define ICSS_SLICE1     1
+
+#ifdef PKTSIZE_ALIGN
+#define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN
+#else
+#define UDMA_RX_BUF_SIZE ALIGN(PKTSIZE, ARCH_DMA_MINALIGN)
+#endif
+
+#ifdef PKTBUFSRX
+#define UDMA_RX_DESC_NUM PKTBUFSRX
+#else
+#define UDMA_RX_DESC_NUM 4
+#endif
+
+/* Config region lies in shared RAM */
+#define ICSS_CONFIG_OFFSET_SLICE0	0
+#define ICSS_CONFIG_OFFSET_SLICE1	0x8000
+
+/* Firmware flags */
+#define ICSS_SET_RUN_FLAG_VLAN_ENABLE		BIT(0)	/* switch only */
+#define ICSS_SET_RUN_FLAG_FLOOD_UNICAST		BIT(1)	/* switch only */
+#define ICSS_SET_RUN_FLAG_PROMISC		BIT(2)	/* MAC only */
+#define ICSS_SET_RUN_FLAG_MULTICAST_PROMISC	BIT(3)	/* MAC only */
+
+/* CTRLMMR_ICSSG_RGMII_CTRL register bits */
+#define ICSSG_CTRL_RGMII_ID_MODE		BIT(24)
+
+/* Management packet type */
+#define PRUETH_PKT_TYPE_CMD		0x10
+
+/* Number of PRU Cores per Slice */
+#define ICSSG_NUM_PRU_CORES		3
+
+static int icssg_gmii_select(struct prueth_priv *priv)
+{
+	struct phy_device *phydev = priv->phydev;
+
+	if (phydev->interface != PHY_INTERFACE_MODE_MII &&
+	    phydev->interface < PHY_INTERFACE_MODE_RGMII &&
+	    phydev->interface > PHY_INTERFACE_MODE_RGMII_TXID) {
+		dev_err(priv->dev, "PHY mode unsupported %s\n",
+			phy_string_for_interface(phydev->interface));
+		return -EINVAL;
+	}
+
+	/* AM65 SR2.0 has TX Internal delay always enabled by hardware
+	 * and it is not possible to disable TX Internal delay. The below
+	 * switch case block describes how we handle different phy modes
+	 * based on hardware restriction.
+	 */
+	switch (phydev->interface) {
+	case PHY_INTERFACE_MODE_RGMII_ID:
+		phydev->interface = PHY_INTERFACE_MODE_RGMII_RXID;
+		break;
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		phydev->interface = PHY_INTERFACE_MODE_RGMII;
+		break;
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+		dev_err(priv->dev, "RGMII mode without TX delay is not supported");
+		return -EINVAL;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int icssg_phy_init(struct udevice *dev)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct phy_device *phydev;
+	u32 supported = PHY_GBIT_FEATURES;
+	int ret;
+
+	phydev = dm_eth_phy_connect(dev);
+	if (!phydev) {
+		dev_err(dev, "phy_connect() failed\n");
+		return -ENODEV;
+	}
+
+	/* disable unsupported features */
+	supported &= ~(PHY_10BT_FEATURES |
+			SUPPORTED_100baseT_Half |
+			SUPPORTED_1000baseT_Half |
+			SUPPORTED_Pause |
+			SUPPORTED_Asym_Pause);
+
+	phydev->supported &= supported;
+	phydev->advertising = phydev->supported;
+	priv->phydev = phydev;
+
+	ret = icssg_gmii_select(priv);
+	if (ret)
+		goto out;
+
+	ret = phy_config(phydev);
+	if (ret < 0)
+		dev_err(dev, "phy_config() failed: %d", ret);
+out:
+	return ret;
+}
+
+static void icssg_config_set_speed(struct prueth_priv *priv, int speed)
+{
+	struct prueth *prueth = priv->prueth;
+	u8 fw_speed;
+
+	switch (speed) {
+	case SPEED_1000:
+		fw_speed = FW_LINK_SPEED_1G;
+		break;
+	case SPEED_100:
+		fw_speed = FW_LINK_SPEED_100M;
+		break;
+	case SPEED_10:
+		fw_speed = FW_LINK_SPEED_10M;
+		break;
+	default:
+		/* Other links speeds not supported */
+		dev_err(priv->dev, "Unsupported link speed\n");
+		return;
+	}
+
+	writeb(fw_speed, prueth->dram[priv->port_id].pa + PORT_LINK_SPEED_OFFSET);
+}
+
+static int icssg_update_link(struct prueth_priv *priv)
+{
+	struct phy_device *phy = priv->phydev;
+	struct prueth *prueth = priv->prueth;
+	bool gig_en = false, full_duplex = false;
+
+	if (phy->link) { /* link up */
+		if (phy->speed == SPEED_1000)
+			gig_en = true;
+		if (phy->duplex == DUPLEX_FULL)
+			full_duplex = true;
+		/* Set the RGMII cfg for gig en and full duplex */
+		icssg_update_rgmii_cfg(prueth->miig_rt, phy->speed, full_duplex,
+				       priv->port_id, priv);
+		/* update the Tx IPG based on 100M/1G speed */
+		icssg_config_ipg(priv, phy->speed, priv->port_id);
+
+		/* Send command to firmware to update Speed setting */
+		icssg_config_set_speed(priv, phy->speed);
+
+		/* Enable PORT FORWARDING */
+		emac_set_port_state(priv, ICSSG_EMAC_PORT_FORWARD);
+
+		printf("link up on port %d, speed %d, %s duplex\n",
+		       priv->port_id, phy->speed,
+		       (phy->duplex == DUPLEX_FULL) ? "full" : "half");
+	} else {
+		emac_set_port_state(priv, ICSSG_EMAC_PORT_DISABLE);
+		printf("link down on port %d\n", priv->port_id);
+	}
+
+	return phy->link;
+}
+
+struct icssg_firmwares {
+	char *pru;
+	char *rtu;
+	char *txpru;
+};
+
+static struct icssg_firmwares icssg_emac_firmwares[] = {
+	{
+		.pru = "/lib/firmware/ti-pruss/am65x-sr2-pru0-prueth-fw.elf",
+		.rtu = "/lib/firmware/ti-pruss/am65x-sr2-rtu0-prueth-fw.elf",
+		.txpru = "/lib/firmware/ti-pruss/am65x-sr2-txpru0-prueth-fw.elf",
+	},
+	{
+		.pru = "/lib/firmware/ti-pruss/am65x-sr2-pru1-prueth-fw.elf",
+		.rtu = "/lib/firmware/ti-pruss/am65x-sr2-rtu1-prueth-fw.elf",
+		.txpru = "/lib/firmware/ti-pruss/am65x-sr2-txpru1-prueth-fw.elf",
+	}
+};
+
+static int icssg_start_pru_cores(struct udevice *dev)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct prueth *prueth = priv->prueth;
+	struct icssg_firmwares *firmwares;
+	struct udevice *rproc_dev = NULL;
+	int ret, slice;
+	u32 phandle;
+	u8 index;
+
+	slice = priv->port_id;
+	index = slice * ICSSG_NUM_PRU_CORES;
+	firmwares = icssg_emac_firmwares;
+
+	ofnode_read_u32_index(dev_ofnode(prueth->dev), "ti,prus", index, &phandle);
+	ret = uclass_get_device_by_phandle_id(UCLASS_REMOTEPROC, phandle, &rproc_dev);
+	if (ret) {
+		dev_err(dev, "Unknown remote processor with phandle '0x%x' requested(%d)\n",
+			phandle, ret);
+		return ret;
+	}
+
+	prueth->pru_core_id = dev_seq(rproc_dev);
+	ret = rproc_set_firmware(rproc_dev, firmwares[slice].pru);
+	if (ret)
+		return ret;
+
+	ret = rproc_boot(rproc_dev);
+	if (ret) {
+		dev_err(dev, "failed to boot PRU%d: %d\n", slice, ret);
+		return -EINVAL;
+	}
+
+	ofnode_read_u32_index(dev_ofnode(prueth->dev), "ti,prus", index + 1, &phandle);
+	ret = uclass_get_device_by_phandle_id(UCLASS_REMOTEPROC, phandle, &rproc_dev);
+	if (ret) {
+		dev_err(dev, "Unknown remote processor with phandle '0x%x' requested(%d)\n",
+			phandle, ret);
+		goto halt_pru;
+	}
+
+	prueth->rtu_core_id = dev_seq(rproc_dev);
+	ret = rproc_set_firmware(rproc_dev, firmwares[slice].rtu);
+	if (ret)
+		goto halt_pru;
+
+	ret = rproc_boot(rproc_dev);
+	if (ret) {
+		dev_err(dev, "failed to boot RTU%d: %d\n", slice, ret);
+		goto halt_pru;
+	}
+
+	ofnode_read_u32_index(dev_ofnode(prueth->dev), "ti,prus", index + 2, &phandle);
+	ret = uclass_get_device_by_phandle_id(UCLASS_REMOTEPROC, phandle, &rproc_dev);
+	if (ret) {
+		dev_err(dev, "Unknown remote processor with phandle '0x%x' requested(%d)\n",
+			phandle, ret);
+		goto halt_rtu;
+	}
+
+	prueth->txpru_core_id = dev_seq(rproc_dev);
+	ret = rproc_set_firmware(rproc_dev, firmwares[slice].txpru);
+	if (ret)
+		goto halt_rtu;
+
+	ret = rproc_boot(rproc_dev);
+	if (ret) {
+		dev_err(dev, "failed to boot TXPRU%d: %d\n", slice, ret);
+		goto halt_rtu;
+	}
+
+	return 0;
+
+halt_rtu:
+	rproc_stop(prueth->rtu_core_id);
+
+halt_pru:
+	rproc_stop(prueth->pru_core_id);
+	return ret;
+}
+
+static int icssg_stop_pru_cores(struct udevice *dev)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct prueth *prueth = priv->prueth;
+
+	rproc_stop(prueth->pru_core_id);
+	rproc_stop(prueth->rtu_core_id);
+	rproc_stop(prueth->txpru_core_id);
+
+	return 0;
+}
+
+static int prueth_start(struct udevice *dev)
+{
+	struct ti_udma_drv_chan_cfg_data *dma_rx_cfg_data;
+	struct eth_pdata *pdata = dev_get_plat(dev);
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct prueth *prueth = priv->prueth;
+	struct icssg_flow_cfg *flow_cfg;
+	u8 *hwaddr = pdata->enetaddr;
+	char chn_name[16];
+	void *config;
+	int ret, i;
+
+	icssg_class_set_mac_addr(prueth->miig_rt, priv->port_id, hwaddr);
+	icssg_ft1_set_mac_addr(prueth->miig_rt, priv->port_id, hwaddr);
+	icssg_class_default(prueth->miig_rt, priv->port_id, 0);
+
+	/* Set Load time configuration */
+	icssg_config(priv);
+
+	ret = icssg_start_pru_cores(dev);
+	if (ret)
+		return ret;
+
+	/* To differentiate channels for SLICE0 vs SLICE1 */
+	snprintf(chn_name, sizeof(chn_name), "tx%d-0", priv->port_id);
+
+	ret = dma_get_by_name(prueth->dev, chn_name, &prueth->dma_tx);
+	if (ret)
+		dev_err(dev, "TX dma get failed %d\n", ret);
+
+	snprintf(chn_name, sizeof(chn_name), "rx%d", priv->port_id);
+	ret = dma_get_by_name(prueth->dev, chn_name, &prueth->dma_rx);
+	if (ret)
+		dev_err(dev, "RX dma get failed %d\n", ret);
+
+	for (i = 0; i < UDMA_RX_DESC_NUM; i++) {
+		ret = dma_prepare_rcv_buf(&prueth->dma_rx,
+					  net_rx_packets[i],
+					  UDMA_RX_BUF_SIZE);
+		if (ret)
+			dev_err(dev, "RX dma add buf failed %d\n", ret);
+	}
+
+	ret = dma_enable(&prueth->dma_tx);
+	if (ret) {
+		dev_err(dev, "TX dma_enable failed %d\n", ret);
+		goto tx_fail;
+	}
+
+	ret = dma_enable(&prueth->dma_rx);
+	if (ret) {
+		dev_err(dev, "RX dma_enable failed %d\n", ret);
+		goto rx_fail;
+	}
+
+	/* check if the rx_flow_id of dma_rx is as expected since
+	 * driver hardcode that value in config struct to firmware
+	 * in probe. Just add this sanity check to catch any change
+	 * to rx channel assignment in the future.
+	 */
+	dma_get_cfg(&prueth->dma_rx, 0, (void **)&dma_rx_cfg_data);
+	config = (void *)(prueth->dram[priv->port_id].pa + ICSSG_CONFIG_OFFSET);
+
+	flow_cfg = config + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
+	writew(dma_rx_cfg_data->flow_id_base, &flow_cfg->rx_base_flow);
+	writew(0, &flow_cfg->mgm_base_flow);
+
+	dev_info(dev, "K3 ICSSG: rflow_id_base: %u, chn_name = %s\n",
+		 dma_rx_cfg_data->flow_id_base, chn_name);
+
+	ret = emac_fdb_flow_id_updated(priv);
+	if (ret) {
+		dev_err(dev, "Failed to update Rx Flow ID %d", ret);
+		goto phy_fail;
+	}
+
+	ret = phy_startup(priv->phydev);
+	if (ret) {
+		dev_err(dev, "phy_startup failed\n");
+		goto phy_fail;
+	}
+
+	ret = icssg_update_link(priv);
+	if (!ret) {
+		ret = -ENODEV;
+		goto phy_shut;
+	}
+
+	return 0;
+
+phy_shut:
+	phy_shutdown(priv->phydev);
+phy_fail:
+	dma_disable(&prueth->dma_rx);
+	dma_free(&prueth->dma_rx);
+rx_fail:
+	dma_disable(&prueth->dma_tx);
+	dma_free(&prueth->dma_tx);
+
+tx_fail:
+	icssg_class_disable(prueth->miig_rt, priv->port_id);
+
+	return ret;
+}
+
+static int prueth_send(struct udevice *dev, void *packet, int length)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct prueth *prueth = priv->prueth;
+	int ret;
+
+	ret = dma_send(&prueth->dma_tx, packet, length, NULL);
+
+	return ret;
+}
+
+static int prueth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct prueth *prueth = priv->prueth;
+	int ret;
+
+	/* try to receive a new packet */
+	ret = dma_receive(&prueth->dma_rx, (void **)packetp, NULL);
+
+	return ret;
+}
+
+static int prueth_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct prueth *prueth = priv->prueth;
+	int ret = 0;
+
+	if (length > 0) {
+		u32 pkt = prueth->rx_next % UDMA_RX_DESC_NUM;
+
+		dev_dbg(dev, "%s length:%d pkt:%u\n", __func__, length, pkt);
+
+		ret = dma_prepare_rcv_buf(&prueth->dma_rx,
+					  net_rx_packets[pkt],
+					  UDMA_RX_BUF_SIZE);
+		prueth->rx_next++;
+	}
+
+	return ret;
+}
+
+static void prueth_stop(struct udevice *dev)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct prueth *prueth = priv->prueth;
+
+	phy_shutdown(priv->phydev);
+
+	dma_disable(&prueth->dma_tx);
+	dma_disable(&prueth->dma_rx);
+
+	icssg_stop_pru_cores(dev);
+
+	dma_free(&prueth->dma_tx);
+	dma_free(&prueth->dma_rx);
+}
+
+static const struct eth_ops prueth_ops = {
+	.start		= prueth_start,
+	.send		= prueth_send,
+	.recv		= prueth_recv,
+	.free_pkt	= prueth_free_pkt,
+	.stop		= prueth_stop,
+};
+
+static int icssg_ofdata_parse_phy(struct udevice *dev)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+
+	dev_read_u32(dev, "reg", &priv->port_id);
+	priv->phy_interface = dev_read_phy_mode(dev);
+	if (priv->phy_interface == PHY_INTERFACE_MODE_NA) {
+		dev_err(dev, "Invalid PHY mode '%s', port %u\n",
+			phy_string_for_interface(priv->phy_interface),
+			priv->port_id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int prueth_port_probe(struct udevice *dev)
+{
+	struct prueth_priv *priv = dev_get_priv(dev);
+	struct prueth *prueth;
+	char portname[15];
+	int ret;
+
+	priv->dev = dev;
+	prueth = dev_get_priv(dev->parent);
+	priv->prueth = prueth;
+
+	sprintf(portname, "%s-%s", dev->parent->name, dev->name);
+
+	device_set_name(dev, portname);
+
+	ret = icssg_ofdata_parse_phy(dev);
+	if (ret)
+		goto out;
+
+	ret = icssg_phy_init(dev);
+	if (ret)
+		goto out;
+
+	ret = pruss_request_mem_region(prueth->pruss,
+				       priv->port_id ? PRUSS_MEM_DRAM1 : PRUSS_MEM_DRAM0,
+				       &prueth->dram[priv->port_id]);
+	if (ret) {
+		dev_err(dev, "could not request DRAM%d region\n", priv->port_id);
+		return ret;
+	}
+out:
+	return ret;
+}
+
+static int prueth_probe(struct udevice *dev)
+{
+	ofnode node, pruss_node, mdio_node, sram_node, curr_sram_node;
+	struct prueth *prueth = dev_get_priv(dev);
+	u32 phandle, err, sp, prev_end_addr;
+	struct udevice **prussdev = NULL;
+	ofnode eth_ports_node, eth_node;
+	struct udevice *port_dev;
+	int ret = 0;
+
+	prueth->dev = dev;
+
+	err = ofnode_read_u32(dev_ofnode(dev), "ti,prus", &phandle);
+	if (err)
+		return err;
+
+	node = ofnode_get_by_phandle(phandle);
+	if (!ofnode_valid(node))
+		return -EINVAL;
+
+	pruss_node = ofnode_get_parent(node);
+	ret = device_get_global_by_ofnode(pruss_node, prussdev);
+	if (ret)
+		dev_err(dev, "error getting the pruss dev\n");
+	prueth->pruss = *prussdev;
+
+	ret = pruss_request_mem_region(*prussdev, PRUSS_MEM_SHRD_RAM2,
+				       &prueth->shram);
+	if (ret)
+		return ret;
+
+	ret = pruss_request_tm_region(*prussdev, &prueth->tmaddr);
+	if (ret)
+		return ret;
+
+	prueth->miig_rt = syscon_regmap_lookup_by_phandle(dev, "ti,mii-g-rt");
+	if (!prueth->miig_rt) {
+		dev_err(dev, "couldn't get mii-g-rt syscon regmap\n");
+		return -ENODEV;
+	}
+
+	prueth->mii_rt = syscon_regmap_lookup_by_phandle(dev, "ti,mii-rt");
+	if (!prueth->mii_rt) {
+		dev_err(dev, "couldn't get mii-rt syscon regmap\n");
+		return -ENODEV;
+	}
+
+	ret = ofnode_read_u32(dev_ofnode(dev), "sram", &sp);
+	if (ret) {
+		dev_err(dev, "sram node fetch failed %d\n", ret);
+		return ret;
+	}
+
+	sram_node = ofnode_get_by_phandle(sp);
+	if (!ofnode_valid(sram_node))
+		return -EINVAL;
+
+	prev_end_addr = ofnode_get_addr(sram_node);
+
+	ofnode_for_each_subnode(curr_sram_node, sram_node) {
+		u32 start_addr, size, end_addr, avail;
+		const char *name;
+
+		name = ofnode_get_name(curr_sram_node);
+		start_addr = ofnode_get_addr(curr_sram_node);
+		size = ofnode_get_size(curr_sram_node);
+		end_addr = start_addr + size;
+		avail = start_addr - prev_end_addr;
+
+		if (avail > MSMC_RAM_SIZE)
+			break;
+
+		prev_end_addr = end_addr;
+	}
+
+	prueth->sram_pa = prev_end_addr;
+	if (prueth->sram_pa % SZ_64K != 0) {
+		/* This is constraint for SR2.0 firmware */
+		dev_err(dev, "sram address needs to be 64KB aligned\n");
+		return -EINVAL;
+	}
+	dev_dbg(dev, "sram: addr %x size %x\n", prueth->sram_pa, MSMC_RAM_SIZE);
+
+	mdio_node = ofnode_find_subnode(pruss_node, "mdio");
+	prueth->mdio_base = ofnode_get_addr(mdio_node);
+	ofnode_read_u32(mdio_node, "bus_freq", &prueth->mdio_freq);
+
+	ret = clk_get_by_name_nodev(mdio_node, "fck", &prueth->mdiofck);
+	if (ret) {
+		dev_err(dev, "failed to get clock %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_enable(&prueth->mdiofck);
+	if (ret) {
+		dev_err(dev, "clk_enable failed %d\n", ret);
+		return ret;
+	}
+
+	eth_ports_node = dev_read_subnode(dev, "ethernet-ports");
+	if (!ofnode_valid(eth_ports_node))
+		return -ENOENT;
+
+	ofnode_for_each_subnode(eth_node, eth_ports_node) {
+		const char *node_name;
+		u32 port_id;
+		bool disabled;
+
+		node_name = ofnode_get_name(eth_node);
+		disabled = !ofnode_is_enabled(eth_node);
+		ret = ofnode_read_u32(eth_node, "reg", &port_id);
+		if (ret)
+			dev_err(dev, "%s: error reading port_id (%d)\n", node_name, ret);
+
+		if (port_id >= PRUETH_NUM_MACS) {
+			dev_err(dev, "%s: invalid port_id (%d)\n", node_name, port_id);
+			return -EINVAL;
+		}
+
+		if (port_id < 0)
+			continue;
+		if (disabled)
+			continue;
+
+		ret = device_bind_driver_to_node(dev, "prueth_port",
+						 ofnode_get_name(eth_node),
+						 eth_node, &port_dev);
+		if (ret) {
+			dev_err(dev, "Failed to bind to %s node\n", ofnode_get_name(eth_node));
+			goto out;
+		}
+	}
+
+	return 0;
+out:
+	clk_disable(&prueth->mdiofck);
+
+	return ret;
+}
+
+static const struct udevice_id prueth_ids[] = {
+	{ .compatible = "ti,am654-icssg-prueth" },
+	{ .compatible = "ti,am642-icssg-prueth" },
+	{ }
+};
+
+U_BOOT_DRIVER(prueth) = {
+	.name	= "prueth",
+	.id	= UCLASS_MISC,
+	.of_match = prueth_ids,
+	.probe	= prueth_probe,
+	.priv_auto = sizeof(struct prueth),
+};
+
+U_BOOT_DRIVER(prueth_port) = {
+	.name	= "prueth_port",
+	.id	= UCLASS_ETH,
+	.probe	= prueth_port_probe,
+	.ops	= &prueth_ops,
+	.priv_auto = sizeof(struct prueth_priv),
+	.plat_auto = sizeof(struct eth_pdata),
+	.flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/net/ti/icssg_prueth.h b/drivers/net/ti/icssg_prueth.h
new file mode 100644
index 0000000..c69cfd4
--- /dev/null
+++ b/drivers/net/ti/icssg_prueth.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_PRUETH_H
+#define __NET_TI_ICSSG_PRUETH_H
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm/lists.h>
+#include <dm/ofnode.h>
+#include <dm/device.h>
+#include <dma-uclass.h>
+#include <regmap.h>
+#include <linux/sizes.h>
+#include <linux/pruss_driver.h>
+#include "icssg_config.h"
+#include "icssg_switch_map.h"
+
+void icssg_class_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac);
+void icssg_class_set_host_mac_addr(struct regmap *miig_rt, u8 *mac);
+void icssg_class_disable(struct regmap *miig_rt, int slice);
+void icssg_class_default(struct regmap *miig_rt, int slice, bool allmulti);
+void icssg_ft1_set_mac_addr(struct regmap *miig_rt, int slice, u8 *mac_addr);
+
+enum prueth_mac {
+	PRUETH_MAC0 = 0,
+	PRUETH_MAC1,
+	PRUETH_NUM_MACS,
+};
+
+enum prueth_port {
+	PRUETH_PORT_HOST = 0,	/* host side port */
+	PRUETH_PORT_MII0,	/* physical port MII 0 */
+	PRUETH_PORT_MII1,	/* physical port MII 1 */
+};
+
+struct prueth {
+	struct udevice		*dev;
+	struct udevice		*pruss;
+	struct regmap		*miig_rt;
+	struct regmap		*mii_rt;
+	fdt_addr_t		mdio_base;
+	struct pruss_mem_region shram;
+	struct pruss_mem_region dram[PRUETH_NUM_MACS];
+	phys_addr_t		tmaddr;
+	struct mii_dev		*bus;
+	u32			sram_pa;
+	ofnode			eth_node[PRUETH_NUM_MACS];
+	u32			mdio_freq;
+	int			phy_interface;
+	struct			clk mdiofck;
+	struct dma		dma_tx;
+	struct dma		dma_rx;
+	struct dma		dma_rx_mgm;
+	u32			rx_next;
+	u32			rx_pend;
+	int			slice;
+	bool			mdio_manual_mode;
+	int			speed;
+	int			duplex;
+	u8			pru_core_id;
+	u8			rtu_core_id;
+	u8			txpru_core_id;
+	u8			icssg_hwcmdseq;
+};
+
+struct prueth_priv {
+	struct udevice		*dev;
+	struct prueth		*prueth;
+	u32			port_id;
+	struct phy_device	*phydev;
+	bool			has_phy;
+	ofnode			phy_node;
+	u32			phy_addr;
+	int			phy_interface;
+};
+
+/* config helpers */
+void icssg_config_ipg(struct prueth_priv *priv, int speed, int mii);
+int icssg_config(struct prueth_priv *priv);
+int emac_set_port_state(struct prueth_priv *priv, enum icssg_port_state_cmd cmd);
+
+/* Buffer queue helpers */
+int icssg_queue_pop(struct prueth *prueth, u8 queue);
+void icssg_queue_push(struct prueth *prueth, int queue, u16 addr);
+u32 icssg_queue_level(struct prueth *prueth, int queue);
+
+/* FDB helpers */
+int icssg_send_fdb_msg(struct prueth_priv *priv, struct mgmt_cmd *cmd,
+		       struct mgmt_cmd_rsp *rsp);
+int emac_fdb_flow_id_updated(struct prueth_priv *priv);
+
+#endif /* __NET_TI_ICSSG_PRUETH_H */
diff --git a/drivers/net/ti/icssg_queues.c b/drivers/net/ti/icssg_queues.c
new file mode 100644
index 0000000..fc4d33d
--- /dev/null
+++ b/drivers/net/ti/icssg_queues.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ICSSG Buffer queue helpers
+ *
+ * Copyright (C) 2018-2024 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <dm/ofnode.h>
+#include <regmap.h>
+#include "icssg_prueth.h"
+
+#define ICSSG_QUEUES_MAX		64
+#define ICSSG_QUEUE_OFFSET		0xd00
+#define ICSSG_QUEUE_PEEK_OFFSET		0xe00
+#define ICSSG_QUEUE_CNT_OFFSET		0xe40
+#define	ICSSG_QUEUE_RESET_OFFSET	0xf40
+
+int icssg_queue_pop(struct prueth *prueth, u8 queue)
+{
+	u32 val, cnt;
+
+	if (queue >= ICSSG_QUEUES_MAX)
+		return -EINVAL;
+
+	regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4 * queue, &cnt);
+	if (!cnt)
+		return -EINVAL;
+
+	regmap_read(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, &val);
+
+	return val;
+}
+
+void icssg_queue_push(struct prueth *prueth, int queue, u16 addr)
+{
+	if (queue >= ICSSG_QUEUES_MAX)
+		return;
+
+	regmap_write(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, addr);
+}
+
+u32 icssg_queue_level(struct prueth *prueth, int queue)
+{
+	u32 reg;
+
+	if (queue >= ICSSG_QUEUES_MAX)
+		return 0;
+
+	regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4 * queue, &reg);
+
+	return reg;
+}
diff --git a/drivers/net/ti/icssg_switch_map.h b/drivers/net/ti/icssg_switch_map.h
new file mode 100644
index 0000000..b62c514
--- /dev/null
+++ b/drivers/net/ti/icssg_switch_map.h
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Texas Instruments ICSSG Ethernet driver
+ *
+ * Copyright (C) 2020-2024 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ */
+
+#ifndef __NET_TI_ICSSG_SWITCH_MAP_H
+#define __NET_TI_ICSSG_SWITCH_MAP_H
+
+/*Time after which FDB entries are checked for aged out values. Value in nanoseconds*/
+#define FDB_AGEING_TIMEOUT_OFFSET                          0x0014
+
+/*default VLAN tag for Host Port*/
+#define HOST_PORT_DF_VLAN_OFFSET                           0x001C
+
+/*Same as HOST_PORT_DF_VLAN_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET        HOST_PORT_DF_VLAN_OFFSET
+
+/*default VLAN tag for P1 Port*/
+#define P1_PORT_DF_VLAN_OFFSET                             0x0020
+
+/*Same as P1_PORT_DF_VLAN_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET        P1_PORT_DF_VLAN_OFFSET
+
+/*default VLAN tag for P2 Port*/
+#define P2_PORT_DF_VLAN_OFFSET                             0x0024
+
+/*Same as P2_PORT_DF_VLAN_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET        P2_PORT_DF_VLAN_OFFSET
+
+/*VLAN-FID Table offset. 4096 VIDs. 2B per VID = 8KB = 0x2000*/
+#define VLAN_STATIC_REG_TABLE_OFFSET                       0x0100
+
+/*VLAN-FID Table offset for EMAC*/
+#define EMAC_ICSSG_SWITCH_DEFAULT_VLAN_TABLE_OFFSET        VLAN_STATIC_REG_TABLE_OFFSET
+
+/*packet descriptor Q reserved memory*/
+#define PORT_DESC0_HI                                      0x2104
+
+/*packet descriptor Q reserved memory*/
+#define PORT_DESC0_LO                                      0x2F6C
+
+/*packet descriptor Q reserved memory*/
+#define PORT_DESC1_HI                                      0x3DD4
+
+/*packet descriptor Q reserved memory*/
+#define PORT_DESC1_LO                                      0x4C3C
+
+/*packet descriptor Q reserved memory*/
+#define HOST_DESC0_HI                                      0x5AA4
+
+/*packet descriptor Q reserved memory*/
+#define HOST_DESC0_LO                                      0x5F0C
+
+/*packet descriptor Q reserved memory*/
+#define HOST_DESC1_HI                                      0x6374
+
+/*packet descriptor Q reserved memory*/
+#define HOST_DESC1_LO                                      0x67DC
+
+/*special packet descriptor Q reserved memory*/
+#define HOST_SPPD0                                         0x7AAC
+
+/*special packet descriptor Q reserved memory*/
+#define HOST_SPPD1                                         0x7EAC
+
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_CYCLECOUNT_OFFSET                   0x83EC
+
+/*IEP count hi roll over count*/
+#define TIMESYNC_FW_WC_HI_ROLLOVER_COUNT_OFFSET            0x83F4
+
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_COUNT_HI_SW_OFFSET_OFFSET           0x83F8
+
+/*Set clock descriptor*/
+#define TIMESYNC_FW_WC_SETCLOCK_DESC_OFFSET                0x83FC
+
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_SYNCOUT_REDUCTION_FACTOR_OFFSET     0x843C
+
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_SYNCOUT_REDUCTION_COUNT_OFFSET      0x8440
+
+/*_Small_Description_*/
+#define TIMESYNC_FW_WC_SYNCOUT_START_TIME_CYCLECOUNT_OFFSET 0x8444
+
+/*Control variable to generate SYNC1*/
+#define TIMESYNC_FW_WC_ISOM_PIN_SIGNAL_EN_OFFSET           0x844C
+
+/*SystemTime Sync0 periodicity*/
+#define TIMESYNC_FW_ST_SYNCOUT_PERIOD_OFFSET               0x8450
+
+/*pktTxDelay for P1 = link speed dependent p1 mac delay + p1 phy delay*/
+#define TIMESYNC_FW_WC_PKTTXDELAY_P1_OFFSET                0x8454
+
+/*pktTxDelay for P2 = link speed dependent p2 mac delay + p2 phy delay*/
+#define TIMESYNC_FW_WC_PKTTXDELAY_P2_OFFSET                0x8458
+
+/*Set clock operation done signal for next task*/
+#define TIMESYNC_FW_SIG_PNFW_OFFSET                        0x845C
+
+/*Set clock operation done signal for next task*/
+#define TIMESYNC_FW_SIG_TIMESYNCFW_OFFSET                  0x8460
+
+/*New list is copied at this time*/
+#define TAS_CONFIG_CHANGE_TIME                             0x000C
+
+/*config change error counter*/
+#define TAS_CONFIG_CHANGE_ERROR_COUNTER                    0x0014
+
+/*TAS List update pending flag*/
+#define TAS_CONFIG_PENDING                                 0x0018
+
+/*TAS list update trigger flag*/
+#define TAS_CONFIG_CHANGE                                  0x0019
+
+/*List length for new TAS schedule*/
+#define TAS_ADMIN_LIST_LENGTH                              0x001A
+
+/*Currently active TAS list index*/
+#define TAS_ACTIVE_LIST_INDEX                              0x001B
+
+/*Cycle time for the new TAS schedule*/
+#define TAS_ADMIN_CYCLE_TIME                               0x001C
+
+/*Cycle counts remaining till the TAS list update*/
+#define TAS_CONFIG_CHANGE_CYCLE_COUNT                      0x0020
+
+/*Base Flow ID for sending packets to Host for Slice0*/
+#define PSI_L_REGULAR_FLOW_ID_BASE_OFFSET                  0x0024
+
+/*Same as PSI_L_REGULAR_FLOW_ID_BASE_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PSI_L_REGULAR_FLOW_ID_BASE_OFFSET PSI_L_REGULAR_FLOW_ID_BASE_OFFSET
+
+/*Base Flow ID for sending mgmt and Tx TS to Host for Slice0*/
+#define PSI_L_MGMT_FLOW_ID_OFFSET                          0x0026
+
+/*Same as PSI_L_MGMT_FLOW_ID_OFFSET*/
+#define EMAC_ICSSG_SWITCH_PSI_L_MGMT_FLOW_ID_BASE_OFFSET   PSI_L_MGMT_FLOW_ID_OFFSET
+
+/*Queue number for Special packets written here*/
+#define SPL_PKT_DEFAULT_PRIORITY                           0x0028
+
+/*Express Preemptible Queue Mask*/
+#define EXPRESS_PRE_EMPTIVE_Q_MASK                         0x0029
+
+/*Port1/Port2 Default Queue number for untagged packets, only 1B is used*/
+#define QUEUE_NUM_UNTAGGED                                 0x002A
+
+/*Stores the table used for priority regeneration. 1B per PCP/Queue*/
+#define PORT_Q_PRIORITY_REGEN_OFFSET                       0x002C
+
+/* For marking Packet as priority/express (this feature is disabled) or
+ * cut-through/S&F.
+ */
+#define EXPRESS_PRE_EMPTIVE_Q_MAP                          0x0034
+
+/*Stores the table used for priority mapping. 1B per PCP/Queue*/
+#define PORT_Q_PRIORITY_MAPPING_OFFSET                     0x003C
+
+/*TAS gate mask for windows list0*/
+#define TAS_GATE_MASK_LIST0                                0x0100
+
+/*TAS gate mask for windows list1*/
+#define TAS_GATE_MASK_LIST1                                0x0350
+
+/*Memory to Enable/Disable Preemption on TX side*/
+#define PRE_EMPTION_ENABLE_TX                              0x05A0
+
+/*Active State of Preemption on TX side*/
+#define PRE_EMPTION_ACTIVE_TX                              0x05A1
+
+/*Memory to Enable/Disable Verify State Machine Preemption*/
+#define PRE_EMPTION_ENABLE_VERIFY                          0x05A2
+
+/*Verify Status of State Machine*/
+#define PRE_EMPTION_VERIFY_STATUS                          0x05A3
+
+/*Non Final Fragment Size supported by Link Partner*/
+#define PRE_EMPTION_ADD_FRAG_SIZE_REMOTE                   0x05A4
+
+/*Non Final Fragment Size supported by Firmware*/
+#define PRE_EMPTION_ADD_FRAG_SIZE_LOCAL                    0x05A6
+
+/*Time in ms the State machine waits for respond packet*/
+#define PRE_EMPTION_VERIFY_TIME                            0x05A8
+
+/*Memory used for R30 related management commands*/
+#define MGR_R30_CMD_OFFSET                                 0x05AC
+
+/*HW Buffer Pool0 base address*/
+#define BUFFER_POOL_0_ADDR_OFFSET                          0x05BC
+
+/*16B for Host Egress MSMC Q (Pre-emptible) context*/
+#define HOST_RX_Q_PRE_CONTEXT_OFFSET                       0x0684
+
+/*Buffer for 8 FDB entries to be added by 'Add Multiple FDB entries IOCTL*/
+#define FDB_CMD_BUFFER                                     0x0894
+
+/*16B for Host Egress MSMC Q (Express) context*/
+#define HOST_RX_Q_EXP_CONTEXT_OFFSET                       0x0940
+
+/*Start of 32 bits PA_STAT counters*/
+#define PA_STAT_32b_START_OFFSET                           0x0080
+
+#endif
+/* __NET_TI_ICSSG_SWITCH_MAP_H */
diff --git a/drivers/rtc/goldfish_rtc.c b/drivers/rtc/goldfish_rtc.c
index 1ace990..3231eb0 100644
--- a/drivers/rtc/goldfish_rtc.c
+++ b/drivers/rtc/goldfish_rtc.c
@@ -72,7 +72,7 @@
 	return 0;
 }
 
-int goldfish_rtc_probe(struct udevice *dev)
+static int goldfish_rtc_probe(struct udevice *dev)
 {
 	struct goldfish_rtc *priv = dev_get_priv(dev);
 	fdt_addr_t addr;
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index ce08a6b..3f2be72 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -109,28 +109,35 @@
 }
 
 #if CONFIG_IS_ENABLED(CLK)
-static int get_lpuart_clk_rate(struct udevice *dev, u32 *clk)
+static int get_lpuart_clk_rate(struct udevice *dev, u32 *clk_rate)
 {
-	struct clk per_clk;
+	struct lpuart_serial_plat *plat = dev_get_plat(dev);
+	struct clk clk;
 	ulong rate;
 	int ret;
+	char *name;
 
-	ret = clk_get_by_name(dev, "per", &per_clk);
+	if (plat->devtype == DEV_MX7ULP)
+		name = "ipg";
+	else
+		name = "per";
+
+	ret = clk_get_by_name(dev, name, &clk);
 	if (ret) {
-		dev_err(dev, "Failed to get per clk: %d\n", ret);
+		dev_err(dev, "Failed to get clk: %d\n", ret);
 		return ret;
 	}
 
-	rate = clk_get_rate(&per_clk);
+	rate = clk_get_rate(&clk);
 	if ((long)rate <= 0) {
-		dev_err(dev, "Failed to get per clk rate: %ld\n", (long)rate);
+		dev_err(dev, "Failed to get clk rate: %ld\n", (long)rate);
 		return ret;
 	}
-	*clk = rate;
+	*clk_rate = rate;
 	return 0;
 }
 #else
-static inline int get_lpuart_clk_rate(struct udevice *dev, u32 *clk)
+static inline int get_lpuart_clk_rate(struct udevice *dev, u32 *clk_rate)
 { return -ENOSYS; }
 #endif
 
@@ -479,19 +486,22 @@
 static int lpuart_serial_probe(struct udevice *dev)
 {
 #if CONFIG_IS_ENABLED(CLK)
+	struct lpuart_serial_plat *plat = dev_get_plat(dev);
 	struct clk per_clk;
 	struct clk ipg_clk;
 	int ret;
 
-	ret = clk_get_by_name(dev, "per", &per_clk);
-	if (!ret) {
-		ret = clk_enable(&per_clk);
-		if (ret) {
-			dev_err(dev, "Failed to enable per clk: %d\n", ret);
-			return ret;
+	if (plat->devtype != DEV_MX7ULP) {
+		ret = clk_get_by_name(dev, "per", &per_clk);
+		if (!ret) {
+			ret = clk_enable(&per_clk);
+			if (ret) {
+				dev_err(dev, "Failed to enable per clk: %d\n", ret);
+				return ret;
+			}
+		} else {
+			debug("%s: Failed to get per clk: %d\n", __func__, ret);
 		}
-	} else {
-		debug("%s: Failed to get per clk: %d\n", __func__, ret);
 	}
 
 	ret = clk_get_by_name(dev, "ipg", &ipg_clk);
diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c
index b6197da..35df413 100644
--- a/drivers/serial/serial_xuartlite.c
+++ b/drivers/serial/serial_xuartlite.c
@@ -23,7 +23,7 @@
 #define ULITE_CONTROL_RST_TX	0x01
 #define ULITE_CONTROL_RST_RX	0x02
 
-static bool little_endian;
+static bool little_endian __section(".data");
 
 struct uartlite {
 	unsigned int rx_fifo;
diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c
index 786825d..d8b4f17 100644
--- a/drivers/soc/soc_xilinx_zynqmp.c
+++ b/drivers/soc/soc_xilinx_zynqmp.c
@@ -44,6 +44,7 @@
 	ZYNQMP_VARIANT_DR = BIT(3),
 	ZYNQMP_VARIANT_DR_SE = BIT(4),
 	ZYNQMP_VARIANT_EG_SE = BIT(5),
+	ZYNQMP_VARIANT_TEG = BIT(6),
 };
 
 struct zynqmp_device {
@@ -75,6 +76,11 @@
 		.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
 	},
 	{
+		.id = 0x04718093,
+		.device = 3,
+		.variants = ZYNQMP_VARIANT_TEG,
+	},
+	{
 		.id = 0x04721093,
 		.device = 4,
 		.variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
@@ -299,6 +305,8 @@
 		strlcat(priv->machine, "dr", sizeof(priv->machine));
 	} else if (device->variants & ZYNQMP_VARIANT_DR_SE) {
 		strlcat(priv->machine, "dr_SE", sizeof(priv->machine));
+	} else if (device->variants & ZYNQMP_VARIANT_TEG) {
+		strlcat(priv->machine, "teg", sizeof(priv->machine));
 	}
 
 	return 0;
diff --git a/drivers/sysreset/sysreset-ti-sci.c b/drivers/sysreset/sysreset-ti-sci.c
index 5fc05c4..0de1326 100644
--- a/drivers/sysreset/sysreset-ti-sci.c
+++ b/drivers/sysreset/sysreset-ti-sci.c
@@ -60,15 +60,9 @@
 	.request = ti_sci_sysreset_request,
 };
 
-static const struct udevice_id ti_sci_sysreset_of_match[] = {
-	{ .compatible = "ti,sci-sysreset", },
-	{ /* sentinel */ },
-};
-
 U_BOOT_DRIVER(ti_sci_sysreset) = {
 	.name = "ti-sci-sysreset",
 	.id = UCLASS_SYSRESET,
-	.of_match = ti_sci_sysreset_of_match,
 	.probe = ti_sci_sysreset_probe,
 	.priv_auto	= sizeof(struct ti_sci_sysreset_data),
 	.ops = &ti_sci_sysreset_ops,
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b60661f..910c5f3 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -685,6 +685,9 @@
 		reset_ep(udev, ep_index);
 
 	ring = virt_dev->eps[ep_index].ring;
+	if (!ring)
+		return -EINVAL;
+
 	/*
 	 * How much data is (potentially) left before the 64KB boundary?
 	 * XHCI Spec puts restriction( TABLE 49 and 6.4.1 section of XHCI Spec)
@@ -871,6 +874,8 @@
 	ep_index = usb_pipe_ep_index(pipe);
 
 	ep_ring = virt_dev->eps[ep_index].ring;
+	if (!ep_ring)
+		return -EINVAL;
 
 	/*
 	 * Check to see if the max packet size for the default control
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index d13cbff..741e186 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -475,67 +475,34 @@
 }
 
 /**
- * Configure the endpoint, programming the device contexts.
+ * Fill endpoint contexts for interface descriptor ifdesc.
  *
- * @param udev	pointer to the USB device structure
- * Return: returns the status of the xhci_configure_endpoints
+ * @param udev		pointer to the USB device structure
+ * @param ctrl		pointer to the xhci pravte device structure
+ * @param virt_dev	pointer to the xhci virtual device structure
+ * @param ifdesc	pointer to the USB interface config descriptor
+ * Return: returns the status of xhci_init_ep_contexts_if
  */
-static int xhci_set_configuration(struct usb_device *udev)
+static int xhci_init_ep_contexts_if(struct usb_device *udev,
+				    struct xhci_ctrl *ctrl,
+				    struct xhci_virt_device *virt_dev,
+				    struct usb_interface *ifdesc
+	)
 {
-	struct xhci_container_ctx *in_ctx;
-	struct xhci_container_ctx *out_ctx;
-	struct xhci_input_control_ctx *ctrl_ctx;
-	struct xhci_slot_ctx *slot_ctx;
 	struct xhci_ep_ctx *ep_ctx[MAX_EP_CTX_NUM];
 	int cur_ep;
-	int max_ep_flag = 0;
 	int ep_index;
 	unsigned int dir;
 	unsigned int ep_type;
-	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
-	int num_of_ep;
-	int ep_flag = 0;
 	u64 trb_64 = 0;
-	int slot_id = udev->slot_id;
-	struct xhci_virt_device *virt_dev = ctrl->devs[slot_id];
-	struct usb_interface *ifdesc;
 	u32 max_esit_payload;
 	unsigned int interval;
 	unsigned int mult;
 	unsigned int max_burst;
 	unsigned int avg_trb_len;
 	unsigned int err_count = 0;
-
-	out_ctx = virt_dev->out_ctx;
-	in_ctx = virt_dev->in_ctx;
-
-	num_of_ep = udev->config.if_desc[0].no_of_ep;
-	ifdesc = &udev->config.if_desc[0];
-
-	ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
-	/* Initialize the input context control */
-	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
-	ctrl_ctx->drop_flags = 0;
+	int num_of_ep = ifdesc->no_of_ep;
 
-	/* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */
-	for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) {
-		ep_flag = xhci_get_ep_index(&ifdesc->ep_desc[cur_ep]);
-		ctrl_ctx->add_flags |= cpu_to_le32(1 << (ep_flag + 1));
-		if (max_ep_flag < ep_flag)
-			max_ep_flag = ep_flag;
-	}
-
-	xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size);
-
-	/* slot context */
-	xhci_slot_copy(ctrl, in_ctx, out_ctx);
-	slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx);
-	slot_ctx->dev_info &= ~(cpu_to_le32(LAST_CTX_MASK));
-	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(max_ep_flag + 1) | 0);
-
-	xhci_endpoint_copy(ctrl, in_ctx, out_ctx, 0);
-
-	/* filling up ep contexts */
 	for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) {
 		struct usb_endpoint_descriptor *endpt_desc = NULL;
 		struct usb_ss_ep_comp_descriptor *ss_ep_comp_desc = NULL;
@@ -561,7 +528,8 @@
 		avg_trb_len = max_esit_payload;
 
 		ep_index = xhci_get_ep_index(endpt_desc);
-		ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, in_ctx, ep_index);
+		ep_ctx[ep_index] = xhci_get_ep_ctx(ctrl, virt_dev->in_ctx,
+						   ep_index);
 
 		/* Allocate the ep rings */
 		virt_dev->eps[ep_index].ring = xhci_ring_alloc(ctrl, 1, true);
@@ -614,6 +582,72 @@
 		}
 	}
 
+	return 0;
+}
+
+/**
+ * Configure the endpoint, programming the device contexts.
+ *
+ * @param udev	pointer to the USB device structure
+ * Return: returns the status of the xhci_configure_endpoints
+ */
+static int xhci_set_configuration(struct usb_device *udev)
+{
+	struct xhci_container_ctx *out_ctx;
+	struct xhci_container_ctx *in_ctx;
+	struct xhci_input_control_ctx *ctrl_ctx;
+	struct xhci_slot_ctx *slot_ctx;
+	int err;
+	int cur_ep;
+	int max_ep_flag = 0;
+	struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
+	int num_of_ep;
+	int ep_flag = 0;
+	int slot_id = udev->slot_id;
+	struct xhci_virt_device *virt_dev = ctrl->devs[slot_id];
+	struct usb_interface *ifdesc;
+	unsigned int ifnum;
+	unsigned int max_ifnum = min((unsigned int)USB_MAX_ACTIVE_INTERFACES,
+				     (unsigned int)udev->config.no_of_if);
+
+	out_ctx = virt_dev->out_ctx;
+	in_ctx = virt_dev->in_ctx;
+
+	ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
+	/* Initialize the input context control */
+	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
+	ctrl_ctx->drop_flags = 0;
+
+	for (ifnum = 0; ifnum < max_ifnum; ifnum++) {
+		ifdesc = &udev->config.if_desc[ifnum];
+		num_of_ep = ifdesc->no_of_ep;
+		/* EP_FLAG gives values 1 & 4 for EP1OUT and EP2IN */
+		for (cur_ep = 0; cur_ep < num_of_ep; cur_ep++) {
+			ep_flag = xhci_get_ep_index(&ifdesc->ep_desc[cur_ep]);
+			ctrl_ctx->add_flags |= cpu_to_le32(1 << (ep_flag + 1));
+			if (max_ep_flag < ep_flag)
+				max_ep_flag = ep_flag;
+		}
+	}
+
+	xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size);
+
+	/* slot context */
+	xhci_slot_copy(ctrl, in_ctx, out_ctx);
+	slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx);
+	slot_ctx->dev_info &= ~(cpu_to_le32(LAST_CTX_MASK));
+	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(max_ep_flag + 1) | 0);
+
+	xhci_endpoint_copy(ctrl, in_ctx, out_ctx, 0);
+
+	/* filling up ep contexts */
+	for (ifnum = 0; ifnum < max_ifnum; ifnum++) {
+		ifdesc = &udev->config.if_desc[ifnum];
+		err = xhci_init_ep_contexts_if(udev, ctrl, virt_dev, ifdesc);
+		if (err < 0)
+			return err;
+	}
+
 	return xhci_configure_endpoints(udev, false);
 }
 
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6f319ba..39c8252 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -180,6 +180,7 @@
 
 config CONSOLE_TRUETYPE
 	bool "Support a console that uses TrueType fonts"
+	select X86_HARDFP if X86
 	help
 	  TrueTrype fonts can provide outline-drawing capability rather than
 	  needing to provide a bitmap for each font and size that is needed.
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index 362458a..28665a3 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -8,6 +8,7 @@
 #include <dm.h>
 #include <log.h>
 #include <malloc.h>
+#include <spl.h>
 #include <video.h>
 #include <video_console.h>
 
@@ -802,6 +803,9 @@
 	struct console_tt_store store;
 	const uint size = sizeof(store);
 
+	if (spl_phase() <= PHASE_SPL)
+		return -ENOSYS;
+
 	/*
 	 * store the whole priv structure as it is simpler that picking out
 	 * what we need
@@ -823,6 +827,9 @@
 	struct console_tt_priv *priv = dev_get_priv(dev);
 	struct console_tt_store store;
 
+	if (spl_phase() <= PHASE_SPL)
+		return -ENOSYS;
+
 	memcpy(&store, abuf_data(buf), sizeof(store));
 
 	vc_priv->xcur_frac = store.cur.xpos_frac;
@@ -847,6 +854,9 @@
 	uint out, val;
 	int ret;
 
+	if (spl_phase() <= PHASE_SPL)
+		return -ENOSYS;
+
 	if (!visible)
 		return 0;
 
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index 5f89f6a..5d06e51 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -126,6 +126,7 @@
 	priv->xcur_frac = VID_TO_POS(x);
 	priv->xstart_frac = priv->xcur_frac;
 	priv->ycur = y;
+	vidconsole_entry_start(dev);
 }
 
 /**
@@ -135,8 +136,10 @@
  * @row:	new row
  * @col:	new column
  */
-static void set_cursor_position(struct vidconsole_priv *priv, int row, int col)
+static void set_cursor_position(struct udevice *dev, int row, int col)
 {
+	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+
 	/*
 	 * Ensure we stay in the bounds of the screen.
 	 */
@@ -145,9 +148,7 @@
 	if (col >= priv->cols)
 		col = priv->cols - 1;
 
-	priv->ycur = row * priv->y_charsize;
-	priv->xcur_frac = priv->xstart_frac +
-			  VID_TO_POS(col * priv->x_charsize);
+	vidconsole_position_cursor(dev, col, row);
 }
 
 /**
@@ -194,7 +195,7 @@
 			int row = priv->row_saved;
 			int col = priv->col_saved;
 
-			set_cursor_position(priv, row, col);
+			set_cursor_position(dev, row, col);
 			priv->escape = 0;
 			return;
 		}
@@ -256,7 +257,7 @@
 		if (row < 0)
 			row = 0;
 		/* Right and bottom overflows are handled in the callee. */
-		set_cursor_position(priv, row, col);
+		set_cursor_position(dev, row, col);
 		break;
 	}
 	case 'H':
@@ -280,7 +281,7 @@
 		if (col)
 			--col;
 
-		set_cursor_position(priv, row, col);
+		set_cursor_position(dev, row, col);
 
 		break;
 	}
diff --git a/env/Kconfig b/env/Kconfig
index 7885c8b..1f8e90af 100644
--- a/env/Kconfig
+++ b/env/Kconfig
@@ -472,7 +472,7 @@
 	string "Device and partition for where to store the environemt in FAT"
 	depends on ENV_IS_IN_FAT
 	default "0:1" if TI_COMMON_CMD_OPTIONS
-	default "0:auto" if ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL
+	default "0:auto" if ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || ARCH_VERSAL_NET
 	default ":auto" if ARCH_SUNXI
 	default "0" if ARCH_AT91
 	help
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index 365c514..2ff0dca 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -765,11 +765,6 @@
 	struct ext2_inode *first_inode = NULL;
 	struct ext2_inode temp_inode;
 
-	if (*dirname != '/') {
-		printf("Please supply Absolute path\n");
-		return -1;
-	}
-
 	/* TODO: input validation make equivalent to linux */
 	depth_dirname = zalloc(strlen(dirname) + 1);
 	if (!depth_dirname)
diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
index 1a340b4..e80f797 100644
--- a/fs/ext4/ext4_journal.c
+++ b/fs/ext4/ext4_journal.c
@@ -430,7 +430,7 @@
 			printf("Recovery required\n");
 	} else {
 		if (recovery_flag == RECOVER)
-			printf("File System is consistent\n");
+			log_debug("File System is consistent\n");
 		goto end;
 	}
 
diff --git a/fs/ext4/ext4_write.c b/fs/ext4/ext4_write.c
index ea4c5d4..d057f6b 100644
--- a/fs/ext4/ext4_write.c
+++ b/fs/ext4/ext4_write.c
@@ -847,6 +847,7 @@
 {
 	int ret = 0;
 	struct ext2_inode *file_inode = NULL;
+	struct ext2_inode *existing_file_inode = NULL;
 	unsigned char *inode_buffer = NULL;
 	int parent_inodeno;
 	int inodeno;
@@ -900,6 +901,15 @@
 	/* check if the filename is already present in root */
 	existing_file_inodeno = ext4fs_filename_unlink(filename);
 	if (existing_file_inodeno != -1) {
+		existing_file_inode = (struct ext2_inode *)zalloc(fs->inodesz);
+		if (!existing_file_inode)
+			goto fail;
+		ret = ext4fs_iget(existing_file_inodeno, existing_file_inode);
+		if (ret) {
+			free(existing_file_inode);
+			goto fail;
+		}
+
 		ret = ext4fs_delete_file(existing_file_inodeno);
 		fs->first_pass_bbmap = 0;
 		fs->curr_blkno = 0;
@@ -948,9 +958,15 @@
 			sizebytes = 0;
 		}
 	} else {
-		file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | S_IRGRP |
-					       S_IROTH | S_IXGRP | S_IXOTH);
+		if (existing_file_inode) {
+			file_inode->mode = existing_file_inode->mode;
+		} else {
+			file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | S_IRGRP |
+						       S_IROTH | S_IXGRP | S_IXOTH);
+		}
 	}
+	if (existing_file_inode)
+		free(existing_file_inode);
 	/* ToDo: Update correct time */
 	file_inode->mtime = cpu_to_le32(timestamp);
 	file_inode->atime = cpu_to_le32(timestamp);
diff --git a/fs/zfs/dev.c b/fs/zfs/dev.c
index 251e7d1..fcd9893 100644
--- a/fs/zfs/dev.c
+++ b/fs/zfs/dev.c
@@ -26,5 +26,5 @@
 int zfs_devread(int sector, int byte_offset, int byte_len, char *buf)
 {
 	return fs_devread(zfs_blk_desc, part_info, sector, byte_offset,
-			  byte_len, buf);
+			  byte_len, buf) ? 0 : 1;
 }
diff --git a/fs/zfs/zfs.c b/fs/zfs/zfs.c
index 1fec96c..bfc11fa 100644
--- a/fs/zfs/zfs.c
+++ b/fs/zfs/zfs.c
@@ -655,7 +655,7 @@
 											dn->endian)
 				<< SPA_MINBLOCKSHIFT;
 			*buf = malloc(size);
-			if (*buf) {
+			if (!*buf) {
 				err = ZFS_ERR_OUT_OF_MEMORY;
 				break;
 			}
@@ -1559,6 +1559,10 @@
 	return 0;
 }
 
+int is_word_aligned_ptr(void *ptr) {
+	return ((uintptr_t)ptr & (sizeof(void *) - 1)) == 0;
+}
+
 int
 zfs_nvlist_lookup_uint64(char *nvlist, char *name, uint64_t *out)
 {
@@ -1574,6 +1578,20 @@
 		return ZFS_ERR_BAD_FS;
 	}
 
+	/* On arm64, calling be64_to_cpu() on a value stored at a memory address
+	 * that's not 8-byte aligned causes the CPU to reset. Avoid that by copying the
+	 * value somewhere else if needed.
+	 */
+	if (!is_word_aligned_ptr((void *)nvpair)) {
+		uint64_t *alignedptr = malloc(sizeof(uint64_t));
+		if (!alignedptr)
+			return 0;
+		memcpy(alignedptr, nvpair, sizeof(uint64_t));
+		*out = be64_to_cpu(*alignedptr);
+		free(alignedptr);
+		return 1;
+	}
+
 	*out = be64_to_cpu(*(uint64_t *) nvpair);
 	return 1;
 }
@@ -1617,6 +1635,11 @@
 							  &size, 0);
 	if (!found)
 		return 0;
+
+	/* Allocate 12 bytes in addition to the nvlist size: One uint32 before the
+	 * nvlist to hold the encoding method, and two zero uint32's after the
+	 * nvlist as the NULL terminator.
+	 */
 	ret = calloc(1, size + 3 * sizeof(uint32_t));
 	if (!ret)
 		return 0;
@@ -2112,7 +2135,7 @@
 		 * Find requested blkid and the offset within that block.
 		 */
 		uint64_t blkid = file->offset + red;
-		blkid = do_div(blkid, blksz);
+		uint64_t blkoff = do_div(blkid, blksz);
 		free(data->file_buf);
 		data->file_buf = 0;
 
@@ -2127,8 +2150,7 @@
 
 		movesize = min(length, data->file_end - (int)file->offset - red);
 
-		memmove(buf, data->file_buf + file->offset + red
-				- data->file_start, movesize);
+		memmove(buf, data->file_buf + blkoff, movesize);
 		buf += movesize;
 		length -= movesize;
 		red += movesize;
diff --git a/include/bootm.h b/include/bootm.h
index 9e0f8d6..6983375 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -273,21 +273,24 @@
 int bootm_process_cmdline_env(int flags);
 
 /**
- * zboot_start() - Boot a zimage
+ * zboot_run() - Run through the various steps to 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
+ * @size: Size of bzImage, or 0 to detect this
  * @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
+ * @base_addr: If non-zero, this indicates that the boot parameters have already
+ *	been loaded by the caller to this address, so the load_zimage() call
+ *	in zboot_load() will be skipped when booting
+ * @cmdline: If non-NULL, the environment variable containing the 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);
+int zboot_run(ulong addr, ulong size, ulong initrd, ulong initrd_size,
+	      ulong base, char *cmdline);
 
 /*
  * zimage_get_kernel_version() - Get the version string from a kernel
@@ -314,7 +317,7 @@
  * bootm_boot_start() - Boot an image at the given address
  *
  * @addr: Image address
- * @cmdline: Command line to set
+ * @cmdline: Command line to set, NULL for default
  */
 int bootm_boot_start(ulong addr, const char *cmdline);
 
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 7daca0a..bb51c02 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -345,9 +345,6 @@
 extern const efi_guid_t efi_guid_text_input_protocol;
 extern const efi_guid_t efi_guid_text_output_protocol;
 
-extern char __efi_runtime_start[], __efi_runtime_stop[];
-extern char __efi_runtime_rel_start[], __efi_runtime_rel_stop[];
-
 /**
  * struct efi_open_protocol_info_item - open protocol info item
  *
diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
index b21c5cb..a75b5a3 100644
--- a/include/efi_tcg2.h
+++ b/include/efi_tcg2.h
@@ -150,16 +150,14 @@
  *				the variable.
  * @variable_data_length:	The size of the variable data.
  * @unicode_name:		The CHAR16 unicode name of the variable
- *				without NULL-terminator.
- * @variable_data:		The data parameter of the efi variable
- *				in the GetVariable() API.
+ *				without NULL-terminator followed by data.
  */
 struct efi_tcg2_uefi_variable_data {
 	efi_guid_t variable_name;
 	u64 unicode_name_length;
 	u64 variable_data_length;
-	u16 unicode_name[1];
-	u8 variable_data[1];
+	u16 unicode_name[];
+	// u8 variable_data[];
 };
 
 /**
diff --git a/include/env_default.h b/include/env_default.h
index 2ca4a08..8ee500d 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -99,6 +99,17 @@
 #ifdef CONFIG_SYS_SOC
 	"soc="		CONFIG_SYS_SOC			"\0"
 #endif
+#ifdef CONFIG_USB_HOST
+	"usb_ignorelist="
+#ifdef CONFIG_USB_KEYBOARD
+	/* Ignore Yubico devices. Currently only a single USB keyboard device is
+	 * supported and the emulated HID keyboard Yubikeys present is useless
+	 * as keyboard.
+	 */
+	"0x1050:*,"
+#endif
+	"\0"
+#endif
 #ifdef CONFIG_ENV_IMPORT_FDT
 	"env_fdt_path="	CONFIG_ENV_FDT_PATH		"\0"
 #endif
diff --git a/include/fastboot-internal.h b/include/fastboot-internal.h
index 610d4f9..e59c187 100644
--- a/include/fastboot-internal.h
+++ b/include/fastboot-internal.h
@@ -6,7 +6,7 @@
 /**
  * fastboot_buf_addr - base address of the fastboot download buffer
  */
-extern void *fastboot_buf_addr;
+extern ulong fastboot_buf_addr;
 
 /**
  * fastboot_buf_size - size of the fastboot download buffer
diff --git a/include/fastboot.h b/include/fastboot.h
index 1e7920e..c75184c 100644
--- a/include/fastboot.h
+++ b/include/fastboot.h
@@ -114,13 +114,13 @@
  */
 void fastboot_set_progress_callback(void (*progress)(const char *msg));
 
-/*
+/**
  * fastboot_init() - initialise new fastboot protocol session
  *
- * @buf_addr: Pointer to download buffer, or NULL for default
+ * @buf_addr: Address of download buffer, or 0 for default
  * @buf_size: Size of download buffer, or zero for default
  */
-void fastboot_init(void *buf_addr, u32 buf_size);
+void fastboot_init(ulong buf_addr, u32 buf_size);
 
 /**
  * fastboot_boot() - Execute fastboot boot command
diff --git a/include/image.h b/include/image.h
index 21de70f..acffd17 100644
--- a/include/image.h
+++ b/include/image.h
@@ -946,7 +946,7 @@
 int image_check_hcrc(const struct legacy_img_hdr *hdr);
 int image_check_dcrc(const struct legacy_img_hdr *hdr);
 #ifndef USE_HOSTCC
-ulong env_get_bootm_low(void);
+phys_addr_t env_get_bootm_low(void);
 phys_size_t env_get_bootm_size(void);
 phys_size_t env_get_bootm_mapsize(void);
 #endif
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index fb002ae..4abaf47 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -249,6 +249,13 @@
  */
 #define NAND_USE_BOUNCE_BUFFER	0x00100000
 
+/*
+ * Do not try to tweak the timings at runtime. This is needed when the
+ * controller initializes the timings on itself or when it relies on
+ * configuration done by the bootloader.
+ */
+#define NAND_KEEP_TIMINGS	0x00800000
+
 /* Options set by nand scan */
 /* bbt has already been read */
 #define NAND_BBT_SCANNED	0x40000000
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 6f479fa..13b5a52 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -251,6 +251,7 @@
 extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
 extern const struct spinand_manufacturer winbond_spinand_manufacturer;
 extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
+extern const struct spinand_manufacturer xtx_spinand_manufacturer;
 
 /**
  * struct spinand_op_variants - SPI NAND operation variants
diff --git a/include/mcheck.h b/include/mcheck.h
new file mode 100644
index 0000000..bd506ae
--- /dev/null
+++ b/include/mcheck.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.1+ */
+/*
+ * Copyright (C) 1996-2024 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * <https://www.gnu.org/licenses/>.
+ */
+#ifndef _MCHECK_H
+#define _MCHECK_H       1
+
+/*
+ * Return values for `mprobe': these are the kinds of inconsistencies that
+ * `mcheck' enables detection of.
+ */
+enum mcheck_status {
+	MCHECK_DISABLED = -1,         /* Consistency checking is not turned on.  */
+	MCHECK_OK,                    /* Block is fine.  */
+	MCHECK_FREE,                  /* Block freed twice.  */
+	MCHECK_HEAD,                  /* Memory before the block was clobbered.  */
+	MCHECK_TAIL                   /* Memory after the block was clobbered.  */
+};
+
+typedef void (*mcheck_abortfunc_t)(enum mcheck_status, const void *p);
+
+int mcheck(mcheck_abortfunc_t func);
+
+/*
+ * Similar to `mcheck' but performs checks for all block whenever one of
+ * the memory handling functions is called.  This can be very slow.
+ */
+int mcheck_pedantic(mcheck_abortfunc_t f);
+
+/* Force check of all blocks now.  */
+void mcheck_check_all(void);
+
+/*
+ * Check for aberrations in a particular malloc'd block. These are the
+ * same checks that `mcheck' does, when you free or reallocate a block.
+ */
+enum mcheck_status mprobe(void *__ptr);
+
+#endif
diff --git a/include/mmc.h b/include/mmc.h
index 1022db3..4b8327f 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -590,7 +590,7 @@
 	uint f_max;
 	uint b_max;
 	unsigned char part_type;
-#ifdef CONFIG_MMC_PWRSEQ
+#if CONFIG_IS_ENABLED(MMC_PWRSEQ)
 	struct udevice *pwr_dev;
 #endif
 };
@@ -736,7 +736,8 @@
 				  * accessing the boot partitions
 				  */
 	u32 quirks;
-	u8 hs400_tuning;
+	bool tuning:1;
+	bool hs400_tuning:1;
 
 	enum bus_mode user_speed_mode; /* input speed mode from user */
 };
@@ -795,7 +796,7 @@
 int mmc_initialize(struct bd_info *bis);
 int mmc_init_device(int num);
 int mmc_init(struct mmc *mmc);
-int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error);
+int mmc_send_tuning(struct mmc *mmc, u32 opcode);
 int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data);
 int mmc_deinit(struct mmc *mmc);
 
@@ -808,7 +809,7 @@
  */
 int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg);
 
-#ifdef CONFIG_MMC_PWRSEQ
+#if CONFIG_IS_ENABLED(MMC_PWRSEQ)
 /**
  * mmc_pwrseq_get_power() - get a power device from device tree
  *
diff --git a/include/u-boot/zlib.h b/include/u-boot/zlib.h
index a33cc87..ee19f46 100644
--- a/include/u-boot/zlib.h
+++ b/include/u-boot/zlib.h
@@ -49,9 +49,6 @@
 extern "C" {
 #endif
 
-#define ZLIB_VERSION "1.2.3"
-#define ZLIB_VERNUM 0x1230
-
 /* #include "zconf.h" */        /* included directly here */
 /* zconf.h -- configuration of the zlib compression library
  * Copyright (C) 1995-2005 Jean-loup Gailly.
@@ -484,7 +481,6 @@
 #define Z_DATA_ERROR   (-3)
 #define Z_MEM_ERROR    (-4)
 #define Z_BUF_ERROR    (-5)
-#define Z_VERSION_ERROR (-6)
 /* Return codes for the compression/decompression functions. Negative
  * values are errors, positive values are used for special but normal events.
  */
@@ -523,11 +519,11 @@
 
 ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
 ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
-			const char *version, int stream_size));
+			int stream_size));
 ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
 ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
 			int windowBits, int memLevel,
-			int strategy, const char *version,
+			int strategy,
 			int stream_size));
 ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
 ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
@@ -553,7 +549,7 @@
 
 
 ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
-			const char *version, int stream_size));
+			int stream_size));
 ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
 /*
     inflate decompresses as much data as possible, and stops when the input
@@ -743,11 +739,11 @@
 */
 
 ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
-                                      const char *version, int stream_size));
+                                      int stream_size));
 #define inflateInit(strm) \
-	inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+	inflateInit_((strm), sizeof(z_stream))
 #define inflateInit2(strm, windowBits) \
-	inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+	inflateInit2_((strm), (windowBits), sizeof(z_stream))
 
 #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
 	struct internal_state {int dummy;}; /* hack for buggy compilers */
diff --git a/include/usb.h b/include/usb.h
index 09e3f0c..3aafdc8 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -49,6 +49,12 @@
  */
 #define USB_TIMEOUT_MS(pipe) (usb_pipebulk(pipe) ? 5000 : 1000)
 
+/*
+ * The xhcd hcd driver prepares only a limited number interfaces / endpoints.
+ * Define this limit so that drivers do not exceed it.
+ */
+#define USB_MAX_ACTIVE_INTERFACES	2
+
 /* device request (setup) */
 struct devrequest {
 	__u8	requesttype;
diff --git a/lib/Kconfig b/lib/Kconfig
index 37ac14f..efb7797 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -348,7 +348,7 @@
 	  Enables function tracing within U-Boot. This allows recording of call
 	  traces including timing information. The command can write data to
 	  memory for exporting for analysis (e.g. using bootchart).
-	  See doc/README.trace for full details.
+	  See doc/develop/trace.rst for full details.
 
 config TRACE_BUFFER_SIZE
 	hex "Size of trace buffer in U-Boot"
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 086521f..034e366 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -71,11 +71,11 @@
 obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += efi_unicode_collation.o
 obj-y += efi_var_common.o
 obj-y += efi_var_mem.o
-obj-y += efi_var_file.o
 ifeq ($(CONFIG_EFI_MM_COMM_TEE),y)
 obj-y += efi_variable_tee.o
 else
 obj-y += efi_variable.o
+obj-y += efi_var_file.o
 obj-$(CONFIG_EFI_VARIABLES_PRESEED) += efi_var_seed.o
 endif
 obj-y += efi_watchdog.o
diff --git a/lib/efi_loader/efi_acpi.c b/lib/efi_loader/efi_acpi.c
index 67bbd2a..67bd7f8 100644
--- a/lib/efi_loader/efi_acpi.c
+++ b/lib/efi_loader/efi_acpi.c
@@ -41,7 +41,7 @@
 	}
 
 	addr = gd_acpi_start();
-	printf("EFI using ACPI tables at %lx\n", addr);
+	log_debug("EFI using ACPI tables at %lx\n", addr);
 
 	/* And expose them to our EFI payload */
 	return efi_install_configuration_table(&acpi_guid,
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index aba3100..12cf23f 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -15,6 +15,7 @@
 #include <watchdog.h>
 #include <asm/cache.h>
 #include <asm/global_data.h>
+#include <asm/sections.h>
 #include <linux/list_sort.h>
 #include <linux/sizes.h>
 
diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
index 16b2c3d..aa8feff 100644
--- a/lib/efi_loader/efi_var_common.c
+++ b/lib/efi_loader/efi_var_common.c
@@ -9,6 +9,7 @@
 #include <efi_loader.h>
 #include <efi_variable.h>
 #include <stdlib.h>
+#include <u-boot/crc.h>
 
 enum efi_secure_mode {
 	EFI_MODE_SETUP,
@@ -416,3 +417,76 @@
 
 	return buf;
 }
+
+/**
+ * efi_var_collect() - Copy EFI variables mstching attributes mask
+ *
+ * @bufp:	buffer containing variable collection
+ * @lenp:	buffer length
+ * @attr_mask:	mask of matched attributes
+ *
+ * Return:	Status code
+ */
+efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t *lenp,
+					    u32 check_attr_mask)
+{
+	size_t len = EFI_VAR_BUF_SIZE;
+	struct efi_var_file *buf;
+	struct efi_var_entry *var, *old_var;
+	size_t old_var_name_length = 2;
+
+	*bufp = NULL; /* Avoid double free() */
+	buf = calloc(1, len);
+	if (!buf)
+		return EFI_OUT_OF_RESOURCES;
+	var = buf->var;
+	old_var = var;
+	for (;;) {
+		efi_uintn_t data_length, var_name_length;
+		u8 *data;
+		efi_status_t ret;
+
+		if ((uintptr_t)buf + len <=
+		    (uintptr_t)var->name + old_var_name_length)
+			return EFI_BUFFER_TOO_SMALL;
+
+		var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name;
+		memcpy(var->name, old_var->name, old_var_name_length);
+		guidcpy(&var->guid, &old_var->guid);
+		ret = efi_get_next_variable_name_int(
+				&var_name_length, var->name, &var->guid);
+		if (ret == EFI_NOT_FOUND)
+			break;
+		if (ret != EFI_SUCCESS) {
+			free(buf);
+			return ret;
+		}
+		old_var_name_length = var_name_length;
+		old_var = var;
+
+		data = (u8 *)var->name + old_var_name_length;
+		data_length = (uintptr_t)buf + len - (uintptr_t)data;
+		ret = efi_get_variable_int(var->name, &var->guid,
+					   &var->attr, &data_length, data,
+					   &var->time);
+		if (ret != EFI_SUCCESS) {
+			free(buf);
+			return ret;
+		}
+		if ((var->attr & check_attr_mask) == check_attr_mask) {
+			var->length = data_length;
+			var = (struct efi_var_entry *)ALIGN((uintptr_t)data + data_length, 8);
+		}
+	}
+
+	buf->reserved = 0;
+	buf->magic = EFI_VAR_FILE_MAGIC;
+	len = (uintptr_t)var - (uintptr_t)buf;
+	buf->crc32 = crc32(0, (u8 *)buf->var,
+			   len - sizeof(struct efi_var_file));
+	buf->length = len;
+	*bufp = buf;
+	*lenp = len;
+
+	return EFI_SUCCESS;
+}
diff --git a/lib/efi_loader/efi_var_file.c b/lib/efi_loader/efi_var_file.c
index 532b6b4..413e179 100644
--- a/lib/efi_loader/efi_var_file.c
+++ b/lib/efi_loader/efi_var_file.c
@@ -52,70 +52,6 @@
 	return EFI_SUCCESS;
 }
 
-efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t *lenp,
-					    u32 check_attr_mask)
-{
-	size_t len = EFI_VAR_BUF_SIZE;
-	struct efi_var_file *buf;
-	struct efi_var_entry *var, *old_var;
-	size_t old_var_name_length = 2;
-
-	*bufp = NULL; /* Avoid double free() */
-	buf = calloc(1, len);
-	if (!buf)
-		return EFI_OUT_OF_RESOURCES;
-	var = buf->var;
-	old_var = var;
-	for (;;) {
-		efi_uintn_t data_length, var_name_length;
-		u8 *data;
-		efi_status_t ret;
-
-		if ((uintptr_t)buf + len <=
-		    (uintptr_t)var->name + old_var_name_length)
-			return EFI_BUFFER_TOO_SMALL;
-
-		var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name;
-		memcpy(var->name, old_var->name, old_var_name_length);
-		guidcpy(&var->guid, &old_var->guid);
-		ret = efi_get_next_variable_name_int(
-				&var_name_length, var->name, &var->guid);
-		if (ret == EFI_NOT_FOUND)
-			break;
-		if (ret != EFI_SUCCESS) {
-			free(buf);
-			return ret;
-		}
-		old_var_name_length = var_name_length;
-		old_var = var;
-
-		data = (u8 *)var->name + old_var_name_length;
-		data_length = (uintptr_t)buf + len - (uintptr_t)data;
-		ret = efi_get_variable_int(var->name, &var->guid,
-					   &var->attr, &data_length, data,
-					   &var->time);
-		if (ret != EFI_SUCCESS) {
-			free(buf);
-			return ret;
-		}
-		if ((var->attr & check_attr_mask) == check_attr_mask) {
-			var->length = data_length;
-			var = (struct efi_var_entry *)ALIGN((uintptr_t)data + data_length, 8);
-		}
-	}
-
-	buf->reserved = 0;
-	buf->magic = EFI_VAR_FILE_MAGIC;
-	len = (uintptr_t)var - (uintptr_t)buf;
-	buf->crc32 = crc32(0, (u8 *)buf->var,
-			   len - sizeof(struct efi_var_file));
-	buf->length = len;
-	*bufp = buf;
-	*lenp = len;
-
-	return EFI_SUCCESS;
-}
-
 /**
  * efi_var_to_file() - save non-volatile variables as file
  *
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 2951dc7..e6c1219 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -163,6 +163,7 @@
 		break;
 	default:
 		/* TODO: support private authenticated variables */
+		ret = EFI_UNSUPPORTED;
 		goto err;
 	}
 
diff --git a/lib/gzip.c b/lib/gzip.c
index 5d9c195..a9a3df5 100644
--- a/lib/gzip.c
+++ b/lib/gzip.c
@@ -67,7 +67,7 @@
 
 	r = deflateInit2_(&s, Z_BEST_SPEED, Z_DEFLATED,	window,
 			DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
-			ZLIB_VERSION, sizeof(z_stream));
+			sizeof(z_stream));
 	if (r != Z_OK) {
 		printf ("Error: deflateInit2_() returned %d\n", r);
 		return -1;
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
index 1007b69..d3b4f71 100644
--- a/lib/rsa/rsa-verify.c
+++ b/lib/rsa/rsa-verify.c
@@ -342,7 +342,7 @@
 		return -EINVAL;
 	}
 
-	debug("Checksum algorithm: %s", checksum->name);
+	debug("Checksum algorithm: %s\n", checksum->name);
 
 	/* Sanity check for stack size */
 	if (sig_len > RSA_MAX_SIG_BITS / 8) {
@@ -444,13 +444,13 @@
 	const char *algo;
 
 	if (node < 0) {
-		debug("%s: Skipping invalid node", __func__);
+		debug("%s: Skipping invalid node\n", __func__);
 		return -EBADF;
 	}
 
 	algo = fdt_getprop(blob, node, "algo", NULL);
 	if (strcmp(info->name, algo)) {
-		debug("%s: Wrong algo: have %s, expected %s", __func__,
+		debug("%s: Wrong algo: have %s, expected %s\n", __func__,
 		      info->name, algo);
 		return -EFAULT;
 	}
@@ -470,7 +470,7 @@
 	prop.rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
 
 	if (!prop.num_bits || !prop.modulus || !prop.rr) {
-		debug("%s: Missing RSA key info", __func__);
+		debug("%s: Missing RSA key info\n", __func__);
 		return -EFAULT;
 	}
 
diff --git a/lib/zlib/deflate.c b/lib/zlib/deflate.c
index 4549f4d..7e1ed4f 100644
--- a/lib/zlib/deflate.c
+++ b/lib/zlib/deflate.c
@@ -196,37 +196,30 @@
     zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
 
 /* ========================================================================= */
-int ZEXPORT deflateInit_(strm, level, version, stream_size)
+int ZEXPORT deflateInit_(strm, level, stream_size)
     z_streamp strm;
     int level;
-    const char *version;
     int stream_size;
 {
     return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
-                         Z_DEFAULT_STRATEGY, version, stream_size);
+                         Z_DEFAULT_STRATEGY, stream_size);
     /* To do: ignore strm->next_in if we use it as window */
 }
 
 /* ========================================================================= */
 int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-                  version, stream_size)
+                  stream_size)
     z_streamp strm;
     int  level;
     int  method;
     int  windowBits;
     int  memLevel;
     int  strategy;
-    const char *version;
     int stream_size;
 {
     deflate_state *s;
     int wrap = 1;
-    static const char my_version[] = ZLIB_VERSION;
 
-    if (version == Z_NULL || version[0] != my_version[0] ||
-        stream_size != sizeof(z_stream)) {
-        return Z_VERSION_ERROR;
-    }
     if (strm == Z_NULL) return Z_STREAM_ERROR;
 
     strm->msg = Z_NULL;
diff --git a/lib/zlib/inffast.c b/lib/zlib/inffast.c
index e3c7f3b..5e2a65a 100644
--- a/lib/zlib/inffast.c
+++ b/lib/zlib/inffast.c
@@ -1,5 +1,5 @@
 /* inffast.c -- fast decoding
- * Copyright (C) 1995-2004 Mark Adler
+ * Copyright (C) 1995-2008, 2010, 2013 Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -12,25 +12,6 @@
 
 #ifndef ASMINF
 
-/* Allow machine dependent optimization for post-increment or pre-increment.
-   Based on testing to date,
-   Pre-increment preferred for:
-   - PowerPC G3 (Adler)
-   - MIPS R5000 (Randers-Pehrson)
-   Post-increment preferred for:
-   - none
-   No measurable difference:
-   - Pentium III (Anderson)
-   - M68060 (Nikl)
- */
-#ifdef POSTINC
-#  define OFF 0
-#  define PUP(a) *(a)++
-#else
-#  define OFF 1
-#  define PUP(a) *++(a)
-#endif
-
 /*
    Decode literal, length, and distance codes and write out the resulting
    literal and match bytes until either not enough input or output is
@@ -66,12 +47,13 @@
       requires strm->avail_out >= 258 for each loop to avoid checking for
       output space.
  */
-void inflate_fast(z_streamp strm, unsigned start)
-/* start: inflate()'s starting value for strm->avail_out */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
 {
     struct inflate_state FAR *state;
-    unsigned char FAR *in;      /* local strm->next_in */
-    unsigned char FAR *last;    /* while in < last, enough input available */
+    z_const unsigned char FAR *in;      /* local strm->next_in */
+    z_const unsigned char FAR *last;    /* have enough input while in < last */
     unsigned char FAR *out;     /* local strm->next_out */
     unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
     unsigned char FAR *end;     /* while out < end, enough space available */
@@ -80,7 +62,7 @@
 #endif
     unsigned wsize;             /* window size or zero if not using window */
     unsigned whave;             /* valid bytes in the window */
-    unsigned write;             /* window write index */
+    unsigned wnext;             /* window write index */
     unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
     unsigned long hold;         /* local strm->hold */
     unsigned bits;              /* local strm->bits */
@@ -88,7 +70,7 @@
     code const FAR *dcode;      /* local strm->distcode */
     unsigned lmask;             /* mask for first level of length codes */
     unsigned dmask;             /* mask for first level of distance codes */
-    code this;                  /* retrieved table entry */
+    code here;                  /* retrieved table entry */
     unsigned op;                /* code bits, operation, extra bits, or */
                                 /*  window position, window bytes to copy */
     unsigned len;               /* match length, unused bytes */
@@ -97,7 +79,7 @@
 
     /* copy state to local variables */
     state = (struct inflate_state FAR *)strm->state;
-    in = strm->next_in - OFF;
+    in = strm->next_in;
     last = in + (strm->avail_in - 5);
     if (in > last && strm->avail_in > 5) {
         /*
@@ -107,7 +89,7 @@
 	strm->avail_in = 0xffffffff - (uintptr_t)in;
         last = in + (strm->avail_in - 5);
     }
-    out = strm->next_out - OFF;
+    out = strm->next_out;
     beg = out - (start - strm->avail_out);
     end = out + (strm->avail_out - 257);
 #ifdef INFLATE_STRICT
@@ -115,7 +97,7 @@
 #endif
     wsize = state->wsize;
     whave = state->whave;
-    write = state->write;
+    wnext = state->wnext;
     window = state->window;
     hold = state->hold;
     bits = state->bits;
@@ -128,29 +110,29 @@
        input data or output space */
     do {
         if (bits < 15) {
-            hold += (unsigned long)(PUP(in)) << bits;
+            hold += (unsigned long)(*in++) << bits;
             bits += 8;
-            hold += (unsigned long)(PUP(in)) << bits;
+            hold += (unsigned long)(*in++) << bits;
             bits += 8;
         }
-        this = lcode[hold & lmask];
+        here = lcode[hold & lmask];
       dolen:
-        op = (unsigned)(this.bits);
+        op = (unsigned)(here.bits);
         hold >>= op;
         bits -= op;
-        op = (unsigned)(this.op);
+        op = (unsigned)(here.op);
         if (op == 0) {                          /* literal */
-            Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
                     "inflate:         literal '%c'\n" :
-                    "inflate:         literal 0x%02x\n", this.val));
-            PUP(out) = (unsigned char)(this.val);
+                    "inflate:         literal 0x%02x\n", here.val));
+            *out++ = (unsigned char)(here.val);
         }
         else if (op & 16) {                     /* length base */
-            len = (unsigned)(this.val);
+            len = (unsigned)(here.val);
             op &= 15;                           /* number of extra bits */
             if (op) {
                 if (bits < op) {
-                    hold += (unsigned long)(PUP(in)) << bits;
+                    hold += (unsigned long)(*in++) << bits;
                     bits += 8;
                 }
                 len += (unsigned)hold & ((1U << op) - 1);
@@ -159,25 +141,25 @@
             }
             Tracevv((stderr, "inflate:         length %u\n", len));
             if (bits < 15) {
-                hold += (unsigned long)(PUP(in)) << bits;
+                hold += (unsigned long)(*in++) << bits;
                 bits += 8;
-                hold += (unsigned long)(PUP(in)) << bits;
+                hold += (unsigned long)(*in++) << bits;
                 bits += 8;
             }
-            this = dcode[hold & dmask];
+            here = dcode[hold & dmask];
           dodist:
-            op = (unsigned)(this.bits);
+            op = (unsigned)(here.bits);
             hold >>= op;
             bits -= op;
-            op = (unsigned)(this.op);
+            op = (unsigned)(here.op);
             if (op & 16) {                      /* distance base */
-                dist = (unsigned)(this.val);
+                dist = (unsigned)(here.val);
                 op &= 15;                       /* number of extra bits */
                 if (bits < op) {
-                    hold += (unsigned long)(PUP(in)) << bits;
+                    hold += (unsigned long)(*in++) << bits;
                     bits += 8;
                     if (bits < op) {
-                        hold += (unsigned long)(PUP(in)) << bits;
+                        hold += (unsigned long)(*in++) << bits;
                         bits += 8;
                     }
                 }
@@ -196,108 +178,80 @@
                 if (dist > op) {                /* see if copy from window */
                     op = dist - op;             /* distance back in window */
                     if (op > whave) {
-                        strm->msg = (char *)"invalid distance too far back";
+                        strm->msg =
+                            (char *)"invalid distance too far back";
                         state->mode = BAD;
                         break;
                     }
-                    from = window - OFF;
-                    if (write == 0) {           /* very common case */
+                    from = window;
+                    if (wnext == 0) {           /* very common case */
                         from += wsize - op;
                         if (op < len) {         /* some from window */
                             len -= op;
                             do {
-                                PUP(out) = PUP(from);
+                                *out++ = *from++;
                             } while (--op);
                             from = out - dist;  /* rest from output */
                         }
                     }
-                    else if (write < op) {      /* wrap around window */
-                        from += wsize + write - op;
-                        op -= write;
+                    else if (wnext < op) {      /* wrap around window */
+                        from += wsize + wnext - op;
+                        op -= wnext;
                         if (op < len) {         /* some from end of window */
                             len -= op;
                             do {
-                                PUP(out) = PUP(from);
+                                *out++ = *from++;
                             } while (--op);
-                            from = window - OFF;
-                            if (write < len) {  /* some from start of window */
-                                op = write;
+                            from = window;
+                            if (wnext < len) {  /* some from start of window */
+                                op = wnext;
                                 len -= op;
                                 do {
-                                    PUP(out) = PUP(from);
+                                    *out++ = *from++;
                                 } while (--op);
                                 from = out - dist;      /* rest from output */
                             }
                         }
                     }
                     else {                      /* contiguous in window */
-                        from += write - op;
+                        from += wnext - op;
                         if (op < len) {         /* some from window */
                             len -= op;
                             do {
-                                PUP(out) = PUP(from);
+                                *out++ = *from++;
                             } while (--op);
                             from = out - dist;  /* rest from output */
                         }
                     }
                     while (len > 2) {
-                        PUP(out) = PUP(from);
-                        PUP(out) = PUP(from);
-                        PUP(out) = PUP(from);
+                        *out++ = *from++;
+                        *out++ = *from++;
+                        *out++ = *from++;
                         len -= 3;
                     }
                     if (len) {
-                        PUP(out) = PUP(from);
+                        *out++ = *from++;
                         if (len > 1)
-                            PUP(out) = PUP(from);
+                            *out++ = *from++;
                     }
                 }
                 else {
-		    unsigned short *sout;
-		    unsigned long loops;
-
                     from = out - dist;          /* copy direct from output */
-                    /* minimum length is three */
-		    /* Align out addr */
-		    if (!((long)(out - 1 + OFF) & 1)) {
-			PUP(out) = PUP(from);
-			len--;
-		    }
-		    sout = (unsigned short *)(out - OFF);
-		    if (dist > 2 ) {
-			unsigned short *sfrom;
-
-			sfrom = (unsigned short *)(from - OFF);
-			loops = len >> 1;
-			do
-			    PUP(sout) = get_unaligned(++sfrom);
-			while (--loops);
-			out = (unsigned char *)sout + OFF;
-			from = (unsigned char *)sfrom + OFF;
-		    } else { /* dist == 1 or dist == 2 */
-			unsigned short pat16;
-
-			pat16 = *(sout-2+2*OFF);
-			if (dist == 1)
-#if defined(__BIG_ENDIAN)
-			    pat16 = (pat16 & 0xff) | ((pat16 & 0xff ) << 8);
-#elif defined(__LITTLE_ENDIAN)
-			    pat16 = (pat16 & 0xff00) | ((pat16 & 0xff00 ) >> 8);
-#else
-#error __BIG_ENDIAN nor __LITTLE_ENDIAN is defined
-#endif
-			loops = len >> 1;
-			do
-			    PUP(sout) = pat16;
-			while (--loops);
-			out = (unsigned char *)sout + OFF;
-		    }
-		    if (len & 1)
-			PUP(out) = PUP(from);
+                    do {                        /* minimum length is three */
+                        *out++ = *from++;
+                        *out++ = *from++;
+                        *out++ = *from++;
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        *out++ = *from++;
+                        if (len > 1)
+                            *out++ = *from++;
+                    }
                 }
             }
             else if ((op & 64) == 0) {          /* 2nd level distance code */
-                this = dcode[this.val + (hold & ((1U << op) - 1))];
+                here = dcode[here.val + (hold & ((1U << op) - 1))];
                 goto dodist;
             }
             else {
@@ -307,7 +261,7 @@
             }
         }
         else if ((op & 64) == 0) {              /* 2nd level length code */
-            this = lcode[this.val + (hold & ((1U << op) - 1))];
+            here = lcode[here.val + (hold & ((1U << op) - 1))];
             goto dolen;
         }
         else if (op & 32) {                     /* end-of-block */
@@ -329,8 +283,8 @@
     hold &= (1U << bits) - 1;
 
     /* update state and return */
-    strm->next_in = in + OFF;
-    strm->next_out = out + OFF;
+    strm->next_in = in;
+    strm->next_out = out;
     strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
     strm->avail_out = (unsigned)(out < end ?
                                  257 + (end - out) : 257 - (out - end));
@@ -343,7 +297,7 @@
    inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
    - Using bit fields for code structure
    - Different op definition to avoid & for extra bits (do & for table bits)
-   - Three separate decoding do-loops for direct, window, and write == 0
+   - Three separate decoding do-loops for direct, window, and wnext == 0
    - Special case for distance > 1 copies to do overlapped load and store copy
    - Explicit branch predictions (based on measured branch probabilities)
    - Deferring match copy and interspersed it with decoding subsequent codes
diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c
index 8f767b7..f7e81fc 100644
--- a/lib/zlib/inflate.c
+++ b/lib/zlib/inflate.c
@@ -21,7 +21,7 @@
     state->head = Z_NULL;
     state->wsize = 0;
     state->whave = 0;
-    state->write = 0;
+    state->wnext = 0;
     state->hold = 0;
     state->bits = 0;
     state->lencode = state->distcode = state->next = state->codes;
@@ -30,14 +30,11 @@
     return Z_OK;
 }
 
-int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, const char *version,
+int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
 			  int stream_size)
 {
     struct inflate_state FAR *state;
 
-    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
-        stream_size != (int)(sizeof(z_stream)))
-        return Z_VERSION_ERROR;
     if (strm == Z_NULL) return Z_STREAM_ERROR;
     strm->msg = Z_NULL;                 /* in case we return an error */
     if (strm->zalloc == (alloc_func)0) {
@@ -70,9 +67,9 @@
     return inflateReset(strm);
 }
 
-int ZEXPORT inflateInit_(z_streamp strm, const char *version, int stream_size)
+int ZEXPORT inflateInit_(z_streamp strm, int stream_size)
 {
-    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+    return inflateInit2_(strm, DEF_WBITS, stream_size);
 }
 
 local void fixedtables(struct inflate_state FAR *state)
@@ -115,7 +112,7 @@
     /* if window not in use yet, initialize */
     if (state->wsize == 0) {
         state->wsize = 1U << state->wbits;
-        state->write = 0;
+        state->wnext = 0;
         state->whave = 0;
     }
 
@@ -123,22 +120,22 @@
     copy = out - strm->avail_out;
     if (copy >= state->wsize) {
         zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
-        state->write = 0;
+        state->wnext = 0;
         state->whave = state->wsize;
     }
     else {
-        dist = state->wsize - state->write;
+        dist = state->wsize - state->wnext;
         if (dist > copy) dist = copy;
-        zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+        zmemcpy(state->window + state->wnext, strm->next_out - copy, dist);
         copy -= dist;
         if (copy) {
             zmemcpy(state->window, strm->next_out - copy, copy);
-            state->write = copy;
+            state->wnext = copy;
             state->whave = state->wsize;
         }
         else {
-            state->write += dist;
-            if (state->write == state->wsize) state->write = 0;
+            state->wnext += dist;
+            if (state->wnext == state->wsize) state->wnext = 0;
             if (state->whave < state->wsize) state->whave += dist;
         }
     }
@@ -823,12 +820,12 @@
             copy = out - left;
             if (state->offset > copy) {         /* copy from window */
                 copy = state->offset - copy;
-                if (copy > state->write) {
-                    copy -= state->write;
+                if (copy > state->wnext) {
+                    copy -= state->wnext;
                     from = state->window + (state->wsize - copy);
                 }
                 else
-                    from = state->window + (state->write - copy);
+                    from = state->window + (state->wnext - copy);
                 if (copy > state->length) copy = state->length;
             }
             else {                              /* copy from output */
diff --git a/lib/zlib/inflate.h b/lib/zlib/inflate.h
index 07bd3e7..2657d61 100644
--- a/lib/zlib/inflate.h
+++ b/lib/zlib/inflate.h
@@ -88,7 +88,7 @@
     unsigned wbits;             /* log base 2 of requested window size */
     unsigned wsize;             /* window size or zero if not using window */
     unsigned whave;             /* valid bytes in the window */
-    unsigned write;             /* window write index */
+    unsigned wnext;             /* window write index */
     unsigned char FAR *window;  /* allocated sliding window, if needed */
         /* bit accumulator */
     unsigned long hold;         /* input bit accumulator */
diff --git a/lib/zlib/zutil.c b/lib/zlib/zutil.c
index 609aac5..ec21b45 100644
--- a/lib/zlib/zutil.c
+++ b/lib/zlib/zutil.c
@@ -21,7 +21,6 @@
 "data error",          /* Z_DATA_ERROR    (-3) */
 "insufficient memory", /* Z_MEM_ERROR     (-4) */
 "buffer error",        /* Z_BUF_ERROR     (-5) */
-"incompatible version",/* Z_VERSION_ERROR (-6) */
 ""};
 
 #ifdef DEBUG
diff --git a/net/nfs.c b/net/nfs.c
index 7a8887e..c182824 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -57,7 +57,8 @@
 static int nfs_len;
 static const ulong nfs_timeout = CONFIG_NFS_TIMEOUT;
 
-static char dirfh[NFS_FHSIZE];	/* NFSv2 / NFSv3 file handle of directory */
+static char dirfh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle of directory */
+static unsigned int dirfh3_length; /* (variable) length of dirfh when NFSv3 */
 static char filefh[NFS3_FHSIZE]; /* NFSv2 / NFSv3 file handle */
 static unsigned int filefh3_length;	/* (variable) length of filefh when NFSv3 */
 
@@ -377,9 +378,9 @@
 
 		rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
 	} else {  /* NFS_V3 */
-		*p++ = htonl(NFS_FHSIZE);	/* Dir handle length */
-		memcpy(p, dirfh, NFS_FHSIZE);
-		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(dirfh3_length);	/* Dir handle length */
+		memcpy(p, dirfh, dirfh3_length);
+		p += (dirfh3_length / 4);
 		*p++ = htonl(fnamelen);
 		if (fnamelen & 3)
 			*(p + fnamelen / 4) = 0;
@@ -565,7 +566,14 @@
 
 	fs_mounted = 1;
 	/*  NFSv2 and NFSv3 use same structure */
-	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	if (choosen_nfs_version != NFS_V3) {
+		memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	} else {
+		dirfh3_length = ntohl(rpc_pkt.u.reply.data[1]);
+		if (dirfh3_length > NFS3_FHSIZE)
+			dirfh3_length  = NFS3_FHSIZE;
+		memcpy(dirfh, rpc_pkt.u.reply.data + 2, dirfh3_length);
+	}
 
 	return 0;
 }
diff --git a/net/wget.c b/net/wget.c
index 817c5eb..abab371 100644
--- a/net/wget.c
+++ b/net/wget.c
@@ -50,6 +50,7 @@
 static unsigned int packets;
 
 static unsigned int initial_data_seq_num;
+static unsigned int next_data_seq_num;
 
 static enum  wget_state current_wget_state;
 
@@ -272,17 +273,18 @@
 
 		current_wget_state = WGET_TRANSFERRING;
 
+		initial_data_seq_num = tcp_seq_num + hlen;
+		next_data_seq_num    = tcp_seq_num + len;
+
 		if (strstr((char *)pkt, http_ok) == 0) {
 			debug_cond(DEBUG_WGET,
 				   "wget: Connected Bad Xfer\n");
-			initial_data_seq_num = tcp_seq_num + hlen;
 			wget_loop_state = NETLOOP_FAIL;
 			wget_send(action, tcp_seq_num, tcp_ack_num, len);
 		} else {
 			debug_cond(DEBUG_WGET,
 				   "wget: Connctd pkt %p  hlen %x\n",
 				   pkt, hlen);
-			initial_data_seq_num = tcp_seq_num + hlen;
 
 			pos = strstr((char *)pkt, content_len);
 			if (!pos) {
@@ -396,9 +398,13 @@
 			   "wget: Transferring, seq=%x, ack=%x,len=%x\n",
 			   tcp_seq_num, tcp_ack_num, len);
 
+		if (next_data_seq_num != tcp_seq_num) {
+			debug_cond(DEBUG_WGET, "wget: seq=%x packet was lost\n", next_data_seq_num);
+			return;
+		}
+		next_data_seq_num = tcp_seq_num + len;
+
-		if (tcp_seq_num >= initial_data_seq_num &&
-		    store_block(pkt, tcp_seq_num - initial_data_seq_num,
-				len) != 0) {
+		if (store_block(pkt, tcp_seq_num - initial_data_seq_num, len) != 0) {
 			wget_fail("wget: store error\n",
 				  tcp_seq_num, tcp_ack_num, action);
 			net_set_state(NETLOOP_FAIL);
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index d074ba2..1868f1b 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -381,6 +381,11 @@
 	$(objtree)/tools/mkexynosspl) $(VAR_SIZE_PARAM) $< $@
 endif
 
+$(obj)/u-boot-spl.ldr: $(obj)/u-boot-spl
+	$(CREATE_LDR_ENV)
+	$(LDR) -T $(CONFIG_LDR_CPU) -c $@ $< $(LDR_FLAGS)
+	$(BOARD_SIZE_CHECK)
+
 quiet_cmd_objcopy = OBJCOPY $@
 cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
 
@@ -575,7 +580,7 @@
 
 SPL_OF_LIST_TARGETS = $(patsubst %,dts/%.dtb,$(subst ",,$(CONFIG_SPL_OF_LIST)))
 SHRUNK_ARCH_DTB = $(addprefix $(obj)/,$(SPL_OF_LIST_TARGETS))
-$(dir $(SHRUNK_ARCH_DTB)):
+$(sort $(dir $(SHRUNK_ARCH_DTB))):
 	$(shell [ -d $@ ] || mkdir -p $@)
 
 .SECONDEXPANSION:
diff --git a/test/py/test.py b/test/py/test.py
index 95859a6..7c47790 100755
--- a/test/py/test.py
+++ b/test/py/test.py
@@ -11,7 +11,6 @@
 import os.path
 import sys
 import pytest
-from pkg_resources import load_entry_point
 
 if __name__ == '__main__':
     # argv; py.test test_directory_name user-supplied-arguments
diff --git a/test/py/tests/test_scsi.py b/test/py/tests/test_scsi.py
index be2e283..445693c 100644
--- a/test/py/tests/test_scsi.py
+++ b/test/py/tests/test_scsi.py
@@ -87,6 +87,6 @@
 def test_scsi_part(u_boot_console):
     test_scsi_dev(u_boot_console)
     output = u_boot_console.run_command('scsi part')
-    assert 'Partition Map for SCSI device' in output
+    assert 'Partition Map for scsi device' in output
     output = u_boot_console.run_command('echo $?')
     assert output.endswith('0')
diff --git a/tools/binman/btool/openssl.py b/tools/binman/btool/openssl.py
index fe81a1f..c6df64c 100644
--- a/tools/binman/btool/openssl.py
+++ b/tools/binman/btool/openssl.py
@@ -283,6 +283,7 @@
 basicConstraints = CA:true
 1.3.6.1.4.1.294.1.3=ASN1:SEQUENCE:swrv
 1.3.6.1.4.1.294.1.9=ASN1:SEQUENCE:ext_boot_info
+1.3.6.1.4.1.294.1.8=ASN1:SEQUENCE:debug
 
 [swrv]
 swrv=INTEGER:{sw_rev}
@@ -323,6 +324,12 @@
 shaType  = OID:{sha_type}
 shaValue = FORMAT:HEX,OCT:{hashval_sysfw_data}
 
+[ debug ]
+debugUID = FORMAT:HEX,OCT:0000000000000000000000000000000000000000000000000000000000000000
+debugType = INTEGER:4
+coreDbgEn = INTEGER:0
+coreDbgSecEn = INTEGER:0
+
 {sysfw_inner_cert_ext_boot_block}
 
 {dm_data_ext_boot_block}
diff --git a/tools/binman/etype/ti_board_config.py b/tools/binman/etype/ti_board_config.py
index 2c3bb8f..c10d66e 100644
--- a/tools/binman/etype/ti_board_config.py
+++ b/tools/binman/etype/ti_board_config.py
@@ -248,7 +248,7 @@
 
             yaml_config = config.YamlLintConfig("extends: default")
             for p in yamllint.linter.run(open(self._config_file, "r"), yaml_config):
-                self.Raise(f"Yamllint error: {p.line}: {p.rule}")
+                self.Raise(f"Yamllint error: Line {p.line} in {self._config_file}: {p.rule}")
             try:
                 validate(self.file_yaml, self.schema_yaml)
             except Exception as e:
diff --git a/tools/fit_image.c b/tools/fit_image.c
index beef1fa..0fccfbb 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -137,7 +137,7 @@
 	int ret;
 	int fd;
 
-	fd = open(fname, O_RDWR | O_BINARY);
+	fd = open(fname, O_RDONLY | O_BINARY);
 	if (fd < 0) {
 		fprintf(stderr, "%s: Can't open %s: %s\n",
 			params->cmdname, fname, strerror(errno));
diff --git a/tools/image-host.c b/tools/image-host.c
index b2a0f2e..7bfc0cb 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -346,17 +346,17 @@
 				      unsigned char *key_iv_data, int expected_size)
 {
 	char filename[PATH_MAX];
-	int ret = -1;
+	int ret;
 
 	ret = snprintf(filename, sizeof(filename), "%s/%s%s",
 		       keydir, key_iv_name, ".bin");
 	if (ret >= sizeof(filename)) {
-		printf("Can't format the key or IV filename when setting up the cipher: insufficient buffer space\n");
-		ret = -1;
+		fprintf(stderr, "Can't format the key or IV filename when setting up the cipher: insufficient buffer space\n");
+		return -1;
 	}
 	if (ret < 0) {
-		printf("Can't format the key or IV filename when setting up the cipher: snprintf error\n");
-		ret = -1;
+		fprintf(stderr, "Can't format the key or IV filename when setting up the cipher: snprintf error\n");
+		return -1;
 	}
 
 	ret = fit_image_read_data(filename, key_iv_data, expected_size);
diff --git a/tools/proftool.c b/tools/proftool.c
index fca45e4..c2e3809 100644
--- a/tools/proftool.c
+++ b/tools/proftool.c
@@ -290,7 +290,7 @@
 		"Options:\n"
 		"   -c <cfg>\tSpecify config file\n"
 		"   -f <subtype>\tSpecify output subtype\n"
-		"   -m <map>\tSpecify Systen.map file\n"
+		"   -m <map>\tSpecify System.map file\n"
 		"   -o <fname>\tSpecify output file\n"
 		"   -t <fname>\tSpecify trace data file (from U-Boot 'trace calls')\n"
 		"   -v <0-4>\tSpecify verbosity\n"
@@ -306,7 +306,7 @@
 }
 
 /**
- * h_cmp_offset - bsearch() function to compare two functions bny their offset
+ * h_cmp_offset - bsearch() function to compare two functions by their offset
  *
  * @v1: Pointer to first function (struct func_info)
  * @v2: Pointer to second function (struct func_info)
@@ -431,7 +431,7 @@
 static struct func_info *find_caller_by_offset(uint offset)
 {
 	int low;	/* least function that could be a match */
-	int high;	/* greated function that could be a match */
+	int high;	/* greatest function that could be a match */
 	struct func_info key;
 
 	low = 0;
@@ -1352,7 +1352,7 @@
 		}
 
 		if (!(func->flags & FUNCF_TRACE)) {
-			debug("Funcion '%s' is excluded from trace\n",
+			debug("Function '%s' is excluded from trace\n",
 			      func->name);
 			skip_count++;
 			continue;
@@ -1781,7 +1781,8 @@
  *
  * This works by maintaining a string shared across all recursive calls. The
  * function name for this node is added to the existing string, to make up the
- * full call-stack description. For example, on entry, @str might contain:
+ * full call-stack description. For example, on entry, @str_buf->data might
+ * contain:
  *
  *    "initf_bootstage;bootstage_mark_name"
  *                                        ^ @base
@@ -1795,18 +1796,18 @@
  * @fout: Output file
  * @out_format: Output format to use
  * @node: Node to output (pass the whole tree at first)
- * @str: String to use to build the output line (e.g. 500 charas long)
- * @maxlen: Maximum length of string
+ * @str_buf: String buffer to use to build the output line
  * @base: Current base position in the string
  * @treep: Returns the resulting flamegraph tree
  * Returns 0 if OK, -1 on error
  */
 static int output_tree(FILE *fout, enum out_format_t out_format,
-		       const struct flame_node *node, char *str, int maxlen,
+		       const struct flame_node *node, struct abuf *str_buf,
 		       int base)
 {
 	const struct flame_node *child;
 	int pos;
+	char *str = abuf_data(str_buf);
 
 	if (node->count) {
 		if (out_format == OUT_FMT_FLAMEGRAPH_CALLS) {
@@ -1832,18 +1833,29 @@
 	if (pos)
 		str[pos++] = ';';
 	list_for_each_entry(child, &node->child_head, sibling_node) {
-		int len;
+		int len, needed;
 
 		len = strlen(child->func->name);
-		if (pos + len + 1 >= maxlen) {
-			fprintf(stderr, "String too short (%d chars)\n",
-				maxlen);
-			return -1;
+		needed = pos + len + 1;
+		if (needed > abuf_size(str_buf)) {
+			/*
+			 * We need to re-allocate the string buffer; increase
+			 * its size by multiples of 500 characters.
+			 */
+			needed = 500 * ((needed / 500) + 1);
+			if (!abuf_realloc(str_buf, needed))
+				return -1;
+			str = abuf_data(str_buf);
+			memset(str + pos, 0, abuf_size(str_buf) - pos);
 		}
 		strcpy(str + pos, child->func->name);
-		if (output_tree(fout, out_format, child, str, maxlen,
-				pos + len))
+		if (output_tree(fout, out_format, child, str_buf, pos + len))
 			return -1;
+		/*
+		 * Update our pointer as the string buffer might have been
+		 * re-allocated.
+		 */
+		str = abuf_data(str_buf);
 	}
 
 	return 0;
@@ -1859,16 +1871,24 @@
 static int make_flamegraph(FILE *fout, enum out_format_t out_format)
 {
 	struct flame_node *tree;
-	char str[500];
+	struct abuf str_buf;
+	char *str;
+	int ret = 0;
 
 	if (make_flame_tree(out_format, &tree))
 		return -1;
 
-	*str = '\0';
-	if (output_tree(fout, out_format, tree, str, sizeof(str), 0))
+	abuf_init(&str_buf);
+	if (!abuf_realloc(&str_buf, 500))
 		return -1;
 
-	return 0;
+	str = abuf_data(&str_buf);
+	memset(str, 0, abuf_size(&str_buf));
+	if (output_tree(fout, out_format, tree, &str_buf, 0))
+		ret = -1;
+
+	abuf_uninit(&str_buf);
+	return ret;
 }
 
 /**