Merge tag 'xilinx-for-v2023.01-rc1-v2' of https://gitlab.denx.de/u-boot/custodians/u-boot-microblaze into next

Xilinx changes for v2023.01-rc1 (round 2)

xilinx:
- Add support for new Versal NET SOC

zynqmp:
- Use mdio bus for ethernet phy description
- Wire ethernet phy reset via i2c-gpio

versal:
- Config cleanup
diff --git a/MAINTAINERS b/MAINTAINERS
index 65f26e3..b4b185a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -356,20 +356,26 @@
 F:	doc/device-tree-bindings/usb/mediatek,*
 F:	doc/README.mediatek
 F:	drivers/clk/mediatek/
+F:	drivers/cpu/mtk_cpu.c
+F:	drivers/i2c/mtk_i2c.c
 F:	drivers/mmc/mtk-sd.c
 F:	drivers/phy/phy-mtk-*
 F:	drivers/pinctrl/mediatek/
 F:	drivers/power/domain/mtk-power-domain.c
 F:	drivers/ram/mediatek/
 F:	drivers/spi/mtk_snfi_spi.c
+F:	drivers/spi/mtk_spim.c
 F:	drivers/timer/mtk_timer.c
 F:	drivers/usb/host/xhci-mtk.c
 F:	drivers/usb/mtu3/
 F:	drivers/watchdog/mtk_wdt.c
 F:	drivers/net/mtk_eth.c
+F:	drivers/net/mtk_eth.h
 F:	drivers/reset/reset-mediatek.c
 F:	tools/mtk_image.c
 F:	tools/mtk_image.h
+F:	tools/mtk_nand_headers.c
+F:	tools/mtk_nand_headers.h
 N:	mediatek
 
 ARM METHODE SUPPORT
diff --git a/arch/Kconfig b/arch/Kconfig
index 994fd3b..1ffd77c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -166,7 +166,6 @@
 	imply CMD_IO
 	imply CMD_IOTRACE
 	imply CMD_LZMADEC
-	imply CMD_SATA
 	imply CMD_SF
 	imply CMD_SF_TEST
 	imply CRC32_VERIFY
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index d6832d1..71e9bd4 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -1238,6 +1238,15 @@
 	mt7622-bananapi-bpi-r64.dtb \
 	mt7623n-bananapi-bpi-r2.dtb \
 	mt7629-rfb.dtb \
+	mt7981-rfb.dtb \
+	mt7981-emmc-rfb.dtb \
+	mt7981-sd-rfb.dtb \
+	mt7986a-rfb.dtb \
+	mt7986b-rfb.dtb \
+	mt7986a-sd-rfb.dtb \
+	mt7986b-sd-rfb.dtb \
+	mt7986a-emmc-rfb.dtb \
+	mt7986b-emmc-rfb.dtb \
 	mt8183-pumpkin.dtb \
 	mt8512-bm1-emmc.dtb \
 	mt8516-pumpkin.dtb \
diff --git a/arch/arm/dts/imx8mm-venice-gw7901-u-boot.dtsi b/arch/arm/dts/imx8mm-venice-gw7901-u-boot.dtsi
index 11c773b..dc99e7b 100644
--- a/arch/arm/dts/imx8mm-venice-gw7901-u-boot.dtsi
+++ b/arch/arm/dts/imx8mm-venice-gw7901-u-boot.dtsi
@@ -129,6 +129,57 @@
 	phy-reset-post-delay = <1>;
 };
 
+&switch {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		lan1: port@0 {
+			phy-handle = <&sw_phy0>;
+		};
+
+		lan2: port@1 {
+			phy-handle = <&sw_phy1>;
+		};
+
+		lan3: port@2 {
+			phy-handle = <&sw_phy2>;
+		};
+
+		lan4: port@3 {
+			phy-handle = <&sw_phy3>;
+		};
+	};
+
+	mdios {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		mdio@0 {
+			reg = <0>;
+			compatible = "microchip,ksz-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sw_phy0: ethernet-phy@0 {
+				reg = <0x0>;
+			};
+
+			sw_phy1: ethernet-phy@1 {
+				reg = <0x1>;
+			};
+
+			sw_phy2: ethernet-phy@2 {
+				reg = <0x2>;
+			};
+
+			sw_phy3: ethernet-phy@3 {
+				reg = <0x3>;
+			};
+		};
+	};
+};
+
 &pinctrl_fec1 {
 	u-boot,dm-spl;
 };
diff --git a/arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi b/arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi
index 920246d..caf5d3a 100644
--- a/arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi
+++ b/arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi
@@ -162,6 +162,65 @@
 	u-boot,dm-spl;
 };
 
+&switch {
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		lan1: port@0 {
+			phy-handle = <&sw_phy0>;
+		};
+
+		lan2: port@1 {
+			phy-handle = <&sw_phy1>;
+		};
+
+		lan3: port@2 {
+			phy-handle = <&sw_phy2>;
+		};
+
+		lan4: port@3 {
+			phy-handle = <&sw_phy3>;
+		};
+
+		lan5: port@4 {
+			phy-handle = <&sw_phy4>;
+		};
+	};
+
+	mdios {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		mdio@0 {
+			reg = <0>;
+			compatible = "microchip,ksz-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			sw_phy0: ethernet-phy@0 {
+				reg = <0x0>;
+			};
+
+			sw_phy1: ethernet-phy@1 {
+				reg = <0x1>;
+			};
+
+			sw_phy2: ethernet-phy@2 {
+				reg = <0x2>;
+			};
+
+			sw_phy3: ethernet-phy@3 {
+				reg = <0x3>;
+			};
+
+			sw_phy4: ethernet-phy@4 {
+				reg = <0x4>;
+			};
+		};
+	};
+};
+
 &usdhc2 {
 	assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_400M>;
 	assigned-clock-rates = <400000000>;
diff --git a/arch/arm/dts/mt7622-rfb.dts b/arch/arm/dts/mt7622-rfb.dts
index 30a9137..b44f19f 100644
--- a/arch/arm/dts/mt7622-rfb.dts
+++ b/arch/arm/dts/mt7622-rfb.dts
@@ -159,6 +159,14 @@
 		};
 
 	};
+
+	i2c1_pins_default: i2c1-default {
+		mux {
+			function = "i2c";
+			groups = "i2c1_0";
+		};
+	};
+
 };
 
 &snfi {
@@ -242,3 +250,13 @@
 &u3phy {
        status = "okay";
 };
+
+&soft_i2c {
+	status = "disabled";
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_default>;
+	status = "okay";
+};
diff --git a/arch/arm/dts/mt7622.dtsi b/arch/arm/dts/mt7622.dtsi
index 0127474..2d89fa0 100644
--- a/arch/arm/dts/mt7622.dtsi
+++ b/arch/arm/dts/mt7622.dtsi
@@ -175,6 +175,7 @@
 		status = "disabled";
 		assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>;
 		assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>;
+		mediatek,force-highspeed;
 	};
 
 	mmc0: mmc@11230000 {
@@ -423,4 +424,28 @@
 		status = "disabled";
 	};
 
+	soft_i2c: soft_i2c@0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "i2c-gpio";
+		gpios = <&gpio 56 GPIO_ACTIVE_HIGH>, /* SDA */
+			<&gpio 55 GPIO_ACTIVE_HIGH>; /* CLK */
+		i2c-gpio,delay-us = <5>;
+		status = "disabled";
+	};
+
+	i2c1: i2c@11008000 {
+		compatible = "mediatek,mt7622-i2c";
+		reg = <0x11008000 0x90>,
+		      <0x11000180 0x80>;
+		interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_LOW>;
+		clock-div = <16>;
+		clocks = <&pericfg CLK_PERI_I2C1_PD>,
+			 <&pericfg CLK_PERI_AP_DMA_PD>;
+		clock-names = "main", "dma";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
 };
diff --git a/arch/arm/dts/mt7981-emmc-rfb.dts b/arch/arm/dts/mt7981-emmc-rfb.dts
new file mode 100644
index 0000000..2b7eae9
--- /dev/null
+++ b/arch/arm/dts/mt7981-emmc-rfb.dts
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7981.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	model = "mt7981-rfb";
+	compatible = "mediatek,mt7981", "mediatek,mt7981-rfb";
+	chosen {
+		stdout-path = &uart0;
+		tick-timer = &timer0;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		  compatible = "regulator-fixed";
+		  regulator-name = "fixed-3.3V";
+		  regulator-min-microvolt = <3300000>;
+		  regulator-max-microvolt = <3300000>;
+		  regulator-boot-on;
+		  regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+	mediatek,gmac-id = <0>;
+	phy-mode = "sgmii";
+	mediatek,switch = "mt7531";
+	reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&pinctrl {
+	spic_pins: spi1-pins-func-1 {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins: spi1-pins-func-3 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	/* pin15 as pwm0 */
+	one_pwm_pins: one-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1";
+		};
+	};
+
+	/* pin15 as pwm0 and pin14 as pwm1 */
+	two_pwm_pins: two-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1", "pwm1_0";
+		};
+	};
+
+	/* pin15 as pwm0, pin14 as pwm1, pin7 as pwm2 */
+	three_pwm_pins: three-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1", "pwm1_0", "pwm2";
+		};
+	};
+
+	mmc0_pins_default: mmc0default {
+		mux {
+			function = "flash";
+			groups =  "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+				"SPI0_CS",  "SPI0_HOLD", "SPI0_WP",
+				"SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+		conf-rst {
+			pins = "PWM0";
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&two_pwm_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_default>;
+	bus-width = <8>;
+	max-frequency = <52000000>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	vmmc-supply = <&reg_3p3v>;
+	non-removable;
+	status = "okay";
+};
diff --git a/arch/arm/dts/mt7981-rfb.dts b/arch/arm/dts/mt7981-rfb.dts
new file mode 100644
index 0000000..5559ace
--- /dev/null
+++ b/arch/arm/dts/mt7981-rfb.dts
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7981.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	model = "mt7981-rfb";
+	compatible = "mediatek,mt7981", "mediatek,mt7981-rfb";
+	chosen {
+		stdout-path = &uart0;
+		tick-timer = &timer0;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+	mediatek,gmac-id = <0>;
+	phy-mode = "sgmii";
+	mediatek,switch = "mt7531";
+	reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&pinctrl {
+	spi_flash_pins: spi0-pins-func-1 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+		};
+
+		conf-pd {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
+		};
+	};
+
+	spi2_flash_pins: spi2-spi2-pins {
+		mux {
+			function = "spi";
+			groups = "spi2", "spi2_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+
+	spic_pins: spi1-pins-func-1 {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins: spi1-pins-func-3 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	/* pin15 as pwm0 */
+	one_pwm_pins: one-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1";
+		};
+	};
+
+	/* pin15 as pwm0 and pin14 as pwm1 */
+	two_pwm_pins: two-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1", "pwm1_0";
+		};
+	};
+
+	/* pin15 as pwm0, pin14 as pwm1, pin7 as pwm2 */
+	three_pwm_pins: three-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1", "pwm1_0", "pwm2";
+		};
+	};
+};
+
+&spi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	must_tx;
+	enhance_timing;
+	dma_ext;
+	ipm_design;
+	support_quad;
+	tick_dly = <2>;
+	sample_sel = <0>;
+
+	spi_nand@0 {
+		compatible = "spi-nand";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+	};
+};
+
+&spi2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2_flash_pins>;
+	status = "okay";
+	must_tx;
+	enhance_timing;
+	dma_ext;
+	ipm_design;
+	support_quad;
+	tick_dly = <2>;
+	sample_sel = <0>;
+
+	spi_nor@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&two_pwm_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "disabled";
+};
diff --git a/arch/arm/dts/mt7981-sd-rfb.dts b/arch/arm/dts/mt7981-sd-rfb.dts
new file mode 100644
index 0000000..34ac227
--- /dev/null
+++ b/arch/arm/dts/mt7981-sd-rfb.dts
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7981.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	model = "mt7981-rfb";
+	compatible = "mediatek,mt7981", "mediatek,mt7981-sd-rfb";
+	chosen {
+		stdout-path = &uart0;
+		tick-timer = &timer0;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		  compatible = "regulator-fixed";
+		  regulator-name = "fixed-3.3V";
+		  regulator-min-microvolt = <3300000>;
+		  regulator-max-microvolt = <3300000>;
+		  regulator-boot-on;
+		  regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+	mediatek,gmac-id = <0>;
+	phy-mode = "sgmii";
+	mediatek,switch = "mt7531";
+	reset-gpios = <&gpio 39 GPIO_ACTIVE_HIGH>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&pinctrl {
+	spic_pins: spi1-pins-func-1 {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	uart1_pins: spi1-pins-func-3 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	/* pin15 as pwm0 */
+	one_pwm_pins: one-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1";
+		};
+	};
+
+	/* pin15 as pwm0 and pin14 as pwm1 */
+	two_pwm_pins: two-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1", "pwm1_0";
+		};
+	};
+
+	/* pin15 as pwm0, pin14 as pwm1, pin7 as pwm2 */
+	three_pwm_pins: three-pwm-pins {
+		mux {
+			function = "pwm";
+			groups = "pwm0_1", "pwm1_0", "pwm2";
+		};
+	};
+
+	mmc0_pins_default: mmc0default {
+		mux {
+			function = "flash";
+			groups =  "emmc_45";
+		};
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+				"SPI0_CS",  "SPI0_HOLD", "SPI0_WP",
+				"SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+		conf-rst {
+			pins = "PWM0";
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&two_pwm_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_default>;
+	bus-width = <4>;
+	max-frequency = <52000000>;
+	cap-sd-highspeed;
+	r_smpl = <0>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
diff --git a/arch/arm/dts/mt7981.dtsi b/arch/arm/dts/mt7981.dtsi
new file mode 100644
index 0000000..3089371
--- /dev/null
+++ b/arch/arm/dts/mt7981.dtsi
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/mt7981-clk.h>
+#include <dt-bindings/reset/mt7629-reset.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+
+/ {
+	compatible = "mediatek,mt7981";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0>;
+			mediatek,hwver = <&hwver>;
+		};
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x1>;
+			mediatek,hwver = <&hwver>;
+		};
+	};
+
+	gpt_clk: gpt_dummy20m {
+		compatible = "fixed-clock";
+		clock-frequency = <13000000>;
+		#clock-cells = <0>;
+		u-boot,dm-pre-reloc;
+	};
+
+	hwver: hwver {
+		compatible = "mediatek,hwver", "syscon";
+		reg = <0x8000000 0x1000>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <13000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+		arm,cpu-registers-not-fw-configured;
+	};
+
+	timer0: timer@10008000 {
+		compatible = "mediatek,mt7986-timer";
+		reg = <0x10008000 0x1000>;
+		interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&gpt_clk>;
+		clock-names = "gpt-clk";
+		u-boot,dm-pre-reloc;
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7986-wdt";
+		reg = <0x1001c000 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+		status = "disabled";
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0x0c000000 0x40000>,  /* GICD */
+		      <0x0c080000 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	fixed_plls: apmixedsys@1001e000 {
+		compatible = "mediatek,mt7981-fixed-plls";
+		reg = <0x1001e000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	topckgen: topckgen@1001b000 {
+		compatible = "mediatek,mt7981-topckgen";
+		reg = <0x1001b000 0x1000>;
+		clock-parent = <&fixed_plls>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	infracfg_ao: infracfg_ao@10001000 {
+		compatible = "mediatek,mt7981-infracfg_ao";
+		reg = <0x10001000 0x80>;
+		clock-parent = <&infracfg>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	infracfg: infracfg@10001000 {
+		compatible = "mediatek,mt7981-infracfg";
+		reg = <0x10001000 0x30>;
+		clock-parent = <&topckgen>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	pinctrl: pinctrl@11d00000 {
+		compatible = "mediatek,mt7981-pinctrl";
+		reg = <0x11d00000 0x1000>,
+		      <0x11c00000 0x1000>,
+		      <0x11c10000 0x1000>,
+		      <0x11d20000 0x1000>,
+		      <0x11e00000 0x1000>,
+		      <0x11e20000 0x1000>,
+		      <0x11f00000 0x1000>,
+		      <0x11f10000 0x1000>,
+		      <0x1000b000 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rm_base",
+			    "iocfg_rb_base", "iocfg_lb_base", "iocfg_bl_base",
+			    "iocfg_tm_base", "iocfg_tl_base", "eint";
+		gpio: gpio-controller {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+	};
+
+	pwm: pwm@10048000 {
+		compatible = "mediatek,mt7981-pwm";
+		reg = <0x10048000 0x1000>;
+		#clock-cells = <1>;
+		#pwm-cells = <2>;
+		interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg CK_INFRA_PWM>,
+			 <&infracfg_ao CK_INFRA_PWM_BSEL>,
+			 <&infracfg_ao CK_INFRA_PWM1_CK>,
+			 <&infracfg_ao CK_INFRA_PWM2_CK>,
+			 /* FIXME */
+			 <&infracfg_ao CK_INFRA_PWM2_CK>;
+		assigned-clocks = <&topckgen CK_TOP_PWM_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>;
+		clock-names = "top", "main", "pwm1", "pwm2", "pwm3";
+		status = "disabled";
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11002000 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART0_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		mediatek,force-highspeed;
+		status = "disabled";
+		u-boot,dm-pre-reloc;
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11003000 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART1_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART1_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		mediatek,force-highspeed;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11004000 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART2_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART2_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		mediatek,force-highspeed;
+		status = "disabled";
+	};
+
+	snand: snand@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0x11005000 0x1000>,
+		      <0x11006000 0x1000>;
+		reg-names = "nfi", "ecc";
+		clocks = <&infracfg_ao CK_INFRA_SPINFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI_HCK_CK>;
+		clock-names = "pad_clk", "nfi_clk", "nfi_hclk";
+		assigned-clocks = <&topckgen CK_TOP_SPINFI_SEL>,
+				  <&topckgen CK_TOP_NFI1X_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D8>,
+					 <&topckgen CK_TOP_CB_M_D8>;
+		status = "disabled";
+	};
+
+	ethsys: syscon@15000000 {
+		compatible = "mediatek,mt7981-ethsys", "syscon";
+		reg = <0x15000000 0x1000>;
+		clock-parent = <&topckgen>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	eth: ethernet@15100000 {
+		compatible = "mediatek,mt7981-eth", "syscon";
+		reg = <0x15100000 0x20000>;
+		resets = <&ethsys ETHSYS_FE_RST>;
+		reset-names = "fe";
+		mediatek,ethsys = <&ethsys>;
+		mediatek,sgmiisys = <&sgmiisys0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	sgmiisys0: syscon@10060000 {
+		compatible = "mediatek,mt7986-sgmiisys", "syscon";
+		reg = <0x10060000 0x1000>;
+		pn_swap;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@10070000 {
+		compatible = "mediatek,mt7986-sgmiisys", "syscon";
+		reg = <0x10070000 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0x1100a000 0x100>;
+		clocks = <&infracfg_ao CK_INFRA_SPI0_CK>,
+			 <&topckgen CK_TOP_SPI_SEL>;
+		assigned-clocks = <&topckgen CK_TOP_SPI_SEL>,
+				  <&infracfg CK_INFRA_SPI0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D2>,
+					 <&topckgen CK_INFRA_ISPI0>;
+		clock-names = "sel-clk", "spi-clk";
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0x1100b000 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	spi2: spi@11009000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0x11009000 0x100>;
+		clocks = <&infracfg_ao CK_INFRA_SPI0_CK>,
+			 <&topckgen CK_TOP_SPI_SEL>;
+		assigned-clocks = <&topckgen CK_TOP_SPI_SEL>,
+				  <&infracfg CK_INFRA_SPI0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D2>,
+					 <&topckgen CK_INFRA_ISPI0>;
+		clock-names = "sel-clk", "spi-clk";
+		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+		compatible = "mediatek,mt7981-mmc";
+		reg = <0x11230000 0x1000>,
+		      <0x11C20000 0x1000>;
+		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_EMMC_400M>,
+			 <&topckgen CK_TOP_EMMC_208M>,
+			 <&infracfg_ao CK_INFRA_MSDC_CK>;
+		assigned-clocks = <&topckgen CK_TOP_EMMC_400M_SEL>,
+				  <&topckgen CK_TOP_EMMC_208M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_NET2_D2>,
+					 <&topckgen CK_TOP_CB_M_D2>;
+		clock-names = "source", "hclk", "source_cg";
+		status = "disabled";
+	};
+
+};
diff --git a/arch/arm/dts/mt7986-u-boot.dtsi b/arch/arm/dts/mt7986-u-boot.dtsi
new file mode 100644
index 0000000..95671f8
--- /dev/null
+++ b/arch/arm/dts/mt7986-u-boot.dtsi
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+&topckgen {
+	u-boot,dm-pre-reloc;
+};
+
+&pericfg {
+	u-boot,dm-pre-reloc;
+};
+
+&apmixedsys {
+	u-boot,dm-pre-reloc;
+};
+
+&timer0 {
+	u-boot,dm-pre-reloc;
+};
+
+&uart0 {
+	u-boot,dm-pre-reloc;
+};
+
+&snand {
+	u-boot,dm-pre-reloc;
+};
+
+&pinctrl {
+	u-boot,dm-pre-reloc;
+};
diff --git a/arch/arm/dts/mt7986.dtsi b/arch/arm/dts/mt7986.dtsi
new file mode 100644
index 0000000..794ab1f
--- /dev/null
+++ b/arch/arm/dts/mt7986.dtsi
@@ -0,0 +1,350 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/clock/mt7986-clk.h>
+#include <dt-bindings/reset/mt7629-reset.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+
+/ {
+	compatible = "mediatek,mt7986";
+	interrupt-parent = <&gic>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	config {
+		u-boot,mmc-env-partition = "u-boot-env";
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0>;
+			mediatek,hwver = <&hwver>;
+		};
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x1>;
+			mediatek,hwver = <&hwver>;
+		};
+		cpu2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x2>;
+			mediatek,hwver = <&hwver>;
+		};
+		cpu3: cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x3>;
+			mediatek,hwver = <&hwver>;
+		};
+	};
+
+	dummy_clk: dummy12m {
+		compatible = "fixed-clock";
+		clock-frequency = <12000000>;
+		#clock-cells = <0>;
+		/* must need this line, or uart uanable to get dummy_clk */
+		u-boot,dm-pre-reloc;
+	};
+
+	hwver: hwver {
+		compatible = "mediatek,hwver", "syscon";
+		reg = <0x8000000 0x1000>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		clock-frequency = <13000000>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+		arm,cpu-registers-not-fw-configured;
+	};
+
+	timer0: timer@10008000 {
+		compatible = "mediatek,mt7986-timer";
+		reg = <0x10008000 0x1000>;
+		interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg CK_INFRA_CK_F26M>;
+		clock-names = "gpt-clk";
+		u-boot,dm-pre-reloc;
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7986-wdt";
+		reg = <0x1001c000 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+		status = "disabled";
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0x0c000000 0x40000>,  /* GICD */
+		      <0x0c080000 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	fixed_plls: apmixedsys@1001E000 {
+		compatible = "mediatek,mt7986-fixed-plls";
+		reg = <0x1001E000 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topckgen: topckgen@1001B000 {
+		compatible = "mediatek,mt7986-topckgen";
+		reg = <0x1001B000 0x1000>;
+		clock-parent = <&fixed_plls>;
+		#clock-cells = <1>;
+	};
+
+	infracfg_ao: infracfg_ao@10001000 {
+		compatible = "mediatek,mt7986-infracfg_ao";
+		reg = <0x10001000 0x68>;
+		clock-parent = <&infracfg>;
+		#clock-cells = <1>;
+	};
+
+	infracfg: infracfg@10001040 {
+		compatible = "mediatek,mt7986-infracfg";
+		reg = <0x10001000 0x1000>;
+		clock-parent = <&topckgen>;
+		#clock-cells = <1>;
+	};
+
+	pinctrl: pinctrl@1001f000 {
+		compatible = "mediatek,mt7986-pinctrl";
+		reg = <0x1001f000 0x1000>,
+		      <0x11c30000 0x1000>,
+		      <0x11c40000 0x1000>,
+		      <0x11e20000 0x1000>,
+		      <0x11e30000 0x1000>,
+		      <0x11f00000 0x1000>,
+		      <0x11f10000 0x1000>,
+		      <0x1000b000 0x1000>;
+		reg-names = "gpio_base", "iocfg_rt_base", "iocfg_rb_base",
+			    "iocfg_lt_base", "iocfg_lb_base", "iocfg_tr_base",
+			    "iocfg_tl_base", "eint";
+		gpio: gpio-controller {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+	};
+
+	pwm: pwm@10048000 {
+		compatible = "mediatek,mt7986-pwm";
+		reg = <0x10048000 0x1000>;
+		#clock-cells = <1>;
+		#pwm-cells = <2>;
+		interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg CK_INFRA_PWM>,
+			 <&infracfg_ao CK_INFRA_PWM_BSEL>,
+			 <&infracfg_ao CK_INFRA_PWM1_CK>,
+			 <&infracfg_ao CK_INFRA_PWM2_CK>;
+		assigned-clocks = <&topckgen CK_TOP_PWM_SEL>,
+				  <&infracfg CK_INFRA_PWM_BSEL>,
+				  <&infracfg CK_INFRA_PWM1_SEL>,
+				  <&infracfg CK_INFRA_PWM2_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D4>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>,
+					 <&infracfg CK_INFRA_PWM>;
+		clock-names = "top", "main", "pwm1", "pwm2";
+		status = "disabled";
+		u-boot,dm-pre-reloc;
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11002000 0x400>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART0_CK>;
+		assigned-clocks = <&topckgen CK_TOP_UART_SEL>,
+				  <&infracfg_ao CK_INFRA_UART0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_CKSQ_40M>,
+					 <&infracfg CK_INFRA_UART>;
+		mediatek,force-highspeed;
+		status = "disabled";
+		u-boot,dm-pre-reloc;
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11003000 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART1_CK>;
+		assigned-clocks = <&infracfg CK_INFRA_UART1_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		mediatek,force-highspeed;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11004000 0x400>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_UART2_CK>;
+		assigned-clocks = <&infracfg CK_INFRA_UART2_SEL>;
+		assigned-clock-parents = <&infracfg CK_INFRA_CK_F26M>;
+		mediatek,force-highspeed;
+		status = "disabled";
+	};
+
+	snand: snand@11005000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0x11005000 0x1000>,
+		      <0x11006000 0x1000>;
+		reg-names = "nfi", "ecc";
+		clocks = <&infracfg_ao CK_INFRA_SPINFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI1_CK>,
+			 <&infracfg_ao CK_INFRA_NFI_HCK_CK>;
+		clock-names = "pad_clk", "nfi_clk", "nfi_hclk";
+		assigned-clocks = <&topckgen CK_TOP_SPINFI_SEL>,
+				  <&topckgen CK_TOP_NFI1X_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D8>,
+					 <&topckgen CK_TOP_CB_M_D8>;
+		status = "disabled";
+	};
+
+	ethsys: syscon@15000000 {
+		compatible = "mediatek,mt7986-ethsys", "syscon";
+		reg = <0x15000000 0x1000>;
+		clock-parent = <&topckgen>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+	};
+
+	eth: ethernet@15100000 {
+		compatible = "mediatek,mt7986-eth", "syscon";
+		reg = <0x15100000 0x20000>;
+		resets = <&ethsys ETHSYS_FE_RST>;
+		reset-names = "fe";
+		mediatek,ethsys = <&ethsys>;
+		mediatek,sgmiisys = <&sgmiisys0>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	sgmiisys0: syscon@10060000 {
+		compatible = "mediatek,mt7986-sgmiisys", "syscon";
+		reg = <0x10060000 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@10070000 {
+		compatible = "mediatek,mt7986-sgmiisys", "syscon";
+		reg = <0x10070000 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	spi0: spi@1100a000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0x1100a000 0x100>;
+		clocks = <&infracfg_ao CK_INFRA_SPI0_CK>,
+			 <&topckgen CK_TOP_SPI_SEL>;
+		assigned-clocks = <&topckgen CK_TOP_SPI_SEL>,
+				  <&infracfg CK_INFRA_SPI0_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_D2>,
+					 <&topckgen CK_INFRA_ISPI0>;
+		clock-names = "sel-clk", "spi-clk";
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	spi1: spi@1100b000 {
+		compatible = "mediatek,ipm-spi";
+		reg = <0x1100b000 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+		compatible = "mediatek,mt7986-mmc";
+		reg = <0x11230000 0x1000>,
+		      <0x11C20000 0x1000>;
+		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_EMMC_416M>,
+			<&topckgen CK_TOP_EMMC_250M>,
+			<&infracfg_ao CK_INFRA_MSDC_CK>;
+		assigned-clocks = <&topckgen CK_TOP_EMMC_416M_SEL>,
+				  <&topckgen CK_TOP_EMMC_250M_SEL>;
+		assigned-clock-parents = <&topckgen CK_TOP_CB_M_416M>,
+					 <&topckgen CK_TOP_NET1_D5_D2>;
+		clock-names = "source", "hclk", "source_cg";
+		status = "disabled";
+	};
+
+	xhci: xhci@11200000 {
+		compatible = "mediatek,mt7986-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0x11200000 0x2e00>,
+		      <0x11203e00 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&u2port0 PHY_TYPE_USB2>,
+		       <&u3port0 PHY_TYPE_USB3>,
+		       <&u2port1 PHY_TYPE_USB2>;
+		clocks = <&dummy_clk>,
+			 <&dummy_clk>,
+			 <&dummy_clk>,
+			 <&dummy_clk>,
+			 <&dummy_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		tpl-support;
+		status = "okay";
+	};
+
+	usbtphy: usb-phy@11e10000 {
+		compatible = "mediatek,mt7986",
+			     "mediatek,generic-tphy-v2";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		status = "okay";
+
+		u2port0: usb-phy@11e10000 {
+			reg = <0x11e10000 0x700>;
+			clocks = <&dummy_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		u3port0: usb-phy@11e10700 {
+			reg = <0x11e10700 0x900>;
+			clocks = <&dummy_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		u2port1: usb-phy@11e11000 {
+			reg = <0x11e11000 0x700>;
+			clocks = <&dummy_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+	};
+};
diff --git a/arch/arm/dts/mt7986a-emmc-rfb.dts b/arch/arm/dts/mt7986a-emmc-rfb.dts
new file mode 100644
index 0000000..315bdd0
--- /dev/null
+++ b/arch/arm/dts/mt7986a-emmc-rfb.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7986a-rfb.dts"
+
+/ {
+	compatible = "mediatek,mt7986", "mediatek,mt7986-rfb",
+		     "mediatek,mt7986-emmc-rfb";
+	bl2_verify {
+		bl2_compatible = "emmc";
+	};
+};
diff --git a/arch/arm/dts/mt7986a-rfb.dts b/arch/arm/dts/mt7986a-rfb.dts
new file mode 100644
index 0000000..80def57
--- /dev/null
+++ b/arch/arm/dts/mt7986a-rfb.dts
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7986.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	model = "mt7986-rfb";
+	compatible = "mediatek,mt7986", "mediatek,mt7986-rfb";
+	chosen {
+		stdout-path = &uart0;
+		tick-timer = &timer0;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+	mediatek,gmac-id = <0>;
+	phy-mode = "sgmii";
+	mediatek,switch = "mt7531";
+	reset-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&pinctrl {
+	spi_flash_pins: spi0-pins-func-1 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+		};
+
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
+		};
+	};
+
+	snfi_pins: snfi-pins-func-1 {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+
+		clk {
+			pins = "SPI0_CLK";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pd {
+			pins = "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+
+	spic_pins: spi1-pins-func-1 {
+		mux {
+			function = "spi";
+			groups = "spi1_2";
+		};
+	};
+
+	uart1_pins: spi1-pins-func-3 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	pwm_pins: pwm0-pins-func-1 {
+		mux {
+			function = "pwm";
+			groups = "pwm0";
+		};
+	};
+
+	mmc0_pins_default: mmc0default {
+		mux {
+			function = "flash";
+			groups =  "emmc_51";
+		};
+
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		conf-dsl {
+			pins = "EMMC_DSL";
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+};
+
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	quad-spi;
+};
+
+&spi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	must_tx;
+	enhance_timing;
+	dma_ext;
+	ipm_design;
+	support_quad;
+	tick_dly = <2>;
+	sample_sel = <0>;
+
+	spi_nor@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+	};
+
+	spi_nand@1 {
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <52000000>;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_default>;
+	bus-width = <8>;
+	max-frequency = <52000000>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	non-removable;
+	status = "okay";
+};
diff --git a/arch/arm/dts/mt7986a-sd-rfb.dts b/arch/arm/dts/mt7986a-sd-rfb.dts
new file mode 100644
index 0000000..5807c5d
--- /dev/null
+++ b/arch/arm/dts/mt7986a-sd-rfb.dts
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7986.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	model = "mt7986-rfb";
+	compatible = "mediatek,mt7986", "mediatek,mt7986-rfb",
+		     "mediatek,mt7986-sd-rfb";
+	chosen {
+		stdout-path = &uart0;
+		tick-timer = &timer0;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+	mediatek,gmac-id = <0>;
+	phy-mode = "sgmii";
+	mediatek,switch = "mt7531";
+	reset-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&pinctrl {
+	spi_flash_pins: spi0-pins-func-1 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+		};
+
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
+		};
+	};
+
+	spic_pins: spi1-pins-func-1 {
+		mux {
+			function = "spi";
+			groups = "spi1_2";
+		};
+	};
+
+	uart1_pins: spi1-pins-func-3 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	pwm_pins: pwm0-pins-func-1 {
+		mux {
+			function = "pwm";
+			groups = "pwm0";
+		};
+	};
+
+	mmc0_pins_default: mmc0default {
+		mux {
+			function = "flash";
+			groups =  "emmc_51";
+		};
+
+		conf-cmd-dat {
+			pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2",
+			       "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5",
+			       "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		conf-clk {
+			pins = "EMMC_CK";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		conf-dsl {
+			pins = "EMMC_DSL";
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		conf-rst {
+			pins = "EMMC_RSTB";
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+};
+
+&spi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	must_tx;
+	enhance_timing;
+	dma_ext;
+	ipm_design;
+	support_quad;
+	tick_dly = <2>;
+	sample_sel = <0>;
+
+	spi_nor@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+	};
+
+	spi_nand@1 {
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <52000000>;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_default>;
+	bus-width = <4>;
+	max-frequency = <52000000>;
+	cap-sd-highspeed;
+	r_smpl = <1>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
diff --git a/arch/arm/dts/mt7986b-emmc-rfb.dts b/arch/arm/dts/mt7986b-emmc-rfb.dts
new file mode 100644
index 0000000..315bdd0
--- /dev/null
+++ b/arch/arm/dts/mt7986b-emmc-rfb.dts
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7986a-rfb.dts"
+
+/ {
+	compatible = "mediatek,mt7986", "mediatek,mt7986-rfb",
+		     "mediatek,mt7986-emmc-rfb";
+	bl2_verify {
+		bl2_compatible = "emmc";
+	};
+};
diff --git a/arch/arm/dts/mt7986b-rfb.dts b/arch/arm/dts/mt7986b-rfb.dts
new file mode 100644
index 0000000..0c4e3e8
--- /dev/null
+++ b/arch/arm/dts/mt7986b-rfb.dts
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7986.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	model = "mt7986-rfb";
+	compatible = "mediatek,mt7986", "mediatek,mt7986-rfb";
+	chosen {
+		stdout-path = &uart0;
+		tick-timer = &timer0;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+	mediatek,gmac-id = <0>;
+	phy-mode = "sgmii";
+	mediatek,switch = "mt7531";
+	reset-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&pinctrl {
+	spi_flash_pins: spi0-pins-func-1 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+		};
+
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
+		};
+	};
+
+	snfi_pins: snfi-pins-func-1 {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+
+		clk {
+			pins = "SPI0_CLK";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pu {
+			pins = "SPI0_CS", "SPI0_HOLD", "SPI0_WP";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_00>;
+		};
+
+		conf-pd {
+			pins = "SPI0_MOSI", "SPI0_MISO";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_00>;
+		};
+	};
+
+	spic_pins: spi1-pins-func-1 {
+		mux {
+			function = "spi";
+			groups = "spi1_2";
+		};
+	};
+
+	uart1_pins: spi1-pins-func-3 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	pwm_pins: pwm0-pins-func-1 {
+		mux {
+			function = "pwm";
+			groups = "pwm0";
+		};
+	};
+
+	mmc0_pins_default: mmc0default {
+		mux {
+			function = "flash";
+			groups =  "emmc_45";
+			input-schmitt-enable;
+		};
+
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+};
+
+&snand {
+	pinctrl-names = "default";
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	quad-spi;
+};
+
+&spi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	must_tx;
+	enhance_timing;
+	dma_ext;
+	ipm_design;
+	support_quad;
+	tick_dly = <2>;
+	sample_sel = <0>;
+
+	spi_nor@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+	};
+
+	spi_nand@1 {
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <52000000>;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_default>;
+	bus-width = <8>;
+	max-frequency = <52000000>;
+	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
+	vmmc-supply = <&reg_3p3v>;
+	non-removable;
+	status = "okay";
+};
diff --git a/arch/arm/dts/mt7986b-sd-rfb.dts b/arch/arm/dts/mt7986b-sd-rfb.dts
new file mode 100644
index 0000000..48f9320
--- /dev/null
+++ b/arch/arm/dts/mt7986b-sd-rfb.dts
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7986.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	model = "mt7986-rfb";
+	compatible = "mediatek,mt7986", "mediatek,mt7986-rfb",
+		     "mediatek,mt7986-sd-rfb";
+	chosen {
+		stdout-path = &uart0;
+		tick-timer = &timer0;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+	mediatek,gmac-id = <0>;
+	phy-mode = "sgmii";
+	mediatek,switch = "mt7531";
+	reset-gpios = <&gpio 5 GPIO_ACTIVE_HIGH>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&pinctrl {
+	spi_flash_pins: spi0-pins-func-1 {
+		mux {
+			function = "flash";
+			groups = "spi0", "spi0_wp_hold";
+		};
+
+		conf-pu {
+			pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
+		};
+
+		conf-pd {
+			pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
+			drive-strength = <MTK_DRIVE_8mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
+		};
+	};
+
+	spic_pins: spi1-pins-func-1 {
+		mux {
+			function = "spi";
+			groups = "spi1_2";
+		};
+	};
+
+	uart1_pins: spi1-pins-func-3 {
+		mux {
+			function = "uart";
+			groups = "uart1_2";
+		};
+	};
+
+	pwm_pins: pwm0-pins-func-1 {
+		mux {
+			function = "pwm";
+			groups = "pwm0";
+		};
+	};
+
+	mmc0_pins_default: mmc0default {
+		mux {
+			function = "flash";
+			groups =  "emmc_45";
+			input-schmitt-enable;
+		};
+
+		conf-cmd-dat {
+			pins = "SPI0_CLK", "SPI0_MOSI", "SPI0_MISO",
+			       "SPI0_CS", "SPI0_HOLD", "SPI0_WP",
+			       "SPI1_CLK", "SPI1_MOSI", "SPI1_MISO";
+			input-enable;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		conf-clk {
+			pins = "SPI1_CS";
+			drive-strength = <MTK_DRIVE_6mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
+		};
+
+		conf-rst {
+			pins = "PWM1";
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
+		};
+	};
+};
+
+&spi0 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_flash_pins>;
+	status = "okay";
+	must_tx;
+	enhance_timing;
+	dma_ext;
+	ipm_design;
+	support_quad;
+	tick_dly = <2>;
+	sample_sel = <0>;
+
+	spi_nor@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+	};
+
+	spi_nand@1 {
+		compatible = "spi-nand";
+		reg = <1>;
+		spi-max-frequency = <52000000>;
+	};
+};
+
+&pwm {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_default>;
+	bus-width = <4>;
+	max-frequency = <52000000>;
+	cap-sd-highspeed;
+	r_smpl = <1>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	status = "okay";
+};
diff --git a/arch/arm/include/asm/arch-imx8m/imx-regs.h b/arch/arm/include/asm/arch-imx8m/imx-regs.h
index ff3b9dd..29d5baa 100644
--- a/arch/arm/include/asm/arch-imx8m/imx-regs.h
+++ b/arch/arm/include/asm/arch-imx8m/imx-regs.h
@@ -27,6 +27,7 @@
 #define IOMUXC_GPR_BASE_ADDR	0x30340000
 #define OCOTP_BASE_ADDR		0x30350000
 #define ANATOP_BASE_ADDR	0x30360000
+#define SNVS_BASE_ADDR		0x30370000
 #define CCM_BASE_ADDR		0x30380000
 #define SRC_BASE_ADDR		0x30390000
 #define GPC_BASE_ADDR		0x303A0000
@@ -113,6 +114,10 @@
 #define SRC_DDR1_RCR_CORE_RESET_N_MASK	BIT(1)
 #define SRC_DDR1_RCR_PRESET_N_MASK	BIT(0)
 
+#define SNVS_LPSR			0x4c
+#define SNVS_LPLVDR			0x64
+#define SNVS_LPPGDR_INIT		0x41736166
+
 struct iomuxc_gpr_base_regs {
 	u32 gpr[47];
 };
diff --git a/arch/arm/mach-imx/imx8m/soc.c b/arch/arm/mach-imx/imx8m/soc.c
index d115b25..a486328 100644
--- a/arch/arm/mach-imx/imx8m/soc.c
+++ b/arch/arm/mach-imx/imx8m/soc.c
@@ -327,7 +327,7 @@
 	}
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	ulong top_addr;
 
@@ -544,6 +544,16 @@
 }
 EVENT_SPY(EVT_DM_POST_INIT, imx8m_check_clock);
 
+static void imx8m_setup_snvs(void)
+{
+	/* Enable SNVS clock */
+	clock_enable(CCGR_SNVS, 1);
+	/* Initialize glitch detect */
+	writel(SNVS_LPPGDR_INIT, SNVS_BASE_ADDR + SNVS_LPLVDR);
+	/* Clear interrupt status */
+	writel(0xffffffff, SNVS_BASE_ADDR + SNVS_LPSR);
+}
+
 int arch_cpu_init(void)
 {
 	struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
@@ -594,6 +604,8 @@
 			writel(0x200, &ocotp->ctrl_clr);
 	}
 
+	imx8m_setup_snvs();
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
index f79a5c6..04aa2fd 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -40,6 +40,24 @@
 	  including DDR3, crypto engine, 3x3 11n/ac Wi-Fi, Gigabit Ethernet,
 	  switch, USB3.0, PCIe, UART, SPI, I2C and PWM.
 
+config TARGET_MT7981
+	bool "MediaTek MT7981 SoC"
+	select ARM64
+	select CPU
+	help
+	  The MediaTek MT7981 is a ARM64-based SoC with a dual-core Cortex-A53.
+	  including UART, SPI, USB, NAND, SNFI, PWM, Gigabit Ethernet, I2C,
+          built-in Wi-Fi, and PCIe.
+
+config TARGET_MT7986
+	bool "MediaTek MT7986 SoC"
+	select ARM64
+	select CPU
+	help
+	  The MediaTek MT7986 is a ARM64-based SoC with a quad-core Cortex-A53.
+	  including UART, SPI, SPI flash, USB3.0, MMC, NAND, SNFI, PWM, PCIe,
+	  Gigabit Ethernet, I2C, built-in 4x4 Wi-Fi, and PCIe.
+
 config TARGET_MT8183
 	bool "MediaTek MT8183 SoC"
 	select ARM64
@@ -84,6 +102,8 @@
 	default "mt7622" if TARGET_MT7622
 	default "mt7623" if TARGET_MT7623
 	default "mt7629" if TARGET_MT7629
+	default "mt7981" if TARGET_MT7981
+	default "mt7986" if TARGET_MT7986
 	default "mt8183" if TARGET_MT8183
 	default "mt8512" if TARGET_MT8512
 	default "mt8516" if TARGET_MT8516
@@ -99,6 +119,8 @@
 	default "mt7622" if TARGET_MT7622
 	default "mt7623" if TARGET_MT7623
 	default "mt7629" if TARGET_MT7629
+	default "mt7981" if TARGET_MT7981
+	default "mt7986" if TARGET_MT7986
 	default "mt8183" if TARGET_MT8183
 	default "mt8512" if TARGET_MT8512
 	default "mt8516" if TARGET_MT8516
@@ -113,6 +135,7 @@
 	string
 	default "media=nor" if TARGET_MT8518 || TARGET_MT8512 || TARGET_MT7629 || TARGET_MT7622
 	default "media=emmc" if TARGET_MT8516 || TARGET_MT8365 || TARGET_MT8183
+	default "media=snand;nandinfo=2k+64" if TARGET_MT7981 || TARGET_MT7986
 	default "lk=1" if TARGET_MT7623
 
 endif
diff --git a/arch/arm/mach-mediatek/Makefile b/arch/arm/mach-mediatek/Makefile
index 0f5b0c1..fc85293 100644
--- a/arch/arm/mach-mediatek/Makefile
+++ b/arch/arm/mach-mediatek/Makefile
@@ -7,6 +7,8 @@
 obj-$(CONFIG_TARGET_MT7622) += mt7622/
 obj-$(CONFIG_TARGET_MT7623) += mt7623/
 obj-$(CONFIG_TARGET_MT7629) += mt7629/
+obj-$(CONFIG_TARGET_MT7981) += mt7981/
+obj-$(CONFIG_TARGET_MT7986) += mt7986/
 obj-$(CONFIG_TARGET_MT8183) += mt8183/
 obj-$(CONFIG_TARGET_MT8516) += mt8516/
 obj-$(CONFIG_TARGET_MT8518) += mt8518/
diff --git a/arch/arm/mach-mediatek/mt7981/Makefile b/arch/arm/mach-mediatek/mt7981/Makefile
new file mode 100644
index 0000000..007eb4a
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7981/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier:	GPL-2.0
+
+obj-y += init.o
+obj-y += lowlevel_init.o
diff --git a/arch/arm/mach-mediatek/mt7981/init.c b/arch/arm/mach-mediatek/mt7981/init.c
new file mode 100644
index 0000000..4f77a3d
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7981/init.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include <init.h>
+#include <asm/armv8/mmu.h>
+#include <asm/system.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_2G);
+
+	return 0;
+}
+
+void reset_cpu(ulong addr)
+{
+	psci_system_reset();
+}
+
+static struct mm_region mt7981_mem_map[] = {
+	{
+		/* DDR */
+		.virt = 0x40000000UL,
+		.phys = 0x40000000UL,
+		.size = 0x80000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_OUTER_SHARE,
+	}, {
+		.virt = 0x00000000UL,
+		.phys = 0x00000000UL,
+		.size = 0x40000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		0,
+	}
+};
+
+struct mm_region *mem_map = mt7981_mem_map;
diff --git a/arch/arm/mach-mediatek/mt7981/lowlevel_init.S b/arch/arm/mach-mediatek/mt7981/lowlevel_init.S
new file mode 100644
index 0000000..85a1cea
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7981/lowlevel_init.S
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/*
+ * Switch from AArch64 EL2 to AArch32 EL2
+ * @param inputs:
+ * x0: argument, zero
+ * x1: machine nr
+ * x2: fdt address
+ * x3: input argument
+ * x4: kernel entry point
+ * @param outputs for secure firmware:
+ * x0: function id
+ * x1: kernel entry point
+ * x2: machine nr
+ * x3: fdt address
+ *
+ * [1] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/mediatek/common/mtk_sip_svc.c
+*/
+
+.global armv8_el2_to_aarch32
+armv8_el2_to_aarch32:
+	mov	x3, x2
+	mov	x2, x1
+	mov	x1, x4
+	mov	x4, #0
+	ldr	x0, =0x82000200	/* MTK_SIP_KERNEL_BOOT_AARCH32 */
+	SMC	#0
+	ret
diff --git a/arch/arm/mach-mediatek/mt7986/Makefile b/arch/arm/mach-mediatek/mt7986/Makefile
new file mode 100644
index 0000000..007eb4a
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7986/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier:	GPL-2.0
+
+obj-y += init.o
+obj-y += lowlevel_init.o
diff --git a/arch/arm/mach-mediatek/mt7986/init.c b/arch/arm/mach-mediatek/mt7986/init.c
new file mode 100644
index 0000000..0fd4596
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7986/init.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include <init.h>
+#include <asm/armv8/mmu.h>
+#include <asm/system.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_2G);
+
+	return 0;
+}
+
+void reset_cpu(ulong addr)
+{
+	psci_system_reset();
+}
+
+static struct mm_region mt7986_mem_map[] = {
+	{
+		/* DDR */
+		.virt = 0x40000000UL,
+		.phys = 0x40000000UL,
+		.size = 0x80000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_OUTER_SHARE,
+	}, {
+		.virt = 0x00000000UL,
+		.phys = 0x00000000UL,
+		.size = 0x40000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		0,
+	}
+};
+
+struct mm_region *mem_map = mt7986_mem_map;
diff --git a/arch/arm/mach-mediatek/mt7986/lowlevel_init.S b/arch/arm/mach-mediatek/mt7986/lowlevel_init.S
new file mode 100644
index 0000000..85a1cea
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7986/lowlevel_init.S
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+/*
+ * Switch from AArch64 EL2 to AArch32 EL2
+ * @param inputs:
+ * x0: argument, zero
+ * x1: machine nr
+ * x2: fdt address
+ * x3: input argument
+ * x4: kernel entry point
+ * @param outputs for secure firmware:
+ * x0: function id
+ * x1: kernel entry point
+ * x2: machine nr
+ * x3: fdt address
+ *
+ * [1] https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/plat/mediatek/common/mtk_sip_svc.c
+*/
+
+.global armv8_el2_to_aarch32
+armv8_el2_to_aarch32:
+	mov	x3, x2
+	mov	x2, x1
+	mov	x1, x4
+	mov	x4, #0
+	ldr	x0, =0x82000200	/* MTK_SIP_KERNEL_BOOT_AARCH32 */
+	SMC	#0
+	ret
diff --git a/arch/arm/mach-mvebu/arm64-common.c b/arch/arm/mach-mvebu/arm64-common.c
index 238edbe..63f6af5 100644
--- a/arch/arm/mach-mvebu/arm64-common.c
+++ b/arch/arm/mach-mvebu/arm64-common.c
@@ -30,7 +30,7 @@
  */
 #define USABLE_RAM_SIZE		0x80000000ULL
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	unsigned long top = CONFIG_SYS_SDRAM_BASE + min(gd->ram_size, USABLE_RAM_SIZE);
 
diff --git a/arch/arm/mach-rockchip/sdram.c b/arch/arm/mach-rockchip/sdram.c
index 705ec7b..12f1d7e 100644
--- a/arch/arm/mach-rockchip/sdram.c
+++ b/arch/arm/mach-rockchip/sdram.c
@@ -205,7 +205,7 @@
 	return 0;
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	unsigned long top = CONFIG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE;
 
diff --git a/arch/arm/mach-stm32mp/dram_init.c b/arch/arm/mach-stm32mp/dram_init.c
index 920b99b..9346fa8 100644
--- a/arch/arm/mach-stm32mp/dram_init.c
+++ b/arch/arm/mach-stm32mp/dram_init.c
@@ -40,7 +40,7 @@
 	return 0;
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	phys_size_t size;
 	phys_addr_t reg;
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 8f7c894..62bb40b 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -65,7 +65,7 @@
 };
 struct mm_region *mem_map = sunxi_mem_map;
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	/* Some devices (like the EMAC) have a 32-bit DMA limit. */
 	if (gd->ram_top > (1ULL << 32))
diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c
index 8950e67..1994db0 100644
--- a/arch/arm/mach-tegra/board2.c
+++ b/arch/arm/mach-tegra/board2.c
@@ -401,7 +401,7 @@
  * This function is called before dram_init_banksize(), so we can't simply
  * return gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size.
  */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	ulong ram_top;
 
diff --git a/arch/mips/mach-jz47xx/jz4780/jz4780.c b/arch/mips/mach-jz47xx/jz4780/jz4780.c
index fefba12..a57ec78 100644
--- a/arch/mips/mach-jz47xx/jz4780/jz4780.c
+++ b/arch/mips/mach-jz47xx/jz4780/jz4780.c
@@ -76,7 +76,7 @@
 }
 #endif /* CONFIG_SPL_BUILD */
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	return CONFIG_SYS_SDRAM_BASE + (256 * 1024 * 1024);
 }
diff --git a/arch/mips/mach-octeon/dram.c b/arch/mips/mach-octeon/dram.c
index 4679260..9c5789b 100644
--- a/arch/mips/mach-octeon/dram.c
+++ b/arch/mips/mach-octeon/dram.c
@@ -77,7 +77,7 @@
 	return UBOOT_RAM_SIZE_MAX;
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	if (IS_ENABLED(CONFIG_RAM_OCTEON)) {
 		/* Map a maximum of 256MiB - return not size but address */
diff --git a/arch/powerpc/cpu/mpc85xx/tlb.c b/arch/powerpc/cpu/mpc85xx/tlb.c
index ab61649..e39fe14 100644
--- a/arch/powerpc/cpu/mpc85xx/tlb.c
+++ b/arch/powerpc/cpu/mpc85xx/tlb.c
@@ -312,7 +312,10 @@
 	if (size || memsize > CONFIG_MAX_MEM_MAPPED) {
 		print_size(memsize > CONFIG_MAX_MEM_MAPPED ?
 			   memsize - CONFIG_MAX_MEM_MAPPED + size : size,
-			   " left unmapped\n");
+			   " of DDR memory left unmapped in U-Boot\n");
+#ifndef CONFIG_SPL_BUILD
+		puts("       ");
+#endif
 	}
 
 	return memsize_in_meg;
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 78e964d..32a90b8 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -269,6 +269,20 @@
 	  from a NOR flash memory without copying the code to ram.
 	  Say yes here if U-Boot boots from flash directly.
 
+config SPL_XIP
+	bool "Enable XIP mode for SPL"
+	help
+	  If SPL starts in read-only memory (XIP for example) then we shouldn't
+	  rely on lock variables (for example hart_lottery and available_harts_lock),
+	  this affects only SPL, other stages should proceed as non-XIP.
+
+config AVAILABLE_HARTS
+	bool "Send IPI by available harts"
+	default y
+	help
+	  By default, IPI sending mechanism will depend on available_harts.
+	  If disable this, it will send IPI by CPUs node numbers of device tree.
+
 config SHOW_REGS
 	bool "Show registers on unhandled exception"
 
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index 3ffcbbd..52ab025 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -19,15 +19,17 @@
  * The variables here must be stored in the data section since they are used
  * before the bss section is available.
  */
-#ifndef CONFIG_XIP
+#if !CONFIG_IS_ENABLED(XIP)
 u32 hart_lottery __section(".data") = 0;
 
+#ifdef CONFIG_AVAILABLE_HARTS
 /*
  * The main hart running U-Boot has acquired available_harts_lock until it has
  * finished initialization of global data.
  */
 u32 available_harts_lock = 1;
 #endif
+#endif
 
 static inline bool supports_extension(char ext)
 {
diff --git a/arch/riscv/cpu/fu540/dram.c b/arch/riscv/cpu/fu540/dram.c
index 1fdc783..44e11bd 100644
--- a/arch/riscv/cpu/fu540/dram.c
+++ b/arch/riscv/cpu/fu540/dram.c
@@ -21,7 +21,7 @@
 	return fdtdec_setup_memory_banksize();
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	/*
 	 * Ensure that we run from first 4GB so that all
diff --git a/arch/riscv/cpu/fu740/dram.c b/arch/riscv/cpu/fu740/dram.c
index 1dc77ef..d6d4a41 100644
--- a/arch/riscv/cpu/fu740/dram.c
+++ b/arch/riscv/cpu/fu740/dram.c
@@ -20,7 +20,7 @@
 	return fdtdec_setup_memory_banksize();
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 #ifdef CONFIG_64BIT
 	/*
diff --git a/arch/riscv/cpu/generic/dram.c b/arch/riscv/cpu/generic/dram.c
index 1fdc783..44e11bd 100644
--- a/arch/riscv/cpu/generic/dram.c
+++ b/arch/riscv/cpu/generic/dram.c
@@ -21,7 +21,7 @@
 	return fdtdec_setup_memory_banksize();
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	/*
 	 * Ensure that we run from first 4GB so that all
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index b7f21ab..4687bca 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -122,7 +122,7 @@
 call_harts_early_init:
 	jal	harts_early_init
 
-#ifndef CONFIG_XIP
+#if !CONFIG_IS_ENABLED(XIP)
 	/*
 	 * Pick hart to initialize global data and run U-Boot. The other harts
 	 * wait for initialization to complete.
@@ -152,22 +152,24 @@
 	/* save the boot hart id to global_data */
 	SREG	tp, GD_BOOT_HART(gp)
 
-#ifndef CONFIG_XIP
+#if !CONFIG_IS_ENABLED(XIP)
+#ifdef CONFIG_AVAILABLE_HARTS
 	la	t0, available_harts_lock
 	amoswap.w.rl zero, zero, 0(t0)
+#endif
 
 wait_for_gd_init:
-	la	t0, available_harts_lock
-	li	t1, 1
-1:	amoswap.w.aq t1, t1, 0(t0)
-	bnez	t1, 1b
-
 	/*
 	 * Set the global data pointer only when gd_t has been initialized.
 	 * This was already set by arch_setup_gd on the boot hart, but all other
 	 * harts' global data pointers gets set here.
 	 */
 	mv	gp, s0
+#ifdef CONFIG_AVAILABLE_HARTS
+	la	t0, available_harts_lock
+	li	t1, 1
+1:	amoswap.w.aq t1, t1, 0(t0)
+	bnez	t1, 1b
 
 	/* register available harts in the available_harts mask */
 	li	t1, 1
@@ -177,6 +179,7 @@
 	SREG	t2, GD_AVAILABLE_HARTS(gp)
 
 	amoswap.w.rl zero, zero, 0(t0)
+#endif
 
 	/*
 	 * Continue on hart lottery winner, others branch to
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
index 095484a..858594a 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -27,9 +27,11 @@
 #if CONFIG_IS_ENABLED(SMP)
 	struct ipi_data ipi[CONFIG_NR_CPUS];
 #endif
-#ifndef CONFIG_XIP
+#if !CONFIG_IS_ENABLED(XIP)
+#ifdef CONFIG_AVAILABLE_HARTS
 	ulong available_harts;
 #endif
+#endif
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c
index f1fe089..452dfce 100644
--- a/arch/riscv/lib/asm-offsets.c
+++ b/arch/riscv/lib/asm-offsets.c
@@ -16,9 +16,11 @@
 {
 	DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
 	DEFINE(GD_FIRMWARE_FDT_ADDR, offsetof(gd_t, arch.firmware_fdt_addr));
-#ifndef CONFIG_XIP
+#if !CONFIG_IS_ENABLED(XIP)
+#ifdef CONFIG_AVAILABLE_HARTS
 	DEFINE(GD_AVAILABLE_HARTS, offsetof(gd_t, arch.available_harts));
 #endif
+#endif
 
 	return 0;
 }
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
index ba99210..c0f65af 100644
--- a/arch/riscv/lib/smp.c
+++ b/arch/riscv/lib/smp.c
@@ -45,11 +45,13 @@
 			continue;
 		}
 
-#ifndef CONFIG_XIP
+#if !CONFIG_IS_ENABLED(XIP)
+#ifdef CONFIG_AVAILABLE_HARTS
 		/* skip if hart is not available */
 		if (!(gd->arch.available_harts & (1 << reg)))
 			continue;
 #endif
+#endif
 
 		gd->arch.ipi[reg].addr = ipi->addr;
 		gd->arch.ipi[reg].arg0 = ipi->arg0;
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index f937991..d6170ad 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -669,6 +669,11 @@
 		os_putc(*str++);
 }
 
+void os_flush(void)
+{
+	fflush(stdout);
+}
+
 int os_write_ram_buf(const char *fname)
 {
 	struct sandbox_state *state = state_get_current();
@@ -1012,8 +1017,24 @@
 	return base;
 }
 
+/**
+ * os_unblock_signals() - unblock all signals
+ *
+ * If we are relaunching the sandbox in a signal handler, we have to unblock
+ * the respective signal before calling execv(). See signal(7) man-page.
+ */
+static void os_unblock_signals(void)
+{
+	sigset_t sigs;
+
+	sigfillset(&sigs);
+	sigprocmask(SIG_UNBLOCK, &sigs, NULL);
+}
+
 void os_relaunch(char *argv[])
 {
+	os_unblock_signals();
+
 	execv(argv[0], argv);
 	os_exit(1);
 }
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index 56e6b38..de7a218 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -245,6 +245,10 @@
 		compatible = "sandbox,sandbox-rng";
 	};
 
+	scsi {
+		compatible = "sandbox,scsi";
+	};
+
 	sound {
 		compatible = "sandbox,sound";
 		cpu {
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index c7fffa2..4ee4712 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1158,6 +1158,11 @@
 		backlight = <&backlight 0 100>;
 	};
 
+	scsi {
+		compatible = "sandbox,scsi";
+		sandbox,filepath = "scsi.img";
+	};
+
 	smem@0 {
 		compatible = "sandbox,smem";
 	};
diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c
index c104a84..1295121 100644
--- a/arch/x86/cpu/broadwell/sdram.c
+++ b/arch/x86/cpu/broadwell/sdram.c
@@ -25,7 +25,7 @@
 #include <asm/arch/pei_data.h>
 #include <asm/arch/pm.h>
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	return mrc_common_board_get_usable_ram_top(total_size);
 }
diff --git a/arch/x86/cpu/coreboot/sdram.c b/arch/x86/cpu/coreboot/sdram.c
index 4a256ba..f4ee4cd 100644
--- a/arch/x86/cpu/coreboot/sdram.c
+++ b/arch/x86/cpu/coreboot/sdram.c
@@ -27,7 +27,7 @@
  * address, and how far U-Boot is moved by relocation are set in the global
  * data structure.
  */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	uintptr_t dest_addr = 0;
 	int i;
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c
index b777856..1c28a43 100644
--- a/arch/x86/cpu/efi/payload.c
+++ b/arch/x86/cpu/efi/payload.c
@@ -27,7 +27,7 @@
  * the relocation address, and how far U-Boot is moved by relocation are
  * set in the global data structure.
  */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	struct efi_mem_desc *desc, *end;
 	struct efi_entry_memmap *map;
diff --git a/arch/x86/cpu/efi/sdram.c b/arch/x86/cpu/efi/sdram.c
index af65982..f3086db 100644
--- a/arch/x86/cpu/efi/sdram.c
+++ b/arch/x86/cpu/efi/sdram.c
@@ -11,7 +11,7 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	return (ulong)efi_get_ram_base() + gd->ram_size;
 }
diff --git a/arch/x86/cpu/intel_common/mrc.c b/arch/x86/cpu/intel_common/mrc.c
index a97b0b7..a4918fb 100644
--- a/arch/x86/cpu/intel_common/mrc.c
+++ b/arch/x86/cpu/intel_common/mrc.c
@@ -25,7 +25,7 @@
 	"active"
 };
 
-ulong mrc_common_board_get_usable_ram_top(ulong total_size)
+phys_size_t mrc_common_board_get_usable_ram_top(phys_size_t total_size)
 {
 	struct memory_info *info = &gd->arch.meminfo;
 	uintptr_t dest_addr = 0;
@@ -50,7 +50,7 @@
 
 	dest_addr = largest->start + largest->size;
 
-	return (ulong)dest_addr;
+	return (phys_size_t)dest_addr;
 }
 
 void mrc_common_dram_init_banksize(void)
diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c
index dd6b875..1a0ec43 100644
--- a/arch/x86/cpu/ivybridge/sdram.c
+++ b/arch/x86/cpu/ivybridge/sdram.c
@@ -44,7 +44,7 @@
 #define CMOS_OFFSET_MRC_SEED_S3		156
 #define CMOS_OFFSET_MRC_SEED_CHK	160
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	return mrc_common_board_get_usable_ram_top(total_size);
 }
diff --git a/arch/x86/cpu/qemu/dram.c b/arch/x86/cpu/qemu/dram.c
index c174550..595c397 100644
--- a/arch/x86/cpu/qemu/dram.c
+++ b/arch/x86/cpu/qemu/dram.c
@@ -71,7 +71,7 @@
  * the relocation address, and how far U-Boot is moved by relocation are
  * set in the global data structure.
  */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	return qemu_get_low_memory_size();
 }
diff --git a/arch/x86/cpu/quark/dram.c b/arch/x86/cpu/quark/dram.c
index 2287dce..8b1ee2d 100644
--- a/arch/x86/cpu/quark/dram.c
+++ b/arch/x86/cpu/quark/dram.c
@@ -184,7 +184,7 @@
  * the relocation address, and how far U-Boot is moved by relocation are
  * set in the global data structure.
  */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	return gd->ram_size;
 }
diff --git a/arch/x86/cpu/slimbootloader/sdram.c b/arch/x86/cpu/slimbootloader/sdram.c
index c6f10e2..d748d5c 100644
--- a/arch/x86/cpu/slimbootloader/sdram.c
+++ b/arch/x86/cpu/slimbootloader/sdram.c
@@ -48,7 +48,7 @@
  * @total_size: The memory size that u-boot occupies
  * Return:    : The top available memory address lower than 4GB
  */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	struct sbl_memory_map_info *data;
 	int i;
diff --git a/arch/x86/cpu/tangier/sdram.c b/arch/x86/cpu/tangier/sdram.c
index afb0847..8a4b1c5 100644
--- a/arch/x86/cpu/tangier/sdram.c
+++ b/arch/x86/cpu/tangier/sdram.c
@@ -204,7 +204,7 @@
  * address, and how far U-Boot is moved by relocation are set in the global
  * data structure.
  */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	struct sfi_table_simple *sb;
 	struct sfi_mem_entry *mentry;
diff --git a/arch/x86/include/asm/mrc_common.h b/arch/x86/include/asm/mrc_common.h
index 3d7f00c..a7f260a 100644
--- a/arch/x86/include/asm/mrc_common.h
+++ b/arch/x86/include/asm/mrc_common.h
@@ -47,7 +47,7 @@
  * the relocation address, and how far U-Boot is moved by relocation are
  * set in the global data structure.
  */
-ulong mrc_common_board_get_usable_ram_top(ulong total_size);
+phys_size_t mrc_common_board_get_usable_ram_top(phys_size_t total_size);
 
 void mrc_common_dram_init_banksize(void);
 
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h
index a1655e1..4cf41e9 100644
--- a/arch/x86/include/asm/u-boot-x86.h
+++ b/arch/x86/include/asm/u-boot-x86.h
@@ -77,7 +77,7 @@
 void x86_enable_caches(void);
 void x86_disable_caches(void);
 int x86_init_cache(void);
-ulong board_get_usable_ram_top(ulong total_size);
+phys_size_t board_get_usable_ram_top(phys_size_t total_size);
 int default_print_cpuinfo(void);
 
 /* Set up a UART which can be used with printch(), printhex8(), etc. */
diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c
index cfd9b9f..5825221 100644
--- a/arch/x86/lib/fsp1/fsp_dram.c
+++ b/arch/x86/lib/fsp1/fsp_dram.c
@@ -34,7 +34,7 @@
  * the relocation address, and how far U-Boot is moved by relocation are
  * set in the global data structure.
  */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	return fsp_get_usable_lowmem_top(gd->arch.hob_list);
 }
diff --git a/arch/x86/lib/fsp2/fsp_dram.c b/arch/x86/lib/fsp2/fsp_dram.c
index 42d3892..f9ea1ab 100644
--- a/arch/x86/lib/fsp2/fsp_dram.c
+++ b/arch/x86/lib/fsp2/fsp_dram.c
@@ -77,7 +77,7 @@
 	return 0;
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	if (!ll_boot_init())
 		return gd->ram_size;
diff --git a/board/broadcom/bcmns3/ns3.c b/board/broadcom/bcmns3/ns3.c
index 88036c1..26652e8 100644
--- a/board/broadcom/bcmns3/ns3.c
+++ b/board/broadcom/bcmns3/ns3.c
@@ -183,7 +183,7 @@
 }
 
 /* Limit RAM used by U-Boot to the DDR first bank End region */
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	return BCM_NS3_MEM_END;
 }
diff --git a/board/data_modul/imx8mm_edm_sbc/imx8mm_data_modul_edm_sbc.c b/board/data_modul/imx8mm_edm_sbc/imx8mm_data_modul_edm_sbc.c
index 6dc4e6a..dc08830 100644
--- a/board/data_modul/imx8mm_edm_sbc/imx8mm_data_modul_edm_sbc.c
+++ b/board/data_modul/imx8mm_edm_sbc/imx8mm_data_modul_edm_sbc.c
@@ -34,22 +34,6 @@
 	return 0;
 }
 
-/* IMX8M SNVS registers needed for the bootcount functionality */
-#define SNVS_BASE_ADDR			0x30370000
-#define SNVS_LPSR			0x4c
-#define SNVS_LPLVDR			0x64
-#define SNVS_LPPGDR_INIT		0x41736166
-
-static void setup_snvs(void)
-{
-	/* Enable SNVS clock */
-	clock_enable(CCGR_SNVS, 1);
-	/* Initialize glitch detect */
-	writel(SNVS_LPPGDR_INIT, SNVS_BASE_ADDR + SNVS_LPLVDR);
-	/* Clear interrupt status */
-	writel(0xffffffff, SNVS_BASE_ADDR + SNVS_LPSR);
-}
-
 static void setup_mac_address(void)
 {
 	unsigned char enetaddr[6];
@@ -99,7 +83,6 @@
 
 int board_init(void)
 {
-	setup_snvs();
 	return 0;
 }
 
diff --git a/board/dhelectronics/dh_imx8mp/imx8mp_dhcom_pdk2.c b/board/dhelectronics/dh_imx8mp/imx8mp_dhcom_pdk2.c
index 6f06daf..9d8e19d 100644
--- a/board/dhelectronics/dh_imx8mp/imx8mp_dhcom_pdk2.c
+++ b/board/dhelectronics/dh_imx8mp/imx8mp_dhcom_pdk2.c
@@ -37,22 +37,6 @@
 	return 0;
 }
 
-/* IMX8M SNVS registers needed for the bootcount functionality */
-#define SNVS_BASE_ADDR			0x30370000
-#define SNVS_LPSR			0x4c
-#define SNVS_LPLVDR			0x64
-#define SNVS_LPPGDR_INIT		0x41736166
-
-static void setup_snvs(void)
-{
-	/* Enable SNVS clock */
-	clock_enable(CCGR_SNVS, 1);
-	/* Initialize glitch detect */
-	writel(SNVS_LPPGDR_INIT, SNVS_BASE_ADDR + SNVS_LPLVDR);
-	/* Clear interrupt status */
-	writel(0xffffffff, SNVS_BASE_ADDR + SNVS_LPSR);
-}
-
 static void setup_eqos(void)
 {
 	struct iomuxc_gpr_base_regs *gpr =
@@ -145,7 +129,6 @@
 {
 	setup_eqos();
 	setup_fec();
-	setup_snvs();
 	return 0;
 }
 
diff --git a/board/imgtec/boston/ddr.c b/board/imgtec/boston/ddr.c
index 182f79b..5b245cb 100644
--- a/board/imgtec/boston/ddr.c
+++ b/board/imgtec/boston/ddr.c
@@ -23,7 +23,7 @@
 	return 0;
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	DECLARE_GLOBAL_DATA_PTR;
 
diff --git a/board/mediatek/mt7981/MAINTAINERS b/board/mediatek/mt7981/MAINTAINERS
new file mode 100644
index 0000000..e7592a7
--- /dev/null
+++ b/board/mediatek/mt7981/MAINTAINERS
@@ -0,0 +1,10 @@
+MT7981
+M:	Sam Shih <sam.shih@mediatek.com>
+S:	Maintained
+F:	board/mediatek/mt7981
+F:	include/configs/mt7981.h
+F:	configs/mt7981_emmc_rfb_defconfig
+F:	configs/mt7981_rfb_defconfig
+F:	configs/mt7981_sd_rfb_defconfig
+F:	configs/mt7981_spim_nand_rfb_defconfig
+F:	configs/mt7981_spim_nor_rfb_defconfig
diff --git a/board/mediatek/mt7981/Makefile b/board/mediatek/mt7981/Makefile
new file mode 100644
index 0000000..fa5990f
--- /dev/null
+++ b/board/mediatek/mt7981/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier:	GPL-2.0
+
+obj-y	+= mt7981_rfb.o
diff --git a/board/mediatek/mt7981/mt7981_rfb.c b/board/mediatek/mt7981/mt7981_rfb.c
new file mode 100644
index 0000000..846c715
--- /dev/null
+++ b/board/mediatek/mt7981/mt7981_rfb.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+int board_init(void)
+{
+	return 0;
+}
diff --git a/board/mediatek/mt7986/MAINTAINERS b/board/mediatek/mt7986/MAINTAINERS
new file mode 100644
index 0000000..ddc078a
--- /dev/null
+++ b/board/mediatek/mt7986/MAINTAINERS
@@ -0,0 +1,12 @@
+MT7986
+M:	Sam Shih <sam.shih@mediatek.com>
+S:	Maintained
+F:	board/mediatek/mt7986
+F:	include/configs/mt7986.h
+F:	configs/mt7986_rfb_defconfig
+F:	configs/mt7986a_bpir3_emmc_defconfig
+F:	configs/mt7986a_bpir3_sd_defconfig
+F:	configs/mt7986a_emmc_rfb_defconfig
+F:	configs/mt7986a_sd_rfb_defconfig
+F:	configs/mt7986b_emmc_rfb_defconfig
+F:	configs/mt7986b_sd_rfb_defconfig
diff --git a/board/mediatek/mt7986/Makefile b/board/mediatek/mt7986/Makefile
new file mode 100644
index 0000000..7bb84fa
--- /dev/null
+++ b/board/mediatek/mt7986/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier:	GPL-2.0
+
+obj-y	+= mt7986_rfb.o
diff --git a/board/mediatek/mt7986/mt7986_rfb.c b/board/mediatek/mt7986/mt7986_rfb.c
new file mode 100644
index 0000000..846c715
--- /dev/null
+++ b/board/mediatek/mt7986/mt7986_rfb.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+int board_init(void)
+{
+	return 0;
+}
diff --git a/board/menlo/m53menlo/m53menlo.c b/board/menlo/m53menlo/m53menlo.c
index 61ab384..4afc5aa 100644
--- a/board/menlo/m53menlo/m53menlo.c
+++ b/board/menlo/m53menlo/m53menlo.c
@@ -42,7 +42,7 @@
 
 static u32 mx53_dram_size[2];
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	/*
 	 * WARNING: We must override get_effective_memsize() function here
diff --git a/board/menlo/mx8menlo/mx8menlo.c b/board/menlo/mx8menlo/mx8menlo.c
index 9d3708a..61fc4ec 100644
--- a/board/menlo/mx8menlo/mx8menlo.c
+++ b/board/menlo/mx8menlo/mx8menlo.c
@@ -12,24 +12,7 @@
 #include <asm/mach-imx/iomux-v3.h>
 #include <spl.h>
 
-#define SNVS_BASE_ADDR		0x30370000
-#define SNVS_LPSR		0x4c
-#define SNVS_LPLVDR		0x64
-#define SNVS_LPPGDR_INIT	0x41736166
-
-static void setup_snvs(void)
-{
-	/* Enable SNVS clock */
-	clock_enable(CCGR_SNVS, 1);
-	/* Initialize glitch detect */
-	writel(SNVS_LPPGDR_INIT, SNVS_BASE_ADDR + SNVS_LPLVDR);
-	/* Clear interrupt status */
-	writel(0xffffffff, SNVS_BASE_ADDR + SNVS_LPSR);
-}
-
 void board_early_init(void)
 {
 	init_uart_clk(1);
-
-	setup_snvs();
 }
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 17b8108..00afb35 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -335,7 +335,7 @@
 /*
  * Prevent relocation from stomping on a firmware provided FDT blob.
  */
-unsigned long board_get_usable_ram_top(unsigned long total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	if ((gd->ram_top - fw_dtb_pointer) > SZ_64M)
 		return gd->ram_top;
diff --git a/board/st/common/stm32mp_dfu.c b/board/st/common/stm32mp_dfu.c
index fa48b2a..0096f71 100644
--- a/board/st/common/stm32mp_dfu.c
+++ b/board/st/common/stm32mp_dfu.c
@@ -37,7 +37,7 @@
 	if (!desc)
 		return;
 
-	name = blk_get_if_type_name(desc->if_type);
+	name = blk_get_uclass_name(desc->uclass_id);
 	devnum = desc->devnum;
 	len = strlen(buf);
 
diff --git a/board/ti/am65x/evm.c b/board/ti/am65x/evm.c
index 8a0a506..34ec391 100644
--- a/board/ti/am65x/evm.c
+++ b/board/ti/am65x/evm.c
@@ -61,7 +61,7 @@
 	return 0;
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 #ifdef CONFIG_PHYS_64BIT
 	/* Limit RAM used by U-Boot to the DDR low region */
diff --git a/board/ti/j721e/evm.c b/board/ti/j721e/evm.c
index 5d09004..d6e431e 100644
--- a/board/ti/j721e/evm.c
+++ b/board/ti/j721e/evm.c
@@ -57,7 +57,7 @@
 	return 0;
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 #ifdef CONFIG_PHYS_64BIT
 	/* Limit RAM used by U-Boot to the DDR low region */
diff --git a/board/ti/j721s2/evm.c b/board/ti/j721s2/evm.c
index 3c75ecf..e09adc8 100644
--- a/board/ti/j721s2/evm.c
+++ b/board/ti/j721s2/evm.c
@@ -46,7 +46,7 @@
 	return 0;
 }
 
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 #ifdef CONFIG_PHYS_64BIT
 	/* Limit RAM used by U-Boot to the DDR low region */
diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c
index e1f7104..391ce4d 100644
--- a/board/xilinx/common/board.c
+++ b/board/xilinx/common/board.c
@@ -631,7 +631,7 @@
 #endif
 
 #if defined(CONFIG_LMB)
-ulong board_get_usable_ram_top(ulong total_size)
+phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 	phys_size_t size;
 	phys_addr_t reg;
diff --git a/boot/bootm_os.c b/boot/bootm_os.c
index f31820c..079224c 100644
--- a/boot/bootm_os.c
+++ b/boot/bootm_os.c
@@ -303,6 +303,7 @@
 #else
 	printf("## Starting vxWorks at 0x%08lx\n", (ulong)images->ep);
 #endif
+	flush();
 
 	boot_jump_vxworks(images);
 
diff --git a/cmd/bcb.c b/cmd/bcb.c
index 8b87aa0..1622a90 100644
--- a/cmd/bcb.c
+++ b/cmd/bcb.c
@@ -122,7 +122,7 @@
 	char *endp;
 	int part, ret;
 
-	desc = blk_get_devnum_by_type(UCLASS_MMC, devnum);
+	desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, devnum);
 	if (!desc) {
 		ret = -ENODEV;
 		goto err_read_fail;
@@ -287,7 +287,7 @@
 	u64 cnt;
 	int ret;
 
-	desc = blk_get_devnum_by_type(UCLASS_MMC, bcb_dev);
+	desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, bcb_dev);
 	if (!desc) {
 		ret = -ENODEV;
 		goto err;
diff --git a/cmd/blk_common.c b/cmd/blk_common.c
index 369c5ae..75a072c 100644
--- a/cmd/blk_common.c
+++ b/cmd/blk_common.c
@@ -12,10 +12,10 @@
 #include <blk.h>
 #include <command.h>
 
-int blk_common_cmd(int argc, char *const argv[], enum uclass_id if_type,
+int blk_common_cmd(int argc, char *const argv[], enum uclass_id uclass_id,
 		   int *cur_devnump)
 {
-	const char *if_name = blk_get_if_type_name(if_type);
+	const char *if_name = blk_get_uclass_name(uclass_id);
 
 	switch (argc) {
 	case 0:
@@ -23,16 +23,16 @@
 		return CMD_RET_USAGE;
 	case 2:
 		if (strncmp(argv[1], "inf", 3) == 0) {
-			blk_list_devices(if_type);
+			blk_list_devices(uclass_id);
 			return 0;
 		} else if (strncmp(argv[1], "dev", 3) == 0) {
-			if (blk_print_device_num(if_type, *cur_devnump)) {
+			if (blk_print_device_num(uclass_id, *cur_devnump)) {
 				printf("\nno %s devices available\n", if_name);
 				return CMD_RET_FAILURE;
 			}
 			return 0;
 		} else if (strncmp(argv[1], "part", 4) == 0) {
-			if (blk_list_part(if_type))
+			if (blk_list_part(uclass_id))
 				printf("\nno %s partition table available\n",
 				       if_name);
 			return 0;
@@ -42,7 +42,7 @@
 		if (strncmp(argv[1], "dev", 3) == 0) {
 			int dev = (int)dectoul(argv[2], NULL);
 
-			if (!blk_show_device(if_type, dev)) {
+			if (!blk_show_device(uclass_id, dev)) {
 				*cur_devnump = dev;
 				printf("... is now current device\n");
 			} else {
@@ -52,7 +52,7 @@
 		} else if (strncmp(argv[1], "part", 4) == 0) {
 			int dev = (int)dectoul(argv[2], NULL);
 
-			if (blk_print_part_devnum(if_type, dev)) {
+			if (blk_print_part_devnum(uclass_id, dev)) {
 				printf("\n%s device %d not available\n",
 				       if_name, dev);
 				return CMD_RET_FAILURE;
@@ -71,7 +71,7 @@
 			printf("\n%s read: device %d block # "LBAFU", count %lu ... ",
 			       if_name, *cur_devnump, blk, cnt);
 
-			n = blk_read_devnum(if_type, *cur_devnump, blk, cnt,
+			n = blk_read_devnum(uclass_id, *cur_devnump, blk, cnt,
 					    (ulong *)addr);
 
 			printf("%ld blocks read: %s\n", n,
@@ -86,7 +86,7 @@
 			printf("\n%s write: device %d block # "LBAFU", count %lu ... ",
 			       if_name, *cur_devnump, blk, cnt);
 
-			n = blk_write_devnum(if_type, *cur_devnump, blk, cnt,
+			n = blk_write_devnum(uclass_id, *cur_devnump, blk, cnt,
 					     (ulong *)addr);
 
 			printf("%ld blocks written: %s\n", n,
diff --git a/cmd/boot.c b/cmd/boot.c
index be67a59..14839c1 100644
--- a/cmd/boot.c
+++ b/cmd/boot.c
@@ -32,6 +32,7 @@
 	addr = hextoul(argv[1], NULL);
 
 	printf ("## Starting application at 0x%08lX ...\n", addr);
+	flush();
 
 	/*
 	 * pass address parameter as argv[0] (aka command name),
diff --git a/cmd/elf.c b/cmd/elf.c
index ce40d3f..b7b9f50 100644
--- a/cmd/elf.c
+++ b/cmd/elf.c
@@ -72,6 +72,7 @@
 		return rcode;
 
 	printf("## Starting application at 0x%08lx ...\n", addr);
+	flush();
 
 	/*
 	 * pass address parameter as argv[0] (aka command name),
@@ -274,6 +275,7 @@
 		puts("## Not an ELF image, assuming binary\n");
 
 	printf("## Starting vxWorks at 0x%08lx ...\n", addr);
+	flush();
 
 	dcache_disable();
 #if defined(CONFIG_ARM64) && defined(CONFIG_ARMV8_PSCI)
diff --git a/cmd/fdt.c b/cmd/fdt.c
index 842e6cb..6fbd920 100644
--- a/cmd/fdt.c
+++ b/cmd/fdt.c
@@ -48,11 +48,27 @@
 /*
  * Get a value from the fdt and format it to be set in the environment
  */
-static int fdt_value_env_set(const void *nodep, int len, const char *var)
+static int fdt_value_env_set(const void *nodep, int len,
+			     const char *var, int index)
 {
-	if (is_printable_string(nodep, len))
-		env_set(var, (void *)nodep);
-	else if (len == 4) {
+	if (is_printable_string(nodep, len)) {
+		const char *nodec = (const char *)nodep;
+		int i;
+
+		/*
+		 * Iterate over all members in stringlist and find the one at
+		 * offset $index. If no such index exists, indicate failure.
+		 */
+		for (i = 0; i < len; i += strlen(nodec) + 1) {
+			if (index-- > 0)
+				continue;
+
+			env_set(var, nodec + i);
+			return 0;
+		}
+
+		return 1;
+	} else if (len == 4) {
 		char buf[11];
 
 		sprintf(buf, "0x%08X", fdt32_to_cpu(*(fdt32_t *)nodep));
@@ -426,10 +442,14 @@
 				return 0;
 			} else if (nodep && len > 0) {
 				if (subcmd[0] == 'v') {
+					int index = 0;
 					int ret;
 
+					if (argc == 7)
+						index = simple_strtoul(argv[6], NULL, 10);
+
 					ret = fdt_value_env_set(nodep, len,
-								var);
+								var, index);
 					if (ret != 0)
 						return ret;
 				} else if (subcmd[0] == 'a') {
@@ -1085,7 +1105,9 @@
 	"fdt resize [<extrasize>]            - Resize fdt to size + padding to 4k addr + some optional <extrasize> if needed\n"
 	"fdt print  <path> [<prop>]          - Recursive print starting at <path>\n"
 	"fdt list   <path> [<prop>]          - Print one level starting at <path>\n"
-	"fdt get value <var> <path> <prop>   - Get <property> and store in <var>\n"
+	"fdt get value <var> <path> <prop> [<index>] - Get <property> and store in <var>\n"
+	"                                      In case of stringlist property, use optional <index>\n"
+	"                                      to select string within the stringlist. Default is 0.\n"
 	"fdt get name <var> <path> <index>   - Get name of node <index> and store in <var>\n"
 	"fdt get addr <var> <path> <prop>    - Get start address of <property> and store in <var>\n"
 	"fdt get size <var> <path> [<prop>]  - Get size of [<property>] or num nodes and store in <var>\n"
diff --git a/cmd/load.c b/cmd/load.c
index e44ae0d..5c4f347 100644
--- a/cmd/load.c
+++ b/cmd/load.c
@@ -83,6 +83,7 @@
 		printf("## Switch baudrate to %d bps and press ENTER ...\n",
 			load_baudrate);
 		udelay(50000);
+		flush();
 		gd->baudrate = load_baudrate;
 		serial_setbrg();
 		udelay(50000);
@@ -126,6 +127,7 @@
 		printf("## Switch baudrate to %d bps and press ESC ...\n",
 			current_baudrate);
 		udelay(50000);
+		flush();
 		gd->baudrate = current_baudrate;
 		serial_setbrg();
 		udelay(50000);
@@ -317,6 +319,7 @@
 		printf("## Switch baudrate to %d bps and press ESC ...\n",
 			(int)current_baudrate);
 		udelay(50000);
+		flush();
 		gd->baudrate = current_baudrate;
 		serial_setbrg();
 		udelay(50000);
@@ -471,6 +474,7 @@
 		printf("## Switch baudrate to %d bps and press ENTER ...\n",
 			load_baudrate);
 		udelay(50000);
+		flush();
 		gd->baudrate = load_baudrate;
 		serial_setbrg();
 		udelay(50000);
@@ -533,6 +537,7 @@
 		printf("## Switch baudrate to %d bps and press ESC ...\n",
 			current_baudrate);
 		udelay(50000);
+		flush();
 		gd->baudrate = current_baudrate;
 		serial_setbrg();
 		udelay(50000);
diff --git a/cmd/lsblk.c b/cmd/lsblk.c
index 6a1c8f5..d214daf 100644
--- a/cmd/lsblk.c
+++ b/cmd/lsblk.c
@@ -36,7 +36,7 @@
 				continue;
 			desc = dev_get_uclass_plat(udev);
 			printf("%c %s %u", i ? ',' : ':',
-			       blk_get_if_type_name(desc->if_type),
+			       blk_get_uclass_name(desc->uclass_id),
 			       desc->devnum);
 			i++;
 		}
diff --git a/cmd/mmc.c b/cmd/mmc.c
index 0f1f4e0..c79d940 100644
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -154,7 +154,7 @@
 
 #ifdef CONFIG_BLOCK_CACHE
 	struct blk_desc *bd = mmc_get_blk_desc(mmc);
-	blkcache_invalidate(bd->if_type, bd->devnum);
+	blkcache_invalidate(bd->uclass_id, bd->devnum);
 #endif
 
 	return mmc;
@@ -530,7 +530,7 @@
 	if (!mmc)
 		return CMD_RET_FAILURE;
 
-	mmc_dev = blk_get_devnum_by_type(UCLASS_MMC, curr_device);
+	mmc_dev = blk_get_devnum_by_uclass_id(UCLASS_MMC, curr_device);
 	if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) {
 		part_print(mmc_dev);
 		return CMD_RET_SUCCESS;
diff --git a/common/Kconfig b/common/Kconfig
index b776c5c..6591acd 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -186,6 +186,12 @@
 	  We should consider removing this option and allocating the memory
 	  in board_init_f_init_reserve() instead.
 
+config CONSOLE_FLUSH_SUPPORT
+	bool "Enable console flush support"
+	default y
+	help
+	  This enables compilation of flush() function for console flush support.
+
 config CONSOLE_MUX
 	bool "Enable console multiplexing"
 	default y if DM_VIDEO || VIDEO || LCD
diff --git a/common/board_f.c b/common/board_f.c
index f92d7b9..3df4efe 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -57,6 +57,7 @@
 #include <asm/sections.h>
 #include <dm/root.h>
 #include <linux/errno.h>
+#include <linux/log2.h>
 
 /*
  * Pointer to initial global data area
@@ -216,6 +217,36 @@
 	return 0;
 }
 
+/*
+ * From input size calculate its nearest rounded unit scale (multiply of 2^10)
+ * and value in calculated unit scale multiplied by 10 (as fractional fixed
+ * point number with one decimal digit), which is human natural format,
+ * same what uses print_size() function for displaying. Mathematically it is:
+ * round_nearest(val * 2^scale) = size * 10; where: 10 <= val < 10240.
+ *
+ * For example for size=87654321 we calculate scale=20 and val=836 which means
+ * that input has natural human format 83.6 M (mega = 2^20).
+ */
+#define compute_size_scale_val(size, scale, val) do { \
+	scale = ilog2(size) / 10 * 10; \
+	val = (10 * size + ((1ULL << scale) >> 1)) >> scale; \
+	if (val == 10240) { val = 10; scale += 10; } \
+} while (0)
+
+/*
+ * Check if the sizes in their natural units written in decimal format with
+ * one fraction number are same.
+ */
+static int sizes_near(unsigned long long size1, unsigned long long size2)
+{
+	unsigned int size1_scale, size1_val, size2_scale, size2_val;
+
+	compute_size_scale_val(size1, size1_scale, size1_val);
+	compute_size_scale_val(size2, size2_scale, size2_val);
+
+	return size1_scale == size2_scale && size1_val == size2_val;
+}
+
 static int show_dram_config(void)
 {
 	unsigned long long size;
@@ -232,7 +263,11 @@
 	}
 	debug("\nDRAM:  ");
 
-	print_size(size, "");
+	print_size(gd->ram_size, "");
+	if (!sizes_near(gd->ram_size, size)) {
+		printf(" (effective ");
+		print_size(size, ")");
+	}
 	board_add_ram_info(0);
 	putc('\n');
 
@@ -305,7 +340,7 @@
 }
 
 /* Get the top of usable RAM */
-__weak ulong board_get_usable_ram_top(ulong total_size)
+__weak phys_size_t board_get_usable_ram_top(phys_size_t total_size)
 {
 #if defined(CONFIG_SYS_SDRAM_BASE) && CONFIG_SYS_SDRAM_BASE > 0
 	/*
@@ -328,7 +363,7 @@
 	/*
 	 * Ram is setup, size stored in gd !!
 	 */
-	debug("Ram size: %08lX\n", (ulong)gd->ram_size);
+	debug("Ram size: %08llX\n", (unsigned long long)gd->ram_size);
 #if CONFIG_VAL(SYS_MEM_TOP_HIDE)
 	/*
 	 * Subtract specified amount of memory to hide so that it won't
@@ -348,7 +383,7 @@
 	gd->ram_top = gd->ram_base + get_effective_memsize();
 	gd->ram_top = board_get_usable_ram_top(gd->mon_len);
 	gd->relocaddr = gd->ram_top;
-	debug("Ram top: %08lX\n", (ulong)gd->ram_top);
+	debug("Ram top: %08llX\n", (unsigned long long)gd->ram_top);
 #if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500))
 	/*
 	 * We need to make sure the location we intend to put secondary core
diff --git a/common/console.c b/common/console.c
index e5be6ff..0c9bf66 100644
--- a/common/console.c
+++ b/common/console.c
@@ -199,6 +199,7 @@
 		case stdout:
 			gd->jt->putc  = putc;
 			gd->jt->puts  = puts;
+			STDIO_DEV_ASSIGN_FLUSH(gd->jt, flush);
 			gd->jt->printf = printf;
 			break;
 		}
@@ -364,6 +365,19 @@
 	}
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static void console_flush(int file)
+{
+	int i;
+	struct stdio_dev *dev;
+
+	for_each_console_dev(i, file, dev) {
+		if (dev->flush != NULL)
+			dev->flush(dev);
+	}
+}
+#endif
+
 #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
 static inline void console_doenv(int file, struct stdio_dev *dev)
 {
@@ -413,6 +427,14 @@
 	stdio_devices[file]->puts(stdio_devices[file], s);
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static inline void console_flush(int file)
+{
+	if (stdio_devices[file]->flush)
+		stdio_devices[file]->flush(stdio_devices[file]);
+}
+#endif
+
 #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
 static inline void console_doenv(int file, struct stdio_dev *dev)
 {
@@ -525,6 +547,14 @@
 	if (file < MAX_FILES)
 		console_puts(file, s);
 }
+
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void fflush(int file)
+{
+	if (file < MAX_FILES)
+		console_flush(file);
+}
+#endif
 
 int fprintf(int file, const char *fmt, ...)
 {
@@ -739,6 +769,40 @@
 		serial_puts(s);
 	}
 }
+
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void flush(void)
+{
+	if (!gd)
+		return;
+
+	/* sandbox can send characters to stdout before it has a console */
+	if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
+		os_flush();
+		return;
+	}
+
+	if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY))
+		return;
+
+	if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
+		return;
+
+	if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
+		return;
+
+	if (!gd->have_console)
+		return;
+
+	if (gd->flags & GD_FLG_DEVINIT) {
+		/* Send to the standard output */
+		fflush(stdout);
+	} else {
+		/* Send directly to the handler */
+		serial_flush();
+	}
+}
+#endif
 
 #ifdef CONFIG_CONSOLE_RECORD
 int console_record_init(void)
diff --git a/common/memsize.c b/common/memsize.c
index d5d13d5..3c80ad2 100644
--- a/common/memsize.c
+++ b/common/memsize.c
@@ -94,11 +94,23 @@
 
 phys_size_t __weak get_effective_memsize(void)
 {
-#ifndef CONFIG_VERY_BIG_RAM
-	return gd->ram_size;
+	phys_size_t ram_size = gd->ram_size;
+
+	/*
+	 * Check for overflow and limit ram size to some representable value.
+	 * It is required that ram_base + ram_size must be representable by
+	 * phys_size_t type and must be aligned by direct access, therefore
+	 * calculate it from last 4kB sector which should work as alignment
+	 * on any platform.
+	 */
+	if (gd->ram_base + ram_size < gd->ram_base)
+		ram_size = ((phys_size_t)~0xfffULL) - gd->ram_base;
+
+#ifndef CONFIG_MAX_MEM_MAPPED
+	return ram_size;
 #else
 	/* limit stack to what we can reasonable map */
-	return ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ?
-		CONFIG_MAX_MEM_MAPPED : gd->ram_size);
+	return ((ram_size > CONFIG_MAX_MEM_MAPPED) ?
+		CONFIG_MAX_MEM_MAPPED : ram_size);
 #endif
 }
diff --git a/common/spl/spl_sata.c b/common/spl/spl_sata.c
index ea9f175..6c36f2c 100644
--- a/common/spl/spl_sata.c
+++ b/common/spl/spl_sata.c
@@ -71,7 +71,7 @@
 
 	/* try to recognize storage devices immediately */
 	scsi_scan(false);
-	stor_dev = blk_get_devnum_by_type(UCLASS_SCSI, 0);
+	stor_dev = blk_get_devnum_by_uclass_id(UCLASS_SCSI, 0);
 	if (!stor_dev)
 		return -ENODEV;
 
diff --git a/common/spl/spl_usb.c b/common/spl/spl_usb.c
index 63c00f8..479e2dc 100644
--- a/common/spl/spl_usb.c
+++ b/common/spl/spl_usb.c
@@ -41,7 +41,7 @@
 
 	/* try to recognize storage devices immediately */
 	usb_stor_curr_dev = usb_stor_scan(1);
-	stor_dev = blk_get_devnum_by_type(UCLASS_USB, usb_stor_curr_dev);
+	stor_dev = blk_get_devnum_by_uclass_id(UCLASS_USB, usb_stor_curr_dev);
 	if (!stor_dev)
 		return -ENODEV;
 
diff --git a/common/stdio.c b/common/stdio.c
index 92161a0..1308384 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -87,6 +87,13 @@
 	serial_puts(s);
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static void stdio_serial_flush(struct stdio_dev *dev)
+{
+	serial_flush();
+}
+#endif
+
 static int stdio_serial_getc(struct stdio_dev *dev)
 {
 	return serial_getc();
@@ -112,6 +119,7 @@
 	dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
 	dev.putc = stdio_serial_putc;
 	dev.puts = stdio_serial_puts;
+	STDIO_DEV_ASSIGN_FLUSH(&dev, stdio_serial_flush);
 	dev.getc = stdio_serial_getc;
 	dev.tstc = stdio_serial_tstc;
 	stdio_register (&dev);
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 7d42016..e59c819 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -279,7 +279,7 @@
 
 		blkdev = &usb_dev_desc[usb_max_devs];
 		memset(blkdev, '\0', sizeof(struct blk_desc));
-		blkdev->if_type = UCLASS_USB;
+		blkdev->uclass_id = UCLASS_USB;
 		blkdev->devnum = usb_max_devs;
 		blkdev->part_type = PART_TYPE_UNKNOWN;
 		blkdev->target = 0xff;
@@ -1577,8 +1577,8 @@
 };
 #else
 U_BOOT_LEGACY_BLK(usb) = {
-	.if_typename	= "usb",
-	.if_type	= UCLASS_USB,
+	.uclass_idname	= "usb",
+	.uclass_id	= UCLASS_USB,
 	.max_devs	= USB_MAX_STOR_DEV,
 	.desc		= usb_dev_desc,
 };
diff --git a/configs/ae350_rv32_spl_defconfig b/configs/ae350_rv32_spl_defconfig
index 9b79cc4..1cc98a2 100644
--- a/configs/ae350_rv32_spl_defconfig
+++ b/configs/ae350_rv32_spl_defconfig
@@ -48,3 +48,4 @@
 CONFIG_SPI=y
 CONFIG_ATCSPI200_SPI=y
 # CONFIG_BINMAN_FDT is not set
+# CONFIG_AVAILABLE_HARTS is not set
diff --git a/configs/ae350_rv32_spl_xip_defconfig b/configs/ae350_rv32_spl_xip_defconfig
index c7b6ea4..67c1e35 100644
--- a/configs/ae350_rv32_spl_xip_defconfig
+++ b/configs/ae350_rv32_spl_xip_defconfig
@@ -11,7 +11,7 @@
 CONFIG_SYS_LOAD_ADDR=0x100000
 CONFIG_TARGET_AX25_AE350=y
 CONFIG_RISCV_SMODE=y
-CONFIG_XIP=y
+CONFIG_SPL_XIP=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
 CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0xffff00
diff --git a/configs/ae350_rv64_spl_defconfig b/configs/ae350_rv64_spl_defconfig
index 4c33ca2..4318300 100644
--- a/configs/ae350_rv64_spl_defconfig
+++ b/configs/ae350_rv64_spl_defconfig
@@ -49,3 +49,4 @@
 CONFIG_SPI=y
 CONFIG_ATCSPI200_SPI=y
 # CONFIG_BINMAN_FDT is not set
+# CONFIG_AVAILABLE_HARTS is not set
diff --git a/configs/ae350_rv64_spl_xip_defconfig b/configs/ae350_rv64_spl_xip_defconfig
index a197c97..baee9bf 100644
--- a/configs/ae350_rv64_spl_xip_defconfig
+++ b/configs/ae350_rv64_spl_xip_defconfig
@@ -12,7 +12,7 @@
 CONFIG_TARGET_AX25_AE350=y
 CONFIG_ARCH_RV64I=y
 CONFIG_RISCV_SMODE=y
-CONFIG_XIP=y
+CONFIG_SPL_XIP=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
 CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0xfffe70
diff --git a/configs/kontron-sl-mx8mm_defconfig b/configs/kontron-sl-mx8mm_defconfig
index 5387f65..f8589b0 100644
--- a/configs/kontron-sl-mx8mm_defconfig
+++ b/configs/kontron-sl-mx8mm_defconfig
@@ -39,7 +39,6 @@
 CONFIG_SYS_SPL_MALLOC_SIZE=0x80000
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
 CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x300
-# CONFIG_SPL_FIT_IMAGE_TINY is not set
 CONFIG_SPL_I2C=y
 CONFIG_SPL_DM_SPI_FLASH=y
 CONFIG_SPL_POWER=y
diff --git a/configs/mt7981_emmc_rfb_defconfig b/configs/mt7981_emmc_rfb_defconfig
new file mode 100644
index 0000000..5f9f6d8
--- /dev/null
+++ b/configs/mt7981_emmc_rfb_defconfig
@@ -0,0 +1,64 @@
+CONFIG_ARM=y
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_SYS_TEXT_BASE=0x41e00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x80000
+CONFIG_ENV_OFFSET=0x300000
+CONFIG_DEFAULT_DEVICE_TREE="mt7981-emmc-rfb"
+CONFIG_TARGET_MT7981=y
+CONFIG_DEBUG_UART_BASE=0x11002000
+CONFIG_DEBUG_UART_CLOCK=40000000
+CONFIG_SYS_LOAD_ADDR=0x46000000
+CONFIG_DEBUG_UART=y
+# CONFIG_AUTOBOOT is not set
+CONFIG_DEFAULT_FDT_FILE="mt7981-emmc-rfb"
+CONFIG_LOGLEVEL=7
+CONFIG_LOG=y
+CONFIG_SYS_PROMPT="MT7981> "
+CONFIG_SYS_CBSIZE=512
+CONFIG_SYS_PBSIZE=1049
+# CONFIG_BOOTM_NETBSD is not set
+# CONFIG_BOOTM_PLAN9 is not set
+# CONFIG_BOOTM_RTEMS is not set
+# CONFIG_BOOTM_VXWORKS is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_UNLZ4 is not set
+# CONFIG_CMD_UNZIP is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_LSBLK=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_READ=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_SMC=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_MMC_MTK=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_MEDIATEK_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT7981=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_MTK_POWER_DOMAIN=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_FAT_WRITE=y
+CONFIG_HEXDUMP=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/mt7981_rfb_defconfig b/configs/mt7981_rfb_defconfig
new file mode 100644
index 0000000..88299e3
--- /dev/null
+++ b/configs/mt7981_rfb_defconfig
@@ -0,0 +1,69 @@
+CONFIG_ARM=y
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_SYS_TEXT_BASE=0x41e00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_DEFAULT_DEVICE_TREE="mt7981-rfb"
+CONFIG_TARGET_MT7981=y
+CONFIG_DEBUG_UART_BASE=0x11002000
+CONFIG_DEBUG_UART_CLOCK=40000000
+CONFIG_SYS_LOAD_ADDR=0x46000000
+CONFIG_DEBUG_UART=y
+# CONFIG_AUTOBOOT is not set
+CONFIG_DEFAULT_FDT_FILE="mt7981-rfb"
+CONFIG_LOGLEVEL=7
+CONFIG_LOG=y
+CONFIG_SYS_PROMPT="MT7981> "
+CONFIG_SYS_CBSIZE=512
+CONFIG_SYS_PBSIZE=1049
+# CONFIG_BOOTM_NETBSD is not set
+# CONFIG_BOOTM_PLAN9 is not set
+# CONFIG_BOOTM_RTEMS is not set
+# CONFIG_BOOTM_VXWORKS is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_UNLZ4 is not set
+# CONFIG_CMD_UNZIP is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_SF_TEST=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_SMC=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_BLK=y
+CONFIG_HAVE_BLOCK_DEVICE=y
+CONFIG_CLK=y
+# CONFIG_MMC is not set
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_SFDP_SUPPORT=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_ISSI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_XMC=y
+CONFIG_SPI_FLASH_XTX=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_MEDIATEK_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT7981=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_MTK_POWER_DOMAIN=y
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_MTK_SPIM=y
+CONFIG_HEXDUMP=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/mt7981_sd_rfb_defconfig b/configs/mt7981_sd_rfb_defconfig
new file mode 100644
index 0000000..b5c765b
--- /dev/null
+++ b/configs/mt7981_sd_rfb_defconfig
@@ -0,0 +1,64 @@
+CONFIG_ARM=y
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_SYS_TEXT_BASE=0x41e00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x80000
+CONFIG_ENV_OFFSET=0x300000
+CONFIG_DEFAULT_DEVICE_TREE="mt7981-sd-rfb"
+CONFIG_TARGET_MT7981=y
+CONFIG_DEBUG_UART_BASE=0x11002000
+CONFIG_DEBUG_UART_CLOCK=40000000
+CONFIG_SYS_LOAD_ADDR=0x46000000
+CONFIG_DEBUG_UART=y
+# CONFIG_AUTOBOOT is not set
+CONFIG_DEFAULT_FDT_FILE="mt7981-sd-rfb"
+CONFIG_LOGLEVEL=7
+CONFIG_LOG=y
+CONFIG_SYS_PROMPT="MT7981> "
+CONFIG_SYS_CBSIZE=512
+CONFIG_SYS_PBSIZE=1049
+# CONFIG_BOOTM_NETBSD is not set
+# CONFIG_BOOTM_PLAN9 is not set
+# CONFIG_BOOTM_RTEMS is not set
+# CONFIG_BOOTM_VXWORKS is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_UNLZ4 is not set
+# CONFIG_CMD_UNZIP is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_LSBLK=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_READ=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_SMC=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_MMC_MTK=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_MEDIATEK_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT7981=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_MTK_POWER_DOMAIN=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_FAT_WRITE=y
+CONFIG_HEXDUMP=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/mt7986_rfb_defconfig b/configs/mt7986_rfb_defconfig
new file mode 100644
index 0000000..ff1e63b
--- /dev/null
+++ b/configs/mt7986_rfb_defconfig
@@ -0,0 +1,66 @@
+CONFIG_ARM=y
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_SYS_TEXT_BASE=0x41e00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-rfb"
+CONFIG_TARGET_MT7986=y
+CONFIG_DEBUG_UART_BASE=0x11002000
+CONFIG_DEBUG_UART_CLOCK=40000000
+CONFIG_SYS_LOAD_ADDR=0x46000000
+CONFIG_DEBUG_UART=y
+# CONFIG_AUTOBOOT is not set
+CONFIG_DEFAULT_FDT_FILE="mt7986a-rfb"
+CONFIG_LOGLEVEL=7
+CONFIG_LOG=y
+CONFIG_SYS_PROMPT="MT7986> "
+CONFIG_SYS_CBSIZE=512
+CONFIG_SYS_PBSIZE=1049
+# CONFIG_BOOTM_NETBSD is not set
+# CONFIG_BOOTM_PLAN9 is not set
+# CONFIG_BOOTM_RTEMS is not set
+# CONFIG_BOOTM_VXWORKS is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_UNLZ4 is not set
+# CONFIG_CMD_UNZIP is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_SF_TEST=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_SMC=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+# CONFIG_MMC is not set
+CONFIG_MTD=y
+CONFIG_DM_MTD=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_SFDP_SUPPORT=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_ISSI=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_XMC=y
+CONFIG_SPI_FLASH_XTX=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_MEDIATEK_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT7986=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_MTK_POWER_DOMAIN=y
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_MTK_SPIM=y
+CONFIG_HEXDUMP=y
diff --git a/configs/mt7986a_bpir3_emmc_defconfig b/configs/mt7986a_bpir3_emmc_defconfig
new file mode 100644
index 0000000..3e368b6
--- /dev/null
+++ b/configs/mt7986a_bpir3_emmc_defconfig
@@ -0,0 +1,64 @@
+CONFIG_ARM=y
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_SYS_TEXT_BASE=0x41e00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x80000
+CONFIG_ENV_OFFSET=0x300000
+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-emmc-rfb"
+CONFIG_TARGET_MT7986=y
+CONFIG_DEBUG_UART_BASE=0x11002000
+CONFIG_DEBUG_UART_CLOCK=40000000
+CONFIG_SYS_LOAD_ADDR=0x46000000
+CONFIG_DEBUG_UART=y
+# CONFIG_AUTOBOOT is not set
+CONFIG_DEFAULT_FDT_FILE="mt7986a-emmc-rfb"
+CONFIG_LOGLEVEL=7
+CONFIG_LOG=y
+CONFIG_SYS_PROMPT="MT7986> "
+CONFIG_SYS_CBSIZE=512
+CONFIG_SYS_PBSIZE=1049
+# CONFIG_BOOTM_NETBSD is not set
+# CONFIG_BOOTM_PLAN9 is not set
+# CONFIG_BOOTM_RTEMS is not set
+# CONFIG_BOOTM_VXWORKS is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_UNLZ4 is not set
+# CONFIG_CMD_UNZIP is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_LSBLK=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_READ=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_SMC=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_MMC_MTK=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_MEDIATEK_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT7986=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_MTK_POWER_DOMAIN=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_FAT_WRITE=y
+CONFIG_HEXDUMP=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/mt7986a_bpir3_sd_defconfig b/configs/mt7986a_bpir3_sd_defconfig
new file mode 100644
index 0000000..b9a69a3
--- /dev/null
+++ b/configs/mt7986a_bpir3_sd_defconfig
@@ -0,0 +1,64 @@
+CONFIG_ARM=y
+CONFIG_POSITION_INDEPENDENT=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_SYS_TEXT_BASE=0x41e00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_ENV_SIZE=0x80000
+CONFIG_ENV_OFFSET=0x300000
+CONFIG_DEFAULT_DEVICE_TREE="mt7986a-sd-rfb"
+CONFIG_TARGET_MT7986=y
+CONFIG_DEBUG_UART_BASE=0x11002000
+CONFIG_DEBUG_UART_CLOCK=40000000
+CONFIG_SYS_LOAD_ADDR=0x46000000
+CONFIG_DEBUG_UART=y
+# CONFIG_AUTOBOOT is not set
+CONFIG_DEFAULT_FDT_FILE="mt7986a-sd-rfb"
+CONFIG_LOGLEVEL=7
+CONFIG_LOG=y
+CONFIG_SYS_PROMPT="MT7986> "
+CONFIG_SYS_CBSIZE=512
+CONFIG_SYS_PBSIZE=1049
+# CONFIG_BOOTM_NETBSD is not set
+# CONFIG_BOOTM_PLAN9 is not set
+# CONFIG_BOOTM_RTEMS is not set
+# CONFIG_BOOTM_VXWORKS is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_UNLZ4 is not set
+# CONFIG_CMD_UNZIP is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_GPT_RENAME=y
+CONFIG_CMD_LSBLK=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_READ=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_SMC=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_PARTITION_TYPE_GUID=y
+CONFIG_ENV_OVERWRITE=y
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_MMC_HS200_SUPPORT=y
+CONFIG_MMC_MTK=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_MEDIATEK_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT7986=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_MTK_POWER_DOMAIN=y
+CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_FAT_WRITE=y
+CONFIG_HEXDUMP=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index 9a1b6e4..b20b181 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -104,7 +104,6 @@
 CONFIG_DEBUG_DEVRES=y
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
-CONFIG_SYS_SATA_MAX_DEVICE=2
 CONFIG_AXI=y
 CONFIG_AXI_SANDBOX=y
 CONFIG_SYS_IDE_MAXBUS=1
@@ -203,6 +202,8 @@
 CONFIG_SANDBOX_RESET=y
 CONFIG_DM_RTC=y
 CONFIG_RTC_RV8803=y
+CONFIG_SCSI=y
+CONFIG_DM_SCSI=y
 CONFIG_SANDBOX_SERIAL=y
 CONFIG_SMEM=y
 CONFIG_SANDBOX_SMEM=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index caecb50..df6a28e 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -137,7 +137,6 @@
 CONFIG_SIMPLE_PM_BUS=y
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
-CONFIG_SYS_SATA_MAX_DEVICE=2
 CONFIG_AXI=y
 CONFIG_AXI_SANDBOX=y
 CONFIG_SYS_IDE_MAXBUS=1
@@ -264,9 +263,7 @@
 CONFIG_DM_RTC=y
 CONFIG_RTC_RV8803=y
 CONFIG_SCSI=y
-CONFIG_SCSI_AHCI_PLAT=y
-CONFIG_SYS_SCSI_MAX_SCSI_ID=8
-CONFIG_SYS_SCSI_MAX_LUN=4
+CONFIG_DM_SCSI=y
 CONFIG_SANDBOX_SERIAL=y
 CONFIG_SMEM=y
 CONFIG_SANDBOX_SMEM=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 4b18c24..a2eb7af 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -85,7 +85,6 @@
 CONFIG_DEBUG_DEVRES=y
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
-CONFIG_SYS_SATA_MAX_DEVICE=2
 CONFIG_AXI=y
 CONFIG_AXI_SANDBOX=y
 CONFIG_CLK=y
@@ -174,6 +173,8 @@
 CONFIG_DM_RESET=y
 CONFIG_SANDBOX_RESET=y
 CONFIG_DM_RTC=y
+CONFIG_SCSI=y
+CONFIG_DM_SCSI=y
 CONFIG_SANDBOX_SERIAL=y
 CONFIG_SOUND=y
 CONFIG_SOUND_SANDBOX=y
diff --git a/configs/sandbox_noinst_defconfig b/configs/sandbox_noinst_defconfig
index 72c908f..8bf10bb 100644
--- a/configs/sandbox_noinst_defconfig
+++ b/configs/sandbox_noinst_defconfig
@@ -108,7 +108,6 @@
 # CONFIG_SPL_SIMPLE_BUS is not set
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
-CONFIG_SYS_SATA_MAX_DEVICE=2
 CONFIG_AXI=y
 CONFIG_AXI_SANDBOX=y
 CONFIG_SYS_IDE_MAXBUS=1
@@ -200,6 +199,8 @@
 CONFIG_SANDBOX_RESET=y
 CONFIG_DM_RTC=y
 CONFIG_SPL_DM_RTC=y
+CONFIG_SCSI=y
+CONFIG_DM_SCSI=y
 CONFIG_SANDBOX_SERIAL=y
 CONFIG_SOUND=y
 CONFIG_SOUND_SANDBOX=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index 11b9aa8..c33f171 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -109,7 +109,6 @@
 # CONFIG_SPL_SIMPLE_BUS is not set
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
-CONFIG_SYS_SATA_MAX_DEVICE=2
 CONFIG_AXI=y
 CONFIG_AXI_SANDBOX=y
 CONFIG_SYS_IDE_MAXBUS=1
@@ -203,6 +202,8 @@
 CONFIG_SANDBOX_RESET=y
 CONFIG_DM_RTC=y
 CONFIG_SPL_DM_RTC=y
+CONFIG_SCSI=y
+CONFIG_DM_SCSI=y
 CONFIG_SANDBOX_SERIAL=y
 CONFIG_SOUND=y
 CONFIG_SOUND_SANDBOX=y
diff --git a/configs/sandbox_vpl_defconfig b/configs/sandbox_vpl_defconfig
index c3856a8..be8186e 100644
--- a/configs/sandbox_vpl_defconfig
+++ b/configs/sandbox_vpl_defconfig
@@ -124,7 +124,6 @@
 # CONFIG_SPL_SIMPLE_BUS is not set
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
-CONFIG_SYS_SATA_MAX_DEVICE=2
 CONFIG_AXI=y
 CONFIG_AXI_SANDBOX=y
 CONFIG_CLK=y
@@ -209,6 +208,8 @@
 CONFIG_DM_RTC=y
 CONFIG_SPL_DM_RTC=y
 CONFIG_TPL_DM_RTC=y
+CONFIG_SCSI=y
+CONFIG_DM_SCSI=y
 CONFIG_SANDBOX_SERIAL=y
 CONFIG_SOUND=y
 CONFIG_SOUND_SANDBOX=y
diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig
index 211acc7..2c418f5 100644
--- a/configs/tools-only_defconfig
+++ b/configs/tools-only_defconfig
@@ -18,7 +18,6 @@
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 # CONFIG_NET is not set
 # CONFIG_ACPIGEN is not set
-CONFIG_SYS_SATA_MAX_DEVICE=2
 CONFIG_AXI=y
 CONFIG_AXI_SANDBOX=y
 CONFIG_SANDBOX_GPIO=y
diff --git a/disk/disk-uclass.c b/disk/disk-uclass.c
index 9351a5c..551f8b1 100644
--- a/disk/disk-uclass.c
+++ b/disk/disk-uclass.c
@@ -191,12 +191,12 @@
 		start_in_disk += part->gpt_part_info.start;
 	}
 
-	if (blkcache_read(block_dev->if_type, block_dev->devnum,
+	if (blkcache_read(block_dev->uclass_id, block_dev->devnum,
 			  start_in_disk, blkcnt, block_dev->blksz, buffer))
 		return blkcnt;
 	blks_read = ops->read(dev, start, blkcnt, buffer);
 	if (blks_read == blkcnt)
-		blkcache_fill(block_dev->if_type, block_dev->devnum,
+		blkcache_fill(block_dev->uclass_id, block_dev->devnum,
 			      start_in_disk, blkcnt, block_dev->blksz, buffer);
 
 	return blks_read;
@@ -216,7 +216,7 @@
 	if (!ops->write)
 		return -ENOSYS;
 
-	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+	blkcache_invalidate(block_dev->uclass_id, block_dev->devnum);
 
 	return ops->write(dev, start, blkcnt, buffer);
 }
@@ -235,7 +235,7 @@
 	if (!ops->erase)
 		return -ENOSYS;
 
-	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+	blkcache_invalidate(block_dev->uclass_id, block_dev->devnum);
 
 	return ops->erase(dev, start, blkcnt);
 }
diff --git a/disk/part.c b/disk/part.c
index 47214c0..f982b30 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -61,7 +61,7 @@
 
 	if (!blk_enabled())
 		return NULL;
-	dev_desc = blk_get_devnum_by_typename(ifname, dev);
+	dev_desc = blk_get_devnum_by_uclass_idname(ifname, dev);
 	if (!dev_desc) {
 		debug("%s: No device for iface '%s', dev %d\n", __func__,
 		      ifname, dev);
@@ -120,7 +120,7 @@
 		return;
 	}
 
-	switch (dev_desc->if_type) {
+	switch (dev_desc->uclass_id) {
 	case UCLASS_SCSI:
 		printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
 			dev_desc->target,dev_desc->lun,
@@ -155,7 +155,7 @@
 		puts("device type unknown\n");
 		return;
 	default:
-		printf("Unhandled device type: %i\n", dev_desc->if_type);
+		printf("Unhandled device type: %i\n", dev_desc->uclass_id);
 		return;
 	}
 	puts ("            Type: ");
@@ -225,7 +225,7 @@
 	const int n_ents = ll_entry_count(struct part_driver, part_driver);
 	struct part_driver *entry;
 
-	blkcache_invalidate(dev_desc->if_type, dev_desc->devnum);
+	blkcache_invalidate(dev_desc->uclass_id, dev_desc->devnum);
 
 	dev_desc->part_type = PART_TYPE_UNKNOWN;
 	for (entry = drv; entry != drv + n_ents; entry++) {
@@ -248,7 +248,7 @@
 	CONFIG_IS_ENABLED(AMIGA_PARTITION) || \
 	CONFIG_IS_ENABLED(EFI_PARTITION)
 	puts ("\nPartition Map for ");
-	switch (dev_desc->if_type) {
+	switch (dev_desc->uclass_id) {
 	case UCLASS_IDE:
 		puts ("IDE");
 		break;
@@ -408,7 +408,7 @@
 		 * Always should be done, otherwise hw partition 0 will return
 		 * stale data after displaying a non-zero hw partition.
 		 */
-		if ((*dev_desc)->if_type == UCLASS_MMC)
+		if ((*dev_desc)->uclass_id == UCLASS_MMC)
 			part_init(*dev_desc);
 	}
 
@@ -762,7 +762,7 @@
 {
 	char *devtype;
 
-	switch (dev_desc->if_type) {
+	switch (dev_desc->uclass_id) {
 	case UCLASS_IDE:
 	case UCLASS_AHCI:
 		devtype = "hd";
diff --git a/doc/imx/habv4/csf_examples/mx8m/csf.sh b/doc/imx/habv4/csf_examples/mx8m/csf.sh
index 6898513..7d267a7 100644
--- a/doc/imx/habv4/csf_examples/mx8m/csf.sh
+++ b/doc/imx/habv4/csf_examples/mx8m/csf.sh
@@ -40,7 +40,7 @@
 # fitImage tree
 fit_block_base=$(printf "0x%x" $(( $(sed -n "/CONFIG_SYS_TEXT_BASE=/ s@.*=@@p" .config) - $(sed -n "/CONFIG_FIT_EXTERNAL_OFFSET=/ s@.*=@@p" .config) - 0x200 - 0x40)) )
 fit_block_offset=$(printf "0x%s" $(fdtget -t x u-boot.dtb /binman/imx-boot/uboot offset))
-fit_block_size=$(printf "0x%x" $(( ( $(fdtdump u-boot.itb 2>/dev/null | sed -n "/^...totalsize:/ s@.*\(0x[0-9a-f]\+\).*@\1@p") + 0x1000 - 0x1 ) & ~(0x1000 - 0x1) + 0x20 )) )
+fit_block_size=$(printf "0x%x" $(( ( ($(fdtdump u-boot.itb 2>/dev/null | sed -n "/^...totalsize:/ s@.*\(0x[0-9a-f]\+\).*@\1@p") + 0x1000 - 0x1 ) & ~(0x1000 - 0x1)) + 0x20 )) )
 sed -i "/Blocks = / s@.*@  Blocks = $fit_block_base $fit_block_offset $fit_block_size \"flash.bin\", \\\\@" csf_fit.tmp
 
 # U-Boot
diff --git a/doc/usage/partitions.rst b/doc/usage/partitions.rst
index 2c1a12b..628469b 100644
--- a/doc/usage/partitions.rst
+++ b/doc/usage/partitions.rst
@@ -20,7 +20,7 @@
 interface
         The interface used to access the partition's device, like ``mmc`` or
         ``scsi``. For a full list of supported interfaces, consult the
-        ``if_typename_str`` array in ``drivers/block/blk-uclass.c``
+        ``uclass_idname_str`` array in ``drivers/block/blk-uclass.c``
 
 devnum
         The device number. This defaults to 0.
diff --git a/drivers/ata/sata.c b/drivers/ata/sata.c
index 604c721..ce3e9b5 100644
--- a/drivers/ata/sata.c
+++ b/drivers/ata/sata.c
@@ -79,7 +79,7 @@
 
 	for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) {
 		memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc));
-		sata_dev_desc[i].if_type = UCLASS_AHCI;
+		sata_dev_desc[i].uclass_id = UCLASS_AHCI;
 		sata_dev_desc[i].devnum = i;
 		sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
 		sata_dev_desc[i].type = DEV_TYPE_HARDDISK;
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index a9a85aa..7d12d54 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -20,7 +20,7 @@
 static struct {
 	enum uclass_id id;
 	const char *name;
-} if_typename_str[] = {
+} uclass_idname_str[] = {
 	{ UCLASS_IDE, "ide" },
 	{ UCLASS_SCSI, "scsi" },
 	{ UCLASS_USB, "usb" },
@@ -34,19 +34,19 @@
 	{ UCLASS_PVBLOCK, "pvblock" },
 };
 
-static enum uclass_id if_typename_to_iftype(const char *if_typename)
+static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(if_typename_str); i++) {
-		if (!strcmp(if_typename, if_typename_str[i].name))
-			return if_typename_str[i].id;
+	for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
+		if (!strcmp(uclass_idname, uclass_idname_str[i].name))
+			return uclass_idname_str[i].id;
 	}
 
 	return UCLASS_INVALID;
 }
 
-static enum uclass_id if_type_to_uclass_id(enum uclass_id if_type)
+static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
 {
 	/*
 	 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
@@ -65,31 +65,30 @@
 	 *    - rename UCLASS_USB name to "usb_ctlr"
 	 *    - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
 	 */
-	if (if_type == UCLASS_USB)
+	if (uclass_id == UCLASS_USB)
 		return UCLASS_MASS_STORAGE;
-
-	return if_type;
+	return uclass_id;
 }
 
-const char *blk_get_if_type_name(enum uclass_id if_type)
+const char *blk_get_uclass_name(enum uclass_id uclass_id)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(if_typename_str); i++) {
-		if (if_typename_str[i].id == if_type)
-			return if_typename_str[i].name;
+	for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
+		if (uclass_idname_str[i].id == uclass_id)
+			return uclass_idname_str[i].name;
 	}
 
 	return "(none)";
 }
 
-struct blk_desc *blk_get_devnum_by_type(enum uclass_id if_type, int devnum)
+struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
 {
 	struct blk_desc *desc;
 	struct udevice *dev;
 	int ret;
 
-	ret = blk_get_device(if_type, devnum, &dev);
+	ret = blk_get_device(uclass_id, devnum, &dev);
 	if (ret)
 		return NULL;
 	desc = dev_get_uclass_plat(dev);
@@ -102,7 +101,7 @@
  * name in a local table. This gives us an interface type which we can match
  * against the uclass of the block device's parent.
  */
-struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
+struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
 {
 	enum uclass_id uclass_id;
 	enum uclass_id type;
@@ -110,16 +109,16 @@
 	struct uclass *uc;
 	int ret;
 
-	type = if_typename_to_iftype(if_typename);
+	type = uclass_name_to_iftype(uclass_idname);
 	if (type == UCLASS_INVALID) {
 		debug("%s: Unknown interface type '%s'\n", __func__,
-		      if_typename);
+		      uclass_idname);
 		return NULL;
 	}
-	uclass_id = if_type_to_uclass_id(type);
+	uclass_id = conv_uclass_id(type);
 	if (uclass_id == UCLASS_INVALID) {
 		debug("%s: Unknown uclass for interface type'\n",
-		      blk_get_if_type_name(type));
+		      blk_get_uclass_name(type));
 		return NULL;
 	}
 
@@ -129,8 +128,8 @@
 	uclass_foreach_dev(dev, uc) {
 		struct blk_desc *desc = dev_get_uclass_plat(dev);
 
-		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
-		      type, devnum, dev->name, desc->if_type, desc->devnum);
+		debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
+		      type, devnum, dev->name, desc->uclass_id, desc->devnum);
 		if (desc->devnum != devnum)
 			continue;
 
@@ -178,14 +177,14 @@
 /**
  * get_desc() - Get the block device descriptor for the given device number
  *
- * @if_type:	Interface type
+ * @uclass_id:	Interface type
  * @devnum:	Device number (0 = first)
  * @descp:	Returns block device descriptor on success
  * Return: 0 on success, -ENODEV if there is no such device and no device
  * with a higher device number, -ENOENT if there is no such device but there
  * is one with a higher number, or other -ve on other error.
  */
-static int get_desc(enum uclass_id if_type, int devnum, struct blk_desc **descp)
+static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
 {
 	bool found_more = false;
 	struct udevice *dev;
@@ -199,9 +198,9 @@
 	uclass_foreach_dev(dev, uc) {
 		struct blk_desc *desc = dev_get_uclass_plat(dev);
 
-		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
-		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
-		if (desc->if_type == if_type) {
+		debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
+		      uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
+		if (desc->uclass_id == uclass_id) {
 			if (desc->devnum == devnum) {
 				ret = device_probe(dev);
 				if (ret)
@@ -218,26 +217,26 @@
 	return found_more ? -ENOENT : -ENODEV;
 }
 
-int blk_select_hwpart_devnum(enum uclass_id if_type, int devnum, int hwpart)
+int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
 {
 	struct udevice *dev;
 	int ret;
 
-	ret = blk_get_device(if_type, devnum, &dev);
+	ret = blk_get_device(uclass_id, devnum, &dev);
 	if (ret)
 		return ret;
 
 	return blk_select_hwpart(dev, hwpart);
 }
 
-int blk_list_part(enum uclass_id if_type)
+int blk_list_part(enum uclass_id uclass_id)
 {
 	struct blk_desc *desc;
 	int devnum, ok;
 	int ret;
 
 	for (ok = 0, devnum = 0;; ++devnum) {
-		ret = get_desc(if_type, devnum, &desc);
+		ret = get_desc(uclass_id, devnum, &desc);
 		if (ret == -ENODEV)
 			break;
 		else if (ret)
@@ -255,12 +254,12 @@
 	return 0;
 }
 
-int blk_print_part_devnum(enum uclass_id if_type, int devnum)
+int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
 {
 	struct blk_desc *desc;
 	int ret;
 
-	ret = get_desc(if_type, devnum, &desc);
+	ret = get_desc(uclass_id, devnum, &desc);
 	if (ret)
 		return ret;
 	if (desc->type == DEV_TYPE_UNKNOWN)
@@ -270,14 +269,14 @@
 	return 0;
 }
 
-void blk_list_devices(enum uclass_id if_type)
+void blk_list_devices(enum uclass_id uclass_id)
 {
 	struct blk_desc *desc;
 	int ret;
 	int i;
 
 	for (i = 0;; ++i) {
-		ret = get_desc(if_type, i, &desc);
+		ret = get_desc(uclass_id, i, &desc);
 		if (ret == -ENODEV)
 			break;
 		else if (ret)
@@ -289,12 +288,12 @@
 	}
 }
 
-int blk_print_device_num(enum uclass_id if_type, int devnum)
+int blk_print_device_num(enum uclass_id uclass_id, int devnum)
 {
 	struct blk_desc *desc;
 	int ret;
 
-	ret = get_desc(if_type, devnum, &desc);
+	ret = get_desc(uclass_id, devnum, &desc);
 	if (ret)
 		return ret;
 	printf("\nIDE device %d: ", devnum);
@@ -303,13 +302,13 @@
 	return 0;
 }
 
-int blk_show_device(enum uclass_id if_type, int devnum)
+int blk_show_device(enum uclass_id uclass_id, int devnum)
 {
 	struct blk_desc *desc;
 	int ret;
 
 	printf("\nDevice %d: ", devnum);
-	ret = get_desc(if_type, devnum, &desc);
+	ret = get_desc(uclass_id, devnum, &desc);
 	if (ret == -ENODEV || ret == -ENOENT) {
 		printf("unknown device\n");
 		return -ENODEV;
@@ -324,14 +323,14 @@
 	return 0;
 }
 
-ulong blk_read_devnum(enum uclass_id if_type, int devnum, lbaint_t start,
+ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
 		      lbaint_t blkcnt, void *buffer)
 {
 	struct blk_desc *desc;
 	ulong n;
 	int ret;
 
-	ret = get_desc(if_type, devnum, &desc);
+	ret = get_desc(uclass_id, devnum, &desc);
 	if (ret)
 		return ret;
 	n = blk_dread(desc, start, blkcnt, buffer);
@@ -341,13 +340,13 @@
 	return n;
 }
 
-ulong blk_write_devnum(enum uclass_id if_type, int devnum, lbaint_t start,
+ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
 		       lbaint_t blkcnt, const void *buffer)
 {
 	struct blk_desc *desc;
 	int ret;
 
-	ret = get_desc(if_type, devnum, &desc);
+	ret = get_desc(uclass_id, devnum, &desc);
 	if (ret)
 		return ret;
 	return blk_dwrite(desc, start, blkcnt, buffer);
@@ -370,7 +369,7 @@
 	return blk_select_hwpart(desc->bdev, hwpart);
 }
 
-int blk_first_device(int if_type, struct udevice **devp)
+int blk_first_device(int uclass_id, struct udevice **devp)
 {
 	struct blk_desc *desc;
 	int ret;
@@ -382,7 +381,7 @@
 		return -ENODEV;
 	do {
 		desc = dev_get_uclass_plat(*devp);
-		if (desc->if_type == if_type)
+		if (desc->uclass_id == uclass_id)
 			return 0;
 		ret = uclass_find_next_device(devp);
 		if (ret)
@@ -395,10 +394,10 @@
 int blk_next_device(struct udevice **devp)
 {
 	struct blk_desc *desc;
-	int ret, if_type;
+	int ret, uclass_id;
 
 	desc = dev_get_uclass_plat(*devp);
-	if_type = desc->if_type;
+	uclass_id = desc->uclass_id;
 	do {
 		ret = uclass_find_next_device(devp);
 		if (ret)
@@ -406,12 +405,12 @@
 		if (!*devp)
 			return -ENODEV;
 		desc = dev_get_uclass_plat(*devp);
-		if (desc->if_type == if_type)
+		if (desc->uclass_id == uclass_id)
 			return 0;
 	} while (1);
 }
 
-int blk_find_device(int if_type, int devnum, struct udevice **devp)
+int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
 {
 	struct uclass *uc;
 	struct udevice *dev;
@@ -423,9 +422,9 @@
 	uclass_foreach_dev(dev, uc) {
 		struct blk_desc *desc = dev_get_uclass_plat(dev);
 
-		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
-		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
-		if (desc->if_type == if_type && desc->devnum == devnum) {
+		debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
+		      uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
+		if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
 			*devp = dev;
 			return 0;
 		}
@@ -434,11 +433,11 @@
 	return -ENODEV;
 }
 
-int blk_get_device(int if_type, int devnum, struct udevice **devp)
+int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
 {
 	int ret;
 
-	ret = blk_find_device(if_type, devnum, devp);
+	ret = blk_find_device(uclass_id, devnum, devp);
 	if (ret)
 		return ret;
 
@@ -455,12 +454,12 @@
 	if (!ops->read)
 		return -ENOSYS;
 
-	if (blkcache_read(block_dev->if_type, block_dev->devnum,
+	if (blkcache_read(block_dev->uclass_id, block_dev->devnum,
 			  start, blkcnt, block_dev->blksz, buffer))
 		return blkcnt;
 	blks_read = ops->read(dev, start, blkcnt, buffer);
 	if (blks_read == blkcnt)
-		blkcache_fill(block_dev->if_type, block_dev->devnum,
+		blkcache_fill(block_dev->uclass_id, block_dev->devnum,
 			      start, blkcnt, block_dev->blksz, buffer);
 
 	return blks_read;
@@ -475,7 +474,7 @@
 	if (!ops->write)
 		return -ENOSYS;
 
-	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+	blkcache_invalidate(block_dev->uclass_id, block_dev->devnum);
 	return ops->write(dev, start, blkcnt, buffer);
 }
 
@@ -488,7 +487,7 @@
 	if (!ops->erase)
 		return -ENOSYS;
 
-	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+	blkcache_invalidate(block_dev->uclass_id, block_dev->devnum);
 	return ops->erase(dev, start, blkcnt);
 }
 
@@ -525,7 +524,7 @@
 	return uclass_get_name(device_get_uclass_id(parent));
 };
 
-int blk_find_max_devnum(enum uclass_id if_type)
+int blk_find_max_devnum(enum uclass_id uclass_id)
 {
 	struct udevice *dev;
 	int max_devnum = -ENODEV;
@@ -538,18 +537,18 @@
 	uclass_foreach_dev(dev, uc) {
 		struct blk_desc *desc = dev_get_uclass_plat(dev);
 
-		if (desc->if_type == if_type && desc->devnum > max_devnum)
+		if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
 			max_devnum = desc->devnum;
 	}
 
 	return max_devnum;
 }
 
-int blk_next_free_devnum(enum uclass_id if_type)
+int blk_next_free_devnum(enum uclass_id uclass_id)
 {
 	int ret;
 
-	ret = blk_find_max_devnum(if_type);
+	ret = blk_find_max_devnum(uclass_id);
 	if (ret == -ENODEV)
 		return 0;
 	if (ret < 0)
@@ -631,7 +630,7 @@
 	return count;
 }
 
-static int blk_claim_devnum(enum uclass_id if_type, int devnum)
+static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
 {
 	struct udevice *dev;
 	struct uclass *uc;
@@ -643,8 +642,8 @@
 	uclass_foreach_dev(dev, uc) {
 		struct blk_desc *desc = dev_get_uclass_plat(dev);
 
-		if (desc->if_type == if_type && desc->devnum == devnum) {
-			int next = blk_next_free_devnum(if_type);
+		if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
+			int next = blk_next_free_devnum(uclass_id);
 
 			if (next < 0)
 				return next;
@@ -657,7 +656,7 @@
 }
 
 int blk_create_device(struct udevice *parent, const char *drv_name,
-		      const char *name, int if_type, int devnum, int blksz,
+		      const char *name, int uclass_id, int devnum, int blksz,
 		      lbaint_t lba, struct udevice **devp)
 {
 	struct blk_desc *desc;
@@ -665,9 +664,9 @@
 	int ret;
 
 	if (devnum == -1) {
-		devnum = blk_next_free_devnum(if_type);
+		devnum = blk_next_free_devnum(uclass_id);
 	} else {
-		ret = blk_claim_devnum(if_type, devnum);
+		ret = blk_claim_devnum(uclass_id, devnum);
 		if (ret < 0 && ret != -ENOENT)
 			return ret;
 	}
@@ -677,7 +676,7 @@
 	if (ret)
 		return ret;
 	desc = dev_get_uclass_plat(dev);
-	desc->if_type = if_type;
+	desc->uclass_id = uclass_id;
 	desc->blksz = blksz;
 	desc->log2blksz = LOG2(desc->blksz);
 	desc->lba = lba;
@@ -690,7 +689,7 @@
 }
 
 int blk_create_devicef(struct udevice *parent, const char *drv_name,
-		       const char *name, int if_type, int devnum, int blksz,
+		       const char *name, int uclass_id, int devnum, int blksz,
 		       lbaint_t lba, struct udevice **devp)
 {
 	char dev_name[30], *str;
@@ -701,7 +700,7 @@
 	if (!str)
 		return -ENOMEM;
 
-	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
+	ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
 				blksz, lba, devp);
 	if (ret) {
 		free(str);
@@ -725,7 +724,7 @@
 	return ret;
 }
 
-int blk_unbind_all(int if_type)
+int blk_unbind_all(int uclass_id)
 {
 	struct uclass *uc;
 	struct udevice *dev, *next;
@@ -737,7 +736,7 @@
 	uclass_foreach_dev_safe(dev, next, uc) {
 		struct blk_desc *desc = dev_get_uclass_plat(dev);
 
-		if (desc->if_type == if_type) {
+		if (desc->uclass_id == uclass_id) {
 			ret = device_remove(dev, DM_REMOVE_NORMAL);
 			if (ret)
 				return ret;
diff --git a/drivers/block/blk_legacy.c b/drivers/block/blk_legacy.c
index 8c6f9cb..5bf1d04 100644
--- a/drivers/block/blk_legacy.c
+++ b/drivers/block/blk_legacy.c
@@ -9,14 +9,14 @@
 #include <part.h>
 #include <linux/err.h>
 
-struct blk_driver *blk_driver_lookup_type(int if_type)
+struct blk_driver *blk_driver_lookup_type(int uclass_id)
 {
 	struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
 	const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
 	struct blk_driver *entry;
 
 	for (entry = drv; entry != drv + n_ents; entry++) {
-		if (if_type == entry->if_type)
+		if (uclass_id == entry->uclass_id)
 			return entry;
 	}
 
@@ -24,14 +24,14 @@
 	return NULL;
 }
 
-static struct blk_driver *blk_driver_lookup_typename(const char *if_typename)
+static struct blk_driver *blk_driver_lookup_typename(const char *uclass_idname)
 {
 	struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
 	const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
 	struct blk_driver *entry;
 
 	for (entry = drv; entry != drv + n_ents; entry++) {
-		if (!strcmp(if_typename, entry->if_typename))
+		if (!strcmp(uclass_idname, entry->uclass_idname))
 			return entry;
 	}
 
@@ -39,11 +39,11 @@
 	return NULL;
 }
 
-const char *blk_get_if_type_name(enum uclass_id if_type)
+const char *blk_get_uclass_name(enum uclass_id uclass_id)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 
-	return drv ? drv->if_typename : NULL;
+	return drv ? drv->uclass_idname : NULL;
 }
 
 /**
@@ -70,14 +70,14 @@
 	return drv->get_dev(devnum, descp);
 }
 
-int blk_list_part(enum uclass_id if_type)
+int blk_list_part(enum uclass_id uclass_id)
 {
 	struct blk_driver *drv;
 	struct blk_desc *desc;
 	int devnum, ok;
 	bool first = true;
 
-	drv = blk_driver_lookup_type(if_type);
+	drv = blk_driver_lookup_type(uclass_id);
 	if (!drv)
 		return -ENOSYS;
 	for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) {
@@ -97,9 +97,9 @@
 	return 0;
 }
 
-int blk_print_part_devnum(enum uclass_id if_type, int devnum)
+int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 	struct blk_desc *desc;
 	int ret;
 
@@ -115,9 +115,9 @@
 	return 0;
 }
 
-void blk_list_devices(enum uclass_id if_type)
+void blk_list_devices(enum uclass_id uclass_id)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 	struct blk_desc *desc;
 	int i;
 
@@ -133,9 +133,9 @@
 	}
 }
 
-int blk_print_device_num(enum uclass_id if_type, int devnum)
+int blk_print_device_num(enum uclass_id uclass_id, int devnum)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 	struct blk_desc *desc;
 	int ret;
 
@@ -144,15 +144,15 @@
 	ret = get_desc(drv, devnum, &desc);
 	if (ret)
 		return ret;
-	printf("\n%s device %d: ", drv->if_typename, devnum);
+	printf("\n%s device %d: ", drv->uclass_idname, devnum);
 	dev_print(desc);
 
 	return 0;
 }
 
-int blk_show_device(enum uclass_id if_type, int devnum)
+int blk_show_device(enum uclass_id uclass_id, int devnum)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 	struct blk_desc *desc;
 	int ret;
 
@@ -174,9 +174,9 @@
 	return 0;
 }
 
-struct blk_desc *blk_get_devnum_by_type(enum uclass_id if_type, int devnum)
+struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 	struct blk_desc *desc;
 
 	if (!drv)
@@ -190,7 +190,7 @@
 
 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(desc->if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(desc->uclass_id);
 
 	if (!drv)
 		return -ENOSYS;
@@ -200,9 +200,9 @@
 	return 0;
 }
 
-struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
+struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
 {
-	struct blk_driver *drv = blk_driver_lookup_typename(if_typename);
+	struct blk_driver *drv = blk_driver_lookup_typename(uclass_idname);
 	struct blk_desc *desc;
 
 	if (!drv)
@@ -214,10 +214,10 @@
 	return desc;
 }
 
-ulong blk_read_devnum(enum uclass_id if_type, int devnum, lbaint_t start,
+ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
 		      lbaint_t blkcnt, void *buffer)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 	struct blk_desc *desc;
 	ulong n;
 	int ret;
@@ -234,10 +234,10 @@
 	return n;
 }
 
-ulong blk_write_devnum(enum uclass_id if_type, int devnum, lbaint_t start,
+ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
 		       lbaint_t blkcnt, const void *buffer)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 	struct blk_desc *desc;
 	int ret;
 
@@ -249,9 +249,9 @@
 	return desc->block_write(desc, start, blkcnt, buffer);
 }
 
-int blk_select_hwpart_devnum(enum uclass_id if_type, int devnum, int hwpart)
+int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
 {
-	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_driver *drv = blk_driver_lookup_type(uclass_id);
 	struct blk_desc *desc;
 	int ret;
 
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index b8840d2..eaa58d8 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -537,7 +537,7 @@
 	/* Select device
 	 */
 	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
-	dev_desc->if_type = UCLASS_IDE;
+	dev_desc->uclass_id = UCLASS_IDE;
 #ifdef CONFIG_ATAPI
 
 	retries = 0;
@@ -752,7 +752,7 @@
 
 	for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i) {
 		ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
-		ide_dev_desc[i].if_type = UCLASS_IDE;
+		ide_dev_desc[i].uclass_id = UCLASS_IDE;
 		ide_dev_desc[i].devnum = i;
 		ide_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
 		ide_dev_desc[i].blksz = 0;
@@ -1143,8 +1143,8 @@
 };
 #else
 U_BOOT_LEGACY_BLK(ide) = {
-	.if_typename	= "ide",
-	.if_type	= UCLASS_IDE,
+	.uclass_idname	= "ide",
+	.uclass_id	= UCLASS_IDE,
 	.max_devs	= CONFIG_SYS_IDE_MAXDEVICE,
 	.desc		= ide_dev_desc,
 };
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
index 2de12e0..f2aae89 100644
--- a/drivers/block/sandbox.c
+++ b/drivers/block/sandbox.c
@@ -150,7 +150,7 @@
 		goto err_file;
 	}
 
-	desc = blk_get_devnum_by_type(UCLASS_ROOT, devnum);
+	desc = blk_get_devnum_by_uclass_id(UCLASS_ROOT, devnum);
 	desc->removable = removable;
 	snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
 	snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
@@ -192,7 +192,7 @@
 	}
 
 	struct blk_desc *blk_dev = &host_dev->blk_dev;
-	blk_dev->if_type = UCLASS_ROOT;
+	blk_dev->uclass_id = UCLASS_ROOT;
 	blk_dev->priv = host_dev;
 	blk_dev->blksz = 512;
 	blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz;
@@ -262,8 +262,8 @@
 };
 #else
 U_BOOT_LEGACY_BLK(sandbox_host) = {
-	.if_typename	= "host",
-	.if_type	= UCLASS_ROOT,
+	.uclass_idname	= "host",
+	.uclass_id	= UCLASS_ROOT,
 	.max_devs	= SANDBOX_HOST_MAX_DEVICES,
 	.get_dev	= host_get_dev_err,
 };
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index 522e724..1decf31 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -7,6 +7,8 @@
 obj-$(CONFIG_TARGET_MT7623) += clk-mt7623.o
 obj-$(CONFIG_TARGET_MT7622) += clk-mt7622.o
 obj-$(CONFIG_TARGET_MT7629) += clk-mt7629.o
+obj-$(CONFIG_TARGET_MT7986) += clk-mt7986.o
+obj-$(CONFIG_TARGET_MT7981) += clk-mt7981.o
 obj-$(CONFIG_TARGET_MT8183) += clk-mt8183.o
 obj-$(CONFIG_TARGET_MT8516) += clk-mt8516.o
 obj-$(CONFIG_TARGET_MT8518) += clk-mt8518.o
diff --git a/drivers/clk/mediatek/clk-mt7981.c b/drivers/clk/mediatek/clk-mt7981.c
new file mode 100644
index 0000000..7fcb814
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7981.c
@@ -0,0 +1,683 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek clock driver for MT7981 SoC
+ *
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <asm/arch-mediatek/reset.h>
+#include <asm/io.h>
+#include <dt-bindings/clock/mt7981-clk.h>
+#include <linux/bitops.h>
+
+#include "clk-mtk.h"
+
+#define MT7981_CLK_PDN 0x250
+#define MT7981_CLK_PDN_EN_WRITE BIT(31)
+
+#define PLL_FACTOR(_id, _name, _parent, _mult, _div)                           \
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_APMIXED)
+
+#define TOP_FACTOR(_id, _name, _parent, _mult, _div)                           \
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_TOPCKGEN)
+
+#define INFRA_FACTOR(_id, _name, _parent, _mult, _div)                         \
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_INFRASYS)
+
+/* FIXED PLLS */
+static const struct mtk_fixed_clk fixed_pll_clks[] = {
+	FIXED_CLK(CK_APMIXED_ARMPLL, CLK_XTAL, 1300000000),
+	FIXED_CLK(CK_APMIXED_NET2PLL, CLK_XTAL, 800000000),
+	FIXED_CLK(CK_APMIXED_MMPLL, CLK_XTAL, 720000000),
+	FIXED_CLK(CK_APMIXED_SGMPLL, CLK_XTAL, 325000000),
+	FIXED_CLK(CK_APMIXED_WEDMCUPLL, CLK_XTAL, 208000000),
+	FIXED_CLK(CK_APMIXED_NET1PLL, CLK_XTAL, 2500000000),
+	FIXED_CLK(CK_APMIXED_MPLL, CLK_XTAL, 416000000),
+	FIXED_CLK(CK_APMIXED_APLL2, CLK_XTAL, 196608000),
+};
+
+/* TOPCKGEN FIXED CLK */
+static const struct mtk_fixed_clk top_fixed_clks[] = {
+	FIXED_CLK(CK_TOP_CB_CKSQ_40M, CLK_XTAL, 40000000),
+};
+
+/* TOPCKGEN FIXED DIV */
+static const struct mtk_fixed_factor top_fixed_divs[] = {
+	PLL_FACTOR(CK_TOP_CB_M_416M, "cb_m_416m", CK_APMIXED_MPLL, 1, 1),
+	PLL_FACTOR(CK_TOP_CB_M_D2, "cb_m_d2", CK_APMIXED_MPLL, 1, 2),
+	PLL_FACTOR(CK_TOP_CB_M_D3, "cb_m_d3", CK_APMIXED_MPLL, 1, 3),
+	PLL_FACTOR(CK_TOP_M_D3_D2, "m_d3_d2", CK_APMIXED_MPLL, 1, 2),
+	PLL_FACTOR(CK_TOP_CB_M_D4, "cb_m_d4", CK_APMIXED_MPLL, 1, 4),
+	PLL_FACTOR(CK_TOP_CB_M_D8, "cb_m_d8", CK_APMIXED_MPLL, 1, 8),
+	PLL_FACTOR(CK_TOP_M_D8_D2, "m_d8_d2", CK_APMIXED_MPLL, 1, 16),
+	PLL_FACTOR(CK_TOP_CB_MM_720M, "cb_mm_720m", CK_APMIXED_MMPLL, 1, 1),
+	PLL_FACTOR(CK_TOP_CB_MM_D2, "cb_mm_d2", CK_APMIXED_MMPLL, 1, 2),
+	PLL_FACTOR(CK_TOP_CB_MM_D3, "cb_mm_d3", CK_APMIXED_MMPLL, 1, 3),
+	PLL_FACTOR(CK_TOP_CB_MM_D3_D5, "cb_mm_d3_d5", CK_APMIXED_MMPLL, 1, 15),
+	PLL_FACTOR(CK_TOP_CB_MM_D4, "cb_mm_d4", CK_APMIXED_MMPLL, 1, 4),
+	PLL_FACTOR(CK_TOP_CB_MM_D6, "cb_mm_d6", CK_APMIXED_MMPLL, 1, 6),
+	PLL_FACTOR(CK_TOP_MM_D6_D2, "mm_d6_d2", CK_APMIXED_MMPLL, 1, 12),
+	PLL_FACTOR(CK_TOP_CB_MM_D8, "cb_mm_d8", CK_APMIXED_MMPLL, 1, 8),
+	PLL_FACTOR(CK_TOP_CB_APLL2_196M, "cb_apll2_196m", CK_APMIXED_APLL2, 1,
+		   1),
+	PLL_FACTOR(CK_TOP_APLL2_D2, "apll2_d2", CK_APMIXED_APLL2, 1, 2),
+	PLL_FACTOR(CK_TOP_APLL2_D4, "apll2_d4", CK_APMIXED_APLL2, 1, 4),
+	PLL_FACTOR(CK_TOP_NET1_2500M, "net1_2500m", CK_APMIXED_NET1PLL, 1, 1),
+	PLL_FACTOR(CK_TOP_CB_NET1_D4, "cb_net1_d4", CK_APMIXED_NET1PLL, 1, 4),
+	PLL_FACTOR(CK_TOP_CB_NET1_D5, "cb_net1_d5", CK_APMIXED_NET1PLL, 1, 5),
+	PLL_FACTOR(CK_TOP_NET1_D5_D2, "net1_d5_d2", CK_APMIXED_NET1PLL, 1, 10),
+	PLL_FACTOR(CK_TOP_NET1_D5_D4, "net1_d5_d4", CK_APMIXED_NET1PLL, 1, 20),
+	PLL_FACTOR(CK_TOP_CB_NET1_D8, "cb_net1_d8", CK_APMIXED_NET1PLL, 1, 8),
+	PLL_FACTOR(CK_TOP_NET1_D8_D2, "net1_d8_d2", CK_APMIXED_NET1PLL, 1, 16),
+	PLL_FACTOR(CK_TOP_NET1_D8_D4, "net1_d8_d4", CK_APMIXED_NET1PLL, 1, 32),
+	PLL_FACTOR(CK_TOP_CB_NET2_800M, "cb_net2_800m", CK_APMIXED_NET2PLL, 1,
+		   1),
+	PLL_FACTOR(CK_TOP_CB_NET2_D2, "cb_net2_d2", CK_APMIXED_NET2PLL, 1, 2),
+	PLL_FACTOR(CK_TOP_CB_NET2_D4, "cb_net2_d4", CK_APMIXED_NET2PLL, 1, 4),
+	PLL_FACTOR(CK_TOP_NET2_D4_D2, "net2_d4_d2", CK_APMIXED_NET2PLL, 1, 8),
+	PLL_FACTOR(CK_TOP_NET2_D4_D4, "net2_d4_d4", CK_APMIXED_NET2PLL, 1, 16),
+	PLL_FACTOR(CK_TOP_CB_NET2_D6, "cb_net2_d6", CK_APMIXED_NET2PLL, 1, 6),
+	PLL_FACTOR(CK_TOP_CB_WEDMCU_208M, "cb_wedmcu_208m",
+		   CK_APMIXED_WEDMCUPLL, 1, 1),
+	PLL_FACTOR(CK_TOP_CB_SGM_325M, "cb_sgm_325m", CK_APMIXED_SGMPLL, 1, 1),
+	TOP_FACTOR(CK_TOP_CKSQ_40M_D2, "cksq_40m_d2", CK_TOP_CB_CKSQ_40M, 1, 2),
+	TOP_FACTOR(CK_TOP_CB_RTC_32K, "cb_rtc_32k", CK_TOP_CB_CKSQ_40M, 1,
+		   1250),
+	TOP_FACTOR(CK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", CK_TOP_CB_CKSQ_40M, 1,
+		   1220),
+	TOP_FACTOR(CK_TOP_USB_TX250M, "usb_tx250m", CK_TOP_CB_CKSQ_40M, 1, 1),
+	TOP_FACTOR(CK_TOP_FAUD, "faud", CK_TOP_CB_CKSQ_40M, 1, 1),
+	TOP_FACTOR(CK_TOP_NFI1X, "nfi1x", CK_TOP_NFI1X_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_USB_EQ_RX250M, "usb_eq_rx250m", CK_TOP_CB_CKSQ_40M, 1,
+		   1),
+	TOP_FACTOR(CK_TOP_USB_CDR_CK, "usb_cdr", CK_TOP_CB_CKSQ_40M, 1, 1),
+	TOP_FACTOR(CK_TOP_USB_LN0_CK, "usb_ln0", CK_TOP_CB_CKSQ_40M, 1, 1),
+	TOP_FACTOR(CK_TOP_SPINFI_BCK, "spinfi_bck", CK_TOP_SPINFI_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_SPI, "spi", CK_TOP_SPI_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_SPIM_MST, "spim_mst", CK_TOP_SPIM_MST_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_UART_BCK, "uart_bck", CK_TOP_UART_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_PWM_BCK, "pwm_bck", CK_TOP_PWM_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_I2C_BCK, "i2c_bck", CK_TOP_I2C_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_PEXTP_TL, "pextp_tl", CK_TOP_PEXTP_TL_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_EMMC_208M, "emmc_208m", CK_TOP_EMMC_208M_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_EMMC_400M, "emmc_400m", CK_TOP_EMMC_400M_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_DRAMC_REF, "dramc_ref", CK_TOP_DRAMC_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_DRAMC_MD32, "dramc_md32", CK_TOP_DRAMC_MD32_SEL, 1,
+		   1),
+	TOP_FACTOR(CK_TOP_SYSAXI, "sysaxi", CK_TOP_SYSAXI_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_SYSAPB, "sysapb", CK_TOP_SYSAPB_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_ARM_DB_MAIN, "arm_db_main", CK_TOP_ARM_DB_MAIN_SEL, 1,
+		   1),
+	TOP_FACTOR(CK_TOP_AP2CNN_HOST, "ap2cnn_host", CK_TOP_AP2CNN_HOST_SEL, 1,
+		   1),
+	TOP_FACTOR(CK_TOP_NETSYS, "netsys", CK_TOP_NETSYS_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_NETSYS_500M, "netsys_500m", CK_TOP_NETSYS_500M_SEL, 1,
+		   1),
+	TOP_FACTOR(CK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu",
+		   CK_TOP_NETSYS_MCU_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_NETSYS_2X, "netsys_2x", CK_TOP_NETSYS_2X_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_SGM_325M, "sgm_325m", CK_TOP_SGM_325M_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_SGM_REG, "sgm_reg", CK_TOP_SGM_REG_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_F26M, "csw_f26m", CK_TOP_F26M_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_EIP97B, "eip97b", CK_TOP_EIP97B_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_USB3_PHY, "usb3_phy", CK_TOP_USB3_PHY_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_AUD, "aud", CK_TOP_FAUD, 1, 1),
+	TOP_FACTOR(CK_TOP_A1SYS, "a1sys", CK_TOP_A1SYS_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_AUD_L, "aud_l", CK_TOP_AUD_L_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_A_TUNER, "a_tuner", CK_TOP_A_TUNER_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_U2U3_REF, "u2u3_ref", CK_TOP_U2U3_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_U2U3_SYS, "u2u3_sys", CK_TOP_U2U3_SYS_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_U2U3_XHCI, "u2u3_xhci", CK_TOP_U2U3_XHCI_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_USB_FRMCNT, "usb_frmcnt", CK_TOP_USB_FRMCNT_SEL, 1,
+		   1),
+};
+
+/* TOPCKGEN MUX PARENTS */
+static const int nfi1x_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_MM_D4,
+				     CK_TOP_NET1_D8_D2,  CK_TOP_CB_NET2_D6,
+				     CK_TOP_CB_M_D4,     CK_TOP_CB_MM_D8,
+				     CK_TOP_NET1_D8_D4,  CK_TOP_CB_M_D8 };
+
+static const int spinfi_parents[] = { CK_TOP_CKSQ_40M_D2, CK_TOP_CB_CKSQ_40M,
+				      CK_TOP_NET1_D5_D4,  CK_TOP_CB_M_D4,
+				      CK_TOP_CB_MM_D8,    CK_TOP_NET1_D8_D4,
+				      CK_TOP_MM_D6_D2,    CK_TOP_CB_M_D8 };
+
+static const int spi_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_M_D2,
+				   CK_TOP_CB_MM_D4,    CK_TOP_NET1_D8_D2,
+				   CK_TOP_CB_NET2_D6,  CK_TOP_NET1_D5_D4,
+				   CK_TOP_CB_M_D4,     CK_TOP_NET1_D8_D4 };
+
+static const int uart_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_M_D8,
+				    CK_TOP_M_D8_D2 };
+
+static const int pwm_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D8_D2,
+				   CK_TOP_NET1_D5_D4,  CK_TOP_CB_M_D4,
+				   CK_TOP_M_D8_D2,     CK_TOP_CB_RTC_32K };
+
+static const int i2c_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D5_D4,
+				   CK_TOP_CB_M_D4, CK_TOP_NET1_D8_D4 };
+
+static const int pextp_tl_ck_parents[] = { CK_TOP_CB_CKSQ_40M,
+					   CK_TOP_NET1_D5_D4, CK_TOP_CB_M_D4,
+					   CK_TOP_CB_RTC_32K };
+
+static const int emmc_208m_parents[] = {
+	CK_TOP_CB_CKSQ_40M,   CK_TOP_CB_M_D2,  CK_TOP_CB_NET2_D4,
+	CK_TOP_CB_APLL2_196M, CK_TOP_CB_MM_D4, CK_TOP_NET1_D8_D2,
+	CK_TOP_CB_MM_D6
+};
+
+static const int emmc_400m_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_NET2_D2,
+					 CK_TOP_CB_MM_D2, CK_TOP_CB_NET2_D2 };
+
+static const int csw_f26m_parents[] = { CK_TOP_CKSQ_40M_D2, CK_TOP_M_D8_D2 };
+
+static const int dramc_md32_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_M_D2,
+					  CK_TOP_CB_WEDMCU_208M };
+
+static const int sysaxi_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D8_D2 };
+
+static const int sysapb_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_M_D3_D2 };
+
+static const int arm_db_main_parents[] = { CK_TOP_CB_CKSQ_40M,
+					   CK_TOP_CB_NET2_D6 };
+
+static const int ap2cnn_host_parents[] = { CK_TOP_CB_CKSQ_40M,
+					   CK_TOP_NET1_D8_D4 };
+
+static const int netsys_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_MM_D2 };
+
+static const int netsys_500m_parents[] = { CK_TOP_CB_CKSQ_40M,
+					   CK_TOP_CB_NET1_D5 };
+
+static const int netsys_mcu_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_MM_720M,
+					  CK_TOP_CB_NET1_D4, CK_TOP_CB_NET1_D5,
+					  CK_TOP_CB_M_416M };
+
+static const int netsys_2x_parents[] = { CK_TOP_CB_CKSQ_40M,
+					 CK_TOP_CB_NET2_800M,
+					 CK_TOP_CB_MM_720M };
+
+static const int sgm_325m_parents[] = { CK_TOP_CB_CKSQ_40M,
+					CK_TOP_CB_SGM_325M };
+
+static const int sgm_reg_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_NET2_D4 };
+
+static const int eip97b_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_NET1_D5,
+				      CK_TOP_CB_M_416M, CK_TOP_CB_MM_D2,
+				      CK_TOP_NET1_D5_D2 };
+
+static const int aud_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_APLL2_196M };
+
+static const int a1sys_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_APLL2_D4 };
+
+static const int aud_l_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_APLL2_196M,
+				     CK_TOP_M_D8_D2 };
+
+static const int a_tuner_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_APLL2_D4,
+				       CK_TOP_M_D8_D2 };
+
+static const int u2u3_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_M_D8_D2 };
+
+static const int u2u3_sys_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D5_D4 };
+
+static const int usb_frmcnt_parents[] = { CK_TOP_CB_CKSQ_40M,
+					  CK_TOP_CB_MM_D3_D5 };
+
+#define TOP_MUX(_id, _name, _parents, _mux_ofs, _mux_set_ofs, _mux_clr_ofs,    \
+		_shift, _width, _gate, _upd_ofs, _upd)                         \
+	{                                                                      \
+		.id = _id, .mux_reg = _mux_ofs, .mux_set_reg = _mux_set_ofs,   \
+		.mux_clr_reg = _mux_clr_ofs, .upd_reg = _upd_ofs,              \
+		.upd_shift = _upd, .mux_shift = _shift,                        \
+		.mux_mask = BIT(_width) - 1, .gate_reg = _mux_ofs,             \
+		.gate_shift = _gate, .parent = _parents,                       \
+		.num_parents = ARRAY_SIZE(_parents),                           \
+		.flags = CLK_MUX_SETCLR_UPD,                                   \
+	}
+
+/* TOPCKGEN MUX_GATE */
+static const struct mtk_composite top_muxes[] = {
+	TOP_MUX(CK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents, 0x0, 0x4, 0x8, 0,
+		3, 7, 0x1c0, 0),
+	TOP_MUX(CK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents, 0x0, 0x4, 0x8,
+		8, 3, 15, 0x1c0, 1),
+	TOP_MUX(CK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x0, 0x4, 0x8, 16, 3,
+		23, 0x1c0, 2),
+	TOP_MUX(CK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents, 0x0, 0x4, 0x8,
+		24, 3, 31, 0x1c0, 3),
+	TOP_MUX(CK_TOP_UART_SEL, "uart_sel", uart_parents, 0x10, 0x14, 0x18, 0,
+		2, 7, 0x1c0, 4),
+	TOP_MUX(CK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x10, 0x14, 0x18, 8, 3,
+		15, 0x1c0, 5),
+	TOP_MUX(CK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x10, 0x14, 0x18, 16, 2,
+		23, 0x1c0, 6),
+	TOP_MUX(CK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel", pextp_tl_ck_parents,
+		0x10, 0x14, 0x18, 24, 2, 31, 0x1c0, 7),
+	TOP_MUX(CK_TOP_EMMC_208M_SEL, "emmc_208m_sel", emmc_208m_parents, 0x20,
+		0x24, 0x28, 0, 3, 7, 0x1c0, 8),
+	TOP_MUX(CK_TOP_EMMC_400M_SEL, "emmc_400m_sel", emmc_400m_parents, 0x20,
+		0x24, 0x28, 8, 2, 15, 0x1c0, 9),
+	TOP_MUX(CK_TOP_F26M_SEL, "csw_f26m_sel", csw_f26m_parents, 0x20, 0x24,
+		0x28, 16, 1, 23, 0x1c0, 10),
+	TOP_MUX(CK_TOP_DRAMC_SEL, "dramc_sel", csw_f26m_parents, 0x20, 0x24,
+		0x28, 24, 1, 31, 0x1c0, 11),
+	TOP_MUX(CK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel", dramc_md32_parents,
+		0x30, 0x34, 0x38, 0, 2, 7, 0x1c0, 12),
+	TOP_MUX(CK_TOP_SYSAXI_SEL, "sysaxi_sel", sysaxi_parents, 0x30, 0x34,
+		0x38, 8, 1, 15, 0x1c0, 13),
+	TOP_MUX(CK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents, 0x30, 0x34,
+		0x38, 16, 1, 23, 0x1c0, 14),
+	TOP_MUX(CK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel", arm_db_main_parents,
+		0x30, 0x34, 0x38, 24, 1, 31, 0x1c0, 15),
+	TOP_MUX(CK_TOP_AP2CNN_HOST_SEL, "ap2cnn_host_sel", ap2cnn_host_parents,
+		0x40, 0x44, 0x48, 0, 1, 7, 0x1c0, 16),
+	TOP_MUX(CK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents, 0x40, 0x44,
+		0x48, 8, 1, 15, 0x1c0, 17),
+	TOP_MUX(CK_TOP_NETSYS_500M_SEL, "netsys_500m_sel", netsys_500m_parents,
+		0x40, 0x44, 0x48, 16, 1, 23, 0x1c0, 18),
+	TOP_MUX(CK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel", netsys_mcu_parents,
+		0x40, 0x44, 0x48, 24, 3, 31, 0x1c0, 19),
+	TOP_MUX(CK_TOP_NETSYS_2X_SEL, "netsys_2x_sel", netsys_2x_parents, 0x50,
+		0x54, 0x58, 0, 2, 7, 0x1c0, 20),
+	TOP_MUX(CK_TOP_SGM_325M_SEL, "sgm_325m_sel", sgm_325m_parents, 0x50,
+		0x54, 0x58, 8, 1, 15, 0x1c0, 21),
+	TOP_MUX(CK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents, 0x50, 0x54,
+		0x58, 16, 1, 23, 0x1c0, 22),
+	TOP_MUX(CK_TOP_EIP97B_SEL, "eip97b_sel", eip97b_parents, 0x50, 0x54,
+		0x58, 24, 3, 31, 0x1c0, 23),
+	TOP_MUX(CK_TOP_USB3_PHY_SEL, "usb3_phy_sel", csw_f26m_parents, 0x60,
+		0x64, 0x68, 0, 1, 7, 0x1c0, 24),
+	TOP_MUX(CK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x60, 0x64, 0x68, 8, 1,
+		15, 0x1c0, 25),
+	TOP_MUX(CK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents, 0x60, 0x64, 0x68,
+		16, 1, 23, 0x1c0, 26),
+	TOP_MUX(CK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents, 0x60, 0x64, 0x68,
+		24, 2, 31, 0x1c0, 27),
+	TOP_MUX(CK_TOP_A_TUNER_SEL, "a_tuner_sel", a_tuner_parents, 0x70, 0x74,
+		0x78, 0, 2, 7, 0x1c0, 28),
+	TOP_MUX(CK_TOP_U2U3_SEL, "u2u3_sel", u2u3_parents, 0x70, 0x74, 0x78, 8,
+		1, 15, 0x1c0, 29),
+	TOP_MUX(CK_TOP_U2U3_SYS_SEL, "u2u3_sys_sel", u2u3_sys_parents, 0x70,
+		0x74, 0x78, 16, 1, 23, 0x1c0, 30),
+	TOP_MUX(CK_TOP_U2U3_XHCI_SEL, "u2u3_xhci_sel", u2u3_sys_parents, 0x70,
+		0x74, 0x78, 24, 1, 31, 0x1c4, 0),
+	TOP_MUX(CK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel", usb_frmcnt_parents,
+		0x80, 0x84, 0x88, 0, 1, 7, 0x1c4, 1),
+};
+
+/* INFRA FIXED DIV */
+static const struct mtk_fixed_factor infra_fixed_divs[] = {
+	TOP_FACTOR(CK_INFRA_CK_F26M, "infra_ck_f26m", CK_TOP_F26M_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_UART, "infra_uart", CK_TOP_UART_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_ISPI0, "infra_ispi0", CK_TOP_SPI_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_I2C, "infra_i2c", CK_TOP_I2C_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_ISPI1, "infra_ispi1", CK_TOP_SPIM_MST_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_PWM, "infra_pwm", CK_TOP_PWM_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_66M_MCK, "infra_66m_mck", CK_TOP_SYSAXI_SEL, 1, 2),
+	TOP_FACTOR(CK_INFRA_CK_F32K, "infra_ck_f32k", CK_TOP_CB_RTC_32P7K, 1,
+		   1),
+	TOP_FACTOR(CK_INFRA_PCIE_CK, "infra_pcie", CK_TOP_PEXTP_TL_SEL, 1, 1),
+	INFRA_FACTOR(CK_INFRA_PWM_BCK, "infra_pwm_bck", CK_INFRA_PWM_BSEL, 1,
+		     1),
+	INFRA_FACTOR(CK_INFRA_PWM_CK1, "infra_pwm_ck1", CK_INFRA_PWM1_SEL, 1,
+		     1),
+	INFRA_FACTOR(CK_INFRA_PWM_CK2, "infra_pwm_ck2", CK_INFRA_PWM2_SEL, 1,
+		     1),
+	TOP_FACTOR(CK_INFRA_133M_HCK, "infra_133m_hck", CK_TOP_SYSAXI, 1, 1),
+	INFRA_FACTOR(CK_INFRA_66M_PHCK, "infra_66m_phck", CK_INFRA_133M_HCK, 1,
+		     1),
+	TOP_FACTOR(CK_INFRA_FAUD_L_CK, "infra_faud_l", CK_TOP_AUD_L, 1, 1),
+	TOP_FACTOR(CK_INFRA_FAUD_AUD_CK, "infra_faud_aud", CK_TOP_A1SYS, 1, 1),
+	TOP_FACTOR(CK_INFRA_FAUD_EG2_CK, "infra_faud_eg2", CK_TOP_A_TUNER, 1,
+		   1),
+	TOP_FACTOR(CK_INFRA_I2CS_CK, "infra_i2cs", CK_TOP_I2C_BCK, 1, 1),
+	INFRA_FACTOR(CK_INFRA_MUX_UART0, "infra_mux_uart0", CK_INFRA_UART0_SEL,
+		     1, 1),
+	INFRA_FACTOR(CK_INFRA_MUX_UART1, "infra_mux_uart1", CK_INFRA_UART1_SEL,
+		     1, 1),
+	INFRA_FACTOR(CK_INFRA_MUX_UART2, "infra_mux_uart2", CK_INFRA_UART2_SEL,
+		     1, 1),
+	TOP_FACTOR(CK_INFRA_NFI_CK, "infra_nfi", CK_TOP_NFI1X, 1, 1),
+	TOP_FACTOR(CK_INFRA_SPINFI_CK, "infra_spinfi", CK_TOP_SPINFI_BCK, 1, 1),
+	INFRA_FACTOR(CK_INFRA_MUX_SPI0, "infra_mux_spi0", CK_INFRA_SPI0_SEL, 1,
+		     1),
+	INFRA_FACTOR(CK_INFRA_MUX_SPI1, "infra_mux_spi1", CK_INFRA_SPI1_SEL, 1,
+		     1),
+	INFRA_FACTOR(CK_INFRA_MUX_SPI2, "infra_mux_spi2", CK_INFRA_SPI2_SEL, 1,
+		     1),
+	TOP_FACTOR(CK_INFRA_RTC_32K, "infra_rtc_32k", CK_TOP_CB_RTC_32K, 1, 1),
+	TOP_FACTOR(CK_INFRA_FMSDC_CK, "infra_fmsdc", CK_TOP_EMMC_400M, 1, 1),
+	TOP_FACTOR(CK_INFRA_FMSDC_HCK_CK, "infra_fmsdc_hck", CK_TOP_EMMC_208M,
+		   1, 1),
+	TOP_FACTOR(CK_INFRA_PERI_133M, "infra_peri_133m", CK_TOP_SYSAXI, 1, 1),
+	TOP_FACTOR(CK_INFRA_133M_PHCK, "infra_133m_phck", CK_TOP_SYSAXI, 1, 1),
+	TOP_FACTOR(CK_INFRA_USB_SYS_CK, "infra_usb_sys", CK_TOP_U2U3_SYS, 1, 1),
+	TOP_FACTOR(CK_INFRA_USB_CK, "infra_usb", CK_TOP_U2U3_REF, 1, 1),
+	TOP_FACTOR(CK_INFRA_USB_XHCI_CK, "infra_usb_xhci", CK_TOP_U2U3_XHCI, 1,
+		   1),
+	TOP_FACTOR(CK_INFRA_PCIE_GFMUX_TL_O_PRE, "infra_pcie_mux",
+		   CK_TOP_PEXTP_TL, 1, 1),
+	TOP_FACTOR(CK_INFRA_F26M_CK0, "infra_f26m_ck0", CK_TOP_F26M, 1, 1),
+	TOP_FACTOR(CK_INFRA_133M_MCK, "infra_133m_mck", CK_TOP_SYSAXI, 1, 1),
+};
+
+/* INFRASYS MUX PARENTS */
+static const int infra_uart0_parents[] = { CK_INFRA_CK_F26M, CK_INFRA_UART };
+
+static const int infra_spi0_parents[] = { CK_INFRA_I2C, CK_INFRA_ISPI0 };
+
+static const int infra_spi1_parents[] = { CK_INFRA_I2C, CK_INFRA_ISPI1 };
+
+static const int infra_pwm1_parents[] = { -1, -1, -1, CK_INFRA_PWM };
+
+static const int infra_pwm_bsel_parents[] = { -1, -1, -1, CK_INFRA_PWM };
+
+static const int infra_pcie_parents[] = { CK_INFRA_CK_F32K, CK_INFRA_CK_F26M,
+					  CK_TOP_CB_CKSQ_40M, CK_INFRA_PCIE_CK};
+
+#define INFRA_MUX(_id, _name, _parents, _reg, _shift, _width)                  \
+	{                                                                      \
+		.id = _id, .mux_reg = (_reg) + 0x8,                            \
+		.mux_set_reg = (_reg) + 0x0, .mux_clr_reg = (_reg) + 0x4,      \
+		.mux_shift = _shift, .mux_mask = BIT(_width) - 1,              \
+		.parent = _parents, .num_parents = ARRAY_SIZE(_parents),       \
+		.flags = CLK_MUX_SETCLR_UPD | CLK_PARENT_INFRASYS,             \
+	}
+
+/* INFRA MUX */
+static const struct mtk_composite infra_muxes[] = {
+	INFRA_MUX(CK_INFRA_UART0_SEL, "infra_uart0_sel", infra_uart0_parents,
+		  0x10, 0, 1),
+	INFRA_MUX(CK_INFRA_UART1_SEL, "infra_uart1_sel", infra_uart0_parents,
+		  0x10, 1, 1),
+	INFRA_MUX(CK_INFRA_UART2_SEL, "infra_uart2_sel", infra_uart0_parents,
+		  0x10, 2, 1),
+	INFRA_MUX(CK_INFRA_SPI0_SEL, "infra_spi0_sel", infra_spi0_parents, 0x10,
+		  4, 1),
+	INFRA_MUX(CK_INFRA_SPI1_SEL, "infra_spi1_sel", infra_spi1_parents, 0x10,
+		  5, 1),
+	INFRA_MUX(CK_INFRA_SPI2_SEL, "infra_spi2_sel", infra_spi0_parents, 0x10,
+		  6, 1),
+	INFRA_MUX(CK_INFRA_PWM1_SEL, "infra_pwm1_sel", infra_pwm1_parents, 0x10,
+		  9, 2),
+	INFRA_MUX(CK_INFRA_PWM2_SEL, "infra_pwm2_sel", infra_pwm1_parents, 0x10,
+		  11, 2),
+	INFRA_MUX(CK_INFRA_PWM_BSEL, "infra_pwm_bsel", infra_pwm_bsel_parents,
+		  0x10, 13, 2),
+	INFRA_MUX(CK_INFRA_PCIE_SEL, "infra_pcie_sel", infra_pcie_parents, 0x20,
+		  0, 2),
+};
+
+static const struct mtk_gate_regs infra_0_cg_regs = {
+	.set_ofs = 0x40,
+	.clr_ofs = 0x44,
+	.sta_ofs = 0x48,
+};
+
+static const struct mtk_gate_regs infra_1_cg_regs = {
+	.set_ofs = 0x50,
+	.clr_ofs = 0x54,
+	.sta_ofs = 0x58,
+};
+
+static const struct mtk_gate_regs infra_2_cg_regs = {
+	.set_ofs = 0x60,
+	.clr_ofs = 0x64,
+	.sta_ofs = 0x68,
+};
+
+#define GATE_INFRA0(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .parent = _parent, .regs = &infra_0_cg_regs,        \
+		.shift = _shift,                                               \
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_INFRASYS,                \
+	}
+
+#define GATE_INFRA1(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .parent = _parent, .regs = &infra_1_cg_regs,        \
+		.shift = _shift,                                               \
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_INFRASYS,                \
+	}
+
+#define GATE_INFRA2(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .parent = _parent, .regs = &infra_2_cg_regs,        \
+		.shift = _shift,                                               \
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_INFRASYS,                \
+	}
+
+/* INFRA GATE */
+static const struct mtk_gate infracfg_ao_gates[] = {
+	GATE_INFRA0(CK_INFRA_GPT_STA, "infra_gpt_sta", CK_INFRA_66M_MCK, 0),
+	GATE_INFRA0(CK_INFRA_PWM_HCK, "infra_pwm_hck", CK_INFRA_66M_MCK, 1),
+	GATE_INFRA0(CK_INFRA_PWM_STA, "infra_pwm_sta", CK_INFRA_PWM_BCK, 2),
+	GATE_INFRA0(CK_INFRA_PWM1_CK, "infra_pwm1", CK_INFRA_PWM_CK1, 3),
+	GATE_INFRA0(CK_INFRA_PWM2_CK, "infra_pwm2", CK_INFRA_PWM_CK2, 4),
+	GATE_INFRA0(CK_INFRA_CQ_DMA_CK, "infra_cq_dma", CK_INFRA_133M_HCK, 6),
+	GATE_INFRA0(CK_INFRA_AUD_BUS_CK, "infra_aud_bus", CK_INFRA_66M_PHCK, 8),
+	GATE_INFRA0(CK_INFRA_AUD_26M_CK, "infra_aud_26m", CK_INFRA_CK_F26M, 9),
+	GATE_INFRA0(CK_INFRA_AUD_L_CK, "infra_aud_l", CK_INFRA_FAUD_L_CK, 10),
+	GATE_INFRA0(CK_INFRA_AUD_AUD_CK, "infra_aud_aud", CK_INFRA_FAUD_AUD_CK,
+		    11),
+	GATE_INFRA0(CK_INFRA_AUD_EG2_CK, "infra_aud_eg2", CK_INFRA_FAUD_EG2_CK,
+		    13),
+	GATE_INFRA0(CK_INFRA_DRAMC_26M_CK, "infra_dramc_26m", CK_INFRA_CK_F26M,
+		    14),
+	GATE_INFRA0(CK_INFRA_DBG_CK, "infra_dbg", CK_INFRA_66M_MCK, 15),
+	GATE_INFRA0(CK_INFRA_AP_DMA_CK, "infra_ap_dma", CK_INFRA_66M_MCK, 16),
+	GATE_INFRA0(CK_INFRA_SEJ_CK, "infra_sej", CK_INFRA_66M_MCK, 24),
+	GATE_INFRA0(CK_INFRA_SEJ_13M_CK, "infra_sej_13m", CK_INFRA_CK_F26M, 25),
+	GATE_INFRA1(CK_INFRA_THERM_CK, "infra_therm", CK_INFRA_CK_F26M, 0),
+	GATE_INFRA1(CK_INFRA_I2CO_CK, "infra_i2co", CK_INFRA_I2CS_CK, 1),
+	GATE_INFRA1(CK_INFRA_UART0_CK, "infra_uart0", CK_INFRA_MUX_UART0, 2),
+	GATE_INFRA1(CK_INFRA_UART1_CK, "infra_uart1", CK_INFRA_MUX_UART1, 3),
+	GATE_INFRA1(CK_INFRA_UART2_CK, "infra_uart2", CK_INFRA_MUX_UART2, 4),
+	GATE_INFRA1(CK_INFRA_SPI2_CK, "infra_spi2", CK_INFRA_MUX_SPI2, 6),
+	GATE_INFRA1(CK_INFRA_SPI2_HCK_CK, "infra_spi2_hck", CK_INFRA_66M_MCK,
+		    7),
+	GATE_INFRA1(CK_INFRA_NFI1_CK, "infra_nfi1", CK_INFRA_NFI_CK, 8),
+	GATE_INFRA1(CK_INFRA_SPINFI1_CK, "infra_spinfi1", CK_INFRA_SPINFI_CK,
+		    9),
+	GATE_INFRA1(CK_INFRA_NFI_HCK_CK, "infra_nfi_hck", CK_INFRA_66M_MCK, 10),
+	GATE_INFRA1(CK_INFRA_SPI0_CK, "infra_spi0", CK_INFRA_MUX_SPI0, 11),
+	GATE_INFRA1(CK_INFRA_SPI1_CK, "infra_spi1", CK_INFRA_MUX_SPI1, 12),
+	GATE_INFRA1(CK_INFRA_SPI0_HCK_CK, "infra_spi0_hck", CK_INFRA_66M_MCK,
+		    13),
+	GATE_INFRA1(CK_INFRA_SPI1_HCK_CK, "infra_spi1_hck", CK_INFRA_66M_MCK,
+		    14),
+	GATE_INFRA1(CK_INFRA_FRTC_CK, "infra_frtc", CK_INFRA_RTC_32K, 15),
+	GATE_INFRA1(CK_INFRA_MSDC_CK, "infra_msdc", CK_INFRA_FMSDC_CK, 16),
+	GATE_INFRA1(CK_INFRA_MSDC_HCK_CK, "infra_msdc_hck",
+		    CK_INFRA_FMSDC_HCK_CK, 17),
+	GATE_INFRA1(CK_INFRA_MSDC_133M_CK, "infra_msdc_133m",
+		    CK_INFRA_PERI_133M, 18),
+	GATE_INFRA1(CK_INFRA_MSDC_66M_CK, "infra_msdc_66m", CK_INFRA_66M_PHCK,
+		    19),
+	GATE_INFRA1(CK_INFRA_ADC_26M_CK, "infra_adc_26m", CK_TOP_F26M, 20),
+	GATE_INFRA1(CK_INFRA_ADC_FRC_CK, "infra_adc_frc", CK_TOP_F26M, 21),
+	GATE_INFRA1(CK_INFRA_FBIST2FPC_CK, "infra_fbist2fpc", CK_INFRA_NFI_CK,
+		    23),
+	GATE_INFRA1(CK_INFRA_I2C_MCK_CK, "infra_i2c_mck", CK_INFRA_133M_MCK,
+		    25),
+	GATE_INFRA1(CK_INFRA_I2C_PCK_CK, "infra_i2c_pck", CK_INFRA_66M_MCK, 26),
+	GATE_INFRA2(CK_INFRA_IUSB_133_CK, "infra_iusb_133", CK_INFRA_133M_PHCK,
+		    0),
+	GATE_INFRA2(CK_INFRA_IUSB_66M_CK, "infra_iusb_66m", CK_INFRA_66M_PHCK,
+		    1),
+	GATE_INFRA2(CK_INFRA_IUSB_SYS_CK, "infra_iusb_sys", CK_INFRA_USB_SYS_CK,
+		    2),
+	GATE_INFRA2(CK_INFRA_IUSB_CK, "infra_iusb", CK_INFRA_USB_CK, 3),
+	GATE_INFRA2(CK_INFRA_IPCIE_CK, "infra_ipcie",
+		    CK_INFRA_PCIE_GFMUX_TL_O_PRE, 12),
+	GATE_INFRA2(CK_INFRA_IPCIER_CK, "infra_ipcier", CK_INFRA_F26M_CK0, 14),
+	GATE_INFRA2(CK_INFRA_IPCIEB_CK, "infra_ipcieb", CK_INFRA_133M_PHCK, 15),
+};
+
+static const struct mtk_clk_tree mt7981_fixed_pll_clk_tree = {
+	.fdivs_offs = CLK_APMIXED_NR_CLK,
+	.xtal_rate = 40 * MHZ,
+	.fclks = fixed_pll_clks,
+};
+
+static const struct mtk_clk_tree mt7981_topckgen_clk_tree = {
+	.fdivs_offs = CK_TOP_CB_M_416M,
+	.muxes_offs = CK_TOP_NFI1X_SEL,
+	.fclks = top_fixed_clks,
+	.fdivs = top_fixed_divs,
+	.muxes = top_muxes,
+	.flags = CLK_BYPASS_XTAL,
+};
+
+static const struct mtk_clk_tree mt7981_infracfg_clk_tree = {
+	.fdivs_offs = CK_INFRA_CK_F26M,
+	.muxes_offs = CK_INFRA_UART0_SEL,
+	.fdivs = infra_fixed_divs,
+	.muxes = infra_muxes,
+};
+
+static const struct udevice_id mt7981_fixed_pll_compat[] = {
+	{ .compatible = "mediatek,mt7981-fixed-plls" },
+	{}
+};
+
+static const struct udevice_id mt7981_topckgen_compat[] = {
+	{ .compatible = "mediatek,mt7981-topckgen" },
+	{}
+};
+
+static int mt7981_fixed_pll_probe(struct udevice *dev)
+{
+	return mtk_common_clk_init(dev, &mt7981_fixed_pll_clk_tree);
+}
+
+static int mt7981_topckgen_probe(struct udevice *dev)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+	writel(MT7981_CLK_PDN_EN_WRITE, priv->base + MT7981_CLK_PDN);
+
+	return mtk_common_clk_init(dev, &mt7981_topckgen_clk_tree);
+}
+
+U_BOOT_DRIVER(mtk_clk_apmixedsys) = {
+	.name = "mt7981-clock-fixed-pll",
+	.id = UCLASS_CLK,
+	.of_match = mt7981_fixed_pll_compat,
+	.probe = mt7981_fixed_pll_probe,
+	.priv_auto = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_topckgen_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_topckgen) = {
+	.name = "mt7981-clock-topckgen",
+	.id = UCLASS_CLK,
+	.of_match = mt7981_topckgen_compat,
+	.probe = mt7981_topckgen_probe,
+	.priv_auto = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_topckgen_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+static const struct udevice_id mt7981_infracfg_compat[] = {
+	{ .compatible = "mediatek,mt7981-infracfg" },
+	{}
+};
+
+static const struct udevice_id mt7981_infracfg_ao_compat[] = {
+	{ .compatible = "mediatek,mt7981-infracfg_ao" },
+	{}
+};
+
+static int mt7981_infracfg_probe(struct udevice *dev)
+{
+	return mtk_common_clk_init(dev, &mt7981_infracfg_clk_tree);
+}
+
+static int mt7981_infracfg_ao_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7981_infracfg_clk_tree,
+					infracfg_ao_gates);
+}
+
+U_BOOT_DRIVER(mtk_clk_infracfg) = {
+	.name = "mt7981-clock-infracfg",
+	.id = UCLASS_CLK,
+	.of_match = mt7981_infracfg_compat,
+	.probe = mt7981_infracfg_probe,
+	.priv_auto = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_infrasys_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_infracfg_ao) = {
+	.name = "mt7981-clock-infracfg-ao",
+	.id = UCLASS_CLK,
+	.of_match = mt7981_infracfg_ao_compat,
+	.probe = mt7981_infracfg_ao_probe,
+	.priv_auto = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+/* ethsys */
+static const struct mtk_gate_regs eth_cg_regs = {
+	.set_ofs = 0x30,
+	.clr_ofs = 0x30,
+	.sta_ofs = 0x30,
+};
+
+#define GATE_ETH(_id, _name, _parent, _shift)                                  \
+	{                                                                      \
+		.id = _id, .parent = _parent, .regs = &eth_cg_regs,            \
+		.shift = _shift,                                               \
+		.flags = CLK_GATE_NO_SETCLR_INV | CLK_PARENT_TOPCKGEN,         \
+	}
+
+static const struct mtk_gate eth_cgs[] = {
+	GATE_ETH(CK_ETH_FE_EN, "eth_fe_en", CK_TOP_NETSYS_2X, 6),
+	GATE_ETH(CK_ETH_GP2_EN, "eth_gp2_en", CK_TOP_SGM_325M, 7),
+	GATE_ETH(CK_ETH_GP1_EN, "eth_gp1_en", CK_TOP_SGM_325M, 8),
+	GATE_ETH(CK_ETH_WOCPU0_EN, "eth_wocpu0_en", CK_TOP_NETSYS_WED_MCU, 15),
+};
+
+static int mt7981_ethsys_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7981_topckgen_clk_tree,
+					eth_cgs);
+}
+
+static int mt7981_ethsys_bind(struct udevice *dev)
+{
+	int ret = 0;
+
+	if (CONFIG_IS_ENABLED(RESET_MEDIATEK)) {
+		ret = mediatek_reset_bind(dev, ETHSYS_HIFSYS_RST_CTRL_OFS, 1);
+		if (ret)
+			debug("Warning: failed to bind reset controller\n");
+	}
+
+	return ret;
+}
+
+static const struct udevice_id mt7981_ethsys_compat[] = {
+	{ .compatible = "mediatek,mt7981-ethsys", },
+	{}
+};
+
+U_BOOT_DRIVER(mtk_clk_ethsys) = {
+	.name = "mt7981-clock-ethsys",
+	.id = UCLASS_CLK,
+	.of_match = mt7981_ethsys_compat,
+	.probe = mt7981_ethsys_probe,
+	.bind = mt7981_ethsys_bind,
+	.priv_auto = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+};
diff --git a/drivers/clk/mediatek/clk-mt7986.c b/drivers/clk/mediatek/clk-mt7986.c
new file mode 100644
index 0000000..b3fa63f
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7986.c
@@ -0,0 +1,672 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek clock driver for MT7986 SoC
+ *
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <asm/arch-mediatek/reset.h>
+#include <asm/io.h>
+#include <dt-bindings/clock/mt7986-clk.h>
+#include <linux/bitops.h>
+
+#include "clk-mtk.h"
+
+#define MT7986_CLK_PDN 0x250
+#define MT7986_CLK_PDN_EN_WRITE BIT(31)
+
+#define PLL_FACTOR(_id, _name, _parent, _mult, _div)                           \
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_APMIXED)
+
+#define TOP_FACTOR(_id, _name, _parent, _mult, _div)                           \
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_TOPCKGEN)
+
+#define INFRA_FACTOR(_id, _name, _parent, _mult, _div)                         \
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_INFRASYS)
+
+/* FIXED PLLS */
+static const struct mtk_fixed_clk fixed_pll_clks[] = {
+	FIXED_CLK(CK_APMIXED_ARMPLL, CLK_XTAL, 2000000000),
+	FIXED_CLK(CK_APMIXED_NET2PLL, CLK_XTAL, 800000000),
+	FIXED_CLK(CK_APMIXED_MMPLL, CLK_XTAL, 1440000000),
+	FIXED_CLK(CK_APMIXED_SGMPLL, CLK_XTAL, 325000000),
+	FIXED_CLK(CK_APMIXED_WEDMCUPLL, CLK_XTAL, 760000000),
+	FIXED_CLK(CK_APMIXED_NET1PLL, CLK_XTAL, 2500000000),
+	FIXED_CLK(CK_APMIXED_MPLL, CLK_XTAL, 416000000),
+	FIXED_CLK(CK_APMIXED_APLL2, CLK_XTAL, 196608000),
+};
+
+/* TOPCKGEN FIXED CLK */
+static const struct mtk_fixed_clk top_fixed_clks[] = {
+	FIXED_CLK(CK_TOP_CB_CKSQ_40M, CLK_XTAL, 40000000),
+};
+
+/* TOPCKGEN FIXED DIV */
+static const struct mtk_fixed_factor top_fixed_divs[] = {
+	PLL_FACTOR(CK_TOP_CB_M_416M, "cb_m_416m", CK_APMIXED_MPLL, 1, 1),
+	PLL_FACTOR(CK_TOP_CB_M_D2, "cb_m_d2", CK_APMIXED_MPLL, 1, 2),
+	PLL_FACTOR(CK_TOP_CB_M_D4, "cb_m_d4", CK_APMIXED_MPLL, 1, 4),
+	PLL_FACTOR(CK_TOP_CB_M_D8, "cb_m_d8", CK_APMIXED_MPLL, 1, 8),
+	PLL_FACTOR(CK_TOP_M_D8_D2, "m_d8_d2", CK_APMIXED_MPLL, 1, 16),
+	PLL_FACTOR(CK_TOP_M_D3_D2, "m_d3_d2", CK_APMIXED_MPLL, 1, 2),
+	PLL_FACTOR(CK_TOP_CB_MM_D2, "cb_mm_d2", CK_APMIXED_MMPLL, 1, 2),
+	PLL_FACTOR(CK_TOP_CB_MM_D4, "cb_mm_d4", CK_APMIXED_MMPLL, 1, 4),
+	PLL_FACTOR(CK_TOP_CB_MM_D8, "cb_mm_d8", CK_APMIXED_MMPLL, 1, 8),
+	PLL_FACTOR(CK_TOP_MM_D8_D2, "mm_d8_d2", CK_APMIXED_MMPLL, 1, 16),
+	PLL_FACTOR(CK_TOP_MM_D3_D8, "mm_d3_d8", CK_APMIXED_MMPLL, 1, 8),
+	PLL_FACTOR(CK_TOP_CB_U2_PHYD_CK, "cb_u2_phyd", CK_APMIXED_MMPLL, 1, 30),
+	PLL_FACTOR(CK_TOP_CB_APLL2_196M, "cb_apll2_196m", CK_APMIXED_APLL2, 1,
+		   1),
+	PLL_FACTOR(CK_TOP_APLL2_D4, "apll2_d4", CK_APMIXED_APLL2, 1, 4),
+	PLL_FACTOR(CK_TOP_CB_NET1_D4, "cb_net1_d4", CK_APMIXED_NET1PLL, 1, 4),
+	PLL_FACTOR(CK_TOP_CB_NET1_D5, "cb_net1_d5", CK_APMIXED_NET1PLL, 1, 5),
+	PLL_FACTOR(CK_TOP_NET1_D5_D2, "net1_d5_d2", CK_APMIXED_NET1PLL, 1, 10),
+	PLL_FACTOR(CK_TOP_NET1_D5_D4, "net1_d5_d4", CK_APMIXED_NET1PLL, 1, 20),
+	PLL_FACTOR(CK_TOP_NET1_D8_D2, "net1_d8_d2", CK_APMIXED_NET1PLL, 1, 16),
+	PLL_FACTOR(CK_TOP_NET1_D8_D4, "net1_d8_d4", CK_APMIXED_NET1PLL, 1, 32),
+	PLL_FACTOR(CK_TOP_CB_NET2_800M, "cb_net2_800m", CK_APMIXED_NET2PLL, 1,
+		   1),
+	PLL_FACTOR(CK_TOP_CB_NET2_D4, "cb_net2_d4", CK_APMIXED_NET2PLL, 1, 4),
+	PLL_FACTOR(CK_TOP_NET2_D4_D2, "net2_d4_d2", CK_APMIXED_NET2PLL, 1, 8),
+	PLL_FACTOR(CK_TOP_NET2_D3_D2, "net2_d3_d2", CK_APMIXED_NET2PLL, 1, 2),
+	PLL_FACTOR(CK_TOP_CB_WEDMCU_760M, "cb_wedmcu_760m",
+		   CK_APMIXED_WEDMCUPLL, 1, 1),
+	PLL_FACTOR(CK_TOP_WEDMCU_D5_D2, "wedmcu_d5_d2", CK_APMIXED_WEDMCUPLL, 1,
+		   10),
+	PLL_FACTOR(CK_TOP_CB_SGM_325M, "cb_sgm_325m", CK_APMIXED_SGMPLL, 1, 1),
+	TOP_FACTOR(CK_TOP_CB_CKSQ_40M_D2, "cb_cksq_40m_d2", CK_TOP_CB_CKSQ_40M,
+		   1, 2),
+	TOP_FACTOR(CK_TOP_CB_RTC_32K, "cb_rtc_32k", CK_TOP_CB_CKSQ_40M, 1,
+		   1250),
+	TOP_FACTOR(CK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", CK_TOP_CB_CKSQ_40M, 1,
+		   1220),
+	TOP_FACTOR(CK_TOP_NFI1X, "nfi1x", CK_TOP_NFI1X_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_USB_EQ_RX250M, "usb_eq_rx250m", CK_TOP_CB_CKSQ_40M, 1,
+		   1),
+	TOP_FACTOR(CK_TOP_USB_TX250M, "usb_tx250m", CK_TOP_CB_CKSQ_40M, 1, 1),
+	TOP_FACTOR(CK_TOP_USB_LN0_CK, "usb_ln0", CK_TOP_CB_CKSQ_40M, 1, 1),
+	TOP_FACTOR(CK_TOP_USB_CDR_CK, "usb_cdr", CK_TOP_CB_CKSQ_40M, 1, 1),
+	TOP_FACTOR(CK_TOP_SPINFI_BCK, "spinfi_bck", CK_TOP_SPINFI_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_I2C_BCK, "i2c_bck", CK_TOP_I2C_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_PEXTP_TL, "pextp_tl", CK_TOP_PEXTP_TL_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_EMMC_250M, "emmc_250m", CK_TOP_EMMC_250M_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_EMMC_416M, "emmc_416m", CK_TOP_EMMC_416M_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_F_26M_ADC_CK, "f_26m_adc", CK_TOP_F_26M_ADC_SEL, 1,
+		   1),
+	TOP_FACTOR(CK_TOP_SYSAXI, "sysaxi", CK_TOP_SYSAXI_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu",
+		   CK_TOP_NETSYS_MCU_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_NETSYS_2X, "netsys_2x", CK_TOP_NETSYS_2X_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_SGM_325M, "sgm_325m", CK_TOP_SGM_325M_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_A1SYS, "a1sys", CK_TOP_A1SYS_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_EIP_B, "eip_b", CK_TOP_EIP_B_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_F26M, "csw_f26m", CK_TOP_F26M_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_AUD_L, "aud_l", CK_TOP_AUD_L_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_A_TUNER, "a_tuner", CK_TOP_A_TUNER_SEL, 2, 1),
+	TOP_FACTOR(CK_TOP_U2U3_REF, "u2u3_ref", CK_TOP_U2U3_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_U2U3_SYS, "u2u3_sys", CK_TOP_U2U3_SYS_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_U2U3_XHCI, "u2u3_xhci", CK_TOP_U2U3_XHCI_SEL, 1, 1),
+	TOP_FACTOR(CK_TOP_AP2CNN_HOST, "ap2cnn_host", CK_TOP_AP2CNN_HOST_SEL, 1,
+		   1),
+};
+
+/* TOPCKGEN MUX PARENTS */
+static const int nfi1x_parents[] = { CK_TOP_CB_CKSQ_40M,  CK_TOP_CB_MM_D8,
+				     CK_TOP_NET1_D8_D2,   CK_TOP_NET2_D3_D2,
+				     CK_TOP_CB_M_D4,      CK_TOP_MM_D8_D2,
+				     CK_TOP_WEDMCU_D5_D2, CK_TOP_CB_M_D8 };
+
+static const int spinfi_parents[] = {
+	CK_TOP_CB_CKSQ_40M_D2, CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D5_D4,
+	CK_TOP_CB_M_D4,	CK_TOP_MM_D8_D2,    CK_TOP_WEDMCU_D5_D2,
+	CK_TOP_MM_D3_D8,       CK_TOP_CB_M_D8
+};
+
+static const int spi_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_M_D2,
+				   CK_TOP_CB_MM_D8,    CK_TOP_NET1_D8_D2,
+				   CK_TOP_NET2_D3_D2,  CK_TOP_NET1_D5_D4,
+				   CK_TOP_CB_M_D4,     CK_TOP_WEDMCU_D5_D2 };
+
+static const int uart_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_M_D8,
+				    CK_TOP_M_D8_D2 };
+
+static const int pwm_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D8_D2,
+				   CK_TOP_NET1_D5_D4, CK_TOP_CB_M_D4 };
+
+static const int i2c_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D5_D4,
+				   CK_TOP_CB_M_D4, CK_TOP_NET1_D8_D4 };
+
+static const int pextp_tl_ck_parents[] = { CK_TOP_CB_CKSQ_40M,
+					   CK_TOP_NET1_D5_D4, CK_TOP_NET2_D4_D2,
+					   CK_TOP_CB_RTC_32K };
+
+static const int emmc_250m_parents[] = { CK_TOP_CB_CKSQ_40M,
+					 CK_TOP_NET1_D5_D2 };
+
+static const int emmc_416m_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_M_416M };
+
+static const int f_26m_adc_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_M_D8_D2 };
+
+static const int dramc_md32_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_M_D2 };
+
+static const int sysaxi_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D8_D2,
+				      CK_TOP_CB_NET2_D4 };
+
+static const int sysapb_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_M_D3_D2,
+				      CK_TOP_NET2_D4_D2 };
+
+static const int arm_db_main_parents[] = { CK_TOP_CB_CKSQ_40M,
+					   CK_TOP_NET2_D3_D2 };
+
+static const int arm_db_jtsel_parents[] = { -1, CK_TOP_CB_CKSQ_40M };
+
+static const int netsys_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_MM_D4 };
+
+static const int netsys_500m_parents[] = { CK_TOP_CB_CKSQ_40M,
+					   CK_TOP_CB_NET1_D5 };
+
+static const int netsys_mcu_parents[] = { CK_TOP_CB_CKSQ_40M,
+					  CK_TOP_CB_WEDMCU_760M,
+					  CK_TOP_CB_MM_D2, CK_TOP_CB_NET1_D4,
+					  CK_TOP_CB_NET1_D5 };
+
+static const int netsys_2x_parents[] = { CK_TOP_CB_CKSQ_40M,
+					 CK_TOP_CB_NET2_800M,
+					 CK_TOP_CB_WEDMCU_760M,
+					 CK_TOP_CB_MM_D2 };
+
+static const int sgm_325m_parents[] = { CK_TOP_CB_CKSQ_40M,
+					CK_TOP_CB_SGM_325M };
+
+static const int sgm_reg_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D8_D4 };
+
+static const int a1sys_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_APLL2_D4 };
+
+static const int conn_mcusys_parents[] = { CK_TOP_CB_CKSQ_40M,
+					   CK_TOP_CB_MM_D2 };
+
+static const int eip_b_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_NET2_800M };
+
+static const int aud_l_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_CB_APLL2_196M,
+				     CK_TOP_M_D8_D2 };
+
+static const int a_tuner_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_APLL2_D4,
+				       CK_TOP_M_D8_D2 };
+
+static const int u2u3_sys_parents[] = { CK_TOP_CB_CKSQ_40M, CK_TOP_NET1_D5_D4 };
+
+static const int da_u2_refsel_parents[] = { CK_TOP_CB_CKSQ_40M,
+					    CK_TOP_CB_U2_PHYD_CK };
+
+#define TOP_MUX(_id, _name, _parents, _mux_ofs, _mux_set_ofs, _mux_clr_ofs,    \
+		_shift, _width, _gate, _upd_ofs, _upd)                         \
+	{                                                                      \
+		.id = _id, .mux_reg = _mux_ofs, .mux_set_reg = _mux_set_ofs,   \
+		.mux_clr_reg = _mux_clr_ofs, .upd_reg = _upd_ofs,              \
+		.upd_shift = _upd, .mux_shift = _shift,                        \
+		.mux_mask = BIT(_width) - 1, .gate_reg = _mux_ofs,             \
+		.gate_shift = _gate, .parent = _parents,                       \
+		.num_parents = ARRAY_SIZE(_parents),                           \
+		.flags = CLK_MUX_SETCLR_UPD,                                   \
+	}
+
+/* TOPCKGEN MUX_GATE */
+static const struct mtk_composite top_muxes[] = {
+	/* CLK_CFG_0 */
+	TOP_MUX(CK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents, 0x000, 0x004,
+		0x008, 0, 3, 7, 0x1C0, 0),
+	TOP_MUX(CK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents, 0x000, 0x004,
+		0x008, 8, 3, 15, 0x1C0, 1),
+	TOP_MUX(CK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x000, 0x004, 0x008, 16,
+		3, 23, 0x1C0, 2),
+	TOP_MUX(CK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents, 0x000, 0x004,
+		0x008, 24, 3, 31, 0x1C0, 3),
+	/* CLK_CFG_1 */
+	TOP_MUX(CK_TOP_UART_SEL, "uart_sel", uart_parents, 0x010, 0x014, 0x018,
+		0, 2, 7, 0x1C0, 4),
+	TOP_MUX(CK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x010, 0x014, 0x018, 8,
+		2, 15, 0x1C0, 5),
+	TOP_MUX(CK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x010, 0x014, 0x018, 16,
+		2, 23, 0x1C0, 6),
+	TOP_MUX(CK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel", pextp_tl_ck_parents,
+		0x010, 0x014, 0x018, 24, 2, 31, 0x1C0, 7),
+	/* CLK_CFG_2 */
+	TOP_MUX(CK_TOP_EMMC_250M_SEL, "emmc_250m_sel", emmc_250m_parents, 0x020,
+		0x024, 0x028, 0, 1, 7, 0x1C0, 8),
+	TOP_MUX(CK_TOP_EMMC_416M_SEL, "emmc_416m_sel", emmc_416m_parents, 0x020,
+		0x024, 0x028, 8, 1, 15, 0x1C0, 9),
+	TOP_MUX(CK_TOP_F_26M_ADC_SEL, "f_26m_adc_sel", f_26m_adc_parents, 0x020,
+		0x024, 0x028, 16, 1, 23, 0x1C0, 10),
+	TOP_MUX(CK_TOP_DRAMC_SEL, "dramc_sel", f_26m_adc_parents, 0x020, 0x024,
+		0x028, 24, 1, 31, 0x1C0, 11),
+	/* CLK_CFG_3 */
+	TOP_MUX(CK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel", dramc_md32_parents,
+		0x030, 0x034, 0x038, 0, 1, 7, 0x1C0, 12),
+	TOP_MUX(CK_TOP_SYSAXI_SEL, "sysaxi_sel", sysaxi_parents, 0x030, 0x034,
+		0x038, 8, 2, 15, 0x1C0, 13),
+	TOP_MUX(CK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents, 0x030, 0x034,
+		0x038, 16, 2, 23, 0x1C0, 14),
+	TOP_MUX(CK_TOP_ARM_DB_MAIN_SEL, "arm_db_main_sel", arm_db_main_parents,
+		0x030, 0x034, 0x038, 24, 1, 31, 0x1C0, 15),
+	/* CLK_CFG_4 */
+	TOP_MUX(CK_TOP_ARM_DB_JTSEL, "arm_db_jtsel", arm_db_jtsel_parents,
+		0x040, 0x044, 0x048, 0, 1, 7, 0x1C0, 16),
+	TOP_MUX(CK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents, 0x040, 0x044,
+		0x048, 8, 1, 15, 0x1C0, 17),
+	TOP_MUX(CK_TOP_NETSYS_500M_SEL, "netsys_500m_sel", netsys_500m_parents,
+		0x040, 0x044, 0x048, 16, 1, 23, 0x1C0, 18),
+	TOP_MUX(CK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel", netsys_mcu_parents,
+		0x040, 0x044, 0x048, 24, 3, 31, 0x1C0, 19),
+	/* CLK_CFG_5 */
+	TOP_MUX(CK_TOP_NETSYS_2X_SEL, "netsys_2x_sel", netsys_2x_parents, 0x050,
+		0x054, 0x058, 0, 2, 7, 0x1C0, 20),
+	TOP_MUX(CK_TOP_SGM_325M_SEL, "sgm_325m_sel", sgm_325m_parents, 0x050,
+		0x054, 0x058, 8, 1, 15, 0x1C0, 21),
+	TOP_MUX(CK_TOP_SGM_REG_SEL, "sgm_reg_sel", sgm_reg_parents, 0x050,
+		0x054, 0x058, 16, 1, 23, 0x1C0, 22),
+	TOP_MUX(CK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents, 0x050, 0x054,
+		0x058, 24, 1, 31, 0x1C0, 23),
+	/* CLK_CFG_6 */
+	TOP_MUX(CK_TOP_CONN_MCUSYS_SEL, "conn_mcusys_sel", conn_mcusys_parents,
+		0x060, 0x064, 0x068, 0, 1, 7, 0x1C0, 24),
+	TOP_MUX(CK_TOP_EIP_B_SEL, "eip_b_sel", eip_b_parents, 0x060, 0x064,
+		0x068, 8, 1, 15, 0x1C0, 25),
+	TOP_MUX(CK_TOP_PCIE_PHY_SEL, "pcie_phy_sel", f_26m_adc_parents, 0x060,
+		0x064, 0x068, 16, 1, 23, 0x1C0, 26),
+	TOP_MUX(CK_TOP_USB3_PHY_SEL, "usb3_phy_sel", f_26m_adc_parents, 0x060,
+		0x064, 0x068, 24, 1, 31, 0x1C0, 27),
+	/* CLK_CFG_7 */
+	TOP_MUX(CK_TOP_F26M_SEL, "csw_f26m_sel", f_26m_adc_parents, 0x070,
+		0x074, 0x078, 0, 1, 7, 0x1C0, 28),
+	TOP_MUX(CK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents, 0x070, 0x074,
+		0x078, 8, 2, 15, 0x1C0, 29),
+	TOP_MUX(CK_TOP_A_TUNER_SEL, "a_tuner_sel", a_tuner_parents, 0x070,
+		0x074, 0x078, 16, 2, 23, 0x1C0, 30),
+	TOP_MUX(CK_TOP_U2U3_SEL, "u2u3_sel", f_26m_adc_parents, 0x070, 0x074,
+		0x078, 24, 1, 31, 0x1C4, 0),
+	/* CLK_CFG_8 */
+	TOP_MUX(CK_TOP_U2U3_SYS_SEL, "u2u3_sys_sel", u2u3_sys_parents, 0x080,
+		0x084, 0x088, 0, 1, 7, 0x1C4, 1),
+	TOP_MUX(CK_TOP_U2U3_XHCI_SEL, "u2u3_xhci_sel", u2u3_sys_parents, 0x080,
+		0x084, 0x088, 8, 1, 15, 0x1C4, 2),
+	TOP_MUX(CK_TOP_DA_U2_REFSEL, "da_u2_refsel", da_u2_refsel_parents,
+		0x080, 0x084, 0x088, 16, 1, 23, 0x1C4, 3),
+	TOP_MUX(CK_TOP_DA_U2_CK_1P_SEL, "da_u2_ck_1p_sel", da_u2_refsel_parents,
+		0x080, 0x084, 0x088, 24, 1, 31, 0x1C4, 4),
+	/* CLK_CFG_9 */
+	TOP_MUX(CK_TOP_AP2CNN_HOST_SEL, "ap2cnn_host_sel", sgm_reg_parents,
+		0x090, 0x094, 0x098, 0, 1, 7, 0x1C4, 5),
+};
+
+/* INFRA FIXED DIV */
+static const struct mtk_fixed_factor infra_fixed_divs[] = {
+	TOP_FACTOR(CK_INFRA_CK_F26M, "infra_ck_f26m", CK_TOP_F26M_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_UART, "infra_uart", CK_TOP_UART_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_ISPI0, "infra_ispi0", CK_TOP_SPI_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_I2C, "infra_i2c", CK_TOP_I2C_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_ISPI1, "infra_ispi1", CK_TOP_SPINFI_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_PWM, "infra_pwm", CK_TOP_PWM_SEL, 1, 1),
+	TOP_FACTOR(CK_INFRA_66M_MCK, "infra_66m_mck", CK_TOP_SYSAXI_SEL, 1, 2),
+	TOP_FACTOR(CK_INFRA_CK_F32K, "infra_ck_f32k", CK_TOP_CB_RTC_32P7K, 1,
+		   1),
+	TOP_FACTOR(CK_INFRA_PCIE_CK, "infra_pcie", CK_TOP_PEXTP_TL_SEL, 1, 1),
+	INFRA_FACTOR(CK_INFRA_PWM_BCK, "infra_pwm_bck", CK_INFRA_PWM_BSEL, 1,
+		     1),
+	INFRA_FACTOR(CK_INFRA_PWM_CK1, "infra_pwm_ck1", CK_INFRA_PWM1_SEL, 1,
+		     1),
+	INFRA_FACTOR(CK_INFRA_PWM_CK2, "infra_pwm_ck2", CK_INFRA_PWM2_SEL, 1,
+		     1),
+	TOP_FACTOR(CK_INFRA_133M_HCK, "infra_133m_hck", CK_TOP_SYSAXI, 1, 1),
+	TOP_FACTOR(CK_INFRA_EIP_CK, "infra_eip", CK_TOP_EIP_B, 1, 1),
+	INFRA_FACTOR(CK_INFRA_66M_PHCK, "infra_66m_phck", CK_INFRA_133M_HCK, 1,
+		     1),
+	TOP_FACTOR(CK_INFRA_FAUD_L_CK, "infra_faud_l", CK_TOP_AUD_L, 1, 1),
+	TOP_FACTOR(CK_INFRA_FAUD_AUD_CK, "infra_faud_aud", CK_TOP_A1SYS, 1, 1),
+	TOP_FACTOR(CK_INFRA_FAUD_EG2_CK, "infra_faud_eg2", CK_TOP_A_TUNER, 1,
+		   1),
+	TOP_FACTOR(CK_INFRA_I2CS_CK, "infra_i2cs", CK_TOP_I2C_BCK, 1, 1),
+	INFRA_FACTOR(CK_INFRA_MUX_UART0, "infra_mux_uart0", CK_INFRA_UART0_SEL,
+		     1, 1),
+	INFRA_FACTOR(CK_INFRA_MUX_UART1, "infra_mux_uart1", CK_INFRA_UART1_SEL,
+		     1, 1),
+	INFRA_FACTOR(CK_INFRA_MUX_UART2, "infra_mux_uart2", CK_INFRA_UART2_SEL,
+		     1, 1),
+	TOP_FACTOR(CK_INFRA_NFI_CK, "infra_nfi", CK_TOP_NFI1X, 1, 1),
+	TOP_FACTOR(CK_INFRA_SPINFI_CK, "infra_spinfi", CK_TOP_SPINFI_BCK, 1, 1),
+	INFRA_FACTOR(CK_INFRA_MUX_SPI0, "infra_mux_spi0", CK_INFRA_SPI0_SEL, 1,
+		     1),
+	INFRA_FACTOR(CK_INFRA_MUX_SPI1, "infra_mux_spi1", CK_INFRA_SPI1_SEL, 1,
+		     1),
+	TOP_FACTOR(CK_INFRA_RTC_32K, "infra_rtc_32k", CK_TOP_CB_RTC_32K, 1, 1),
+	TOP_FACTOR(CK_INFRA_FMSDC_CK, "infra_fmsdc", CK_TOP_EMMC_416M, 1, 1),
+	TOP_FACTOR(CK_INFRA_FMSDC_HCK_CK, "infra_fmsdc_hck", CK_TOP_EMMC_250M,
+		   1, 1),
+	TOP_FACTOR(CK_INFRA_PERI_133M, "infra_peri_133m", CK_TOP_SYSAXI, 1, 1),
+	TOP_FACTOR(CK_INFRA_133M_PHCK, "infra_133m_phck", CK_TOP_SYSAXI, 1, 1),
+	TOP_FACTOR(CK_INFRA_USB_SYS_CK, "infra_usb_sys", CK_TOP_U2U3_SYS, 1, 1),
+	TOP_FACTOR(CK_INFRA_USB_CK, "infra_usb", CK_TOP_U2U3_REF, 1, 1),
+	TOP_FACTOR(CK_INFRA_USB_XHCI_CK, "infra_usb_xhci", CK_TOP_U2U3_XHCI, 1,
+		   1),
+	TOP_FACTOR(CK_INFRA_PCIE_GFMUX_TL_O_PRE, "infra_pcie_mux",
+		   CK_TOP_PEXTP_TL, 1, 1),
+	TOP_FACTOR(CK_INFRA_F26M_CK0, "infra_f26m_ck0", CK_TOP_F26M, 1, 1),
+	TOP_FACTOR(CK_INFRA_HD_133M, "infra_hd_133m", CK_TOP_SYSAXI, 1, 1),
+};
+
+/* INFRASYS MUX PARENTS */
+static const int infra_uart0_parents[] = { CK_INFRA_CK_F26M, CK_INFRA_UART };
+
+static const int infra_spi0_parents[] = { CK_INFRA_I2C, CK_INFRA_ISPI0 };
+
+static const int infra_spi1_parents[] = { CK_INFRA_I2C, CK_INFRA_ISPI1 };
+
+static const int infra_pwm_bsel_parents[] = { CK_INFRA_CK_F32K,
+					      CK_INFRA_CK_F26M,
+					      CK_INFRA_66M_MCK, CK_INFRA_PWM };
+
+static const int infra_pcie_parents[] = { CK_INFRA_CK_F32K, CK_INFRA_CK_F26M,
+					  -1, CK_INFRA_PCIE_CK };
+
+#define INFRA_MUX(_id, _name, _parents, _reg, _shift, _width)                  \
+	{                                                                      \
+		.id = _id, .mux_reg = (_reg) + 0x8,                            \
+		.mux_set_reg = (_reg) + 0x0, .mux_clr_reg = (_reg) + 0x4,      \
+		.mux_shift = _shift, .mux_mask = BIT(_width) - 1,              \
+		.parent = _parents, .num_parents = ARRAY_SIZE(_parents),       \
+		.flags = CLK_MUX_SETCLR_UPD | CLK_PARENT_INFRASYS,             \
+	}
+
+/* INFRA MUX */
+
+static const struct mtk_composite infra_muxes[] = {
+	/* MODULE_CLK_SEL_0 */
+	INFRA_MUX(CK_INFRA_UART0_SEL, "infra_uart0_sel", infra_uart0_parents,
+		  0x10, 0, 1),
+	INFRA_MUX(CK_INFRA_UART1_SEL, "infra_uart1_sel", infra_uart0_parents,
+		  0x10, 1, 1),
+	INFRA_MUX(CK_INFRA_UART2_SEL, "infra_uart2_sel", infra_uart0_parents,
+		  0x10, 2, 1),
+	INFRA_MUX(CK_INFRA_SPI0_SEL, "infra_spi0_sel", infra_spi0_parents, 0x10,
+		  4, 1),
+	INFRA_MUX(CK_INFRA_SPI1_SEL, "infra_spi1_sel", infra_spi1_parents, 0x10,
+		  5, 1),
+	INFRA_MUX(CK_INFRA_PWM1_SEL, "infra_pwm1_sel", infra_pwm_bsel_parents,
+		  0x10, 9, 2),
+	INFRA_MUX(CK_INFRA_PWM2_SEL, "infra_pwm2_sel", infra_pwm_bsel_parents,
+		  0x10, 11, 2),
+	INFRA_MUX(CK_INFRA_PWM_BSEL, "infra_pwm_bsel", infra_pwm_bsel_parents,
+		  0x10, 13, 2),
+	/* MODULE_CLK_SEL_1 */
+	INFRA_MUX(CK_INFRA_PCIE_SEL, "infra_pcie_sel", infra_pcie_parents, 0x20,
+		  0, 2),
+};
+
+static const struct mtk_gate_regs infra_0_cg_regs = {
+	.set_ofs = 0x40,
+	.clr_ofs = 0x44,
+	.sta_ofs = 0x48,
+};
+
+static const struct mtk_gate_regs infra_1_cg_regs = {
+	.set_ofs = 0x50,
+	.clr_ofs = 0x54,
+	.sta_ofs = 0x58,
+};
+
+static const struct mtk_gate_regs infra_2_cg_regs = {
+	.set_ofs = 0x60,
+	.clr_ofs = 0x64,
+	.sta_ofs = 0x68,
+};
+
+#define GATE_INFRA0(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .parent = _parent, .regs = &infra_0_cg_regs,        \
+		.shift = _shift,                                               \
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_INFRASYS,                \
+	}
+
+#define GATE_INFRA1(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .parent = _parent, .regs = &infra_1_cg_regs,        \
+		.shift = _shift,                                               \
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_INFRASYS,                \
+	}
+
+#define GATE_INFRA2(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .parent = _parent, .regs = &infra_2_cg_regs,        \
+		.shift = _shift,                                               \
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_INFRASYS,                \
+	}
+
+/* INFRA GATE */
+
+static const struct mtk_gate infracfg_ao_gates[] = {
+	/* INFRA0 */
+	GATE_INFRA0(CK_INFRA_GPT_STA, "infra_gpt_sta", CK_INFRA_66M_MCK, 0),
+	GATE_INFRA0(CK_INFRA_PWM_HCK, "infra_pwm_hck", CK_INFRA_66M_MCK, 1),
+	GATE_INFRA0(CK_INFRA_PWM_STA, "infra_pwm_sta", CK_INFRA_PWM_BCK, 2),
+	GATE_INFRA0(CK_INFRA_PWM1_CK, "infra_pwm1", CK_INFRA_PWM_CK1, 3),
+	GATE_INFRA0(CK_INFRA_PWM2_CK, "infra_pwm2", CK_INFRA_PWM_CK2, 4),
+	GATE_INFRA0(CK_INFRA_CQ_DMA_CK, "infra_cq_dma", CK_INFRA_133M_HCK, 6),
+	GATE_INFRA0(CK_INFRA_EIP97_CK, "infra_eip97", CK_INFRA_EIP_CK, 7),
+	GATE_INFRA0(CK_INFRA_AUD_BUS_CK, "infra_aud_bus", CK_INFRA_66M_PHCK, 8),
+	GATE_INFRA0(CK_INFRA_AUD_26M_CK, "infra_aud_26m", CK_INFRA_CK_F26M, 9),
+	GATE_INFRA0(CK_INFRA_AUD_L_CK, "infra_aud_l", CK_INFRA_FAUD_L_CK, 10),
+	GATE_INFRA0(CK_INFRA_AUD_AUD_CK, "infra_aud_aud", CK_INFRA_FAUD_AUD_CK,
+		    11),
+	GATE_INFRA0(CK_INFRA_AUD_EG2_CK, "infra_aud_eg2", CK_INFRA_FAUD_EG2_CK,
+		    13),
+	GATE_INFRA0(CK_INFRA_DRAMC_26M_CK, "infra_dramc_26m", CK_INFRA_CK_F26M,
+		    14),
+	GATE_INFRA0(CK_INFRA_DBG_CK, "infra_dbg", CK_INFRA_66M_MCK, 15),
+	GATE_INFRA0(CK_INFRA_AP_DMA_CK, "infra_ap_dma", CK_INFRA_66M_MCK, 16),
+	GATE_INFRA0(CK_INFRA_SEJ_CK, "infra_sej", CK_INFRA_66M_MCK, 24),
+	GATE_INFRA0(CK_INFRA_SEJ_13M_CK, "infra_sej_13m", CK_INFRA_CK_F26M, 25),
+	GATE_INFRA0(CK_INFRA_TRNG_CK, "infra_trng", CK_INFRA_HD_133M, 26),
+	/* INFRA1 */
+	GATE_INFRA1(CK_INFRA_THERM_CK, "infra_therm", CK_INFRA_CK_F26M, 0),
+	GATE_INFRA1(CK_INFRA_I2CO_CK, "infra_i2co", CK_INFRA_I2CS_CK, 1),
+	GATE_INFRA1(CK_INFRA_UART0_CK, "infra_uart0", CK_INFRA_MUX_UART0, 2),
+	GATE_INFRA1(CK_INFRA_UART1_CK, "infra_uart1", CK_INFRA_MUX_UART1, 3),
+	GATE_INFRA1(CK_INFRA_UART2_CK, "infra_uart2", CK_INFRA_MUX_UART2, 4),
+	GATE_INFRA1(CK_INFRA_NFI1_CK, "infra_nfi1", CK_INFRA_NFI_CK, 8),
+	GATE_INFRA1(CK_INFRA_SPINFI1_CK, "infra_spinfi1", CK_INFRA_SPINFI_CK,
+		    9),
+	GATE_INFRA1(CK_INFRA_NFI_HCK_CK, "infra_nfi_hck", CK_INFRA_66M_MCK, 10),
+	GATE_INFRA1(CK_INFRA_SPI0_CK, "infra_spi0", CK_INFRA_MUX_SPI0, 11),
+	GATE_INFRA1(CK_INFRA_SPI1_CK, "infra_spi1", CK_INFRA_MUX_SPI1, 12),
+	GATE_INFRA1(CK_INFRA_SPI0_HCK_CK, "infra_spi0_hck", CK_INFRA_66M_MCK,
+		    13),
+	GATE_INFRA1(CK_INFRA_SPI1_HCK_CK, "infra_spi1_hck", CK_INFRA_66M_MCK,
+		    14),
+	GATE_INFRA1(CK_INFRA_FRTC_CK, "infra_frtc", CK_INFRA_RTC_32K, 15),
+	GATE_INFRA1(CK_INFRA_MSDC_CK, "infra_msdc", CK_INFRA_FMSDC_CK, 16),
+	GATE_INFRA1(CK_INFRA_MSDC_HCK_CK, "infra_msdc_hck",
+		    CK_INFRA_FMSDC_HCK_CK, 17),
+	GATE_INFRA1(CK_INFRA_MSDC_133M_CK, "infra_msdc_133m",
+		    CK_INFRA_PERI_133M, 18),
+	GATE_INFRA1(CK_INFRA_MSDC_66M_CK, "infra_msdc_66m", CK_INFRA_66M_PHCK,
+		    19),
+	GATE_INFRA1(CK_INFRA_ADC_26M_CK, "infra_adc_26m", CK_INFRA_CK_F26M, 20),
+	GATE_INFRA1(CK_INFRA_ADC_FRC_CK, "infra_adc_frc", CK_INFRA_CK_F26M, 21),
+	GATE_INFRA1(CK_INFRA_FBIST2FPC_CK, "infra_fbist2fpc", CK_INFRA_NFI_CK,
+		    23),
+	/* INFRA2 */
+	GATE_INFRA2(CK_INFRA_IUSB_133_CK, "infra_iusb_133", CK_INFRA_133M_PHCK,
+		    0),
+	GATE_INFRA2(CK_INFRA_IUSB_66M_CK, "infra_iusb_66m", CK_INFRA_66M_PHCK,
+		    1),
+	GATE_INFRA2(CK_INFRA_IUSB_SYS_CK, "infra_iusb_sys", CK_INFRA_USB_SYS_CK,
+		    2),
+	GATE_INFRA2(CK_INFRA_IUSB_CK, "infra_iusb", CK_INFRA_USB_CK, 3),
+	GATE_INFRA2(CK_INFRA_IPCIE_CK, "infra_ipcie", CK_INFRA_PCIE_CK, 13),
+	GATE_INFRA2(CK_INFRA_IPCIER_CK, "infra_ipcier", CK_INFRA_F26M_CK0, 15),
+	GATE_INFRA2(CK_INFRA_IPCIEB_CK, "infra_ipcieb", CK_INFRA_133M_PHCK, 15),
+};
+
+static const struct mtk_clk_tree mt7986_fixed_pll_clk_tree = {
+	.fdivs_offs = CLK_APMIXED_NR_CLK,
+	.xtal_rate = 40 * MHZ,
+	.fclks = fixed_pll_clks,
+};
+
+static const struct mtk_clk_tree mt7986_topckgen_clk_tree = {
+	.fdivs_offs = CK_TOP_CB_M_416M,
+	.muxes_offs = CK_TOP_NFI1X_SEL,
+	.fclks = top_fixed_clks,
+	.fdivs = top_fixed_divs,
+	.muxes = top_muxes,
+	.flags = CLK_BYPASS_XTAL,
+};
+
+static const struct mtk_clk_tree mt7986_infracfg_clk_tree = {
+	.fdivs_offs = CK_INFRA_CK_F26M,
+	.muxes_offs = CK_INFRA_UART0_SEL,
+	.fdivs = infra_fixed_divs,
+	.muxes = infra_muxes,
+};
+
+static const struct udevice_id mt7986_fixed_pll_compat[] = {
+	{ .compatible = "mediatek,mt7986-fixed-plls" },
+	{}
+};
+
+static const struct udevice_id mt7986_topckgen_compat[] = {
+	{ .compatible = "mediatek,mt7986-topckgen" },
+	{}
+};
+
+static int mt7986_fixed_pll_probe(struct udevice *dev)
+{
+	return mtk_common_clk_init(dev, &mt7986_fixed_pll_clk_tree);
+}
+
+static int mt7986_topckgen_probe(struct udevice *dev)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+	writel(MT7986_CLK_PDN_EN_WRITE, priv->base + MT7986_CLK_PDN);
+
+	return mtk_common_clk_init(dev, &mt7986_topckgen_clk_tree);
+}
+
+U_BOOT_DRIVER(mtk_clk_apmixedsys) = {
+	.name = "mt7986-clock-fixed-pll",
+	.id = UCLASS_CLK,
+	.of_match = mt7986_fixed_pll_compat,
+	.probe = mt7986_fixed_pll_probe,
+	.priv_auto = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_topckgen_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_topckgen) = {
+	.name = "mt7986-clock-topckgen",
+	.id = UCLASS_CLK,
+	.of_match = mt7986_topckgen_compat,
+	.probe = mt7986_topckgen_probe,
+	.priv_auto = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_topckgen_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+static const struct udevice_id mt7986_infracfg_compat[] = {
+	{ .compatible = "mediatek,mt7986-infracfg" },
+	{}
+};
+
+static const struct udevice_id mt7986_infracfg_ao_compat[] = {
+	{ .compatible = "mediatek,mt7986-infracfg_ao" },
+	{}
+};
+
+static int mt7986_infracfg_probe(struct udevice *dev)
+{
+	return mtk_common_clk_init(dev, &mt7986_infracfg_clk_tree);
+}
+
+static int mt7986_infracfg_ao_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7986_infracfg_clk_tree,
+					infracfg_ao_gates);
+}
+
+U_BOOT_DRIVER(mtk_clk_infracfg) = {
+	.name = "mt7986-clock-infracfg",
+	.id = UCLASS_CLK,
+	.of_match = mt7986_infracfg_compat,
+	.probe = mt7986_infracfg_probe,
+	.priv_auto = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_infrasys_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_infracfg_ao) = {
+	.name = "mt7986-clock-infracfg-ao",
+	.id = UCLASS_CLK,
+	.of_match = mt7986_infracfg_ao_compat,
+	.probe = mt7986_infracfg_ao_probe,
+	.priv_auto = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+/* ethsys */
+static const struct mtk_gate_regs eth_cg_regs = {
+	.sta_ofs = 0x30,
+};
+
+#define GATE_ETH(_id, _name, _parent, _shift)                                  \
+	{                                                                      \
+		.id = _id, .parent = _parent, .regs = &eth_cg_regs,            \
+		.shift = _shift,                                               \
+		.flags = CLK_GATE_NO_SETCLR_INV | CLK_PARENT_TOPCKGEN,         \
+	}
+
+static const struct mtk_gate eth_cgs[] = {
+	GATE_ETH(CK_ETH_FE_EN, "eth_fe_en", CK_TOP_NETSYS_2X, 7),
+	GATE_ETH(CK_ETH_GP2_EN, "eth_gp2_en", CK_TOP_SGM_325M, 8),
+	GATE_ETH(CK_ETH_GP1_EN, "eth_gp1_en", CK_TOP_SGM_325M, 8),
+	GATE_ETH(CK_ETH_WOCPU1_EN, "eth_wocpu1_en", CK_TOP_NETSYS_WED_MCU, 14),
+	GATE_ETH(CK_ETH_WOCPU0_EN, "eth_wocpu0_en", CK_TOP_NETSYS_WED_MCU, 15),
+};
+
+static int mt7986_ethsys_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7986_topckgen_clk_tree,
+					eth_cgs);
+}
+
+static int mt7986_ethsys_bind(struct udevice *dev)
+{
+	int ret = 0;
+
+	if (CONFIG_IS_ENABLED(RESET_MEDIATEK)) {
+		ret = mediatek_reset_bind(dev, ETHSYS_HIFSYS_RST_CTRL_OFS, 1);
+		if (ret)
+			debug("Warning: failed to bind reset controller\n");
+	}
+
+	return ret;
+}
+
+static const struct udevice_id mt7986_ethsys_compat[] = {
+	{ .compatible = "mediatek,mt7986-ethsys" },
+	{ }
+};
+
+U_BOOT_DRIVER(mtk_clk_ethsys) = {
+	.name = "mt7986-clock-ethsys",
+	.id = UCLASS_CLK,
+	.of_match = mt7986_ethsys_compat,
+	.probe = mt7986_ethsys_probe,
+	.bind = mt7986_ethsys_bind,
+	.priv_auto = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+};
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index d43b8a0..4303300 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -42,20 +42,14 @@
  * the accurate frequency.
  */
 static ulong mtk_clk_find_parent_rate(struct clk *clk, int id,
-				      const struct driver *drv)
+				      struct udevice *pdev)
 {
 	struct clk parent = { .id = id, };
 
-	if (drv) {
-		struct udevice *dev;
-
-		if (uclass_get_device_by_driver(UCLASS_CLK, drv, &dev))
-			return -ENODEV;
-
-		parent.dev = dev;
-	} else {
+	if (pdev)
+		parent.dev = pdev;
+	else
 		parent.dev = clk->dev;
-	}
 
 	return clk_get_rate(&parent);
 }
@@ -296,14 +290,36 @@
 	switch (fdiv->flags & CLK_PARENT_MASK) {
 	case CLK_PARENT_APMIXED:
 		rate = mtk_clk_find_parent_rate(clk, fdiv->parent,
-				DM_DRIVER_GET(mtk_clk_apmixedsys));
+						priv->parent);
 		break;
 	case CLK_PARENT_TOPCKGEN:
 		rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL);
 		break;
 
+	case CLK_PARENT_XTAL:
 	default:
 		rate = priv->tree->xtal_rate;
+	}
+
+	return mtk_factor_recalc_rate(fdiv, rate);
+}
+
+static ulong mtk_infrasys_get_factor_rate(struct clk *clk, u32 off)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_fixed_factor *fdiv = &priv->tree->fdivs[off];
+	ulong rate;
+
+	switch (fdiv->flags & CLK_PARENT_MASK) {
+	case CLK_PARENT_TOPCKGEN:
+		rate = mtk_clk_find_parent_rate(clk, fdiv->parent,
+						priv->parent);
+		break;
+	case CLK_PARENT_XTAL:
+		rate = priv->tree->xtal_rate;
+		break;
+	default:
+		rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL);
 	}
 
 	return mtk_factor_recalc_rate(fdiv, rate);
@@ -319,13 +335,51 @@
 	index &= mux->mux_mask << mux->mux_shift;
 	index = index >> mux->mux_shift;
 
-	if (mux->parent[index])
-		return mtk_clk_find_parent_rate(clk, mux->parent[index],
-						NULL);
+	if (mux->parent[index] > 0 ||
+	    (mux->parent[index] == CLK_XTAL &&
+	     priv->tree->flags & CLK_BYPASS_XTAL)) {
+		switch (mux->flags & CLK_PARENT_MASK) {
+		case CLK_PARENT_APMIXED:
+			return mtk_clk_find_parent_rate(clk, mux->parent[index],
+							priv->parent);
+			break;
+		default:
+			return mtk_clk_find_parent_rate(clk, mux->parent[index],
+							NULL);
+			break;
+		}
+	}
 
 	return priv->tree->xtal_rate;
 }
 
+static ulong mtk_infrasys_get_mux_rate(struct clk *clk, u32 off)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_composite *mux = &priv->tree->muxes[off];
+	u32 index;
+
+	index = readl(priv->base + mux->mux_reg);
+	index &= mux->mux_mask << mux->mux_shift;
+	index = index >> mux->mux_shift;
+
+	if (mux->parent[index] > 0 ||
+	    (mux->parent[index] == CLK_XTAL &&
+	     priv->tree->flags & CLK_BYPASS_XTAL)) {
+		switch (mux->flags & CLK_PARENT_MASK) {
+		case CLK_PARENT_TOPCKGEN:
+			return mtk_clk_find_parent_rate(clk, mux->parent[index],
+							priv->parent);
+			break;
+		default:
+			return mtk_clk_find_parent_rate(clk, mux->parent[index],
+							NULL);
+			break;
+		}
+	}
+	return 0;
+}
+
 static ulong mtk_topckgen_get_rate(struct clk *clk)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
@@ -340,9 +394,28 @@
 						 priv->tree->muxes_offs);
 }
 
-static int mtk_topckgen_enable(struct clk *clk)
+static ulong mtk_infrasys_get_rate(struct clk *clk)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+
+	ulong rate;
+
+	if (clk->id < priv->tree->fdivs_offs) {
+		rate = priv->tree->fclks[clk->id].rate;
+	} else if (clk->id < priv->tree->muxes_offs) {
+		rate = mtk_infrasys_get_factor_rate(clk, clk->id -
+						    priv->tree->fdivs_offs);
+	} else {
+		rate = mtk_infrasys_get_mux_rate(clk, clk->id -
+						 priv->tree->muxes_offs);
+	}
+
+	return rate;
+}
+
+static int mtk_clk_mux_enable(struct clk *clk)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
 	const struct mtk_composite *mux;
 	u32 val;
 
@@ -373,7 +446,7 @@
 	return 0;
 }
 
-static int mtk_topckgen_disable(struct clk *clk)
+static int mtk_clk_mux_disable(struct clk *clk)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
 	const struct mtk_composite *mux;
@@ -399,7 +472,7 @@
 	return 0;
 }
 
-static int mtk_topckgen_set_parent(struct clk *clk, struct clk *parent)
+static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
 
@@ -471,19 +544,7 @@
 	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
 	const struct mtk_gate *gate = &priv->gates[clk->id];
 
-	switch (gate->flags & CLK_PARENT_MASK) {
-	case CLK_PARENT_APMIXED:
-		return mtk_clk_find_parent_rate(clk, gate->parent,
-				DM_DRIVER_GET(mtk_clk_apmixedsys));
-		break;
-	case CLK_PARENT_TOPCKGEN:
-		return mtk_clk_find_parent_rate(clk, gate->parent,
-				DM_DRIVER_GET(mtk_clk_topckgen));
-		break;
-
-	default:
-		return priv->tree->xtal_rate;
-	}
+	return mtk_clk_find_parent_rate(clk, gate->parent, priv->parent);
 }
 
 const struct clk_ops mtk_clk_apmixedsys_ops = {
@@ -494,10 +555,17 @@
 };
 
 const struct clk_ops mtk_clk_topckgen_ops = {
-	.enable = mtk_topckgen_enable,
-	.disable = mtk_topckgen_disable,
+	.enable = mtk_clk_mux_enable,
+	.disable = mtk_clk_mux_disable,
 	.get_rate = mtk_topckgen_get_rate,
-	.set_parent = mtk_topckgen_set_parent,
+	.set_parent = mtk_common_clk_set_parent,
+};
+
+const struct clk_ops mtk_clk_infrasys_ops = {
+	.enable = mtk_clk_mux_enable,
+	.disable = mtk_clk_mux_disable,
+	.get_rate = mtk_infrasys_get_rate,
+	.set_parent = mtk_common_clk_set_parent,
 };
 
 const struct clk_ops mtk_clk_gate_ops = {
@@ -510,11 +578,22 @@
 			const struct mtk_clk_tree *tree)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(dev);
+	struct udevice *parent;
+	int ret;
 
 	priv->base = dev_read_addr_ptr(dev);
 	if (!priv->base)
 		return -ENOENT;
 
+	ret = uclass_get_device_by_phandle(UCLASS_CLK, dev, "clock-parent", &parent);
+	if (ret || !parent) {
+		ret = uclass_get_device_by_driver(UCLASS_CLK,
+				DM_DRIVER_GET(mtk_clk_apmixedsys), &parent);
+		if (ret || !parent)
+			return -ENOENT;
+	}
+
+	priv->parent = parent;
 	priv->tree = tree;
 
 	return 0;
@@ -525,11 +604,22 @@
 			     const struct mtk_gate *gates)
 {
 	struct mtk_cg_priv *priv = dev_get_priv(dev);
+	struct udevice *parent;
+	int ret;
 
 	priv->base = dev_read_addr_ptr(dev);
 	if (!priv->base)
 		return -ENOENT;
 
+	ret = uclass_get_device_by_phandle(UCLASS_CLK, dev, "clock-parent", &parent);
+	if (ret || !parent) {
+		ret = uclass_get_device_by_driver(UCLASS_CLK,
+				DM_DRIVER_GET(mtk_clk_topckgen), &parent);
+		if (ret || !parent)
+			return -ENOENT;
+	}
+
+	priv->parent = parent;
 	priv->tree = tree;
 	priv->gates = gates;
 
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index 95a23d1..48ce164 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -11,6 +11,11 @@
 #define CLK_XTAL			0
 #define MHZ				(1000 * 1000)
 
+/* flags in struct mtk_clk_tree */
+
+/* clk id == 0 doesn't mean it's xtal clk */
+#define CLK_BYPASS_XTAL			BIT(0)
+
 #define HAVE_RST_BAR			BIT(0)
 #define CLK_DOMAIN_SCPSYS		BIT(0)
 #define CLK_MUX_SETCLR_UPD		BIT(1)
@@ -23,7 +28,9 @@
 
 #define CLK_PARENT_APMIXED		BIT(4)
 #define CLK_PARENT_TOPCKGEN		BIT(5)
-#define CLK_PARENT_MASK			GENMASK(5, 4)
+#define CLK_PARENT_INFRASYS		BIT(6)
+#define CLK_PARENT_XTAL			BIT(7)
+#define CLK_PARENT_MASK			GENMASK(7, 4)
 
 #define ETHSYS_HIFSYS_RST_CTRL_OFS	0x34
 
@@ -197,14 +204,17 @@
 	const struct mtk_fixed_clk *fclks;
 	const struct mtk_fixed_factor *fdivs;
 	const struct mtk_composite *muxes;
+	u32 flags;
 };
 
 struct mtk_clk_priv {
+	struct udevice *parent;
 	void __iomem *base;
 	const struct mtk_clk_tree *tree;
 };
 
 struct mtk_cg_priv {
+	struct udevice *parent;
 	void __iomem *base;
 	const struct mtk_clk_tree *tree;
 	const struct mtk_gate *gates;
@@ -212,6 +222,7 @@
 
 extern const struct clk_ops mtk_clk_apmixedsys_ops;
 extern const struct clk_ops mtk_clk_topckgen_ops;
+extern const struct clk_ops mtk_clk_infrasys_ops;
 extern const struct clk_ops mtk_clk_gate_ops;
 
 int mtk_common_clk_init(struct udevice *dev,
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index 20884b1..3b38ba9 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
 obj-$(CONFIG_ARCH_IMX8) += imx8_cpu.o
 obj-$(CONFIG_ARCH_AT91) += at91_cpu.o
+obj-$(CONFIG_ARCH_MEDIATEK) += mtk_cpu.o
 obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
 obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
 obj-$(CONFIG_CPU_MICROBLAZE) += microblaze_cpu.o
diff --git a/drivers/cpu/mtk_cpu.c b/drivers/cpu/mtk_cpu.c
new file mode 100644
index 0000000..2a08be9
--- /dev/null
+++ b/drivers/cpu/mtk_cpu.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/types.h>
+#include <cpu.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/global_data.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct mtk_cpu_plat {
+	struct regmap *hwver;
+};
+
+static int mtk_cpu_get_desc(const struct udevice *dev, char *buf, int size)
+{
+	struct mtk_cpu_plat *plat = dev_get_plat(dev);
+	uint val;
+
+	regmap_read(plat->hwver, 0, &val);
+
+	snprintf(buf, size, "MediaTek MT%04X", val);
+
+	return 0;
+}
+
+static int mtk_cpu_get_count(const struct udevice *dev)
+{
+	return 1;
+}
+
+static int mtk_cpu_get_vendor(const struct udevice *dev, char *buf, int size)
+{
+	snprintf(buf, size, "MediaTek");
+
+	return 0;
+}
+
+static int mtk_cpu_probe(struct udevice *dev)
+{
+	struct mtk_cpu_plat *plat = dev_get_plat(dev);
+	struct ofnode_phandle_args args;
+	int ret;
+
+	ret = dev_read_phandle_with_args(dev, "mediatek,hwver", NULL, 0, 0,
+					 &args);
+	if (ret)
+		return ret;
+
+	plat->hwver = syscon_node_to_regmap(args.node);
+	if (IS_ERR(plat->hwver))
+		return PTR_ERR(plat->hwver);
+
+	return 0;
+}
+
+static const struct cpu_ops mtk_cpu_ops = {
+	.get_desc	= mtk_cpu_get_desc,
+	.get_count	= mtk_cpu_get_count,
+	.get_vendor	= mtk_cpu_get_vendor,
+};
+
+static const struct udevice_id mtk_cpu_ids[] = {
+	{ .compatible = "arm,cortex-a7" },
+	{ .compatible = "arm,cortex-a53" },
+	{ .compatible = "arm,cortex-a73" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(cpu_mtk) = {
+	.name		= "mtk-cpu",
+	.id		= UCLASS_CPU,
+	.of_match	= mtk_cpu_ids,
+	.ops		= &mtk_cpu_ops,
+	.probe		= mtk_cpu_probe,
+	.plat_auto	= sizeof(struct mtk_cpu_plat),
+	.flags		= DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/ddr/fsl/lc_common_dimm_params.c b/drivers/ddr/fsl/lc_common_dimm_params.c
index d738ae3..5e4ad56 100644
--- a/drivers/ddr/fsl/lc_common_dimm_params.c
+++ b/drivers/ddr/fsl/lc_common_dimm_params.c
@@ -422,6 +422,9 @@
 					dimm_params[i].mpart);
 #endif
 			}
+#ifndef CONFIG_SPL_BUILD
+			puts("       ");
+#endif
 		}
 	}
 
diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c
index 1903562..ed3313a 100644
--- a/drivers/ddr/fsl/main.c
+++ b/drivers/ddr/fsl/main.c
@@ -857,17 +857,32 @@
 	debug("total_memory by %s = %llu\n", __func__, total_memory);
 
 #if !defined(CONFIG_PHYS_64BIT)
-	/* Check for 4G or more.  Bad. */
-	if ((first_ctrl == 0) && (total_memory >= (1ull << 32))) {
+	/*
+	 * Show warning about big DDR moodules. But avoid warning for 4 GB DDR
+	 * modules when U-Boot supports RAM of maximal size 4 GB - 1 byte.
+	 */
+	if ((first_ctrl == 0) && (total_memory - 1 > (phys_size_t)~0ULL)) {
 		puts("Detected ");
 		print_size(total_memory, " of memory\n");
-		printf("       This U-Boot only supports < 4G of DDR\n");
-		printf("       You could rebuild it with CONFIG_PHYS_64BIT\n");
-		printf("       "); /* re-align to match init_dram print */
-		total_memory = CONFIG_MAX_MEM_MAPPED;
+#ifndef CONFIG_SPL_BUILD
+		puts("       "); /* re-align to match init_dram print */
+#endif
+		puts("This U-Boot only supports <= ");
+		print_size((unsigned long long)((phys_size_t)~0ULL)+1, " of DDR\n");
+#ifndef CONFIG_SPL_BUILD
+		puts("       "); /* re-align to match init_dram print */
+#endif
+		puts("You could rebuild it with CONFIG_PHYS_64BIT\n");
+#ifndef CONFIG_SPL_BUILD
+		puts("       "); /* re-align to match init_dram print */
+#endif
 	}
 #endif
 
+	/* Ensure that total_memory does not overflow on return */
+	if (total_memory > (phys_size_t)~0ULL)
+		total_memory = (phys_size_t)~0ULL;
+
 	return total_memory;
 }
 
@@ -941,5 +956,9 @@
 	/* Compute it once normally. */
 	total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 1);
 
+	/* Ensure that total_memory does not overflow on return */
+	if (total_memory > (phys_size_t)~0ULL)
+		total_memory = (phys_size_t)~0ULL;
+
 	return total_memory;
 }
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index be4724b..08b6c7b 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -261,6 +261,15 @@
 	  internal buffer holding up to 8 bytes for transfers and supports
 	  both 7-bit and 10-bit addresses.
 
+config SYS_I2C_MTK
+	bool "MediaTek I2C driver"
+	help
+	  This selects the MediaTek Integrated Inter Circuit bus driver.
+	  The I2C bus adapter is the base for some other I2C client,
+	  eg: touch, sensors.
+	  If you want to use MediaTek I2C interface, say Y here.
+	  If unsure, say N.
+
 config SYS_I2C_MICROCHIP
 	bool "Microchip I2C driver"
 	help
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 7e046f8..920aafb 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -32,6 +32,7 @@
 obj-$(CONFIG_SYS_I2C_MV) += mv_i2c.o
 obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
 obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
+obj-$(CONFIG_SYS_I2C_MTK) += mtk_i2c.o
 obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o
 obj-$(CONFIG_SYS_I2C_NPCM) += npcm_i2c.o
 obj-$(CONFIG_SYS_I2C_OCORES) += ocores_i2c.o
diff --git a/drivers/i2c/mtk_i2c.c b/drivers/i2c/mtk_i2c.c
new file mode 100644
index 0000000..5528bcd
--- /dev/null
+++ b/drivers/i2c/mtk_i2c.c
@@ -0,0 +1,822 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: Mingming Lee <Mingming.Lee@mediatek.com>
+ *
+ * MediaTek I2C Interface driver
+ */
+
+#include <clk.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+
+#define I2C_RS_TRANSFER			BIT(4)
+#define I2C_HS_NACKERR			BIT(2)
+#define I2C_ACKERR			BIT(1)
+#define I2C_TRANSAC_COMP		BIT(0)
+#define I2C_TRANSAC_START		BIT(0)
+#define I2C_RS_MUL_CNFG			BIT(15)
+#define I2C_RS_MUL_TRIG			BIT(14)
+#define I2C_DCM_DISABLE			0x0000
+#define I2C_IO_CONFIG_OPEN_DRAIN	0x0003
+#define I2C_IO_CONFIG_PUSH_PULL		0x0000
+#define I2C_SOFT_RST			0x0001
+#define I2C_FIFO_ADDR_CLR		0x0001
+#define I2C_DELAY_LEN			0x0002
+#define I2C_ST_START_CON		0x8001
+#define I2C_FS_START_CON		0x1800
+#define I2C_TIME_CLR_VALUE		0x0000
+#define I2C_TIME_DEFAULT_VALUE		0x0003
+#define I2C_WRRD_TRANAC_VALUE		0x0002
+#define I2C_RD_TRANAC_VALUE		0x0001
+
+#define I2C_DMA_CON_TX			0x0000
+#define I2C_DMA_CON_RX			0x0001
+#define I2C_DMA_START_EN		0x0001
+#define I2C_DMA_INT_FLAG_NONE		0x0000
+#define I2C_DMA_CLR_FLAG		0x0000
+#define I2C_DMA_TX_RX			0x0000
+#define I2C_DMA_HARD_RST		0x0002
+
+#define MAX_ST_MODE_SPEED		100000
+#define MAX_FS_MODE_SPEED		400000
+#define MAX_HS_MODE_SPEED		3400000
+#define MAX_SAMPLE_CNT_DIV		8
+#define MAX_STEP_CNT_DIV		64
+#define MAX_HS_STEP_CNT_DIV		8
+#define I2C_DEFAULT_CLK_DIV		4
+
+#define MAX_I2C_ADDR			0x7f
+#define MAX_I2C_LEN			0xff
+#define TRANS_ADDR_ONLY			BIT(8)
+#define TRANSFER_TIMEOUT		50000  /* us */
+#define I2C_FIFO_STAT1_MASK		0x001f
+#define TIMING_SAMPLE_OFFSET		8
+#define HS_SAMPLE_OFFSET		12
+#define HS_STEP_OFFSET			8
+
+#define I2C_CONTROL_WRAPPER		BIT(0)
+#define I2C_CONTROL_RS			BIT(1)
+#define I2C_CONTROL_DMA_EN		BIT(2)
+#define I2C_CONTROL_CLK_EXT_EN		BIT(3)
+#define I2C_CONTROL_DIR_CHANGE		BIT(4)
+#define I2C_CONTROL_ACKERR_DET_EN	BIT(5)
+#define I2C_CONTROL_TRANSFER_LEN_CHANGE BIT(6)
+#define I2C_CONTROL_DMAACK		BIT(8)
+#define I2C_CONTROL_ASYNC		BIT(9)
+
+#define I2C_MASTER_WR			BIT(0)
+#define I2C_MASTER_RD			BIT(1)
+#define I2C_MASTER_WRRD			(I2C_MASTER_WR | I2C_MASTER_RD)
+
+enum I2C_REGS_OFFSET {
+	REG_PORT,
+	REG_SLAVE_ADDR,
+	REG_INTR_MASK,
+	REG_INTR_STAT,
+	REG_CONTROL,
+	REG_TRANSFER_LEN,
+	REG_TRANSAC_LEN,
+	REG_DELAY_LEN,
+	REG_TIMING,
+	REG_START,
+	REG_EXT_CONF,
+	REG_FIFO_STAT1,
+	REG_LTIMING,
+	REG_FIFO_STAT,
+	REG_FIFO_THRESH,
+	REG_FIFO_ADDR_CLR,
+	REG_IO_CONFIG,
+	REG_RSV_DEBUG,
+	REG_HS,
+	REG_SOFTRESET,
+	REG_DCM_EN,
+	REG_PATH_DIR,
+	REG_DEBUGSTAT,
+	REG_DEBUGCTRL,
+	REG_TRANSFER_LEN_AUX,
+	REG_CLOCK_DIV,
+	REG_SCL_HL_RATIO,
+	REG_SCL_HS_HL_RATIO,
+	REG_SCL_MIS_COMP_POINT,
+	REG_STA_STOP_AC_TIME,
+	REG_HS_STA_STOP_AC_TIME,
+	REG_DATA_TIME,
+};
+
+enum DMA_REGS_OFFSET {
+	REG_INT_FLAG = 0x0,
+	REG_INT_EN = 0x04,
+	REG_EN = 0x08,
+	REG_RST = 0x0c,
+	REG_CON = 0x18,
+	REG_TX_MEM_ADDR = 0x1c,
+	REG_RX_MEM_ADDR = 0x20,
+	REG_TX_LEN = 0x24,
+	REG_RX_LEN = 0x28,
+};
+
+static const uint mt_i2c_regs_v1[] = {
+	[REG_PORT] = 0x0,
+	[REG_SLAVE_ADDR] = 0x4,
+	[REG_INTR_MASK] = 0x8,
+	[REG_INTR_STAT] = 0xc,
+	[REG_CONTROL] = 0x10,
+	[REG_TRANSFER_LEN] = 0x14,
+	[REG_TRANSAC_LEN] = 0x18,
+	[REG_DELAY_LEN] = 0x1c,
+	[REG_TIMING] = 0x20,
+	[REG_START] = 0x24,
+	[REG_EXT_CONF] = 0x28,
+	[REG_FIFO_STAT1] = 0x2c,
+	[REG_FIFO_STAT] = 0x30,
+	[REG_FIFO_THRESH] = 0x34,
+	[REG_FIFO_ADDR_CLR] = 0x38,
+	[REG_IO_CONFIG] = 0x40,
+	[REG_RSV_DEBUG] = 0x44,
+	[REG_HS] = 0x48,
+	[REG_SOFTRESET] = 0x50,
+	[REG_SOFTRESET] = 0x50,
+	[REG_DCM_EN] = 0x54,
+	[REG_DEBUGSTAT] = 0x64,
+	[REG_DEBUGCTRL] = 0x68,
+	[REG_TRANSFER_LEN_AUX] = 0x6c,
+	[REG_CLOCK_DIV] = 0x70,
+	[REG_SCL_HL_RATIO] = 0x74,
+	[REG_SCL_HS_HL_RATIO] = 0x78,
+	[REG_SCL_MIS_COMP_POINT] = 0x7c,
+	[REG_STA_STOP_AC_TIME] = 0x80,
+	[REG_HS_STA_STOP_AC_TIME] = 0x84,
+	[REG_DATA_TIME] = 0x88,
+};
+
+static const uint mt_i2c_regs_v2[] = {
+	[REG_PORT] = 0x0,
+	[REG_SLAVE_ADDR] = 0x4,
+	[REG_INTR_MASK] = 0x8,
+	[REG_INTR_STAT] = 0xc,
+	[REG_CONTROL] = 0x10,
+	[REG_TRANSFER_LEN] = 0x14,
+	[REG_TRANSAC_LEN] = 0x18,
+	[REG_DELAY_LEN] = 0x1c,
+	[REG_TIMING] = 0x20,
+	[REG_START] = 0x24,
+	[REG_EXT_CONF] = 0x28,
+	[REG_LTIMING] = 0x2c,
+	[REG_HS] = 0x30,
+	[REG_IO_CONFIG] = 0x34,
+	[REG_FIFO_ADDR_CLR] = 0x38,
+	[REG_TRANSFER_LEN_AUX] = 0x44,
+	[REG_CLOCK_DIV] = 0x48,
+	[REG_SOFTRESET] = 0x50,
+	[REG_DEBUGSTAT] = 0xe0,
+	[REG_DEBUGCTRL] = 0xe8,
+	[REG_FIFO_STAT] = 0xf4,
+	[REG_FIFO_THRESH] = 0xf8,
+	[REG_DCM_EN] = 0xf88,
+};
+
+struct mtk_i2c_soc_data {
+	const uint *regs;
+	uint dma_sync: 1;
+};
+
+struct mtk_i2c_priv {
+	/* set in i2c probe */
+	void __iomem *base;		/* i2c base addr */
+	void __iomem *pdmabase;		/* dma base address*/
+	struct clk clk_main;		/* main clock for i2c bus */
+	struct clk clk_dma;		/* DMA clock for i2c via DMA */
+	const struct mtk_i2c_soc_data *soc_data; /* Compatible data for different IC */
+	int op;				/* operation mode */
+	bool zero_len;			/* Only transfer slave address, no data */
+	bool pushpull;			/* push pull mode or open drain mode */
+	bool filter_msg;		/* filter msg error log */
+	bool auto_restart;		/* restart mode */
+	bool ignore_restart_irq;	/* ignore restart IRQ */
+	uint speed;			/* i2c speed, unit: hz */
+};
+
+static inline void i2c_writel(struct mtk_i2c_priv *priv, uint reg, uint value)
+{
+	u32 offset = priv->soc_data->regs[reg];
+
+	writel(value, priv->base + offset);
+}
+
+static inline uint i2c_readl(struct mtk_i2c_priv *priv, uint offset)
+{
+	return readl(priv->base + priv->soc_data->regs[offset]);
+}
+
+static int mtk_i2c_clk_enable(struct mtk_i2c_priv *priv)
+{
+	int ret;
+
+	ret = clk_enable(&priv->clk_main);
+	if (ret)
+		return log_msg_ret("enable clk_main", ret);
+
+	ret = clk_enable(&priv->clk_dma);
+	if (ret)
+		return log_msg_ret("enable clk_dma", ret);
+
+	return 0;
+}
+
+static int mtk_i2c_clk_disable(struct mtk_i2c_priv *priv)
+{
+	int ret;
+
+	ret = clk_disable(&priv->clk_dma);
+	if (ret)
+		return log_msg_ret("disable clk_dma", ret);
+
+	ret = clk_disable(&priv->clk_main);
+	if (ret)
+		return log_msg_ret("disable clk_main", ret);
+
+	return 0;
+}
+
+static void mtk_i2c_init_hw(struct mtk_i2c_priv *priv)
+{
+	uint control_reg;
+
+	writel(I2C_DMA_HARD_RST, priv->pdmabase + REG_RST);
+	writel(I2C_DMA_CLR_FLAG, priv->pdmabase + REG_RST);
+	i2c_writel(priv, REG_SOFTRESET, I2C_SOFT_RST);
+	/* set ioconfig */
+	if (priv->pushpull)
+		i2c_writel(priv, REG_IO_CONFIG, I2C_IO_CONFIG_PUSH_PULL);
+	else
+		i2c_writel(priv, REG_IO_CONFIG, I2C_IO_CONFIG_OPEN_DRAIN);
+
+	i2c_writel(priv, REG_DCM_EN, I2C_DCM_DISABLE);
+	control_reg = I2C_CONTROL_ACKERR_DET_EN | I2C_CONTROL_CLK_EXT_EN;
+	if (priv->soc_data->dma_sync)
+		control_reg |= I2C_CONTROL_DMAACK | I2C_CONTROL_ASYNC;
+	i2c_writel(priv, REG_CONTROL, control_reg);
+	i2c_writel(priv, REG_DELAY_LEN, I2C_DELAY_LEN);
+}
+
+/*
+ * Calculate i2c port speed
+ *
+ * Hardware design:
+ * i2c_bus_freq = parent_clk / (clock_div * 2 * sample_cnt * step_cnt)
+ * clock_div: fixed in hardware, but may be various in different SoCs
+ *
+ * The calculation want to pick the highest bus frequency that is still
+ * less than or equal to target_speed. The calculation try to get
+ * sample_cnt and step_cn
+ * @param[in]
+ *     clk_src: i2c clock source
+ * @param[out]
+ *     timing_step_cnt: step cnt calculate result
+ * @param[out]
+ *     timing_sample_cnt: sample cnt calculate result
+ * @return
+ *     0, set speed successfully.
+ *     -EINVAL, Unsupported speed.
+ */
+static int mtk_i2c_calculate_speed(uint clk_src,
+				   uint target_speed,
+				   uint *timing_step_cnt,
+				   uint *timing_sample_cnt)
+{
+	uint base_sample_cnt = MAX_SAMPLE_CNT_DIV;
+	uint base_step_cnt;
+	uint max_step_cnt;
+	uint sample_cnt;
+	uint step_cnt;
+	uint opt_div;
+	uint best_mul;
+	uint cnt_mul;
+
+	if (target_speed > MAX_HS_MODE_SPEED)
+		target_speed = MAX_HS_MODE_SPEED;
+
+	if (target_speed > MAX_FS_MODE_SPEED)
+		max_step_cnt = MAX_HS_STEP_CNT_DIV;
+	else
+		max_step_cnt = MAX_STEP_CNT_DIV;
+
+	base_step_cnt = max_step_cnt;
+	/* Find the best combination */
+	opt_div = DIV_ROUND_UP(clk_src >> 1, target_speed);
+	best_mul = MAX_SAMPLE_CNT_DIV * max_step_cnt;
+
+	/*
+	 * Search for the best pair (sample_cnt, step_cnt) with
+	 * 0 < sample_cnt < MAX_SAMPLE_CNT_DIV
+	 * 0 < step_cnt < max_step_cnt
+	 * sample_cnt * step_cnt >= opt_div
+	 * optimizing for sample_cnt * step_cnt being minimal
+	 */
+	for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) {
+		step_cnt = DIV_ROUND_UP(opt_div, sample_cnt);
+		cnt_mul = step_cnt * sample_cnt;
+		if (step_cnt > max_step_cnt)
+			continue;
+
+		if (cnt_mul < best_mul) {
+			best_mul = cnt_mul;
+			base_sample_cnt = sample_cnt;
+			base_step_cnt = step_cnt;
+			if (best_mul == opt_div)
+				break;
+		}
+	}
+
+	sample_cnt = base_sample_cnt;
+	step_cnt = base_step_cnt;
+
+	if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) {
+		/*
+		 * In this case, hardware can't support such
+		 * low i2c_bus_freq
+		 */
+		debug("Unsupported speed(%uhz)\n", target_speed);
+		return log_msg_ret("calculate speed", -EINVAL);
+	}
+
+	*timing_step_cnt = step_cnt - 1;
+	*timing_sample_cnt = sample_cnt - 1;
+
+	return 0;
+}
+
+/*
+ * mtk_i2c_set_speed
+ *
+ * @par Description
+ *     Calculate i2c speed and write sample_cnt, step_cnt to TIMING register.
+ * @param[in]
+ *     dev: udevice pointer, struct udevice contains i2c source clock,
+ *     clock divide and speed.
+ * @return
+ *     0, set speed successfully.\n
+ *     error code from mtk_i2c_calculate_speed().
+ */
+static int mtk_i2c_set_speed(struct udevice *dev, uint speed)
+{
+	struct mtk_i2c_priv *priv = dev_get_priv(dev);
+	uint high_speed_reg;
+	uint sample_cnt;
+	uint timing_reg;
+	uint step_cnt;
+	uint clk_src;
+	int ret = 0;
+
+	priv->speed = speed;
+	if (mtk_i2c_clk_enable(priv))
+		return log_msg_ret("set_speed enable clk", -1);
+
+	clk_src = clk_get_rate(&priv->clk_main) / I2C_DEFAULT_CLK_DIV;
+	i2c_writel(priv, REG_CLOCK_DIV, (I2C_DEFAULT_CLK_DIV - 1));
+	if (priv->speed > MAX_FS_MODE_SPEED) {
+		/* Set master code speed register */
+		ret = mtk_i2c_calculate_speed(clk_src, MAX_FS_MODE_SPEED,
+					      &step_cnt, &sample_cnt);
+		if (ret < 0)
+			goto exit;
+
+		timing_reg = (sample_cnt << TIMING_SAMPLE_OFFSET) | step_cnt;
+		i2c_writel(priv, REG_TIMING, timing_reg);
+		/* Set the high speed mode register */
+		ret = mtk_i2c_calculate_speed(clk_src, priv->speed,
+					      &step_cnt, &sample_cnt);
+		if (ret < 0)
+			goto exit;
+
+		high_speed_reg = I2C_TIME_DEFAULT_VALUE |
+				(sample_cnt << HS_SAMPLE_OFFSET) |
+				(step_cnt << HS_STEP_OFFSET);
+		i2c_writel(priv, REG_HS, high_speed_reg);
+	} else {
+		ret = mtk_i2c_calculate_speed(clk_src, priv->speed,
+					      &step_cnt, &sample_cnt);
+		if (ret < 0)
+			goto exit;
+
+		timing_reg = (sample_cnt << TIMING_SAMPLE_OFFSET) | step_cnt;
+		/* Disable the high speed transaction */
+		high_speed_reg = I2C_TIME_CLR_VALUE;
+		i2c_writel(priv, REG_TIMING, timing_reg);
+		i2c_writel(priv, REG_HS, high_speed_reg);
+	}
+exit:
+	if (mtk_i2c_clk_disable(priv))
+		return log_msg_ret("set_speed disable clk", -1);
+
+	return ret;
+}
+
+/*
+ * mtk_i2c_do_transfer
+ *
+ * @par Description
+ *     Configure i2c register and trigger transfer.
+ * @param[in]
+ *     priv: mtk_i2cmtk_i2c_priv pointer, struct mtk_i2c_priv contains register base\n
+ *     address, operation mode, interrupt status and i2c driver data.
+ * @param[in]
+ *     msgs: i2c_msg pointer, struct i2c_msg contains slave\n
+ *     address, operation mode, msg length and data buffer.
+ * @param[in]
+ *     num: i2c_msg number.
+ * @param[in]
+ *     left_num: left i2c_msg number.
+ * @return
+ *     0, i2c transfer successfully.\n
+ *     -ETIMEDOUT, i2c transfer timeout.\n
+ *     -EREMOTEIO, i2c transfer ack error.
+ */
+static int mtk_i2c_do_transfer(struct mtk_i2c_priv *priv,
+			       struct i2c_msg *msgs,
+			       int num, int left_num)
+{
+	struct i2c_msg *msg_rx = NULL;
+	uint restart_flag = 0;
+	uint trans_error = 0;
+	uint irq_stat = 0;
+	uint tmo_poll = 0;
+	uint control_reg;
+	bool tmo = false;
+	uint start_reg;
+	uint addr_reg;
+	int ret = 0;
+
+	if (priv->auto_restart)
+		restart_flag = I2C_RS_TRANSFER;
+
+	control_reg = i2c_readl(priv, REG_CONTROL) &
+		~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
+
+	if (priv->speed > MAX_FS_MODE_SPEED || num > 1)
+		control_reg |= I2C_CONTROL_RS;
+
+	if (priv->op == I2C_MASTER_WRRD)
+		control_reg |= I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS;
+
+	control_reg |= I2C_CONTROL_DMA_EN;
+	i2c_writel(priv, REG_CONTROL, control_reg);
+
+	/* set start condition */
+	if (priv->speed <= MAX_ST_MODE_SPEED)
+		i2c_writel(priv, REG_EXT_CONF, I2C_ST_START_CON);
+	else
+		i2c_writel(priv, REG_EXT_CONF, I2C_FS_START_CON);
+
+	addr_reg = msgs->addr << 1;
+	if (priv->op == I2C_MASTER_RD)
+		addr_reg |= I2C_M_RD;
+	if (priv->zero_len)
+		i2c_writel(priv, REG_SLAVE_ADDR, addr_reg | TRANS_ADDR_ONLY);
+	else
+		i2c_writel(priv, REG_SLAVE_ADDR, addr_reg);
+
+	/* clear interrupt status */
+	i2c_writel(priv, REG_INTR_STAT, restart_flag | I2C_HS_NACKERR |
+		   I2C_ACKERR | I2C_TRANSAC_COMP);
+	i2c_writel(priv, REG_FIFO_ADDR_CLR, I2C_FIFO_ADDR_CLR);
+
+	/* enable interrupt */
+	i2c_writel(priv, REG_INTR_MASK, restart_flag | I2C_HS_NACKERR |
+		   I2C_ACKERR | I2C_TRANSAC_COMP);
+
+	/* set transfer and transaction len */
+	if (priv->op == I2C_MASTER_WRRD) {
+		i2c_writel(priv, REG_TRANSFER_LEN, msgs->len);
+		i2c_writel(priv, REG_TRANSFER_LEN_AUX, (msgs + 1)->len);
+		i2c_writel(priv, REG_TRANSAC_LEN, I2C_WRRD_TRANAC_VALUE);
+	} else {
+		i2c_writel(priv, REG_TRANSFER_LEN, msgs->len);
+		i2c_writel(priv, REG_TRANSAC_LEN, num);
+	}
+
+	/* Clear DMA interrupt flag */
+	writel(I2C_DMA_INT_FLAG_NONE, priv->pdmabase + REG_INT_FLAG);
+
+	/* Flush cache for first msg */
+	flush_cache((ulong)msgs->buf, msgs->len);
+
+	/*
+	 * prepare buffer data to start transfer
+	 * three cases here: read, write, write then read
+	 */
+	if (priv->op & I2C_MASTER_WR) {
+		/* Set DMA direction TX (w/ or w/o RX) */
+		writel(I2C_DMA_CON_TX, priv->pdmabase + REG_CON);
+
+		/* Write the tx buffer address to dma register */
+		writel((ulong)msgs->buf, priv->pdmabase + REG_TX_MEM_ADDR);
+		/* Write the tx length to dma register */
+		writel(msgs->len, priv->pdmabase + REG_TX_LEN);
+
+		if (priv->op & I2C_MASTER_RD) {
+			/* write then read */
+			msg_rx = msgs + 1;
+
+			/* Flush cache for second msg */
+			flush_cache((ulong)msg_rx->buf, msg_rx->len);
+		}
+	}
+
+	if (priv->op & I2C_MASTER_RD) {
+		if (!msg_rx) {
+			/* Set DMA direction RX */
+			writel(I2C_DMA_CON_RX, priv->pdmabase + REG_CON);
+
+			msg_rx = msgs;
+		}
+
+		/* Write the rx buffer address to dma register */
+		writel((ulong)msg_rx->buf, priv->pdmabase + REG_RX_MEM_ADDR);
+		/* Write the rx length to dma register */
+		writel(msg_rx->len, priv->pdmabase + REG_RX_LEN);
+	}
+
+	writel(I2C_DMA_START_EN, priv->pdmabase + REG_EN);
+
+	if (!priv->auto_restart) {
+		start_reg = I2C_TRANSAC_START;
+	} else {
+		start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
+		if (left_num >= 1)
+			start_reg |= I2C_RS_MUL_CNFG;
+	}
+	i2c_writel(priv, REG_START, start_reg);
+
+	for (;;) {
+		irq_stat = i2c_readl(priv, REG_INTR_STAT);
+
+		/* ignore the first restart irq after the master code */
+		if (priv->ignore_restart_irq && (irq_stat & restart_flag)) {
+			priv->ignore_restart_irq = false;
+			irq_stat = 0;
+			i2c_writel(priv, REG_START, I2C_RS_MUL_CNFG |
+				   I2C_RS_MUL_TRIG | I2C_TRANSAC_START);
+		}
+
+		if (irq_stat & (I2C_TRANSAC_COMP | restart_flag)) {
+			tmo = false;
+			if (irq_stat & (I2C_HS_NACKERR | I2C_ACKERR))
+				trans_error = 1;
+
+			break;
+		}
+		udelay(1);
+		if (tmo_poll++ >= TRANSFER_TIMEOUT) {
+			tmo = true;
+			break;
+		}
+	}
+
+	/* clear interrupt mask */
+	i2c_writel(priv, REG_INTR_MASK, ~(restart_flag | I2C_HS_NACKERR |
+		  I2C_ACKERR | I2C_TRANSAC_COMP));
+
+	if (!tmo && trans_error != 0) {
+		if (tmo) {
+			ret = -ETIMEDOUT;
+			if (!priv->filter_msg)
+				debug("I2C timeout! addr: 0x%x,\n", msgs->addr);
+		} else {
+			ret = -EREMOTEIO;
+			if (!priv->filter_msg)
+				debug("I2C ACKERR! addr: 0x%x,IRQ:0x%x\n",
+				      msgs->addr, irq_stat);
+		}
+		mtk_i2c_init_hw(priv);
+	}
+
+	return ret;
+}
+
+/*
+ * mtk_i2c_transfer
+ *
+ * @par Description
+ *     Common i2c transfer API. Set i2c transfer mode according to i2c_msg\n
+ *     information, then call mtk_i2c_do_transfer() to configure i2c register\n
+ *     and trigger transfer.
+ * @param[in]
+ *     dev: udevice pointer, struct udevice contains struct mtk_i2c_priv, \n
+ *	   struct mtk_i2c_priv contains register base\n
+ *     address, operation mode, interrupt status and i2c driver data.
+ * @param[in]
+ *     msgs: i2c_msg pointer, struct i2c_msg contains slave\n
+ *     address, operation mode, msg length and data buffer.
+ * @param[in]
+ *     num: i2c_msg number.
+ * @return
+ *     i2c_msg number, i2c transfer successfully.\n
+ *     -EINVAL, msg length is more than 16\n
+ *     use DMA MODE or slave address more than 0x7f.\n
+ *     error code from mtk_i2c_init_base().\n
+ *     error code from mtk_i2c_set_speed().\n
+ *     error code from mtk_i2c_do_transfer().
+ */
+static int mtk_i2c_transfer(struct udevice *dev, struct i2c_msg *msg,
+			    int nmsgs)
+{
+	struct mtk_i2c_priv *priv = dev_get_priv(dev);
+	int left_num;
+	uint num_cnt;
+	int ret;
+
+	priv->auto_restart = true;
+	left_num = nmsgs;
+	if (mtk_i2c_clk_enable(priv))
+		return log_msg_ret("transfer enable clk", -1);
+
+	for (num_cnt = 0; num_cnt < nmsgs; num_cnt++) {
+		if (((msg + num_cnt)->addr) > MAX_I2C_ADDR) {
+			ret = -EINVAL;
+			goto err_exit;
+		}
+		if ((msg + num_cnt)->len > MAX_I2C_LEN) {
+			ret = -EINVAL;
+			goto err_exit;
+		}
+	}
+
+	/* check if we can skip restart and optimize using WRRD mode */
+	if (priv->auto_restart && nmsgs == 2) {
+		if (!(msg[0].flags & I2C_M_RD) && (msg[1].flags & I2C_M_RD) &&
+		    msg[0].addr == msg[1].addr) {
+			priv->auto_restart = false;
+		}
+	}
+
+	if (priv->auto_restart && nmsgs >= 2 && priv->speed > MAX_FS_MODE_SPEED)
+		/* ignore the first restart irq after the master code,
+		 * otherwise the first transfer will be discarded.
+		 */
+		priv->ignore_restart_irq = true;
+	else
+		priv->ignore_restart_irq = false;
+
+	while (left_num--) {
+		/* transfer slave address only to support devices detect */
+		if (!msg->buf)
+			priv->zero_len = true;
+		else
+			priv->zero_len = false;
+
+		if (msg->flags & I2C_M_RD)
+			priv->op = I2C_MASTER_RD;
+		else
+			priv->op = I2C_MASTER_WR;
+
+		if (!priv->auto_restart) {
+			if (nmsgs > 1) {
+				/* combined two messages into one transaction */
+				priv->op = I2C_MASTER_WRRD;
+				left_num--;
+			}
+		}
+		ret = mtk_i2c_do_transfer(priv, msg, nmsgs, left_num);
+		if (ret < 0)
+			goto err_exit;
+		msg++;
+	}
+	ret = 0;
+
+err_exit:
+	if (mtk_i2c_clk_disable(priv))
+		return log_msg_ret("transfer disable clk", -1);
+
+	return ret;
+}
+
+static int mtk_i2c_of_to_plat(struct udevice *dev)
+{
+	struct mtk_i2c_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->base = dev_remap_addr_index(dev, 0);
+	priv->pdmabase = dev_remap_addr_index(dev, 1);
+	ret = clk_get_by_index(dev, 0, &priv->clk_main);
+	if (ret)
+		return log_msg_ret("clk_get_by_index 0", ret);
+
+	ret = clk_get_by_index(dev, 1, &priv->clk_dma);
+
+	return ret;
+}
+
+static int mtk_i2c_probe(struct udevice *dev)
+{
+	struct mtk_i2c_priv *priv = dev_get_priv(dev);
+
+	priv->soc_data = (struct mtk_i2c_soc_data *)dev_get_driver_data(dev);
+
+	if (mtk_i2c_clk_enable(priv))
+		return log_msg_ret("probe enable clk", -1);
+
+	mtk_i2c_init_hw(priv);
+
+	if (mtk_i2c_clk_disable(priv))
+		return log_msg_ret("probe disable clk", -1);
+
+	return 0;
+}
+
+static int mtk_i2c_deblock(struct udevice *dev)
+{
+	struct mtk_i2c_priv *priv = dev_get_priv(dev);
+
+	if (mtk_i2c_clk_enable(priv))
+		return log_msg_ret("deblock enable clk", -1);
+
+	mtk_i2c_init_hw(priv);
+
+	if (mtk_i2c_clk_disable(priv))
+		return log_msg_ret("deblock disable clk", -1);
+
+	return 0;
+}
+
+static const struct mtk_i2c_soc_data mt76xx_soc_data = {
+	.regs = mt_i2c_regs_v1,
+	.dma_sync = 0,
+};
+
+static const struct mtk_i2c_soc_data mt7981_soc_data = {
+	.regs = mt_i2c_regs_v1,
+	.dma_sync = 1,
+};
+
+static const struct mtk_i2c_soc_data mt7986_soc_data = {
+	.regs = mt_i2c_regs_v1,
+	.dma_sync = 1,
+};
+
+static const struct mtk_i2c_soc_data mt8183_soc_data = {
+	.regs = mt_i2c_regs_v2,
+	.dma_sync = 1,
+};
+
+static const struct mtk_i2c_soc_data mt8518_soc_data = {
+	.regs = mt_i2c_regs_v1,
+	.dma_sync = 0,
+};
+
+static const struct mtk_i2c_soc_data mt8512_soc_data = {
+	.regs = mt_i2c_regs_v1,
+	.dma_sync = 1,
+};
+
+static const struct dm_i2c_ops mtk_i2c_ops = {
+	.xfer		= mtk_i2c_transfer,
+	.set_bus_speed	= mtk_i2c_set_speed,
+	.deblock	= mtk_i2c_deblock,
+};
+
+static const struct udevice_id mtk_i2c_ids[] = {
+	{
+		.compatible = "mediatek,mt7622-i2c",
+		.data = (ulong)&mt76xx_soc_data,
+	}, {
+		.compatible = "mediatek,mt7623-i2c",
+		.data = (ulong)&mt76xx_soc_data,
+	}, {
+		.compatible = "mediatek,mt7629-i2c",
+		.data = (ulong)&mt76xx_soc_data,
+	}, {
+		.compatible = "mediatek,mt7981-i2c",
+		.data = (ulong)&mt7981_soc_data,
+	}, {
+		.compatible = "mediatek,mt7986-i2c",
+		.data = (ulong)&mt7986_soc_data,
+	}, {
+		.compatible = "mediatek,mt8183-i2c",
+		.data = (ulong)&mt8183_soc_data,
+	}, {
+		.compatible = "mediatek,mt8512-i2c",
+		.data = (ulong)&mt8512_soc_data,
+	}, {
+		.compatible = "mediatek,mt8518-i2c",
+		.data = (ulong)&mt8518_soc_data,
+	}
+};
+
+U_BOOT_DRIVER(mtk_i2c) = {
+	.name		= "mtk_i2c",
+	.id		= UCLASS_I2C,
+	.of_match	= mtk_i2c_ids,
+	.of_to_plat	= mtk_i2c_of_to_plat,
+	.probe		= mtk_i2c_probe,
+	.priv_auto	= sizeof(struct mtk_i2c_priv),
+	.ops		= &mtk_i2c_ops,
+};
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index b1bd4ae..759a6b7 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -472,7 +472,7 @@
 
 	ret = mmc_switch_part(mmc, hwpart);
 	if (!ret)
-		blkcache_invalidate(desc->if_type, desc->devnum);
+		blkcache_invalidate(desc->uclass_id, desc->devnum);
 
 	return ret;
 }
diff --git a/drivers/mmc/mmc_legacy.c b/drivers/mmc/mmc_legacy.c
index 4e0891e..a101ee4 100644
--- a/drivers/mmc/mmc_legacy.c
+++ b/drivers/mmc/mmc_legacy.c
@@ -132,7 +132,7 @@
 	.dsr_imp		= 0,
 	.dsr			= 0xffffffff,
 	.block_dev = {
-		.if_type	= UCLASS_MMC,
+		.uclass_id	= UCLASS_MMC,
 		.removable	= 1,
 		.devnum		= 0,
 		.block_read	= mmc_bread,
@@ -194,7 +194,7 @@
 	mmc->dsr = 0xffffffff;
 	/* Setup the universal parts of the block interface just once */
 	bdesc = mmc_get_blk_desc(mmc);
-	bdesc->if_type = UCLASS_MMC;
+	bdesc->uclass_id = UCLASS_MMC;
 	bdesc->removable = 1;
 	bdesc->devnum = mmc_get_next_devnum();
 	bdesc->block_read = mmc_bread;
@@ -253,8 +253,8 @@
 }
 
 U_BOOT_LEGACY_BLK(mmc) = {
-	.if_typename	= "mmc",
-	.if_type	= UCLASS_MMC,
+	.uclass_idname	= "mmc",
+	.uclass_id	= UCLASS_MMC,
 	.max_devs	= -1,
 	.get_dev	= mmc_get_dev,
 	.select_hwpart	= mmc_select_hwpartp,
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
index e61e8cf..b206b0a 100644
--- a/drivers/mmc/mtk-sd.c
+++ b/drivers/mmc/mtk-sd.c
@@ -1496,7 +1496,12 @@
 	/* Enable data & cmd interrupts */
 	writel(DATA_INTS_MASK | CMD_INTS_MASK, &host->base->msdc_inten);
 
-	writel(0, tune_reg);
+	if (host->top_base) {
+		writel(0, &host->top_base->emmc_top_control);
+		writel(0, &host->top_base->emmc_top_cmd);
+	} else {
+		writel(0, tune_reg);
+	}
 	writel(0, &host->base->msdc_iocon);
 
 	if (host->r_smpl)
@@ -1507,9 +1512,14 @@
 	writel(0x403c0046, &host->base->patch_bit0);
 	writel(0xffff4089, &host->base->patch_bit1);
 
-	if (host->dev_comp->stop_clk_fix)
+	if (host->dev_comp->stop_clk_fix) {
 		clrsetbits_le32(&host->base->patch_bit1, MSDC_PB1_STOP_DLY_M,
 				3 << MSDC_PB1_STOP_DLY_S);
+		clrbits_le32(&host->base->sdc_fifo_cfg,
+			     SDC_FIFO_CFG_WRVALIDSEL);
+		clrbits_le32(&host->base->sdc_fifo_cfg,
+			     SDC_FIFO_CFG_RDVALIDSEL);
+	}
 
 	if (host->dev_comp->busy_check)
 		clrbits_le32(&host->base->patch_bit1, (1 << 7));
@@ -1544,15 +1554,28 @@
 	}
 
 	if (host->dev_comp->data_tune) {
-		setbits_le32(tune_reg,
-			     MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL);
-		clrsetbits_le32(&host->base->patch_bit0,
-				MSDC_INT_DAT_LATCH_CK_SEL_M,
-				host->latch_ck <<
-				MSDC_INT_DAT_LATCH_CK_SEL_S);
+		if (host->top_base) {
+			setbits_le32(&host->top_base->emmc_top_control,
+				     PAD_DAT_RD_RXDLY_SEL);
+			clrbits_le32(&host->top_base->emmc_top_control,
+				     DATA_K_VALUE_SEL);
+			setbits_le32(&host->top_base->emmc_top_cmd,
+				     PAD_CMD_RD_RXDLY_SEL);
+		} else {
+			setbits_le32(tune_reg,
+				     MSDC_PAD_TUNE_RD_SEL | MSDC_PAD_TUNE_CMD_SEL);
+			clrsetbits_le32(&host->base->patch_bit0,
+					MSDC_INT_DAT_LATCH_CK_SEL_M,
+					host->latch_ck <<
+					MSDC_INT_DAT_LATCH_CK_SEL_S);
+		}
 	} else {
 		/* choose clock tune */
-		setbits_le32(tune_reg, MSDC_PAD_TUNE_RXDLYSEL);
+		if (host->top_base)
+			setbits_le32(&host->top_base->emmc_top_control,
+				     PAD_RXDLY_SEL);
+		else
+			setbits_le32(tune_reg, MSDC_PAD_TUNE_RXDLYSEL);
 	}
 
 	if (host->dev_comp->builtin_pad_ctrl) {
@@ -1604,12 +1627,6 @@
 	clrsetbits_le32(&host->base->sdc_cfg, SDC_CFG_DTOC_M,
 			3 << SDC_CFG_DTOC_S);
 
-	if (host->dev_comp->stop_clk_fix) {
-		clrbits_le32(&host->base->sdc_fifo_cfg,
-			     SDC_FIFO_CFG_WRVALIDSEL);
-		clrbits_le32(&host->base->sdc_fifo_cfg,
-			     SDC_FIFO_CFG_RDVALIDSEL);
-	}
 
 	host->def_tune_para.iocon = readl(&host->base->msdc_iocon);
 	host->def_tune_para.pad_tune = readl(&host->base->pad_tune);
@@ -1792,6 +1809,25 @@
 	.enhance_rx = false
 };
 
+static const struct msdc_compatible mt7986_compat = {
+	.clk_div_bits = 12,
+	.pad_tune0 = true,
+	.async_fifo = true,
+	.data_tune = true,
+	.busy_check = true,
+	.stop_clk_fix = true,
+	.enhance_rx = true,
+};
+
+static const struct msdc_compatible mt7981_compat = {
+	.clk_div_bits = 12,
+	.pad_tune0 = true,
+	.async_fifo = true,
+	.data_tune = true,
+	.busy_check = true,
+	.stop_clk_fix = true,
+};
+
 static const struct msdc_compatible mt8512_compat = {
 	.clk_div_bits = 12,
 	.pad_tune0 = true,
@@ -1824,6 +1860,8 @@
 	{ .compatible = "mediatek,mt7621-mmc", .data = (ulong)&mt7621_compat },
 	{ .compatible = "mediatek,mt7622-mmc", .data = (ulong)&mt7622_compat },
 	{ .compatible = "mediatek,mt7623-mmc", .data = (ulong)&mt7623_compat },
+	{ .compatible = "mediatek,mt7986-mmc", .data = (ulong)&mt7986_compat },
+	{ .compatible = "mediatek,mt7981-mmc", .data = (ulong)&mt7981_compat },
 	{ .compatible = "mediatek,mt8512-mmc", .data = (ulong)&mt8512_compat },
 	{ .compatible = "mediatek,mt8516-mmc", .data = (ulong)&mt8516_compat },
 	{ .compatible = "mediatek,mt8183-mmc", .data = (ulong)&mt8183_compat },
diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
index 835e5bd..d43a85b 100644
--- a/drivers/net/fsl_enetc.c
+++ b/drivers/net/fsl_enetc.c
@@ -146,7 +146,7 @@
 	if (!enetc_has_imdio(dev))
 		return 0;
 
-	if (priv->if_type == PHY_INTERFACE_MODE_2500BASEX)
+	if (priv->uclass_id == PHY_INTERFACE_MODE_2500BASEX)
 		is2500 = true;
 
 	/*
@@ -221,7 +221,7 @@
 	struct enetc_priv *priv = dev_get_priv(dev);
 	u32 if_mode;
 
-	switch (priv->if_type) {
+	switch (priv->uclass_id) {
 	case PHY_INTERFACE_MODE_RGMII:
 	case PHY_INTERFACE_MODE_RGMII_ID:
 	case PHY_INTERFACE_MODE_RGMII_RXID:
@@ -278,14 +278,14 @@
 		return;
 	}
 
-	priv->if_type = dev_read_phy_mode(dev);
-	if (priv->if_type == PHY_INTERFACE_MODE_NA) {
+	priv->uclass_id = dev_read_phy_mode(dev);
+	if (priv->uclass_id == PHY_INTERFACE_MODE_NA) {
 		enetc_dbg(dev,
 			  "phy-mode property not found, defaulting to SGMII\n");
-		priv->if_type = PHY_INTERFACE_MODE_SGMII;
+		priv->uclass_id = PHY_INTERFACE_MODE_SGMII;
 	}
 
-	switch (priv->if_type) {
+	switch (priv->uclass_id) {
 	case PHY_INTERFACE_MODE_SGMII:
 	case PHY_INTERFACE_MODE_2500BASEX:
 		enetc_init_sgmii(dev);
diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h
index 69f2f4a..f2acf36 100644
--- a/drivers/net/fsl_enetc.h
+++ b/drivers/net/fsl_enetc.h
@@ -158,7 +158,7 @@
 	struct bd_ring tx_bdr;
 	struct bd_ring rx_bdr;
 
-	int if_type;
+	int uclass_id;
 	struct mii_dev imdio;
 	struct phy_device *phy;
 };
diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c
index 4fe7ee0..4c9fb26 100644
--- a/drivers/net/mtk_eth.c
+++ b/drivers/net/mtk_eth.c
@@ -65,95 +65,34 @@
 	(DP_DISCARD << MC_DP_S) | \
 	(DP_DISCARD << UN_DP_S))
 
-struct pdma_rxd_info1 {
-	u32 PDP0;
-};
-
-struct pdma_rxd_info2 {
-	u32 PLEN1 : 14;
-	u32 LS1 : 1;
-	u32 UN_USED : 1;
-	u32 PLEN0 : 14;
-	u32 LS0 : 1;
-	u32 DDONE : 1;
-};
-
-struct pdma_rxd_info3 {
-	u32 PDP1;
-};
-
-struct pdma_rxd_info4 {
-	u32 FOE_ENTRY : 14;
-	u32 CRSN : 5;
-	u32 SP : 3;
-	u32 L4F : 1;
-	u32 L4VLD : 1;
-	u32 TACK : 1;
-	u32 IP4F : 1;
-	u32 IP4 : 1;
-	u32 IP6 : 1;
-	u32 UN_USED : 4;
-};
-
-struct pdma_rxdesc {
-	struct pdma_rxd_info1 rxd_info1;
-	struct pdma_rxd_info2 rxd_info2;
-	struct pdma_rxd_info3 rxd_info3;
-	struct pdma_rxd_info4 rxd_info4;
-};
-
-struct pdma_txd_info1 {
-	u32 SDP0;
-};
-
-struct pdma_txd_info2 {
-	u32 SDL1 : 14;
-	u32 LS1 : 1;
-	u32 BURST : 1;
-	u32 SDL0 : 14;
-	u32 LS0 : 1;
-	u32 DDONE : 1;
-};
-
-struct pdma_txd_info3 {
-	u32 SDP1;
-};
-
-struct pdma_txd_info4 {
-	u32 VLAN_TAG : 16;
-	u32 INS : 1;
-	u32 RESV : 2;
-	u32 UDF : 6;
-	u32 FPORT : 3;
-	u32 TSO : 1;
-	u32 TUI_CO : 3;
-};
-
-struct pdma_txdesc {
-	struct pdma_txd_info1 txd_info1;
-	struct pdma_txd_info2 txd_info2;
-	struct pdma_txd_info3 txd_info3;
-	struct pdma_txd_info4 txd_info4;
-};
-
 enum mtk_switch {
 	SW_NONE,
 	SW_MT7530,
 	SW_MT7531
 };
 
-enum mtk_soc {
-	SOC_MT7623,
-	SOC_MT7629,
-	SOC_MT7622,
-	SOC_MT7621
+/* struct mtk_soc_data -	This is the structure holding all differences
+ *				among various plaforms
+ * @caps			Flags shown the extra capability for the SoC
+ * @ana_rgc3:			The offset for register ANA_RGC3 related to
+ *				sgmiisys syscon
+ * @pdma_base:			Register base of PDMA block
+ * @txd_size:			Tx DMA descriptor size.
+ * @rxd_size:			Rx DMA descriptor size.
+ */
+struct mtk_soc_data {
+	u32 caps;
+	u32 ana_rgc3;
+	u32 pdma_base;
+	u32 txd_size;
+	u32 rxd_size;
 };
 
 struct mtk_eth_priv {
 	char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
 
-	struct pdma_txdesc *tx_ring_noc;
-	struct pdma_rxdesc *rx_ring_noc;
+	void *tx_ring_noc;
+	void *rx_ring_noc;
 
 	int rx_dma_owner_idx0;
 	int tx_cpu_owner_idx0;
@@ -171,11 +110,12 @@
 	int (*mmd_write)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
 			 u16 val);
 
-	enum mtk_soc soc;
+	const struct mtk_soc_data *soc;
 	int gmac_id;
 	int force_mode;
 	int speed;
 	int duplex;
+	bool pn_swap;
 
 	struct phy_device *phydev;
 	int phy_interface;
@@ -195,13 +135,13 @@
 
 static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
 {
-	writel(val, priv->fe_base + PDMA_BASE + reg);
+	writel(val, priv->fe_base + priv->soc->pdma_base + reg);
 }
 
 static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
 			 u32 set)
 {
-	clrsetbits_le32(priv->fe_base + PDMA_BASE + reg, clr, set);
+	clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set);
 }
 
 static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg,
@@ -679,7 +619,7 @@
 	u32 val, txdrv;
 	int i;
 
-	if (priv->soc != SOC_MT7621) {
+	if (!MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
 		/* Select 250MHz clk for RGMII mode */
 		mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG,
 			       ETHSYS_TRGMII_CLK_SEL362_5, 0);
@@ -1108,9 +1048,8 @@
 static void mtk_sgmii_init(struct mtk_eth_priv *priv)
 {
 	/* Set SGMII GEN2 speed(2.5G) */
-	clrsetbits_le32(priv->sgmii_base + ((priv->soc == SOC_MT7622) ?
-			SGMSYS_GEN2_SPEED : SGMSYS_GEN2_SPEED_V2),
-			SGMSYS_SPEED_2500, SGMSYS_SPEED_2500);
+	setbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
+		     SGMSYS_SPEED_2500);
 
 	/* Disable SGMII AN */
 	clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
@@ -1119,6 +1058,12 @@
 	/* SGMII force mode setting */
 	writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
 
+	/* SGMII PN SWAP setting */
+	if (priv->pn_swap) {
+		setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
+			     SGMII_PN_SWAP_TX_RX);
+	}
+
 	/* Release PHYA power down state */
 	clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
 			SGMII_PHYA_PWD, 0);
@@ -1182,7 +1127,8 @@
 		mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
 	}
 
-	if (priv->soc == SOC_MT7623) {
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) &&
+	    !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
 		/* Lower Tx Driving for TRGMII path */
 		for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
 			mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i),
@@ -1198,14 +1144,16 @@
 static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
 {
 	char *pkt_base = priv->pkt_pool;
+	struct mtk_tx_dma_v2 *txd;
+	struct mtk_rx_dma_v2 *rxd;
 	int i;
 
 	mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0);
 	udelay(500);
 
-	memset(priv->tx_ring_noc, 0, NUM_TX_DESC * sizeof(struct pdma_txdesc));
-	memset(priv->rx_ring_noc, 0, NUM_RX_DESC * sizeof(struct pdma_rxdesc));
-	memset(priv->pkt_pool, 0, TOTAL_PKT_BUF_SIZE);
+	memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size);
+	memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size);
+	memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE);
 
 	flush_dcache_range((ulong)pkt_base,
 			   (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE));
@@ -1214,17 +1162,29 @@
 	priv->tx_cpu_owner_idx0 = 0;
 
 	for (i = 0; i < NUM_TX_DESC; i++) {
-		priv->tx_ring_noc[i].txd_info2.LS0 = 1;
-		priv->tx_ring_noc[i].txd_info2.DDONE = 1;
-		priv->tx_ring_noc[i].txd_info4.FPORT = priv->gmac_id + 1;
+		txd = priv->tx_ring_noc + i * priv->soc->txd_size;
+
+		txd->txd1 = virt_to_phys(pkt_base);
+		txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0;
 
-		priv->tx_ring_noc[i].txd_info1.SDP0 = virt_to_phys(pkt_base);
+		if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
+			txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1);
+		else
+			txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1);
+
 		pkt_base += PKTSIZE_ALIGN;
 	}
 
 	for (i = 0; i < NUM_RX_DESC; i++) {
-		priv->rx_ring_noc[i].rxd_info2.PLEN0 = PKTSIZE_ALIGN;
-		priv->rx_ring_noc[i].rxd_info1.PDP0 = virt_to_phys(pkt_base);
+		rxd = priv->rx_ring_noc + i * priv->soc->rxd_size;
+
+		rxd->rxd1 = virt_to_phys(pkt_base);
+
+		if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
+			rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+		else
+			rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+
 		pkt_base += PKTSIZE_ALIGN;
 	}
 
@@ -1252,6 +1212,9 @@
 	reset_deassert(&priv->rst_fe);
 	mdelay(10);
 
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
+		setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2);
+
 	/* Packets forward to PDMA */
 	mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU);
 
@@ -1286,7 +1249,7 @@
 		     TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0);
 	udelay(500);
 
-	wait_for_bit_le32(priv->fe_base + PDMA_BASE + PDMA_GLO_CFG_REG,
+	wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG,
 			  RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0);
 }
 
@@ -1311,20 +1274,25 @@
 {
 	struct mtk_eth_priv *priv = dev_get_priv(dev);
 	u32 idx = priv->tx_cpu_owner_idx0;
+	struct mtk_tx_dma_v2 *txd;
 	void *pkt_base;
 
-	if (!priv->tx_ring_noc[idx].txd_info2.DDONE) {
+	txd = priv->tx_ring_noc + idx * priv->soc->txd_size;
+
+	if (!(txd->txd2 & PDMA_TXD2_DDONE)) {
 		debug("mtk-eth: TX DMA descriptor ring is full\n");
 		return -EPERM;
 	}
 
-	pkt_base = (void *)phys_to_virt(priv->tx_ring_noc[idx].txd_info1.SDP0);
+	pkt_base = (void *)phys_to_virt(txd->txd1);
 	memcpy(pkt_base, packet, length);
 	flush_dcache_range((ulong)pkt_base, (ulong)pkt_base +
 			   roundup(length, ARCH_DMA_MINALIGN));
 
-	priv->tx_ring_noc[idx].txd_info2.SDL0 = length;
-	priv->tx_ring_noc[idx].txd_info2.DDONE = 0;
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
+		txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length);
+	else
+		txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length);
 
 	priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC;
 	mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
@@ -1336,16 +1304,23 @@
 {
 	struct mtk_eth_priv *priv = dev_get_priv(dev);
 	u32 idx = priv->rx_dma_owner_idx0;
+	struct mtk_rx_dma_v2 *rxd;
 	uchar *pkt_base;
 	u32 length;
 
-	if (!priv->rx_ring_noc[idx].rxd_info2.DDONE) {
+	rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
+
+	if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) {
 		debug("mtk-eth: RX DMA descriptor ring is empty\n");
 		return -EAGAIN;
 	}
 
-	length = priv->rx_ring_noc[idx].rxd_info2.PLEN0;
-	pkt_base = (void *)phys_to_virt(priv->rx_ring_noc[idx].rxd_info1.PDP0);
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
+		length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2);
+	else
+		length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2);
+
+	pkt_base = (void *)phys_to_virt(rxd->rxd1);
 	invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base +
 				roundup(length, ARCH_DMA_MINALIGN));
 
@@ -1359,10 +1334,14 @@
 {
 	struct mtk_eth_priv *priv = dev_get_priv(dev);
 	u32 idx = priv->rx_dma_owner_idx0;
+	struct mtk_rx_dma_v2 *rxd;
+
+	rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
 
-	priv->rx_ring_noc[idx].rxd_info2.DDONE = 0;
-	priv->rx_ring_noc[idx].rxd_info2.LS0 = 0;
-	priv->rx_ring_noc[idx].rxd_info2.PLEN0 = PKTSIZE_ALIGN;
+	if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
+		rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
+	else
+		rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
 
 	mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx);
 	priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC;
@@ -1389,11 +1368,11 @@
 		return ret;
 
 	/* Prepare for tx/rx rings */
-	priv->tx_ring_noc = (struct pdma_txdesc *)
-		noncached_alloc(sizeof(struct pdma_txdesc) * NUM_TX_DESC,
+	priv->tx_ring_noc = (void *)
+		noncached_alloc(priv->soc->txd_size * NUM_TX_DESC,
 				ARCH_DMA_MINALIGN);
-	priv->rx_ring_noc = (struct pdma_rxdesc *)
-		noncached_alloc(sizeof(struct pdma_rxdesc) * NUM_RX_DESC,
+	priv->rx_ring_noc = (void *)
+		noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC,
 				ARCH_DMA_MINALIGN);
 
 	/* Set MAC mode */
@@ -1431,7 +1410,11 @@
 	ofnode subnode;
 	int ret;
 
-	priv->soc = dev_get_driver_data(dev);
+	priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev);
+	if (!priv->soc) {
+		dev_err(dev, "missing soc compatible data\n");
+		return -EINVAL;
+	}
 
 	pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
 
@@ -1494,6 +1477,8 @@
 			dev_err(dev, "Unable to find sgmii\n");
 			return -ENODEV;
 		}
+
+		priv->pn_swap = ofnode_read_bool(args.node, "pn_swap");
 	}
 
 	/* check for switch first, otherwise phy will be used */
@@ -1544,11 +1529,57 @@
 	return 0;
 }
 
+static const struct mtk_soc_data mt7986_data = {
+	.caps = MT7986_CAPS,
+	.ana_rgc3 = 0x128,
+	.pdma_base = PDMA_V2_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma_v2),
+	.rxd_size = sizeof(struct mtk_rx_dma_v2),
+};
+
+static const struct mtk_soc_data mt7981_data = {
+	.caps = MT7986_CAPS,
+	.ana_rgc3 = 0x128,
+	.pdma_base = PDMA_V2_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma_v2),
+	.rxd_size = sizeof(struct mtk_rx_dma_v2),
+};
+
+static const struct mtk_soc_data mt7629_data = {
+	.ana_rgc3 = 0x128,
+	.pdma_base = PDMA_V1_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma),
+	.rxd_size = sizeof(struct mtk_rx_dma),
+};
+
+static const struct mtk_soc_data mt7623_data = {
+	.caps = MT7623_CAPS,
+	.pdma_base = PDMA_V1_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma),
+	.rxd_size = sizeof(struct mtk_rx_dma),
+};
+
+static const struct mtk_soc_data mt7622_data = {
+	.ana_rgc3 = 0x2028,
+	.pdma_base = PDMA_V1_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma),
+	.rxd_size = sizeof(struct mtk_rx_dma),
+};
+
+static const struct mtk_soc_data mt7621_data = {
+	.caps = MT7621_CAPS,
+	.pdma_base = PDMA_V1_BASE,
+	.txd_size = sizeof(struct mtk_tx_dma),
+	.rxd_size = sizeof(struct mtk_rx_dma),
+};
+
 static const struct udevice_id mtk_eth_ids[] = {
-	{ .compatible = "mediatek,mt7629-eth", .data = SOC_MT7629 },
-	{ .compatible = "mediatek,mt7623-eth", .data = SOC_MT7623 },
-	{ .compatible = "mediatek,mt7622-eth", .data = SOC_MT7622 },
-	{ .compatible = "mediatek,mt7621-eth", .data = SOC_MT7621 },
+	{ .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data },
+	{ .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data },
+	{ .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data },
+	{ .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data },
+	{ .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data },
+	{ .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data },
 	{}
 };
 
diff --git a/drivers/net/mtk_eth.h b/drivers/net/mtk_eth.h
index 057ecfa..1382ccb 100644
--- a/drivers/net/mtk_eth.h
+++ b/drivers/net/mtk_eth.h
@@ -9,9 +9,38 @@
 #ifndef _MTK_ETH_H_
 #define _MTK_ETH_H_
 
-/* Frame Engine Register Bases */
 #include <linux/bitops.h>
-#define PDMA_BASE			0x0800
+#include <linux/bitfield.h>
+
+enum mkt_eth_capabilities {
+	MTK_TRGMII_BIT,
+	MTK_TRGMII_MT7621_CLK_BIT,
+	MTK_NETSYS_V2_BIT,
+
+	/* PATH BITS */
+	MTK_ETH_PATH_GMAC1_TRGMII_BIT,
+};
+
+#define MTK_TRGMII			BIT(MTK_TRGMII_BIT)
+#define MTK_TRGMII_MT7621_CLK		BIT(MTK_TRGMII_MT7621_CLK_BIT)
+#define MTK_NETSYS_V2			BIT(MTK_NETSYS_V2_BIT)
+
+/* Supported path present on SoCs */
+#define MTK_ETH_PATH_GMAC1_TRGMII	BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
+
+#define MTK_GMAC1_TRGMII	(MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
+
+#define MTK_HAS_CAPS(caps, _x)		(((caps) & (_x)) == (_x))
+
+#define MT7621_CAPS  (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK)
+
+#define MT7623_CAPS  (MTK_GMAC1_TRGMII)
+
+#define MT7986_CAPS  (MTK_NETSYS_V2)
+
+/* Frame Engine Register Bases */
+#define PDMA_V1_BASE			0x0800
+#define PDMA_V2_BASE			0x6000
 #define GDMA1_BASE			0x0500
 #define GDMA2_BASE			0x1500
 #define GMAC_BASE			0x10000
@@ -45,11 +74,16 @@
 #define SGMSYS_QPHY_PWR_STATE_CTRL	0xe8
 #define SGMII_PHYA_PWD			BIT(4)
 
+#define SGMSYS_QPHY_WRAP_CTRL		0xec
+#define SGMII_PN_SWAP_TX_RX		0x03
+
 #define SGMSYS_GEN2_SPEED		0x2028
 #define SGMSYS_GEN2_SPEED_V2		0x128
 #define SGMSYS_SPEED_2500		BIT(2)
 
 /* Frame Engine Registers */
+#define FE_GLO_MISC_REG			0x124
+#define PDMA_VER_V2			BIT(4)
 
 /* PDMA */
 #define TX_BASE_PTR_REG(n)		(0x000 + (n) * 0x10)
@@ -412,4 +446,67 @@
 #define PHY_POWER_SAVING_M		0x300
 #define PHY_POWER_SAVING_TX		0x0
 
+/* PDMA descriptors */
+struct mtk_rx_dma {
+	unsigned int rxd1;
+	unsigned int rxd2;
+	unsigned int rxd3;
+	unsigned int rxd4;
+} __packed __aligned(4);
+
+struct mtk_rx_dma_v2 {
+	unsigned int rxd1;
+	unsigned int rxd2;
+	unsigned int rxd3;
+	unsigned int rxd4;
+	unsigned int rxd5;
+	unsigned int rxd6;
+	unsigned int rxd7;
+	unsigned int rxd8;
+} __packed __aligned(4);
+
+struct mtk_tx_dma {
+	unsigned int txd1;
+	unsigned int txd2;
+	unsigned int txd3;
+	unsigned int txd4;
+} __packed __aligned(4);
+
+struct mtk_tx_dma_v2 {
+	unsigned int txd1;
+	unsigned int txd2;
+	unsigned int txd3;
+	unsigned int txd4;
+	unsigned int txd5;
+	unsigned int txd6;
+	unsigned int txd7;
+	unsigned int txd8;
+} __packed __aligned(4);
+
+/* PDMA TXD fields */
+#define PDMA_TXD2_DDONE			BIT(31)
+#define PDMA_TXD2_LS0			BIT(30)
+#define PDMA_V1_TXD2_SDL0_M		GENMASK(29, 16)
+#define PDMA_V1_TXD2_SDL0_SET(_v)	FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v))
+#define PDMA_V2_TXD2_SDL0_M		GENMASK(23, 8)
+#define PDMA_V2_TXD2_SDL0_SET(_v)	FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v))
+
+#define PDMA_V1_TXD4_FPORT_M		GENMASK(27, 25)
+#define PDMA_V1_TXD4_FPORT_SET(_v)	FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v))
+#define PDMA_V2_TXD4_FPORT_M		GENMASK(27, 24)
+#define PDMA_V2_TXD4_FPORT_SET(_v)	FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v))
+
+#define PDMA_V2_TXD5_FPORT_M		GENMASK(19, 16)
+#define PDMA_V2_TXD5_FPORT_SET(_v)	FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v))
+
+/* PDMA RXD fields */
+#define PDMA_RXD2_DDONE			BIT(31)
+#define PDMA_RXD2_LS0			BIT(30)
+#define PDMA_V1_RXD2_PLEN0_M		GENMASK(29, 16)
+#define PDMA_V1_RXD2_PLEN0_GET(_v)	FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v))
+#define PDMA_V1_RXD2_PLEN0_SET(_v)	FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v))
+#define PDMA_V2_RXD2_PLEN0_M		GENMASK(23, 8)
+#define PDMA_V2_RXD2_PLEN0_GET(_v)	FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v))
+#define PDMA_V2_RXD2_PLEN0_SET(_v)	FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v))
+
 #endif /* _MTK_ETH_H_ */
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 58df508..27e8998 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -16,6 +16,14 @@
 	bool "MT7629 SoC pinctrl driver"
 	select PINCTRL_MTK
 
+config PINCTRL_MT7981
+	bool "MT7981 SoC pinctrl driver"
+	select PINCTRL_MTK
+
+config PINCTRL_MT7986
+	bool "MT7986 SoC pinctrl driver"
+	select PINCTRL_MTK
+
 config PINCTRL_MT8512
 	bool "MT8512 SoC pinctrl driver"
 	select PINCTRL_MTK
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index d7e8cf1..6e73375 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -6,6 +6,8 @@
 obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o
 obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o
 obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o
+obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o
+obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o
 obj-$(CONFIG_PINCTRL_MT8512) += pinctrl-mt8512.o
 obj-$(CONFIG_PINCTRL_MT8516) += pinctrl-mt8516.o
 obj-$(CONFIG_PINCTRL_MT8518) += pinctrl-mt8518.o
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
new file mode 100644
index 0000000..d887524
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
@@ -0,0 +1,1049 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The MT7981 driver based on Linux generic pinctrl binding.
+ *
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include <dm.h>
+#include "pinctrl-mtk-common.h"
+
+#define MT7981_TYPE0_PIN(_number, _name)	\
+	MTK_TYPED_PIN(_number, _name, DRV_GRP4, IO_TYPE_GRP0)
+
+#define MT7981_TYPE1_PIN(_number, _name)	\
+	MTK_TYPED_PIN(_number, _name, DRV_GRP4, IO_TYPE_GRP1)
+
+#define PIN_FIELD_GPIO(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_BASE_CALC(_s_pin, _e_pin, GPIO_BASE, _s_addr, _x_addrs,	\
+			    _s_bit, _x_bits, 32, 0)
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,	\
+		       _x_bits)							\
+	PIN_FIELD_BASE_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,	\
+	_x_bits, 32, 0)
+
+/**
+ * enum - Locking variants of the iocfg bases
+ *
+ * MT7981 have multiple bases to program pin configuration listed as the below:
+ * iocfg_rt:0x11c00000, iocfg_rm:0x11c10000, iocfg_rb:0x11d20000,
+ * iocfg_lb:0x11e00000, iocfg_bl:0x11e20000, iocfg_tm:0x11f00000,
+ * iocfg_tl:0x11f10000,
+ * _i_based could be used to indicate what base the pin should be mapped into.
+ *
+ * Each iocfg register base control different group of pads on the SoC
+ *
+ *
+ *  chip carrier
+ *
+ *      A  B  C  D  E  F  G  H
+ *    +------------------------+
+ *  8 | o  o  o  o  o  o  o  o |
+ *  7 | o  o  o  o  o  o  o  o |
+ *  6 | o  o  o  o  o  o  o  o |
+ *  5 | o  o  o  o  o  o  o  o |
+ *  4 | o  o  o  o  o  o  o  o |
+ *  3 | o  o  o  o  o  o  o  o |
+ *  2 | o  o  o  o  o  o  o  o |
+ *  1 | o  o  o  o  o  o  o  o |
+ *    +------------------------+
+ *
+ *  inside Chip carrier
+ *
+ *      A  B  C  D  E  F  G  H
+ *    +------------------------+
+ *  8 |                        |
+ *  7 |       TL TM            |
+ *  6 |      +---------+       |
+ *  5 |      |         | RT    |
+ *  4 |      |         | RM    |
+ *  3 |   LB |         | RB    |
+ *  2 |      +---------+       |
+ *  1 |        BL              |
+ *    +------------------------+
+ *
+ */
+
+enum {
+	GPIO_BASE,
+	IOCFG_RT_BASE,
+	IOCFG_RM_BASE,
+	IOCFG_RB_BASE,
+	IOCFG_LB_BASE,
+	IOCFG_BL_BASE,
+	IOCFG_TM_BASE,
+	IOCFG_TL_BASE,
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_mode_range[] = {
+	PIN_FIELD_GPIO(0, 56, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_dir_range[] = {
+	PIN_FIELD_GPIO(0, 56, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_di_range[] = {
+	PIN_FIELD_GPIO(0, 56, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_do_range[] = {
+	PIN_FIELD_GPIO(0, 56, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_ies_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x10, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x10, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x20, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x20, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x20, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x20, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x20, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x20, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x20, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x20, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x20, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x20, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x20, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x10, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x10, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x20, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x20, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x10, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x10, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(40, 40, 7, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(41, 41, 7, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(42, 42, 7, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 7, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(45, 45, 7, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(46, 46, 7, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(47, 47, 7, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(48, 48, 7, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(49, 49, 7, 0x30, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x10, 0x10, 0, 1),
+	PIN_FIELD_BASE(51, 51, 6, 0x10, 0x10, 2, 1),
+	PIN_FIELD_BASE(52, 52, 6, 0x10, 0x10, 3, 1),
+	PIN_FIELD_BASE(53, 53, 6, 0x10, 0x10, 4, 1),
+	PIN_FIELD_BASE(54, 54, 6, 0x10, 0x10, 5, 1),
+	PIN_FIELD_BASE(55, 55, 6, 0x10, 0x10, 6, 1),
+	PIN_FIELD_BASE(56, 56, 6, 0x10, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_smt_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x80, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x80, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x80, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x80, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x90, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x90, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x90, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x80, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x90, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x90, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x90, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x90, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x90, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x60, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x80, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x80, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x60, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(40, 40, 7, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(41, 41, 7, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(42, 42, 7, 0x70, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 7, 0x70, 0x10, 7, 1),
+	PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(45, 45, 7, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(46, 46, 7, 0x70, 0x10, 4, 1),
+	PIN_FIELD_BASE(47, 47, 7, 0x70, 0x10, 5, 1),
+	PIN_FIELD_BASE(48, 48, 7, 0x70, 0x10, 6, 1),
+	PIN_FIELD_BASE(49, 49, 7, 0x70, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(51, 51, 6, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(52, 52, 6, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(53, 53, 6, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(54, 54, 6, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(55, 55, 6, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(56, 56, 6, 0x50, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pu_range[] = {
+	PIN_FIELD_BASE(40, 40, 7, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(41, 41, 7, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(42, 42, 7, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 7, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(44, 44, 7, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(45, 45, 7, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(46, 46, 7, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(47, 47, 7, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(48, 48, 7, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(49, 49, 7, 0x50, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(51, 51, 6, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(52, 52, 6, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(53, 53, 6, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(54, 54, 6, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(55, 55, 6, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(56, 56, 6, 0x30, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pd_range[] = {
+	PIN_FIELD_BASE(40, 40, 7, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(41, 41, 7, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(42, 42, 7, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 7, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(44, 44, 7, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(45, 45, 7, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(46, 46, 7, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(47, 47, 7, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(48, 48, 7, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(49, 49, 7, 0x40, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(51, 51, 6, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(52, 52, 6, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(53, 53, 6, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(54, 54, 6, 0x20, 0x10, 5, 1),
+	PIN_FIELD_BASE(55, 55, 6, 0x20, 0x10, 6, 1),
+	PIN_FIELD_BASE(56, 56, 6, 0x20, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(1, 1, 1, 0x00, 0x10, 0, 3),
+
+	PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 18, 3),
+
+	PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(6, 6, 4, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(9, 9, 4, 0x00, 0x10, 27, 3),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(11, 11, 5, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(12, 12, 5, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(13, 13, 5, 0x00, 0x10, 3, 3),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x00, 0x10, 27, 3),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(16, 16, 2, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(17, 17, 2, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(18, 18, 2, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(19, 19, 2, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(20, 20, 2, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(21, 21, 2, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(22, 22, 2, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(23, 23, 2, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(24, 24, 2, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(25, 25, 2, 0x00, 0x10, 24, 3),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(27, 27, 5, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(28, 28, 5, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(29, 29, 5, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(30, 30, 5, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(31, 31, 5, 0x00, 0x10, 15, 3),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(33, 33, 1, 0x00, 0x10, 12, 3),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(35, 35, 4, 0x00, 0x10, 21, 3),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(37, 37, 3, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(38, 38, 3, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(39, 39, 3, 0x00, 0x10, 3, 3),
+
+	PIN_FIELD_BASE(40, 40, 7, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(41, 41, 7, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(42, 42, 7, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(43, 43, 7, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(44, 44, 7, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(45, 45, 7, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(46, 46, 7, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(47, 47, 7, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(48, 48, 7, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(49, 49, 7, 0x00, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(50, 50, 6, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(51, 51, 6, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(52, 52, 6, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(53, 53, 6, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(54, 54, 6, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(55, 55, 6, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(56, 56, 6, 0x00, 0x10, 3, 3),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_pupd_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x20, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x30, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x30, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x30, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x30, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x30, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x20, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x30, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x20, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x20, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_r0_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x40, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x40, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x40, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x40, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x40, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x30, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x40, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x30, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_field_calc mt7981_pin_r1_range[] = {
+	PIN_FIELD_BASE(0, 0, 1, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(1, 1, 1, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(3, 3, 4, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 4, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(5, 5, 4, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(6, 6, 4, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(7, 7, 4, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x50, 0x10, 9, 1),
+
+	PIN_FIELD_BASE(10, 10, 5, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(11, 11, 5, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(12, 12, 5, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(13, 13, 5, 0x50, 0x10, 11, 1),
+
+	PIN_FIELD_BASE(14, 14, 4, 0x50, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(15, 15, 2, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(16, 16, 2, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(17, 17, 2, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(18, 18, 2, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(19, 19, 2, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 2, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(21, 21, 2, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(22, 22, 2, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(23, 23, 2, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(24, 24, 2, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(25, 25, 2, 0x50, 0x10, 8, 1),
+
+	PIN_FIELD_BASE(26, 26, 5, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(27, 27, 5, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(28, 28, 5, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(29, 29, 5, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(30, 30, 5, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(31, 31, 5, 0x50, 0x10, 5, 1),
+
+	PIN_FIELD_BASE(32, 32, 1, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(33, 33, 1, 0x40, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(34, 34, 4, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(35, 35, 4, 0x50, 0x10, 7, 1),
+
+	PIN_FIELD_BASE(36, 36, 3, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x40, 0x10, 1, 1),
+};
+
+static const struct mtk_pin_reg_calc mt7981_reg_cals[] = {
+	[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7981_pin_mode_range),
+	[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7981_pin_dir_range),
+	[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7981_pin_di_range),
+	[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7981_pin_do_range),
+	[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7981_pin_smt_range),
+	[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7981_pin_ies_range),
+	[PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7981_pin_pu_range),
+	[PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7981_pin_pd_range),
+	[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7981_pin_drv_range),
+	[PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7981_pin_pupd_range),
+	[PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7981_pin_r0_range),
+	[PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7981_pin_r1_range),
+};
+
+static const struct mtk_pin_desc mt7981_pins[] = {
+	MT7981_TYPE0_PIN(0, "GPIO_WPS"),
+	MT7981_TYPE0_PIN(1, "GPIO_RESET"),
+	MT7981_TYPE0_PIN(2, "SYS_WATCHDOG"),
+	MT7981_TYPE0_PIN(3, "PCIE_PERESET_N"),
+	MT7981_TYPE0_PIN(4, "JTAG_JTDO"),
+	MT7981_TYPE0_PIN(5, "JTAG_JTDI"),
+	MT7981_TYPE0_PIN(6, "JTAG_JTMS"),
+	MT7981_TYPE0_PIN(7, "JTAG_JTCLK"),
+	MT7981_TYPE0_PIN(8, "JTAG_JTRST_N"),
+	MT7981_TYPE0_PIN(9, "WO_JTAG_JTDO"),
+	MT7981_TYPE0_PIN(10, "WO_JTAG_JTDI"),
+	MT7981_TYPE0_PIN(11, "WO_JTAG_JTMS"),
+	MT7981_TYPE0_PIN(12, "WO_JTAG_JTCLK"),
+	MT7981_TYPE0_PIN(13, "WO_JTAG_JTRST_N"),
+	MT7981_TYPE0_PIN(14, "USB_VBUS"),
+	MT7981_TYPE0_PIN(15, "PWM0"),
+	MT7981_TYPE0_PIN(16, "SPI0_CLK"),
+	MT7981_TYPE0_PIN(17, "SPI0_MOSI"),
+	MT7981_TYPE0_PIN(18, "SPI0_MISO"),
+	MT7981_TYPE0_PIN(19, "SPI0_CS"),
+	MT7981_TYPE0_PIN(20, "SPI0_HOLD"),
+	MT7981_TYPE0_PIN(21, "SPI0_WP"),
+	MT7981_TYPE0_PIN(22, "SPI1_CLK"),
+	MT7981_TYPE0_PIN(23, "SPI1_MOSI"),
+	MT7981_TYPE0_PIN(24, "SPI1_MISO"),
+	MT7981_TYPE0_PIN(25, "SPI1_CS"),
+	MT7981_TYPE0_PIN(26, "SPI2_CLK"),
+	MT7981_TYPE0_PIN(27, "SPI2_MOSI"),
+	MT7981_TYPE0_PIN(28, "SPI2_MISO"),
+	MT7981_TYPE0_PIN(29, "SPI2_CS"),
+	MT7981_TYPE0_PIN(30, "SPI2_HOLD"),
+	MT7981_TYPE0_PIN(31, "SPI2_WP"),
+	MT7981_TYPE0_PIN(32, "UART0_RXD"),
+	MT7981_TYPE0_PIN(33, "UART0_TXD"),
+	MT7981_TYPE0_PIN(34, "PCIE_CLK_REQ"),
+	MT7981_TYPE0_PIN(35, "PCIE_WAKE_N"),
+	MT7981_TYPE0_PIN(36, "SMI_MDC"),
+	MT7981_TYPE0_PIN(37, "SMI_MDIO"),
+	MT7981_TYPE0_PIN(38, "GBE_INT"),
+	MT7981_TYPE0_PIN(39, "GBE_RESET"),
+	MT7981_TYPE1_PIN(40, "WF_DIG_RESETB"),
+	MT7981_TYPE1_PIN(41, "WF_CBA_RESETB"),
+	MT7981_TYPE1_PIN(42, "WF_XO_REQ"),
+	MT7981_TYPE1_PIN(43, "WF_TOP_CLK"),
+	MT7981_TYPE1_PIN(44, "WF_TOP_DATA"),
+	MT7981_TYPE1_PIN(45, "WF_HB1"),
+	MT7981_TYPE1_PIN(46, "WF_HB2"),
+	MT7981_TYPE1_PIN(47, "WF_HB3"),
+	MT7981_TYPE1_PIN(48, "WF_HB4"),
+	MT7981_TYPE1_PIN(49, "WF_HB0"),
+	MT7981_TYPE1_PIN(50, "WF_HB0_B"),
+	MT7981_TYPE1_PIN(51, "WF_HB5"),
+	MT7981_TYPE1_PIN(52, "WF_HB6"),
+	MT7981_TYPE1_PIN(53, "WF_HB7"),
+	MT7981_TYPE1_PIN(54, "WF_HB8"),
+	MT7981_TYPE1_PIN(55, "WF_HB9"),
+	MT7981_TYPE1_PIN(56, "WF_HB10"),
+};
+
+/* WA_AICE */
+static int mt7981_wa_aice1_pins[] = { 0, 1, };
+static int mt7981_wa_aice1_funcs[] = { 2, 2, };
+
+static int mt7981_wa_aice2_pins[] = { 0, 1, };
+static int mt7981_wa_aice2_funcs[] = { 3, 3, };
+
+static int mt7981_wa_aice3_pins[] = { 28, 29, };
+static int mt7981_wa_aice3_funcs[] = { 3, 3, };
+
+static int mt7981_wm_aice1_pins[] = { 9, 10, };
+static int mt7981_wm_aice1_funcs[] = { 2, 2, };
+
+static int mt7981_wm_aice2_pins[] = { 30, 31, };
+static int mt7981_wm_aice2_funcs[] = { 5, 5, };
+
+/* WM_UART */
+static int mt7981_wm_uart_0_pins[] = { 0, 1, };
+static int mt7981_wm_uart_0_funcs[] = { 5, 5, };
+
+static int mt7981_wm_uart_1_pins[] = { 20, 21, };
+static int mt7981_wm_uart_1_funcs[] = { 4, 4, };
+
+static int mt7981_wm_uart_2_pins[] = { 30, 31, };
+static int mt7981_wm_uart_2_funcs[] = { 3, 3, };
+
+/* DFD */
+static int mt7981_dfd_pins[] = { 0, 1, 4, 5, };
+static int mt7981_dfd_funcs[] = { 5, 5, 6, 6, };
+
+/* SYS_WATCHDOG */
+static int mt7981_watchdog_pins[] = { 2, };
+static int mt7981_watchdog_funcs[] = { 1, };
+
+static int mt7981_watchdog1_pins[] = { 13, };
+static int mt7981_watchdog1_funcs[] = { 5, };
+
+/* PCIE_PERESET_N */
+static int mt7981_pcie_pereset_pins[] = { 3, };
+static int mt7981_pcie_pereset_funcs[] = { 1, };
+
+/* JTAG */
+static int mt7981_jtag_pins[] = { 4, 5, 6, 7, 8, };
+static int mt7981_jtag_funcs[] = { 1, 1, 1, 1, 1, };
+
+/* WM_JTAG */
+static int mt7981_wm_jtag_0_pins[] = { 4, 5, 6, 7, 8, };
+static int mt7981_wm_jtag_0_funcs[] = { 2, 2, 2, 2, 2, };
+
+static int mt7981_wm_jtag_1_pins[] = { 20, 21, 22, 23, 24, };
+static int mt7981_wm_jtag_1_funcs[] = { 5, 5, 5, 5, 5, };
+
+/* WO0_JTAG */
+static int mt7981_wo0_jtag_0_pins[] = { 9, 10, 11, 12, 13, };
+static int mt7981_wo0_jtag_0_funcs[] = { 1, 1, 1, 1, 1, };
+
+static int mt7981_wo0_jtag_1_pins[] = { 25, 26, 27, 28, 29, };
+static int mt7981_wo0_jtag_1_funcs[] = { 5, 5, 5, 5, 5, };
+
+/* UART2 */
+static int mt7981_uart2_0_pins[] = { 4, 5, 6, 7, };
+static int mt7981_uart2_0_funcs[] = { 3, 3, 3, 3, };
+
+/* GBE_LED0 */
+static int mt7981_gbe_led0_pins[] = { 8, };
+static int mt7981_gbe_led0_funcs[] = { 3, };
+
+/* PTA_EXT */
+static int mt7981_pta_ext_0_pins[] = { 4, 5, 6, };
+static int mt7981_pta_ext_0_funcs[] = { 4, 4, 4, };
+
+static int mt7981_pta_ext_1_pins[] = { 22, 23, 24, };
+static int mt7981_pta_ext_1_funcs[] = { 4, 4, 4, };
+
+/* PWM2 */
+static int mt7981_pwm2_pins[] = { 7, };
+static int mt7981_pwm2_funcs[] = { 4, };
+
+/* NET_WO0_UART_TXD */
+static int mt7981_net_wo0_uart_txd_0_pins[] = { 8, };
+static int mt7981_net_wo0_uart_txd_0_funcs[] = { 4, };
+
+static int mt7981_net_wo0_uart_txd_1_pins[] = { 14, };
+static int mt7981_net_wo0_uart_txd_1_funcs[] = { 3, };
+
+static int mt7981_net_wo0_uart_txd_2_pins[] = { 15, };
+static int mt7981_net_wo0_uart_txd_2_funcs[] = { 4, };
+
+/* SPI1 */
+static int mt7981_spi1_0_pins[] = { 4, 5, 6, 7, };
+static int mt7981_spi1_0_funcs[] = { 5, 5, 5, 5, };
+
+/* I2C */
+static int mt7981_i2c0_0_pins[] = { 6, 7, };
+static int mt7981_i2c0_0_funcs[] = { 6, 6, };
+
+static int mt7981_i2c0_1_pins[] = { 30, 31, };
+static int mt7981_i2c0_1_funcs[] = { 4, 4, };
+
+static int mt7981_i2c0_2_pins[] = { 36, 37, };
+static int mt7981_i2c0_2_funcs[] = { 2, 2, };
+
+static int mt7981_u2_phy_i2c_pins[] = { 30, 31, };
+static int mt7981_u2_phy_i2c_funcs[] = { 6, 6, };
+
+static int mt7981_u3_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_u3_phy_i2c_funcs[] = { 3, 3, };
+
+static int mt7981_sgmii1_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_sgmii1_phy_i2c_funcs[] = { 2, 2, };
+
+static int mt7981_sgmii0_phy_i2c_pins[] = { 32, 33, };
+static int mt7981_sgmii0_phy_i2c_funcs[] = { 5, 5, };
+
+/* DFD_NTRST */
+static int mt7981_dfd_ntrst_pins[] = { 8, };
+static int mt7981_dfd_ntrst_funcs[] = { 6, };
+
+/* PWM0 */
+static int mt7981_pwm0_0_pins[] = { 13, };
+static int mt7981_pwm0_0_funcs[] = { 2, };
+
+static int mt7981_pwm0_1_pins[] = { 15, };
+static int mt7981_pwm0_1_funcs[] = { 1, };
+
+/* PWM1 */
+static int mt7981_pwm1_0_pins[] = { 14, };
+static int mt7981_pwm1_0_funcs[] = { 2, };
+
+static int mt7981_pwm1_1_pins[] = { 15, };
+static int mt7981_pwm1_1_funcs[] = { 3, };
+
+/* GBE_LED1 */
+static int mt7981_gbe_led1_pins[] = { 13, };
+static int mt7981_gbe_led1_funcs[] = { 3, };
+
+/* PCM */
+static int mt7981_pcm_pins[] = { 9, 10, 11, 12, 13, 25 };
+static int mt7981_pcm_funcs[] = { 4, 4, 4, 4, 4, 4, };
+
+/* UDI */
+static int mt7981_udi_pins[] = { 9, 10, 11, 12, 13, };
+static int mt7981_udi_funcs[] = { 6, 6, 6, 6, 6, };
+
+/* DRV_VBUS */
+static int mt7981_drv_vbus_pins[] = { 14, };
+static int mt7981_drv_vbus_funcs[] = { 1, };
+
+/* EMMC */
+static int mt7981_emmc_45_pins[] = { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, };
+static int mt7981_emmc_45_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, };
+
+/* SNFI */
+static int mt7981_snfi_pins[] = { 16, 17, 18, 19, 20, 21, };
+static int mt7981_snfi_funcs[] = { 3, 3, 3, 3, 3, 3, };
+
+/* SPI0 */
+static int mt7981_spi0_pins[] = { 16, 17, 18, 19, };
+static int mt7981_spi0_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI0 */
+static int mt7981_spi0_wp_hold_pins[] = { 20, 21, };
+static int mt7981_spi0_wp_hold_funcs[] = { 1, 1, };
+
+/* SPI1 */
+static int mt7981_spi1_1_pins[] = { 22, 23, 24, 25, };
+static int mt7981_spi1_1_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI2 */
+static int mt7981_spi2_pins[] = { 26, 27, 28, 29, };
+static int mt7981_spi2_funcs[] = { 1, 1, 1, 1, };
+
+/* SPI2 */
+static int mt7981_spi2_wp_hold_pins[] = { 30, 31, };
+static int mt7981_spi2_wp_hold_funcs[] = { 1, 1, };
+
+/* UART1 */
+static int mt7981_uart1_0_pins[] = { 16, 17, 18, 19, };
+static int mt7981_uart1_0_funcs[] = { 4, 4, 4, 4, };
+
+static int mt7981_uart1_1_pins[] = { 26, 27, 28, 29, };
+static int mt7981_uart1_1_funcs[] = { 2, 2, 2, 2, };
+
+/* UART2 */
+static int mt7981_uart2_1_pins[] = { 22, 23, 24, 25, };
+static int mt7981_uart2_1_funcs[] = { 3, 3, 3, 3, };
+
+/* UART0 */
+static int mt7981_uart0_pins[] = { 32, 33, };
+static int mt7981_uart0_funcs[] = { 1, 1, };
+
+/* PCIE_CLK_REQ */
+static int mt7981_pcie_clk_pins[] = { 34, };
+static int mt7981_pcie_clk_funcs[] = { 2, };
+
+/* PCIE_WAKE_N */
+static int mt7981_pcie_wake_pins[] = { 35, };
+static int mt7981_pcie_wake_funcs[] = { 2, };
+
+/* MDC_MDIO */
+static int mt7981_smi_mdc_mdio_pins[] = { 36, 37, };
+static int mt7981_smi_mdc_mdio_funcs[] = { 1, 1, };
+
+static int mt7981_gbe_ext_mdc_mdio_pins[] = { 36, 37, };
+static int mt7981_gbe_ext_mdc_mdio_funcs[] = { 3, 3, };
+
+/* WF0_MODE1 */
+static int mt7981_wf0_mode1_pins[] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+				       50, 51, 52, 53, 54, 55, 56 };
+static int mt7981_wf0_mode1_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+					1, 1, 1, 1 };
+
+/* WF0_MODE3 */
+static int mt7981_wf0_mode3_pins[] = { 45, 46, 47, 48, 49, 51 };
+static int mt7981_wf0_mode3_funcs[] = { 2, 2, 2, 2, 2, 2 };
+
+/* WF2G_LED */
+static int mt7981_wf2g_led0_pins[] = { 30, };
+static int mt7981_wf2g_led0_funcs[] = { 2, };
+
+static int mt7981_wf2g_led1_pins[] = { 34, };
+static int mt7981_wf2g_led1_funcs[] = { 1, };
+
+/* WF5G_LED */
+static int mt7981_wf5g_led0_pins[] = { 31, };
+static int mt7981_wf5g_led0_funcs[] = { 2, };
+
+static int mt7981_wf5g_led1_pins[] = { 35, };
+static int mt7981_wf5g_led1_funcs[] = { 1, };
+
+/* MT7531_INT */
+static int mt7981_mt7531_int_pins[] = { 38, };
+static int mt7981_mt7531_int_funcs[] = { 1, };
+
+/* ANT_SEL */
+static int mt7981_ant_sel_pins[] = { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 34, 35 };
+static int mt7981_ant_sel_funcs[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 };
+
+static const struct mtk_group_desc mt7981_groups[] = {
+	/* @GPIO(0,1): WA_AICE(2) */
+	PINCTRL_PIN_GROUP("wa_aice1", mt7981_wa_aice1),
+	/* @GPIO(0,1): WA_AICE(3) */
+	PINCTRL_PIN_GROUP("wa_aice2", mt7981_wa_aice2),
+	/* @GPIO(0,1): WM_UART(5) */
+	PINCTRL_PIN_GROUP("wm_uart_0", mt7981_wm_uart_0),
+	/* @GPIO(0,1,4,5): DFD(6) */
+	PINCTRL_PIN_GROUP("dfd", mt7981_dfd),
+	/* @GPIO(2): SYS_WATCHDOG(1) */
+	PINCTRL_PIN_GROUP("watchdog", mt7981_watchdog),
+	/* @GPIO(3): PCIE_PERESET_N(1) */
+	PINCTRL_PIN_GROUP("pcie_pereset", mt7981_pcie_pereset),
+	/* @GPIO(4,8) JTAG(1) */
+	PINCTRL_PIN_GROUP("jtag", mt7981_jtag),
+	/* @GPIO(4,8) WM_JTAG(2) */
+	PINCTRL_PIN_GROUP("wm_jtag_0", mt7981_wm_jtag_0),
+	/* @GPIO(9,13) WO0_JTAG(1) */
+	PINCTRL_PIN_GROUP("wo0_jtag_0", mt7981_wo0_jtag_0),
+	/* @GPIO(4,7) WM_JTAG(3) */
+	PINCTRL_PIN_GROUP("uart2_0", mt7981_uart2_0),
+	/* @GPIO(8) GBE_LED0(3) */
+	PINCTRL_PIN_GROUP("gbe_led0", mt7981_gbe_led0),
+	/* @GPIO(4,6) PTA_EXT(4) */
+	PINCTRL_PIN_GROUP("pta_ext_0", mt7981_pta_ext_0),
+	/* @GPIO(7) PWM2(4) */
+	PINCTRL_PIN_GROUP("pwm2", mt7981_pwm2),
+	/* @GPIO(8) NET_WO0_UART_TXD(4) */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7981_net_wo0_uart_txd_0),
+	/* @GPIO(4,7) SPI1(5) */
+	PINCTRL_PIN_GROUP("spi1_0", mt7981_spi1_0),
+	/* @GPIO(6,7) I2C(5) */
+	PINCTRL_PIN_GROUP("i2c0_0", mt7981_i2c0_0),
+	/* @GPIO(8): DFD_NTRST(6) */
+	PINCTRL_PIN_GROUP("dfd_ntrst", mt7981_dfd_ntrst),
+	/* @GPIO(9,10): WM_AICE(2) */
+	PINCTRL_PIN_GROUP("wm_aice1", mt7981_wm_aice1),
+	/* @GPIO(13): PWM0(2) */
+	PINCTRL_PIN_GROUP("pwm0_0", mt7981_pwm0_0),
+	/* @GPIO(15): PWM0(1) */
+	PINCTRL_PIN_GROUP("pwm0_1", mt7981_pwm0_1),
+	/* @GPIO(14): PWM1(2) */
+	PINCTRL_PIN_GROUP("pwm1_0", mt7981_pwm1_0),
+	/* @GPIO(15): PWM1(3) */
+	PINCTRL_PIN_GROUP("pwm1_1", mt7981_pwm1_1),
+	/* @GPIO(14) NET_WO0_UART_TXD(3) */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7981_net_wo0_uart_txd_1),
+	/* @GPIO(15) NET_WO0_UART_TXD(4) */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_2", mt7981_net_wo0_uart_txd_2),
+	/* @GPIO(13) GBE_LED0(3) */
+	PINCTRL_PIN_GROUP("gbe_led1", mt7981_gbe_led1),
+	/* @GPIO(9,13) PCM(4) */
+	PINCTRL_PIN_GROUP("pcm", mt7981_pcm),
+	/* @GPIO(13): SYS_WATCHDOG1(5) */
+	PINCTRL_PIN_GROUP("watchdog1", mt7981_watchdog1),
+	/* @GPIO(9,13) UDI(4) */
+	PINCTRL_PIN_GROUP("udi", mt7981_udi),
+	/* @GPIO(14) DRV_VBUS(1) */
+	PINCTRL_PIN_GROUP("drv_vbus", mt7981_drv_vbus),
+	/* @GPIO(15,25): EMMC(2) */
+	PINCTRL_PIN_GROUP("emmc_45", mt7981_emmc_45),
+	/* @GPIO(16,21): SNFI(3) */
+	PINCTRL_PIN_GROUP("snfi", mt7981_snfi),
+	/* @GPIO(16,19): SPI0(1) */
+	PINCTRL_PIN_GROUP("spi0", mt7981_spi0),
+	/* @GPIO(20,21): SPI0(1) */
+	PINCTRL_PIN_GROUP("spi0_wp_hold", mt7981_spi0_wp_hold),
+	/* @GPIO(22,25) SPI1(1) */
+	PINCTRL_PIN_GROUP("spi1_1", mt7981_spi1_1),
+	/* @GPIO(26,29): SPI2(1) */
+	PINCTRL_PIN_GROUP("spi2", mt7981_spi2),
+	/* @GPIO(30,31): SPI2(1) */
+	PINCTRL_PIN_GROUP("spi2_wp_hold", mt7981_spi2_wp_hold),
+	/* @GPIO(16,19): UART1(4) */
+	PINCTRL_PIN_GROUP("uart1_0", mt7981_uart1_0),
+	/* @GPIO(26,29): UART1(2) */
+	PINCTRL_PIN_GROUP("uart1_1", mt7981_uart1_1),
+	/* @GPIO(22,25): UART2(3) */
+	PINCTRL_PIN_GROUP("uart2_0", mt7981_uart2_1),
+	/* @GPIO(22,24) PTA_EXT(4) */
+	PINCTRL_PIN_GROUP("pta_ext_1", mt7981_pta_ext_1),
+	/* @GPIO(20,21): WM_UART(4) */
+	PINCTRL_PIN_GROUP("wm_aurt_1", mt7981_wm_uart_1),
+	/* @GPIO(30,31): WM_UART(3) */
+	PINCTRL_PIN_GROUP("wm_aurt_2", mt7981_wm_uart_2),
+	/* @GPIO(20,24) WM_JTAG(5) */
+	PINCTRL_PIN_GROUP("wm_jtag_1", mt7981_wm_jtag_1),
+	/* @GPIO(25,29) WO0_JTAG(5) */
+	PINCTRL_PIN_GROUP("wo0_jtag_1", mt7981_wo0_jtag_1),
+	/* @GPIO(28,29): WA_AICE(3) */
+	PINCTRL_PIN_GROUP("wa_aice3", mt7981_wa_aice3),
+	/* @GPIO(30,31): WM_AICE(5) */
+	PINCTRL_PIN_GROUP("wm_aice2", mt7981_wm_aice2),
+	/* @GPIO(30,31): I2C(4) */
+	PINCTRL_PIN_GROUP("i2c0_1", mt7981_i2c0_1),
+	/* @GPIO(30,31): I2C(6) */
+	PINCTRL_PIN_GROUP("u2_phy_i2c", mt7981_u2_phy_i2c),
+	/* @GPIO(32,33): I2C(1) */
+	PINCTRL_PIN_GROUP("uart0", mt7981_uart0),
+	/* @GPIO(32,33): I2C(2) */
+	PINCTRL_PIN_GROUP("sgmii1_phy_i2c", mt7981_sgmii1_phy_i2c),
+	/* @GPIO(32,33): I2C(3) */
+	PINCTRL_PIN_GROUP("u3_phy_i2c", mt7981_u3_phy_i2c),
+	/* @GPIO(32,33): I2C(5) */
+	PINCTRL_PIN_GROUP("sgmii0_phy_i2c", mt7981_sgmii0_phy_i2c),
+	/* @GPIO(34): PCIE_CLK_REQ(2) */
+	PINCTRL_PIN_GROUP("pcie_clk", mt7981_pcie_clk),
+	/* @GPIO(35): PCIE_WAKE_N(2) */
+	PINCTRL_PIN_GROUP("pcie_wake", mt7981_pcie_wake),
+	/* @GPIO(36,37): I2C(2) */
+	PINCTRL_PIN_GROUP("i2c0_2", mt7981_i2c0_2),
+	/* @GPIO(36,37): MDC_MDIO(1) */
+	PINCTRL_PIN_GROUP("smi_mdc_mdio", mt7981_smi_mdc_mdio),
+	/* @GPIO(36,37): MDC_MDIO(3) */
+	PINCTRL_PIN_GROUP("gbe_ext_mdc_mdio", mt7981_gbe_ext_mdc_mdio),
+	/* @GPIO(40,56): WF0_MODE1(1) */
+	PINCTRL_PIN_GROUP("wf0_mode1", mt7981_wf0_mode1),
+	/* @GPIO(45,46,47,48,49,51): WF0_MODE3(3) */
+	PINCTRL_PIN_GROUP("wf0_mode3", mt7981_wf0_mode3),
+	/* @GPIO(30): WF2G_LED(2) */
+	PINCTRL_PIN_GROUP("wf2g_led0", mt7981_wf2g_led0),
+	/* @GPIO(34): WF2G_LED(1) */
+	PINCTRL_PIN_GROUP("wf2g_led1", mt7981_wf2g_led1),
+	/* @GPIO(31): WF5G_LED(2) */
+	PINCTRL_PIN_GROUP("wf5g_led0", mt7981_wf5g_led0),
+	/* @GPIO(35): WF5G_LED(1) */
+	PINCTRL_PIN_GROUP("wf5g_led1", mt7981_wf5g_led1),
+	/* @GPIO(38): MT7531_INT(1) */
+	PINCTRL_PIN_GROUP("mt7531_int", mt7981_mt7531_int),
+	/* @GPIO(14,15,26,17,18,19,20,21,22,23,24,25,34,35): ANT_SEL(1) */
+	PINCTRL_PIN_GROUP("ant_sel", mt7981_ant_sel),
+};
+
+static const struct mtk_io_type_desc mt7981_io_type_desc[] = {
+	[IO_TYPE_GRP0] = {
+		.name = "18OD33",
+		.bias_set = mtk_pinconf_bias_set_pupd_r1_r0,
+		.drive_set = mtk_pinconf_drive_set_v1,
+		.input_enable = mtk_pinconf_input_enable_v1,
+	},
+	[IO_TYPE_GRP1] = {
+		.name = "18A01",
+		.bias_set = mtk_pinconf_bias_set_pu_pd,
+		.drive_set = mtk_pinconf_drive_set_v1,
+		.input_enable = mtk_pinconf_input_enable_v1,
+	},
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+static const char *const mt7981_wa_aice_groups[] = { "wa_aice1", "wa_aice2",
+	"wm_aice1_1", "wa_aice3", "wm_aice1_2", };
+static const char *const mt7981_uart_groups[] = { "wm_uart_0", "uart2_0",
+	"net_wo0_uart_txd_0", "net_wo0_uart_txd_1", "net_wo0_uart_txd_2",
+	"uart1_0", "uart1_1", "uart2_0", "wm_aurt_1", "wm_aurt_2", "uart0", };
+static const char *const mt7981_dfd_groups[] = { "dfd", "dfd_ntrst", };
+static const char *const mt7981_wdt_groups[] = { "watchdog", "watchdog1", };
+static const char *const mt7981_pcie_groups[] = { "pcie_pereset", "pcie_clk",
+	"pcie_wake", };
+static const char *const mt7981_jtag_groups[] = { "jtag", "wm_jtag_0",
+	"wo0_jtag_0", "wo0_jtag_1", "wm_jtag_1", };
+static const char *const mt7981_led_groups[] = { "gbe_led0", "gbe_led1",
+	"wf2g_led0", "wf2g_led1", "wf5g_led0", "wf5g_led1", };
+static const char *const mt7981_pta_groups[] = { "pta_ext_0", "pta_ext_1", };
+static const char *const mt7981_pwm_groups[] = { "pwm2", "pwm0_0", "pwm0_1",
+	"pwm1_0", "pwm1_1", };
+static const char *const mt7981_spi_groups[] = { "spi1_0", "spi0",
+	"spi0_wp_hold", "spi1_1", "spi2", "spi2_wp_hold", };
+static const char *const mt7981_i2c_groups[] = { "i2c0_0", "i2c0_1",
+	"u2_phy_i2c", "sgmii1_phy_i2c", "u3_phy_i2c", "sgmii0_phy_i2c",
+	"i2c0_2", };
+static const char *const mt7981_pcm_groups[] = { "pcm", };
+static const char *const mt7981_udi_groups[] = { "udi", };
+static const char *const mt7981_usb_groups[] = { "drv_vbus", };
+static const char *const mt7981_flash_groups[] = { "emmc_45", "snfi", };
+static const char *const mt7981_ethernet_groups[] = { "smi_mdc_mdio",
+	"gbe_ext_mdc_mdio", "wf0_mode1", "wf0_mode3", "mt7531_int", };
+static const char *const mt7981_ant_groups[] = { "ant_sel", };
+
+static const struct mtk_function_desc mt7981_functions[] = {
+	{"wa_aice", mt7981_wa_aice_groups, ARRAY_SIZE(mt7981_wa_aice_groups)},
+	{"dfd", mt7981_dfd_groups, ARRAY_SIZE(mt7981_dfd_groups)},
+	{"jtag", mt7981_jtag_groups, ARRAY_SIZE(mt7981_jtag_groups)},
+	{"pta", mt7981_pta_groups, ARRAY_SIZE(mt7981_pta_groups)},
+	{"pcm", mt7981_pcm_groups, ARRAY_SIZE(mt7981_pcm_groups)},
+	{"udi", mt7981_udi_groups, ARRAY_SIZE(mt7981_udi_groups)},
+	{"usb", mt7981_usb_groups, ARRAY_SIZE(mt7981_usb_groups)},
+	{"ant", mt7981_ant_groups, ARRAY_SIZE(mt7981_ant_groups)},
+	{"eth", mt7981_ethernet_groups, ARRAY_SIZE(mt7981_ethernet_groups)},
+	{"i2c", mt7981_i2c_groups, ARRAY_SIZE(mt7981_i2c_groups)},
+	{"led", mt7981_led_groups, ARRAY_SIZE(mt7981_led_groups)},
+	{"pwm", mt7981_pwm_groups, ARRAY_SIZE(mt7981_pwm_groups)},
+	{"spi", mt7981_spi_groups, ARRAY_SIZE(mt7981_spi_groups)},
+	{"uart", mt7981_uart_groups, ARRAY_SIZE(mt7981_uart_groups)},
+	{"watchdog", mt7981_wdt_groups, ARRAY_SIZE(mt7981_wdt_groups)},
+	{"flash", mt7981_flash_groups, ARRAY_SIZE(mt7981_flash_groups)},
+	{"pcie", mt7981_pcie_groups, ARRAY_SIZE(mt7981_pcie_groups)},
+};
+
+static const char *const mt7981_pinctrl_register_base_names[] = {
+	"gpio_base", "iocfg_rt_base", "iocfg_rm_base", "iocfg_rb_base",
+	"iocfg_lb_base", "iocfg_bl_base", "iocfg_tm_base", "iocfg_tl_base",
+};
+
+static struct mtk_pinctrl_soc mt7981_data = {
+	.name = "mt7981_pinctrl",
+	.reg_cal = mt7981_reg_cals,
+	.pins = mt7981_pins,
+	.npins = ARRAY_SIZE(mt7981_pins),
+	.grps = mt7981_groups,
+	.ngrps = ARRAY_SIZE(mt7981_groups),
+	.funcs = mt7981_functions,
+	.nfuncs = ARRAY_SIZE(mt7981_functions),
+	.io_type = mt7981_io_type_desc,
+	.ntype = ARRAY_SIZE(mt7981_io_type_desc),
+	.gpio_mode = 0,
+	.base_names = mt7981_pinctrl_register_base_names,
+	.nbase_names = ARRAY_SIZE(mt7981_pinctrl_register_base_names),
+	.base_calc = 1,
+};
+
+static int mtk_pinctrl_mt7981_probe(struct udevice *dev)
+{
+	return mtk_pinctrl_common_probe(dev, &mt7981_data);
+}
+
+static const struct udevice_id mt7981_pctrl_match[] = {
+	{.compatible = "mediatek,mt7981-pinctrl"},
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mt7981_pinctrl) = {
+	.name = "mt7981_pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = mt7981_pctrl_match,
+	.ops = &mtk_pinctrl_ops,
+	.probe = mtk_pinctrl_mt7981_probe,
+	.priv_auto = sizeof(struct mtk_pinctrl_priv),
+};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7986.c b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
new file mode 100644
index 0000000..449e5ad
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
@@ -0,0 +1,775 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The MT7986 driver based on Linux generic pinctrl binding.
+ *
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include <dm.h>
+#include "pinctrl-mtk-common.h"
+
+#define MT7986_TYPE0_PIN(_number, _name)	\
+	MTK_TYPED_PIN(_number, _name, DRV_GRP4, IO_TYPE_GRP0)
+
+#define MT7986_TYPE1_PIN(_number, _name)	\
+	MTK_TYPED_PIN(_number, _name, DRV_GRP4, IO_TYPE_GRP1)
+
+#define PIN_FIELD_GPIO(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_BASE_CALC(_s_pin, _e_pin, GPIO_BASE, _s_addr, _x_addrs,	\
+			    _s_bit, _x_bits, 32, 0)
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,	\
+		       _x_bits)							\
+	PIN_FIELD_BASE_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,	\
+	_x_bits, 32, 0)
+
+/**
+ * enum - Locking variants of the iocfg bases
+ *
+ * MT7986 have multiple bases to program pin configuration listed as the below:
+ * iocfg_rt:0x11c30000, iocfg_rb:0x11c40000, iocfg_lt:0x11e20000,
+ * iocfg_lb:0x11e30000, iocfg_tr:0x11f00000, iocfg_tl:0x11f10000,
+ * _i_based could be used to indicate what base the pin should be mapped into.
+ *
+ * Each iocfg register base control different group of pads on the SoC
+ *
+ *
+ *  chip carrier
+ *
+ *      A  B  C  D  E  F  G  H
+ *    +------------------------+
+ *  8 | o  o  o  o  o  o  o  o |
+ *  7 | o  o  o  o  o  o  o  o |
+ *  6 | o  o  o  o  o  o  o  o |
+ *  5 | o  o  o  o  o  o  o  o |
+ *  4 | o  o  o  o  o  o  o  o |
+ *  3 | o  o  o  o  o  o  o  o |
+ *  2 | o  o  o  o  o  o  o  o |
+ *  1 | o  o  o  o  o  o  o  o |
+ *    +------------------------+
+ *
+ *  inside Chip carrier
+ *
+ *      A  B  C  D  E  F  G  H
+ *    +------------------------+
+ *  8 |                        |
+ *  7 |        TL  TR          |
+ *  6 |      +---------+       |
+ *  5 |   LT |         | RT    |
+ *  4 |      |         |       |
+ *  3 |   LB |         | RB    |
+ *  2 |      +---------+       |
+ *  1 |                        |
+ *    +------------------------+
+ *
+ */
+
+enum {
+	GPIO_BASE,
+	IOCFG_RT_BASE,
+	IOCFG_RB_BASE,
+	IOCFG_LT_BASE,
+	IOCFG_LB_BASE,
+	IOCFG_TR_BASE,
+	IOCFG_TL_BASE,
+};
+
+static const char *const mt7986_pinctrl_register_base_names[] = {
+	"gpio", "iocfg_rt", "iocfg_rb", "iocfg_lt", "iocfg_lb", "iocfg_tr",
+	"iocfg_tl",
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_mode_range[] = {
+	PIN_FIELD_GPIO(0, 100, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_dir_range[] = {
+	PIN_FIELD_GPIO(0, 100, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_di_range[] = {
+	PIN_FIELD_GPIO(0, 100, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_do_range[] = {
+	PIN_FIELD_GPIO(0, 100, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_ies_range[] = {
+	PIN_FIELD_BASE(0, 0, IOCFG_RB_BASE, 0x40, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 2, IOCFG_LT_BASE, 0x20, 0x10, 10, 1),
+	PIN_FIELD_BASE(3, 4, IOCFG_LB_BASE, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 6, IOCFG_RB_BASE, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(7, 10, IOCFG_LT_BASE, 0x20, 0x10, 0, 1),
+	PIN_FIELD_BASE(11, 14, IOCFG_RB_BASE, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(15, 20, IOCFG_RB_BASE, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(21, 23, IOCFG_RT_BASE, 0x30, 0x10, 12, 1),
+	PIN_FIELD_BASE(24, 24, IOCFG_RT_BASE, 0x30, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, IOCFG_RT_BASE, 0x30, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 27, IOCFG_RT_BASE, 0x30, 0x10, 15, 1),
+	PIN_FIELD_BASE(28, 29, IOCFG_RT_BASE, 0x30, 0x10, 19, 1),
+	PIN_FIELD_BASE(30, 30, IOCFG_RT_BASE, 0x30, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, IOCFG_RT_BASE, 0x30, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, IOCFG_RT_BASE, 0x30, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, IOCFG_LT_BASE, 0x20, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, IOCFG_LT_BASE, 0x20, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, IOCFG_LT_BASE, 0x20, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 37, IOCFG_LT_BASE, 0x20, 0x10, 5, 1),
+	PIN_FIELD_BASE(38, 38, IOCFG_LT_BASE, 0x20, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 40, IOCFG_RB_BASE, 0x40, 0x10, 18, 1),
+	PIN_FIELD_BASE(41, 41, IOCFG_RB_BASE, 0x40, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 43, IOCFG_RB_BASE, 0x40, 0x10, 22, 1),
+	PIN_FIELD_BASE(44, 45, IOCFG_RB_BASE, 0x40, 0x10, 20, 1),
+	PIN_FIELD_BASE(46, 47, IOCFG_RB_BASE, 0x40, 0x10, 26, 1),
+	PIN_FIELD_BASE(48, 49, IOCFG_RB_BASE, 0x40, 0x10, 24, 1),
+	PIN_FIELD_BASE(50, 57, IOCFG_RT_BASE, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(58, 58, IOCFG_RT_BASE, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, IOCFG_RT_BASE, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 61, IOCFG_RT_BASE, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(62, 62, IOCFG_RB_BASE, 0x40, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, IOCFG_RB_BASE, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, IOCFG_RB_BASE, 0x40, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, IOCFG_RB_BASE, 0x40, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 68, IOCFG_LB_BASE, 0x20, 0x10, 2, 1),
+	PIN_FIELD_BASE(69, 69, IOCFG_TR_BASE, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, IOCFG_TR_BASE, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(71, 71, IOCFG_TR_BASE, 0x30, 0x10, 16, 1),
+	PIN_FIELD_BASE(72, 73, IOCFG_TR_BASE, 0x30, 0x10, 14, 1),
+	PIN_FIELD_BASE(74, 74, IOCFG_TR_BASE, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(75, 77, IOCFG_TR_BASE, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(78, 79, IOCFG_TR_BASE, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(80, 84, IOCFG_TR_BASE, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(85, 85, IOCFG_TR_BASE, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(86, 86, IOCFG_TL_BASE, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(87, 87, IOCFG_TL_BASE, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(88, 88, IOCFG_TL_BASE, 0x30, 0x10, 14, 1),
+	PIN_FIELD_BASE(89, 90, IOCFG_TL_BASE, 0x30, 0x10, 12, 1),
+	PIN_FIELD_BASE(91, 94, IOCFG_TL_BASE, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(95, 96, IOCFG_TL_BASE, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(97, 100, IOCFG_TL_BASE, 0x30, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_smt_range[] = {
+	PIN_FIELD_BASE(0, 0, IOCFG_RB_BASE, 0xf0, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 2, IOCFG_LT_BASE, 0x90, 0x10, 10, 1),
+	PIN_FIELD_BASE(3, 4, IOCFG_LB_BASE, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 6, IOCFG_RB_BASE, 0xf0, 0x10, 0, 1),
+	PIN_FIELD_BASE(7, 10, IOCFG_LT_BASE, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(11, 14, IOCFG_RB_BASE, 0xf0, 0x10, 8, 1),
+	PIN_FIELD_BASE(15, 20, IOCFG_RB_BASE, 0xf0, 0x10, 2, 1),
+	PIN_FIELD_BASE(21, 23, IOCFG_RT_BASE, 0xc0, 0x10, 12, 1),
+	PIN_FIELD_BASE(24, 24, IOCFG_RT_BASE, 0xc0, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, IOCFG_RT_BASE, 0xc0, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 27, IOCFG_RT_BASE, 0xc0, 0x10, 15, 1),
+	PIN_FIELD_BASE(28, 29, IOCFG_RT_BASE, 0xc0, 0x10, 19, 1),
+	PIN_FIELD_BASE(30, 30, IOCFG_RT_BASE, 0xc0, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, IOCFG_RT_BASE, 0xc0, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, IOCFG_RT_BASE, 0xc0, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, IOCFG_LT_BASE, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, IOCFG_LT_BASE, 0x90, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, IOCFG_LT_BASE, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 37, IOCFG_LT_BASE, 0x90, 0x10, 5, 1),
+	PIN_FIELD_BASE(38, 38, IOCFG_LT_BASE, 0x90, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 40, IOCFG_RB_BASE, 0xf0, 0x10, 18, 1),
+	PIN_FIELD_BASE(41, 41, IOCFG_RB_BASE, 0xf0, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 43, IOCFG_RB_BASE, 0xf0, 0x10, 22, 1),
+	PIN_FIELD_BASE(44, 45, IOCFG_RB_BASE, 0xf0, 0x10, 20, 1),
+	PIN_FIELD_BASE(46, 47, IOCFG_RB_BASE, 0xf0, 0x10, 26, 1),
+	PIN_FIELD_BASE(48, 49, IOCFG_RB_BASE, 0xf0, 0x10, 24, 1),
+	PIN_FIELD_BASE(50, 57, IOCFG_RT_BASE, 0xc0, 0x10, 2, 1),
+	PIN_FIELD_BASE(58, 58, IOCFG_RT_BASE, 0xc0, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, IOCFG_RT_BASE, 0xc0, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 61, IOCFG_RT_BASE, 0xc0, 0x10, 10, 1),
+	PIN_FIELD_BASE(62, 62, IOCFG_RB_BASE, 0xf0, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, IOCFG_RB_BASE, 0xf0, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, IOCFG_RB_BASE, 0xf0, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, IOCFG_RB_BASE, 0xf0, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 68, IOCFG_LB_BASE, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(69, 69, IOCFG_TR_BASE, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, IOCFG_TR_BASE, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(71, 71, IOCFG_TR_BASE, 0x80, 0x10, 16, 1),
+	PIN_FIELD_BASE(72, 73, IOCFG_TR_BASE, 0x80, 0x10, 14, 1),
+	PIN_FIELD_BASE(74, 74, IOCFG_TR_BASE, 0x80, 0x10, 4, 1),
+	PIN_FIELD_BASE(75, 77, IOCFG_TR_BASE, 0x80, 0x10, 6, 1),
+	PIN_FIELD_BASE(78, 79, IOCFG_TR_BASE, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(80, 84, IOCFG_TR_BASE, 0x80, 0x10, 9, 1),
+	PIN_FIELD_BASE(85, 85, IOCFG_TR_BASE, 0x80, 0x10, 5, 1),
+	PIN_FIELD_BASE(86, 86, IOCFG_TL_BASE, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(87, 87, IOCFG_TL_BASE, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(88, 88, IOCFG_TL_BASE, 0x70, 0x10, 14, 1),
+	PIN_FIELD_BASE(89, 90, IOCFG_TL_BASE, 0x70, 0x10, 12, 1),
+	PIN_FIELD_BASE(91, 94, IOCFG_TL_BASE, 0x70, 0x10, 4, 1),
+	PIN_FIELD_BASE(95, 96, IOCFG_TL_BASE, 0x70, 0x10, 2, 1),
+	PIN_FIELD_BASE(97, 100, IOCFG_TL_BASE, 0x70, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_pu_range[] = {
+	PIN_FIELD_BASE(69, 69, IOCFG_TR_BASE, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, IOCFG_TR_BASE, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(71, 71, IOCFG_TR_BASE, 0x50, 0x10, 16, 1),
+	PIN_FIELD_BASE(72, 73, IOCFG_TR_BASE, 0x50, 0x10, 14, 1),
+	PIN_FIELD_BASE(74, 74, IOCFG_TR_BASE, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(75, 77, IOCFG_TR_BASE, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(78, 79, IOCFG_TR_BASE, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(80, 84, IOCFG_TR_BASE, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(85, 85, IOCFG_TR_BASE, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(86, 86, IOCFG_TL_BASE, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(87, 87, IOCFG_TL_BASE, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(88, 88, IOCFG_TL_BASE, 0x50, 0x10, 14, 1),
+	PIN_FIELD_BASE(89, 90, IOCFG_TL_BASE, 0x50, 0x10, 12, 1),
+	PIN_FIELD_BASE(91, 94, IOCFG_TL_BASE, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(95, 96, IOCFG_TL_BASE, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(97, 100, IOCFG_TL_BASE, 0x50, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_pd_range[] = {
+	PIN_FIELD_BASE(69, 69, IOCFG_TR_BASE, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, IOCFG_TR_BASE, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(71, 71, IOCFG_TR_BASE, 0x40, 0x10, 16, 1),
+	PIN_FIELD_BASE(72, 73, IOCFG_TR_BASE, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(74, 74, IOCFG_TR_BASE, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(75, 77, IOCFG_TR_BASE, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(78, 79, IOCFG_TR_BASE, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(80, 84, IOCFG_TR_BASE, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(85, 85, IOCFG_TR_BASE, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(86, 86, IOCFG_TL_BASE, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(87, 87, IOCFG_TL_BASE, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(88, 88, IOCFG_TL_BASE, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(89, 90, IOCFG_TL_BASE, 0x40, 0x10, 12, 1),
+	PIN_FIELD_BASE(91, 94, IOCFG_TL_BASE, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(95, 96, IOCFG_TL_BASE, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(97, 100, IOCFG_TL_BASE, 0x40, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_drv_range[] = {
+	PIN_FIELD_BASE(0, 0, IOCFG_RB_BASE, 0x10, 0x10, 21, 3),
+	PIN_FIELD_BASE(1, 2, IOCFG_LT_BASE, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(3, 4, IOCFG_LB_BASE, 0x00, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, IOCFG_RB_BASE, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(6, 6, IOCFG_RB_BASE, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(7, 10, IOCFG_LT_BASE, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(11, 12, IOCFG_RB_BASE, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(13, 14, IOCFG_RB_BASE, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(15, 20, IOCFG_RB_BASE, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(21, 23, IOCFG_RT_BASE, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(24, 24, IOCFG_RT_BASE, 0x10, 0x10, 24, 3),
+	PIN_FIELD_BASE(25, 25, IOCFG_RT_BASE, 0x10, 0x10, 21, 3),
+	PIN_FIELD_BASE(26, 27, IOCFG_RT_BASE, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(28, 28, IOCFG_RT_BASE, 0x10, 0x10, 27, 3),
+	PIN_FIELD_BASE(29, 29, IOCFG_RT_BASE, 0x20, 0x10, 0, 3),
+	PIN_FIELD_BASE(30, 30, IOCFG_RT_BASE, 0x20, 0x10, 9, 3),
+	PIN_FIELD_BASE(31, 31, IOCFG_RT_BASE, 0x20, 0x10, 6, 3),
+	PIN_FIELD_BASE(32, 32, IOCFG_RT_BASE, 0x20, 0x10, 3, 3),
+	PIN_FIELD_BASE(33, 33, IOCFG_LT_BASE, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(34, 34, IOCFG_LT_BASE, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(35, 35, IOCFG_LT_BASE, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(36, 37, IOCFG_LT_BASE, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(38, 38, IOCFG_LT_BASE, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(39, 39, IOCFG_RB_BASE, 0x10, 0x10, 27, 3),
+	PIN_FIELD_BASE(40, 40, IOCFG_RB_BASE, 0x20, 0x10, 0, 3),
+	PIN_FIELD_BASE(41, 41, IOCFG_RB_BASE, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(42, 43, IOCFG_RB_BASE, 0x20, 0x10, 9, 3),
+	PIN_FIELD_BASE(44, 45, IOCFG_RB_BASE, 0x20, 0x10, 3, 3),
+	PIN_FIELD_BASE(46, 47, IOCFG_RB_BASE, 0x20, 0x10, 21, 3),
+	PIN_FIELD_BASE(48, 49, IOCFG_RB_BASE, 0x20, 0x10, 15, 3),
+	PIN_FIELD_BASE(50, 57, IOCFG_RT_BASE, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(58, 58, IOCFG_RT_BASE, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(59, 59, IOCFG_RT_BASE, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(60, 61, IOCFG_RT_BASE, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(62, 62, IOCFG_RB_BASE, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(63, 63, IOCFG_RB_BASE, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(64, 64, IOCFG_RB_BASE, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(65, 65, IOCFG_RB_BASE, 0x10, 0x10, 18, 3),
+	PIN_FIELD_BASE(66, 68, IOCFG_LB_BASE, 0x00, 0x10, 2, 3),
+	PIN_FIELD_BASE(69, 69, IOCFG_TR_BASE, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(70, 70, IOCFG_TR_BASE, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(71, 71, IOCFG_TR_BASE, 0x10, 0x10, 18, 3),
+	PIN_FIELD_BASE(72, 73, IOCFG_TR_BASE, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(74, 77, IOCFG_TR_BASE, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(78, 79, IOCFG_TR_BASE, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(80, 80, IOCFG_TR_BASE, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(81, 84, IOCFG_TR_BASE, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(85, 85, IOCFG_TR_BASE, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(86, 86, IOCFG_TL_BASE, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(87, 87, IOCFG_TL_BASE, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(88, 88, IOCFG_TL_BASE, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(89, 90, IOCFG_TL_BASE, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(91, 94, IOCFG_TL_BASE, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(95, 96, IOCFG_TL_BASE, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(97, 98, IOCFG_TL_BASE, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(99, 100, IOCFG_TL_BASE, 0x10, 0x10, 2, 3),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_pupd_range[] = {
+	PIN_FIELD_BASE(0, 0, IOCFG_RB_BASE, 0x60, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 2, IOCFG_LT_BASE, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(3, 4, IOCFG_LB_BASE, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 6, IOCFG_RB_BASE, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(7, 10, IOCFG_LT_BASE, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(11, 14, IOCFG_RB_BASE, 0x60, 0x10, 8, 1),
+	PIN_FIELD_BASE(15, 20, IOCFG_RB_BASE, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(21, 23, IOCFG_RT_BASE, 0x40, 0x10, 12, 1),
+	PIN_FIELD_BASE(24, 24, IOCFG_RT_BASE, 0x40, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, IOCFG_RT_BASE, 0x40, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 27, IOCFG_RT_BASE, 0x40, 0x10, 15, 1),
+	PIN_FIELD_BASE(28, 29, IOCFG_RT_BASE, 0x40, 0x10, 19, 1),
+	PIN_FIELD_BASE(30, 30, IOCFG_RT_BASE, 0x40, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, IOCFG_RT_BASE, 0x40, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, IOCFG_RT_BASE, 0x40, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, IOCFG_LT_BASE, 0x30, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, IOCFG_LT_BASE, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, IOCFG_LT_BASE, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 37, IOCFG_LT_BASE, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(38, 38, IOCFG_LT_BASE, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 40, IOCFG_RB_BASE, 0x60, 0x10, 18, 1),
+	PIN_FIELD_BASE(41, 41, IOCFG_RB_BASE, 0x60, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 43, IOCFG_RB_BASE, 0x60, 0x10, 23, 1),
+	PIN_FIELD_BASE(44, 45, IOCFG_RB_BASE, 0x60, 0x10, 21, 1),
+	PIN_FIELD_BASE(46, 47, IOCFG_RB_BASE, 0x60, 0x10, 27, 1),
+	PIN_FIELD_BASE(48, 49, IOCFG_RB_BASE, 0x60, 0x10, 25, 1),
+	PIN_FIELD_BASE(50, 57, IOCFG_RT_BASE, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(58, 58, IOCFG_RT_BASE, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, IOCFG_RT_BASE, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 61, IOCFG_RT_BASE, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(62, 62, IOCFG_RB_BASE, 0x60, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, IOCFG_RB_BASE, 0x60, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, IOCFG_RB_BASE, 0x60, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, IOCFG_RB_BASE, 0x60, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 68, IOCFG_LB_BASE, 0x40, 0x10, 2, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_r0_range[] = {
+	PIN_FIELD_BASE(0, 0, IOCFG_RB_BASE, 0x70, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 2, IOCFG_LT_BASE, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(3, 4, IOCFG_LB_BASE, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 6, IOCFG_RB_BASE, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(7, 10, IOCFG_LT_BASE, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(11, 14, IOCFG_RB_BASE, 0x70, 0x10, 8, 1),
+	PIN_FIELD_BASE(15, 20, IOCFG_RB_BASE, 0x70, 0x10, 2, 1),
+	PIN_FIELD_BASE(21, 23, IOCFG_RT_BASE, 0x50, 0x10, 12, 1),
+	PIN_FIELD_BASE(24, 24, IOCFG_RT_BASE, 0x50, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, IOCFG_RT_BASE, 0x50, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 27, IOCFG_RT_BASE, 0x50, 0x10, 15, 1),
+	PIN_FIELD_BASE(28, 29, IOCFG_RT_BASE, 0x50, 0x10, 19, 1),
+	PIN_FIELD_BASE(30, 30, IOCFG_RT_BASE, 0x50, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, IOCFG_RT_BASE, 0x50, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, IOCFG_RT_BASE, 0x50, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, IOCFG_LT_BASE, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, IOCFG_LT_BASE, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, IOCFG_LT_BASE, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 37, IOCFG_LT_BASE, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(38, 38, IOCFG_LT_BASE, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 40, IOCFG_RB_BASE, 0x70, 0x10, 18, 1),
+	PIN_FIELD_BASE(41, 41, IOCFG_RB_BASE, 0x70, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 43, IOCFG_RB_BASE, 0x70, 0x10, 23, 1),
+	PIN_FIELD_BASE(44, 45, IOCFG_RB_BASE, 0x70, 0x10, 21, 1),
+	PIN_FIELD_BASE(46, 47, IOCFG_RB_BASE, 0x70, 0x10, 27, 1),
+	PIN_FIELD_BASE(48, 49, IOCFG_RB_BASE, 0x70, 0x10, 25, 1),
+	PIN_FIELD_BASE(50, 57, IOCFG_RT_BASE, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(58, 58, IOCFG_RT_BASE, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, IOCFG_RT_BASE, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 61, IOCFG_RT_BASE, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(62, 62, IOCFG_RB_BASE, 0x70, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, IOCFG_RB_BASE, 0x70, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, IOCFG_RB_BASE, 0x70, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, IOCFG_RB_BASE, 0x70, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 68, IOCFG_LB_BASE, 0x50, 0x10, 2, 1),
+};
+
+static const struct mtk_pin_field_calc mt7986_pin_r1_range[] = {
+	PIN_FIELD_BASE(0, 0, IOCFG_RB_BASE, 0x80, 0x10, 17, 1),
+	PIN_FIELD_BASE(1, 2, IOCFG_LT_BASE, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(3, 4, IOCFG_LB_BASE, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 6, IOCFG_RB_BASE, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(7, 10, IOCFG_LT_BASE, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(11, 14, IOCFG_RB_BASE, 0x80, 0x10, 8, 1),
+	PIN_FIELD_BASE(15, 20, IOCFG_RB_BASE, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(21, 23, IOCFG_RT_BASE, 0x60, 0x10, 12, 1),
+	PIN_FIELD_BASE(24, 24, IOCFG_RT_BASE, 0x60, 0x10, 18, 1),
+	PIN_FIELD_BASE(25, 25, IOCFG_RT_BASE, 0x60, 0x10, 17, 1),
+	PIN_FIELD_BASE(26, 27, IOCFG_RT_BASE, 0x60, 0x10, 15, 1),
+	PIN_FIELD_BASE(28, 29, IOCFG_RT_BASE, 0x60, 0x10, 19, 1),
+	PIN_FIELD_BASE(30, 30, IOCFG_RT_BASE, 0x60, 0x10, 23, 1),
+	PIN_FIELD_BASE(31, 31, IOCFG_RT_BASE, 0x60, 0x10, 22, 1),
+	PIN_FIELD_BASE(32, 32, IOCFG_RT_BASE, 0x60, 0x10, 21, 1),
+	PIN_FIELD_BASE(33, 33, IOCFG_LT_BASE, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(34, 34, IOCFG_LT_BASE, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(35, 35, IOCFG_LT_BASE, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(36, 37, IOCFG_LT_BASE, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(38, 38, IOCFG_LT_BASE, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(39, 40, IOCFG_RB_BASE, 0x80, 0x10, 18, 1),
+	PIN_FIELD_BASE(41, 41, IOCFG_RB_BASE, 0x80, 0x10, 12, 1),
+	PIN_FIELD_BASE(42, 43, IOCFG_RB_BASE, 0x80, 0x10, 23, 1),
+	PIN_FIELD_BASE(44, 45, IOCFG_RB_BASE, 0x80, 0x10, 21, 1),
+	PIN_FIELD_BASE(46, 47, IOCFG_RB_BASE, 0x80, 0x10, 27, 1),
+	PIN_FIELD_BASE(48, 49, IOCFG_RB_BASE, 0x80, 0x10, 25, 1),
+	PIN_FIELD_BASE(50, 57, IOCFG_RT_BASE, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(58, 58, IOCFG_RT_BASE, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(59, 59, IOCFG_RT_BASE, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(60, 61, IOCFG_RT_BASE, 0x60, 0x10, 10, 1),
+	PIN_FIELD_BASE(62, 62, IOCFG_RB_BASE, 0x80, 0x10, 15, 1),
+	PIN_FIELD_BASE(63, 63, IOCFG_RB_BASE, 0x80, 0x10, 14, 1),
+	PIN_FIELD_BASE(64, 64, IOCFG_RB_BASE, 0x80, 0x10, 13, 1),
+	PIN_FIELD_BASE(65, 65, IOCFG_RB_BASE, 0x80, 0x10, 16, 1),
+	PIN_FIELD_BASE(66, 68, IOCFG_LB_BASE, 0x60, 0x10, 2, 1),
+};
+
+static const struct mtk_pin_reg_calc mt7986_reg_cals[] = {
+	[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7986_pin_mode_range),
+	[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7986_pin_dir_range),
+	[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7986_pin_di_range),
+	[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7986_pin_do_range),
+	[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7986_pin_smt_range),
+	[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7986_pin_ies_range),
+	[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7986_pin_drv_range),
+	[PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7986_pin_pu_range),
+	[PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7986_pin_pd_range),
+	[PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7986_pin_pupd_range),
+	[PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7986_pin_r0_range),
+	[PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7986_pin_r1_range),
+};
+
+static const struct mtk_pin_desc mt7986_pins[] = {
+	MT7986_TYPE0_PIN(0, "SYS_WATCHDOG"),
+	MT7986_TYPE0_PIN(1, "WF2G_LED"),
+	MT7986_TYPE0_PIN(2, "WF5G_LED"),
+	MT7986_TYPE0_PIN(3, "I2C_SCL"),
+	MT7986_TYPE0_PIN(4, "I2C_SDA"),
+	MT7986_TYPE0_PIN(5, "GPIO_0"),
+	MT7986_TYPE0_PIN(6, "GPIO_1"),
+	MT7986_TYPE0_PIN(7, "GPIO_2"),
+	MT7986_TYPE0_PIN(8, "GPIO_3"),
+	MT7986_TYPE0_PIN(9, "GPIO_4"),
+	MT7986_TYPE0_PIN(10, "GPIO_5"),
+	MT7986_TYPE0_PIN(11, "GPIO_6"),
+	MT7986_TYPE0_PIN(12, "GPIO_7"),
+	MT7986_TYPE0_PIN(13, "GPIO_8"),
+	MT7986_TYPE0_PIN(14, "GPIO_9"),
+	MT7986_TYPE0_PIN(15, "GPIO_10"),
+	MT7986_TYPE0_PIN(16, "GPIO_11"),
+	MT7986_TYPE0_PIN(17, "GPIO_12"),
+	MT7986_TYPE0_PIN(18, "GPIO_13"),
+	MT7986_TYPE0_PIN(19, "GPIO_14"),
+	MT7986_TYPE0_PIN(20, "GPIO_15"),
+	MT7986_TYPE0_PIN(21, "PWM0"),
+	MT7986_TYPE0_PIN(22, "PWM1"),
+	MT7986_TYPE0_PIN(23, "SPI0_CLK"),
+	MT7986_TYPE0_PIN(24, "SPI0_MOSI"),
+	MT7986_TYPE0_PIN(25, "SPI0_MISO"),
+	MT7986_TYPE0_PIN(26, "SPI0_CS"),
+	MT7986_TYPE0_PIN(27, "SPI0_HOLD"),
+	MT7986_TYPE0_PIN(28, "SPI0_WP"),
+	MT7986_TYPE0_PIN(29, "SPI1_CLK"),
+	MT7986_TYPE0_PIN(30, "SPI1_MOSI"),
+	MT7986_TYPE0_PIN(31, "SPI1_MISO"),
+	MT7986_TYPE0_PIN(32, "SPI1_CS"),
+	MT7986_TYPE0_PIN(33, "SPI2_CLK"),
+	MT7986_TYPE0_PIN(34, "SPI2_MOSI"),
+	MT7986_TYPE0_PIN(35, "SPI2_MISO"),
+	MT7986_TYPE0_PIN(36, "SPI2_CS"),
+	MT7986_TYPE0_PIN(37, "SPI2_HOLD"),
+	MT7986_TYPE0_PIN(38, "SPI2_WP"),
+	MT7986_TYPE0_PIN(39, "UART0_RXD"),
+	MT7986_TYPE0_PIN(40, "UART0_TXD"),
+	MT7986_TYPE0_PIN(41, "PCIE_PERESET_N"),
+	MT7986_TYPE0_PIN(42, "UART1_RXD"),
+	MT7986_TYPE0_PIN(43, "UART1_TXD"),
+	MT7986_TYPE0_PIN(44, "UART1_CTS"),
+	MT7986_TYPE0_PIN(45, "UART1_RTS"),
+	MT7986_TYPE0_PIN(46, "UART2_RXD"),
+	MT7986_TYPE0_PIN(47, "UART2_TXD"),
+	MT7986_TYPE0_PIN(48, "UART2_CTS"),
+	MT7986_TYPE0_PIN(49, "UART2_RTS"),
+	MT7986_TYPE0_PIN(50, "EMMC_DATA_0"),
+	MT7986_TYPE0_PIN(51, "EMMC_DATA_1"),
+	MT7986_TYPE0_PIN(52, "EMMC_DATA_2"),
+	MT7986_TYPE0_PIN(53, "EMMC_DATA_3"),
+	MT7986_TYPE0_PIN(54, "EMMC_DATA_4"),
+	MT7986_TYPE0_PIN(55, "EMMC_DATA_5"),
+	MT7986_TYPE0_PIN(56, "EMMC_DATA_6"),
+	MT7986_TYPE0_PIN(57, "EMMC_DATA_7"),
+	MT7986_TYPE0_PIN(58, "EMMC_CMD"),
+	MT7986_TYPE0_PIN(59, "EMMC_CK"),
+	MT7986_TYPE0_PIN(60, "EMMC_DSL"),
+	MT7986_TYPE0_PIN(61, "EMMC_RSTB"),
+	MT7986_TYPE0_PIN(62, "PCM_DTX"),
+	MT7986_TYPE0_PIN(63, "PCM_DRX"),
+	MT7986_TYPE0_PIN(64, "PCM_CLK"),
+	MT7986_TYPE0_PIN(65, "PCM_FS"),
+	MT7986_TYPE0_PIN(66, "MT7531_INT"),
+	MT7986_TYPE0_PIN(67, "SMI_MDC"),
+	MT7986_TYPE0_PIN(68, "SMI_MDIO"),
+	MT7986_TYPE1_PIN(69, "WF0_DIG_RESETB"),
+	MT7986_TYPE1_PIN(70, "WF0_CBA_RESETB"),
+	MT7986_TYPE1_PIN(71, "WF0_XO_REQ"),
+	MT7986_TYPE1_PIN(72, "WF0_TOP_CLK"),
+	MT7986_TYPE1_PIN(73, "WF0_TOP_DATA"),
+	MT7986_TYPE1_PIN(74, "WF0_HB1"),
+	MT7986_TYPE1_PIN(75, "WF0_HB2"),
+	MT7986_TYPE1_PIN(76, "WF0_HB3"),
+	MT7986_TYPE1_PIN(77, "WF0_HB4"),
+	MT7986_TYPE1_PIN(78, "WF0_HB0"),
+	MT7986_TYPE1_PIN(79, "WF0_HB0_B"),
+	MT7986_TYPE1_PIN(80, "WF0_HB5"),
+	MT7986_TYPE1_PIN(81, "WF0_HB6"),
+	MT7986_TYPE1_PIN(82, "WF0_HB7"),
+	MT7986_TYPE1_PIN(83, "WF0_HB8"),
+	MT7986_TYPE1_PIN(84, "WF0_HB9"),
+	MT7986_TYPE1_PIN(85, "WF0_HB10"),
+	MT7986_TYPE1_PIN(86, "WF1_DIG_RESETB"),
+	MT7986_TYPE1_PIN(87, "WF1_CBA_RESETB"),
+	MT7986_TYPE1_PIN(88, "WF1_XO_REQ"),
+	MT7986_TYPE1_PIN(89, "WF1_TOP_CLK"),
+	MT7986_TYPE1_PIN(90, "WF1_TOP_DATA"),
+	MT7986_TYPE1_PIN(91, "WF1_HB1"),
+	MT7986_TYPE1_PIN(92, "WF1_HB2"),
+	MT7986_TYPE1_PIN(93, "WF1_HB3"),
+	MT7986_TYPE1_PIN(94, "WF1_HB4"),
+	MT7986_TYPE1_PIN(95, "WF1_HB0"),
+	MT7986_TYPE1_PIN(96, "WF1_HB0_B"),
+	MT7986_TYPE1_PIN(97, "WF1_HB5"),
+	MT7986_TYPE1_PIN(98, "WF1_HB6"),
+	MT7986_TYPE1_PIN(99, "WF1_HB7"),
+	MT7986_TYPE1_PIN(100, "WF1_HB8"),
+};
+
+static const struct mtk_io_type_desc mt7986_io_type_desc[] = {
+	[IO_TYPE_GRP0] = {
+		.name = "18OD33",
+		.bias_set = mtk_pinconf_bias_set_pupd_r1_r0,
+		.drive_set = mtk_pinconf_drive_set_v1,
+		.input_enable = mtk_pinconf_input_enable_v1,
+	},
+	[IO_TYPE_GRP1] = {
+		.name = "18A01",
+		.bias_set = mtk_pinconf_bias_set_pu_pd,
+		.drive_set = mtk_pinconf_drive_set_v1,
+		.input_enable = mtk_pinconf_input_enable_v1,
+	},
+};
+
+/* List all groups consisting of these pins dedicated to the enablement of
+ * certain hardware block and the corresponding mode for all of the pins.
+ * The hardware probably has multiple combinations of these pinouts.
+ */
+
+static int mt7986_watchdog_pins[] = { 0, };
+static int mt7986_watchdog_funcs[] = { 1, };
+
+static int mt7986_wifi_led_pins[] = { 1, 2, };
+static int mt7986_wifi_led_funcs[] = { 1, 1, };
+
+static int mt7986_i2c_pins[] = { 3, 4, };
+static int mt7986_i2c_funcs[] = { 1, 1, };
+
+static int mt7986_uart1_0_pins[] = { 7, 8, 9, 10, };
+static int mt7986_uart1_0_funcs[] = { 3, 3, 3, 3, };
+
+static int mt7986_spi1_0_pins[] = { 11, 12, 13, 14, };
+static int mt7986_spi1_0_funcs[] = { 3, 3, 3, 3, };
+
+static int mt7986_pwm1_1_pins[] = { 20, };
+static int mt7986_pwm1_1_funcs[] = { 2, };
+
+static int mt7986_pwm0_pins[] = { 21, };
+static int mt7986_pwm0_funcs[] = { 1, };
+
+static int mt7986_pwm1_0_pins[] = { 22, };
+static int mt7986_pwm1_0_funcs[] = { 1, };
+
+static int mt7986_emmc_45_pins[] = {
+	22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, };
+static int mt7986_emmc_45_funcs[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, };
+
+static int mt7986_snfi_pins[] = { 23, 24, 25, 26, 27, 28, };
+static int mt7986_snfi_funcs[] = { 1, 1, 1, 1, 1, 1, };
+
+static int mt7986_spi1_1_pins[] = { 23, 24, 25, 26, };
+static int mt7986_spi1_1_funcs[] = { 3, 3, 3, 3, };
+
+static int mt7986_uart1_1_pins[] = { 23, 24, 25, 26, };
+static int mt7986_uart1_1_funcs[] = { 4, 4, 4, 4, };
+
+static int mt7986_spi1_2_pins[] = { 29, 30, 31, 32, };
+static int mt7986_spi1_2_funcs[] = { 1, 1, 1, 1, };
+
+static int mt7986_uart1_2_pins[] = { 29, 30, 31, 32, };
+static int mt7986_uart1_2_funcs[] = { 3, 3, 3, 3, };
+
+static int mt7986_uart2_0_pins[] = { 29, 30, 31, 32, };
+static int mt7986_uart2_0_funcs[] = { 4, 4, 4, 4, };
+
+static int mt7986_spi0_pins[] = { 33, 34, 35, 36, };
+static int mt7986_spi0_funcs[] = { 1, 1, 1, 1, };
+
+static int mt7986_spi0_wp_hold_pins[] = { 37, 38, };
+static int mt7986_spi0_wp_hold_funcs[] = { 1, 1, };
+
+static int mt7986_uart2_1_pins[] = { 33, 34, 35, 36, };
+static int mt7986_uart2_1_funcs[] = { 3, 3, 3, 3, };
+
+static int mt7986_uart1_3_rx_tx_pins[] = { 35, 36, };
+static int mt7986_uart1_3_rx_tx_funcs[] = { 2, 2, };
+
+static int mt7986_uart1_3_cts_rts_pins[] = { 37, 38, };
+static int mt7986_uart1_3_cts_rts_funcs[] = { 2, 2, };
+
+static int mt7986_spi1_3_pins[] = { 33, 34, 35, 36, };
+static int mt7986_spi1_3_funcs[] = { 4, 4, 4, 4, };
+
+static int mt7986_uart0_pins[] = { 39, 40, };
+static int mt7986_uart0_funcs[] = { 1, 1, };
+
+static int mt7986_pcie_reset_pins[] = { 41, };
+static int mt7986_pcie_reset_funcs[] = { 1, };
+
+static int mt7986_uart1_pins[] = { 42, 43, 44, 45, };
+static int mt7986_uart1_funcs[] = { 1, 1, 1, 1, };
+
+static int mt7986_uart2_pins[] = { 46, 47, 48, 49, };
+static int mt7986_uart2_funcs[] = { 1, 1, 1, 1, };
+
+static int mt7986_emmc_51_pins[] = {
+	50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, };
+static int mt7986_emmc_51_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+static int mt7986_pcm_pins[] = { 62, 63, 64, 65, };
+static int mt7986_pcm_funcs[] = { 1, 1, 1, 1, };
+
+static int mt7986_i2s_pins[] = { 62, 63, 64, 65, };
+static int mt7986_i2s_funcs[] = { 1, 1, 1, 1, };
+
+static int mt7986_switch_int_pins[] = { 66, };
+static int mt7986_switch_int_funcs[] = { 1, };
+
+static int mt7986_mdc_mdio_pins[] = { 67, 68, };
+static int mt7986_mdc_mdio_funcs[] = { 1, 1, };
+
+static int mt7986_wf_2g_pins[] = {74, 75, 76, 77, 78, 79, 80, 81, 82, 83, };
+static int mt7986_wf_2g_funcs[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+static int mt7986_wf_5g_pins[] = {91, 92, 93, 94, 95, 96, 97, 98, 99, 100, };
+static int mt7986_wf_5g_funcs[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+static int mt7986_wf_dbdc_pins[] = {
+	74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, };
+static int mt7986_wf_dbdc_funcs[] = {
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, };
+
+static int mt7986_pcie_clk_pins[] = { 9, };
+static int mt7986_pcie_clk_funcs[] = { 1, };
+
+static int mt7986_pcie_wake_pins[] = { 10, };
+static int mt7986_pcie_wake_funcs[] = { 1, };
+
+static const struct mtk_group_desc mt7986_groups[] = {
+	PINCTRL_PIN_GROUP("watchdog", mt7986_watchdog),
+	PINCTRL_PIN_GROUP("wifi_led", mt7986_wifi_led),
+	PINCTRL_PIN_GROUP("i2c", mt7986_i2c),
+	PINCTRL_PIN_GROUP("uart1_0", mt7986_uart1_0),
+	PINCTRL_PIN_GROUP("pcie_clk", mt7986_pcie_clk),
+	PINCTRL_PIN_GROUP("pcie_wake", mt7986_pcie_wake),
+	PINCTRL_PIN_GROUP("spi1_0", mt7986_spi1_0),
+	PINCTRL_PIN_GROUP("pwm1_1", mt7986_pwm1_1),
+	PINCTRL_PIN_GROUP("pwm0", mt7986_pwm0),
+	PINCTRL_PIN_GROUP("pwm1_0", mt7986_pwm1_0),
+	PINCTRL_PIN_GROUP("emmc_45", mt7986_emmc_45),
+	PINCTRL_PIN_GROUP("snfi", mt7986_snfi),
+	PINCTRL_PIN_GROUP("spi1_1", mt7986_spi1_1),
+	PINCTRL_PIN_GROUP("uart1_1", mt7986_uart1_1),
+	PINCTRL_PIN_GROUP("spi1_2", mt7986_spi1_2),
+	PINCTRL_PIN_GROUP("uart1_2", mt7986_uart1_2),
+	PINCTRL_PIN_GROUP("uart2_0", mt7986_uart2_0),
+	PINCTRL_PIN_GROUP("spi0", mt7986_spi0),
+	PINCTRL_PIN_GROUP("spi0_wp_hold", mt7986_spi0_wp_hold),
+	PINCTRL_PIN_GROUP("uart2_1", mt7986_uart2_1),
+	PINCTRL_PIN_GROUP("uart1_3_rx_tx", mt7986_uart1_3_rx_tx),
+	PINCTRL_PIN_GROUP("uart1_3_cts_rts", mt7986_uart1_3_cts_rts),
+	PINCTRL_PIN_GROUP("spi1_3", mt7986_spi1_3),
+	PINCTRL_PIN_GROUP("uart0", mt7986_uart0),
+	PINCTRL_PIN_GROUP("switch_int", mt7986_switch_int),
+	PINCTRL_PIN_GROUP("mdc_mdio", mt7986_mdc_mdio),
+	PINCTRL_PIN_GROUP("pcie_pereset", mt7986_pcie_reset),
+	PINCTRL_PIN_GROUP("uart1", mt7986_uart1),
+	PINCTRL_PIN_GROUP("uart2", mt7986_uart2),
+	PINCTRL_PIN_GROUP("emmc_51", mt7986_emmc_51),
+	PINCTRL_PIN_GROUP("pcm", mt7986_pcm),
+	PINCTRL_PIN_GROUP("i2s", mt7986_i2s),
+	PINCTRL_PIN_GROUP("wf_2g", mt7986_wf_2g),
+	PINCTRL_PIN_GROUP("wf_5g", mt7986_wf_5g),
+	PINCTRL_PIN_GROUP("wf_dbdc", mt7986_wf_dbdc),
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+
+static const char *const mt7986_audio_groups[] = { "pcm", "i2s" };
+static const char *const mt7986_emmc_groups[] = { "emmc_45", "emmc_51", };
+static const char *const mt7986_ethernet_groups[] = { "switch_int",
+	"mdc_mdio", };
+static const char *const mt7986_i2c_groups[] = { "i2c", };
+static const char *const mt7986_led_groups[] = { "wifi_led", };
+static const char *const mt7986_flash_groups[] = { "snfi", };
+static const char *const mt7986_pcie_groups[] = { "pcie_clk", "pcie_wake",
+	"pcie_pereset" };
+static const char *const mt7986_pwm_groups[] = { "pwm0", "pwm1_0", "pwm1_1", };
+static const char *const mt7986_spi_groups[] = { "spi0", "spi0_wp_hold",
+	"spi1_0", "spi1_1", "spi1_2", "spi1_3", };
+static const char *const mt7986_uart_groups[] = { "uart1_0", "uart1_1",
+	"uart1_2", "uart1_3_rx_tx", "uart1_3_cts_rts", "uart2_0", "uart2_1",
+	"uart0", "uart1", "uart2", };
+static const char *const mt7986_wdt_groups[] = { "watchdog", };
+static const char *const mt7986_wf_groups[] = { "wf_2g", "wf_5g", "wf_dbdc", };
+
+static const struct mtk_function_desc mt7986_functions[] = {
+	{"audio", mt7986_audio_groups, ARRAY_SIZE(mt7986_audio_groups)},
+	{"emmc", mt7986_emmc_groups, ARRAY_SIZE(mt7986_emmc_groups)},
+	{"eth", mt7986_ethernet_groups, ARRAY_SIZE(mt7986_ethernet_groups)},
+	{"i2c", mt7986_i2c_groups, ARRAY_SIZE(mt7986_i2c_groups)},
+	{"led", mt7986_led_groups, ARRAY_SIZE(mt7986_led_groups)},
+	{"flash", mt7986_flash_groups, ARRAY_SIZE(mt7986_flash_groups)},
+	{"pcie", mt7986_pcie_groups, ARRAY_SIZE(mt7986_pcie_groups)},
+	{"pwm", mt7986_pwm_groups, ARRAY_SIZE(mt7986_pwm_groups)},
+	{"spi", mt7986_spi_groups, ARRAY_SIZE(mt7986_spi_groups)},
+	{"uart", mt7986_uart_groups, ARRAY_SIZE(mt7986_uart_groups)},
+	{"watchdog", mt7986_wdt_groups, ARRAY_SIZE(mt7986_wdt_groups)},
+	{"wifi", mt7986_wf_groups, ARRAY_SIZE(mt7986_wf_groups)},
+};
+
+static struct mtk_pinctrl_soc mt7986_data = {
+	.name = "mt7986_pinctrl",
+	.reg_cal = mt7986_reg_cals,
+	.pins = mt7986_pins,
+	.npins = ARRAY_SIZE(mt7986_pins),
+	.grps = mt7986_groups,
+	.ngrps = ARRAY_SIZE(mt7986_groups),
+	.funcs = mt7986_functions,
+	.nfuncs = ARRAY_SIZE(mt7986_functions),
+	.io_type = mt7986_io_type_desc,
+	.ntype = ARRAY_SIZE(mt7986_io_type_desc),
+	.gpio_mode = 0,
+	.base_names = mt7986_pinctrl_register_base_names,
+	.nbase_names = ARRAY_SIZE(mt7986_pinctrl_register_base_names),
+	.base_calc = 1,
+};
+
+static int mtk_pinctrl_mt7986_probe(struct udevice *dev)
+{
+	return mtk_pinctrl_common_probe(dev, &mt7986_data);
+}
+
+static const struct udevice_id mt7986_pctrl_match[] = {
+	{.compatible = "mediatek,mt7986-pinctrl"},
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mt7986_pinctrl) = {
+	.name = "mt7986_pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = mt7986_pctrl_match,
+	.ops = &mtk_pinctrl_ops,
+	.probe = mtk_pinctrl_mt7986_probe,
+	.priv_auto = sizeof(struct mtk_pinctrl_priv),
+};
diff --git a/drivers/pwm/pwm-mtk.c b/drivers/pwm/pwm-mtk.c
index aee1d82..605142e 100644
--- a/drivers/pwm/pwm-mtk.c
+++ b/drivers/pwm/pwm-mtk.c
@@ -29,13 +29,23 @@
 
 #define NSEC_PER_SEC 1000000000L
 
-static const unsigned int mtk_pwm_reg_offset[] = {
+enum mtk_pwm_reg_ver {
+	PWM_REG_V1,
+	PWM_REG_V2,
+};
+
+static const unsigned int mtk_pwm_reg_offset_v1[] = {
 	0x0010, 0x0050, 0x0090, 0x00d0, 0x0110, 0x0150, 0x0190, 0x0220
 };
 
+static const unsigned int mtk_pwm_reg_offset_v2[] = {
+	0x0080, 0x00c0, 0x0100, 0x0140, 0x0180, 0x01c0, 0x0200, 0x0240
+};
+
 struct mtk_pwm_soc {
 	unsigned int num_pwms;
 	bool pwm45_fixup;
+	enum mtk_pwm_reg_ver reg_ver;
 };
 
 struct mtk_pwm_priv {
@@ -49,7 +59,16 @@
 static void mtk_pwm_w32(struct udevice *dev, uint channel, uint reg, uint val)
 {
 	struct mtk_pwm_priv *priv = dev_get_priv(dev);
-	u32 offset = mtk_pwm_reg_offset[channel];
+	u32 offset;
+
+	switch (priv->soc->reg_ver) {
+	case PWM_REG_V2:
+		offset = mtk_pwm_reg_offset_v2[channel];
+		break;
+
+	default:
+		offset = mtk_pwm_reg_offset_v1[channel];
+	}
 
 	writel(val, priv->base + offset + reg);
 }
@@ -159,22 +178,39 @@
 static const struct mtk_pwm_soc mt7622_data = {
 	.num_pwms = 6,
 	.pwm45_fixup = false,
+	.reg_ver = PWM_REG_V1,
 };
 
 static const struct mtk_pwm_soc mt7623_data = {
 	.num_pwms = 5,
 	.pwm45_fixup = true,
+	.reg_ver = PWM_REG_V1,
 };
 
 static const struct mtk_pwm_soc mt7629_data = {
 	.num_pwms = 1,
 	.pwm45_fixup = false,
+	.reg_ver = PWM_REG_V1,
 };
 
+static const struct mtk_pwm_soc mt7981_data = {
+	.num_pwms = 2,
+	.pwm45_fixup = false,
+	.reg_ver = PWM_REG_V2,
+};
+
+static const struct mtk_pwm_soc mt7986_data = {
+	.num_pwms = 2,
+	.pwm45_fixup = false,
+	.reg_ver = PWM_REG_V1,
+};
+
 static const struct udevice_id mtk_pwm_ids[] = {
 	{ .compatible = "mediatek,mt7622-pwm", .data = (ulong)&mt7622_data },
 	{ .compatible = "mediatek,mt7623-pwm", .data = (ulong)&mt7623_data },
 	{ .compatible = "mediatek,mt7629-pwm", .data = (ulong)&mt7629_data },
+	{ .compatible = "mediatek,mt7981-pwm", .data = (ulong)&mt7981_data },
+	{ .compatible = "mediatek,mt7986-pwm", .data = (ulong)&mt7986_data },
 	{ }
 };
 
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 25194ee..d1b40c6 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -17,4 +17,5 @@
 
 ifdef CONFIG_SCSI
 obj-$(CONFIG_SANDBOX) += sandbox_scsi.o
+obj-$(CONFIG_SANDBOX) += scsi_emul.o
 endif
diff --git a/drivers/scsi/sandbox_scsi.c b/drivers/scsi/sandbox_scsi.c
index 39b969a..a7ac33c 100644
--- a/drivers/scsi/sandbox_scsi.c
+++ b/drivers/scsi/sandbox_scsi.c
@@ -7,19 +7,145 @@
  * that CONFIG_SCSI can be enabled for sandbox.
  */
 
+#define LOG_CATEGORY UCLASS_SCSI
+
 #include <common.h>
+#include <dm.h>
+#include <os.h>
+#include <malloc.h>
 #include <scsi.h>
+#include <scsi_emul.h>
+
+enum {
+	SANDBOX_SCSI_BLOCK_LEN		= 512,
+	SANDBOX_SCSI_BUF_SIZE		= 512,
+};
 
-int scsi_bus_reset(struct udevice *dev)
+/**
+ * struct sandbox_scsi_priv
+ *
+ * @eminfo: emulator state
+ * @pathanme: Path to the backing file, e.g. 'scsi.img'
+ * @fd: File descriptor of backing file
+ */
+struct sandbox_scsi_priv {
+	struct scsi_emul_info eminfo;
+	const char *pathname;
+	int fd;
+};
+
+static int sandbox_scsi_exec(struct udevice *dev, struct scsi_cmd *req)
 {
+	struct sandbox_scsi_priv *priv = dev_get_priv(dev);
+	struct scsi_emul_info *info = &priv->eminfo;
+	int ret;
+
+	if (req->lun || req->target)
+		return -EIO;
+	ret = sb_scsi_emul_command(info, req, req->cmdlen);
+	if (ret < 0) {
+		log_debug("SCSI command 0x%02x ret errno %d\n", req->cmd[0],
+			  ret);
+		return ret;
+	} else if (ret == SCSI_EMUL_DO_READ && priv->fd != -1) {
+		long bytes_read;
+
+		log_debug("read %x %x\n", info->seek_block, info->read_len);
+		os_lseek(priv->fd, info->seek_block * info->block_size,
+			 OS_SEEK_SET);
+		bytes_read = os_read(priv->fd, req->pdata, info->buff_used);
+		if (bytes_read < 0)
+			return bytes_read;
+		if (bytes_read != info->buff_used)
+			return -EIO;
+	} else if (!ret) {
+		req->pdata = info->buff;
+		info->phase = SCSIPH_STATUS;
+		log_debug("sending buf\n");
+	} else {
+		log_debug("error\n");
+		return -EIO;
+	}
+
 	return 0;
 }
 
-void scsi_init(void)
+static int sandbox_scsi_bus_reset(struct udevice *dev)
 {
+	/* Not implemented */
+
+	return 0;
 }
 
-int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
+static int sandbox_scsi_of_to_plat(struct udevice *dev)
 {
+	struct sandbox_scsi_priv *priv = dev_get_priv(dev);
+
+	priv->pathname = dev_read_string(dev, "sandbox,filepath");
+
 	return 0;
 }
+
+static int sandbox_scsi_probe(struct udevice *dev)
+{
+	struct scsi_plat *scsi_plat = dev_get_uclass_plat(dev);
+	struct sandbox_scsi_priv *priv = dev_get_priv(dev);
+	struct scsi_emul_info *info = &priv->eminfo;
+	int ret;
+
+	scsi_plat->max_id = 2;
+	scsi_plat->max_lun = 3;
+	scsi_plat->max_bytes_per_req = 1 << 20;
+
+	info->vendor = "SANDBOX";
+	info->product = "FAKE DISK";
+	info->buff = malloc(SANDBOX_SCSI_BUF_SIZE);
+	if (!info->buff)
+		return log_ret(-ENOMEM);
+	info->block_size = SANDBOX_SCSI_BLOCK_LEN;
+
+	if (priv->pathname) {
+		priv->fd = os_open(priv->pathname, OS_O_RDONLY);
+		if (priv->fd != -1) {
+			ret = os_get_filesize(priv->pathname, &info->file_size);
+			if (ret)
+				return log_msg_ret("sz", ret);
+		}
+	} else {
+		priv->fd = -1;
+	}
+	log_debug("filename: %s, fd %d\n", priv->pathname, priv->fd);
+
+	return 0;
+}
+
+static int sandbox_scsi_remove(struct udevice *dev)
+{
+	struct sandbox_scsi_priv *priv = dev_get_priv(dev);
+	struct scsi_emul_info *info = &priv->eminfo;
+
+	free(info->buff);
+
+	return 0;
+}
+
+struct scsi_ops sandbox_scsi_ops = {
+	.exec		= sandbox_scsi_exec,
+	.bus_reset	= sandbox_scsi_bus_reset,
+};
+
+static const struct udevice_id sanbox_scsi_ids[] = {
+	{ .compatible = "sandbox,scsi" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_scsi) = {
+	.name		= "sandbox_scsi",
+	.id		= UCLASS_SCSI,
+	.ops		= &sandbox_scsi_ops,
+	.of_match	= sanbox_scsi_ids,
+	.of_to_plat	= sandbox_scsi_of_to_plat,
+	.probe		= sandbox_scsi_probe,
+	.remove		= sandbox_scsi_remove,
+	.priv_auto	= sizeof(struct sandbox_scsi_priv),
+};
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 99be5ae..3e769b0 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -456,7 +456,7 @@
 {
 	dev_desc->lba = 0;
 	dev_desc->blksz = 0;
-	dev_desc->if_type = UCLASS_SCSI;
+	dev_desc->uclass_id = UCLASS_SCSI;
 	dev_desc->devnum = devnum;
 	dev_desc->part_type = PART_TYPE_UNKNOWN;
 
@@ -706,8 +706,8 @@
 };
 #else
 U_BOOT_LEGACY_BLK(scsi) = {
-	.if_typename	= "scsi",
-	.if_type	= UCLASS_SCSI,
+	.uclass_idname	= "scsi",
+	.uclass_id	= UCLASS_SCSI,
 	.max_devs	= SCSI_MAX_DEVICE,
 	.desc		= scsi_dev_desc,
 };
diff --git a/drivers/scsi/scsi_emul.c b/drivers/scsi/scsi_emul.c
new file mode 100644
index 0000000..5ba364b
--- /dev/null
+++ b/drivers/scsi/scsi_emul.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Emulation of enough SCSI commands to find and read from a unit
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * implementation of SCSI functions required so that CONFIG_SCSI can be enabled
+ * for sandbox.
+ */
+
+#define LOG_CATEGORY UCLASS_SCSI
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <scsi.h>
+#include <scsi_emul.h>
+
+int sb_scsi_emul_command(struct scsi_emul_info *info,
+			 const struct scsi_cmd *req, int len)
+{
+	int ret = 0;
+
+	info->buff_used = 0;
+	log_debug("emul %x\n", *req->cmd);
+	switch (*req->cmd) {
+	case SCSI_INQUIRY: {
+		struct scsi_inquiry_resp *resp = (void *)info->buff;
+
+		info->alloc_len = req->cmd[4];
+		memset(resp, '\0', sizeof(*resp));
+		resp->data_format = 1;
+		resp->additional_len = 0x1f;
+		strncpy(resp->vendor, info->vendor, sizeof(resp->vendor));
+		strncpy(resp->product, info->product, sizeof(resp->product));
+		strncpy(resp->revision, "1.0", sizeof(resp->revision));
+		info->buff_used = sizeof(*resp);
+		break;
+	}
+	case SCSI_TST_U_RDY:
+		break;
+	case SCSI_RD_CAPAC: {
+		struct scsi_read_capacity_resp *resp = (void *)info->buff;
+		uint blocks;
+
+		if (info->file_size)
+			blocks = info->file_size / info->block_size - 1;
+		else
+			blocks = 0;
+		resp->last_block_addr = cpu_to_be32(blocks);
+		resp->block_len = cpu_to_be32(info->block_size);
+		info->buff_used = sizeof(*resp);
+		break;
+	}
+	case SCSI_READ10: {
+		const struct scsi_read10_req *read_req = (void *)req;
+
+		info->seek_block = be32_to_cpu(read_req->lba);
+		info->read_len = be16_to_cpu(read_req->xfer_len);
+		info->buff_used = info->read_len * info->block_size;
+		ret = SCSI_EMUL_DO_READ;
+		break;
+	}
+	default:
+		debug("Command not supported: %x\n", req->cmd[0]);
+		ret = -EPROTONOSUPPORT;
+	}
+	if (ret >= 0)
+		info->phase = info->transfer_len ? SCSIPH_DATA : SCSIPH_STATUS;
+	log_debug("   - done %x: ret=%d\n", *req->cmd, ret);
+
+	return ret;
+}
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 0d43e9b..da3e1eb 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -238,6 +238,18 @@
 	} while (*str);
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static void _serial_flush(struct udevice *dev)
+{
+	struct dm_serial_ops *ops = serial_get_ops(dev);
+
+	if (!ops->pending)
+		return;
+	while (ops->pending(dev, false) > 0)
+		;
+}
+#endif
+
 static int __serial_getc(struct udevice *dev)
 {
 	struct dm_serial_ops *ops = serial_get_ops(dev);
@@ -314,6 +326,16 @@
 	if (gd->cur_serial_dev)
 		_serial_puts(gd->cur_serial_dev, str);
 }
+
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void serial_flush(void)
+{
+	if (!gd->cur_serial_dev)
+		return;
+
+	_serial_flush(gd->cur_serial_dev);
+}
+#endif
 
 int serial_getc(void)
 {
@@ -398,6 +420,13 @@
 	_serial_puts(sdev->priv, str);
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static void serial_stub_flush(struct stdio_dev *sdev)
+{
+	_serial_flush(sdev->priv);
+}
+#endif
+
 static int serial_stub_getc(struct stdio_dev *sdev)
 {
 	return _serial_getc(sdev->priv);
@@ -447,6 +476,7 @@
 			printf("## Switch baudrate to %d bps and press ENTER ...\n",
 			       baudrate);
 			udelay(50000);
+			flush();
 		}
 
 		gd->baudrate = baudrate;
@@ -520,6 +550,7 @@
 	sdev.priv = dev;
 	sdev.putc = serial_stub_putc;
 	sdev.puts = serial_stub_puts;
+	STDIO_DEV_ASSIGN_FLUSH(&sdev, serial_stub_flush);
 	sdev.getc = serial_stub_getc;
 	sdev.tstc = serial_stub_tstc;
 
diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c
index 22251c5..03b9e86 100644
--- a/drivers/serial/serial_mtk.c
+++ b/drivers/serial/serial_mtk.c
@@ -10,6 +10,7 @@
 #include <common.h>
 #include <div64.h>
 #include <dm.h>
+#include <dm/device_compat.h>
 #include <errno.h>
 #include <log.h>
 #include <serial.h>
@@ -70,27 +71,37 @@
 #define BAUD_ALLOW_MAX(baud)	((baud) + (baud) * 3 / 100)
 #define BAUD_ALLOW_MIX(baud)	((baud) - (baud) * 3 / 100)
 
+/* struct mtk_serial_priv -	Structure holding all information used by the
+ *				driver
+ * @regs:			Register base of the serial port
+ * @clk:			The baud clock device
+ * @fixed_clk_rate:		Fallback fixed baud clock rate if baud clock
+ *				device is not specified
+ * @force_highspeed:		Force using high-speed mode
+ */
 struct mtk_serial_priv {
 	struct mtk_serial_regs __iomem *regs;
-	u32 clock;
+	struct clk clk;
+	u32 fixed_clk_rate;
 	bool force_highspeed;
 };
 
-static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
+static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud,
+			       uint clk_rate)
 {
 	u32 quot, realbaud, samplecount = 1;
 
 	/* Special case for low baud clock */
-	if (baud <= 115200 && priv->clock <= 12000000) {
+	if (baud <= 115200 && clk_rate == 12000000) {
 		writel(3, &priv->regs->highspeed);
 
-		quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
+		quot = DIV_ROUND_CLOSEST(clk_rate, 256 * baud);
 		if (quot == 0)
 			quot = 1;
 
-		samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
+		samplecount = DIV_ROUND_CLOSEST(clk_rate, quot * baud);
 
-		realbaud = priv->clock / samplecount / quot;
+		realbaud = clk_rate / samplecount / quot;
 		if (realbaud > BAUD_ALLOW_MAX(baud) ||
 		    realbaud < BAUD_ALLOW_MIX(baud)) {
 			pr_info("baud %d can't be handled\n", baud);
@@ -104,7 +115,7 @@
 
 	if (baud <= 115200) {
 		writel(0, &priv->regs->highspeed);
-		quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
+		quot = DIV_ROUND_CLOSEST(clk_rate, 16 * baud);
 	} else if (baud <= 576000) {
 		writel(2, &priv->regs->highspeed);
 
@@ -112,13 +123,13 @@
 		if ((baud == 500000) || (baud == 576000))
 			baud = 460800;
 
-		quot = DIV_ROUND_UP(priv->clock, 4 * baud);
+		quot = DIV_ROUND_UP(clk_rate, 4 * baud);
 	} else {
 use_hs3:
 		writel(3, &priv->regs->highspeed);
 
-		quot = DIV_ROUND_UP(priv->clock, 256 * baud);
-		samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
+		quot = DIV_ROUND_UP(clk_rate, 256 * baud);
+		samplecount = DIV_ROUND_CLOSEST(clk_rate, quot * baud);
 	}
 
 set_baud:
@@ -167,8 +178,13 @@
 static int mtk_serial_setbrg(struct udevice *dev, int baudrate)
 {
 	struct mtk_serial_priv *priv = dev_get_priv(dev);
+	u32 clk_rate;
 
-	_mtk_serial_setbrg(priv, baudrate);
+	clk_rate = clk_get_rate(&priv->clk);
+	if (IS_ERR_VALUE(clk_rate) || clk_rate == 0)
+		clk_rate = priv->fixed_clk_rate;
+
+	_mtk_serial_setbrg(priv, baudrate, clk_rate);
 
 	return 0;
 }
@@ -211,7 +227,6 @@
 {
 	struct mtk_serial_priv *priv = dev_get_priv(dev);
 	fdt_addr_t addr;
-	struct clk clk;
 	int err;
 
 	addr = dev_read_addr(dev);
@@ -220,22 +235,19 @@
 
 	priv->regs = map_physmem(addr, 0, MAP_NOCACHE);
 
-	err = clk_get_by_index(dev, 0, &clk);
-	if (!err) {
-		err = clk_get_rate(&clk);
-		if (!IS_ERR_VALUE(err))
-			priv->clock = err;
-	} else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
-		debug("mtk_serial: failed to get clock\n");
-		return err;
-	}
-
-	if (!priv->clock)
-		priv->clock = dev_read_u32_default(dev, "clock-frequency", 0);
-
-	if (!priv->clock) {
-		debug("mtk_serial: clock not defined\n");
-		return -EINVAL;
+	err = clk_get_by_index(dev, 0, &priv->clk);
+	if (err) {
+		err = dev_read_u32(dev, "clock-frequency", &priv->fixed_clk_rate);
+		if (err) {
+			dev_err(dev, "baud clock not defined\n");
+			return -EINVAL;
+		}
+	} else {
+		err = clk_get_rate(&priv->clk);
+		if (IS_ERR_VALUE(err)) {
+			dev_err(dev, "invalid baud clock\n");
+			return -EINVAL;
+		}
 	}
 
 	priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed");
@@ -273,7 +285,7 @@
 #define DECLARE_HSUART_PRIV(port) \
 	static struct mtk_serial_priv mtk_hsuart##port = { \
 	.regs = (struct mtk_serial_regs *)CONFIG_SYS_NS16550_COM##port, \
-	.clock = CONFIG_SYS_NS16550_CLK \
+	.fixed_clk_rate = CONFIG_SYS_NS16550_CLK \
 };
 
 #define DECLARE_HSUART_FUNCTIONS(port) \
@@ -282,12 +294,14 @@
 		writel(0, &mtk_hsuart##port.regs->ier); \
 		writel(UART_MCRVAL, &mtk_hsuart##port.regs->mcr); \
 		writel(UART_FCRVAL, &mtk_hsuart##port.regs->fcr); \
-		_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
+		_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate, \
+				   mtk_hsuart##port.fixed_clk_rate); \
 		return 0 ; \
 	} \
 	static void mtk_serial##port##_setbrg(void) \
 	{ \
-		_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
+		_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate, \
+				   mtk_hsuart##port.fixed_clk_rate); \
 	} \
 	static int mtk_serial##port##_getc(void) \
 	{ \
@@ -427,13 +441,13 @@
 	struct mtk_serial_priv priv;
 
 	priv.regs = (void *) CONFIG_VAL(DEBUG_UART_BASE);
-	priv.clock = CONFIG_DEBUG_UART_CLOCK;
+	priv.fixed_clk_rate = CONFIG_DEBUG_UART_CLOCK;
 
 	writel(0, &priv.regs->ier);
 	writel(UART_MCRVAL, &priv.regs->mcr);
 	writel(UART_FCRVAL, &priv.regs->fcr);
 
-	_mtk_serial_setbrg(&priv, CONFIG_BAUDRATE);
+	_mtk_serial_setbrg(&priv, CONFIG_BAUDRATE, priv.fixed_clk_rate);
 }
 
 static inline void _debug_uart_putc(int ch)
diff --git a/drivers/serial/usbtty.h b/drivers/serial/usbtty.h
index 0d89fc0..e27aa36 100644
--- a/drivers/serial/usbtty.h
+++ b/drivers/serial/usbtty.h
@@ -13,8 +13,6 @@
 #include <usbdevice.h>
 #if defined(CONFIG_PPC)
 #include <usb/mpc8xx_udc.h>
-#elif defined(CONFIG_DW_UDC)
-#include <usb/designware_udc.h>
 #elif defined(CONFIG_CI_UDC)
 #include <usb/ci_udc.h>
 #endif
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 240ff21..2f12081 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -286,6 +286,14 @@
 	  used to access SPI memory devices like SPI-NOR or SPI-NAND on
 	  platforms embedding this IP core, like MT7622/M7629.
 
+config MTK_SPIM
+	bool "Mediatek SPI-MEM master controller driver"
+	depends on SPI_MEM
+	help
+	  Enable MediaTek SPI-MEM master controller driver. This driver mainly
+	  supports SPI flashes. You can use single, dual or quad mode
+	  transmission on this controller.
+
 config MVEBU_A3700_SPI
 	bool "Marvell Armada 3700 SPI driver"
 	select CLK_ARMADA_3720
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 7ba953d..50ba435 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -44,6 +44,7 @@
 obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
 obj-$(CONFIG_MTK_SNFI_SPI) += mtk_snfi_spi.o
 obj-$(CONFIG_MTK_SNOR) += mtk_snor.o
+obj-$(CONFIG_MTK_SPIM) += mtk_spim.o
 obj-$(CONFIG_MT7620_SPI) += mt7620_spi.o
 obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o
 obj-$(CONFIG_MSCC_BB_SPI) += mscc_bb_spi.o
diff --git a/drivers/spi/mtk_spim.c b/drivers/spi/mtk_spim.c
new file mode 100644
index 0000000..b45ef52
--- /dev/null
+++ b/drivers/spi/mtk_spim.c
@@ -0,0 +1,701 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 MediaTek Inc. All Rights Reserved.
+ *
+ * Author: SkyLake.Huang <skylake.huang@mediatek.com>
+ */
+
+#include <clk.h>
+#include <cpu_func.h>
+#include <div64.h>
+#include <dm.h>
+#include <spi.h>
+#include <spi-mem.h>
+#include <stdbool.h>
+#include <watchdog.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+#define SPI_CFG0_REG				0x0000
+#define SPI_CFG1_REG				0x0004
+#define SPI_TX_SRC_REG				0x0008
+#define SPI_RX_DST_REG				0x000c
+#define SPI_TX_DATA_REG				0x0010
+#define SPI_RX_DATA_REG				0x0014
+#define SPI_CMD_REG				0x0018
+#define SPI_IRQ_REG				0x001c
+#define SPI_STATUS_REG				0x0020
+#define SPI_PAD_SEL_REG				0x0024
+#define SPI_CFG2_REG				0x0028
+#define SPI_TX_SRC_REG_64			0x002c
+#define SPI_RX_DST_REG_64			0x0030
+#define SPI_CFG3_IPM_REG			0x0040
+
+#define SPI_CFG0_SCK_HIGH_OFFSET		0
+#define SPI_CFG0_SCK_LOW_OFFSET			8
+#define SPI_CFG0_CS_HOLD_OFFSET			16
+#define SPI_CFG0_CS_SETUP_OFFSET		24
+#define SPI_ADJUST_CFG0_CS_HOLD_OFFSET		0
+#define SPI_ADJUST_CFG0_CS_SETUP_OFFSET		16
+
+#define SPI_CFG1_CS_IDLE_OFFSET			0
+#define SPI_CFG1_PACKET_LOOP_OFFSET		8
+#define SPI_CFG1_PACKET_LENGTH_OFFSET		16
+#define SPI_CFG1_GET_TICKDLY_OFFSET		29
+
+#define SPI_CFG1_GET_TICKDLY_MASK		GENMASK(31, 29)
+#define SPI_CFG1_CS_IDLE_MASK			0xff
+#define SPI_CFG1_PACKET_LOOP_MASK		0xff00
+#define SPI_CFG1_PACKET_LENGTH_MASK		0x3ff0000
+#define SPI_CFG1_IPM_PACKET_LENGTH_MASK		GENMASK(31, 16)
+#define SPI_CFG2_SCK_HIGH_OFFSET		0
+#define SPI_CFG2_SCK_LOW_OFFSET			16
+#define SPI_CFG2_SCK_HIGH_MASK			GENMASK(15, 0)
+#define SPI_CFG2_SCK_LOW_MASK			GENMASK(31, 16)
+
+#define SPI_CMD_ACT				BIT(0)
+#define SPI_CMD_RESUME				BIT(1)
+#define SPI_CMD_RST				BIT(2)
+#define SPI_CMD_PAUSE_EN			BIT(4)
+#define SPI_CMD_DEASSERT			BIT(5)
+#define SPI_CMD_SAMPLE_SEL			BIT(6)
+#define SPI_CMD_CS_POL				BIT(7)
+#define SPI_CMD_CPHA				BIT(8)
+#define SPI_CMD_CPOL				BIT(9)
+#define SPI_CMD_RX_DMA				BIT(10)
+#define SPI_CMD_TX_DMA				BIT(11)
+#define SPI_CMD_TXMSBF				BIT(12)
+#define SPI_CMD_RXMSBF				BIT(13)
+#define SPI_CMD_RX_ENDIAN			BIT(14)
+#define SPI_CMD_TX_ENDIAN			BIT(15)
+#define SPI_CMD_FINISH_IE			BIT(16)
+#define SPI_CMD_PAUSE_IE			BIT(17)
+#define SPI_CMD_IPM_NONIDLE_MODE		BIT(19)
+#define SPI_CMD_IPM_SPIM_LOOP			BIT(21)
+#define SPI_CMD_IPM_GET_TICKDLY_OFFSET		22
+
+#define SPI_CMD_IPM_GET_TICKDLY_MASK		GENMASK(24, 22)
+
+#define PIN_MODE_CFG(x)				((x) / 2)
+
+#define SPI_CFG3_IPM_PIN_MODE_OFFSET		0
+#define SPI_CFG3_IPM_HALF_DUPLEX_DIR		BIT(2)
+#define SPI_CFG3_IPM_HALF_DUPLEX_EN		BIT(3)
+#define SPI_CFG3_IPM_XMODE_EN			BIT(4)
+#define SPI_CFG3_IPM_NODATA_FLAG		BIT(5)
+#define SPI_CFG3_IPM_CMD_BYTELEN_OFFSET		8
+#define SPI_CFG3_IPM_ADDR_BYTELEN_OFFSET	12
+#define SPI_CFG3_IPM_DUMMY_BYTELEN_OFFSET	16
+
+#define SPI_CFG3_IPM_CMD_PIN_MODE_MASK		GENMASK(1, 0)
+#define SPI_CFG3_IPM_CMD_BYTELEN_MASK		GENMASK(11, 8)
+#define SPI_CFG3_IPM_ADDR_BYTELEN_MASK		GENMASK(15, 12)
+#define SPI_CFG3_IPM_DUMMY_BYTELEN_MASK		GENMASK(19, 16)
+
+#define MT8173_SPI_MAX_PAD_SEL			3
+
+#define MTK_SPI_PAUSE_INT_STATUS		0x2
+
+#define MTK_SPI_IDLE				0
+#define MTK_SPI_PAUSED				1
+
+#define MTK_SPI_MAX_FIFO_SIZE			32U
+#define MTK_SPI_PACKET_SIZE			1024
+#define MTK_SPI_IPM_PACKET_SIZE			SZ_64K
+#define MTK_SPI_IPM_PACKET_LOOP			SZ_256
+
+#define MTK_SPI_32BITS_MASK			0xffffffff
+
+#define DMA_ADDR_EXT_BITS			36
+#define DMA_ADDR_DEF_BITS			32
+
+#define CLK_TO_US(freq, clkcnt) DIV_ROUND_UP((clkcnt), (freq) / 1000000)
+
+/* struct mtk_spim_capability
+ * @enhance_timing:	Some IC design adjust cfg register to enhance time accuracy
+ * @dma_ext:		Some IC support DMA addr extension
+ * @ipm_design:		The IPM IP design improves some features, and supports dual/quad mode
+ * @support_quad:	Whether quad mode is supported
+ */
+struct mtk_spim_capability {
+	bool enhance_timing;
+	bool dma_ext;
+	bool ipm_design;
+	bool support_quad;
+};
+
+/* struct mtk_spim_priv
+ * @base:		Base address of the spi controller
+ * @state:		Controller state
+ * @sel_clk:		Pad clock
+ * @spi_clk:		Core clock
+ * @xfer_len:		Current length of data for transfer
+ * @hw_cap:		Controller capabilities
+ * @tick_dly:		Used to postpone SPI sampling time
+ * @sample_sel:		Sample edge of MISO
+ * @dev:		udevice of this spi controller
+ * @tx_dma:		Tx DMA address
+ * @rx_dma:		Rx DMA address
+ */
+struct mtk_spim_priv {
+	void __iomem *base;
+	u32 state;
+	struct clk sel_clk, spi_clk;
+	u32 xfer_len;
+	struct mtk_spim_capability hw_cap;
+	u32 tick_dly;
+	u32 sample_sel;
+
+	struct device *dev;
+	dma_addr_t tx_dma;
+	dma_addr_t rx_dma;
+};
+
+static void mtk_spim_reset(struct mtk_spim_priv *priv)
+{
+	/* set the software reset bit in SPI_CMD_REG. */
+	setbits_le32(priv->base + SPI_CMD_REG, SPI_CMD_RST);
+	clrbits_le32(priv->base + SPI_CMD_REG, SPI_CMD_RST);
+}
+
+static int mtk_spim_hw_init(struct spi_slave *slave)
+{
+	struct udevice *bus = dev_get_parent(slave->dev);
+	struct mtk_spim_priv *priv = dev_get_priv(bus);
+	u16 cpha, cpol;
+	u32 reg_val;
+
+	cpha = slave->mode & SPI_CPHA ? 1 : 0;
+	cpol = slave->mode & SPI_CPOL ? 1 : 0;
+
+	if (priv->hw_cap.enhance_timing) {
+		if (priv->hw_cap.ipm_design) {
+			/* CFG3 reg only used for spi-mem,
+			 * here write to default value
+			 */
+			writel(0x0, priv->base + SPI_CFG3_IPM_REG);
+			clrsetbits_le32(priv->base + SPI_CMD_REG,
+					SPI_CMD_IPM_GET_TICKDLY_MASK,
+					priv->tick_dly <<
+					SPI_CMD_IPM_GET_TICKDLY_OFFSET);
+		} else {
+			clrsetbits_le32(priv->base + SPI_CFG1_REG,
+					SPI_CFG1_GET_TICKDLY_MASK,
+					priv->tick_dly <<
+					SPI_CFG1_GET_TICKDLY_OFFSET);
+		}
+	}
+
+	reg_val = readl(priv->base + SPI_CMD_REG);
+	if (priv->hw_cap.ipm_design) {
+		/* SPI transfer without idle time until packet length done */
+		reg_val |= SPI_CMD_IPM_NONIDLE_MODE;
+		if (slave->mode & SPI_LOOP)
+			reg_val |= SPI_CMD_IPM_SPIM_LOOP;
+		else
+			reg_val &= ~SPI_CMD_IPM_SPIM_LOOP;
+	}
+
+	if (cpha)
+		reg_val |= SPI_CMD_CPHA;
+	else
+		reg_val &= ~SPI_CMD_CPHA;
+	if (cpol)
+		reg_val |= SPI_CMD_CPOL;
+	else
+		reg_val &= ~SPI_CMD_CPOL;
+
+	/* set the mlsbx and mlsbtx */
+	if (slave->mode & SPI_LSB_FIRST) {
+		reg_val &= ~SPI_CMD_TXMSBF;
+		reg_val &= ~SPI_CMD_RXMSBF;
+	} else {
+		reg_val |= SPI_CMD_TXMSBF;
+		reg_val |= SPI_CMD_RXMSBF;
+	}
+
+	/* do not reverse tx/rx endian */
+	reg_val &= ~SPI_CMD_TX_ENDIAN;
+	reg_val &= ~SPI_CMD_RX_ENDIAN;
+
+	if (priv->hw_cap.enhance_timing) {
+		/* set CS polarity */
+		if (slave->mode & SPI_CS_HIGH)
+			reg_val |= SPI_CMD_CS_POL;
+		else
+			reg_val &= ~SPI_CMD_CS_POL;
+
+		if (priv->sample_sel)
+			reg_val |= SPI_CMD_SAMPLE_SEL;
+		else
+			reg_val &= ~SPI_CMD_SAMPLE_SEL;
+	}
+
+	/* disable dma mode */
+	reg_val &= ~(SPI_CMD_TX_DMA | SPI_CMD_RX_DMA);
+
+	/* disable deassert mode */
+	reg_val &= ~SPI_CMD_DEASSERT;
+
+	writel(reg_val, priv->base + SPI_CMD_REG);
+
+	return 0;
+}
+
+static void mtk_spim_prepare_transfer(struct mtk_spim_priv *priv,
+				      u32 speed_hz)
+{
+	u32 spi_clk_hz, div, sck_time, cs_time, reg_val;
+
+	spi_clk_hz = clk_get_rate(&priv->spi_clk);
+	if (speed_hz <= spi_clk_hz / 4)
+		div = DIV_ROUND_UP(spi_clk_hz, speed_hz);
+	else
+		div = 4;
+
+	sck_time = (div + 1) / 2;
+	cs_time = sck_time * 2;
+
+	if (priv->hw_cap.enhance_timing) {
+		reg_val = ((sck_time - 1) & 0xffff)
+			   << SPI_CFG2_SCK_HIGH_OFFSET;
+		reg_val |= ((sck_time - 1) & 0xffff)
+			   << SPI_CFG2_SCK_LOW_OFFSET;
+		writel(reg_val, priv->base + SPI_CFG2_REG);
+
+		reg_val = ((cs_time - 1) & 0xffff)
+			   << SPI_ADJUST_CFG0_CS_HOLD_OFFSET;
+		reg_val |= ((cs_time - 1) & 0xffff)
+			   << SPI_ADJUST_CFG0_CS_SETUP_OFFSET;
+		writel(reg_val, priv->base + SPI_CFG0_REG);
+	} else {
+		reg_val = ((sck_time - 1) & 0xff)
+			   << SPI_CFG0_SCK_HIGH_OFFSET;
+		reg_val |= ((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET;
+		reg_val |= ((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET;
+		reg_val |= ((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET;
+		writel(reg_val, priv->base + SPI_CFG0_REG);
+	}
+
+	reg_val = readl(priv->base + SPI_CFG1_REG);
+	reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
+	reg_val |= ((cs_time - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET;
+	writel(reg_val, priv->base + SPI_CFG1_REG);
+}
+
+/**
+ * mtk_spim_setup_packet() - setup packet format.
+ * @priv:	controller priv
+ *
+ * This controller sents/receives data in packets. The packet size is
+ * configurable.
+ *
+ * This function calculates the maximum packet size available for current
+ * data, and calculates the number of packets required to sent/receive data
+ * as much as possible.
+ */
+static void mtk_spim_setup_packet(struct mtk_spim_priv *priv)
+{
+	u32 packet_size, packet_loop, reg_val;
+
+	/* Calculate maximum packet size */
+	if (priv->hw_cap.ipm_design)
+		packet_size = min_t(u32,
+				    priv->xfer_len,
+				    MTK_SPI_IPM_PACKET_SIZE);
+	else
+		packet_size = min_t(u32,
+				    priv->xfer_len,
+				    MTK_SPI_PACKET_SIZE);
+
+	/* Calculates number of packets to sent/receive */
+	packet_loop = priv->xfer_len / packet_size;
+
+	reg_val = readl(priv->base + SPI_CFG1_REG);
+	if (priv->hw_cap.ipm_design)
+		reg_val &= ~SPI_CFG1_IPM_PACKET_LENGTH_MASK;
+	else
+		reg_val &= ~SPI_CFG1_PACKET_LENGTH_MASK;
+
+	reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET;
+
+	reg_val &= ~SPI_CFG1_PACKET_LOOP_MASK;
+
+	reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET;
+
+	writel(reg_val, priv->base + SPI_CFG1_REG);
+}
+
+static void mtk_spim_enable_transfer(struct mtk_spim_priv *priv)
+{
+	u32 cmd;
+
+	cmd = readl(priv->base + SPI_CMD_REG);
+	if (priv->state == MTK_SPI_IDLE)
+		cmd |= SPI_CMD_ACT;
+	else
+		cmd |= SPI_CMD_RESUME;
+	writel(cmd, priv->base + SPI_CMD_REG);
+}
+
+static bool mtk_spim_supports_op(struct spi_slave *slave,
+				 const struct spi_mem_op *op)
+{
+	struct udevice *bus = dev_get_parent(slave->dev);
+	struct mtk_spim_priv *priv = dev_get_priv(bus);
+
+	if (op->cmd.buswidth == 0 || op->cmd.buswidth > 4 ||
+	    op->addr.buswidth > 4 || op->dummy.buswidth > 4 ||
+	    op->data.buswidth > 4)
+		return false;
+
+	if (!priv->hw_cap.support_quad && (op->cmd.buswidth > 2 ||
+	    op->addr.buswidth > 2 || op->dummy.buswidth > 2 ||
+	    op->data.buswidth > 2))
+		return false;
+
+	if (op->addr.nbytes && op->dummy.nbytes &&
+	    op->addr.buswidth != op->dummy.buswidth)
+		return false;
+
+	if (op->addr.nbytes + op->dummy.nbytes > 16)
+		return false;
+
+	if (op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE) {
+		if (op->data.nbytes / MTK_SPI_IPM_PACKET_SIZE >
+		    MTK_SPI_IPM_PACKET_LOOP ||
+		    op->data.nbytes % MTK_SPI_IPM_PACKET_SIZE != 0)
+			return false;
+	}
+
+	return true;
+}
+
+static void mtk_spim_setup_dma_xfer(struct mtk_spim_priv *priv,
+				    const struct spi_mem_op *op)
+{
+	writel((u32)(priv->tx_dma & MTK_SPI_32BITS_MASK),
+	       priv->base + SPI_TX_SRC_REG);
+
+	if (priv->hw_cap.dma_ext)
+		writel((u32)(priv->tx_dma >> 32),
+		       priv->base + SPI_TX_SRC_REG_64);
+
+	if (op->data.dir == SPI_MEM_DATA_IN) {
+		writel((u32)(priv->rx_dma & MTK_SPI_32BITS_MASK),
+		       priv->base + SPI_RX_DST_REG);
+
+		if (priv->hw_cap.dma_ext)
+			writel((u32)(priv->rx_dma >> 32),
+			       priv->base + SPI_RX_DST_REG_64);
+	}
+}
+
+static int mtk_spim_transfer_wait(struct spi_slave *slave,
+				  const struct spi_mem_op *op)
+{
+	struct udevice *bus = dev_get_parent(slave->dev);
+	struct mtk_spim_priv *priv = dev_get_priv(bus);
+	u32 sck_l, sck_h, spi_bus_clk, clk_count, reg;
+	ulong us = 1;
+	int ret = 0;
+
+	if (op->data.dir == SPI_MEM_NO_DATA)
+		clk_count = 32;
+	else
+		clk_count = op->data.nbytes;
+
+	spi_bus_clk = clk_get_rate(&priv->spi_clk);
+	sck_l = readl(priv->base + SPI_CFG2_REG) >> SPI_CFG2_SCK_LOW_OFFSET;
+	sck_h = readl(priv->base + SPI_CFG2_REG) & SPI_CFG2_SCK_HIGH_MASK;
+	do_div(spi_bus_clk, sck_l + sck_h + 2);
+
+	us = CLK_TO_US(spi_bus_clk, clk_count * 8);
+	us += 1000 * 1000; /* 1s tolerance */
+
+	if (us > UINT_MAX)
+		us = UINT_MAX;
+
+	ret = readl_poll_timeout(priv->base + SPI_STATUS_REG, reg,
+				 reg & 0x1, us);
+	if (ret < 0) {
+		dev_err(priv->dev, "transfer timeout, val: 0x%lx\n", us);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int mtk_spim_exec_op(struct spi_slave *slave,
+			    const struct spi_mem_op *op)
+{
+	struct udevice *bus = dev_get_parent(slave->dev);
+	struct mtk_spim_priv *priv = dev_get_priv(bus);
+	u32 reg_val, nio = 1, tx_size;
+	char *tx_tmp_buf;
+	char *rx_tmp_buf;
+	int i, ret = 0;
+
+	mtk_spim_reset(priv);
+	mtk_spim_hw_init(slave);
+	mtk_spim_prepare_transfer(priv, slave->max_hz);
+
+	reg_val = readl(priv->base + SPI_CFG3_IPM_REG);
+	/* opcode byte len */
+	reg_val &= ~SPI_CFG3_IPM_CMD_BYTELEN_MASK;
+	reg_val |= 1 << SPI_CFG3_IPM_CMD_BYTELEN_OFFSET;
+
+	/* addr & dummy byte len */
+	if (op->addr.nbytes || op->dummy.nbytes)
+		reg_val |= (op->addr.nbytes + op->dummy.nbytes) <<
+			    SPI_CFG3_IPM_ADDR_BYTELEN_OFFSET;
+
+	/* data byte len */
+	if (!op->data.nbytes) {
+		reg_val |= SPI_CFG3_IPM_NODATA_FLAG;
+		writel(0, priv->base + SPI_CFG1_REG);
+	} else {
+		reg_val &= ~SPI_CFG3_IPM_NODATA_FLAG;
+		priv->xfer_len = op->data.nbytes;
+		mtk_spim_setup_packet(priv);
+	}
+
+	if (op->addr.nbytes || op->dummy.nbytes) {
+		if (op->addr.buswidth == 1 || op->dummy.buswidth == 1)
+			reg_val |= SPI_CFG3_IPM_XMODE_EN;
+		else
+			reg_val &= ~SPI_CFG3_IPM_XMODE_EN;
+	}
+
+	if (op->addr.buswidth == 2 ||
+	    op->dummy.buswidth == 2 ||
+	    op->data.buswidth == 2)
+		nio = 2;
+	else if (op->addr.buswidth == 4 ||
+		 op->dummy.buswidth == 4 ||
+		 op->data.buswidth == 4)
+		nio = 4;
+
+	reg_val &= ~SPI_CFG3_IPM_CMD_PIN_MODE_MASK;
+	reg_val |= PIN_MODE_CFG(nio) << SPI_CFG3_IPM_PIN_MODE_OFFSET;
+
+	reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_EN;
+	if (op->data.dir == SPI_MEM_DATA_IN)
+		reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_DIR;
+	else
+		reg_val &= ~SPI_CFG3_IPM_HALF_DUPLEX_DIR;
+	writel(reg_val, priv->base + SPI_CFG3_IPM_REG);
+
+	tx_size = 1 + op->addr.nbytes + op->dummy.nbytes;
+	if (op->data.dir == SPI_MEM_DATA_OUT)
+		tx_size += op->data.nbytes;
+
+	tx_size = max(tx_size, (u32)32);
+
+	/* Fill up tx data */
+	tx_tmp_buf = kzalloc(tx_size, GFP_KERNEL);
+	if (!tx_tmp_buf) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	tx_tmp_buf[0] = op->cmd.opcode;
+
+	if (op->addr.nbytes) {
+		for (i = 0; i < op->addr.nbytes; i++)
+			tx_tmp_buf[i + 1] = op->addr.val >>
+					(8 * (op->addr.nbytes - i - 1));
+	}
+
+	if (op->dummy.nbytes)
+		memset(tx_tmp_buf + op->addr.nbytes + 1, 0xff,
+		       op->dummy.nbytes);
+
+	if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
+		memcpy(tx_tmp_buf + op->dummy.nbytes + op->addr.nbytes + 1,
+		       op->data.buf.out, op->data.nbytes);
+	/* Finish filling up tx data */
+
+	priv->tx_dma = dma_map_single(tx_tmp_buf, tx_size, DMA_TO_DEVICE);
+	if (dma_mapping_error(priv->dev, priv->tx_dma)) {
+		ret = -ENOMEM;
+		goto tx_free;
+	}
+
+	if (op->data.dir == SPI_MEM_DATA_IN) {
+		if (!IS_ALIGNED((size_t)op->data.buf.in, 4)) {
+			rx_tmp_buf = kzalloc(op->data.nbytes, GFP_KERNEL);
+			if (!rx_tmp_buf) {
+				ret = -ENOMEM;
+				goto tx_unmap;
+			}
+		} else {
+			rx_tmp_buf = op->data.buf.in;
+		}
+
+		priv->rx_dma = dma_map_single(rx_tmp_buf, op->data.nbytes,
+					      DMA_FROM_DEVICE);
+		if (dma_mapping_error(priv->dev, priv->rx_dma)) {
+			ret = -ENOMEM;
+			goto rx_free;
+		}
+	}
+
+	reg_val = readl(priv->base + SPI_CMD_REG);
+	reg_val |= SPI_CMD_TX_DMA;
+	if (op->data.dir == SPI_MEM_DATA_IN)
+		reg_val |= SPI_CMD_RX_DMA;
+
+	writel(reg_val, priv->base + SPI_CMD_REG);
+
+	mtk_spim_setup_dma_xfer(priv, op);
+
+	mtk_spim_enable_transfer(priv);
+
+	/* Wait for the interrupt. */
+	ret = mtk_spim_transfer_wait(slave, op);
+	if (ret)
+		goto rx_unmap;
+
+	if (op->data.dir == SPI_MEM_DATA_IN &&
+	    !IS_ALIGNED((size_t)op->data.buf.in, 4))
+		memcpy(op->data.buf.in, rx_tmp_buf, op->data.nbytes);
+
+rx_unmap:
+	/* spi disable dma */
+	reg_val = readl(priv->base + SPI_CMD_REG);
+	reg_val &= ~SPI_CMD_TX_DMA;
+	if (op->data.dir == SPI_MEM_DATA_IN)
+		reg_val &= ~SPI_CMD_RX_DMA;
+	writel(reg_val, priv->base + SPI_CMD_REG);
+
+	writel(0, priv->base + SPI_TX_SRC_REG);
+	writel(0, priv->base + SPI_RX_DST_REG);
+
+	if (op->data.dir == SPI_MEM_DATA_IN)
+		dma_unmap_single(priv->rx_dma,
+				 op->data.nbytes, DMA_FROM_DEVICE);
+rx_free:
+	if (op->data.dir == SPI_MEM_DATA_IN &&
+	    !IS_ALIGNED((size_t)op->data.buf.in, 4))
+		kfree(rx_tmp_buf);
+tx_unmap:
+	dma_unmap_single(priv->tx_dma,
+			 tx_size, DMA_TO_DEVICE);
+tx_free:
+	kfree(tx_tmp_buf);
+exit:
+	return ret;
+}
+
+static int mtk_spim_adjust_op_size(struct spi_slave *slave,
+				   struct spi_mem_op *op)
+{
+	int opcode_len;
+
+	if (!op->data.nbytes)
+		return 0;
+
+	if (op->data.dir != SPI_MEM_NO_DATA) {
+		opcode_len = 1 + op->addr.nbytes + op->dummy.nbytes;
+		if (opcode_len + op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE) {
+			op->data.nbytes = MTK_SPI_IPM_PACKET_SIZE - opcode_len;
+			/* force data buffer dma-aligned. */
+			op->data.nbytes -= op->data.nbytes % 4;
+		}
+	}
+
+	return 0;
+}
+
+static int mtk_spim_get_attr(struct mtk_spim_priv *priv, struct udevice *dev)
+{
+	int ret;
+
+	priv->hw_cap.enhance_timing = dev_read_bool(dev, "enhance_timing");
+	priv->hw_cap.dma_ext = dev_read_bool(dev, "dma_ext");
+	priv->hw_cap.ipm_design = dev_read_bool(dev, "ipm_design");
+	priv->hw_cap.support_quad = dev_read_bool(dev, "support_quad");
+
+	ret = dev_read_u32(dev, "tick_dly", &priv->tick_dly);
+	if (ret < 0)
+		dev_err(priv->dev, "tick dly not set.\n");
+
+	ret = dev_read_u32(dev, "sample_sel", &priv->sample_sel);
+	if (ret < 0)
+		dev_err(priv->dev, "sample sel not set.\n");
+
+	return ret;
+}
+
+static int mtk_spim_probe(struct udevice *dev)
+{
+	struct mtk_spim_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->base = (void __iomem *)devfdt_get_addr(dev);
+	if (!priv->base)
+		return -EINVAL;
+
+	mtk_spim_get_attr(priv, dev);
+
+	ret = clk_get_by_name(dev, "sel-clk", &priv->sel_clk);
+	if (ret < 0) {
+		dev_err(dev, "failed to get sel-clk\n");
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "spi-clk", &priv->spi_clk);
+	if (ret < 0) {
+		dev_err(dev, "failed to get spi-clk\n");
+		return ret;
+	}
+
+	clk_enable(&priv->sel_clk);
+	clk_enable(&priv->spi_clk);
+
+	return 0;
+}
+
+static int mtk_spim_set_speed(struct udevice *dev, uint speed)
+{
+	return 0;
+}
+
+static int mtk_spim_set_mode(struct udevice *dev, uint mode)
+{
+	return 0;
+}
+
+static const struct spi_controller_mem_ops mtk_spim_mem_ops = {
+	.adjust_op_size = mtk_spim_adjust_op_size,
+	.supports_op = mtk_spim_supports_op,
+	.exec_op = mtk_spim_exec_op
+};
+
+static const struct dm_spi_ops mtk_spim_ops = {
+	.mem_ops = &mtk_spim_mem_ops,
+	.set_speed = mtk_spim_set_speed,
+	.set_mode = mtk_spim_set_mode,
+};
+
+static const struct udevice_id mtk_spim_ids[] = {
+	{ .compatible = "mediatek,ipm-spi" },
+	{}
+};
+
+U_BOOT_DRIVER(mtk_spim) = {
+	.name = "mtk_spim",
+	.id = UCLASS_SPI,
+	.of_match = mtk_spim_ids,
+	.ops = &mtk_spim_ops,
+	.priv_auto = sizeof(struct mtk_spim_priv),
+	.probe = mtk_spim_probe,
+};
diff --git a/drivers/timer/mtk_timer.c b/drivers/timer/mtk_timer.c
index f6b97f8..223e63f 100644
--- a/drivers/timer/mtk_timer.c
+++ b/drivers/timer/mtk_timer.c
@@ -13,24 +13,32 @@
 #include <asm/io.h>
 #include <linux/bitops.h>
 
-#define MTK_GPT4_CTRL	0x40
-#define MTK_GPT4_CLK	0x44
-#define MTK_GPT4_CNT	0x48
+#define MTK_GPT4_OFFSET_V1	0x40
+#define MTK_GPT4_OFFSET_V2	0x80
 
-#define GPT4_ENABLE	BIT(0)
-#define GPT4_CLEAR	BIT(1)
-#define GPT4_FREERUN	GENMASK(5, 4)
-#define GPT4_CLK_SYS	0x0
-#define GPT4_CLK_DIV1	0x0
+#define MTK_GPT_CON		0x0
+#define MTK_GPT_V1_CLK		0x4
+#define MTK_GPT_CNT		0x8
+
+#define GPT_ENABLE		BIT(0)
+#define GPT_CLEAR		BIT(1)
+#define GPT_V1_FREERUN		GENMASK(5, 4)
+#define GPT_V2_FREERUN		GENMASK(6, 5)
+
+enum mtk_gpt_ver {
+	MTK_GPT_V1,
+	MTK_GPT_V2
+};
 
 struct mtk_timer_priv {
 	void __iomem *base;
+	unsigned int gpt4_offset;
 };
 
 static u64 mtk_timer_get_count(struct udevice *dev)
 {
 	struct mtk_timer_priv *priv = dev_get_priv(dev);
-	u32 val = readl(priv->base + MTK_GPT4_CNT);
+	u32 val = readl(priv->base + priv->gpt4_offset + MTK_GPT_CNT);
 
 	return timer_conv_64(val);
 }
@@ -40,12 +48,27 @@
 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 	struct mtk_timer_priv *priv = dev_get_priv(dev);
 	struct clk clk, parent;
-	int ret;
+	int ret, gpt_ver;
 
 	priv->base = dev_read_addr_ptr(dev);
+	gpt_ver = dev_get_driver_data(dev);
+
 	if (!priv->base)
 		return -ENOENT;
 
+	if (gpt_ver == MTK_GPT_V2) {
+		priv->gpt4_offset = MTK_GPT4_OFFSET_V2;
+
+		writel(GPT_V2_FREERUN | GPT_CLEAR | GPT_ENABLE,
+		       priv->base + priv->gpt4_offset + MTK_GPT_CON);
+	} else {
+		priv->gpt4_offset = MTK_GPT4_OFFSET_V1;
+
+		writel(GPT_V1_FREERUN | GPT_CLEAR | GPT_ENABLE,
+		       priv->base + priv->gpt4_offset + MTK_GPT_CON);
+		writel(0, priv->base + priv->gpt4_offset + MTK_GPT_V1_CLK);
+	}
+
 	ret = clk_get_by_index(dev, 0, &clk);
 	if (ret)
 		return ret;
@@ -61,16 +84,6 @@
 	if (!uc_priv->clock_rate)
 		return -EINVAL;
 
-	/*
-	 * Initialize the timer:
-	 * 1. set clock source to system clock with clock divider setting to 1
-	 * 2. set timer mode to free running
-	 * 3. reset timer counter to 0 then enable the timer
-	 */
-	writel(GPT4_CLK_SYS | GPT4_CLK_DIV1, priv->base + MTK_GPT4_CLK);
-	writel(GPT4_FREERUN | GPT4_CLEAR | GPT4_ENABLE,
-	       priv->base + MTK_GPT4_CTRL);
-
 	return 0;
 }
 
@@ -79,8 +92,10 @@
 };
 
 static const struct udevice_id mtk_timer_ids[] = {
-	{ .compatible = "mediatek,timer" },
-	{ .compatible = "mediatek,mt6577-timer" },
+	{ .compatible = "mediatek,timer", .data = MTK_GPT_V1 },
+	{ .compatible = "mediatek,mt6577-timer", .data = MTK_GPT_V1 },
+	{ .compatible = "mediatek,mt7981-timer", .data = MTK_GPT_V2 },
+	{ .compatible = "mediatek,mt7986-timer", .data = MTK_GPT_V2 },
 	{ }
 };
 
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index fd13cf3..3afb45d 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -48,7 +48,7 @@
 	  automatically probed when found on the bus.
 
 config SPL_DM_USB
-	bool "Enable driver model for USB host most in SPL"
+	bool "Enable driver model for USB host mode in SPL"
 	depends on SPL_DM && DM_USB
 	default n if ARCH_MVEBU
 	default y
diff --git a/drivers/usb/emul/sandbox_flash.c b/drivers/usb/emul/sandbox_flash.c
index 01b2b41..2589c70 100644
--- a/drivers/usb/emul/sandbox_flash.c
+++ b/drivers/usb/emul/sandbox_flash.c
@@ -7,8 +7,10 @@
 #include <common.h>
 #include <dm.h>
 #include <log.h>
+#include <malloc.h>
 #include <os.h>
 #include <scsi.h>
+#include <scsi_emul.h>
 #include <usb.h>
 
 /*
@@ -21,14 +23,9 @@
 	SANDBOX_FLASH_EP_OUT		= 1,	/* endpoints */
 	SANDBOX_FLASH_EP_IN		= 2,
 	SANDBOX_FLASH_BLOCK_LEN		= 512,
+	SANDBOX_FLASH_BUF_SIZE		= 512,
 };
 
-enum cmd_phase {
-	PHASE_START,
-	PHASE_DATA,
-	PHASE_STATUS,
-};
-
 enum {
 	STRINGID_MANUFACTURER = 1,
 	STRINGID_PRODUCT,
@@ -40,29 +37,19 @@
 /**
  * struct sandbox_flash_priv - private state for this driver
  *
+ * @eminfo:	emulator state
  * @error:	true if there is an error condition
- * @alloc_len:	Allocation length from the last incoming command
- * @transfer_len: Transfer length from CBW header
- * @read_len:	Number of blocks of data left in the current read command
  * @tag:	Tag value from last command
  * @fd:		File descriptor of backing file
  * @file_size:	Size of file in bytes
  * @status_buff:	Data buffer for outgoing status
- * @buff_used:	Number of bytes ready to transfer back to host
- * @buff:	Data buffer for outgoing data
  */
 struct sandbox_flash_priv {
+	struct scsi_emul_info eminfo;
 	bool error;
-	int alloc_len;
-	int transfer_len;
-	int read_len;
-	enum cmd_phase phase;
 	u32 tag;
 	int fd;
-	loff_t file_size;
 	struct umass_bbb_csw status;
-	int buff_used;
-	u8 buff[512];
 };
 
 struct sandbox_flash_plat {
@@ -70,32 +57,6 @@
 	struct usb_string flash_strings[STRINGID_COUNT];
 };
 
-struct scsi_inquiry_resp {
-	u8 type;
-	u8 flags;
-	u8 version;
-	u8 data_format;
-	u8 additional_len;
-	u8 spare[3];
-	char vendor[8];
-	char product[16];
-	char revision[4];
-};
-
-struct scsi_read_capacity_resp {
-	u32 last_block_addr;
-	u32 block_len;
-};
-
-struct __packed scsi_read10_req {
-	u8 cmd;
-	u8 lun_flags;
-	u32 lba;
-	u8 spare;
-	u16 transfer_len;
-	u8 spare2[3];
-};
-
 static struct usb_device_descriptor flash_device_desc = {
 	.bLength =		sizeof(flash_device_desc),
 	.bDescriptorType =	USB_DT_DEVICE,
@@ -200,7 +161,6 @@
 	csw->dCSWTag = priv->tag;
 	csw->dCSWDataResidue = 0;
 	csw->bCSWStatus = CSWSTATUS_FAILED;
-	priv->buff_used = 0;
 }
 
 /**
@@ -210,8 +170,7 @@
  * @resp:	Response to send, or NULL if none
  * @size:	Size of response
  */
-static void setup_response(struct sandbox_flash_priv *priv, void *resp,
-			   int size)
+static void setup_response(struct sandbox_flash_priv *priv)
 {
 	struct umass_bbb_csw *csw = &priv->status;
 
@@ -219,97 +178,45 @@
 	csw->dCSWTag = priv->tag;
 	csw->dCSWDataResidue = 0;
 	csw->bCSWStatus = CSWSTATUS_GOOD;
-
-	assert(!resp || resp == priv->buff);
-	priv->buff_used = size;
 }
 
-static void handle_read(struct sandbox_flash_priv *priv, ulong lba,
-			ulong transfer_len)
-{
-	debug("%s: lba=%lx, transfer_len=%lx\n", __func__, lba, transfer_len);
-	priv->read_len = transfer_len;
-	if (priv->fd != -1) {
-		os_lseek(priv->fd, lba * SANDBOX_FLASH_BLOCK_LEN, OS_SEEK_SET);
-		setup_response(priv, priv->buff,
-			       transfer_len * SANDBOX_FLASH_BLOCK_LEN);
-	} else {
-		setup_fail_response(priv);
-	}
-}
-
-static int handle_ufi_command(struct sandbox_flash_plat *plat,
-			      struct sandbox_flash_priv *priv, const void *buff,
+static int handle_ufi_command(struct sandbox_flash_priv *priv, const void *buff,
 			      int len)
 {
+	struct scsi_emul_info *info = &priv->eminfo;
 	const struct scsi_cmd *req = buff;
-
-	switch (*req->cmd) {
-	case SCSI_INQUIRY: {
-		struct scsi_inquiry_resp *resp = (void *)priv->buff;
+	int ret;
 
-		priv->alloc_len = req->cmd[4];
-		memset(resp, '\0', sizeof(*resp));
-		resp->data_format = 1;
-		resp->additional_len = 0x1f;
-		strncpy(resp->vendor,
-			plat->flash_strings[STRINGID_MANUFACTURER -  1].s,
-			sizeof(resp->vendor));
-		strncpy(resp->product,
-			plat->flash_strings[STRINGID_PRODUCT - 1].s,
-			sizeof(resp->product));
-		strncpy(resp->revision, "1.0", sizeof(resp->revision));
-		setup_response(priv, resp, sizeof(*resp));
-		break;
-	}
-	case SCSI_TST_U_RDY:
-		setup_response(priv, NULL, 0);
-		break;
-	case SCSI_RD_CAPAC: {
-		struct scsi_read_capacity_resp *resp = (void *)priv->buff;
-		uint blocks;
-
-		if (priv->file_size)
-			blocks = priv->file_size / SANDBOX_FLASH_BLOCK_LEN - 1;
-		else
-			blocks = 0;
-		resp->last_block_addr = cpu_to_be32(blocks);
-		resp->block_len = cpu_to_be32(SANDBOX_FLASH_BLOCK_LEN);
-		setup_response(priv, resp, sizeof(*resp));
-		break;
-	}
-	case SCSI_READ10: {
-		struct scsi_read10_req *req = (void *)buff;
-
-		handle_read(priv, be32_to_cpu(req->lba),
-			    be16_to_cpu(req->transfer_len));
-		break;
-	}
-	default:
-		debug("Command not supported: %x\n", req->cmd[0]);
-		return -EPROTONOSUPPORT;
+	ret = sb_scsi_emul_command(info, req, len);
+	if (!ret) {
+		setup_response(priv);
+	} else if (ret == SCSI_EMUL_DO_READ && priv->fd != -1) {
+		os_lseek(priv->fd, info->seek_block * info->block_size,
+			 OS_SEEK_SET);
+		setup_response(priv);
+	} else {
+		setup_fail_response(priv);
 	}
 
-	priv->phase = priv->transfer_len ? PHASE_DATA : PHASE_STATUS;
 	return 0;
 }
 
 static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev,
 			      unsigned long pipe, void *buff, int len)
 {
-	struct sandbox_flash_plat *plat = dev_get_plat(dev);
 	struct sandbox_flash_priv *priv = dev_get_priv(dev);
+	struct scsi_emul_info *info = &priv->eminfo;
 	int ep = usb_pipeendpoint(pipe);
 	struct umass_bbb_cbw *cbw = buff;
 
 	debug("%s: dev=%s, pipe=%lx, ep=%x, len=%x, phase=%d\n", __func__,
-	      dev->name, pipe, ep, len, priv->phase);
+	      dev->name, pipe, ep, len, info->phase);
 	switch (ep) {
 	case SANDBOX_FLASH_EP_OUT:
-		switch (priv->phase) {
-		case PHASE_START:
-			priv->alloc_len = 0;
-			priv->read_len = 0;
+		switch (info->phase) {
+		case SCSIPH_START:
+			info->alloc_len = 0;
+			info->read_len = 0;
 			if (priv->error || len != UMASS_BBB_CBW_SIZE ||
 			    cbw->dCBWSignature != CBWSIGNATURE)
 				goto err;
@@ -318,22 +225,22 @@
 				goto err;
 			if (cbw->bCDBLength < 1 || cbw->bCDBLength >= 0x10)
 				goto err;
-			priv->transfer_len = cbw->dCBWDataTransferLength;
+			info->transfer_len = cbw->dCBWDataTransferLength;
 			priv->tag = cbw->dCBWTag;
-			return handle_ufi_command(plat, priv, cbw->CBWCDB,
+			return handle_ufi_command(priv, cbw->CBWCDB,
 						  cbw->bCDBLength);
-		case PHASE_DATA:
+		case SCSIPH_DATA:
 			debug("data out\n");
 			break;
 		default:
 			break;
 		}
 	case SANDBOX_FLASH_EP_IN:
-		switch (priv->phase) {
-		case PHASE_DATA:
-			debug("data in, len=%x, alloc_len=%x, priv->read_len=%x\n",
-			      len, priv->alloc_len, priv->read_len);
-			if (priv->read_len) {
+		switch (info->phase) {
+		case SCSIPH_DATA:
+			debug("data in, len=%x, alloc_len=%x, info->read_len=%x\n",
+			      len, info->alloc_len, info->read_len);
+			if (info->read_len) {
 				ulong bytes_read;
 
 				if (priv->fd == -1)
@@ -342,24 +249,24 @@
 				bytes_read = os_read(priv->fd, buff, len);
 				if (bytes_read != len)
 					return -EIO;
-				priv->read_len -= len / SANDBOX_FLASH_BLOCK_LEN;
-				if (!priv->read_len)
-					priv->phase = PHASE_STATUS;
+				info->read_len -= len / info->block_size;
+				if (!info->read_len)
+					info->phase = SCSIPH_STATUS;
 			} else {
-				if (priv->alloc_len && len > priv->alloc_len)
-					len = priv->alloc_len;
-				if (len > sizeof(priv->buff))
-					len = sizeof(priv->buff);
-				memcpy(buff, priv->buff, len);
-				priv->phase = PHASE_STATUS;
+				if (info->alloc_len && len > info->alloc_len)
+					len = info->alloc_len;
+				if (len > SANDBOX_FLASH_BUF_SIZE)
+					len = SANDBOX_FLASH_BUF_SIZE;
+				memcpy(buff, info->buff, len);
+				info->phase = SCSIPH_STATUS;
 			}
 			return len;
-		case PHASE_STATUS:
+		case SCSIPH_STATUS:
 			debug("status in, len=%x\n", len);
 			if (len > sizeof(priv->status))
 				len = sizeof(priv->status);
 			memcpy(buff, &priv->status, len);
-			priv->phase = PHASE_START;
+			info->phase = SCSIPH_START;
 			return len;
 		default:
 			break;
@@ -400,10 +307,31 @@
 {
 	struct sandbox_flash_plat *plat = dev_get_plat(dev);
 	struct sandbox_flash_priv *priv = dev_get_priv(dev);
+	struct scsi_emul_info *info = &priv->eminfo;
+	int ret;
 
 	priv->fd = os_open(plat->pathname, OS_O_RDONLY);
-	if (priv->fd != -1)
-		return os_get_filesize(plat->pathname, &priv->file_size);
+	if (priv->fd != -1) {
+		ret = os_get_filesize(plat->pathname, &info->file_size);
+		if (ret)
+			return log_msg_ret("sz", ret);
+	}
+	info->buff = malloc(SANDBOX_FLASH_BUF_SIZE);
+	if (!info->buff)
+		return log_ret(-ENOMEM);
+	info->vendor = plat->flash_strings[STRINGID_MANUFACTURER -  1].s;
+	info->product = plat->flash_strings[STRINGID_PRODUCT - 1].s;
+	info->block_size = SANDBOX_FLASH_BLOCK_LEN;
+
+	return 0;
+}
+
+static int sandbox_flash_remove(struct udevice *dev)
+{
+	struct sandbox_flash_priv *priv = dev_get_priv(dev);
+	struct scsi_emul_info *info = &priv->eminfo;
+
+	free(info->buff);
 
 	return 0;
 }
@@ -424,6 +352,7 @@
 	.of_match = sandbox_usb_flash_ids,
 	.bind	= sandbox_flash_bind,
 	.probe	= sandbox_flash_probe,
+	.remove	= sandbox_flash_remove,
 	.of_to_plat = sandbox_flash_of_to_plat,
 	.ops	= &sandbox_usb_flash_ops,
 	.priv_auto	= sizeof(struct sandbox_flash_priv),
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 306dd31..dd09ee0 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -42,6 +42,5 @@
 ifdef CONFIG_USB_DEVICE
 obj-y += core.o
 obj-y += ep0.o
-obj-$(CONFIG_DW_UDC) += designware_udc.o
 endif
 endif
diff --git a/drivers/usb/gadget/designware_udc.c b/drivers/usb/gadget/designware_udc.c
deleted file mode 100644
index 41a6e8c..0000000
--- a/drivers/usb/gadget/designware_udc.c
+++ /dev/null
@@ -1,1021 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Based on drivers/usb/gadget/omap1510_udc.c
- * TI OMAP1510 USB bus interface driver
- *
- * (C) Copyright 2009
- * Vipin Kumar, STMicroelectronics, vipin.kumar@st.com.
- */
-
-#include <common.h>
-#include <serial.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-
-#include <env.h>
-#include <usbdevice.h>
-#include "ep0.h"
-#include <usb/designware_udc.h>
-#include <usb/udc.h>
-#include <asm/arch/hardware.h>
-
-#define UDC_INIT_MDELAY		80	/* Device settle delay */
-
-/* Some kind of debugging output... */
-#ifndef DEBUG_DWUSBTTY
-#define UDCDBG(str)
-#define UDCDBGA(fmt, args...)
-#else
-#define UDCDBG(str) serial_printf(str "\n")
-#define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args)
-#endif
-
-static struct urb *ep0_urb;
-static struct usb_device_instance *udc_device;
-
-static struct plug_regs *const plug_regs_p =
-    (struct plug_regs * const)CONFIG_SYS_PLUG_BASE;
-static struct udc_regs *const udc_regs_p =
-    (struct udc_regs * const)CONFIG_SYS_USBD_BASE;
-static struct udc_endp_regs *const outep_regs_p =
-    &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0];
-static struct udc_endp_regs *const inep_regs_p =
-    &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0];
-
-/*
- * udc_state_transition - Write the next packet to TxFIFO.
- * @initial:	Initial state.
- * @final:	Final state.
- *
- * Helper function to implement device state changes. The device states and
- * the events that transition between them are:
- *
- *				STATE_ATTACHED
- *				||	/\
- *				\/	||
- *	DEVICE_HUB_CONFIGURED			DEVICE_HUB_RESET
- *				||	/\
- *				\/	||
- *				STATE_POWERED
- *				||	/\
- *				\/	||
- *	DEVICE_RESET				DEVICE_POWER_INTERRUPTION
- *				||	/\
- *				\/	||
- *				STATE_DEFAULT
- *				||	/\
- *				\/	||
- *	DEVICE_ADDRESS_ASSIGNED			DEVICE_RESET
- *				||	/\
- *				\/	||
- *				STATE_ADDRESSED
- *				||	/\
- *				\/	||
- *	DEVICE_CONFIGURED			DEVICE_DE_CONFIGURED
- *				||	/\
- *				\/	||
- *				STATE_CONFIGURED
- *
- * udc_state_transition transitions up (in the direction from STATE_ATTACHED
- * to STATE_CONFIGURED) from the specified initial state to the specified final
- * state, passing through each intermediate state on the way. If the initial
- * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
- * no state transitions will take place.
- *
- * udc_state_transition also transitions down (in the direction from
- * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
- * specified final state, passing through each intermediate state on the way.
- * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
- * state, then no state transitions will take place.
- *
- * This function must only be called with interrupts disabled.
- */
-static void udc_state_transition(usb_device_state_t initial,
-				 usb_device_state_t final)
-{
-	if (initial < final) {
-		switch (initial) {
-		case STATE_ATTACHED:
-			usbd_device_event_irq(udc_device,
-					      DEVICE_HUB_CONFIGURED, 0);
-			if (final == STATE_POWERED)
-				break;
-		case STATE_POWERED:
-			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
-			if (final == STATE_DEFAULT)
-				break;
-		case STATE_DEFAULT:
-			usbd_device_event_irq(udc_device,
-					      DEVICE_ADDRESS_ASSIGNED, 0);
-			if (final == STATE_ADDRESSED)
-				break;
-		case STATE_ADDRESSED:
-			usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
-		case STATE_CONFIGURED:
-			break;
-		default:
-			break;
-		}
-	} else if (initial > final) {
-		switch (initial) {
-		case STATE_CONFIGURED:
-			usbd_device_event_irq(udc_device,
-					      DEVICE_DE_CONFIGURED, 0);
-			if (final == STATE_ADDRESSED)
-				break;
-		case STATE_ADDRESSED:
-			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
-			if (final == STATE_DEFAULT)
-				break;
-		case STATE_DEFAULT:
-			usbd_device_event_irq(udc_device,
-					      DEVICE_POWER_INTERRUPTION, 0);
-			if (final == STATE_POWERED)
-				break;
-		case STATE_POWERED:
-			usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
-		case STATE_ATTACHED:
-			break;
-		default:
-			break;
-		}
-	}
-}
-
-/* Stall endpoint */
-static void udc_stall_ep(u32 ep_num)
-{
-	writel(readl(&inep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL,
-	       &inep_regs_p[ep_num].endp_cntl);
-
-	writel(readl(&outep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL,
-	       &outep_regs_p[ep_num].endp_cntl);
-}
-
-static void *get_fifo(int ep_num, int in)
-{
-	u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE;
-
-	switch (ep_num) {
-	case UDC_EP3:
-		fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn);
-		/* break intentionally left out */
-
-	case UDC_EP1:
-		fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn);
-		/* break intentionally left out */
-
-	case UDC_EP0:
-	default:
-		if (in) {
-			fifo_ptr +=
-			    readl(&outep_regs_p[2].endp_maxpacksize) >> 16;
-			/* break intentionally left out */
-		} else {
-			break;
-		}
-
-	case UDC_EP2:
-		fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16;
-		/* break intentionally left out */
-	}
-
-	return (void *)fifo_ptr;
-}
-
-static int usbgetpckfromfifo(int epNum, u8 *bufp, u32 len)
-{
-	u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0);
-	u32 i, nw, nb;
-	u32 *wrdp;
-	u8 *bytp;
-	u32 tmp[128];
-
-	if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY)
-		return -1;
-
-	nw = len / sizeof(u32);
-	nb = len % sizeof(u32);
-
-	/* use tmp buf if bufp is not word aligned */
-	if ((int)bufp & 0x3)
-		wrdp = (u32 *)&tmp[0];
-	else
-		wrdp = (u32 *)bufp;
-
-	for (i = 0; i < nw; i++) {
-		writel(readl(fifo_ptr), wrdp);
-		wrdp++;
-	}
-
-	bytp = (u8 *)wrdp;
-	for (i = 0; i < nb; i++) {
-		writeb(readb(fifo_ptr), bytp);
-		fifo_ptr++;
-		bytp++;
-	}
-	readl(&outep_regs_p[epNum].write_done);
-
-	/* copy back tmp buffer to bufp if bufp is not word aligned */
-	if ((int)bufp & 0x3)
-		memcpy(bufp, tmp, len);
-
-	return 0;
-}
-
-static void usbputpcktofifo(int epNum, u8 *bufp, u32 len)
-{
-	u32 i, nw, nb;
-	u32 *wrdp;
-	u8 *bytp;
-	u8 *fifo_ptr = get_fifo(epNum, 1);
-
-	nw = len / sizeof(int);
-	nb = len % sizeof(int);
-	wrdp = (u32 *)bufp;
-	for (i = 0; i < nw; i++) {
-		writel(*wrdp, fifo_ptr);
-		wrdp++;
-	}
-
-	bytp = (u8 *)wrdp;
-	for (i = 0; i < nb; i++) {
-		writeb(*bytp, fifo_ptr);
-		fifo_ptr++;
-		bytp++;
-	}
-}
-
-/*
- * dw_write_noniso_tx_fifo - Write the next packet to TxFIFO.
- * @endpoint:		Endpoint pointer.
- *
- * If the endpoint has an active tx_urb, then the next packet of data from the
- * URB is written to the tx FIFO.  The total amount of data in the urb is given
- * by urb->actual_length.  The maximum amount of data that can be sent in any
- * one packet is given by endpoint->tx_packetSize.  The number of data bytes
- * from this URB that have already been transmitted is given by endpoint->sent.
- * endpoint->last is updated by this routine with the number of data bytes
- * transmitted in this packet.
- *
- */
-static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance
-				       *endpoint)
-{
-	struct urb *urb = endpoint->tx_urb;
-	int align;
-
-	if (urb) {
-		u32 last;
-
-		UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d",
-			urb->buffer, urb->buffer_length, urb->actual_length);
-
-		last = min_t(u32, urb->actual_length - endpoint->sent,
-			     endpoint->tx_packetSize);
-
-		if (last) {
-			u8 *cp = urb->buffer + endpoint->sent;
-
-			/*
-			 * This ensures that USBD packet fifo is accessed
-			 * - through word aligned pointer or
-			 * - through non word aligned pointer but only
-			 *   with a max length to make the next packet
-			 *   word aligned
-			 */
-
-			align = ((ulong)cp % sizeof(int));
-			if (align)
-				last = min(last, sizeof(int) - align);
-
-			UDCDBGA("endpoint->sent %d, tx_packetSize %d, last %d",
-				endpoint->sent, endpoint->tx_packetSize, last);
-
-			usbputpcktofifo(endpoint->endpoint_address &
-					USB_ENDPOINT_NUMBER_MASK, cp, last);
-		}
-		endpoint->last = last;
-	}
-}
-
-/*
- * Handle SETUP USB interrupt.
- * This function implements TRM Figure 14-14.
- */
-static void dw_udc_setup(struct usb_endpoint_instance *endpoint)
-{
-	u8 *datap = (u8 *)&ep0_urb->device_request;
-	int ep_addr = endpoint->endpoint_address;
-
-	UDCDBG("-> Entering device setup");
-	usbgetpckfromfifo(ep_addr, datap, 8);
-
-	/* Try to process setup packet */
-	if (ep0_recv_setup(ep0_urb)) {
-		/* Not a setup packet, stall next EP0 transaction */
-		udc_stall_ep(0);
-		UDCDBG("can't parse setup packet, still waiting for setup");
-		return;
-	}
-
-	/* Check direction */
-	if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
-	    == USB_REQ_HOST2DEVICE) {
-		UDCDBG("control write on EP0");
-		if (le16_to_cpu(ep0_urb->device_request.wLength)) {
-			/* Stall this request */
-			UDCDBG("Stalling unsupported EP0 control write data "
-			       "stage.");
-			udc_stall_ep(0);
-		}
-	} else {
-
-		UDCDBG("control read on EP0");
-		/*
-		 * The ep0_recv_setup function has already placed our response
-		 * packet data in ep0_urb->buffer and the packet length in
-		 * ep0_urb->actual_length.
-		 */
-		endpoint->tx_urb = ep0_urb;
-		endpoint->sent = 0;
-		/*
-		 * Write packet data to the FIFO.  dw_write_noniso_tx_fifo
-		 * will update endpoint->last with the number of bytes written
-		 * to the FIFO.
-		 */
-		dw_write_noniso_tx_fifo(endpoint);
-
-		writel(0x0, &inep_regs_p[ep_addr].write_done);
-	}
-
-	udc_unset_nak(endpoint->endpoint_address);
-
-	UDCDBG("<- Leaving device setup");
-}
-
-/*
- * Handle endpoint 0 RX interrupt
- */
-static void dw_udc_ep0_rx(struct usb_endpoint_instance *endpoint)
-{
-	u8 dummy[64];
-
-	UDCDBG("RX on EP0");
-
-	/* Check direction */
-	if ((ep0_urb->device_request.bmRequestType
-	     & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
-		/*
-		 * This rx interrupt must be for a control write data
-		 * stage packet.
-		 *
-		 * We don't support control write data stages.
-		 * We should never end up here.
-		 */
-
-		UDCDBG("Stalling unexpected EP0 control write "
-		       "data stage packet");
-		udc_stall_ep(0);
-	} else {
-		/*
-		 * This rx interrupt must be for a control read status
-		 * stage packet.
-		 */
-		UDCDBG("ACK on EP0 control read status stage packet");
-		u32 len = (readl(&outep_regs_p[0].endp_status) >> 11) & 0xfff;
-		usbgetpckfromfifo(0, dummy, len);
-	}
-}
-
-/*
- * Handle endpoint 0 TX interrupt
- */
-static void dw_udc_ep0_tx(struct usb_endpoint_instance *endpoint)
-{
-	struct usb_device_request *request = &ep0_urb->device_request;
-	int ep_addr;
-
-	UDCDBG("TX on EP0");
-
-	/* Check direction */
-	if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) ==
-	    USB_REQ_HOST2DEVICE) {
-		/*
-		 * This tx interrupt must be for a control write status
-		 * stage packet.
-		 */
-		UDCDBG("ACK on EP0 control write status stage packet");
-	} else {
-		/*
-		 * This tx interrupt must be for a control read data
-		 * stage packet.
-		 */
-		int wLength = le16_to_cpu(request->wLength);
-
-		/*
-		 * Update our count of bytes sent so far in this
-		 * transfer.
-		 */
-		endpoint->sent += endpoint->last;
-
-		/*
-		 * We are finished with this transfer if we have sent
-		 * all of the bytes in our tx urb (urb->actual_length)
-		 * unless we need a zero-length terminating packet.  We
-		 * need a zero-length terminating packet if we returned
-		 * fewer bytes than were requested (wLength) by the host,
-		 * and the number of bytes we returned is an exact
-		 * multiple of the packet size endpoint->tx_packetSize.
-		 */
-		if ((endpoint->sent == ep0_urb->actual_length) &&
-		    ((ep0_urb->actual_length == wLength) ||
-		     (endpoint->last != endpoint->tx_packetSize))) {
-			/* Done with control read data stage. */
-			UDCDBG("control read data stage complete");
-		} else {
-			/*
-			 * We still have another packet of data to send
-			 * in this control read data stage or else we
-			 * need a zero-length terminating packet.
-			 */
-			UDCDBG("ACK control read data stage packet");
-			dw_write_noniso_tx_fifo(endpoint);
-
-			ep_addr = endpoint->endpoint_address;
-			writel(0x0, &inep_regs_p[ep_addr].write_done);
-		}
-	}
-}
-
-static struct usb_endpoint_instance *dw_find_ep(int ep)
-{
-	int i;
-
-	for (i = 0; i < udc_device->bus->max_endpoints; i++) {
-		if ((udc_device->bus->endpoint_array[i].endpoint_address &
-		     USB_ENDPOINT_NUMBER_MASK) == ep)
-			return &udc_device->bus->endpoint_array[i];
-	}
-	return NULL;
-}
-
-/*
- * Handle RX transaction on non-ISO endpoint.
- * The ep argument is a physical endpoint number for a non-ISO IN endpoint
- * in the range 1 to 15.
- */
-static void dw_udc_epn_rx(int ep)
-{
-	int nbytes = 0;
-	struct urb *urb;
-	struct usb_endpoint_instance *endpoint = dw_find_ep(ep);
-
-	if (endpoint) {
-		urb = endpoint->rcv_urb;
-
-		if (urb) {
-			u8 *cp = urb->buffer + urb->actual_length;
-
-			nbytes = (readl(&outep_regs_p[ep].endp_status) >> 11) &
-			    0xfff;
-			usbgetpckfromfifo(ep, cp, nbytes);
-			usbd_rcv_complete(endpoint, nbytes, 0);
-		}
-	}
-}
-
-/*
- * Handle TX transaction on non-ISO endpoint.
- * The ep argument is a physical endpoint number for a non-ISO IN endpoint
- * in the range 16 to 30.
- */
-static void dw_udc_epn_tx(int ep)
-{
-	struct usb_endpoint_instance *endpoint = dw_find_ep(ep);
-
-	if (!endpoint)
-		return;
-
-	/*
-	 * We need to transmit a terminating zero-length packet now if
-	 * we have sent all of the data in this URB and the transfer
-	 * size was an exact multiple of the packet size.
-	 */
-	if (endpoint->tx_urb &&
-	    (endpoint->last == endpoint->tx_packetSize) &&
-	    (endpoint->tx_urb->actual_length - endpoint->sent -
-	     endpoint->last == 0)) {
-		/* handle zero length packet here */
-		writel(0x0, &inep_regs_p[ep].write_done);
-
-	}
-
-	if (endpoint->tx_urb && endpoint->tx_urb->actual_length) {
-		/* retire the data that was just sent */
-		usbd_tx_complete(endpoint);
-		/*
-		 * Check to see if we have more data ready to transmit
-		 * now.
-		 */
-		if (endpoint->tx_urb && endpoint->tx_urb->actual_length) {
-			/* write data to FIFO */
-			dw_write_noniso_tx_fifo(endpoint);
-			writel(0x0, &inep_regs_p[ep].write_done);
-
-		} else if (endpoint->tx_urb
-			   && (endpoint->tx_urb->actual_length == 0)) {
-			/* udc_set_nak(ep); */
-		}
-	}
-}
-
-/*
- * Start of public functions.
- */
-
-/* Called to start packet transmission. */
-int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
-{
-	udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK);
-	return 0;
-}
-
-/* Start to initialize h/w stuff */
-int udc_init(void)
-{
-	int i;
-	u32 plug_st;
-
-	udc_device = NULL;
-
-	UDCDBG("starting");
-
-	readl(&plug_regs_p->plug_pending);
-
-	for (i = 0; i < UDC_INIT_MDELAY; i++)
-		udelay(1000);
-
-	plug_st = readl(&plug_regs_p->plug_state);
-	writel(plug_st | PLUG_STATUS_EN, &plug_regs_p->plug_state);
-
-	writel(~0x0, &udc_regs_p->endp_int);
-	writel(~0x0, &udc_regs_p->dev_int_mask);
-	writel(~0x0, &udc_regs_p->endp_int_mask);
-
-#ifndef CONFIG_USBD_HS
-	writel(DEV_CONF_FS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW |
-	       DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf);
-#else
-	writel(DEV_CONF_HS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW |
-			DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf);
-#endif
-
-	writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl);
-
-	/* Clear all interrupts pending */
-	writel(DEV_INT_MSK, &udc_regs_p->dev_int);
-
-	return 0;
-}
-
-int is_usbd_high_speed(void)
-{
-	return (readl(&udc_regs_p->dev_stat) & DEV_STAT_ENUM) ? 0 : 1;
-}
-
-/*
- * udc_setup_ep - setup endpoint
- * Associate a physical endpoint with endpoint_instance
- */
-void udc_setup_ep(struct usb_device_instance *device,
-		  u32 ep, struct usb_endpoint_instance *endpoint)
-{
-	UDCDBGA("setting up endpoint addr %x", endpoint->endpoint_address);
-	int ep_addr;
-	int ep_num, ep_type;
-	int packet_size;
-	int buffer_size;
-	int attributes;
-	char *tt;
-	u32 endp_intmask;
-
-	if ((ep != 0) && (udc_device->device_state < STATE_ADDRESSED))
-		return;
-
-	tt = env_get("usbtty");
-	if (!tt)
-		tt = "generic";
-
-	ep_addr = endpoint->endpoint_address;
-	ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-
-	if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-		/* IN endpoint */
-		packet_size = endpoint->tx_packetSize;
-		buffer_size = packet_size * 2;
-		attributes = endpoint->tx_attributes;
-	} else {
-		/* OUT endpoint */
-		packet_size = endpoint->rcv_packetSize;
-		buffer_size = packet_size * 2;
-		attributes = endpoint->rcv_attributes;
-	}
-
-	switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {
-	case USB_ENDPOINT_XFER_CONTROL:
-		ep_type = ENDP_EPTYPE_CNTL;
-		break;
-	case USB_ENDPOINT_XFER_BULK:
-	default:
-		ep_type = ENDP_EPTYPE_BULK;
-		break;
-	case USB_ENDPOINT_XFER_INT:
-		ep_type = ENDP_EPTYPE_INT;
-		break;
-	case USB_ENDPOINT_XFER_ISOC:
-		ep_type = ENDP_EPTYPE_ISO;
-		break;
-	}
-
-	struct udc_endp_regs *out_p = &outep_regs_p[ep_num];
-	struct udc_endp_regs *in_p = &inep_regs_p[ep_num];
-
-	if (!ep_addr) {
-		/* Setup endpoint 0 */
-		buffer_size = packet_size;
-
-		writel(readl(&in_p->endp_cntl) | ENDP_CNTL_CNAK,
-		       &in_p->endp_cntl);
-
-		writel(readl(&out_p->endp_cntl) | ENDP_CNTL_CNAK,
-		       &out_p->endp_cntl);
-
-		writel(ENDP_CNTL_CONTROL | ENDP_CNTL_FLUSH, &in_p->endp_cntl);
-
-		writel(buffer_size / sizeof(int), &in_p->endp_bsorfn);
-
-		writel(packet_size, &in_p->endp_maxpacksize);
-
-		writel(ENDP_CNTL_CONTROL | ENDP_CNTL_RRDY, &out_p->endp_cntl);
-
-		writel(packet_size | ((buffer_size / sizeof(int)) << 16),
-		       &out_p->endp_maxpacksize);
-
-	} else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-		/* Setup the IN endpoint */
-		writel(0x0, &in_p->endp_status);
-		writel((ep_type << 4) | ENDP_CNTL_RRDY, &in_p->endp_cntl);
-		writel(buffer_size / sizeof(int), &in_p->endp_bsorfn);
-		writel(packet_size, &in_p->endp_maxpacksize);
-
-		if (!strcmp(tt, "cdc_acm")) {
-			if (ep_type == ENDP_EPTYPE_INT) {
-				/* Conf no. 1 Interface no. 0 */
-				writel((packet_size << 19) |
-				       ENDP_EPDIR_IN | (1 << 7) |
-				       (0 << 11) | (ep_type << 5) | ep_num,
-				       &udc_regs_p->udc_endp_reg[ep_num]);
-			} else {
-				/* Conf no. 1 Interface no. 1 */
-				writel((packet_size << 19) |
-				       ENDP_EPDIR_IN | (1 << 7) |
-				       (1 << 11) | (ep_type << 5) | ep_num,
-				       &udc_regs_p->udc_endp_reg[ep_num]);
-			}
-		} else {
-			/* Conf no. 1 Interface no. 0 */
-			writel((packet_size << 19) |
-			       ENDP_EPDIR_IN | (1 << 7) |
-			       (0 << 11) | (ep_type << 5) | ep_num,
-			       &udc_regs_p->udc_endp_reg[ep_num]);
-		}
-
-	} else {
-		/* Setup the OUT endpoint */
-		writel(0x0, &out_p->endp_status);
-		writel((ep_type << 4) | ENDP_CNTL_RRDY, &out_p->endp_cntl);
-		writel(packet_size | ((buffer_size / sizeof(int)) << 16),
-		       &out_p->endp_maxpacksize);
-
-		if (!strcmp(tt, "cdc_acm")) {
-			writel((packet_size << 19) |
-			       ENDP_EPDIR_OUT | (1 << 7) |
-			       (1 << 11) | (ep_type << 5) | ep_num,
-			       &udc_regs_p->udc_endp_reg[ep_num]);
-		} else {
-			writel((packet_size << 19) |
-			       ENDP_EPDIR_OUT | (1 << 7) |
-			       (0 << 11) | (ep_type << 5) | ep_num,
-			       &udc_regs_p->udc_endp_reg[ep_num]);
-		}
-
-	}
-
-	endp_intmask = readl(&udc_regs_p->endp_int_mask);
-	endp_intmask &= ~((1 << ep_num) | 0x10000 << ep_num);
-	writel(endp_intmask, &udc_regs_p->endp_int_mask);
-}
-
-/* Turn on the USB connection by enabling the pullup resistor */
-void udc_connect(void)
-{
-	u32 plug_st, dev_cntl;
-
-	dev_cntl = readl(&udc_regs_p->dev_cntl);
-	dev_cntl |= DEV_CNTL_SOFTDISCONNECT;
-	writel(dev_cntl, &udc_regs_p->dev_cntl);
-
-	udelay(1000);
-
-	dev_cntl = readl(&udc_regs_p->dev_cntl);
-	dev_cntl &= ~DEV_CNTL_SOFTDISCONNECT;
-	writel(dev_cntl, &udc_regs_p->dev_cntl);
-
-	plug_st = readl(&plug_regs_p->plug_state);
-	plug_st &= ~(PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE);
-	writel(plug_st, &plug_regs_p->plug_state);
-}
-
-/* Turn off the USB connection by disabling the pullup resistor */
-void udc_disconnect(void)
-{
-	u32 plug_st;
-
-	writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl);
-
-	plug_st = readl(&plug_regs_p->plug_state);
-	plug_st |= (PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE);
-	writel(plug_st, &plug_regs_p->plug_state);
-}
-
-/* Switch on the UDC */
-void udc_enable(struct usb_device_instance *device)
-{
-	UDCDBGA("enable device %p, status %d", device, device->status);
-
-	/* Save the device structure pointer */
-	udc_device = device;
-
-	/* Setup ep0 urb */
-	if (!ep0_urb) {
-		ep0_urb =
-		    usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array);
-	} else {
-		serial_printf("udc_enable: ep0_urb already allocated %p\n",
-			      ep0_urb);
-	}
-
-	writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask);
-}
-
-/**
- * udc_startup - allow udc code to do any additional startup
- */
-void udc_startup_events(struct usb_device_instance *device)
-{
-	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
-	usbd_device_event_irq(device, DEVICE_INIT, 0);
-
-	/*
-	 * The DEVICE_CREATE event puts the USB device in the state
-	 * STATE_ATTACHED.
-	 */
-	usbd_device_event_irq(device, DEVICE_CREATE, 0);
-
-	/*
-	 * Some USB controller driver implementations signal
-	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
-	 * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
-	 * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
-	 * The DW USB client controller has the capability to detect when the
-	 * USB cable is connected to a powered USB bus, so we will defer the
-	 * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later.
-	 */
-
-	udc_enable(device);
-}
-
-/*
- * Plug detection interrupt handling
- */
-static void dw_udc_plug_irq(void)
-{
-	if (readl(&plug_regs_p->plug_state) & PLUG_STATUS_ATTACHED) {
-		/*
-		 * USB cable attached
-		 * Turn off PHY reset bit (PLUG detect).
-		 * Switch PHY opmode to normal operation (PLUG detect).
-		 */
-		udc_connect();
-		writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask);
-
-		UDCDBG("device attached and powered");
-		udc_state_transition(udc_device->device_state, STATE_POWERED);
-	} else {
-		writel(~0x0, &udc_regs_p->dev_int_mask);
-
-		UDCDBG("device detached or unpowered");
-		udc_state_transition(udc_device->device_state, STATE_ATTACHED);
-	}
-}
-
-/*
- * Device interrupt handling
- */
-static void dw_udc_dev_irq(void)
-{
-	if (readl(&udc_regs_p->dev_int) & DEV_INT_USBRESET) {
-		writel(~0x0, &udc_regs_p->endp_int_mask);
-
-		writel(readl(&inep_regs_p[0].endp_cntl) | ENDP_CNTL_FLUSH,
-		       &inep_regs_p[0].endp_cntl);
-
-		writel(DEV_INT_USBRESET, &udc_regs_p->dev_int);
-
-		/*
-		 * This endpoint0 specific register can be programmed only
-		 * after the phy clock is initialized
-		 */
-		writel((EP0_MAX_PACKET_SIZE << 19) | ENDP_EPTYPE_CNTL,
-				&udc_regs_p->udc_endp_reg[0]);
-
-		UDCDBG("device reset in progess");
-		udc_state_transition(udc_device->device_state, STATE_DEFAULT);
-	}
-
-	/* Device Enumeration completed */
-	if (readl(&udc_regs_p->dev_int) & DEV_INT_ENUM) {
-		writel(DEV_INT_ENUM, &udc_regs_p->dev_int);
-
-		/* Endpoint interrupt enabled for Ctrl IN & Ctrl OUT */
-		writel(readl(&udc_regs_p->endp_int_mask) & ~0x10001,
-		       &udc_regs_p->endp_int_mask);
-
-		UDCDBG("default -> addressed");
-		udc_state_transition(udc_device->device_state, STATE_ADDRESSED);
-	}
-
-	/* The USB will be in SUSPEND in 3 ms */
-	if (readl(&udc_regs_p->dev_int) & DEV_INT_INACTIVE) {
-		writel(DEV_INT_INACTIVE, &udc_regs_p->dev_int);
-
-		UDCDBG("entering inactive state");
-		/* usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); */
-	}
-
-	/* SetConfiguration command received */
-	if (readl(&udc_regs_p->dev_int) & DEV_INT_SETCFG) {
-		writel(DEV_INT_SETCFG, &udc_regs_p->dev_int);
-
-		UDCDBG("entering configured state");
-		udc_state_transition(udc_device->device_state,
-				     STATE_CONFIGURED);
-	}
-
-	/* SetInterface command received */
-	if (readl(&udc_regs_p->dev_int) & DEV_INT_SETINTF)
-		writel(DEV_INT_SETINTF, &udc_regs_p->dev_int);
-
-	/* USB Suspend detected on cable */
-	if (readl(&udc_regs_p->dev_int) & DEV_INT_SUSPUSB) {
-		writel(DEV_INT_SUSPUSB, &udc_regs_p->dev_int);
-
-		UDCDBG("entering suspended state");
-		usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0);
-	}
-
-	/* USB Start-Of-Frame detected on cable */
-	if (readl(&udc_regs_p->dev_int) & DEV_INT_SOF)
-		writel(DEV_INT_SOF, &udc_regs_p->dev_int);
-}
-
-/*
- * Endpoint interrupt handling
- */
-static void dw_udc_endpoint_irq(void)
-{
-	while (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLOUT) {
-
-		writel(ENDP0_INT_CTRLOUT, &udc_regs_p->endp_int);
-
-		if ((readl(&outep_regs_p[0].endp_status) & ENDP_STATUS_OUTMSK)
-		    == ENDP_STATUS_OUT_SETUP) {
-			dw_udc_setup(udc_device->bus->endpoint_array + 0);
-			writel(ENDP_STATUS_OUT_SETUP,
-			       &outep_regs_p[0].endp_status);
-
-		} else if ((readl(&outep_regs_p[0].endp_status) &
-			    ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) {
-			dw_udc_ep0_rx(udc_device->bus->endpoint_array + 0);
-			writel(ENDP_STATUS_OUT_DATA,
-			       &outep_regs_p[0].endp_status);
-
-		} else if ((readl(&outep_regs_p[0].endp_status) &
-			    ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) {
-			/* NONE received */
-		}
-
-		writel(0x0, &outep_regs_p[0].endp_status);
-	}
-
-	if (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLIN) {
-		dw_udc_ep0_tx(udc_device->bus->endpoint_array + 0);
-
-		writel(ENDP_STATUS_IN, &inep_regs_p[0].endp_status);
-		writel(ENDP0_INT_CTRLIN, &udc_regs_p->endp_int);
-	}
-
-	if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOOUT_MSK) {
-		u32 epnum = 0;
-		u32 ep_int = readl(&udc_regs_p->endp_int) &
-		    ENDP_INT_NONISOOUT_MSK;
-
-		ep_int >>= 16;
-		while (0x0 == (ep_int & 0x1)) {
-			ep_int >>= 1;
-			epnum++;
-		}
-
-		writel((1 << 16) << epnum, &udc_regs_p->endp_int);
-
-		if ((readl(&outep_regs_p[epnum].endp_status) &
-		     ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) {
-
-			dw_udc_epn_rx(epnum);
-			writel(ENDP_STATUS_OUT_DATA,
-			       &outep_regs_p[epnum].endp_status);
-		} else if ((readl(&outep_regs_p[epnum].endp_status) &
-			    ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) {
-			writel(0x0, &outep_regs_p[epnum].endp_status);
-		}
-	}
-
-	if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOIN_MSK) {
-		u32 epnum = 0;
-		u32 ep_int = readl(&udc_regs_p->endp_int) &
-		    ENDP_INT_NONISOIN_MSK;
-
-		while (0x0 == (ep_int & 0x1)) {
-			ep_int >>= 1;
-			epnum++;
-		}
-
-		if (readl(&inep_regs_p[epnum].endp_status) & ENDP_STATUS_IN) {
-			writel(ENDP_STATUS_IN,
-			       &outep_regs_p[epnum].endp_status);
-			dw_udc_epn_tx(epnum);
-
-			writel(ENDP_STATUS_IN,
-			       &outep_regs_p[epnum].endp_status);
-		}
-
-		writel((1 << epnum), &udc_regs_p->endp_int);
-	}
-}
-
-/*
- * UDC interrupts
- */
-void udc_irq(void)
-{
-	/*
-	 * Loop while we have interrupts.
-	 * If we don't do this, the input chain
-	 * polling delay is likely to miss
-	 * host requests.
-	 */
-	while (readl(&plug_regs_p->plug_pending))
-		dw_udc_plug_irq();
-
-	while (readl(&udc_regs_p->dev_int))
-		dw_udc_dev_irq();
-
-	if (readl(&udc_regs_p->endp_int))
-		dw_udc_endpoint_irq();
-}
-
-/* Flow control */
-void udc_set_nak(int epid)
-{
-	writel(readl(&inep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK,
-	       &inep_regs_p[epid].endp_cntl);
-
-	writel(readl(&outep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK,
-	       &outep_regs_p[epid].endp_cntl);
-}
-
-void udc_unset_nak(int epid)
-{
-	u32 val;
-
-	val = readl(&inep_regs_p[epid].endp_cntl);
-	val &= ~ENDP_CNTL_SNAK;
-	val |= ENDP_CNTL_CNAK;
-	writel(val, &inep_regs_p[epid].endp_cntl);
-
-	val = readl(&outep_regs_p[epid].endp_cntl);
-	val &= ~ENDP_CNTL_SNAK;
-	val |= ENDP_CNTL_CNAK;
-	writel(val, &outep_regs_p[epid].endp_cntl);
-}
diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c
index 9710b79..30cfc56 100644
--- a/drivers/virtio/virtio_blk.c
+++ b/drivers/virtio/virtio_blk.c
@@ -75,7 +75,7 @@
 	struct blk_desc *desc = dev_get_uclass_plat(dev);
 	int devnum;
 
-	desc->if_type = UCLASS_VIRTIO;
+	desc->uclass_id = UCLASS_VIRTIO;
 	/*
 	 * Initialize the devnum to -ENODEV. This is to make sure that
 	 * blk_next_free_devnum() works as expected, since the default
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index b098b2e..368b368 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -145,6 +145,7 @@
 static const struct udevice_id mtk_wdt_ids[] = {
 	{ .compatible = "mediatek,wdt"},
 	{ .compatible = "mediatek,mt6589-wdt"},
+	{ .compatible = "mediatek,mt7986-wdt" },
 	{}
 };
 
diff --git a/drivers/xen/pvblock.c b/drivers/xen/pvblock.c
index 1090e52..970182c 100644
--- a/drivers/xen/pvblock.c
+++ b/drivers/xen/pvblock.c
@@ -665,7 +665,7 @@
 	struct blk_desc *desc = dev_get_uclass_plat(udev);
 	int devnum;
 
-	desc->if_type = UCLASS_PVBLOCK;
+	desc->uclass_id = UCLASS_PVBLOCK;
 	/*
 	 * Initialize the devnum to -ENODEV. This is to make sure that
 	 * blk_next_free_devnum() works as expected, since the default
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index c64e253..a945904 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -1145,7 +1145,7 @@
 	}
 
 	if (blk_enabled()) {
-		printf("Interface:  %s\n", blk_get_if_type_name(cur_dev->if_type));
+		printf("Interface:  %s\n", blk_get_uclass_name(cur_dev->uclass_id));
 		printf("  Device %d: ", cur_dev->devnum);
 		dev_print(cur_dev);
 	}
diff --git a/include/_exports.h b/include/_exports.h
index f6df8b6..1af946f 100644
--- a/include/_exports.h
+++ b/include/_exports.h
@@ -12,6 +12,9 @@
 	EXPORT_FUNC(tstc, int, tstc, void)
 	EXPORT_FUNC(putc, void, putc, const char)
 	EXPORT_FUNC(puts, void, puts, const char *)
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+	EXPORT_FUNC(flush, void, flush, void)
+#endif
 	EXPORT_FUNC(printf, int, printf, const char*, ...)
 #if (defined(CONFIG_X86) && !defined(CONFIG_X86_64)) || defined(CONFIG_PPC)
 	EXPORT_FUNC(irq_install_handler, void, install_hdlr,
diff --git a/include/blk.h b/include/blk.h
index 279f9ea..8806c38 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -54,7 +54,7 @@
 	 * TODO: With driver model we should be able to use the parent
 	 * device's uclass instead.
 	 */
-	enum uclass_id	if_type;	/* type of the interface */
+	enum uclass_id	uclass_id;	/* type of the interface */
 	int		devnum;		/* device number */
 	unsigned char	part_type;	/* partition type */
 	unsigned char	target;		/* target SCSI ID */
@@ -114,7 +114,7 @@
 /**
  * blkcache_read() - attempt to read a set of blocks from cache
  *
- * @param iftype - IF_TYPE_x for type of device
+ * @param iftype - uclass_id_x for type of device
  * @param dev - device index of particular type
  * @param start - starting block number
  * @param blkcnt - number of blocks to read
@@ -131,7 +131,7 @@
  * blkcache_fill() - make data read from a block device available
  * to the block cache
  *
- * @param iftype - IF_TYPE_x for type of device
+ * @param iftype - uclass_id_x for type of device
  * @param dev - device index of particular type
  * @param start - starting block number
  * @param blkcnt - number of blocks available
@@ -147,7 +147,7 @@
  * blkcache_invalidate() - discard the cache for a set of blocks
  * because of a write or device (re)initialization.
  *
- * @param iftype - IF_TYPE_x for type of device
+ * @param iftype - uclass_id_x for type of device
  * @param dev - device index of particular type
  */
 void blkcache_invalidate(int iftype, int dev);
@@ -279,22 +279,22 @@
  * This function does not activate the device. The device will be returned
  * whether or not it is activated.
  *
- * @if_type:	Interface type (enum uclass_id_t)
+ * @uclass_id:	Interface type (enum uclass_id_t)
  * @devnum:	Device number (specific to each interface type)
  * @devp:	the device, if found
  * Return: 0 if found, -ENODEV if no device found, or other -ve error value
  */
-int blk_find_device(int if_type, int devnum, struct udevice **devp);
+int blk_find_device(int uclass_id, int devnum, struct udevice **devp);
 
 /**
  * blk_get_device() - Find and probe a block device ready for use
  *
- * @if_type:	Interface type (enum uclass_id_t)
+ * @uclass_id:	Interface type (enum uclass_id_t)
  * @devnum:	Device number (specific to each interface type)
  * @devp:	the device, if found
  * Return: 0 if found, -ENODEV if no device found, or other -ve error value
  */
-int blk_get_device(int if_type, int devnum, struct udevice **devp);
+int blk_get_device(int uclass_id, int devnum, struct udevice **devp);
 
 /**
  * blk_first_device() - Find the first device for a given interface
@@ -305,7 +305,7 @@
  * @devp:	the device, if found
  * Return: 0 if found, -ENODEV if no device, or other -ve error value
  */
-int blk_first_device(int if_type, struct udevice **devp);
+int blk_first_device(int uclass_id, struct udevice **devp);
 
 /**
  * blk_next_device() - Find the next device for a given interface
@@ -327,7 +327,7 @@
  * @parent:	Parent of the new device
  * @drv_name:	Driver name to use for the block device
  * @name:	Name for the device
- * @if_type:	Interface type (enum uclass_id_t)
+ * @uclass_id:	Interface type (enum uclass_id_t)
  * @devnum:	Device number, specific to the interface type, or -1 to
  *		allocate the next available number
  * @blksz:	Block size of the device in bytes (typically 512)
@@ -335,7 +335,7 @@
  * @devp:	the new device (which has not been probed)
  */
 int blk_create_device(struct udevice *parent, const char *drv_name,
-		      const char *name, int if_type, int devnum, int blksz,
+		      const char *name, int uclass_id, int devnum, int blksz,
 		      lbaint_t lba, struct udevice **devp);
 
 /**
@@ -344,7 +344,7 @@
  * @parent:	Parent of the new device
  * @drv_name:	Driver name to use for the block device
  * @name:	Name for the device (parent name is prepended)
- * @if_type:	Interface type (enum uclass_id_t)
+ * @uclass_id:	Interface type (enum uclass_id_t)
  * @devnum:	Device number, specific to the interface type, or -1 to
  *		allocate the next available number
  * @blksz:	Block size of the device in bytes (typically 512)
@@ -352,7 +352,7 @@
  * @devp:	the new device (which has not been probed)
  */
 int blk_create_devicef(struct udevice *parent, const char *drv_name,
-		       const char *name, int if_type, int devnum, int blksz,
+		       const char *name, int uclass_id, int devnum, int blksz,
 		       lbaint_t lba, struct udevice **devp);
 
 /**
@@ -372,33 +372,33 @@
  *
  * The devices are removed and then unbound.
  *
- * @if_type:	Interface type to unbind
+ * @uclass_id:	Interface type to unbind
  * Return: 0 if OK, -ve on error
  */
-int blk_unbind_all(int if_type);
+int blk_unbind_all(int uclass_id);
 
 /**
  * blk_find_max_devnum() - find the maximum device number for an interface type
  *
- * Finds the last allocated device number for an interface type @if_type. The
+ * Finds the last allocated device number for an interface type @uclass_id. The
  * next number is safe to use for a newly allocated device.
  *
- * @if_type:	Interface type to scan
+ * @uclass_id:	Interface type to scan
  * Return: maximum device number found, or -ENODEV if none, or other -ve on
  * error
  */
-int blk_find_max_devnum(enum uclass_id if_type);
+int blk_find_max_devnum(enum uclass_id uclass_id);
 
 /**
  * blk_next_free_devnum() - get the next device number for an interface type
  *
  * Finds the next number that is safe to use for a newly allocated device for
- * an interface type @if_type.
+ * an interface type @uclass_id.
  *
- * @if_type:	Interface type to scan
+ * @uclass_id:	Interface type to scan
  * Return: next device number safe to use, or -ve on error
  */
-int blk_next_free_devnum(enum uclass_id if_type);
+int blk_next_free_devnum(enum uclass_id uclass_id);
 
 /**
  * blk_select_hwpart() - select a hardware partition
@@ -447,7 +447,7 @@
 			      lbaint_t blkcnt, void *buffer)
 {
 	ulong blks_read;
-	if (blkcache_read(block_dev->if_type, block_dev->devnum,
+	if (blkcache_read(block_dev->uclass_id, block_dev->devnum,
 			  start, blkcnt, block_dev->blksz, buffer))
 		return blkcnt;
 
@@ -458,7 +458,7 @@
 	 */
 	blks_read = block_dev->block_read(block_dev, start, blkcnt, buffer);
 	if (blks_read == blkcnt)
-		blkcache_fill(block_dev->if_type, block_dev->devnum,
+		blkcache_fill(block_dev->uclass_id, block_dev->devnum,
 			      start, blkcnt, block_dev->blksz, buffer);
 
 	return blks_read;
@@ -467,14 +467,14 @@
 static inline ulong blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
 			       lbaint_t blkcnt, const void *buffer)
 {
-	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+	blkcache_invalidate(block_dev->uclass_id, block_dev->devnum);
 	return block_dev->block_write(block_dev, start, blkcnt, buffer);
 }
 
 static inline ulong blk_derase(struct blk_desc *block_dev, lbaint_t start,
 			       lbaint_t blkcnt)
 {
-	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
+	blkcache_invalidate(block_dev->uclass_id, block_dev->devnum);
 	return block_dev->block_erase(block_dev, start, blkcnt);
 }
 
@@ -485,15 +485,15 @@
  * driver should be provided using U_BOOT_LEGACY_BLK() for each interface
  * type that is to be supported.
  *
- * @if_typename:	Interface type name
- * @if_type:		Interface type
+ * @uclass_idname:	Interface type name
+ * @uclass_id:		Interface type
  * @max_devs:		Maximum number of devices supported
  * @desc:		Pointer to list of devices for this interface type,
  *			or NULL to use @get_dev() instead
  */
 struct blk_driver {
-	const char *if_typename;
-	enum uclass_id if_type;
+	const char *uclass_idname;
+	enum uclass_id uclass_id;
 	int max_devs;
 	struct blk_desc *desc;
 	/**
@@ -540,33 +540,33 @@
 #define U_BOOT_LEGACY_BLK(__name)					\
 	ll_entry_declare(struct blk_driver, __name, blk_driver)
 
-struct blk_driver *blk_driver_lookup_type(int if_type);
+struct blk_driver *blk_driver_lookup_type(int uclass_id);
 
 #endif /* !CONFIG_BLK */
 
 /**
- * blk_get_devnum_by_typename() - Get a block device by type and number
+ * blk_get_devnum_by_uclass_idname() - Get a block device by type and number
  *
  * This looks through the available block devices of the given type, returning
  * the one with the given @devnum.
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  * @devnum:	Device number
  * Return: point to block device descriptor, or NULL if not found
  */
-struct blk_desc *blk_get_devnum_by_type(enum uclass_id if_type, int devnum);
+struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum);
 
 /**
- * blk_get_devnum_by_type() - Get a block device by type name, and number
+ * blk_get_devnum_by_uclass_id() - Get a block device by type name, and number
  *
- * This looks up the block device type based on @if_typename, then calls
- * blk_get_devnum_by_type().
+ * This looks up the block device type based on @uclass_idname, then calls
+ * blk_get_devnum_by_uclass_id().
  *
- * @if_typename:	Block device type name
+ * @uclass_idname:	Block device type name
  * @devnum:		Device number
  * Return: point to block device descriptor, or NULL if not found
  */
-struct blk_desc *blk_get_devnum_by_typename(const char *if_typename,
+struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname,
 					    int devnum);
 
 /**
@@ -585,34 +585,34 @@
 /**
  * blk_list_part() - list the partitions for block devices of a given type
  *
- * This looks up the partition type for each block device of type @if_type,
+ * This looks up the partition type for each block device of type @uclass_id,
  * then displays a list of partitions.
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  * Return: 0 if OK, -ENODEV if there is none of that type
  */
-int blk_list_part(enum uclass_id if_type);
+int blk_list_part(enum uclass_id uclass_id);
 
 /**
  * blk_list_devices() - list the block devices of a given type
  *
- * This lists each block device of the type @if_type, showing the capacity
+ * This lists each block device of the type @uclass_id, showing the capacity
  * as well as type-specific information.
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  */
-void blk_list_devices(enum uclass_id if_type);
+void blk_list_devices(enum uclass_id uclass_id);
 
 /**
  * blk_show_device() - show information about a given block device
  *
  * This shows the block device capacity as well as type-specific information.
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  * @devnum:	Device number
  * Return: 0 if OK, -ENODEV for invalid device number
  */
-int blk_show_device(enum uclass_id if_type, int devnum);
+int blk_show_device(enum uclass_id uclass_id, int devnum);
 
 /**
  * blk_print_device_num() - show information about a given block device
@@ -620,45 +620,45 @@
  * This is similar to blk_show_device() but returns an error if the block
  * device type is unknown.
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  * @devnum:	Device number
  * Return: 0 if OK, -ENODEV for invalid device number, -ENOENT if the block
  * device is not connected
  */
-int blk_print_device_num(enum uclass_id if_type, int devnum);
+int blk_print_device_num(enum uclass_id uclass_id, int devnum);
 
 /**
  * blk_print_part_devnum() - print the partition information for a device
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  * @devnum:	Device number
  * Return: 0 if OK, -ENOENT if the block device is not connected, -ENOSYS if
  * the interface type is not supported, other -ve on other error
  */
-int blk_print_part_devnum(enum uclass_id if_type, int devnum);
+int blk_print_part_devnum(enum uclass_id uclass_id, int devnum);
 
 /**
  * blk_read_devnum() - read blocks from a device
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  * @devnum:	Device number
  * @blkcnt:	Number of blocks to read
  * @buffer:	Address to write data to
  * Return: number of blocks read, or -ve error number on error
  */
-ulong blk_read_devnum(enum uclass_id if_type, int devnum, lbaint_t start,
+ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
 		      lbaint_t blkcnt, void *buffer);
 
 /**
  * blk_write_devnum() - write blocks to a device
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  * @devnum:	Device number
  * @blkcnt:	Number of blocks to write
  * @buffer:	Address to read data from
  * Return: number of blocks written, or -ve error number on error
  */
-ulong blk_write_devnum(enum uclass_id if_type, int devnum, lbaint_t start,
+ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
 		       lbaint_t blkcnt, const void *buffer);
 
 /**
@@ -667,31 +667,31 @@
  * This is similar to blk_dselect_hwpart() but it looks up the interface and
  * device number.
  *
- * @if_type:	Block device type
+ * @uclass_id:	Block device type
  * @devnum:	Device number
  * @hwpart:	Partition number to select
  * Return: 0 if OK, -ve on error
  */
-int blk_select_hwpart_devnum(enum uclass_id if_type, int devnum, int hwpart);
+int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart);
 
 /**
- * blk_get_if_type_name() - Get the name of an interface type
+ * blk_get_uclass_name() - Get the name of an interface type
  *
- * @if_type: Interface type to check
+ * @uclass_id: Interface type to check
  * Return: name of interface, or NULL if none
  */
-const char *blk_get_if_type_name(enum uclass_id if_type);
+const char *blk_get_uclass_name(enum uclass_id uclass_id);
 
 /**
  * blk_common_cmd() - handle common commands with block devices
  *
  * @args: Number of arguments to the command (argv[0] is the command itself)
  * @argv: Command arguments
- * @if_type: Interface type
+ * @uclass_id: Interface type
  * @cur_devnump: Current device number for this interface type
  * Return: 0 if OK, CMD_RET_ERROR on error
  */
-int blk_common_cmd(int argc, char *const argv[], enum uclass_id if_type,
+int blk_common_cmd(int argc, char *const argv[], enum uclass_id uclass_id,
 		   int *cur_devnump);
 
 enum blk_flag_t {
diff --git a/include/configs/mt7981.h b/include/configs/mt7981.h
new file mode 100644
index 0000000..01ad309
--- /dev/null
+++ b/include/configs/mt7981.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Configuration for MediaTek MT7981 SoC
+ *
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#ifndef __MT7981_H
+#define __MT7981_H
+
+#include <linux/sizes.h>
+
+#define CONFIG_SYS_NONCACHED_MEMORY	SZ_1M
+
+/* Uboot definition */
+#define CONFIG_SYS_UBOOT_BASE		CONFIG_SYS_TEXT_BASE
+
+/* SPL -> Uboot */
+#define CONFIG_SYS_UBOOT_START		CONFIG_SYS_TEXT_BASE
+
+/* DRAM */
+#define CONFIG_SYS_SDRAM_BASE		0x40000000
+
+#endif
diff --git a/include/configs/mt7986.h b/include/configs/mt7986.h
new file mode 100644
index 0000000..ccdd6ab
--- /dev/null
+++ b/include/configs/mt7986.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Configuration for MediaTek MT7986 SoC
+ *
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#ifndef __MT7986_H
+#define __MT7986_H
+
+#include <linux/sizes.h>
+
+#define CONFIG_SYS_NONCACHED_MEMORY	SZ_1M
+
+/* Uboot definition */
+#define CONFIG_SYS_UBOOT_BASE		CONFIG_SYS_TEXT_BASE
+
+/* SPL -> Uboot */
+#define CONFIG_SYS_UBOOT_START		CONFIG_SYS_TEXT_BASE
+
+/* DRAM */
+#define CONFIG_SYS_SDRAM_BASE		0x40000000
+
+#endif
diff --git a/include/dt-bindings/clock/mt7981-clk.h b/include/dt-bindings/clock/mt7981-clk.h
new file mode 100644
index 0000000..e24c759
--- /dev/null
+++ b/include/dt-bindings/clock/mt7981-clk.h
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
+ *
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT7981_H
+#define _DT_BINDINGS_CLK_MT7981_H
+
+/* INFRACFG */
+
+#define CK_INFRA_CK_F26M		0
+#define CK_INFRA_UART			1
+#define CK_INFRA_ISPI0			2
+#define CK_INFRA_I2C			3
+#define CK_INFRA_ISPI1			4
+#define CK_INFRA_PWM			5
+#define CK_INFRA_66M_MCK		6
+#define CK_INFRA_CK_F32K		7
+#define CK_INFRA_PCIE_CK		8
+#define CK_INFRA_PWM_BCK		9
+#define CK_INFRA_PWM_CK1		10
+#define CK_INFRA_PWM_CK2		11
+#define CK_INFRA_133M_HCK		12
+#define CK_INFRA_66M_PHCK		13
+#define CK_INFRA_FAUD_L_CK		14
+#define CK_INFRA_FAUD_AUD_CK		15
+#define CK_INFRA_FAUD_EG2_CK		16
+#define CK_INFRA_I2CS_CK		17
+#define CK_INFRA_MUX_UART0		18
+#define CK_INFRA_MUX_UART1		19
+#define CK_INFRA_MUX_UART2		20
+#define CK_INFRA_NFI_CK			21
+#define CK_INFRA_SPINFI_CK		22
+#define CK_INFRA_MUX_SPI0		23
+#define CK_INFRA_MUX_SPI1		24
+#define CK_INFRA_MUX_SPI2		25
+#define CK_INFRA_RTC_32K		26
+#define CK_INFRA_FMSDC_CK		27
+#define CK_INFRA_FMSDC_HCK_CK		28
+#define CK_INFRA_PERI_133M		29
+#define CK_INFRA_133M_PHCK		30
+#define CK_INFRA_USB_SYS_CK		31
+#define CK_INFRA_USB_CK			32
+#define CK_INFRA_USB_XHCI_CK		33
+#define CK_INFRA_PCIE_GFMUX_TL_O_PRE	34
+#define CK_INFRA_F26M_CK0		35
+#define CK_INFRA_133M_MCK		36
+#define CLK_INFRA_NR_CLK		37
+
+/* TOPCKGEN */
+
+#define CK_TOP_CB_CKSQ_40M		0
+#define CK_TOP_CB_M_416M		1
+#define CK_TOP_CB_M_D2			2
+#define CK_TOP_CB_M_D3			3
+#define CK_TOP_M_D3_D2			4
+#define CK_TOP_CB_M_D4			5
+#define CK_TOP_CB_M_D8			6
+#define CK_TOP_M_D8_D2			7
+#define CK_TOP_CB_MM_720M		8
+#define CK_TOP_CB_MM_D2			9
+#define CK_TOP_CB_MM_D3			10
+#define CK_TOP_CB_MM_D3_D5		11
+#define CK_TOP_CB_MM_D4			12
+#define CK_TOP_CB_MM_D6			13
+#define CK_TOP_MM_D6_D2			14
+#define CK_TOP_CB_MM_D8			15
+#define CK_TOP_CB_APLL2_196M		16
+#define CK_TOP_APLL2_D2			17
+#define CK_TOP_APLL2_D4			18
+#define CK_TOP_NET1_2500M		19
+#define CK_TOP_CB_NET1_D4		20
+#define CK_TOP_CB_NET1_D5		21
+#define CK_TOP_NET1_D5_D2		22
+#define CK_TOP_NET1_D5_D4		23
+#define CK_TOP_CB_NET1_D8		24
+#define CK_TOP_NET1_D8_D2		25
+#define CK_TOP_NET1_D8_D4		26
+#define CK_TOP_CB_NET2_800M		27
+#define CK_TOP_CB_NET2_D2		28
+#define CK_TOP_CB_NET2_D4		29
+#define CK_TOP_NET2_D4_D2		30
+#define CK_TOP_NET2_D4_D4		31
+#define CK_TOP_CB_NET2_D6		32
+#define CK_TOP_CB_WEDMCU_208M		33
+#define CK_TOP_CB_SGM_325M		34
+#define CK_TOP_CKSQ_40M_D2		35
+#define CK_TOP_CB_RTC_32K		36
+#define CK_TOP_CB_RTC_32P7K		37
+#define CK_TOP_USB_TX250M		38
+#define CK_TOP_FAUD			39
+#define CK_TOP_NFI1X			40
+#define CK_TOP_USB_EQ_RX250M		41
+#define CK_TOP_USB_CDR_CK		42
+#define CK_TOP_USB_LN0_CK		43
+#define CK_TOP_SPINFI_BCK		44
+#define CK_TOP_SPI			45
+#define CK_TOP_SPIM_MST			46
+#define CK_TOP_UART_BCK			47
+#define CK_TOP_PWM_BCK			48
+#define CK_TOP_I2C_BCK			49
+#define CK_TOP_PEXTP_TL			50
+#define CK_TOP_EMMC_208M		51
+#define CK_TOP_EMMC_400M		52
+#define CK_TOP_DRAMC_REF		53
+#define CK_TOP_DRAMC_MD32		54
+#define CK_TOP_SYSAXI			55
+#define CK_TOP_SYSAPB			56
+#define CK_TOP_ARM_DB_MAIN		57
+#define CK_TOP_AP2CNN_HOST		58
+#define CK_TOP_NETSYS			59
+#define CK_TOP_NETSYS_500M		60
+#define CK_TOP_NETSYS_WED_MCU		61
+#define CK_TOP_NETSYS_2X		62
+#define CK_TOP_SGM_325M			63
+#define CK_TOP_SGM_REG			64
+#define CK_TOP_F26M			65
+#define CK_TOP_EIP97B			66
+#define CK_TOP_USB3_PHY			67
+#define CK_TOP_AUD			68
+#define CK_TOP_A1SYS			69
+#define CK_TOP_AUD_L			70
+#define CK_TOP_A_TUNER			71
+#define CK_TOP_U2U3_REF			72
+#define CK_TOP_U2U3_SYS			73
+#define CK_TOP_U2U3_XHCI		74
+#define CK_TOP_USB_FRMCNT		75
+#define CK_TOP_NFI1X_SEL		76
+#define CK_TOP_SPINFI_SEL		77
+#define CK_TOP_SPI_SEL			78
+#define CK_TOP_SPIM_MST_SEL		79
+#define CK_TOP_UART_SEL			80
+#define CK_TOP_PWM_SEL			81
+#define CK_TOP_I2C_SEL			82
+#define CK_TOP_PEXTP_TL_SEL		83
+#define CK_TOP_EMMC_208M_SEL		84
+#define CK_TOP_EMMC_400M_SEL		85
+#define CK_TOP_F26M_SEL			86
+#define CK_TOP_DRAMC_SEL		87
+#define CK_TOP_DRAMC_MD32_SEL		88
+#define CK_TOP_SYSAXI_SEL		89
+#define CK_TOP_SYSAPB_SEL		90
+#define CK_TOP_ARM_DB_MAIN_SEL		91
+#define CK_TOP_AP2CNN_HOST_SEL		92
+#define CK_TOP_NETSYS_SEL		93
+#define CK_TOP_NETSYS_500M_SEL		94
+#define CK_TOP_NETSYS_MCU_SEL		95
+#define CK_TOP_NETSYS_2X_SEL		96
+#define CK_TOP_SGM_325M_SEL		97
+#define CK_TOP_SGM_REG_SEL		98
+#define CK_TOP_EIP97B_SEL		99
+#define CK_TOP_USB3_PHY_SEL		100
+#define CK_TOP_AUD_SEL			101
+#define CK_TOP_A1SYS_SEL		102
+#define CK_TOP_AUD_L_SEL		103
+#define CK_TOP_A_TUNER_SEL		104
+#define CK_TOP_U2U3_SEL			105
+#define CK_TOP_U2U3_SYS_SEL		106
+#define CK_TOP_U2U3_XHCI_SEL		107
+#define CK_TOP_USB_FRMCNT_SEL		108
+#define CLK_TOP_NR_CLK			109
+
+/*
+ * INFRACFG_AO
+ * clock muxes need to be append to infracfg domain, and clock gates
+ * need to be keep in infracgh_ao domain
+ */
+#define INFRACFG_AO_OFFSET		10
+
+#define CK_INFRA_UART0_SEL		(0 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_UART1_SEL		(1 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_UART2_SEL		(2 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_SPI0_SEL		(3 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_SPI1_SEL		(4 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_SPI2_SEL		(5 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_PWM1_SEL		(6 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_PWM2_SEL		(7 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_PWM_BSEL		(8 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_PCIE_SEL		(9 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_GPT_STA		(10 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_PWM_HCK		(11 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_PWM_STA		(12 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_PWM1_CK		(13 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_PWM2_CK		(14 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_CQ_DMA_CK		(15 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_AUD_BUS_CK		(16 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_AUD_26M_CK		(17 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_AUD_L_CK		(18 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_AUD_AUD_CK		(19 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_AUD_EG2_CK		(20 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_DRAMC_26M_CK		(21 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_DBG_CK			(22 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_AP_DMA_CK		(23 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SEJ_CK			(24 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SEJ_13M_CK		(25 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_THERM_CK		(26 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_I2CO_CK		(27 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_UART0_CK		(28 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_UART1_CK		(29 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_UART2_CK		(30 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SPI2_CK		(31 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SPI2_HCK_CK		(32 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_NFI1_CK		(33 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SPINFI1_CK		(34 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_NFI_HCK_CK		(35 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SPI0_CK		(36 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SPI1_CK		(37 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SPI0_HCK_CK		(38 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_SPI1_HCK_CK		(39 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_FRTC_CK		(40 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_MSDC_CK		(41 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_MSDC_HCK_CK		(42 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_MSDC_133M_CK		(43 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_MSDC_66M_CK		(44 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_ADC_26M_CK		(45 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_ADC_FRC_CK		(46 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_FBIST2FPC_CK		(47 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_I2C_MCK_CK		(48 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_I2C_PCK_CK		(49 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_IUSB_133_CK		(50 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_IUSB_66M_CK		(51 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_IUSB_SYS_CK		(52 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_IUSB_CK		(53 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_IPCIE_CK		(54 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_IPCIER_CK		(55 - INFRACFG_AO_OFFSET)
+#define CK_INFRA_IPCIEB_CK		(56 - INFRACFG_AO_OFFSET)
+#define CLK_INFRA_AO_NR_CLK		(57 - INFRACFG_AO_OFFSET)
+
+/* APMIXEDSYS */
+
+#define CK_APMIXED_ARMPLL		0
+#define CK_APMIXED_NET2PLL		1
+#define CK_APMIXED_MMPLL		2
+#define CK_APMIXED_SGMPLL		3
+#define CK_APMIXED_WEDMCUPLL		4
+#define CK_APMIXED_NET1PLL		5
+#define CK_APMIXED_MPLL			6
+#define CK_APMIXED_APLL2		7
+#define CLK_APMIXED_NR_CLK		8
+
+/* SGMIISYS_0 */
+
+#define CK_SGM0_TX_EN			0
+#define CK_SGM0_RX_EN			1
+#define CK_SGM0_CK0_EN			2
+#define CK_SGM0_CDR_CK0_EN		3
+#define CLK_SGMII0_NR_CLK		4
+
+/* SGMIISYS_1 */
+
+#define CK_SGM1_TX_EN			0
+#define CK_SGM1_RX_EN			1
+#define CK_SGM1_CK1_EN			2
+#define CK_SGM1_CDR_CK1_EN		3
+#define CLK_SGMII1_NR_CLK		4
+
+/* ETHSYS */
+
+#define CK_ETH_FE_EN			0
+#define CK_ETH_GP2_EN			1
+#define CK_ETH_GP1_EN			2
+#define CK_ETH_WOCPU0_EN		3
+#define CLK_ETH_NR_CLK			4
+
+#endif /* _DT_BINDINGS_CLK_MT7981_H */
diff --git a/include/dt-bindings/clock/mt7986-clk.h b/include/dt-bindings/clock/mt7986-clk.h
new file mode 100644
index 0000000..820f863
--- /dev/null
+++ b/include/dt-bindings/clock/mt7986-clk.h
@@ -0,0 +1,249 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
+ *
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT7986_H
+#define _DT_BINDINGS_CLK_MT7986_H
+
+/* INFRACFG */
+
+#define CK_INFRA_CK_F26M		0
+#define CK_INFRA_UART			1
+#define CK_INFRA_ISPI0			2
+#define CK_INFRA_I2C			3
+#define CK_INFRA_ISPI1			4
+#define CK_INFRA_PWM			5
+#define CK_INFRA_66M_MCK		6
+#define CK_INFRA_CK_F32K		7
+#define CK_INFRA_PCIE_CK		8
+#define CK_INFRA_PWM_BCK		9
+#define CK_INFRA_PWM_CK1		10
+#define CK_INFRA_PWM_CK2		11
+#define CK_INFRA_133M_HCK		12
+#define CK_INFRA_EIP_CK			13
+#define CK_INFRA_66M_PHCK		14
+#define CK_INFRA_FAUD_L_CK		15
+#define CK_INFRA_FAUD_AUD_CK		17
+#define CK_INFRA_FAUD_EG2_CK		17
+#define CK_INFRA_I2CS_CK		18
+#define CK_INFRA_MUX_UART0		19
+#define CK_INFRA_MUX_UART1		20
+#define CK_INFRA_MUX_UART2		21
+#define CK_INFRA_NFI_CK			22
+#define CK_INFRA_SPINFI_CK		23
+#define CK_INFRA_MUX_SPI0		24
+#define CK_INFRA_MUX_SPI1		25
+#define CK_INFRA_RTC_32K		26
+#define CK_INFRA_FMSDC_CK		27
+#define CK_INFRA_FMSDC_HCK_CK		28
+#define CK_INFRA_PERI_133M		29
+#define CK_INFRA_133M_PHCK		30
+#define CK_INFRA_USB_SYS_CK		31
+#define CK_INFRA_USB_CK			32
+#define CK_INFRA_USB_XHCI_CK		33
+#define CK_INFRA_PCIE_GFMUX_TL_O_PRE	34
+#define CK_INFRA_F26M_CK0		35
+#define CK_INFRA_HD_133M		36
+#define CLK_INFRA_NR_CLK		37
+
+/* TOPCKGEN */
+
+#define CK_TOP_CB_CKSQ_40M		0
+#define CK_TOP_CB_M_416M		1
+#define CK_TOP_CB_M_D2			2
+#define CK_TOP_CB_M_D4			3
+#define CK_TOP_CB_M_D8			4
+#define CK_TOP_M_D8_D2			5
+#define CK_TOP_M_D3_D2			6
+#define CK_TOP_CB_MM_D2			7
+#define CK_TOP_CB_MM_D4			8
+#define CK_TOP_CB_MM_D8			9
+#define CK_TOP_MM_D8_D2			10
+#define CK_TOP_MM_D3_D8			11
+#define CK_TOP_CB_U2_PHYD_CK		12
+#define CK_TOP_CB_APLL2_196M		13
+#define CK_TOP_APLL2_D4			14
+#define CK_TOP_CB_NET1_D4		15
+#define CK_TOP_CB_NET1_D5		16
+#define CK_TOP_NET1_D5_D2		17
+#define CK_TOP_NET1_D5_D4		18
+#define CK_TOP_NET1_D8_D2		19
+#define CK_TOP_NET1_D8_D4		20
+#define CK_TOP_CB_NET2_800M		21
+#define CK_TOP_CB_NET2_D4		22
+#define CK_TOP_NET2_D4_D2		23
+#define CK_TOP_NET2_D3_D2		24
+#define CK_TOP_CB_WEDMCU_760M		25
+#define CK_TOP_WEDMCU_D5_D2		26
+#define CK_TOP_CB_SGM_325M		27
+#define CK_TOP_CB_CKSQ_40M_D2		28
+#define CK_TOP_CB_RTC_32K		29
+#define CK_TOP_CB_RTC_32P7K		30
+#define CK_TOP_NFI1X			31
+#define CK_TOP_USB_EQ_RX250M		32
+#define CK_TOP_USB_TX250M		33
+#define CK_TOP_USB_LN0_CK		34
+#define CK_TOP_USB_CDR_CK		35
+#define CK_TOP_SPINFI_BCK		36
+#define CK_TOP_I2C_BCK			37
+#define CK_TOP_PEXTP_TL			38
+#define CK_TOP_EMMC_250M		39
+#define CK_TOP_EMMC_416M		40
+#define CK_TOP_F_26M_ADC_CK		41
+#define CK_TOP_SYSAXI			42
+#define CK_TOP_NETSYS_WED_MCU		43
+#define CK_TOP_NETSYS_2X		44
+#define CK_TOP_SGM_325M			45
+#define CK_TOP_A1SYS			46
+#define CK_TOP_EIP_B			47
+#define CK_TOP_F26M			48
+#define CK_TOP_AUD_L			49
+#define CK_TOP_A_TUNER			50
+#define CK_TOP_U2U3_REF			51
+#define CK_TOP_U2U3_SYS			52
+#define CK_TOP_U2U3_XHCI		53
+#define CK_TOP_AP2CNN_HOST		54
+#define CK_TOP_NFI1X_SEL		55
+#define CK_TOP_SPINFI_SEL		56
+#define CK_TOP_SPI_SEL			57
+#define CK_TOP_SPIM_MST_SEL		58
+#define CK_TOP_UART_SEL			59
+#define CK_TOP_PWM_SEL			60
+#define CK_TOP_I2C_SEL			61
+#define CK_TOP_PEXTP_TL_SEL		62
+#define CK_TOP_EMMC_250M_SEL		63
+#define CK_TOP_EMMC_416M_SEL		64
+#define CK_TOP_F_26M_ADC_SEL		65
+#define CK_TOP_DRAMC_SEL		66
+#define CK_TOP_DRAMC_MD32_SEL		67
+#define CK_TOP_SYSAXI_SEL		68
+#define CK_TOP_SYSAPB_SEL		69
+#define CK_TOP_ARM_DB_MAIN_SEL		70
+#define CK_TOP_ARM_DB_JTSEL		71
+#define CK_TOP_NETSYS_SEL		72
+#define CK_TOP_NETSYS_500M_SEL		73
+#define CK_TOP_NETSYS_MCU_SEL		74
+#define CK_TOP_NETSYS_2X_SEL		75
+#define CK_TOP_SGM_325M_SEL		76
+#define CK_TOP_SGM_REG_SEL		77
+#define CK_TOP_A1SYS_SEL		78
+#define CK_TOP_CONN_MCUSYS_SEL		79
+#define CK_TOP_EIP_B_SEL		80
+#define CK_TOP_PCIE_PHY_SEL		81
+#define CK_TOP_USB3_PHY_SEL		82
+#define CK_TOP_F26M_SEL			83
+#define CK_TOP_AUD_L_SEL		84
+#define CK_TOP_A_TUNER_SEL		85
+#define CK_TOP_U2U3_SEL			86
+#define CK_TOP_U2U3_SYS_SEL		87
+#define CK_TOP_U2U3_XHCI_SEL		88
+#define CK_TOP_DA_U2_REFSEL		89
+#define CK_TOP_DA_U2_CK_1P_SEL		90
+#define CK_TOP_AP2CNN_HOST_SEL		91
+#define CLK_TOP_NR_CLK			92
+
+/*
+ * INFRACFG_AO
+ * clock muxes need to be append to infracfg domain, and clock gates
+ * need to be keep in infracgh_ao domain
+ */
+
+#define CK_INFRA_UART0_SEL		(0 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_UART1_SEL		(1 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_UART2_SEL		(2 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_SPI0_SEL		(3 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_SPI1_SEL		(4 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_PWM1_SEL		(5 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_PWM2_SEL		(6 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_PWM_BSEL		(7 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_PCIE_SEL		(8 + CLK_INFRA_NR_CLK)
+#define CK_INFRA_GPT_STA		0
+#define CK_INFRA_PWM_HCK		1
+#define CK_INFRA_PWM_STA		2
+#define CK_INFRA_PWM1_CK		3
+#define CK_INFRA_PWM2_CK		4
+#define CK_INFRA_CQ_DMA_CK		5
+#define CK_INFRA_EIP97_CK		6
+#define CK_INFRA_AUD_BUS_CK		7
+#define CK_INFRA_AUD_26M_CK		8
+#define CK_INFRA_AUD_L_CK		9
+#define CK_INFRA_AUD_AUD_CK		10
+#define CK_INFRA_AUD_EG2_CK		11
+#define CK_INFRA_DRAMC_26M_CK		12
+#define CK_INFRA_DBG_CK			13
+#define CK_INFRA_AP_DMA_CK		14
+#define CK_INFRA_SEJ_CK			15
+#define CK_INFRA_SEJ_13M_CK		16
+#define CK_INFRA_THERM_CK		17
+#define CK_INFRA_I2CO_CK		18
+#define CK_INFRA_TRNG_CK		19
+#define CK_INFRA_UART0_CK		20
+#define CK_INFRA_UART1_CK		21
+#define CK_INFRA_UART2_CK		22
+#define CK_INFRA_NFI1_CK		23
+#define CK_INFRA_SPINFI1_CK		24
+#define CK_INFRA_NFI_HCK_CK		25
+#define CK_INFRA_SPI0_CK		26
+#define CK_INFRA_SPI1_CK		27
+#define CK_INFRA_SPI0_HCK_CK		28
+#define CK_INFRA_SPI1_HCK_CK		29
+#define CK_INFRA_FRTC_CK		30
+#define CK_INFRA_MSDC_CK		31
+#define CK_INFRA_MSDC_HCK_CK		32
+#define CK_INFRA_MSDC_133M_CK		33
+#define CK_INFRA_MSDC_66M_CK		34
+#define CK_INFRA_ADC_26M_CK		35
+#define CK_INFRA_ADC_FRC_CK		36
+#define CK_INFRA_FBIST2FPC_CK		37
+#define CK_INFRA_IUSB_133_CK		38
+#define CK_INFRA_IUSB_66M_CK		39
+#define CK_INFRA_IUSB_SYS_CK		40
+#define CK_INFRA_IUSB_CK		41
+#define CK_INFRA_IPCIE_CK		42
+#define CK_INFRA_IPCIER_CK		43
+#define CK_INFRA_IPCIEB_CK		44
+#define CLK_INFRA_AO_NR_CLK		45
+
+/* APMIXEDSYS */
+
+#define CK_APMIXED_ARMPLL		0
+#define CK_APMIXED_NET2PLL		1
+#define CK_APMIXED_MMPLL		2
+#define CK_APMIXED_SGMPLL		3
+#define CK_APMIXED_WEDMCUPLL		4
+#define CK_APMIXED_NET1PLL		5
+#define CK_APMIXED_MPLL			6
+#define CK_APMIXED_APLL2		7
+#define CLK_APMIXED_NR_CLK		8
+
+/* SGMIISYS_0 */
+
+#define CK_SGM0_TX_EN			0
+#define CK_SGM0_RX_EN			1
+#define CK_SGM0_CK0_EN			2
+#define CK_SGM0_CDR_CK0_EN		3
+#define CLK_SGMII0_NR_CLK		4
+
+/* SGMIISYS_1 */
+
+#define CK_SGM1_TX_EN			0
+#define CK_SGM1_RX_EN			1
+#define CK_SGM1_CK1_EN			2
+#define CK_SGM1_CDR_CK1_EN		3
+#define CLK_SGMII1_NR_CLK		4
+
+/* ETHSYS */
+
+#define CK_ETH_FE_EN			0
+#define CK_ETH_GP2_EN			1
+#define CK_ETH_GP1_EN			2
+#define CK_ETH_WOCPU1_EN		3
+#define CK_ETH_WOCPU0_EN		4
+#define CLK_ETH_NR_CLK			5
+
+#endif
+
+/* _DT_BINDINGS_CLK_MT7986_H */
diff --git a/include/dt-bindings/pinctrl/mt65xx.h b/include/dt-bindings/pinctrl/mt65xx.h
new file mode 100644
index 0000000..fbea8d3
--- /dev/null
+++ b/include/dt-bindings/pinctrl/mt65xx.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Hongzhou.Yang <hongzhou.yang@mediatek.com>
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_MT65XX_H
+#define _DT_BINDINGS_PINCTRL_MT65XX_H
+
+#define MTK_PIN_NO(x)		((x) << 8)
+#define MTK_GET_PIN_NO(x)	((x) >> 8)
+#define MTK_GET_PIN_FUNC(x)	((x) & 0xf)
+
+#define MTK_PUPD_SET_R1R0_00	100
+#define MTK_PUPD_SET_R1R0_01	101
+#define MTK_PUPD_SET_R1R0_10	102
+#define MTK_PUPD_SET_R1R0_11	103
+
+#define MTK_PULL_SET_RSEL_000	200
+#define MTK_PULL_SET_RSEL_001	201
+#define MTK_PULL_SET_RSEL_010	202
+#define MTK_PULL_SET_RSEL_011	203
+#define MTK_PULL_SET_RSEL_100	204
+#define MTK_PULL_SET_RSEL_101	205
+#define MTK_PULL_SET_RSEL_110	206
+#define MTK_PULL_SET_RSEL_111	207
+
+#define MTK_DRIVE_2mA		2
+#define MTK_DRIVE_4mA		4
+#define MTK_DRIVE_6mA		6
+#define MTK_DRIVE_8mA		8
+#define MTK_DRIVE_10mA		10
+#define MTK_DRIVE_12mA		12
+#define MTK_DRIVE_14mA		14
+#define MTK_DRIVE_16mA		16
+#define MTK_DRIVE_20mA		20
+#define MTK_DRIVE_24mA		24
+#define MTK_DRIVE_28mA		28
+#define MTK_DRIVE_32mA		32
+
+#endif /* _DT_BINDINGS_PINCTRL_MT65XX_H */
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 7554f3b..ad01395 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -161,7 +161,7 @@
 
 /* EFI system partition */
 extern struct efi_system_partition {
-	enum uclass_id if_type;
+	enum uclass_id uclass_id;
 	int devnum;
 	u8 part;
 } efi_system_partition;
@@ -562,7 +562,7 @@
 				   struct efi_loaded_image *loaded_image_info);
 /* Create handles and protocols for the partitions of a block device */
 int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
-			       const char *if_typename, int diskid,
+			       const char *uclass_idname, int diskid,
 			       const char *pdevname);
 /* Called by bootefi to make GOP (graphical) interface available */
 efi_status_t efi_gop_register(void);
diff --git a/include/init.h b/include/init.h
index 02bb4ce..50a8302 100644
--- a/include/init.h
+++ b/include/init.h
@@ -291,7 +291,7 @@
  *
  * @param total_size	Size of U-Boot (unused?)
  */
-ulong board_get_usable_ram_top(ulong total_size);
+phys_size_t board_get_usable_ram_top(phys_size_t total_size);
 
 int board_early_init_f(void);
 
diff --git a/include/os.h b/include/os.h
index 1481787..5b353ae 100644
--- a/include/os.h
+++ b/include/os.h
@@ -296,6 +296,14 @@
 void os_puts(const char *str);
 
 /**
+ * os_flush() - flush controlling OS terminal
+ *
+ * This bypasses the U-Boot console support and flushes directly the OS
+ * stdout file descriptor.
+ */
+void os_flush(void);
+
+/**
  * os_write_ram_buf() - write the sandbox RAM buffer to a existing file
  *
  * @fname:	filename to write memory to (simple binary format)
diff --git a/include/scsi.h b/include/scsi.h
index b47c746..94e1d8c 100644
--- a/include/scsi.h
+++ b/include/scsi.h
@@ -15,27 +15,47 @@
 
 struct udevice;
 
+/**
+ * struct scsi_cmd - information about a SCSI command to be processed
+ *
+ * @cmd: command
+ * @sense_buf: for request sense
+ * @status: SCSI Status
+ * @target: Target ID
+ * @lun: Target LUN
+ * @cmdlen: command len
+ * @datalen: Total data length
+ * @pdata: pointer to data
+ * @msgout: Messge out buffer (NOT USED)
+ * @msgin: Message in buffer
+ * @sensecmdlen: Sense command len
+ * @sensedatalen: Sense data len
+ * @sensecmd: Sense command
+ * @contr_stat: Controller Status
+ * @trans_bytes: tranfered bytes
+ * @priv: Private value
+ * @dma_dir: Direction of data structure
+ */
 struct scsi_cmd {
-	unsigned char		cmd[16];					/* command				   */
-	/* for request sense */
-	unsigned char		sense_buf[64]
+	unsigned char cmd[16];
+	unsigned char sense_buf[64]
 		__attribute__((aligned(ARCH_DMA_MINALIGN)));
-	unsigned char		status;						/* SCSI Status			 */
-	unsigned char		target;						/* Target ID				 */
-	unsigned char		lun;							/* Target LUN        */
-	unsigned char		cmdlen;						/* command len				*/
-	unsigned long		datalen;					/* Total data length	*/
-	unsigned char	*	pdata;						/* pointer to data		*/
-	unsigned char		msgout[12];				/* Messge out buffer (NOT USED) */
-	unsigned char		msgin[12];				/* Message in buffer	*/
-	unsigned char		sensecmdlen;			/* Sense command len	*/
-	unsigned long		sensedatalen;			/* Sense data len			*/
-	unsigned char		sensecmd[6];			/* Sense command			*/
-	unsigned long		contr_stat;				/* Controller Status	*/
-	unsigned long		trans_bytes;			/* tranfered bytes		*/
+	unsigned char status;
+	unsigned char target;
+	unsigned char lun;
+	unsigned char cmdlen;
+	unsigned long datalen;
+	unsigned char *pdata;
+	unsigned char msgout[12];
+	unsigned char msgin[12];
+	unsigned char sensecmdlen;
+	unsigned long sensedatalen;
+	unsigned char sensecmd[6];
+	unsigned long contr_stat;
+	unsigned long trans_bytes;
 
-	unsigned int		priv;
-	enum dma_data_direction	dma_dir;
+	unsigned int priv;
+	enum dma_data_direction dma_dir;
 };
 
 /*-----------------------------------------------------------
@@ -168,6 +188,74 @@
 #define SCSI_WRITE_SAME	0x41		/* Write Same (O) */
 
 /**
+ * enum scsi_cmd_phase - current phase of the SCSI protocol
+ *
+ * @SCSIPH_START: Start phase
+ * @SCSIPH_DATA: Data phase
+ * @SCSIPH_STATUS: Status phase
+ */
+enum scsi_cmd_phase {
+	SCSIPH_START,
+	SCSIPH_DATA,
+	SCSIPH_STATUS,
+};
+
+/**
+ * struct scsi_inquiry_resp - holds a SCSI inquiry command
+ *
+ * @type; command type
+ * @flags; command flags
+ * @version; command version
+ * @data_format; data format
+ * @additional_len; additional data length
+ * @spare[3]; spare bytes
+ * @vendor[8]; vendor information
+ * @product[16]; production information
+ * @revision[4]; revision information
+ */
+struct scsi_inquiry_resp {
+	u8 type;
+	u8 flags;
+	u8 version;
+	u8 data_format;
+	u8 additional_len;
+	u8 spare[3];
+	char vendor[8];
+	char product[16];
+	char revision[4];
+};
+
+/**
+ * struct scsi_read_capacity_resp - holds the response to a read-capacity cmd
+ *
+ * @last_block_addr: Logical block address of last block
+ * @block_len: Length of each block in bytes
+ */
+struct scsi_read_capacity_resp {
+	u32 last_block_addr;
+	u32 block_len;
+};
+
+/**
+ * struct scsi_read10_req - holds a SCSI READ10 request
+ *
+ * @cmd; command type
+ * @lun_flags; LUN flags
+ * @lba; Logical block address to start reading from
+ * @spare; spare bytes
+ * @xfer_len: number of blocks to read
+ * @spare2: more spare bytes
+ */
+struct __packed scsi_read10_req {
+	u8 cmd;
+	u8 lun_flags;
+	u32 lba;
+	u8 spare;
+	u16 xfer_len;
+	u8 spare2[3];
+};
+
+/**
  * struct scsi_plat - stores information about SCSI controller
  *
  * @base: Controller base address
diff --git a/include/scsi_emul.h b/include/scsi_emul.h
new file mode 100644
index 0000000..13c3f86
--- /dev/null
+++ b/include/scsi_emul.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Emulation of enough SCSI commands to find and read from a unit
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * implementations of SCSI functions required so that CONFIG_SCSI can be enabled
+ * for sandbox
+ */
+
+#ifndef __scsi_emul_h
+#define __scsi_emul_h
+
+/**
+ * struct scsi_emul_info - information for emulating a SCSI device
+ *
+ * @vendor: Vendor name
+ * @product: Product name
+ * @block_size: Block size of device in bytes (normally 512)
+ * @file_size: Size of the backing file for this emulator, in bytes
+ * @seek_block: Seek position for file (block number)
+ *
+ * @phase: Current SCSI phase
+ * @buff_used: Number of bytes ready to transfer back to host
+ * @read_len: Number of bytes of data left in the current read command
+ * @alloc_len: Allocation length from the last incoming command
+ * @transfer_len: Transfer length from CBW header
+ * @buff: Data buffer for outgoing data
+ */
+struct scsi_emul_info {
+	/* provided by the caller: */
+	void *buff;
+	const char *vendor;
+	const char *product;
+	int block_size;
+	loff_t file_size;
+	int seek_block;
+
+	/* state maintained by the emulator: */
+	enum scsi_cmd_phase phase;
+	int buff_used;
+	int read_len;
+	uint seek_pos;
+	int alloc_len;
+	uint transfer_len;
+};
+
+/* Indicates that a read is being started */
+#define SCSI_EMUL_DO_READ	1
+
+/**
+ * sb_scsi_emul_command() - Process a SCSI command
+ *
+ * This sets up the response in info->buff and updates various other values
+ * in info.
+ *
+ * If SCSI_EMUL_DO_READ is returned then the caller should set up so that the
+ * backing file can be read, or return an error status if there is no file.
+ *
+ * @info: Emulation information
+ * @req: Request to process
+ * @len: Length of request in bytes
+ * @return SCSI_EMUL_DO_READ if a read has started, 0 if some other operation
+ *	has started, -ve if there was an error
+ */
+int sb_scsi_emul_command(struct scsi_emul_info *info,
+			 const struct scsi_cmd *req, int len);
+
+#endif
diff --git a/include/serial.h b/include/serial.h
index 8c2e7ad..fe01bcf 100644
--- a/include/serial.h
+++ b/include/serial.h
@@ -362,6 +362,11 @@
 void serial_putc(const char ch);
 void serial_putc_raw(const char ch);
 void serial_puts(const char *str);
+#if defined(CONFIG_CONSOLE_FLUSH_SUPPORT) && CONFIG_IS_ENABLED(DM_SERIAL)
+void serial_flush(void);
+#else
+static inline void serial_flush(void) {}
+#endif
 int serial_getc(void);
 int serial_tstc(void);
 
diff --git a/include/stdio.h b/include/stdio.h
index 1939a48..3241e2d 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -15,6 +15,11 @@
 		defined(CONFIG_SPL_SERIAL))
 void putc(const char c);
 void puts(const char *s);
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void flush(void);
+#else
+static inline void flush(void) {}
+#endif
 int __printf(1, 2) printf(const char *fmt, ...);
 int vprintf(const char *fmt, va_list args);
 #else
@@ -26,6 +31,10 @@
 {
 }
 
+static inline void flush(void)
+{
+}
+
 static inline int __printf(1, 2) printf(const char *fmt, ...)
 {
 	return 0;
@@ -48,11 +57,17 @@
 /* stderr */
 #define eputc(c)		fputc(stderr, c)
 #define eputs(s)		fputs(stderr, s)
+#define eflush()		fflush(stderr)
 #define eprintf(fmt, args...)	fprintf(stderr, fmt, ##args)
 
 int __printf(2, 3) fprintf(int file, const char *fmt, ...);
 void fputs(int file, const char *s);
 void fputc(int file, const char c);
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void fflush(int file);
+#else
+static inline void fflush(int file) {}
+#endif
 int ftstc(int file);
 int fgetc(int file);
 
diff --git a/include/stdio_dev.h b/include/stdio_dev.h
index 270fa27..3105928 100644
--- a/include/stdio_dev.h
+++ b/include/stdio_dev.h
@@ -37,6 +37,13 @@
 	void (*putc)(struct stdio_dev *dev, const char c);
 	/* To put a string (accelerator) */
 	void (*puts)(struct stdio_dev *dev, const char *s);
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+	/* To flush output queue */
+	void (*flush)(struct stdio_dev *dev);
+#define STDIO_DEV_ASSIGN_FLUSH(dev, flush_func) ((dev)->flush = (flush_func))
+#else
+#define STDIO_DEV_ASSIGN_FLUSH(dev, flush_func)
+#endif
 
 /* INPUT functions */
 
diff --git a/include/usb/designware_udc.h b/include/usb/designware_udc.h
deleted file mode 100644
index f716f07..0000000
--- a/include/usb/designware_udc.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * (C) Copyright 2009
- * Vipin Kumar, STMicroelectronics, vipin.kumar@st.com.
- */
-
-#ifndef __DW_UDC_H
-#define __DW_UDC_H
-
-/*
- * Defines for  USBD
- *
- * The udc_ahb controller has three AHB slaves:
- *
- * 1.  THe UDC registers
- * 2.  The plug detect
- * 3.  The RX/TX FIFO
- */
-
-#define MAX_ENDPOINTS		16
-
-struct udc_endp_regs {
-	u32 endp_cntl;
-	u32 endp_status;
-	u32 endp_bsorfn;
-	u32 endp_maxpacksize;
-	u32 reserved_1;
-	u32 endp_desc_point;
-	u32 reserved_2;
-	u32 write_done;
-};
-
-/* Endpoint Control Register definitions */
-
-#define  ENDP_CNTL_STALL		0x00000001
-#define  ENDP_CNTL_FLUSH		0x00000002
-#define  ENDP_CNTL_SNOOP		0x00000004
-#define  ENDP_CNTL_POLL			0x00000008
-#define  ENDP_CNTL_CONTROL		0x00000000
-#define  ENDP_CNTL_ISO			0x00000010
-#define  ENDP_CNTL_BULK			0x00000020
-#define  ENDP_CNTL_INT			0x00000030
-#define  ENDP_CNTL_NAK			0x00000040
-#define  ENDP_CNTL_SNAK			0x00000080
-#define  ENDP_CNTL_CNAK			0x00000100
-#define  ENDP_CNTL_RRDY			0x00000200
-
-/* Endpoint Satus Register definitions */
-
-#define  ENDP_STATUS_PIDMSK		0x0000000f
-#define  ENDP_STATUS_OUTMSK		0x00000030
-#define  ENDP_STATUS_OUT_NONE		0x00000000
-#define  ENDP_STATUS_OUT_DATA		0x00000010
-#define  ENDP_STATUS_OUT_SETUP		0x00000020
-#define  ENDP_STATUS_IN			0x00000040
-#define  ENDP_STATUS_BUFFNAV		0x00000080
-#define  ENDP_STATUS_FATERR		0x00000100
-#define  ENDP_STATUS_HOSTBUSERR		0x00000200
-#define  ENDP_STATUS_TDC		0x00000400
-#define  ENDP_STATUS_RXPKTMSK		0x003ff800
-
-struct udc_regs {
-	struct udc_endp_regs in_regs[MAX_ENDPOINTS];
-	struct udc_endp_regs out_regs[MAX_ENDPOINTS];
-	u32 dev_conf;
-	u32 dev_cntl;
-	u32 dev_stat;
-	u32 dev_int;
-	u32 dev_int_mask;
-	u32 endp_int;
-	u32 endp_int_mask;
-	u32 reserved_3[0x39];
-	u32 reserved_4;		/* offset 0x500 */
-	u32 udc_endp_reg[MAX_ENDPOINTS];
-};
-
-/* Device Configuration Register definitions */
-
-#define  DEV_CONF_HS_SPEED		0x00000000
-#define  DEV_CONF_LS_SPEED		0x00000002
-#define  DEV_CONF_FS_SPEED		0x00000003
-#define  DEV_CONF_REMWAKEUP		0x00000004
-#define  DEV_CONF_SELFPOW		0x00000008
-#define  DEV_CONF_SYNCFRAME		0x00000010
-#define  DEV_CONF_PHYINT_8		0x00000020
-#define  DEV_CONF_PHYINT_16		0x00000000
-#define  DEV_CONF_UTMI_BIDIR		0x00000040
-#define  DEV_CONF_STATUS_STALL		0x00000080
-
-/* Device Control Register definitions */
-
-#define  DEV_CNTL_RESUME		0x00000001
-#define  DEV_CNTL_TFFLUSH		0x00000002
-#define  DEV_CNTL_RXDMAEN		0x00000004
-#define  DEV_CNTL_TXDMAEN		0x00000008
-#define  DEV_CNTL_DESCRUPD		0x00000010
-#define  DEV_CNTL_BIGEND		0x00000020
-#define  DEV_CNTL_BUFFILL		0x00000040
-#define  DEV_CNTL_TSHLDEN		0x00000080
-#define  DEV_CNTL_BURSTEN		0x00000100
-#define  DEV_CNTL_DMAMODE		0x00000200
-#define  DEV_CNTL_SOFTDISCONNECT	0x00000400
-#define  DEV_CNTL_SCALEDOWN		0x00000800
-#define  DEV_CNTL_BURSTLENU		0x00010000
-#define  DEV_CNTL_BURSTLENMSK		0x00ff0000
-#define  DEV_CNTL_TSHLDLENU		0x01000000
-#define  DEV_CNTL_TSHLDLENMSK		0xff000000
-
-/* Device Status Register definitions */
-
-#define  DEV_STAT_CFG			0x0000000f
-#define  DEV_STAT_INTF			0x000000f0
-#define  DEV_STAT_ALT			0x00000f00
-#define  DEV_STAT_SUSP			0x00001000
-#define  DEV_STAT_ENUM			0x00006000
-#define  DEV_STAT_ENUM_SPEED_HS		0x00000000
-#define  DEV_STAT_ENUM_SPEED_FS		0x00002000
-#define  DEV_STAT_ENUM_SPEED_LS		0x00004000
-#define  DEV_STAT_RXFIFO_EMPTY		0x00008000
-#define  DEV_STAT_PHY_ERR		0x00010000
-#define  DEV_STAT_TS			0xf0000000
-
-/* Device Interrupt Register definitions */
-
-#define  DEV_INT_MSK			0x0000007f
-#define  DEV_INT_SETCFG			0x00000001
-#define  DEV_INT_SETINTF		0x00000002
-#define  DEV_INT_INACTIVE		0x00000004
-#define  DEV_INT_USBRESET		0x00000008
-#define  DEV_INT_SUSPUSB		0x00000010
-#define  DEV_INT_SOF			0x00000020
-#define  DEV_INT_ENUM			0x00000040
-
-/* Endpoint Interrupt Register definitions */
-
-#define  ENDP0_INT_CTRLIN		0x00000001
-#define  ENDP1_INT_BULKIN		0x00000002
-#define  ENDP_INT_NONISOIN_MSK		0x0000AAAA
-#define  ENDP2_INT_BULKIN		0x00000004
-#define  ENDP0_INT_CTRLOUT		0x00010000
-#define  ENDP1_INT_BULKOUT		0x00020000
-#define  ENDP2_INT_BULKOUT		0x00040000
-#define  ENDP_INT_NONISOOUT_MSK		0x55540000
-
-/* Endpoint Register definitions */
-#define  ENDP_EPDIR_OUT			0x00000000
-#define  ENDP_EPDIR_IN			0x00000010
-#define  ENDP_EPTYPE_CNTL		0x0
-#define  ENDP_EPTYPE_ISO		0x1
-#define  ENDP_EPTYPE_BULK		0x2
-#define  ENDP_EPTYPE_INT		0x3
-
-/*
- * Defines for Plug Detect
- */
-
-struct plug_regs {
-	u32 plug_state;
-	u32 plug_pending;
-};
-
-/* Plug State Register definitions */
-#define  PLUG_STATUS_EN			0x1
-#define  PLUG_STATUS_ATTACHED		0x2
-#define  PLUG_STATUS_PHY_RESET		0x4
-#define  PLUG_STATUS_PHY_MODE		0x8
-
-/*
- * Defines for UDC FIFO (Slave Mode)
- */
-struct udcfifo_regs {
-	u32 *fifo_p;
-};
-
-/*
- * UDC endpoint definitions
- */
-#define  UDC_EP0			0
-#define  UDC_EP1			1
-#define  UDC_EP2			2
-#define  UDC_EP3			3
-
-#endif /* __DW_UDC_H */
diff --git a/lib/display_options.c b/lib/display_options.c
index 7feb446..80def52 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -127,6 +127,12 @@
 		if (m >= 10) {
 			m -= 10;
 			n += 1;
+
+			if (n == 1024 && i > 0) {
+				n = 1;
+				m = 0;
+				c = names[i - 1];
+			}
 		}
 	}
 
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index e39968a..39ea1a6 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -498,13 +498,13 @@
 		  diskobj->media.last_block);
 
 	/* Store first EFI system partition */
-	if (part && !efi_system_partition.if_type) {
+	if (part && !efi_system_partition.uclass_id) {
 		if (part_info->bootable & PART_EFI_SYSTEM_PARTITION) {
-			efi_system_partition.if_type = desc->if_type;
+			efi_system_partition.uclass_id = desc->uclass_id;
 			efi_system_partition.devnum = desc->devnum;
 			efi_system_partition.part = part;
 			EFI_PRINT("EFI system partition: %s %x:%x\n",
-				  blk_get_if_type_name(desc->if_type),
+				  blk_get_uclass_name(desc->uclass_id),
 				  desc->devnum, part);
 		}
 	}
@@ -640,7 +640,7 @@
 	 * has already created an efi_disk at this moment.
 	 */
 	desc = dev_get_uclass_plat(dev);
-	if (desc->if_type != UCLASS_EFI_LOADER) {
+	if (desc->uclass_id != UCLASS_EFI_LOADER) {
 		ret = efi_disk_create_raw(dev);
 		if (ret)
 			return -1;
@@ -675,7 +675,7 @@
 		return -1;
 
 	desc = dev_get_uclass_plat(dev);
-	if (desc->if_type != UCLASS_EFI_LOADER) {
+	if (desc->uclass_id != UCLASS_EFI_LOADER) {
 		diskobj = container_of(handle, struct efi_disk_obj, header);
 		efi_free_pool(diskobj->dp);
 	}
@@ -794,7 +794,7 @@
 	} else {
 		return EFI_INVALID_PARAMETER;
 	}
-	if_typename = blk_get_if_type_name(desc->if_type);
+	if_typename = blk_get_uclass_name(desc->uclass_id);
 	diskid = desc->devnum;
 
 	if (is_partition) {
diff --git a/lib/efi_loader/efi_var_file.c b/lib/efi_loader/efi_var_file.c
index 994e663..3d58caa 100644
--- a/lib/efi_loader/efi_var_file.c
+++ b/lib/efi_loader/efi_var_file.c
@@ -38,13 +38,13 @@
 	char part_str[PART_STR_LEN];
 	int r;
 
-	if (efi_system_partition.if_type == UCLASS_INVALID) {
+	if (efi_system_partition.uclass_id == UCLASS_INVALID) {
 		log_err("No EFI system partition\n");
 		return EFI_DEVICE_ERROR;
 	}
 	snprintf(part_str, PART_STR_LEN, "%x:%x",
 		 efi_system_partition.devnum, efi_system_partition.part);
-	r = fs_set_blk_dev(blk_get_if_type_name(efi_system_partition.if_type),
+	r = fs_set_blk_dev(blk_get_uclass_name(efi_system_partition.uclass_id),
 			   part_str, FS_TYPE_ANY);
 	if (r) {
 		log_err("Cannot read EFI system partition\n");
diff --git a/lib/efi_selftest/efi_selftest_loadimage.c b/lib/efi_selftest/efi_selftest_loadimage.c
index d4c76f5..24548f1 100644
--- a/lib/efi_selftest/efi_selftest_loadimage.c
+++ b/lib/efi_selftest/efi_selftest_loadimage.c
@@ -142,38 +142,39 @@
 	&priv_file_system_info.info;
 
 /* Forward definitions of file and file system functions */
-static efi_status_t EFIAPI open_volume
+static efi_status_t EFIAPI efi_st_open_volume
 	(struct efi_simple_file_system_protocol *this,
 	 struct efi_file_handle **root);
 
-static efi_status_t EFIAPI open
+static efi_status_t EFIAPI efi_st_open
 	(struct efi_file_handle *this,
 	 struct efi_file_handle **new_handle,
 	 u16 *file_name, u64 open_mode, u64 attributes);
 
-static efi_status_t EFIAPI close(struct efi_file_handle *this);
+static efi_status_t EFIAPI efi_st_close(struct efi_file_handle *this);
 
-static efi_status_t EFIAPI delete(struct efi_file_handle *this);
+static efi_status_t EFIAPI efi_st_delete(struct efi_file_handle *this);
 
-static efi_status_t EFIAPI read
+static efi_status_t EFIAPI efi_st_read
 	(struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer);
 
-static efi_status_t EFIAPI write
+static efi_status_t EFIAPI efi_st_write
 	(struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer);
 
-static efi_status_t EFIAPI getpos(struct efi_file_handle *this, u64 *pos);
+static efi_status_t EFIAPI efi_st_getpos(struct efi_file_handle *this,
+					 u64 *pos);
 
-static efi_status_t EFIAPI setpos(struct efi_file_handle *this, u64 pos);
+static efi_status_t EFIAPI efi_st_setpos(struct efi_file_handle *this, u64 pos);
 
-static efi_status_t EFIAPI getinfo
+static efi_status_t EFIAPI efi_st_getinfo
 	(struct efi_file_handle *this, const efi_guid_t *info_type,
 	 efi_uintn_t *buffer_size, void *buffer);
 
-static efi_status_t EFIAPI setinfo
+static efi_status_t EFIAPI efi_st_setinfo
 	(struct efi_file_handle *this, const efi_guid_t *info_type,
 	 efi_uintn_t buffer_size, void *buffer);
 
-static efi_status_t EFIAPI flush(struct efi_file_handle *this);
+static efi_status_t EFIAPI efi_st_flush(struct efi_file_handle *this);
 
 /* Internal information about status of file system */
 static struct {
@@ -190,40 +191,40 @@
 /* EFI_FILE_PROTOCOL for file */
 static struct efi_file_handle file = {
 	.rev = 0x00010000,
-	.open = open,
-	.close = close,
-	.delete = delete,
-	.read = read,
-	.write = write,
-	.getpos = getpos,
-	.setpos = setpos,
-	.getinfo = getinfo,
-	.setinfo = setinfo,
-	.flush = flush,
+	.open = efi_st_open,
+	.close = efi_st_close,
+	.delete = efi_st_delete,
+	.read = efi_st_read,
+	.write = efi_st_write,
+	.getpos = efi_st_getpos,
+	.setpos = efi_st_setpos,
+	.getinfo = efi_st_getinfo,
+	.setinfo = efi_st_setinfo,
+	.flush = efi_st_flush,
 };
 
 /* EFI_FILE_PROTOCOL for root directory */
 static struct efi_file_handle volume = {
 	.rev = 0x00010000,
-	.open = open,
-	.close = close,
-	.delete = delete,
-	.read = read,
-	.write = write,
-	.getpos = getpos,
-	.setpos = setpos,
-	.getinfo = getinfo,
-	.setinfo = setinfo,
-	.flush = flush,
+	.open = efi_st_open,
+	.close = efi_st_close,
+	.delete = efi_st_delete,
+	.read = efi_st_read,
+	.write = efi_st_write,
+	.getpos = efi_st_getpos,
+	.setpos = efi_st_setpos,
+	.getinfo = efi_st_getinfo,
+	.setinfo = efi_st_setinfo,
+	.flush = efi_st_flush,
 };
 
 /* EFI_SIMPLE_FILE_SYSTEM_PROTOCOL of the block device */
 struct efi_simple_file_system_protocol file_system = {
 	.rev = 0x00010000,
-	.open_volume = open_volume,
+	.open_volume = efi_st_open_volume,
 };
 
-static efi_status_t EFIAPI open_volume
+static efi_status_t EFIAPI efi_st_open_volume
 	(struct efi_simple_file_system_protocol *this,
 	 struct efi_file_handle **root)
 {
@@ -236,7 +237,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t EFIAPI open
+static efi_status_t EFIAPI efi_st_open
 	(struct efi_file_handle *this,
 	 struct efi_file_handle **new_handle,
 	 u16 *file_name, u64 open_mode, u64 attributes)
@@ -251,7 +252,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t EFIAPI close(struct efi_file_handle *this)
+static efi_status_t EFIAPI efi_st_close(struct efi_file_handle *this)
 {
 	if (this == &file)
 		priv.file_open_count--;
@@ -263,7 +264,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t EFIAPI delete(struct efi_file_handle *this)
+static efi_status_t EFIAPI efi_st_delete(struct efi_file_handle *this)
 {
 	if (this != &file)
 		return EFI_INVALID_PARAMETER;
@@ -271,7 +272,7 @@
 	return EFI_UNSUPPORTED;
 }
 
-static efi_status_t EFIAPI read
+static efi_status_t EFIAPI efi_st_read
 	(struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer)
 {
 	if (this != &file)
@@ -288,7 +289,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t EFIAPI write
+static efi_status_t EFIAPI efi_st_write
 	(struct efi_file_handle *this, efi_uintn_t *buffer_size, void *buffer)
 {
 	if (this != &file)
@@ -297,7 +298,7 @@
 	return EFI_UNSUPPORTED;
 }
 
-static efi_status_t EFIAPI getpos(struct efi_file_handle *this, u64 *pos)
+static efi_status_t EFIAPI efi_st_getpos(struct efi_file_handle *this, u64 *pos)
 {
 	if (this != &file)
 		return EFI_INVALID_PARAMETER;
@@ -307,7 +308,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t EFIAPI setpos(struct efi_file_handle *this, u64 pos)
+static efi_status_t EFIAPI efi_st_setpos(struct efi_file_handle *this, u64 pos)
 {
 	if (this != &file)
 		return EFI_INVALID_PARAMETER;
@@ -317,7 +318,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t EFIAPI getinfo
+static efi_status_t EFIAPI efi_st_getinfo
 	(struct efi_file_handle *this, const efi_guid_t *info_type,
 	 efi_uintn_t *buffer_size, void *buffer)
 {
@@ -348,7 +349,7 @@
 	return EFI_SUCCESS;
 }
 
-static efi_status_t EFIAPI setinfo
+static efi_status_t EFIAPI efi_st_setinfo
 	(struct efi_file_handle *this, const efi_guid_t *info_type,
 	 efi_uintn_t buffer_size, void *buffer)
 {
@@ -358,7 +359,7 @@
 	return EFI_UNSUPPORTED;
 }
 
-static efi_status_t EFIAPI flush(struct efi_file_handle *this)
+static efi_status_t EFIAPI efi_st_flush(struct efi_file_handle *this)
 {
 	if (this != &file)
 		return EFI_INVALID_PARAMETER;
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 7543df8..5178daa 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -91,6 +91,7 @@
 obj-$(CONFIG_DM_RNG) += rng.o
 obj-$(CONFIG_DM_RTC) += rtc.o
 obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o
+obj-$(CONFIG_SCSI) += scsi.o
 obj-$(CONFIG_DM_SERIAL) += serial.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_SIMPLE_BUS) += simple-bus.o
diff --git a/test/dm/scsi.c b/test/dm/scsi.c
new file mode 100644
index 0000000..380cfc8
--- /dev/null
+++ b/test/dm/scsi.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2015 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <part.h>
+#include <scsi.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+/* Test that sandbox SCSI works correctly */
+static int dm_test_scsi_base(struct unit_test_state *uts)
+{
+	const struct disk_partition *info;
+	const struct disk_part *part;
+	struct udevice *dev;
+
+	ut_assertok(scsi_scan(false));
+
+	/*
+	 * We expect some sort of partition on the disk image, created by
+	 * test_ut_dm_init()
+	 */
+	ut_assertok(uclass_first_device_err(UCLASS_PARTITION, &dev));
+
+	part = dev_get_uclass_plat(dev);
+	ut_asserteq(1, part->partnum);
+
+	info = &part->gpt_part_info;
+	ut_asserteq_str("sda1", info->name);
+	ut_asserteq_str("U-Boot", info->type);
+	ut_asserteq(0x83 /* linux */, info->sys_ind);
+
+	return 0;
+}
+DM_TEST(dm_test_scsi_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
diff --git a/test/lib/test_print.c b/test/lib/test_print.c
index a60a5a5..79b67c7 100644
--- a/test/lib/test_print.c
+++ b/test/lib/test_print.c
@@ -68,6 +68,9 @@
 	ut_assertok(test_print_size(uts, 7654321, "7.3 MiB;"));
 	ut_assertok(test_print_size(uts, 87654321, "83.6 MiB;"));
 	ut_assertok(test_print_size(uts, 987654321, "941.9 MiB;"));
+	ut_assertok(test_print_size(uts, 1073689395, "1023.9 MiB;"));
+	ut_assertok(test_print_size(uts, 1073689396, "1 GiB;"));
+	ut_assertok(test_print_size(uts, 1073741824, "1 GiB;"));
 	ut_assertok(test_print_size(uts, 1987654321, "1.9 GiB;"));
 	ut_assertok(test_print_size(uts, 54321987654321, "49.4 TiB;"));
 	return 0;
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index 35fb393..9d42390 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -114,6 +114,15 @@
         with open(fn, 'wb') as fh:
             fh.write(data)
 
+    # Create a file with a single partition
+    fn = u_boot_console.config.source_dir + '/scsi.img'
+    if not os.path.exists(fn):
+        data = b'\x00' * (2 * 1024 * 1024)
+        with open(fn, 'wb') as fh:
+            fh.write(data)
+        u_boot_utils.run_and_log(
+            u_boot_console, f'sfdisk {fn}', stdin=b'type=83')
+
 @pytest.mark.buildconfigspec('cmd_bootflow')
 def test_ut_dm_init_bootstd(u_boot_console):
     """Initialise data for bootflow tests"""
diff --git a/tools/Makefile b/tools/Makefile
index 3626919..34a1aa7 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -147,6 +147,7 @@
 			gpimage.o \
 			gpimage-common.o \
 			mtk_image.o \
+			mtk_nand_headers.o \
 			$(ECDSA_OBJS-y) \
 			$(RSA_OBJS-y) \
 			$(AES_OBJS-y)
diff --git a/tools/binman/bintool.py b/tools/binman/bintool.py
index 032179a..a582d9d 100644
--- a/tools/binman/bintool.py
+++ b/tools/binman/bintool.py
@@ -319,7 +319,7 @@
             return result.stdout
 
     @classmethod
-    def build_from_git(cls, git_repo, make_target, bintool_path):
+    def build_from_git(cls, git_repo, make_target, bintool_path, flags=None):
         """Build a bintool from a git repo
 
         This clones the repo in a temporary directory, builds it with 'make',
@@ -330,6 +330,7 @@
             make_target (str): Target to pass to 'make' to build the tool
             bintool_path (str): Relative path of the tool in the repo, after
                 build is complete
+            flags (list of str): Flags or variables to pass to make, or None
 
         Returns:
             tuple:
@@ -341,8 +342,11 @@
         print(f"- clone git repo '{git_repo}' to '{tmpdir}'")
         tools.run('git', 'clone', '--depth', '1', git_repo, tmpdir)
         print(f"- build target '{make_target}'")
-        tools.run('make', '-C', tmpdir, '-j', f'{multiprocessing.cpu_count()}',
-                  make_target)
+        cmd = ['make', '-C', tmpdir, '-j', f'{multiprocessing.cpu_count()}',
+               make_target]
+        if flags:
+            cmd += flags
+        tools.run(*cmd)
         fname = os.path.join(tmpdir, bintool_path)
         if not os.path.exists(fname):
             print(f"- File '{fname}' was not produced")
diff --git a/tools/binman/btool/futility.py b/tools/binman/btool/futility.py
index 75a05c2..04c9aef 100644
--- a/tools/binman/btool/futility.py
+++ b/tools/binman/btool/futility.py
@@ -160,8 +160,17 @@
         Raises:
             Valuerror: Fetching could not be completed
         """
-        if method != bintool.FETCH_BIN:
+        if method != bintool.FETCH_BUILD:
             return None
-        fname, tmpdir = self.fetch_from_drive(
-            '1hdsInzsE4aJbmBeJ663kYgjOQyW1I-E0')
-        return fname, tmpdir
+
+        # The Chromium OS repo is here:
+        # https://chromium.googlesource.com/chromiumos/platform/vboot_reference/
+        #
+        # Unfortunately this requires logging in and obtaining a line for the
+        # .gitcookies file. So use a mirror instead.
+        result = self.build_from_git(
+            'https://github.com/sjg20/vboot_reference.git',
+            'all',
+            'build/futility/futility',
+            flags=['USE_FLASHROM=0'])
+        return result
diff --git a/tools/mtk_image.c b/tools/mtk_image.c
index de5ce4d..9b3136a 100644
--- a/tools/mtk_image.c
+++ b/tools/mtk_image.c
@@ -12,216 +12,7 @@
 #include <u-boot/sha256.h>
 #include "imagetool.h"
 #include "mtk_image.h"
-
-/* NAND header for SPI-NAND with 2KB page + 64B spare */
-static const union nand_boot_header snand_hdr_2k_64_data = {
-	.data = {
-		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
-		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
-		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
-		0x00, 0x00, 0x00, 0x08, 0x03, 0x00, 0x40, 0x00,
-		0x40, 0x00, 0x00, 0x08, 0x10, 0x00, 0x16, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x7B, 0xC4, 0x17, 0x9D,
-		0xCA, 0x42, 0x90, 0xD0, 0x98, 0xD0, 0xE0, 0xF7,
-		0xDB, 0xCD, 0x16, 0xF6, 0x03, 0x73, 0xD2, 0xB8,
-		0x93, 0xB2, 0x56, 0x5A, 0x84, 0x6E, 0x00, 0x00
-	}
-};
-
-/* NAND header for SPI-NAND with 2KB page + 120B/128B spare */
-static const union nand_boot_header snand_hdr_2k_128_data = {
-	.data = {
-		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
-		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
-		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
-		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x70, 0x00,
-		0x40, 0x00, 0x00, 0x08, 0x10, 0x00, 0x16, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x90, 0x28, 0xED, 0x13,
-		0x7F, 0x12, 0x22, 0xCD, 0x3D, 0x06, 0xF1, 0xB3,
-		0x6F, 0x2E, 0xD9, 0xA0, 0x9D, 0x7A, 0xBD, 0xD7,
-		0xB3, 0x28, 0x3C, 0x13, 0xDB, 0x4E, 0x00, 0x00
-	}
-};
-
-/* NAND header for SPI-NAND with 4KB page + 256B spare */
-static const union nand_boot_header snand_hdr_4k_256_data = {
-	.data = {
-		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
-		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
-		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
-		0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0xE0, 0x00,
-		0x40, 0x00, 0x00, 0x08, 0x10, 0x00, 0x16, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x47, 0xED, 0x0E, 0xC3,
-		0x83, 0xBF, 0x41, 0xD2, 0x85, 0x21, 0x97, 0x57,
-		0xC4, 0x2E, 0x6B, 0x7A, 0x40, 0xE0, 0xCF, 0x8F,
-		0x37, 0xBD, 0x17, 0xB6, 0xC7, 0xFE, 0x00, 0x00
-	}
-};
-
-/* NAND header for Parallel NAND 1Gb with 2KB page + 64B spare */
-static const union nand_boot_header nand_hdr_1gb_2k_64_data = {
-	.data = {
-		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
-		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
-		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
-		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x40, 0x00,
-		0x40, 0x00, 0x00, 0x04, 0x0B, 0x00, 0x11, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x1C, 0x12,
-		0x8F, 0xFD, 0xF8, 0x32, 0x6F, 0x6D, 0xCF, 0x6C,
-		0xDA, 0x21, 0x70, 0x8C, 0xDA, 0x0A, 0x22, 0x82,
-		0xAA, 0x59, 0xFA, 0x7C, 0x42, 0x2D, 0x00, 0x00
-	}
-};
-
-/* NAND header for Parallel NAND 2Gb with 2KB page + 64B spare */
-static const union nand_boot_header nand_hdr_2gb_2k_64_data = {
-	.data = {
-		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
-		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
-		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
-		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x40, 0x00,
-		0x40, 0x00, 0x00, 0x08, 0x0B, 0x00, 0x11, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x20, 0x9C, 0x3D, 0x2D,
-		0x7B, 0x68, 0x63, 0x52, 0x2E, 0x04, 0x63, 0xF1,
-		0x35, 0x4E, 0x44, 0x3E, 0xF8, 0xAC, 0x9B, 0x95,
-		0xAB, 0xFE, 0xE4, 0xE1, 0xD5, 0xF9, 0x00, 0x00
-	}
-};
-
-/* NAND header for Parallel NAND 4Gb with 2KB page + 64B spare */
-static const union nand_boot_header nand_hdr_4gb_2k_64_data = {
-	.data = {
-		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
-		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
-		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
-		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x40, 0x00,
-		0x40, 0x00, 0x00, 0x10, 0x0B, 0x00, 0x11, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0xE3, 0x0F, 0x86, 0x32,
-		0x68, 0x05, 0xD9, 0xC8, 0x13, 0xDF, 0xC5, 0x0B,
-		0x35, 0x3A, 0x68, 0xA5, 0x3C, 0x0C, 0x73, 0x87,
-		0x63, 0xB0, 0xBE, 0xCC, 0x84, 0x47, 0x00, 0x00
-	}
-};
-
-/* NAND header for Parallel NAND 2Gb with 2KB page + 128B spare */
-static const union nand_boot_header nand_hdr_2gb_2k_128_data = {
-	.data = {
-		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
-		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
-		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
-		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x70, 0x00,
-		0x40, 0x00, 0x00, 0x08, 0x0B, 0x00, 0x11, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x01, 0xA5, 0xE9, 0x5A,
-		0xDF, 0x58, 0x62, 0x41, 0xD6, 0x26, 0x77, 0xBC,
-		0x76, 0x1F, 0x27, 0x4E, 0x4F, 0x6C, 0xC3, 0xF0,
-		0x36, 0xDE, 0xD9, 0xB3, 0xFF, 0x93, 0x00, 0x00
-	}
-};
-
-/* NAND header for Parallel NAND 4Gb with 2KB page + 128B spare */
-static const union nand_boot_header nand_hdr_4gb_2k_128_data = {
-	.data = {
-		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
-		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
-		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
-		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x70, 0x00,
-		0x40, 0x00, 0x00, 0x10, 0x0B, 0x00, 0x11, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0xC2, 0x36, 0x52, 0x45,
-		0xCC, 0x35, 0xD8, 0xDB, 0xEB, 0xFD, 0xD1, 0x46,
-		0x76, 0x6B, 0x0B, 0xD5, 0x8B, 0xCC, 0x2B, 0xE2,
-		0xFE, 0x90, 0x83, 0x9E, 0xAE, 0x2D, 0x00, 0x00
-	}
-};
-
-static const struct nand_header_type {
-	const char *name;
-	const union nand_boot_header *data;
-} nand_headers[] = {
-	{
-		.name = "2k+64",
-		.data = &snand_hdr_2k_64_data
-	}, {
-		.name = "2k+120",
-		.data = &snand_hdr_2k_128_data
-	}, {
-		.name = "2k+128",
-		.data = &snand_hdr_2k_128_data
-	}, {
-		.name = "4k+256",
-		.data = &snand_hdr_4k_256_data
-	}, {
-		.name = "1g:2k+64",
-		.data = &nand_hdr_1gb_2k_64_data
-	}, {
-		.name = "2g:2k+64",
-		.data = &nand_hdr_2gb_2k_64_data
-	}, {
-		.name = "4g:2k+64",
-		.data = &nand_hdr_4gb_2k_64_data
-	}, {
-		.name = "2g:2k+128",
-		.data = &nand_hdr_2gb_2k_128_data
-	}, {
-		.name = "4g:2k+128",
-		.data = &nand_hdr_4gb_2k_128_data
-	}
-};
+#include "mtk_nand_headers.h"
 
 static const struct brom_img_type {
 	const char *name;
@@ -242,6 +33,9 @@
 	}, {
 		.name = "snand",
 		.type = BRLYT_TYPE_SNAND
+	}, {
+		.name = "spim-nand",
+		.type = BRLYT_TYPE_SNAND
 	}
 };
 
@@ -263,7 +57,8 @@
 static uint32_t crc32tbl[256];
 
 /* NAND header selected by user */
-static const union nand_boot_header *hdr_nand;
+static const struct nand_header_type *hdr_nand;
+static uint32_t hdr_nand_size;
 
 /* GFH header + 2 * 4KB pages of NAND */
 static char hdr_tmp[sizeof(struct gfh_header) + 0x2000];
@@ -402,12 +197,7 @@
 	}
 
 	/* parse nand header type */
-	for (i = 0; i < ARRAY_SIZE(nand_headers); i++) {
-		if (!strcmp(nand_headers[i].name, nandinfo)) {
-			hdr_nand = nand_headers[i].data;
-			break;
-		}
-	}
+	hdr_nand = mtk_nand_header_find(nandinfo);
 
 	/* parse device header offset */
 	if (hdr_offs && hdr_offs[0])
@@ -432,6 +222,9 @@
 		return -EINVAL;
 	}
 
+	if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND)
+		hdr_nand_size = mtk_nand_header_size(hdr_nand);
+
 	return 0;
 }
 
@@ -468,7 +261,7 @@
 	}
 
 	if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND)
-		tparams->header_size = 2 * le16_to_cpu(hdr_nand->pagesize);
+		tparams->header_size = hdr_nand_size;
 	else
 		tparams->header_size = sizeof(struct gen_device_header);
 
@@ -480,6 +273,25 @@
 	return SHA256_SUM_LEN;
 }
 
+static int mtk_image_verify_gfh(struct gfh_header *gfh, uint32_t type, int print)
+{
+	if (strcmp(gfh->file_info.name, GFH_FILE_INFO_NAME))
+		return -1;
+
+	if (le32_to_cpu(gfh->file_info.flash_type) != type)
+		return -1;
+
+	if (print)
+		printf("Load Address: %08x\n",
+		       le32_to_cpu(gfh->file_info.load_addr) +
+		       le32_to_cpu(gfh->file_info.jump_offset));
+
+	if (print)
+		printf("Architecture: %s\n", is_arm64_image ? "ARM64" : "ARM");
+
+	return 0;
+}
+
 static int mtk_image_verify_gen_header(const uint8_t *ptr, int print)
 {
 	union gen_boot_header *gbh = (union gen_boot_header *)ptr;
@@ -542,89 +354,57 @@
 
 	gfh = (struct gfh_header *)(ptr + gfh_offset);
 
-	if (strcmp(gfh->file_info.name, GFH_FILE_INFO_NAME))
-		return -1;
-
-	if (le32_to_cpu(gfh->file_info.flash_type) != GFH_FLASH_TYPE_GEN)
-		return -1;
-
-	if (print)
-		printf("Load Address: %08x\n",
-		       le32_to_cpu(gfh->file_info.load_addr) +
-		       le32_to_cpu(gfh->file_info.jump_offset));
-
-	if (print)
-		printf("Architecture: %s\n", is_arm64_image ? "ARM64" : "ARM");
-
-	return 0;
+	return mtk_image_verify_gfh(gfh, GFH_FLASH_TYPE_GEN, print);
 }
 
 static int mtk_image_verify_nand_header(const uint8_t *ptr, int print)
 {
-	union nand_boot_header *nh = (union nand_boot_header *)ptr;
 	struct brom_layout_header *bh;
+	struct nand_header_info info;
 	struct gfh_header *gfh;
 	const char *bootmedia;
+	int ret;
 
-	if (strncmp(nh->version, NAND_BOOT_VERSION, sizeof(nh->version)) ||
-	    strcmp(nh->id, NAND_BOOT_ID))
-		return -1;
+	ret = mtk_nand_header_info(ptr, &info);
+	if (ret < 0)
+		return ret;
 
-	bh = (struct brom_layout_header *)(ptr + le16_to_cpu(nh->pagesize));
+	if (!ret) {
+		bh = (struct brom_layout_header *)(ptr + info.page_size);
 
-	if (strcmp(bh->name, BRLYT_NAME))
-		return -1;
+		if (strcmp(bh->name, BRLYT_NAME))
+			return -1;
 
-	if (le32_to_cpu(bh->magic) != BRLYT_MAGIC) {
-		return -1;
-	} else {
+		if (le32_to_cpu(bh->magic) != BRLYT_MAGIC)
+			return -1;
+
 		if (le32_to_cpu(bh->type) == BRLYT_TYPE_NAND)
 			bootmedia = "Parallel NAND";
 		else if (le32_to_cpu(bh->type) == BRLYT_TYPE_SNAND)
-			bootmedia = "Serial NAND";
+			bootmedia = "Serial NAND (SNFI/AP)";
 		else
 			return -1;
+	} else {
+		if (info.snfi)
+			bootmedia = "Serial NAND (SNFI/HSM)";
+		else
+			bootmedia = "Serial NAND (SPIM)";
 	}
 
 	if (print) {
-		printf("Boot Media: %s\n", bootmedia);
-
-		if (le32_to_cpu(bh->type) == BRLYT_TYPE_NAND) {
-			uint64_t capacity =
-				(uint64_t)le16_to_cpu(nh->numblocks) *
-				(uint64_t)le16_to_cpu(nh->pages_of_block) *
-				(uint64_t)le16_to_cpu(nh->pagesize) * 8;
-			printf("Capacity:     %dGb\n",
-			       (uint32_t)(capacity >> 30));
-		}
+		printf("Boot Media:   %s\n", bootmedia);
 
-		if (le16_to_cpu(nh->pagesize) >= 1024)
-			printf("Page Size:    %dKB\n",
-			       le16_to_cpu(nh->pagesize) >> 10);
+		if (info.page_size >= 1024)
+			printf("Page Size:    %dKB\n", info.page_size >> 10);
 		else
-			printf("Page Size:    %dB\n",
-			       le16_to_cpu(nh->pagesize));
+			printf("Page Size:    %dB\n", info.page_size);
 
-		printf("Spare Size:   %dB\n", le16_to_cpu(nh->oobsize));
+		printf("Spare Size:   %dB\n", info.spare_size);
 	}
 
-	gfh = (struct gfh_header *)(ptr + 2 * le16_to_cpu(nh->pagesize));
-
-	if (strcmp(gfh->file_info.name, GFH_FILE_INFO_NAME))
-		return -1;
-
-	if (le32_to_cpu(gfh->file_info.flash_type) != GFH_FLASH_TYPE_NAND)
-		return -1;
+	gfh = (struct gfh_header *)(ptr + info.gfh_offset);
 
-	if (print)
-		printf("Load Address: %08x\n",
-		       le32_to_cpu(gfh->file_info.load_addr) +
-		       le32_to_cpu(gfh->file_info.jump_offset));
-
-	if (print)
-		printf("Architecture: %s\n", is_arm64_image ? "ARM64" : "ARM");
-
-	return 0;
+	return mtk_image_verify_gfh(gfh, GFH_FLASH_TYPE_NAND, print);
 }
 
 static uint32_t crc32be_cal(const void *data, size_t length)
@@ -722,7 +502,7 @@
 	if (image_get_magic(hdr) == IH_MAGIC)
 		return mtk_image_verify_mt7621_header(ptr, 0);
 
-	if (!strcmp((char *)ptr, NAND_BOOT_NAME))
+	if (is_mtk_nand_header(ptr))
 		return mtk_image_verify_nand_header(ptr, 0);
 	else
 		return mtk_image_verify_gen_header(ptr, 0);
@@ -748,7 +528,7 @@
 		return;
 	}
 
-	if (!strcmp((char *)ptr, NAND_BOOT_NAME))
+	if (is_mtk_nand_header(ptr))
 		mtk_image_verify_nand_header(ptr, 1);
 	else
 		mtk_image_verify_gen_header(ptr, 1);
@@ -879,36 +659,33 @@
 static void mtk_image_set_nand_header(void *ptr, off_t filesize,
 				      uint32_t loadaddr)
 {
-	union nand_boot_header *nh = (union nand_boot_header *)ptr;
 	struct brom_layout_header *brlyt;
 	struct gfh_header *gfh;
-	uint32_t payload_pages;
-	int i;
+	uint32_t payload_pages, nand_page_size;
 
-	/* NAND device header, repeat 4 times */
-	for (i = 0; i < 4; i++)
-		memcpy(nh + i, hdr_nand, sizeof(union nand_boot_header));
+	/* NAND header */
+	nand_page_size = mtk_nand_header_put(hdr_nand, ptr);
 
-	/* BRLYT header */
-	payload_pages = (filesize + le16_to_cpu(hdr_nand->pagesize) - 1) /
-			le16_to_cpu(hdr_nand->pagesize);
-	brlyt = (struct brom_layout_header *)
-		(ptr + le16_to_cpu(hdr_nand->pagesize));
-	put_brom_layout_header(brlyt, hdr_media);
-	brlyt->header_size = cpu_to_le32(2);
-	brlyt->total_size = cpu_to_le32(payload_pages);
-	brlyt->header_size_2 = brlyt->header_size;
-	brlyt->total_size_2 = brlyt->total_size;
-	brlyt->unused = cpu_to_le32(1);
+	if (nand_page_size) {
+		/* BRLYT header */
+		payload_pages = (filesize + nand_page_size - 1) /
+				nand_page_size;
+		brlyt = (struct brom_layout_header *)(ptr + nand_page_size);
+		put_brom_layout_header(brlyt, hdr_media);
+		brlyt->header_size = cpu_to_le32(2);
+		brlyt->total_size = cpu_to_le32(payload_pages);
+		brlyt->header_size_2 = brlyt->header_size;
+		brlyt->total_size_2 = brlyt->total_size;
+		brlyt->unused = cpu_to_le32(1);
+	}
 
 	/* GFH header */
-	gfh = (struct gfh_header *)(ptr + 2 * le16_to_cpu(hdr_nand->pagesize));
-	put_ghf_header(gfh, filesize, 2 * le16_to_cpu(hdr_nand->pagesize),
-		       loadaddr, GFH_FLASH_TYPE_NAND);
+	gfh = (struct gfh_header *)(ptr + hdr_nand_size);
+	put_ghf_header(gfh, filesize, hdr_nand_size, loadaddr,
+		       GFH_FLASH_TYPE_NAND);
 
 	/* Generate SHA256 hash */
-	put_hash((uint8_t *)gfh,
-		 filesize - 2 * le16_to_cpu(hdr_nand->pagesize) - SHA256_SUM_LEN);
+	put_hash((uint8_t *)gfh, filesize - hdr_nand_size - SHA256_SUM_LEN);
 }
 
 static void mtk_image_set_mt7621_header(void *ptr, off_t filesize,
diff --git a/tools/mtk_image.h b/tools/mtk_image.h
index d868545..fad9372 100644
--- a/tools/mtk_image.h
+++ b/tools/mtk_image.h
@@ -26,31 +26,6 @@
 #define SF_BOOT_NAME		"SF_BOOT"
 #define SDMMC_BOOT_NAME		"SDMMC_BOOT"
 
-/* Header for NAND */
-union nand_boot_header {
-	struct {
-		char name[12];
-		char version[4];
-		char id[8];
-		uint16_t ioif;
-		uint16_t pagesize;
-		uint16_t addrcycles;
-		uint16_t oobsize;
-		uint16_t pages_of_block;
-		uint16_t numblocks;
-		uint16_t writesize_shift;
-		uint16_t erasesize_shift;
-		uint8_t dummy[60];
-		uint8_t ecc_parity[28];
-	};
-
-	uint8_t data[0x80];
-};
-
-#define NAND_BOOT_NAME		"BOOTLOADER!"
-#define NAND_BOOT_VERSION	"V006"
-#define NAND_BOOT_ID		"NFIINFO"
-
 /* BootROM layout header */
 struct brom_layout_header {
 	char name[8];
diff --git a/tools/mtk_nand_headers.c b/tools/mtk_nand_headers.c
new file mode 100644
index 0000000..2fa91e7
--- /dev/null
+++ b/tools/mtk_nand_headers.c
@@ -0,0 +1,668 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MediaTek BootROM NAND header definitions
+ *
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "imagetool.h"
+#include "mtk_image.h"
+#include "mtk_nand_headers.h"
+
+/* NAND header for SPI-NAND with 2KB page + 64B spare */
+static const union nand_boot_header snand_hdr_2k_64_data = {
+	.data = {
+		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
+		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
+		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
+		0x00, 0x00, 0x00, 0x08, 0x03, 0x00, 0x40, 0x00,
+		0x40, 0x00, 0x00, 0x08, 0x10, 0x00, 0x16, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x7B, 0xC4, 0x17, 0x9D,
+		0xCA, 0x42, 0x90, 0xD0, 0x98, 0xD0, 0xE0, 0xF7,
+		0xDB, 0xCD, 0x16, 0xF6, 0x03, 0x73, 0xD2, 0xB8,
+		0x93, 0xB2, 0x56, 0x5A, 0x84, 0x6E, 0x00, 0x00
+	}
+};
+
+/* NAND header for SPI-NAND with 2KB page + 120B/128B spare */
+static const union nand_boot_header snand_hdr_2k_128_data = {
+	.data = {
+		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
+		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
+		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
+		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x70, 0x00,
+		0x40, 0x00, 0x00, 0x08, 0x10, 0x00, 0x16, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x90, 0x28, 0xED, 0x13,
+		0x7F, 0x12, 0x22, 0xCD, 0x3D, 0x06, 0xF1, 0xB3,
+		0x6F, 0x2E, 0xD9, 0xA0, 0x9D, 0x7A, 0xBD, 0xD7,
+		0xB3, 0x28, 0x3C, 0x13, 0xDB, 0x4E, 0x00, 0x00
+	}
+};
+
+/* NAND header for SPI-NAND with 4KB page + 256B spare */
+static const union nand_boot_header snand_hdr_4k_256_data = {
+	.data = {
+		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
+		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
+		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
+		0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0xE0, 0x00,
+		0x40, 0x00, 0x00, 0x08, 0x10, 0x00, 0x16, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x47, 0xED, 0x0E, 0xC3,
+		0x83, 0xBF, 0x41, 0xD2, 0x85, 0x21, 0x97, 0x57,
+		0xC4, 0x2E, 0x6B, 0x7A, 0x40, 0xE0, 0xCF, 0x8F,
+		0x37, 0xBD, 0x17, 0xB6, 0xC7, 0xFE, 0x00, 0x00
+	}
+};
+
+/* NAND header for Parallel NAND 1Gb with 2KB page + 64B spare */
+static const union nand_boot_header nand_hdr_1gb_2k_64_data = {
+	.data = {
+		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
+		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
+		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
+		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x40, 0x00,
+		0x40, 0x00, 0x00, 0x04, 0x0B, 0x00, 0x11, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x12, 0x28, 0x1C, 0x12,
+		0x8F, 0xFD, 0xF8, 0x32, 0x6F, 0x6D, 0xCF, 0x6C,
+		0xDA, 0x21, 0x70, 0x8C, 0xDA, 0x0A, 0x22, 0x82,
+		0xAA, 0x59, 0xFA, 0x7C, 0x42, 0x2D, 0x00, 0x00
+	}
+};
+
+/* NAND header for Parallel NAND 2Gb with 2KB page + 64B spare */
+static const union nand_boot_header nand_hdr_2gb_2k_64_data = {
+	.data = {
+		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
+		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
+		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
+		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x40, 0x00,
+		0x40, 0x00, 0x00, 0x08, 0x0B, 0x00, 0x11, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x20, 0x9C, 0x3D, 0x2D,
+		0x7B, 0x68, 0x63, 0x52, 0x2E, 0x04, 0x63, 0xF1,
+		0x35, 0x4E, 0x44, 0x3E, 0xF8, 0xAC, 0x9B, 0x95,
+		0xAB, 0xFE, 0xE4, 0xE1, 0xD5, 0xF9, 0x00, 0x00
+	}
+};
+
+/* NAND header for Parallel NAND 4Gb with 2KB page + 64B spare */
+static const union nand_boot_header nand_hdr_4gb_2k_64_data = {
+	.data = {
+		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
+		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
+		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
+		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x40, 0x00,
+		0x40, 0x00, 0x00, 0x10, 0x0B, 0x00, 0x11, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0xE3, 0x0F, 0x86, 0x32,
+		0x68, 0x05, 0xD9, 0xC8, 0x13, 0xDF, 0xC5, 0x0B,
+		0x35, 0x3A, 0x68, 0xA5, 0x3C, 0x0C, 0x73, 0x87,
+		0x63, 0xB0, 0xBE, 0xCC, 0x84, 0x47, 0x00, 0x00
+	}
+};
+
+/* NAND header for Parallel NAND 2Gb with 2KB page + 128B spare */
+static const union nand_boot_header nand_hdr_2gb_2k_128_data = {
+	.data = {
+		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
+		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
+		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
+		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x70, 0x00,
+		0x40, 0x00, 0x00, 0x08, 0x0B, 0x00, 0x11, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x01, 0xA5, 0xE9, 0x5A,
+		0xDF, 0x58, 0x62, 0x41, 0xD6, 0x26, 0x77, 0xBC,
+		0x76, 0x1F, 0x27, 0x4E, 0x4F, 0x6C, 0xC3, 0xF0,
+		0x36, 0xDE, 0xD9, 0xB3, 0xFF, 0x93, 0x00, 0x00
+	}
+};
+
+/* NAND header for Parallel NAND 4Gb with 2KB page + 128B spare */
+static const union nand_boot_header nand_hdr_4gb_2k_128_data = {
+	.data = {
+		0x42, 0x4F, 0x4F, 0x54, 0x4C, 0x4F, 0x41, 0x44,
+		0x45, 0x52, 0x21, 0x00, 0x56, 0x30, 0x30, 0x36,
+		0x4E, 0x46, 0x49, 0x49, 0x4E, 0x46, 0x4F, 0x00,
+		0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x70, 0x00,
+		0x40, 0x00, 0x00, 0x10, 0x0B, 0x00, 0x11, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0xC2, 0x36, 0x52, 0x45,
+		0xCC, 0x35, 0xD8, 0xDB, 0xEB, 0xFD, 0xD1, 0x46,
+		0x76, 0x6B, 0x0B, 0xD5, 0x8B, 0xCC, 0x2B, 0xE2,
+		0xFE, 0x90, 0x83, 0x9E, 0xAE, 0x2D, 0x00, 0x00
+	}
+};
+
+/* HSM BROM NAND header for SPI NAND with 2KB page + 64B spare */
+static const union hsm_nand_boot_header hsm_nand_hdr_2k_64_data = {
+	.data = {
+		0x4E, 0x41, 0x4E, 0x44, 0x43, 0x46, 0x47, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+		0x40, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+		0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+		0xFF, 0x00, 0x00, 0x00, 0x21, 0xD2, 0xEE, 0xF6,
+		0xAE, 0xDD, 0x5E, 0xC2, 0x82, 0x8E, 0x9A, 0x62,
+		0x09, 0x8E, 0x80, 0xE2, 0x37, 0x0D, 0xC9, 0xFA,
+		0xA9, 0xDD, 0xFC, 0x92, 0x34, 0x2A, 0xED, 0x51,
+		0xA4, 0x1B, 0xF7, 0x63, 0xCC, 0x5A, 0xC7, 0xFB,
+		0xED, 0x21, 0x02, 0x23, 0x51, 0x31
+	}
+};
+
+/* HSM BROM NAND header for SPI NAND with 2KB page + 128B spare */
+static const union hsm_nand_boot_header hsm_nand_hdr_2k_128_data = {
+	.data = {
+		0x4E, 0x41, 0x4E, 0x44, 0x43, 0x46, 0x47, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x08, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+		0x40, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+		0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+		0xFF, 0x00, 0x00, 0x00, 0x71, 0x7f, 0x71, 0xAC,
+		0x42, 0xD0, 0x5B, 0xD2, 0x12, 0x81, 0x15, 0x0A,
+		0x0C, 0xD4, 0xF6, 0x32, 0x1E, 0x63, 0xE7, 0x81,
+		0x8A, 0x7F, 0xDE, 0xF9, 0x4B, 0x91, 0xEC, 0xC2,
+		0x70, 0x00, 0x7F, 0x57, 0xAF, 0xDC, 0xE4, 0x24,
+		0x57, 0x09, 0xBC, 0xC5, 0x35, 0xDC
+	}
+};
+
+/* HSM BROM NAND header for SPI NAND with 4KB page + 256B spare */
+static const union hsm_nand_boot_header hsm_nand_hdr_4k_256_data = {
+	.data = {
+		0x4E, 0x41, 0x4E, 0x44, 0x43, 0x46, 0x47, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+		0x40, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+		0x0C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+		0xFF, 0x00, 0x00, 0x00, 0x62, 0x04, 0xD6, 0x1F,
+		0x2B, 0x57, 0x7A, 0x2D, 0xFE, 0xBB, 0x4A, 0x50,
+		0xEC, 0xF8, 0x70, 0x1A, 0x44, 0x15, 0xF6, 0xA2,
+		0x8E, 0xB0, 0xFD, 0xFA, 0xDC, 0xAA, 0x5A, 0x4E,
+		0xCB, 0x8E, 0xC9, 0x72, 0x08, 0xDC, 0x20, 0xB9,
+		0x98, 0xC8, 0x82, 0xD8, 0xBE, 0x44
+	}
+};
+
+/* HSM2.0 BROM NAND header for SPI NAND with 2KB page + 64B spare */
+static const union hsm20_nand_boot_header hsm20_nand_hdr_2k_64_data = {
+	.data = {
+		0x4E, 0x41, 0x4E, 0x44, 0x43, 0x46, 0x47, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+		0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+		0x40, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+		0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+		0x01, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x5F, 0x4B, 0xB2, 0x5B, 0x8B, 0x1C, 0x35, 0xDA,
+		0x83, 0xE6, 0x6C, 0xC3, 0xFB, 0x8C, 0x78, 0x23,
+		0xD0, 0x89, 0x24, 0xD9, 0x6C, 0x35, 0x2C, 0x5D,
+		0x8F, 0xBB, 0xFC, 0x10, 0xD0, 0xE2, 0x22, 0x7D,
+		0xC8, 0x97, 0x9A, 0xEF, 0xC6, 0xB5, 0xA7, 0x4E,
+		0x4E, 0x0E
+	}
+};
+
+/* HSM2.0 BROM NAND header for SPI NAND with 2KB page + 128B spare */
+static const union hsm20_nand_boot_header hsm20_nand_hdr_2k_128_data = {
+	.data = {
+		0x4E, 0x41, 0x4E, 0x44, 0x43, 0x46, 0x47, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+		0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x08, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+		0x40, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+		0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+		0x01, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0xF8, 0x7E, 0xC1, 0x5D, 0x61, 0x54, 0xEA, 0x9F,
+		0x5E, 0x66, 0x39, 0x66, 0x21, 0xFF, 0x8C, 0x3B,
+		0xBE, 0xA7, 0x5A, 0x9E, 0xD7, 0xBD, 0x9E, 0x89,
+		0xEE, 0x7E, 0x10, 0x31, 0x9A, 0x1D, 0x82, 0x49,
+		0xA3, 0x4E, 0xD8, 0x47, 0xD7, 0x19, 0xF4, 0x2D,
+		0x8E, 0x53
+	}
+};
+
+/* HSM2.0 BROM NAND header for SPI NAND with 4KB page + 256B spare */
+static const union hsm20_nand_boot_header hsm20_nand_hdr_4k_256_data = {
+	.data = {
+		0x4E, 0x41, 0x4E, 0x44, 0x43, 0x46, 0x47, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+		0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+		0x40, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+		0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+		0x01, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x79, 0x01, 0x1F, 0x86, 0x62, 0x6A, 0x43, 0xAE,
+		0xE6, 0xF8, 0xDD, 0x5B, 0x29, 0xB7, 0xA2, 0x7F,
+		0x29, 0x72, 0x54, 0x37, 0xBE, 0x50, 0xD4, 0x24,
+		0xAB, 0x60, 0xF4, 0x44, 0x97, 0x3B, 0x65, 0x21,
+		0x73, 0x24, 0x1F, 0x93, 0x0E, 0x9E, 0x96, 0x88,
+		0x78, 0x6C
+	}
+};
+
+/* SPIM-NAND header for SPI NAND with 2KB page + 64B spare */
+static const union spim_nand_boot_header spim_nand_hdr_2k_64_data = {
+	.data = {
+		0x53, 0x50, 0x49, 0x4e, 0x41, 0x4e, 0x44, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+		0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+		0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x30,
+		0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	}
+};
+
+/* SPIM-NAND header for SPI NAND with 2KB page + 128B spare */
+static const union spim_nand_boot_header spim_nand_hdr_2k_128_data = {
+	.data = {
+		0x53, 0x50, 0x49, 0x4e, 0x41, 0x4e, 0x44, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+		0x00, 0x08, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+		0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x30,
+		0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	}
+};
+
+/* SPIM-NAND header for SPI NAND with 4KB page + 256B spare */
+static const union spim_nand_boot_header spim_nand_hdr_4k_256_data = {
+	.data = {
+		0x53, 0x50, 0x49, 0x4e, 0x41, 0x4e, 0x44, 0x21,
+		0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+		0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+		0x40, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x30,
+		0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	}
+};
+
+struct nand_header_type {
+	const char *name;
+	enum nand_boot_header_type type;
+	union {
+		const union nand_boot_header *ap;
+		const union hsm_nand_boot_header *hsm;
+		const union hsm20_nand_boot_header *hsm20;
+		const union spim_nand_boot_header *spim;
+	};
+} nand_headers[] = {
+	{
+		.name = "2k+64",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &snand_hdr_2k_64_data,
+	}, {
+		.name = "2k+120",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &snand_hdr_2k_128_data,
+	}, {
+		.name = "2k+128",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &snand_hdr_2k_128_data,
+	}, {
+		.name = "4k+256",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &snand_hdr_4k_256_data,
+	}, {
+		.name = "1g:2k+64",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &nand_hdr_1gb_2k_64_data,
+	}, {
+		.name = "2g:2k+64",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &nand_hdr_2gb_2k_64_data,
+	}, {
+		.name = "4g:2k+64",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &nand_hdr_4gb_2k_64_data,
+	}, {
+		.name = "2g:2k+128",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &nand_hdr_2gb_2k_128_data,
+	}, {
+		.name = "4g:2k+128",
+		.type = NAND_BOOT_AP_HEADER,
+		.ap = &nand_hdr_4gb_2k_128_data,
+	}, {
+		.name = "hsm:2k+64",
+		.type = NAND_BOOT_HSM_HEADER,
+		.hsm = &hsm_nand_hdr_2k_64_data,
+	}, {
+		.name = "hsm:2k+128",
+		.type = NAND_BOOT_HSM_HEADER,
+		.hsm = &hsm_nand_hdr_2k_128_data,
+	}, {
+		.name = "hsm:4k+256",
+		.type = NAND_BOOT_HSM_HEADER,
+		.hsm = &hsm_nand_hdr_4k_256_data,
+	},  {
+		.name = "hsm20:2k+64",
+		.type = NAND_BOOT_HSM20_HEADER,
+		.hsm20 = &hsm20_nand_hdr_2k_64_data,
+	}, {
+		.name = "hsm20:2k+128",
+		.type = NAND_BOOT_HSM20_HEADER,
+		.hsm20 = &hsm20_nand_hdr_2k_128_data,
+	}, {
+		.name = "hsm20:4k+256",
+		.type = NAND_BOOT_HSM20_HEADER,
+		.hsm20 = &hsm20_nand_hdr_4k_256_data,
+	}, {
+		.name = "spim:2k+64",
+		.type = NAND_BOOT_SPIM_HEADER,
+		.spim = &spim_nand_hdr_2k_64_data,
+	}, {
+		.name = "spim:2k+128",
+		.type = NAND_BOOT_SPIM_HEADER,
+		.spim = &spim_nand_hdr_2k_128_data,
+	}, {
+		.name = "spim:4k+256",
+		.type = NAND_BOOT_SPIM_HEADER,
+		.spim = &spim_nand_hdr_4k_256_data,
+	}
+};
+
+const struct nand_header_type *mtk_nand_header_find(const char *name)
+{
+	uint32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(nand_headers); i++) {
+		if (!strcmp(nand_headers[i].name, name))
+			return &nand_headers[i];
+	}
+
+	return NULL;
+}
+
+uint32_t mtk_nand_header_size(const struct nand_header_type *hdr_nand)
+{
+	switch (hdr_nand->type) {
+	case NAND_BOOT_HSM_HEADER:
+		return le32_to_cpu(hdr_nand->hsm->page_size);
+
+	case NAND_BOOT_HSM20_HEADER:
+		return le32_to_cpu(hdr_nand->hsm20->page_size);
+
+	case NAND_BOOT_SPIM_HEADER:
+		return le32_to_cpu(hdr_nand->spim->page_size);
+
+	default:
+		return 2 * le16_to_cpu(hdr_nand->ap->pagesize);
+	}
+}
+
+static int mtk_nand_header_ap_info(const void *ptr,
+				   struct nand_header_info *info)
+{
+	union nand_boot_header *nh = (union nand_boot_header *)ptr;
+
+	if (strncmp(nh->version, NAND_BOOT_VERSION, sizeof(nh->version)) ||
+	    strcmp(nh->id, NAND_BOOT_ID))
+		return -1;
+
+	info->page_size = le16_to_cpu(nh->pagesize);
+	info->spare_size = le16_to_cpu(nh->oobsize);
+	info->gfh_offset = 2 * info->page_size;
+	info->snfi = true;
+
+	return 0;
+}
+
+static int mtk_nand_header_hsm_info(const void *ptr,
+				    struct nand_header_info *info)
+{
+	union hsm_nand_boot_header *nh = (union hsm_nand_boot_header *)ptr;
+
+	info->page_size = le16_to_cpu(nh->page_size);
+	info->spare_size = le16_to_cpu(nh->spare_size);
+	info->gfh_offset = info->page_size;
+	info->snfi = true;
+
+	return 1;
+}
+
+static int mtk_nand_header_spim_info(const void *ptr,
+				     struct nand_header_info *info)
+{
+	union spim_nand_boot_header *nh = (union spim_nand_boot_header *)ptr;
+
+	info->page_size = le16_to_cpu(nh->page_size);
+	info->spare_size = le16_to_cpu(nh->spare_size);
+	info->gfh_offset = info->page_size;
+	info->snfi = false;
+
+	return 1;
+}
+
+int mtk_nand_header_info(const void *ptr, struct nand_header_info *info)
+{
+	if (!strcmp((char *)ptr, NAND_BOOT_NAME))
+		return mtk_nand_header_ap_info(ptr, info);
+	else if (!strncmp((char *)ptr, HSM_NAND_BOOT_NAME, 8))
+		return mtk_nand_header_hsm_info(ptr, info);
+	else if (!strncmp((char *)ptr, SPIM_NAND_BOOT_NAME, 8))
+		return mtk_nand_header_spim_info(ptr, info);
+
+	return -1;
+}
+
+bool is_mtk_nand_header(const void *ptr)
+{
+	struct nand_header_info info;
+
+	if (mtk_nand_header_info(ptr, &info) >= 0)
+		return true;
+
+	return false;
+}
+
+static uint16_t crc16(const uint8_t *p, uint32_t len)
+{
+	uint16_t crc = 0x4f4e;
+	uint32_t i;
+
+	while (len--) {
+		crc ^= *p++ << 8;
+		for (i = 0; i < 8; i++)
+			crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
+	}
+
+	return crc;
+}
+
+static uint32_t mtk_nand_header_put_ap(const struct nand_header_type *hdr_nand,
+				       void *ptr)
+{
+	int i;
+
+	/* NAND device header, repeat 4 times */
+	for (i = 0; i < 4; i++) {
+		memcpy(ptr, hdr_nand->ap, sizeof(*hdr_nand->ap));
+		ptr += sizeof(*hdr_nand->ap);
+	}
+
+	return le16_to_cpu(hdr_nand->ap->pagesize);
+}
+
+static uint32_t mtk_nand_header_put_hsm(const struct nand_header_type *hdr_nand,
+					void *ptr)
+{
+	memcpy(ptr, hdr_nand->hsm, sizeof(*hdr_nand->hsm));
+	return 0;
+}
+
+static uint32_t mtk_nand_header_put_hsm20(const struct nand_header_type *hdr_nand,
+					  void *ptr)
+{
+	memcpy(ptr, hdr_nand->hsm20, sizeof(*hdr_nand->hsm20));
+	return 0;
+}
+
+static uint32_t mtk_nand_header_put_spim(const struct nand_header_type *hdr_nand,
+					 void *ptr)
+{
+	uint16_t crc;
+
+	memcpy(ptr, hdr_nand->spim, sizeof(*hdr_nand->spim));
+
+	crc = crc16(ptr, 0x4e);
+	memcpy(ptr + 0x4e, &crc, sizeof(uint16_t));
+
+	return 0;
+}
+
+uint32_t mtk_nand_header_put(const struct nand_header_type *hdr_nand, void *ptr)
+{
+	switch (hdr_nand->type) {
+	case NAND_BOOT_HSM_HEADER:
+		return mtk_nand_header_put_hsm(hdr_nand, ptr);
+
+	case NAND_BOOT_HSM20_HEADER:
+		return mtk_nand_header_put_hsm20(hdr_nand, ptr);
+
+	case NAND_BOOT_SPIM_HEADER:
+		return mtk_nand_header_put_spim(hdr_nand, ptr);
+
+	default:
+		return mtk_nand_header_put_ap(hdr_nand, ptr);
+	}
+}
diff --git a/tools/mtk_nand_headers.h b/tools/mtk_nand_headers.h
new file mode 100644
index 0000000..9b1c4ba
--- /dev/null
+++ b/tools/mtk_nand_headers.h
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * MediaTek BootROM NAND header definitions
+ *
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MTK_NAND_HEADERS_H
+#define _MTK_NAND_HEADERS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct nand_header_info {
+	uint32_t page_size;
+	uint32_t spare_size;
+	uint32_t gfh_offset;
+	bool snfi;
+};
+
+/* AP BROM Header for NAND */
+union nand_boot_header {
+	struct {
+		char name[12];
+		char version[4];
+		char id[8];
+		uint16_t ioif;			/* I/O interface */
+		uint16_t pagesize;		/* NAND page size */
+		uint16_t addrcycles;		/* Address cycles */
+		uint16_t oobsize;		/* NAND page spare size */
+		uint16_t pages_of_block;	/* Pages of one block */
+		uint16_t numblocks;		/* Total blocks of NAND chip */
+		uint16_t writesize_shift;
+		uint16_t erasesize_shift;
+		uint8_t dummy[60];
+		uint8_t ecc_parity[28];		/* ECC parity of this header */
+	};
+
+	uint8_t data[0x80];
+};
+
+/* HSM BROM Header for NAND */
+union hsm_nand_boot_header {
+	struct {
+		char id[8];
+		uint32_t version;		/* Header version */
+		uint32_t config;		/* Header config */
+		uint32_t sector_size;		/* ECC step size */
+		uint32_t fdm_size;		/* User OOB size of a step */
+		uint32_t fdm_ecc_size;		/* ECC parity size of a step */
+		uint32_t lbs;
+		uint32_t page_size;		/* NAND page size */
+		uint32_t spare_size;		/* NAND page spare size */
+		uint32_t page_per_block;	/* Pages of one block */
+		uint32_t blocks;		/* Total blocks of NAND chip */
+		uint32_t plane_sel_position;	/* Plane bit position */
+		uint32_t pll;			/* Value of pll reg */
+		uint32_t acccon;		/* Value of access timing reg */
+		uint32_t strobe_sel;		/* Value of DQS selection reg*/
+		uint32_t acccon1;		/* Value of access timing reg */
+		uint32_t dqs_mux;		/* Value of DQS mux reg */
+		uint32_t dqs_ctrl;		/* Value of DQS control reg */
+		uint32_t delay_ctrl;		/* Value of delay ctrl reg */
+		uint32_t latch_lat;		/* Value of latch latency reg */
+		uint32_t sample_delay;		/* Value of sample delay reg */
+		uint32_t driving;		/* Value of driving reg */
+		uint32_t bl_start;		/* Bootloader start addr */
+		uint32_t bl_end;		/* Bootloader end addr */
+		uint8_t ecc_parity[42];		/* ECC parity of this header */
+	};
+
+	uint8_t data[0x8E];
+};
+
+/* HSM2.0 BROM Header for NAND */
+union hsm20_nand_boot_header {
+	struct {
+		char id[8];
+		uint32_t version;		/* Header version */
+		uint32_t config;		/* Header config */
+		uint32_t sector_size;		/* ECC step size */
+		uint32_t fdm_size;		/* User OOB size of a step */
+		uint32_t fdm_ecc_size;		/* ECC parity size of a step */
+		uint32_t lbs;
+		uint32_t page_size;		/* NAND page size */
+		uint32_t spare_size;		/* NAND page spare size */
+		uint32_t page_per_block;	/* Pages of one block */
+		uint32_t blocks;		/* Total blocks of NAND chip */
+		uint32_t plane_sel_position;	/* Plane bit position */
+		uint32_t pll;			/* Value of pll reg */
+		uint32_t acccon;		/* Value of access timing reg */
+		uint32_t strobe_sel;		/* Value of DQS selection reg*/
+		uint32_t acccon1;		/* Value of access timing reg */
+		uint32_t dqs_mux;		/* Value of DQS mux reg */
+		uint32_t dqs_ctrl;		/* Value of DQS control reg */
+		uint32_t delay_ctrl;		/* Value of delay ctrl reg */
+		uint32_t latch_lat;		/* Value of latch latency reg */
+		uint32_t sample_delay;		/* Value of sample delay reg */
+		uint32_t driving;		/* Value of driving reg */
+		uint32_t reserved;
+		uint32_t bl0_start;		/* Bootloader start addr */
+		uint32_t bl0_end;		/* Bootloader end addr */
+		uint32_t bl0_type;		/* Bootloader type */
+		uint8_t bl_reserve[84];
+		uint8_t ecc_parity[42];		/* ECC parity of this header */
+	};
+
+	uint8_t data[0xEA];
+};
+
+/* SPIM BROM Header for SPI-NAND */
+union spim_nand_boot_header {
+	struct {
+		char id[8];
+		uint32_t version;		/* Header version */
+		uint32_t config;		/* Header config */
+		uint32_t page_size;		/* NAND page size */
+		uint32_t spare_size;		/* NAND page spare size */
+		uint16_t page_per_block;	/* Pages of one block */
+		uint16_t plane_sel_position;	/* Plane bit position */
+		uint16_t reserve_reg;
+		uint16_t reserve_val;
+		uint16_t ecc_error;		/* ECC error reg addr */
+		uint16_t ecc_mask;		/* ECC error bit mask */
+		uint32_t bl_start;		/* Bootloader start addr */
+		uint32_t bl_end;		/* Bootloader end addr */
+		uint8_t ecc_parity[32];		/* ECC parity of this header */
+		uint32_t integrity_crc;		/* CRC of this header */
+	};
+
+	uint8_t data[0x50];
+};
+
+enum nand_boot_header_type {
+	NAND_BOOT_AP_HEADER,
+	NAND_BOOT_HSM_HEADER,
+	NAND_BOOT_HSM20_HEADER,
+	NAND_BOOT_SPIM_HEADER
+};
+
+#define NAND_BOOT_NAME		"BOOTLOADER!"
+#define NAND_BOOT_VERSION	"V006"
+#define NAND_BOOT_ID		"NFIINFO"
+
+#define HSM_NAND_BOOT_NAME	"NANDCFG!"
+#define SPIM_NAND_BOOT_NAME	"SPINAND!"
+
+/* Find nand header data by name */
+const struct nand_header_type *mtk_nand_header_find(const char *name);
+
+/* Device header size using this nand header */
+uint32_t mtk_nand_header_size(const struct nand_header_type *hdr_nand);
+
+/* Get nand info from nand header (page size, spare size, ...) */
+int mtk_nand_header_info(const void *ptr, struct nand_header_info *info);
+
+/* Whether given header data is valid */
+bool is_mtk_nand_header(const void *ptr);
+
+/* Generate Device header using give nand header */
+uint32_t mtk_nand_header_put(const struct nand_header_type *hdr_nand,
+			     void *ptr);
+
+#endif /* _MTK_NAND_HEADERS_H */