Merge branch '2018-11-28-master-imports'

- Add MediaTek support
diff --git a/MAINTAINERS b/MAINTAINERS
index abdb6dc..214629e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -158,6 +158,26 @@
 F:	arch/arm/cpu/pxa/
 F:	arch/arm/include/asm/arch-pxa/
 
+ARM MEDIATEK
+M:	Ryder Lee <ryder.lee@mediatek.com>
+M:	Weijie Gao <weijie.gao@mediatek.com>
+S:	Maintained
+F:	arch/arm/mach-mediatek/
+F:	arch/arm/include/asm/arch-mediatek/
+F:	board/mediatek/
+F:	doc/README.mediatek
+F:	drivers/clk/mediatek/
+F:	drivers/mmc/mtk-sd.c
+F:	drivers/pinctrl/mediatek/
+F:	drivers/power/domain/mtk-power-domain.c
+F:	drivers/ram/mediatek/
+F:	drivers/spi/mtk_qspi.c
+F:	drivers/timer/mtk_timer.c
+F:	drivers/watchdog/mtk_wdt.c
+F:	tools/mtk_image.c
+F:	tools/mtk_image.h
+N:	mediatek
+
 ARM OWL
 M:	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 S:	Maintained
diff --git a/Makefile b/Makefile
index aeb1c14..a4b1d1d 100644
--- a/Makefile
+++ b/Makefile
@@ -852,6 +852,8 @@
 ALL-$(CONFIG_OF_SEPARATE) += u-boot-dtb-tegra.bin
 endif
 
+ALL-$(CONFIG_ARCH_MEDIATEK) += u-boot-mtk.bin
+
 # Add optional build target if defined in board/cpu/soc headers
 ifneq ($(CONFIG_BUILD_TARGET),)
 ALL-y += $(CONFIG_BUILD_TARGET:"%"=%)
@@ -1361,6 +1363,26 @@
 	$(Q)$(OBJCOPY) -I binary $(PLATFORM_ELFFLAGS) $< u-boot-elf.o
 	$(call if_changed,u-boot-elf)
 
+# MediaTek's ARM-based u-boot needs a header to contains its load address
+# which is parsed by the BootROM.
+# If the SPL build is enabled, the header will be added to the spl binary,
+# and the spl binary and the u-boot.img will be combined into one file.
+# Otherwise the header will be added to the u-boot.bin directly.
+
+ifeq ($(CONFIG_SPL),y)
+spl/u-boot-spl-mtk.bin: spl/u-boot-spl
+
+u-boot-mtk.bin: u-boot.dtb u-boot.img spl/u-boot-spl-mtk.bin FORCE
+	$(call if_changed,binman)
+else
+MKIMAGEFLAGS_u-boot-mtk.bin = -T mtk_image \
+	-a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \
+	-n "$(patsubst "%",%,$(CONFIG_MTK_BROM_HEADER_INFO))"
+
+u-boot-mtk.bin: u-boot.bin FORCE
+	$(call if_changed,mkimage)
+endif
+
 ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(ARCH)/Makefile.postlink)
 
 # Rule to link u-boot
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f5d4d39..96eadb6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -664,6 +664,20 @@
 	  targeted at media players and tablet computers. We currently
 	  support the S905 (GXBaby) 64-bit SoC.
 
+config ARCH_MEDIATEK
+	bool "MediaTek SoCs"
+	select BINMAN
+	select DM
+	select OF_CONTROL
+	select SPL_DM if SPL
+	select SPL_LIBCOMMON_SUPPORT if SPL
+	select SPL_LIBGENERIC_SUPPORT if SPL
+	select SPL_OF_CONTROL if SPL
+	select SUPPORT_SPL
+	help
+	  Support for the MediaTek SoCs family developed by MediaTek Inc.
+	  Please refer to doc/README.mediatek for more information.
+
 config ARCH_LPC32XX
 	bool "NXP LPC32xx platform"
 	select CPU_ARM926EJS
@@ -1449,6 +1463,8 @@
 
 source "arch/arm/mach-meson/Kconfig"
 
+source "arch/arm/mach-mediatek/Kconfig"
+
 source "arch/arm/mach-qemu/Kconfig"
 
 source "arch/arm/mach-rockchip/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 4b6c5e1..c38ef3c 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -62,6 +62,7 @@
 machine-$(CONFIG_ARCH_KEYSTONE)		+= keystone
 # TODO: rename CONFIG_KIRKWOOD -> CONFIG_ARCH_KIRKWOOD
 machine-$(CONFIG_KIRKWOOD)		+= kirkwood
+machine-$(CONFIG_ARCH_MEDIATEK)		+= mediatek
 machine-$(CONFIG_ARCH_MESON)		+= meson
 machine-$(CONFIG_ARCH_MVEBU)		+= mvebu
 # TODO: rename CONFIG_TEGRA -> CONFIG_ARCH_TEGRA
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 55f3fd1..c9bf445 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -563,6 +563,10 @@
 
 dtb-$(CONFIG_SOC_K3_AM6) += k3-am654-base-board.dtb k3-am654-r5-base-board.dtb
 
+dtb-$(CONFIG_ARCH_MEDIATEK) += \
+	mt7623n-bananapi-bpi-r2.dtb \
+	mt7629-rfb.dtb
+
 targets += $(dtb-y)
 
 # Add any required device tree compiler flags here
diff --git a/arch/arm/dts/mt7623.dtsi b/arch/arm/dts/mt7623.dtsi
new file mode 100644
index 0000000..f50f4ef
--- /dev/null
+++ b/arch/arm/dts/mt7623.dtsi
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ */
+
+#include <dt-bindings/clock/mt7623-clk.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/power/mt7623-power.h>
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "mediatek,mt7623";
+	interrupt-parent = <&sysirq>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		enable-method = "mediatek,mt6589-smp";
+
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x0>;
+			clocks = <&infracfg CLK_INFRA_CPUSEL>,
+				 <&apmixedsys CLK_APMIXED_MAINPLL>;
+			clock-names = "cpu", "intermediate";
+			clock-frequency = <1300000000>;
+		};
+
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x1>;
+			clocks = <&infracfg CLK_INFRA_CPUSEL>,
+				 <&apmixedsys CLK_APMIXED_MAINPLL>;
+			clock-names = "cpu", "intermediate";
+			clock-frequency = <1300000000>;
+		};
+
+		cpu2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x2>;
+			clocks = <&infracfg CLK_INFRA_CPUSEL>,
+				 <&apmixedsys CLK_APMIXED_MAINPLL>;
+			clock-names = "cpu", "intermediate";
+			clock-frequency = <1300000000>;
+		};
+
+		cpu3: cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x3>;
+			clocks = <&infracfg CLK_INFRA_CPUSEL>,
+				 <&apmixedsys CLK_APMIXED_MAINPLL>;
+			clock-names = "cpu", "intermediate";
+			clock-frequency = <1300000000>;
+		};
+	};
+
+	system_clk: dummy13m {
+		compatible = "fixed-clock";
+		clock-frequency = <13000000>;
+		#clock-cells = <0>;
+	};
+
+	rtc32k: oscillator-1 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32000>;
+		clock-output-names = "rtc32k";
+	};
+
+	clk26m: oscillator-0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <26000000>;
+		clock-output-names = "clk26m";
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		clock-frequency = <13000000>;
+		arm,cpu-registers-not-fw-configured;
+	};
+
+	topckgen: clock-controller@10000000 {
+		compatible = "mediatek,mt7623-topckgen";
+		reg = <0x10000000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	infracfg: syscon@10001000 {
+		compatible = "mediatek,mt7623-infracfg", "syscon";
+		reg = <0x10001000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	pericfg: syscon@10003000 {
+		compatible = "mediatek,mt7623-pericfg", "syscon";
+		reg = <0x10003000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	pinctrl: pinctrl@10005000 {
+		compatible = "mediatek,mt7623-pinctrl";
+		reg = <0x10005000 0x1000>;
+
+		gpio: gpio-controller {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+	};
+
+	scpsys: scpsys@10006000 {
+		compatible = "mediatek,mt7623-scpsys";
+		#power-domain-cells = <1>;
+		reg = <0x10006000 0x1000>;
+		infracfg = <&infracfg>;
+		clocks = <&topckgen CLK_TOP_MM_SEL>,
+			 <&topckgen CLK_TOP_MFG_SEL>,
+			 <&topckgen CLK_TOP_ETHIF_SEL>;
+		clock-names = "mm", "mfg", "ethif";
+	};
+
+	watchdog: watchdog@10007000 {
+		compatible = "mediatek,wdt";
+		reg = <0x10007000 0x100>;
+	};
+
+	wdt-reboot {
+		compatible = "wdt-reboot";
+		wdt = <&watchdog>;
+	};
+
+	timer0: timer@10008000 {
+		compatible = "mediatek,timer";
+		reg = <0x10008000 0x80>;
+		interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&system_clk>;
+		clock-names = "system-clk";
+		u-boot,dm-pre-reloc;
+	};
+
+	sysirq: interrupt-controller@10200100 {
+		compatible = "mediatek,sysirq";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		reg = <0x10200100 0x1c>;
+	};
+
+	apmixedsys: clock-controller@10209000 {
+		compatible = "mediatek,mt7623-apmixedsys";
+		reg = <0x10209000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	gic: interrupt-controller@10211000 {
+		compatible = "arm,cortex-a7-gic";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		reg = <0x10211000 0x1000>,
+		      <0x10212000 0x1000>,
+		      <0x10214000 0x2000>,
+		      <0x10216000 0x2000>;
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11002000 0x400>;
+		reg-shift = <2>;
+		interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_UART_SEL>,
+			 <&pericfg CLK_PERI_UART0>;
+		clock-names = "baud", "bus";
+		status = "disabled";
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11003000 0x400>;
+		reg-shift = <2>;
+		interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_UART_SEL>,
+			 <&pericfg CLK_PERI_UART1>;
+		clock-names = "baud", "bus";
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11004000 0x400>;
+		reg-shift = <2>;
+		interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_UART_SEL>,
+			 <&pericfg CLK_PERI_UART2>;
+		clock-names = "baud", "bus";
+		status = "disabled";
+		u-boot,dm-pre-reloc;
+	};
+
+	uart3: serial@11005000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11005000 0x400>;
+		reg-shift = <2>;
+		interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_UART_SEL>,
+			 <&pericfg CLK_PERI_UART3>;
+		clock-names = "baud", "bus";
+		status = "disabled";
+	};
+
+	mmc0: mmc@11230000 {
+		compatible = "mediatek,mt7623-mmc";
+		reg = <0x11230000 0x1000>;
+		interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&pericfg CLK_PERI_MSDC30_0>,
+			 <&topckgen CLK_TOP_MSDC30_0_SEL>;
+		clock-names = "source", "hclk";
+		status = "disabled";
+	};
+
+	mmc1: mmc@11240000 {
+		compatible = "mediatek,mt7623-mmc";
+		reg = <0x11240000 0x1000>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&pericfg CLK_PERI_MSDC30_1>,
+			 <&topckgen CLK_TOP_MSDC30_1_SEL>;
+		clock-names = "source", "hclk";
+		status = "disabled";
+	};
+
+	ethsys: syscon@1b000000 {
+		compatible = "mediatek,mt7623-ethsys";
+		reg = <0x1b000000 0x1000>;
+		#clock-cells = <1>;
+	};
+};
diff --git a/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts
new file mode 100644
index 0000000..84a77fd
--- /dev/null
+++ b/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ */
+
+/dts-v1/;
+#include "mt7623.dtsi"
+
+/ {
+	model = "Bananapi BPI-R2";
+	compatible = "bananapi,bpi-r2", "mediatek,mt7623";
+
+	chosen {
+		stdout-path = &uart2;
+		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;
+	};
+
+	reg_5v: regulator-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-5V";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		blue {
+			label = "bpi-r2:pio:blue";
+			gpios = <&gpio 241 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+
+		green {
+			label = "bpi-r2:pio:green";
+			gpios = <&gpio 240 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+
+		red {
+			label = "bpi-r2:pio:red";
+			gpios = <&gpio 239 GPIO_ACTIVE_HIGH>;
+			default-state = "off";
+		};
+	};
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_default>;
+	status = "okay";
+	bus-width = <8>;
+	max-frequency = <50000000>;
+	cap-mmc-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	non-removable;
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_default>;
+	status = "okay";
+	bus-width = <4>;
+	max-frequency = <50000000>;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio 261 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+};
+
+&pinctrl {
+	ephy_default: ephy_default {
+		mux {
+			function = "eth";
+			groups = "mdc_mdio", "ephy";
+		};
+
+		conf {
+			pins = "G2_TXEN", "G2_TXD0", "G2_TXD1", "G2_TXD2",
+			       "G2_TXD3", "G2_TXC", "G2_RXC", "G2_RXD0",
+			       "G2_RXD1", "G2_RXD2", "G2_RXD3", "G2_RXDV",
+			       "MDC", "MDIO";
+			drive-strength = <12>;
+			mediatek,tdsel = <5>;
+		};
+	};
+
+	mmc0_pins_default: mmc0default {
+		mux {
+			function = "msdc";
+			groups =  "msdc0";
+		};
+
+		conf-cmd-data {
+			pins = "MSDC0_CMD", "MSDC0_DAT0", "MSDC0_DAT1",
+			       "MSDC0_DAT2", "MSDC0_DAT3", "MSDC0_DAT4",
+			       "MSDC0_DAT5", "MSDC0_DAT6", "MSDC0_DAT7";
+			input-enable;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "MSDC0_CLK";
+			bias-pull-down;
+		};
+
+		conf-rst {
+			pins = "MSDC0_RSTB";
+			bias-pull-up;
+		};
+	};
+
+	mmc1_pins_default: mmc1default {
+		mux {
+			function = "msdc";
+			groups =  "msdc1", "msdc1_wp_0";
+		};
+
+		conf-cmd-data {
+			pins = "MSDC1_DAT0", "MSDC1_DAT1", "MSDC1_DAT2",
+			       "MSDC1_DAT3", "MSDC1_DAT3", "MSDC1_CMD";
+			input-enable;
+			drive-strength = <4>;
+			bias-pull-up;
+		};
+
+		conf-clk {
+			pins = "MSDC1_CLK";
+			drive-strength = <4>;
+		};
+
+		conf-wp {
+			pins = "EINT7";
+			input-enable;
+			bias-pull-up;
+		};
+	};
+
+	uart0_pins_a: uart0-default {
+		mux {
+			function = "uart";
+			groups =  "uart0_0_txd_rxd";
+		};
+	};
+
+	uart1_pins_a: uart1-default {
+		mux {
+			function = "uart";
+			groups =  "uart1_0_txd_rxd";
+		};
+	};
+
+	uart2_pins_a: uart2-default {
+		mux {
+			function = "uart";
+			groups =  "uart2_0_txd_rxd";
+		};
+	};
+
+	uart2_pins_b: uart2-alt {
+		mux {
+			function = "uart";
+			groups =  "uart2_1_txd_rxd";
+		};
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_a>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins_a>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2_pins_a>;
+	status = "okay";
+};
diff --git a/arch/arm/dts/mt7629-rfb-u-boot.dtsi b/arch/arm/dts/mt7629-rfb-u-boot.dtsi
new file mode 100644
index 0000000..1ef5568
--- /dev/null
+++ b/arch/arm/dts/mt7629-rfb-u-boot.dtsi
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <config.h>
+/ {
+	binman {
+		filename = "u-boot-mtk.bin";
+		pad-byte = <0xff>;
+
+#ifdef CONFIG_SPL
+		blob {
+			filename = "spl/u-boot-spl-mtk.bin";
+			size = <CONFIG_SPL_PAD_TO>;
+		};
+
+		u-boot-img {
+		};
+#endif
+	};
+};
diff --git a/arch/arm/dts/mt7629-rfb.dts b/arch/arm/dts/mt7629-rfb.dts
new file mode 100644
index 0000000..a6d28a0
--- /dev/null
+++ b/arch/arm/dts/mt7629-rfb.dts
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ */
+
+/dts-v1/;
+#include "mt7629.dtsi"
+
+/ {
+	model = "MediaTek MT7629 RFB";
+	compatible = "mediatek,mt7629-rfb", "mediatek,mt7629";
+
+	aliases {
+		spi0 = &qspi;
+	};
+
+	chosen {
+		stdout-path = &uart0;
+		tick-timer = &timer0;
+	};
+};
+
+&pinctrl {
+	qspi_pins: qspi-pins {
+		mux {
+			function = "flash";
+			groups = "spi_nor";
+		};
+	};
+
+	uart0_pins: uart0-default {
+		mux {
+			function = "uart";
+			groups = "uart0_txd_rxd";
+		};
+	};
+
+	watchdog_pins: watchdog-default {
+		mux {
+			function = "watchdog";
+			groups = "watchdog";
+		};
+	};
+};
+
+&qspi {
+	pinctrl-names = "default";
+	pinctrl-0 = <&qspi_pins>;
+	status = "okay";
+
+	spi-flash@0{
+		compatible = "spi-flash";
+		reg = <0>;
+		u-boot,dm-pre-reloc;
+	};
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins>;
+	status = "okay";
+};
+
+&watchdog {
+	pinctrl-names = "default";
+	pinctrl-0 = <&watchdog_pins>;
+	status = "okay";
+};
diff --git a/arch/arm/dts/mt7629.dtsi b/arch/arm/dts/mt7629.dtsi
new file mode 100644
index 0000000..e6052bb
--- /dev/null
+++ b/arch/arm/dts/mt7629.dtsi
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ */
+
+#include <dt-bindings/clock/mt7629-clk.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/power/mt7629-power.h>
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "mediatek,mt7629";
+	interrupt-parent = <&sysirq>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		enable-method = "mediatek,mt6589-smp";
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x0>;
+			clock-frequency = <1250000000>;
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0x1>;
+			clock-frequency = <1250000000>;
+		};
+	};
+
+	clk20m: oscillator@0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <20000000>;
+		clock-output-names = "clk20m";
+	};
+
+	clk40m: oscillator@1 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+		clock-output-names = "clkxtal";
+	};
+
+	timer {
+		compatible = "arm,armv7-timer";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
+			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+		clock-frequency = <20000000>;
+		arm,cpu-registers-not-fw-configured;
+	};
+
+	infracfg: syscon@10000000 {
+		compatible = "mediatek,mt7629-infracfg", "syscon";
+		reg = <0x10000000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	pericfg: syscon@10002000 {
+		compatible = "mediatek,mt7629-pericfg", "syscon";
+		reg = <0x10002000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	timer0: timer@10004000 {
+		compatible = "mediatek,timer";
+		reg = <0x10004000 0x80>;
+		interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_10M_SEL>,
+			 <&topckgen CLK_TOP_CLKXTAL_D4>;
+		clock-names = "mux", "src";
+		u-boot,dm-pre-reloc;
+	};
+
+	scpsys: scpsys@10006000 {
+		compatible = "mediatek,mt7629-scpsys";
+		reg = <0x10006000 0x1000>;
+		clocks = <&topckgen CLK_TOP_HIF_SEL>;
+		clock-names = "hif_sel";
+		assigned-clocks = <&topckgen CLK_TOP_HIF_SEL>;
+		assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>;
+		#power-domain-cells = <1>;
+		infracfg = <&infracfg>;
+	};
+
+	mcucfg: syscon@10200000 {
+		compatible = "mediatek,mt7629-mcucfg", "syscon";
+		reg = <0x10200000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	sysirq: interrupt-controller@10200a80 {
+		compatible = "mediatek,sysirq";
+		reg = <0x10200a80 0x20>;
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+	};
+
+	dramc: dramc@10203000 {
+		compatible = "mediatek,mt7629-dramc";
+		reg = <0x10203000 0x600>,	/* EMI */
+		      <0x10213000 0x1000>,	/* DDRPHY */
+		      <0x10214000 0xd00>;	/* DRAMC_AO */
+		clocks = <&topckgen CLK_TOP_DDRPHYCFG_SEL>,
+			 <&topckgen CLK_TOP_SYSPLL1_D8>,
+			 <&topckgen CLK_TOP_MEM_SEL>,
+			 <&topckgen CLK_TOP_DMPLL>;
+		clock-names = "phy", "phy_mux", "mem", "mem_mux";
+		u-boot,dm-pre-reloc;
+	};
+
+	apmixedsys: clock-controller@10209000 {
+		compatible = "mediatek,mt7629-apmixedsys";
+		reg = <0x10209000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	topckgen: clock-controller@10210000 {
+		compatible = "mediatek,mt7629-topckgen";
+		reg = <0x10210000 0x1000>;
+		#clock-cells = <1>;
+		u-boot,dm-pre-reloc;
+	};
+
+	watchdog: watchdog@10212000 {
+		compatible = "mediatek,wdt";
+		reg = <0x10212000 0x600>;
+		interrupts = <GIC_SPI 128 IRQ_TYPE_EDGE_FALLING>;
+		#reset-cells = <1>;
+		status = "disabled";
+	};
+
+	wdt-reboot {
+		compatible = "wdt-reboot";
+		wdt = <&watchdog>;
+	};
+
+	pinctrl: pinctrl@10217000 {
+		compatible = "mediatek,mt7629-pinctrl";
+		reg = <0x10217000 0x8000>;
+
+		gpio: gpio-controller {
+			gpio-controller;
+			#gpio-cells = <2>;
+		};
+	};
+
+	gic: interrupt-controller@10300000 {
+		compatible = "arm,gic-400";
+		interrupt-controller;
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		reg = <0x10310000 0x1000>,
+		      <0x10320000 0x1000>,
+		      <0x10340000 0x2000>,
+		      <0x10360000 0x2000>;
+	};
+
+	uart0: serial@11002000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11002000 0x400>;
+		reg-shift = <2>;
+		interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_UART_SEL>,
+			 <&pericfg CLK_PERI_UART0_PD>;
+		clock-names = "baud", "bus";
+		status = "disabled";
+		assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>;
+		assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>;
+		u-boot,dm-pre-reloc;
+	};
+
+	uart1: serial@11003000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11003000 0x400>;
+		reg-shift = <2>;
+		interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_UART_SEL>,
+			 <&pericfg CLK_PERI_UART1_PD>;
+		clock-names = "baud", "bus";
+		assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>;
+		assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>;
+		status = "disabled";
+	};
+
+	uart2: serial@11004000 {
+		compatible = "mediatek,hsuart";
+		reg = <0x11004000 0x400>;
+		reg-shift = <2>;
+		interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
+		clocks = <&topckgen CLK_TOP_UART_SEL>,
+			 <&pericfg CLK_PERI_UART2_PD>;
+		clock-names = "baud", "bus";
+		assigned-clocks = <&topckgen CLK_TOP_AXI_SEL>;
+		assigned-clock-parents = <&topckgen CLK_TOP_SYSPLL1_D2>;
+		status = "disabled";
+	};
+
+	qspi: qspi@11014000 {
+		compatible = "mediatek,mt7629-qspi";
+		reg = <0x11014000 0xe0>, <0x30000000 0x10000000>;
+		reg-names = "reg_base", "mem_base";
+		status = "disabled";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		u-boot,dm-pre-reloc;
+	};
+
+	ethsys: syscon@1b000000 {
+		compatible = "mediatek,mt7629-ethsys", "syscon";
+		reg = <0x1b000000 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys0: syscon@1b128000 {
+		compatible = "mediatek,mt7629-sgmiisys", "syscon";
+		reg = <0x1b128000 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@1b130000 {
+		compatible = "mediatek,mt7629-sgmiisys", "syscon";
+		reg = <0x1b130000 0x1000>;
+		#clock-cells = <1>;
+	};
+};
diff --git a/arch/arm/include/asm/arch-mediatek/gpio.h b/arch/arm/include/asm/arch-mediatek/gpio.h
new file mode 100644
index 0000000..4ea1020
--- /dev/null
+++ b/arch/arm/include/asm/arch-mediatek/gpio.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef __MEDIATEK_GPIO_H
+#define __MEDIATEK_GPIO_H
+
+#endif	/* __MEDIATEK_GPIO_H */
diff --git a/arch/arm/include/asm/arch-mediatek/misc.h b/arch/arm/include/asm/arch-mediatek/misc.h
new file mode 100644
index 0000000..2530e78
--- /dev/null
+++ b/arch/arm/include/asm/arch-mediatek/misc.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef __MEDIATEK_MISC_H_
+#define __MEDIATEK_MISC_H_
+
+#define VER_BASE		0x08000000
+#define VER_SIZE		0x10
+
+#define APHW_CODE		0x00
+#define APHW_SUBCODE		0x04
+#define APHW_VER		0x08
+#define APSW_VER		0x0c
+
+#endif /* __MEDIATEK_MISC_H_ */
diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
new file mode 100644
index 0000000..7a733e9
--- /dev/null
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -0,0 +1,39 @@
+if ARCH_MEDIATEK
+
+config SYS_SOC
+	default "mediatek"
+
+config SYS_VENDOR
+	default "mediatek"
+
+choice
+	prompt "MediaTek board select"
+
+config TARGET_MT7623
+	bool "MediaTek MT7623 SoC"
+	select CPU_V7A
+	select ARCH_MISC_INIT
+	help
+	  The MediaTek MT7623 is a ARM-based SoC with a quad-core Cortex-A7
+	  including NEON and GPU, Mali-450 graphics, several DDR3 options,
+	  crypto engine, built-in Wi-Fi / Bluetooth combo chip, JPEG decoder,
+	  video interfaces supporting HDMI and MIPI, and video codec support.
+	  Peripherals include Gigabit Ethernet, switch, USB3.0 and OTG, PCIe,
+	  I2S, PCM, S/PDIF, UART, SPI, I2C, IR TX/RX, and PWM.
+
+config TARGET_MT7629
+	bool "MediaTek MT7629 SoC"
+	select CPU_V7A
+	select SPL
+	select ARCH_MISC_INIT
+	help
+	  The MediaTek MT7629 is a ARM-based SoC with a dual-core Cortex-A7
+	  including DDR3, crypto engine, 3x3 11n/ac Wi-Fi, Gigabit Ethernet,
+	  switch, USB3.0, PCIe, UART, SPI, I2C and PWM.
+
+endchoice
+
+source "board/mediatek/mt7623/Kconfig"
+source "board/mediatek/mt7629/Kconfig"
+
+endif
diff --git a/arch/arm/mach-mediatek/Makefile b/arch/arm/mach-mediatek/Makefile
new file mode 100644
index 0000000..b5d3a37
--- /dev/null
+++ b/arch/arm/mach-mediatek/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier:	GPL-2.0
+
+obj-y	+= cpu.o
+obj-$(CONFIG_SPL_BUILD)	+= spl.o
+
+obj-$(CONFIG_TARGET_MT7623) += mt7623/
+obj-$(CONFIG_TARGET_MT7629) += mt7629/
diff --git a/arch/arm/mach-mediatek/cpu.c b/arch/arm/mach-mediatek/cpu.c
new file mode 100644
index 0000000..b37e299
--- /dev/null
+++ b/arch/arm/mach-mediatek/cpu.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <wdt.h>
+#include <dm/uclass-internal.h>
+
+int arch_misc_init(void)
+{
+	struct udevice *wdt;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_WDT, &wdt);
+	if (!ret)
+		wdt_stop(wdt);
+
+	return 0;
+}
+
+int arch_cpu_init(void)
+{
+	icache_enable();
+
+	return 0;
+}
+
+void enable_caches(void)
+{
+	/* Enable D-cache. I-cache is already enabled in start.S */
+	dcache_enable();
+}
diff --git a/arch/arm/mach-mediatek/init.h b/arch/arm/mach-mediatek/init.h
new file mode 100644
index 0000000..1d896fb
--- /dev/null
+++ b/arch/arm/mach-mediatek/init.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef __MEDIATEK_INIT_H_
+#define __MEDIATEK_INIT_H_
+
+extern int mtk_soc_early_init(void);
+
+#endif /* __MEDIATEK_INIT_H_ */
diff --git a/arch/arm/mach-mediatek/mt7623/Makefile b/arch/arm/mach-mediatek/mt7623/Makefile
new file mode 100644
index 0000000..007eb4a
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7623/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/mt7623/init.c b/arch/arm/mach-mediatek/mt7623/init.c
new file mode 100644
index 0000000..0ee8c66
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7623/init.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <asm/arch/misc.h>
+
+#include "preloader.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct boot_argument *preloader_param;
+
+int mtk_soc_early_init(void)
+{
+	return 0;
+}
+
+int dram_init(void)
+{
+	u32 i;
+
+	if (((size_t)preloader_param >= CONFIG_SYS_SDRAM_BASE) &&
+	    ((size_t)preloader_param % sizeof(size_t) == 0) &&
+	    preloader_param->magic == BOOT_ARGUMENT_MAGIC &&
+	    preloader_param->dram_rank_num <=
+	    ARRAY_SIZE(preloader_param->dram_rank_size)) {
+		gd->ram_size = 0;
+
+		for (i = 0; i < preloader_param->dram_rank_num; i++)
+			gd->ram_size += preloader_param->dram_rank_size[i];
+	} else {
+		gd->ram_size = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE,
+					    SZ_2G);
+	}
+
+	return 0;
+}
+
+int print_cpuinfo(void)
+{
+	void __iomem *chipid;
+	u32 swver;
+
+	chipid = ioremap(VER_BASE, VER_SIZE);
+	swver = readl(chipid + APSW_VER);
+
+	printf("CPU:   MediaTek MT7623 E%d\n", (swver & 0xf) + 1);
+
+	return 0;
+}
diff --git a/arch/arm/mach-mediatek/mt7623/lowlevel_init.S b/arch/arm/mach-mediatek/mt7623/lowlevel_init.S
new file mode 100644
index 0000000..afb9476
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7623/lowlevel_init.S
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#include <linux/linkage.h>
+
+.extern	preloader_param
+
+ENTRY(save_boot_params)
+	ldr	r6, =preloader_param
+	str	r4, [r6]
+	b	save_boot_params_ret
+ENDPROC(save_boot_params)
+
+ENTRY(lowlevel_init)
+	/* enable SMP bit */
+	mrc	p15, 0, r0, c1, c0, 1
+	orr	r0, r0, #0x40
+	mcr	p15, 0, r0, c1, c0, 1
+	mov	pc, lr
+ENDPROC(lowlevel_init)
diff --git a/arch/arm/mach-mediatek/mt7623/preloader.h b/arch/arm/mach-mediatek/mt7623/preloader.h
new file mode 100644
index 0000000..2d2c71a
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7623/preloader.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef __PRELOADER_H_
+#define __PRELOADER_H_
+
+enum forbidden_mode {
+	F_FACTORY_MODE = 0x0001
+};
+
+union lk_hdr {
+	struct {
+		u32 magic;
+		u32 size;
+		char name[32];
+		u32 loadaddr;
+	};
+
+	u8 data[512];
+};
+
+struct sec_limit {
+	unsigned int magic_num;
+	enum forbidden_mode forbid_mode;
+};
+
+enum bootmode {
+	NORMAL_BOOT = 0,
+	META_BOOT = 1,
+	RECOVERY_BOOT = 2,
+	SW_REBOOT = 3,
+	FACTORY_BOOT = 4,
+	ADVMETA_BOOT = 5,
+	ATE_FACTORY_BOOT = 6,
+	ALARM_BOOT = 7,
+
+	KERNEL_POWER_OFF_CHARGING_BOOT = 8,
+	LOW_POWER_OFF_CHARGING_BOOT = 9,
+
+	FAST_BOOT = 99,
+	DOWNLOAD_BOOT = 100,
+	UNKNOWN_BOOT
+};
+
+enum boot_reason {
+	BR_POWER_KEY = 0,
+	BR_USB,
+	BR_RTC,
+	BR_WDT,
+	BR_WDT_BY_PASS_PWK,
+	BR_TOOL_BY_PASS_PWK,
+	BR_2SEC_REBOOT,
+	BR_UNKNOWN
+};
+
+enum meta_com_type {
+	META_UNKNOWN_COM = 0,
+	META_UART_COM,
+	META_USB_COM
+};
+
+struct da_info_t {
+	u32 addr;
+	u32 arg1;
+	u32 arg2;
+	u32 len;
+	u32 sig_len;
+};
+
+struct boot_argument {
+	u32 magic;
+	enum bootmode boot_mode;
+	u32 e_flag;
+	u32 log_port;
+	u32 log_baudrate;
+	u8 log_enable;
+	u8 part_num;
+	u8 reserved[2];
+	u32 dram_rank_num;
+	u32 dram_rank_size[4];
+	u32 boot_reason;
+	enum meta_com_type meta_com_type;
+	u32 meta_com_id;
+	u32 boot_time;
+	struct da_info_t da_info;
+	struct sec_limit sec_limit;
+	union lk_hdr *part_info;
+	u8 md_type[4];
+	u32 ddr_reserve_enable;
+	u32 ddr_reserve_success;
+	u32 chip_ver;
+	char pl_version[8];
+};
+
+#define BOOT_ARGUMENT_MAGIC	0x504c504c
+
+#endif /* __PRELOADER_H_ */
diff --git a/arch/arm/mach-mediatek/mt7629/Makefile b/arch/arm/mach-mediatek/mt7629/Makefile
new file mode 100644
index 0000000..007eb4a
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7629/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/mt7629/init.c b/arch/arm/mach-mediatek/mt7629/init.c
new file mode 100644
index 0000000..ba91a6e
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7629/init.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <ram.h>
+#include <asm/arch/misc.h>
+#include <asm/sections.h>
+#include <dm/uclass.h>
+#include <linux/io.h>
+
+#include <dt-bindings/clock/mt7629-clk.h>
+
+#define L2_CFG_BASE		0x10200000
+#define L2_CFG_SIZE		0x1000
+#define L2_SHARE_CFG_MP0	0x7f0
+#define L2_SHARE_MODE_OFF	BIT(8)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int mtk_pll_early_init(void)
+{
+	unsigned long pll_rates[] = {
+		[CLK_APMIXED_ARMPLL] = 1250000000,
+		[CLK_APMIXED_MAINPLL] = 1120000000,
+		[CLK_APMIXED_UNIV2PLL] = 1200000000,
+		[CLK_APMIXED_ETH1PLL] = 500000000,
+		[CLK_APMIXED_ETH2PLL] = 700000000,
+		[CLK_APMIXED_SGMIPLL] = 650000000,
+	};
+	struct udevice *dev;
+	int ret, i;
+
+	ret = uclass_get_device_by_driver(UCLASS_CLK,
+			DM_GET_DRIVER(mtk_clk_apmixedsys), &dev);
+	if (ret)
+		return ret;
+
+	/* configure default rate then enable apmixedsys */
+	for (i = 0; i < ARRAY_SIZE(pll_rates); i++) {
+		struct clk clk = { .id = i, .dev = dev };
+
+		ret = clk_set_rate(&clk, pll_rates[i]);
+		if (ret)
+			return ret;
+
+		ret = clk_enable(&clk);
+		if (ret)
+			return ret;
+	}
+
+	/* setup mcu bus */
+	ret = uclass_get_device_by_driver(UCLASS_SYSCON,
+			DM_GET_DRIVER(mtk_mcucfg), &dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int mtk_soc_early_init(void)
+{
+	struct udevice *dev;
+	int ret;
+
+	/* initialize early clocks */
+	ret = mtk_pll_early_init();
+	if (ret)
+		return ret;
+
+	ret = uclass_first_device_err(UCLASS_RAM, &dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int mach_cpu_init(void)
+{
+	void __iomem *base;
+
+	base = ioremap(L2_CFG_BASE, L2_CFG_SIZE);
+
+	/* disable L2C shared mode */
+	writel(L2_SHARE_MODE_OFF, base + L2_SHARE_CFG_MP0);
+
+	return 0;
+}
+
+int dram_init(void)
+{
+	struct ram_info ram;
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_RAM, &dev);
+	if (ret)
+		return ret;
+
+	ret = ram_get_info(dev, &ram);
+	if (ret)
+		return ret;
+
+	debug("RAM init base=%lx, size=%x\n", ram.base, ram.size);
+
+	gd->ram_size = ram.size;
+
+	return 0;
+}
+
+int print_cpuinfo(void)
+{
+	void __iomem *chipid;
+	u32 hwcode, swver;
+
+	chipid = ioremap(VER_BASE, VER_SIZE);
+	hwcode = readl(chipid + APHW_CODE);
+	swver = readl(chipid + APSW_VER);
+
+	printf("CPU:   MediaTek MT%04x E%d\n", hwcode, (swver & 0xf) + 1);
+
+	return 0;
+}
diff --git a/arch/arm/mach-mediatek/mt7629/lowlevel_init.S b/arch/arm/mach-mediatek/mt7629/lowlevel_init.S
new file mode 100644
index 0000000..90dd4ea
--- /dev/null
+++ b/arch/arm/mach-mediatek/mt7629/lowlevel_init.S
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#include <linux/linkage.h>
+
+ENTRY(lowlevel_init)
+
+#ifndef CONFIG_SPL_BUILD
+	/* Return to U-Boot via saved link register */
+	mov	pc, lr
+#else
+	/*
+	 * Arch timer :
+	 * set CNTFRQ = 20Mhz, set CNTVOFF = 0
+	 */
+	movw	r0, #0x2d00
+	movt	r0, #0x131
+	mcr	p15, 0, r0, c14, c0, 0
+
+	/* enable SMP bit */
+	mrc	p15, 0, r0, c1, c0, 1
+	orr	r0, r0, #0x40
+	mcr	p15, 0, r0, c1, c0, 1
+
+	/* if MP core, handle secondary cores */
+	mrc	p15, 0, r0, c0, c0, 5
+	ands	r1, r0, #0x40000000
+	bne	go			@ Go if UP
+	ands	r0, r0, #0x0f
+	beq	go			@ Go if core0 on primary core tile
+	b	secondary
+
+go:
+	/* master CPU */
+	mov	pc, lr
+
+secondary:
+	/* read slave CPU number into r0 firstly */
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #0x0f
+
+loop:
+	dsb
+	isb
+	wfi				@Zzz...
+	b	loop
+#endif
+ENDPROC(lowlevel_init)
diff --git a/arch/arm/mach-mediatek/spl.c b/arch/arm/mach-mediatek/spl.c
new file mode 100644
index 0000000..9b3590f
--- /dev/null
+++ b/arch/arm/mach-mediatek/spl.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <spl.h>
+
+#include "init.h"
+
+void board_init_f(ulong dummy)
+{
+	int ret;
+
+	ret = spl_early_init();
+	if (ret)
+		hang();
+
+	/* enable console uart printing */
+	preloader_console_init();
+
+	/* soc early initialization */
+	ret = mtk_soc_early_init();
+	if (ret)
+		hang();
+}
+
+u32 spl_boot_device(void)
+{
+#if defined(CONFIG_SPL_SPI_SUPPORT)
+	return BOOT_DEVICE_SPI;
+#elif defined(CONFIG_SPL_MMC_SUPPORT)
+	return BOOT_DEVICE_MMC1;
+#elif defined(CONFIG_SPL_NAND_SUPPORT)
+	return BOOT_DEVICE_NAND;
+#elif defined(CONFIG_SPL_NOR_SUPPORT)
+	return BOOT_DEVICE_NOR;
+#else
+	return BOOT_DEVICE_NONE;
+#endif
+}
diff --git a/board/mediatek/mt7623/Kconfig b/board/mediatek/mt7623/Kconfig
new file mode 100644
index 0000000..a8c670e
--- /dev/null
+++ b/board/mediatek/mt7623/Kconfig
@@ -0,0 +1,13 @@
+if TARGET_MT7623
+
+config SYS_BOARD
+	default "mt7623"
+
+config SYS_CONFIG_NAME
+	default "mt7623"
+
+config MTK_BROM_HEADER_INFO
+	string
+	default "lk=1"
+
+endif
diff --git a/board/mediatek/mt7623/MAINTAINERS b/board/mediatek/mt7623/MAINTAINERS
new file mode 100644
index 0000000..eeb0375
--- /dev/null
+++ b/board/mediatek/mt7623/MAINTAINERS
@@ -0,0 +1,7 @@
+MT7623
+M:	Ryder Lee <ryder.lee@mediatek.com>
+M:	Weijie Gao <weijie.gao@mediatek.com>
+S:	Maintained
+F:	board/mediatek/mt7623
+F:	include/configs/mt7623.h
+F:	configs/mt7623n_bpir2_defconfig
diff --git a/board/mediatek/mt7623/Makefile b/board/mediatek/mt7623/Makefile
new file mode 100644
index 0000000..2b42071
--- /dev/null
+++ b/board/mediatek/mt7623/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier:	GPL-2.0
+
+obj-y += mt7623_rfb.o
diff --git a/board/mediatek/mt7623/mt7623_rfb.c b/board/mediatek/mt7623/mt7623_rfb.c
new file mode 100644
index 0000000..08468b5
--- /dev/null
+++ b/board/mediatek/mt7623/mt7623_rfb.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int board_init(void)
+{
+	/* address of boot parameters */
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	return 0;
+}
diff --git a/board/mediatek/mt7629/Kconfig b/board/mediatek/mt7629/Kconfig
new file mode 100644
index 0000000..6055164
--- /dev/null
+++ b/board/mediatek/mt7629/Kconfig
@@ -0,0 +1,17 @@
+if TARGET_MT7629
+
+config SYS_BOARD
+	default "mt7629"
+
+config SYS_CONFIG_NAME
+	default "mt7629"
+
+config MTK_SPL_PAD_SIZE
+	hex
+	default 0x10000
+
+config MTK_BROM_HEADER_INFO
+	string
+	default "media=nor"
+
+endif
diff --git a/board/mediatek/mt7629/MAINTAINERS b/board/mediatek/mt7629/MAINTAINERS
new file mode 100644
index 0000000..424f115
--- /dev/null
+++ b/board/mediatek/mt7629/MAINTAINERS
@@ -0,0 +1,7 @@
+MT7629
+M:	Ryder Lee <ryder.lee@mediatek.com>
+M:	Weijie Gao <weijie.gao@mediatek.com>
+S:	Maintained
+F:	board/mediatek/mt7629
+F:	include/configs/mt7629.h
+F:	configs/mt7629_rfb_defconfig
diff --git a/board/mediatek/mt7629/Makefile b/board/mediatek/mt7629/Makefile
new file mode 100644
index 0000000..83ccbba
--- /dev/null
+++ b/board/mediatek/mt7629/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier:	GPL-2.0
+
+obj-y += mt7629_rfb.o
diff --git a/board/mediatek/mt7629/mt7629_rfb.c b/board/mediatek/mt7629/mt7629_rfb.c
new file mode 100644
index 0000000..08468b5
--- /dev/null
+++ b/board/mediatek/mt7629/mt7629_rfb.c
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int board_init(void)
+{
+	/* address of boot parameters */
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	return 0;
+}
diff --git a/common/image.c b/common/image.c
index 1c3a772..0659133 100644
--- a/common/image.c
+++ b/common/image.c
@@ -166,6 +166,7 @@
 	{	IH_TYPE_FIRMWARE_IVT, "firmware_ivt", "Firmware with HABv4 IVT" },
 	{       IH_TYPE_PMMC,        "pmmc",        "TI Power Management Micro-Controller Firmware",},
 	{	IH_TYPE_STM32IMAGE, "stm32image", "STMicroelectronics STM32 Image" },
+	{	IH_TYPE_MTKIMAGE,   "mtk_image",   "MediaTek BootROM loadable Image" },
 	{	-1,		    "",		  "",			},
 };
 
diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig
new file mode 100644
index 0000000..3a4de72
--- /dev/null
+++ b/configs/mt7623n_bpir2_defconfig
@@ -0,0 +1,54 @@
+CONFIG_ARM=y
+CONFIG_SYS_THUMB_BUILD=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_SYS_TEXT_BASE=0x81e00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_TARGET_MT7623=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_BOOTDELAY=3
+CONFIG_SYS_CONSOLE_IS_IN_ENV=y
+CONFIG_DEFAULT_FDT_FILE="mt7623n-bananapi-bpi-r2"
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_PROMPT="U-Boot> "
+CONFIG_CMD_BOOTMENU=y
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_READ=y
+# CONFIG_CMD_SETEXPR is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_CMD_PING=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_OF_EMBED=y
+CONFIG_DEFAULT_DEVICE_TREE="mt7623n-bananapi-bpi-r2"
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+# CONFIG_BLOCK_CACHE is not set
+CONFIG_CLK=y
+CONFIG_DM_GPIO=y
+CONFIG_DM_MMC=y
+# CONFIG_MMC_QUIRKS is not set
+CONFIG_MMC_HS400_SUPPORT=y
+CONFIG_MMC_MTK=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT7623=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_MTK_POWER_DOMAIN=y
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_SYSRESET=y
+CONFIG_SYSRESET_WATCHDOG=y
+CONFIG_TIMER=y
+CONFIG_MTK_TIMER=y
+CONFIG_WDT_MTK=y
+CONFIG_LZMA=y
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig
new file mode 100644
index 0000000..1729d13
--- /dev/null
+++ b/configs/mt7629_rfb_defconfig
@@ -0,0 +1,73 @@
+CONFIG_ARM=y
+CONFIG_SYS_THUMB_BUILD=y
+CONFIG_ARCH_MEDIATEK=y
+CONFIG_SYS_TEXT_BASE=0x41e00000
+CONFIG_SYS_MALLOC_F_LEN=0x4000
+CONFIG_TARGET_MT7629=y
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_BOOTDELAY=3
+CONFIG_SYS_CONSOLE_IS_IN_ENV=y
+CONFIG_DEFAULT_FDT_FILE="mt7629-rfb"
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_SPL_SYS_MALLOC_SIMPLE=y
+CONFIG_SPL_NOR_SUPPORT=y
+CONFIG_SPL_WATCHDOG_SUPPORT=y
+CONFIG_HUSH_PARSER=y
+CONFIG_SYS_PROMPT="U-Boot> "
+CONFIG_CMD_BOOTMENU=y
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SF_TEST=y
+# CONFIG_CMD_SETEXPR is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_CMD_PING=y
+# CONFIG_PARTITIONS is not set
+CONFIG_OF_EMBED=y
+CONFIG_DEFAULT_DEVICE_TREE="mt7629-rfb"
+CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-parents"
+CONFIG_SPL_DM_SEQ_ALIAS=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_DM_GPIO=y
+# CONFIG_MMC is not set
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=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_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_MT7629=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_MTK_POWER_DOMAIN=y
+CONFIG_RAM=y
+CONFIG_SPL_RAM=y
+CONFIG_DM_SERIAL=y
+CONFIG_MTK_SERIAL=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_MTK_QSPI=y
+CONFIG_SYSRESET=y
+CONFIG_SYSRESET_WATCHDOG=y
+CONFIG_TIMER=y
+CONFIG_SPL_TIMER=y
+CONFIG_MTK_TIMER=y
+CONFIG_WDT_MTK=y
+CONFIG_LZMA=y
+# CONFIG_EFI_LOADER is not set
diff --git a/doc/README.mediatek b/doc/README.mediatek
new file mode 100644
index 0000000..246579d
--- /dev/null
+++ b/doc/README.mediatek
@@ -0,0 +1,221 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2018 MediaTek Inc.
+# Ryder Lee <ryder.lee@kernel.org>
+
+
+This document describes how to compile the U-Boot and how to change U-Boot
+configuration about the MediaTek SoCs.
+
+
+Build Procedure
+===============
+	-Set the cross compiler:
+
+		# export CROSS_COMPILE=/path/to/toolchain/arm-linux-gnueabi-
+
+	-Clean-up old residuals:
+
+		# make mrproper
+
+	-Configure the U-Boot:
+
+		# make <defconfig_file>
+		# make
+
+		- For the MT7623n bananapi R2 board use "mt7623n_bpir2_defconfig"
+		- For the MT7629 reference board use "mt7629_rfb_defconfig"
+
+
+Boot sequence
+=============
+	-Bootrom -> MTK preloader -> U-Boot
+
+		- MT7623n
+
+	This version of U-Boot doesn't implement SPL. So, MTK preloader binary
+	is needed to boot up:
+
+	https://github.com/BPI-SINOVOIP/BPI-R2-bsp/tree/master/mt-pack/mtk/bpi-r2/bin
+
+
+	-Bootrom -> SPL -> U-Boot
+
+		- MT7629
+
+
+Configuration update
+====================
+	To update the U-Boot configuration, please refer to doc/README.kconfig
+
+
+MediaTek image header
+=====================
+Currently there are two image headers used for MediaTek chips:
+
+	- BootROM image header. This header is used by the first stage bootloader. It records
+	  the desired compatible boot device, integrity information and its load address.
+
+	  The on-chip BootROM will firstly verify integrity and compatibility of the bootloader.
+
+	  If verification passed, the BootROM will then load the bootloader into on-chip SRAM,
+	  and pass control to it.
+
+	  Note that this header is actually a combination of three independent headers:
+	  Device header, BRLYT header and GFH header.
+
+	  Used by U-Boot SPL of MT7629 and preloader of MT7623.
+
+
+	- MediaTek legacy image header. This header was originally used by the legacy image. It
+	  basically records the load address, image size and image name.
+
+	  After all low level initializations passed, the preloader will locate the LK image and
+	  load it into DRAM, and pass control to it.
+
+	  Now this header is used by U-Boot of MT7623.
+
+
+To generate these two headers with mkimage:
+
+	# mkimage -T mtk_image -a <load_addr> -n <option_string> -d <input_file> <image_file>
+
+	- mtk_image means using MediaTek's header generation method.
+
+
+	- load_addr is the load address of this image.
+	  For first stage bootloader like U-Boot SPL or preloader, it usually points to the
+	  on-chip SRAM.
+
+	  For second stage bootloader like U-Boot, it usually points to the DRAM.
+
+
+	- option_string contains options to generate the header.
+
+	  The option string is using the follow format:
+		key1=value1;key2=value2;...
+
+	  The following key names are valid:
+		lk: If lk=1, LK image header is used. Otherwise BootROM image header is used.
+
+		lkname: The name of the LK image header. The maximum length is 32.
+			The default value is "U-Boot".
+
+		media: Desired boot device. The valid values are:
+		nand : Parallel NAND
+		snand: Serial NAND
+		nor  : Serial NOR
+		emmc : eMMC
+		sdmmc: SD
+
+	   nandinfo: Desired NAND device type, a combination of page size, oob size and
+		     optional device capacity. Valid types are:
+		2k+64    : for Serial NAND, 2KiB page size + 64B oob size
+		2k+120   : for Serial NAND, 2KiB page size + 120B oob size
+		2k+128   : for Serial NAND, 2KiB page size + 128B oob size
+		4k+256   : for Serial NAND, 4KiB page size + 256B oob size
+		1g:2k+64 : for Parallel NAND, 2KiB page size + 64B oob size, total 1Gbit size
+		2g:2k+64 : for Parallel NAND, 2KiB page size + 64B oob size, total 2Gbit size
+		4g:2k+64 : for Parallel NAND, 2KiB page size + 64B oob size, total 4Gbit size
+		2g:2k+128: for Parallel NAND, 2KiB page size + 128B oob size, total 2Gbit size
+		4g:2k+128: for Parallel NAND, 2KiB page size + 128B oob size, total 4Gbit size
+
+
+MT7629 partitions on Serial NOR
+===============================
+
+	Start      End       Size       Description
+	00000000 - 0000ffff: 64KiB      U-Boot SPL
+	00010000 - 0005ffff: 320KiB     U-Boot
+	00060000 - 0006ffff: 64KiB      U-Boot env / MediaTek NVRAM
+	00070000 - 000affff: 256KiB     RF calibration data
+	000b0000 - xxxxxxxx: all left   Firmware image
+
+
+BPi-R2 (MT7623N) partitions on SD
+=================================
+	Please note that the last two partitions can vary from different Linux distributions
+	depending on the MBR partition table.
+
+	Start      End       Size       Description
+	00000000 - 000001ff: 512B       Device header (with MBR partition table)
+	00000200 - 000007ff: 1536B      BRLYT header
+	00000800 - 0004ffff: 318KiB     Preloader (with GFH header)
+	00050000 - 000fffff: 704KiB     U-Boot
+	00100000 - 063fffff: 99MiB      Reserved
+	06400000 - 163fffff: 256MiB     Partition 1 (FAT32)
+	16400000 - xxxxxxxx: all left   Partition 2 (ext4)
+
+
+Upgrading notice on Serial NOR
+==============================
+Example: MT7629
+
+	The command sf is used to operate the Serial NOR device:
+
+	- To probe current NOR flash:
+
+		# sf probe
+
+	- To erase a region:
+
+		# sf erase <offset> <len>
+
+	- To write data to an offset:
+
+		# sf write <data_addr> <offset> <len>
+
+	- To boot kernel:
+
+		# bootm 0x300b0000
+
+	The memory address range 0x30000000 - 0x3fffffff is mapped to the NOR flash.
+	The DRAM starts at 0x40000000.
+
+	Please note that the output binary u-boot-mtk.bin is a combination of SPL and U-Boot,
+	and it should be write to beginning of the flash.
+
+	Otherwise you should use standalone files:
+
+		spl/u-boot-spl-mtk.bin for SPL,
+		u-boot.img for U-Boot.
+
+
+Upgrading notice on SD / eMMC
+=============================
+Example: MT7623
+
+	Normally only Preloader and U-Boot can be upgraded within U-Boot, and other partitions
+	should be written in PC.
+
+	- To probe current SD card / eMMC:
+
+		# mmc dev 0 for eMMC
+		# mmc dev 1 for SD
+
+	- To erase a region:
+
+		# mmc erase <blk_offset> <blk_num>
+
+	- To write data to a block offset:
+
+		# mmc write <data_addr> <blk_offset> <blk_num>
+
+	- To load kernel image from partition 1:
+
+		# fatload mmc 0:1 <load_address> <path_to_kernel_uImage> for eMMC
+		# fatload mmc 1:1 <load_address> <path_to_kernel_uImage> for SD
+
+	- To boot kernel:
+
+		# bootm <load_address>
+
+	The DRAM starts at 0x80000000.
+
+	Please note that we use block offset and block count for SD card, not the byte offset.
+	The block size is always 512 bytes for SD card.
+
+
+Documentation
+=============
+	http://wiki.banana-pi.org/Banana_Pi_BPI-R2
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 821b586..c128538 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -10,6 +10,7 @@
 obj-y += tegra/
 obj-$(CONFIG_ARCH_ASPEED) += aspeed/
 obj-$(CONFIG_ARCH_MESON) += clk_meson.o
+obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_ARCH_SOCFPGA) += altera/
 obj-$(CONFIG_CLK_AT91) += at91/
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
new file mode 100644
index 0000000..0632dc8
--- /dev/null
+++ b/drivers/clk/mediatek/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+# Core
+obj-$(CONFIG_ARCH_MEDIATEK) += clk-mtk.o
+
+# SoC Drivers
+obj-$(CONFIG_TARGET_MT7623) += clk-mt7623.o
+obj-$(CONFIG_TARGET_MT7629) += clk-mt7629.o
diff --git a/drivers/clk/mediatek/clk-mt7623.c b/drivers/clk/mediatek/clk-mt7623.c
new file mode 100644
index 0000000..c6b09d8
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7623.c
@@ -0,0 +1,870 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek clock driver for MT7623 SoC
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <dt-bindings/clock/mt7623-clk.h>
+
+#include "clk-mtk.h"
+
+#define MT7623_CLKSQ_STB_CON0		0x18
+#define MT7623_PLL_ISO_CON0		0x24
+#define MT7623_PLL_FMAX			(2000UL * MHZ)
+#define MT7623_CON0_RST_BAR		BIT(27)
+
+#define MCU_AXI_DIV			0x60
+#define AXI_DIV_MSK			GENMASK(4, 0)
+#define AXI_DIV_SEL(x)			(x)
+
+/* apmixedsys */
+#define PLL(_id, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg,	\
+	    _pd_shift, _pcw_reg, _pcw_shift) {				\
+		.id = _id,						\
+		.reg = _reg,						\
+		.pwr_reg = _pwr_reg,					\
+		.en_mask = _en_mask,					\
+		.rst_bar_mask = MT7623_CON0_RST_BAR,			\
+		.fmax = MT7623_PLL_FMAX,				\
+		.flags = _flags,					\
+		.pcwbits = _pcwbits,					\
+		.pd_reg = _pd_reg,					\
+		.pd_shift = _pd_shift,					\
+		.pcw_reg = _pcw_reg,					\
+		.pcw_shift = _pcw_shift,				\
+	}
+
+static const struct mtk_pll_data apmixed_plls[] = {
+	PLL(CLK_APMIXED_ARMPLL, 0x200, 0x20c, 0x80000001, 0,
+	    21, 0x204, 24, 0x204, 0),
+	PLL(CLK_APMIXED_MAINPLL, 0x210, 0x21c, 0xf0000001, HAVE_RST_BAR,
+	    21, 0x210, 4, 0x214, 0),
+	PLL(CLK_APMIXED_UNIVPLL, 0x220, 0x22c, 0xf3000001, HAVE_RST_BAR,
+	    7, 0x220, 4, 0x224, 14),
+	PLL(CLK_APMIXED_MMPLL, 0x230, 0x23c, 0x00000001, 0,
+	    21, 0x230, 4, 0x234, 0),
+	PLL(CLK_APMIXED_MSDCPLL, 0x240, 0x24c, 0x00000001, 0,
+	    21, 0x240, 4, 0x244, 0),
+	PLL(CLK_APMIXED_TVDPLL, 0x250, 0x25c, 0x00000001, 0,
+	    21, 0x250, 4, 0x254, 0),
+	PLL(CLK_APMIXED_AUD1PLL, 0x270, 0x27c, 0x00000001, 0,
+	    31, 0x270, 4, 0x274, 0),
+	PLL(CLK_APMIXED_TRGPLL, 0x280, 0x28c, 0x00000001, 0,
+	    31, 0x280, 4, 0x284, 0),
+	PLL(CLK_APMIXED_ETHPLL, 0x290, 0x29c, 0x00000001, 0,
+	    31, 0x290, 4, 0x294, 0),
+	PLL(CLK_APMIXED_VDECPLL, 0x2a0, 0x2ac, 0x00000001, 0,
+	    31, 0x2a0, 4, 0x2a4, 0),
+	PLL(CLK_APMIXED_HADDS2PLL, 0x2b0, 0x2bc, 0x00000001, 0,
+	    31, 0x2b0, 4, 0x2b4, 0),
+	PLL(CLK_APMIXED_AUD2PLL, 0x2c0, 0x2cc, 0x00000001, 0,
+	    31, 0x2c0, 4, 0x2c4, 0),
+	PLL(CLK_APMIXED_TVD2PLL, 0x2d0, 0x2dc, 0x00000001, 0,
+	    21, 0x2d0, 4, 0x2d4, 0),
+};
+
+/* topckgen */
+#define FACTOR0(_id, _parent, _mult, _div)			\
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_APMIXED)
+
+#define FACTOR1(_id, _parent, _mult, _div)			\
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_TOPCKGEN)
+
+#define FACTOR2(_id, _parent, _mult, _div)			\
+	FACTOR(_id, _parent, _mult, _div, 0)
+
+static const struct mtk_fixed_clk top_fixed_clks[] = {
+	FIXED_CLK(CLK_TOP_DPI, CLK_XTAL, 108 * MHZ),
+	FIXED_CLK(CLK_TOP_DMPLL, CLK_XTAL, 400 * MHZ),
+	FIXED_CLK(CLK_TOP_VENCPLL, CLK_XTAL, 295.75 * MHZ),
+	FIXED_CLK(CLK_TOP_HDMI_0_PIX340M, CLK_XTAL, 340 * MHZ),
+	FIXED_CLK(CLK_TOP_HDMI_0_DEEP340M, CLK_XTAL, 340 * MHZ),
+	FIXED_CLK(CLK_TOP_HDMI_0_PLL340M, CLK_XTAL, 340 * MHZ),
+	FIXED_CLK(CLK_TOP_HADDS2_FB, CLK_XTAL, 27 * MHZ),
+	FIXED_CLK(CLK_TOP_WBG_DIG_416M, CLK_XTAL, 416 * MHZ),
+	FIXED_CLK(CLK_TOP_DSI0_LNTC_DSI, CLK_XTAL, 143 * MHZ),
+	FIXED_CLK(CLK_TOP_HDMI_SCL_RX, CLK_XTAL, 27 * MHZ),
+	FIXED_CLK(CLK_TOP_32K_EXTERNAL, CLK_XTAL, 32000),
+	FIXED_CLK(CLK_TOP_HDMITX_CLKDIG_CTS, CLK_XTAL, 300 * MHZ),
+	FIXED_CLK(CLK_TOP_AUD_EXT1, CLK_XTAL, 0),
+	FIXED_CLK(CLK_TOP_AUD_EXT2, CLK_XTAL, 0),
+	FIXED_CLK(CLK_TOP_NFI1X_PAD, CLK_XTAL, 0),
+};
+
+static const struct mtk_fixed_factor top_fixed_divs[] = {
+	FACTOR0(CLK_TOP_SYSPLL, CLK_APMIXED_MAINPLL, 1, 1),
+	FACTOR0(CLK_TOP_SYSPLL_D2, CLK_APMIXED_MAINPLL, 1, 2),
+	FACTOR0(CLK_TOP_SYSPLL_D3, CLK_APMIXED_MAINPLL, 1, 3),
+	FACTOR0(CLK_TOP_SYSPLL_D5, CLK_APMIXED_MAINPLL, 1, 5),
+	FACTOR0(CLK_TOP_SYSPLL_D7, CLK_APMIXED_MAINPLL, 1, 7),
+	FACTOR1(CLK_TOP_SYSPLL1_D2, CLK_TOP_SYSPLL_D2, 1, 2),
+	FACTOR1(CLK_TOP_SYSPLL1_D4, CLK_TOP_SYSPLL_D2, 1, 4),
+	FACTOR1(CLK_TOP_SYSPLL1_D8, CLK_TOP_SYSPLL_D2, 1, 8),
+	FACTOR1(CLK_TOP_SYSPLL1_D16, CLK_TOP_SYSPLL_D2, 1, 16),
+	FACTOR1(CLK_TOP_SYSPLL2_D2, CLK_TOP_SYSPLL_D3, 1, 2),
+	FACTOR1(CLK_TOP_SYSPLL2_D4, CLK_TOP_SYSPLL_D3, 1, 4),
+	FACTOR1(CLK_TOP_SYSPLL2_D8, CLK_TOP_SYSPLL_D3, 1, 8),
+	FACTOR1(CLK_TOP_SYSPLL3_D2, CLK_TOP_SYSPLL_D5, 1, 2),
+	FACTOR1(CLK_TOP_SYSPLL3_D4, CLK_TOP_SYSPLL_D5, 1, 4),
+	FACTOR1(CLK_TOP_SYSPLL4_D2, CLK_TOP_SYSPLL_D7, 1, 2),
+	FACTOR1(CLK_TOP_SYSPLL4_D4, CLK_TOP_SYSPLL_D7, 1, 4),
+
+	FACTOR0(CLK_TOP_UNIVPLL, CLK_APMIXED_UNIVPLL, 1, 1),
+	FACTOR0(CLK_TOP_UNIVPLL_D2, CLK_APMIXED_UNIVPLL, 1, 2),
+	FACTOR0(CLK_TOP_UNIVPLL_D3, CLK_APMIXED_UNIVPLL, 1, 3),
+	FACTOR0(CLK_TOP_UNIVPLL_D5, CLK_APMIXED_UNIVPLL, 1, 5),
+	FACTOR0(CLK_TOP_UNIVPLL_D7, CLK_APMIXED_UNIVPLL, 1, 7),
+	FACTOR0(CLK_TOP_UNIVPLL_D26, CLK_APMIXED_UNIVPLL, 1, 26),
+	FACTOR0(CLK_TOP_UNIVPLL_D52, CLK_APMIXED_UNIVPLL, 1, 52),
+	FACTOR0(CLK_TOP_UNIVPLL_D108, CLK_APMIXED_UNIVPLL, 1, 108),
+	FACTOR0(CLK_TOP_USB_PHY48M, CLK_APMIXED_UNIVPLL, 1, 26),
+	FACTOR1(CLK_TOP_UNIVPLL1_D2, CLK_TOP_UNIVPLL_D2, 1, 2),
+	FACTOR1(CLK_TOP_UNIVPLL1_D4, CLK_TOP_UNIVPLL_D2, 1, 4),
+	FACTOR1(CLK_TOP_UNIVPLL1_D8, CLK_TOP_UNIVPLL_D2, 1, 8),
+	FACTOR1(CLK_TOP_UNIVPLL2_D2, CLK_TOP_UNIVPLL_D3, 1, 2),
+	FACTOR1(CLK_TOP_UNIVPLL2_D4, CLK_TOP_UNIVPLL_D3, 1, 4),
+	FACTOR1(CLK_TOP_UNIVPLL2_D8, CLK_TOP_UNIVPLL_D3, 1, 8),
+	FACTOR1(CLK_TOP_UNIVPLL2_D16, CLK_TOP_UNIVPLL_D3, 1, 16),
+	FACTOR1(CLK_TOP_UNIVPLL2_D32, CLK_TOP_UNIVPLL_D3, 1, 32),
+	FACTOR1(CLK_TOP_UNIVPLL3_D2, CLK_TOP_UNIVPLL_D5, 1, 2),
+	FACTOR1(CLK_TOP_UNIVPLL3_D4, CLK_TOP_UNIVPLL_D5, 1, 4),
+	FACTOR1(CLK_TOP_UNIVPLL3_D8, CLK_TOP_UNIVPLL_D5, 1, 8),
+
+	FACTOR0(CLK_TOP_MSDCPLL, CLK_APMIXED_MSDCPLL, 1, 1),
+	FACTOR0(CLK_TOP_MSDCPLL_D2, CLK_APMIXED_MSDCPLL, 1, 2),
+	FACTOR0(CLK_TOP_MSDCPLL_D4, CLK_APMIXED_MSDCPLL, 1, 4),
+	FACTOR0(CLK_TOP_MSDCPLL_D8, CLK_APMIXED_MSDCPLL, 1, 8),
+
+	FACTOR0(CLK_TOP_MMPLL, CLK_APMIXED_MMPLL, 1, 1),
+	FACTOR0(CLK_TOP_MMPLL_D2, CLK_APMIXED_MMPLL, 1, 2),
+
+	FACTOR1(CLK_TOP_DMPLL_D2, CLK_TOP_DMPLL, 1, 2),
+	FACTOR1(CLK_TOP_DMPLL_D4, CLK_TOP_DMPLL, 1, 4),
+	FACTOR1(CLK_TOP_DMPLL_X2, CLK_TOP_DMPLL, 1, 1),
+
+	FACTOR0(CLK_TOP_TVDPLL, CLK_APMIXED_TVDPLL, 1, 1),
+	FACTOR0(CLK_TOP_TVDPLL_D2, CLK_APMIXED_TVDPLL, 1, 2),
+	FACTOR0(CLK_TOP_TVDPLL_D4, CLK_APMIXED_TVDPLL, 1, 4),
+
+	FACTOR0(CLK_TOP_VDECPLL, CLK_APMIXED_VDECPLL, 1, 1),
+	FACTOR0(CLK_TOP_TVD2PLL, CLK_APMIXED_TVD2PLL, 1, 1),
+	FACTOR0(CLK_TOP_TVD2PLL_D2, CLK_APMIXED_TVD2PLL, 1, 2),
+
+	FACTOR1(CLK_TOP_MIPIPLL, CLK_TOP_DPI, 1, 1),
+	FACTOR1(CLK_TOP_MIPIPLL_D2, CLK_TOP_DPI, 1, 2),
+	FACTOR1(CLK_TOP_MIPIPLL_D4, CLK_TOP_DPI, 1, 4),
+
+	FACTOR1(CLK_TOP_HDMIPLL, CLK_TOP_HDMITX_CLKDIG_CTS, 1, 1),
+	FACTOR1(CLK_TOP_HDMIPLL_D2, CLK_TOP_HDMITX_CLKDIG_CTS, 1, 2),
+	FACTOR1(CLK_TOP_HDMIPLL_D3, CLK_TOP_HDMITX_CLKDIG_CTS, 1, 3),
+
+	FACTOR0(CLK_TOP_ARMPLL_1P3G, CLK_APMIXED_ARMPLL, 1, 1),
+
+	FACTOR1(CLK_TOP_AUDPLL, CLK_TOP_AUDPLL_MUX_SEL, 1, 1),
+	FACTOR1(CLK_TOP_AUDPLL_D4, CLK_TOP_AUDPLL_MUX_SEL, 1, 4),
+	FACTOR1(CLK_TOP_AUDPLL_D8, CLK_TOP_AUDPLL_MUX_SEL, 1, 8),
+	FACTOR1(CLK_TOP_AUDPLL_D16, CLK_TOP_AUDPLL_MUX_SEL, 1, 16),
+	FACTOR1(CLK_TOP_AUDPLL_D24, CLK_TOP_AUDPLL_MUX_SEL, 1, 24),
+
+	FACTOR0(CLK_TOP_AUD1PLL_98M, CLK_APMIXED_AUD1PLL, 1, 3),
+	FACTOR0(CLK_TOP_AUD2PLL_90M, CLK_APMIXED_AUD2PLL, 1, 3),
+	FACTOR0(CLK_TOP_HADDS2PLL_98M, CLK_APMIXED_HADDS2PLL, 1, 3),
+	FACTOR0(CLK_TOP_HADDS2PLL_294M, CLK_APMIXED_HADDS2PLL, 1, 1),
+	FACTOR0(CLK_TOP_ETHPLL_500M, CLK_APMIXED_ETHPLL, 1, 1),
+	FACTOR2(CLK_TOP_CLK26M_D8, CLK_XTAL, 1, 8),
+	FACTOR2(CLK_TOP_32K_INTERNAL, CLK_XTAL, 1, 793),
+	FACTOR1(CLK_TOP_AXISEL_D4, CLK_TOP_AXI_SEL, 1, 4),
+	FACTOR1(CLK_TOP_8BDAC, CLK_TOP_UNIVPLL_D2, 1, 1),
+};
+
+static const int axi_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_SYSPLL_D5,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_MMPLL_D2,
+	CLK_TOP_DMPLL_D2
+};
+
+static const int mem_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_DMPLL
+};
+
+static const int ddrphycfg_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D8
+};
+
+static const int mm_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_VENCPLL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_UNIVPLL1_D2,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_DMPLL
+};
+
+static const int pwm_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_UNIVPLL3_D2,
+	CLK_TOP_UNIVPLL1_D4
+};
+
+static const int vdec_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_VDECPLL,
+	CLK_TOP_SYSPLL_D5,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_VENCPLL,
+	CLK_TOP_MSDCPLL_D2,
+	CLK_TOP_MMPLL_D2
+};
+
+static const int mfg_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_MMPLL,
+	CLK_TOP_DMPLL_X2,
+	CLK_TOP_MSDCPLL,
+	CLK_XTAL,
+	CLK_TOP_SYSPLL_D3,
+	CLK_TOP_UNIVPLL_D3,
+	CLK_TOP_UNIVPLL1_D2
+};
+
+static const int camtg_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL_D26,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_SYSPLL3_D2,
+	CLK_TOP_SYSPLL3_D4,
+	CLK_TOP_MSDCPLL_D2,
+	CLK_TOP_MMPLL_D2
+};
+
+static const int uart_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D8
+};
+
+static const int spi_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL3_D2,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_UNIVPLL1_D8
+};
+
+static const int usb20_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL1_D8,
+	CLK_TOP_UNIVPLL3_D4
+};
+
+static const int msdc30_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_MSDCPLL_D2,
+	CLK_TOP_SYSPLL2_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL1_D4,
+	CLK_TOP_UNIVPLL2_D4,
+};
+
+static const int aud_intbus_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_SYSPLL3_D2,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_UNIVPLL3_D2,
+	CLK_TOP_UNIVPLL2_D4
+};
+
+static const int pmicspi_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D8,
+	CLK_TOP_SYSPLL2_D4,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_SYSPLL3_D4,
+	CLK_TOP_SYSPLL2_D8,
+	CLK_TOP_SYSPLL1_D16,
+	CLK_TOP_UNIVPLL3_D4,
+	CLK_TOP_UNIVPLL_D26,
+	CLK_TOP_DMPLL_D2,
+	CLK_TOP_DMPLL_D4
+};
+
+static const int scp_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D8,
+	CLK_TOP_DMPLL_D2,
+	CLK_TOP_DMPLL_D4
+};
+
+static const int dpi0_tve_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_MIPIPLL,
+	CLK_TOP_MIPIPLL_D2,
+	CLK_TOP_MIPIPLL_D4,
+	CLK_XTAL,
+	CLK_TOP_TVDPLL,
+	CLK_TOP_TVDPLL_D2,
+	CLK_TOP_TVDPLL_D4
+};
+
+static const int dpi1_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_TVDPLL,
+	CLK_TOP_TVDPLL_D2,
+	CLK_TOP_TVDPLL_D4
+};
+
+static const int hdmi_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_HDMIPLL,
+	CLK_TOP_HDMIPLL_D2,
+	CLK_TOP_HDMIPLL_D3
+};
+
+static const int apll_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_AUDPLL,
+	CLK_TOP_AUDPLL_D4,
+	CLK_TOP_AUDPLL_D8,
+	CLK_TOP_AUDPLL_D16,
+	CLK_TOP_AUDPLL_D24,
+	CLK_XTAL,
+	CLK_XTAL
+};
+
+static const int rtc_parents[] = {
+	CLK_TOP_32K_INTERNAL,
+	CLK_TOP_32K_EXTERNAL,
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL3_D8
+};
+
+static const int nfi2x_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL2_D2,
+	CLK_TOP_SYSPLL_D7,
+	CLK_TOP_UNIVPLL3_D2,
+	CLK_TOP_SYSPLL2_D4,
+	CLK_TOP_UNIVPLL3_D4,
+	CLK_TOP_SYSPLL4_D4,
+	CLK_XTAL
+};
+
+static const int emmc_hclk_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_SYSPLL2_D2
+};
+
+static const int flash_parents[] = {
+	CLK_TOP_CLK26M_D8,
+	CLK_XTAL,
+	CLK_TOP_SYSPLL2_D8,
+	CLK_TOP_SYSPLL3_D4,
+	CLK_TOP_UNIVPLL3_D4,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_SYSPLL2_D4,
+	CLK_TOP_UNIVPLL2_D4
+};
+
+static const int di_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_TVD2PLL,
+	CLK_TOP_TVD2PLL_D2,
+	CLK_XTAL
+};
+
+static const int nr_osd_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_VENCPLL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_UNIVPLL1_D2,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_DMPLL
+};
+
+static const int hdmirx_bist_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL_D3,
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D16,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_VENCPLL,
+	CLK_XTAL
+};
+
+static const int intdir_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_MMPLL,
+	CLK_TOP_SYSPLL_D2,
+	CLK_TOP_UNIVPLL_D2
+};
+
+static const int asm_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_SYSPLL_D5
+};
+
+static const int ms_card_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL3_D8,
+	CLK_TOP_SYSPLL4_D4
+};
+
+static const int ethif_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_SYSPLL_D5,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_UNIVPLL1_D2,
+	CLK_TOP_DMPLL,
+	CLK_TOP_DMPLL_D2
+};
+
+static const int hdmirx_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL_D52
+};
+
+static const int cmsys_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_UNIVPLL1_D2,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_SYSPLL_D5,
+	CLK_TOP_SYSPLL2_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_SYSPLL3_D2,
+	CLK_TOP_SYSPLL2_D4,
+	CLK_TOP_SYSPLL1_D8,
+	CLK_XTAL,
+	CLK_XTAL,
+	CLK_XTAL,
+	CLK_XTAL,
+	CLK_XTAL
+};
+
+static const int clk_8bdac_parents[] = {
+	CLK_TOP_32K_INTERNAL,
+	CLK_TOP_8BDAC,
+	CLK_XTAL,
+	CLK_XTAL
+};
+
+static const int aud2dvd_parents[] = {
+	CLK_TOP_AUD_48K_TIMING,
+	CLK_TOP_AUD_44K_TIMING
+};
+
+static const int padmclk_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL_D26,
+	CLK_TOP_UNIVPLL_D52,
+	CLK_TOP_UNIVPLL_D108,
+	CLK_TOP_UNIVPLL2_D8,
+	CLK_TOP_UNIVPLL2_D16,
+	CLK_TOP_UNIVPLL2_D32
+};
+
+static const int aud_mux_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_AUD1PLL_98M,
+	CLK_TOP_AUD2PLL_90M,
+	CLK_TOP_HADDS2PLL_98M,
+	CLK_TOP_AUD_EXTCK1_DIV,
+	CLK_TOP_AUD_EXTCK2_DIV
+};
+
+static const int aud_src_parents[] = {
+	CLK_TOP_AUD_MUX1_SEL,
+	CLK_TOP_AUD_MUX2_SEL
+};
+
+static const struct mtk_composite top_muxes[] = {
+	MUX_GATE(CLK_TOP_AXI_SEL, axi_parents, 0x40, 0, 3, 7),
+	MUX_GATE(CLK_TOP_MEM_SEL, mem_parents, 0x40, 8, 1, 15),
+	MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, ddrphycfg_parents, 0x40, 16, 1, 23),
+	MUX_GATE_FLAGS(CLK_TOP_MM_SEL, mm_parents, 0x40, 24, 3, 31,
+		       CLK_DOMAIN_SCPSYS),
+
+	MUX_GATE(CLK_TOP_PWM_SEL, pwm_parents, 0x50, 0, 2, 7),
+	MUX_GATE(CLK_TOP_VDEC_SEL, vdec_parents, 0x50, 8, 4, 15),
+	MUX_GATE_FLAGS(CLK_TOP_MFG_SEL, mfg_parents, 0x50, 16, 3, 23,
+		       CLK_DOMAIN_SCPSYS),
+	MUX_GATE(CLK_TOP_CAMTG_SEL, camtg_parents, 0x50, 24, 3, 31),
+
+	MUX_GATE(CLK_TOP_UART_SEL, uart_parents, 0x60, 0, 1, 7),
+	MUX_GATE(CLK_TOP_SPI0_SEL, spi_parents, 0x60, 8, 3, 15),
+	MUX_GATE(CLK_TOP_USB20_SEL, usb20_parents, 0x60, 16, 2, 23),
+	MUX_GATE(CLK_TOP_MSDC30_0_SEL, msdc30_parents, 0x60, 24, 3, 31),
+
+	MUX_GATE(CLK_TOP_MSDC30_1_SEL, msdc30_parents, 0x70, 0, 3, 7),
+	MUX_GATE(CLK_TOP_MSDC30_2_SEL, msdc30_parents, 0x70, 8, 3, 15),
+	MUX_GATE(CLK_TOP_AUDIO_SEL, msdc30_parents, 0x70, 16, 1, 23),
+	MUX_GATE(CLK_TOP_AUDINTBUS_SEL, aud_intbus_parents, 0x70, 24, 3, 31),
+
+	MUX_GATE(CLK_TOP_PMICSPI_SEL, pmicspi_parents, 0x80, 0, 4, 7),
+	MUX_GATE(CLK_TOP_SCP_SEL, scp_parents, 0x80, 8, 2, 15),
+	MUX_GATE(CLK_TOP_DPI0_SEL, dpi0_tve_parents, 0x80, 16, 3, 23),
+	MUX_GATE(CLK_TOP_DPI1_SEL, dpi1_parents, 0x80, 24, 2, 31),
+
+	MUX_GATE(CLK_TOP_TVE_SEL, dpi0_tve_parents, 0x90, 0, 3, 7),
+	MUX_GATE(CLK_TOP_HDMI_SEL, hdmi_parents, 0x90, 8, 2, 15),
+	MUX_GATE(CLK_TOP_APLL_SEL, apll_parents, 0x90, 16, 3, 23),
+
+	MUX_GATE(CLK_TOP_RTC_SEL, rtc_parents, 0xA0, 0, 2, 7),
+	MUX_GATE(CLK_TOP_NFI2X_SEL, nfi2x_parents, 0xA0, 8, 3, 15),
+	MUX_GATE(CLK_TOP_EMMC_HCLK_SEL, emmc_hclk_parents, 0xA0, 24, 2, 31),
+
+	MUX_GATE(CLK_TOP_FLASH_SEL, flash_parents, 0xB0, 0, 3, 7),
+	MUX_GATE(CLK_TOP_DI_SEL, di_parents, 0xB0, 8, 2, 15),
+	MUX_GATE(CLK_TOP_NR_SEL, nr_osd_parents, 0xB0, 16, 3, 23),
+	MUX_GATE(CLK_TOP_OSD_SEL, nr_osd_parents, 0xB0, 24, 3, 31),
+
+	MUX_GATE(CLK_TOP_HDMIRX_BIST_SEL, hdmirx_bist_parents, 0xC0, 0, 3, 7),
+	MUX_GATE(CLK_TOP_INTDIR_SEL, intdir_parents, 0xC0, 8, 2, 15),
+	MUX_GATE(CLK_TOP_ASM_I_SEL, asm_parents, 0xC0, 16, 2, 23),
+	MUX_GATE(CLK_TOP_ASM_M_SEL, asm_parents, 0xC0, 24, 3, 31),
+
+	MUX_GATE(CLK_TOP_ASM_H_SEL, asm_parents, 0xD0, 0, 2, 7),
+	MUX_GATE(CLK_TOP_MS_CARD_SEL, ms_card_parents, 0xD0, 16, 2, 23),
+	MUX_GATE_FLAGS(CLK_TOP_ETHIF_SEL, ethif_parents, 0xD0, 24, 3, 31,
+		       CLK_DOMAIN_SCPSYS),
+
+	MUX_GATE(CLK_TOP_HDMIRX26_24_SEL, hdmirx_parents, 0xE0, 0, 1, 7),
+	MUX_GATE(CLK_TOP_MSDC30_3_SEL, msdc30_parents, 0xE0, 8, 3, 15),
+	MUX_GATE(CLK_TOP_CMSYS_SEL, cmsys_parents, 0xE0, 16, 4, 23),
+
+	MUX_GATE(CLK_TOP_SPI1_SEL, spi_parents, 0xE0, 24, 3, 31),
+	MUX_GATE(CLK_TOP_SPI2_SEL, spi_parents, 0xF0, 0, 3, 7),
+	MUX_GATE(CLK_TOP_8BDAC_SEL, clk_8bdac_parents, 0xF0, 8, 2, 15),
+	MUX_GATE(CLK_TOP_AUD2DVD_SEL, aud2dvd_parents, 0xF0, 16, 1, 23),
+
+	MUX(CLK_TOP_PADMCLK_SEL, padmclk_parents, 0x100, 0, 3),
+
+	MUX(CLK_TOP_AUD_MUX1_SEL, aud_mux_parents, 0x12c, 0, 3),
+	MUX(CLK_TOP_AUD_MUX2_SEL, aud_mux_parents, 0x12c, 3, 3),
+	MUX(CLK_TOP_AUDPLL_MUX_SEL, aud_mux_parents, 0x12c, 6, 3),
+
+	MUX_GATE(CLK_TOP_AUD_K1_SRC_SEL, aud_src_parents, 0x12c, 15, 1, 23),
+	MUX_GATE(CLK_TOP_AUD_K2_SRC_SEL, aud_src_parents, 0x12c, 16, 1, 24),
+	MUX_GATE(CLK_TOP_AUD_K3_SRC_SEL, aud_src_parents, 0x12c, 17, 1, 25),
+	MUX_GATE(CLK_TOP_AUD_K4_SRC_SEL, aud_src_parents, 0x12c, 18, 1, 26),
+	MUX_GATE(CLK_TOP_AUD_K5_SRC_SEL, aud_src_parents, 0x12c, 19, 1, 27),
+	MUX_GATE(CLK_TOP_AUD_K6_SRC_SEL, aud_src_parents, 0x12c, 20, 1, 28),
+};
+
+/* infracfg */
+static const struct mtk_gate_regs infra_cg_regs = {
+	.set_ofs = 0x40,
+	.clr_ofs = 0x44,
+	.sta_ofs = 0x48,
+};
+
+#define GATE_INFRA(_id, _parent, _shift) {			\
+		.id = _id,					\
+		.parent = _parent,				\
+		.regs = &infra_cg_regs,				\
+		.shift = _shift,				\
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN,	\
+	}
+
+static const struct mtk_gate infra_cgs[] = {
+	GATE_INFRA(CLK_INFRA_DBG, CLK_TOP_AXI_SEL, 0),
+	GATE_INFRA(CLK_INFRA_SMI, CLK_TOP_MM_SEL, 1),
+	GATE_INFRA(CLK_INFRA_QAXI_CM4, CLK_TOP_AXI_SEL, 2),
+	GATE_INFRA(CLK_INFRA_AUD_SPLIN_B, CLK_TOP_HADDS2PLL_294M, 4),
+	GATE_INFRA(CLK_INFRA_AUDIO, CLK_XTAL, 5),
+	GATE_INFRA(CLK_INFRA_EFUSE, CLK_XTAL, 6),
+	GATE_INFRA(CLK_INFRA_L2C_SRAM, CLK_TOP_MM_SEL, 7),
+	GATE_INFRA(CLK_INFRA_M4U, CLK_TOP_MEM_SEL, 8),
+	GATE_INFRA(CLK_INFRA_CONNMCU, CLK_TOP_WBG_DIG_416M, 12),
+	GATE_INFRA(CLK_INFRA_TRNG, CLK_TOP_AXI_SEL, 13),
+	GATE_INFRA(CLK_INFRA_RAMBUFIF, CLK_TOP_MEM_SEL, 14),
+	GATE_INFRA(CLK_INFRA_CPUM, CLK_TOP_MEM_SEL, 15),
+	GATE_INFRA(CLK_INFRA_KP, CLK_TOP_AXI_SEL, 16),
+	GATE_INFRA(CLK_INFRA_CEC, CLK_TOP_RTC_SEL, 18),
+	GATE_INFRA(CLK_INFRA_IRRX, CLK_TOP_AXI_SEL, 19),
+	GATE_INFRA(CLK_INFRA_PMICSPI, CLK_TOP_PMICSPI_SEL, 22),
+	GATE_INFRA(CLK_INFRA_PMICWRAP, CLK_TOP_AXI_SEL, 23),
+	GATE_INFRA(CLK_INFRA_DDCCI, CLK_TOP_AXI_SEL, 24),
+};
+
+/* pericfg */
+static const struct mtk_gate_regs peri0_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0x10,
+	.sta_ofs = 0x18,
+};
+
+static const struct mtk_gate_regs peri1_cg_regs = {
+	.set_ofs = 0xC,
+	.clr_ofs = 0x14,
+	.sta_ofs = 0x1C,
+};
+
+#define GATE_PERI0(_id, _parent, _shift) {			\
+		.id = _id,					\
+		.parent = _parent,				\
+		.regs = &peri0_cg_regs,				\
+		.shift = _shift,				\
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN,	\
+	}
+
+#define GATE_PERI1(_id, _parent, _shift) {			\
+		.id = _id,					\
+		.parent = _parent,				\
+		.regs = &peri1_cg_regs,				\
+		.shift = _shift,				\
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN,	\
+	}
+
+static const struct mtk_gate peri_cgs[] = {
+	GATE_PERI0(CLK_PERI_NFI, CLK_TOP_NFI2X_SEL, 0),
+	GATE_PERI0(CLK_PERI_THERM, CLK_TOP_AXI_SEL, 1),
+	GATE_PERI0(CLK_PERI_PWM1, CLK_TOP_AXISEL_D4, 2),
+	GATE_PERI0(CLK_PERI_PWM2, CLK_TOP_AXISEL_D4, 3),
+	GATE_PERI0(CLK_PERI_PWM3, CLK_TOP_AXISEL_D4, 4),
+	GATE_PERI0(CLK_PERI_PWM4, CLK_TOP_AXISEL_D4, 5),
+	GATE_PERI0(CLK_PERI_PWM5, CLK_TOP_AXISEL_D4, 6),
+	GATE_PERI0(CLK_PERI_PWM6, CLK_TOP_AXISEL_D4, 7),
+	GATE_PERI0(CLK_PERI_PWM7, CLK_TOP_AXISEL_D4, 8),
+	GATE_PERI0(CLK_PERI_PWM, CLK_TOP_AXI_SEL, 9),
+	GATE_PERI0(CLK_PERI_USB0, CLK_TOP_USB20_SEL, 10),
+	GATE_PERI0(CLK_PERI_USB1, CLK_TOP_USB20_SEL, 11),
+	GATE_PERI0(CLK_PERI_AP_DMA, CLK_TOP_AXI_SEL, 12),
+	GATE_PERI0(CLK_PERI_MSDC30_0, CLK_TOP_MSDC30_0_SEL, 13),
+	GATE_PERI0(CLK_PERI_MSDC30_1, CLK_TOP_MSDC30_1_SEL, 14),
+	GATE_PERI0(CLK_PERI_MSDC30_2, CLK_TOP_MSDC30_2_SEL, 15),
+	GATE_PERI0(CLK_PERI_MSDC30_3, CLK_TOP_MSDC30_3_SEL, 16),
+	GATE_PERI0(CLK_PERI_MSDC50_3, CLK_TOP_EMMC_HCLK_SEL, 17),
+	GATE_PERI0(CLK_PERI_NLI, CLK_TOP_AXI_SEL, 18),
+	GATE_PERI0(CLK_PERI_UART0, CLK_TOP_AXI_SEL, 19),
+	GATE_PERI0(CLK_PERI_UART1, CLK_TOP_AXI_SEL, 20),
+	GATE_PERI0(CLK_PERI_UART2, CLK_TOP_AXI_SEL, 21),
+	GATE_PERI0(CLK_PERI_UART3, CLK_TOP_AXI_SEL, 22),
+	GATE_PERI0(CLK_PERI_BTIF, CLK_TOP_AXI_SEL, 23),
+	GATE_PERI0(CLK_PERI_I2C0, CLK_TOP_AXI_SEL, 24),
+	GATE_PERI0(CLK_PERI_I2C1, CLK_TOP_AXI_SEL, 25),
+	GATE_PERI0(CLK_PERI_I2C2, CLK_TOP_AXI_SEL, 26),
+	GATE_PERI0(CLK_PERI_I2C3, CLK_XTAL, 27),
+	GATE_PERI0(CLK_PERI_AUXADC, CLK_XTAL, 28),
+	GATE_PERI0(CLK_PERI_SPI0, CLK_TOP_SPI0_SEL, 29),
+	GATE_PERI0(CLK_PERI_ETH, CLK_XTAL, 30),
+	GATE_PERI0(CLK_PERI_USB0_MCU, CLK_TOP_AXI_SEL, 31),
+
+	GATE_PERI1(CLK_PERI_USB1_MCU, CLK_TOP_AXI_SEL, 0),
+	GATE_PERI1(CLK_PERI_USB_SLV, CLK_TOP_AXI_SEL, 1),
+	GATE_PERI1(CLK_PERI_GCPU, CLK_TOP_AXI_SEL, 2),
+	GATE_PERI1(CLK_PERI_NFI_ECC, CLK_TOP_NFI1X_PAD, 3),
+	GATE_PERI1(CLK_PERI_NFI_PAD, CLK_TOP_NFI1X_PAD, 4),
+	GATE_PERI1(CLK_PERI_FLASH, CLK_TOP_NFI2X_SEL, 5),
+	GATE_PERI1(CLK_PERI_HOST89_INT, CLK_TOP_AXI_SEL, 6),
+	GATE_PERI1(CLK_PERI_HOST89_SPI, CLK_TOP_SPI0_SEL, 7),
+	GATE_PERI1(CLK_PERI_HOST89_DVD, CLK_TOP_AUD2DVD_SEL, 8),
+	GATE_PERI1(CLK_PERI_SPI1, CLK_TOP_SPI1_SEL, 9),
+	GATE_PERI1(CLK_PERI_SPI2, CLK_TOP_SPI2_SEL, 10),
+	GATE_PERI1(CLK_PERI_FCI, CLK_TOP_MS_CARD_SEL, 11),
+};
+
+/* ethsys */
+static const struct mtk_gate_regs eth_cg_regs = {
+	.sta_ofs = 0x30,
+};
+
+#define GATE_ETH(_id, _parent, _shift, _flag) {			\
+		.id = _id,					\
+		.parent = _parent,				\
+		.regs = &eth_cg_regs,				\
+		.shift = _shift,				\
+		.flags = CLK_GATE_NO_SETCLR_INV | (_flag),	\
+	}
+
+#define GATE_ETH0(_id, _parent, _shift)				\
+	GATE_ETH(_id, _parent, _shift, CLK_PARENT_APMIXED)
+
+#define GATE_ETH1(_id, _parent, _shift)				\
+	GATE_ETH(_id, _parent, _shift, CLK_PARENT_TOPCKGEN)
+
+static const struct mtk_gate eth_cgs[] = {
+	GATE_ETH1(CLK_ETHSYS_HSDMA, CLK_TOP_ETHIF_SEL, 5),
+	GATE_ETH1(CLK_ETHSYS_ESW, CLK_TOP_ETHPLL_500M, 6),
+	GATE_ETH0(CLK_ETHSYS_GP2, CLK_APMIXED_TRGPLL, 7),
+	GATE_ETH1(CLK_ETHSYS_GP1, CLK_TOP_ETHPLL_500M, 8),
+	GATE_ETH1(CLK_ETHSYS_PCM, CLK_TOP_ETHIF_SEL, 11),
+	GATE_ETH1(CLK_ETHSYS_GDMA, CLK_TOP_ETHIF_SEL, 14),
+	GATE_ETH1(CLK_ETHSYS_I2S, CLK_TOP_ETHIF_SEL, 17),
+	GATE_ETH1(CLK_ETHSYS_CRYPTO, CLK_TOP_ETHIF_SEL, 29),
+};
+
+static const struct mtk_clk_tree mt7623_clk_tree = {
+	.xtal_rate = 26 * MHZ,
+	.xtal2_rate = 26 * MHZ,
+	.fdivs_offs = CLK_TOP_SYSPLL,
+	.muxes_offs = CLK_TOP_AXI_SEL,
+	.plls = apmixed_plls,
+	.fclks = top_fixed_clks,
+	.fdivs = top_fixed_divs,
+	.muxes = top_muxes,
+};
+
+static int mt7623_mcucfg_probe(struct udevice *dev)
+{
+	void __iomem *base;
+
+	base = dev_read_addr_ptr(dev);
+	if (!base)
+		return -ENOENT;
+
+	clrsetbits_le32(base + MCU_AXI_DIV, AXI_DIV_MSK,
+			AXI_DIV_SEL(0x12));
+
+	return 0;
+}
+
+static int mt7623_apmixedsys_probe(struct udevice *dev)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = mtk_common_clk_init(dev, &mt7623_clk_tree);
+	if (ret)
+		return ret;
+
+	/* reduce clock square disable time */
+	writel(0x50001, priv->base + MT7623_CLKSQ_STB_CON0);
+	/* extend control timing to 1us */
+	writel(0x888, priv->base + MT7623_PLL_ISO_CON0);
+
+	return 0;
+}
+
+static int mt7623_topckgen_probe(struct udevice *dev)
+{
+	return mtk_common_clk_init(dev, &mt7623_clk_tree);
+}
+
+static int mt7623_infracfg_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7623_clk_tree, infra_cgs);
+}
+
+static int mt7623_pericfg_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7623_clk_tree, peri_cgs);
+}
+
+static int mt7623_ethsys_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7623_clk_tree, eth_cgs);
+}
+
+static const struct udevice_id mt7623_apmixed_compat[] = {
+	{ .compatible = "mediatek,mt7623-apmixedsys" },
+	{ }
+};
+
+static const struct udevice_id mt7623_topckgen_compat[] = {
+	{ .compatible = "mediatek,mt7623-topckgen" },
+	{ }
+};
+
+static const struct udevice_id mt7623_infracfg_compat[] = {
+	{ .compatible = "mediatek,mt7623-infracfg", },
+	{ }
+};
+
+static const struct udevice_id mt7623_pericfg_compat[] = {
+	{ .compatible = "mediatek,mt7623-pericfg", },
+	{ }
+};
+
+static const struct udevice_id mt7623_ethsys_compat[] = {
+	{ .compatible = "mediatek,mt7623-ethsys" },
+	{ }
+};
+
+static const struct udevice_id mt7623_mcucfg_compat[] = {
+	{ .compatible = "mediatek,mt7623-mcucfg" },
+	{ }
+};
+
+U_BOOT_DRIVER(mtk_mcucfg) = {
+	.name = "mt7623-mcucfg",
+	.id = UCLASS_SYSCON,
+	.of_match = mt7623_mcucfg_compat,
+	.probe = mt7623_mcucfg_probe,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_apmixedsys) = {
+	.name = "mt7623-clock-apmixedsys",
+	.id = UCLASS_CLK,
+	.of_match = mt7623_apmixed_compat,
+	.probe = mt7623_apmixedsys_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_apmixedsys_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_topckgen) = {
+	.name = "mt7623-clock-topckgen",
+	.id = UCLASS_CLK,
+	.of_match = mt7623_topckgen_compat,
+	.probe = mt7623_topckgen_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_topckgen_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_infracfg) = {
+	.name = "mt7623-infracfg",
+	.id = UCLASS_CLK,
+	.of_match = mt7623_infracfg_compat,
+	.probe = mt7623_infracfg_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_pericfg) = {
+	.name = "mt7623-pericfg",
+	.id = UCLASS_CLK,
+	.of_match = mt7623_pericfg_compat,
+	.probe = mt7623_pericfg_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_ethsys) = {
+	.name = "mt7623-clock-ethsys",
+	.id = UCLASS_CLK,
+	.of_match = mt7623_ethsys_compat,
+	.probe = mt7623_ethsys_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+};
diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c
new file mode 100644
index 0000000..2601b6c
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7629.c
@@ -0,0 +1,709 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek clock driver for MT7629 SoC
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <dt-bindings/clock/mt7629-clk.h>
+
+#include "clk-mtk.h"
+
+#define MT7629_CLKSQ_STB_CON0		0x20
+#define MT7629_PLL_ISO_CON0		0x2c
+#define MT7629_PLL_FMAX			(2500UL * MHZ)
+#define MT7629_CON0_RST_BAR		BIT(24)
+
+#define MCU_AXI_DIV			0x640
+#define AXI_DIV_MSK			GENMASK(4, 0)
+#define AXI_DIV_SEL(x)			(x)
+
+#define MCU_BUS_MUX			0x7c0
+#define MCU_BUS_MSK			GENMASK(10, 9)
+#define MCU_BUS_SEL(x)			((x) << 9)
+
+/* apmixedsys */
+#define PLL(_id, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg,	\
+	    _pd_shift, _pcw_reg, _pcw_shift) {				\
+		.id = _id,						\
+		.reg = _reg,						\
+		.pwr_reg = _pwr_reg,					\
+		.en_mask = _en_mask,					\
+		.rst_bar_mask = MT7629_CON0_RST_BAR,			\
+		.fmax = MT7629_PLL_FMAX,				\
+		.flags = _flags,					\
+		.pcwbits = _pcwbits,					\
+		.pd_reg = _pd_reg,					\
+		.pd_shift = _pd_shift,					\
+		.pcw_reg = _pcw_reg,					\
+		.pcw_shift = _pcw_shift,				\
+	}
+
+static const struct mtk_pll_data apmixed_plls[] = {
+	PLL(CLK_APMIXED_ARMPLL, 0x200, 0x20c, 0x1, 0,
+	    21, 0x204, 24, 0x204, 0),
+	PLL(CLK_APMIXED_MAINPLL, 0x210, 0x21c, 0x1, HAVE_RST_BAR,
+	    21, 0x214, 24, 0x214, 0),
+	PLL(CLK_APMIXED_UNIV2PLL, 0x220, 0x22c, 0x1, HAVE_RST_BAR,
+	    7, 0x224, 24, 0x224, 14),
+	PLL(CLK_APMIXED_ETH1PLL, 0x300, 0x310, 0x1, 0,
+	    21, 0x300, 1, 0x304, 0),
+	PLL(CLK_APMIXED_ETH2PLL, 0x314, 0x320, 0x1, 0,
+	    21, 0x314, 1, 0x318, 0),
+	PLL(CLK_APMIXED_SGMIPLL, 0x358, 0x368, 0x1, 0,
+	    21, 0x358, 1, 0x35c, 0),
+};
+
+/* topckgen */
+#define FACTOR0(_id, _parent, _mult, _div)			\
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_APMIXED)
+
+#define FACTOR1(_id, _parent, _mult, _div)			\
+	FACTOR(_id, _parent, _mult, _div, CLK_PARENT_TOPCKGEN)
+
+#define FACTOR2(_id, _parent, _mult, _div)			\
+	FACTOR(_id, _parent, _mult, _div, 0)
+
+static const struct mtk_fixed_clk top_fixed_clks[] = {
+	FIXED_CLK(CLK_TOP_TO_U2_PHY, CLK_XTAL, 31250000),
+	FIXED_CLK(CLK_TOP_TO_U2_PHY_1P, CLK_XTAL, 31250000),
+	FIXED_CLK(CLK_TOP_PCIE0_PIPE_EN, CLK_XTAL, 125000000),
+	FIXED_CLK(CLK_TOP_PCIE1_PIPE_EN, CLK_XTAL, 125000000),
+	FIXED_CLK(CLK_TOP_SSUSB_TX250M, CLK_XTAL, 250000000),
+	FIXED_CLK(CLK_TOP_SSUSB_EQ_RX250M, CLK_XTAL, 250000000),
+	FIXED_CLK(CLK_TOP_SSUSB_CDR_REF, CLK_XTAL, 33333333),
+	FIXED_CLK(CLK_TOP_SSUSB_CDR_FB, CLK_XTAL, 50000000),
+	FIXED_CLK(CLK_TOP_SATA_ASIC, CLK_XTAL, 50000000),
+	FIXED_CLK(CLK_TOP_SATA_RBC, CLK_XTAL, 50000000),
+};
+
+static const struct mtk_fixed_factor top_fixed_divs[] = {
+	FACTOR0(CLK_TOP_TO_USB3_SYS, CLK_APMIXED_ETH1PLL, 1, 4),
+	FACTOR0(CLK_TOP_P1_1MHZ, CLK_APMIXED_ETH1PLL, 1, 500),
+	FACTOR0(CLK_TOP_4MHZ, CLK_APMIXED_ETH1PLL, 1, 125),
+	FACTOR0(CLK_TOP_P0_1MHZ, CLK_APMIXED_ETH1PLL, 1, 500),
+	FACTOR0(CLK_TOP_ETH_500M, CLK_APMIXED_ETH1PLL, 1, 1),
+	FACTOR1(CLK_TOP_TXCLK_SRC_PRE, CLK_TOP_SGMIIPLL_D2, 1, 1),
+	FACTOR2(CLK_TOP_RTC, CLK_XTAL, 1, 1024),
+	FACTOR2(CLK_TOP_PWM_QTR_26M, CLK_XTAL, 1, 1),
+	FACTOR2(CLK_TOP_CPUM_TCK_IN, CLK_XTAL, 1, 1),
+	FACTOR2(CLK_TOP_TO_USB3_DA_TOP, CLK_XTAL, 1, 1),
+	FACTOR2(CLK_TOP_MEMPLL, CLK_XTAL, 32, 1),
+	FACTOR1(CLK_TOP_DMPLL, CLK_TOP_MEMPLL, 1, 1),
+	FACTOR1(CLK_TOP_DMPLL_D4, CLK_TOP_MEMPLL, 1, 4),
+	FACTOR1(CLK_TOP_DMPLL_D8, CLK_TOP_MEMPLL, 1, 8),
+	FACTOR0(CLK_TOP_SYSPLL_D2, CLK_APMIXED_MAINPLL, 1, 2),
+	FACTOR0(CLK_TOP_SYSPLL1_D2, CLK_APMIXED_MAINPLL, 1, 4),
+	FACTOR0(CLK_TOP_SYSPLL1_D4, CLK_APMIXED_MAINPLL, 1, 8),
+	FACTOR0(CLK_TOP_SYSPLL1_D8, CLK_APMIXED_MAINPLL, 1, 16),
+	FACTOR0(CLK_TOP_SYSPLL1_D16, CLK_APMIXED_MAINPLL, 1, 32),
+	FACTOR0(CLK_TOP_SYSPLL2_D2, CLK_APMIXED_MAINPLL, 1, 6),
+	FACTOR0(CLK_TOP_SYSPLL2_D4, CLK_APMIXED_MAINPLL, 1, 12),
+	FACTOR0(CLK_TOP_SYSPLL2_D8, CLK_APMIXED_MAINPLL, 1, 24),
+	FACTOR0(CLK_TOP_SYSPLL_D5, CLK_APMIXED_MAINPLL, 1, 5),
+	FACTOR0(CLK_TOP_SYSPLL3_D2, CLK_APMIXED_MAINPLL, 1, 10),
+	FACTOR0(CLK_TOP_SYSPLL3_D4, CLK_APMIXED_MAINPLL, 1, 20),
+	FACTOR0(CLK_TOP_SYSPLL_D7, CLK_APMIXED_MAINPLL, 1, 7),
+	FACTOR0(CLK_TOP_SYSPLL4_D2, CLK_APMIXED_MAINPLL, 1, 14),
+	FACTOR0(CLK_TOP_SYSPLL4_D4, CLK_APMIXED_MAINPLL, 1, 28),
+	FACTOR0(CLK_TOP_SYSPLL4_D16, CLK_APMIXED_MAINPLL, 1, 112),
+	FACTOR0(CLK_TOP_UNIVPLL, CLK_APMIXED_UNIV2PLL, 1, 2),
+	FACTOR1(CLK_TOP_UNIVPLL1_D2, CLK_TOP_UNIVPLL, 1, 4),
+	FACTOR1(CLK_TOP_UNIVPLL1_D4, CLK_TOP_UNIVPLL, 1, 8),
+	FACTOR1(CLK_TOP_UNIVPLL1_D8, CLK_TOP_UNIVPLL, 1, 16),
+	FACTOR1(CLK_TOP_UNIVPLL_D3, CLK_TOP_UNIVPLL, 1, 3),
+	FACTOR1(CLK_TOP_UNIVPLL2_D2, CLK_TOP_UNIVPLL, 1, 6),
+	FACTOR1(CLK_TOP_UNIVPLL2_D4, CLK_TOP_UNIVPLL, 1, 12),
+	FACTOR1(CLK_TOP_UNIVPLL2_D8, CLK_TOP_UNIVPLL, 1, 24),
+	FACTOR1(CLK_TOP_UNIVPLL2_D16, CLK_TOP_UNIVPLL, 1, 48),
+	FACTOR1(CLK_TOP_UNIVPLL_D5, CLK_TOP_UNIVPLL, 1, 5),
+	FACTOR1(CLK_TOP_UNIVPLL3_D2, CLK_TOP_UNIVPLL, 1, 10),
+	FACTOR1(CLK_TOP_UNIVPLL3_D4, CLK_TOP_UNIVPLL, 1, 20),
+	FACTOR1(CLK_TOP_UNIVPLL3_D16, CLK_TOP_UNIVPLL, 1, 80),
+	FACTOR1(CLK_TOP_UNIVPLL_D7, CLK_TOP_UNIVPLL, 1, 7),
+	FACTOR1(CLK_TOP_UNIVPLL_D80_D4, CLK_TOP_UNIVPLL, 1, 320),
+	FACTOR1(CLK_TOP_UNIV48M, CLK_TOP_UNIVPLL, 1, 25),
+	FACTOR0(CLK_TOP_SGMIIPLL_D2, CLK_APMIXED_SGMIPLL, 1, 2),
+	FACTOR2(CLK_TOP_CLKXTAL_D4, CLK_XTAL, 1, 4),
+	FACTOR1(CLK_TOP_HD_FAXI, CLK_TOP_AXI_SEL, 1, 1),
+	FACTOR1(CLK_TOP_FAXI, CLK_TOP_AXI_SEL, 1, 1),
+	FACTOR1(CLK_TOP_F_FAUD_INTBUS, CLK_TOP_AUD_INTBUS_SEL, 1, 1),
+	FACTOR1(CLK_TOP_AP2WBHIF_HCLK, CLK_TOP_SYSPLL1_D8, 1, 1),
+	FACTOR1(CLK_TOP_10M_INFRAO, CLK_TOP_10M_SEL, 1, 1),
+	FACTOR1(CLK_TOP_MSDC30_1, CLK_TOP_MSDC30_1, 1, 1),
+	FACTOR1(CLK_TOP_SPI, CLK_TOP_SPI0_SEL, 1, 1),
+	FACTOR1(CLK_TOP_SF, CLK_TOP_NFI_INFRA_SEL, 1, 1),
+	FACTOR1(CLK_TOP_FLASH, CLK_TOP_FLASH_SEL, 1, 1),
+	FACTOR1(CLK_TOP_TO_USB3_REF, CLK_TOP_SATA_SEL, 1, 4),
+	FACTOR1(CLK_TOP_TO_USB3_MCU, CLK_TOP_AXI_SEL, 1, 1),
+	FACTOR1(CLK_TOP_TO_USB3_DMA, CLK_TOP_HIF_SEL, 1, 1),
+	FACTOR1(CLK_TOP_FROM_TOP_AHB, CLK_TOP_AXI_SEL, 1, 1),
+	FACTOR1(CLK_TOP_FROM_TOP_AXI, CLK_TOP_HIF_SEL, 1, 1),
+	FACTOR1(CLK_TOP_PCIE1_MAC_EN, CLK_TOP_UNIVPLL1_D4, 1, 1),
+	FACTOR1(CLK_TOP_PCIE0_MAC_EN, CLK_TOP_UNIVPLL1_D4, 1, 1),
+};
+
+static const int axi_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_SYSPLL_D5,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_UNIVPLL_D7,
+	CLK_TOP_DMPLL
+};
+
+static const int mem_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_DMPLL
+};
+
+static const int ddrphycfg_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D8
+};
+
+static const int eth_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_UNIVPLL1_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_SGMIIPLL_D2,
+	CLK_TOP_UNIVPLL_D7,
+	CLK_TOP_DMPLL
+};
+
+static const int pwm_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D4
+};
+
+static const int f10m_ref_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SGMIIPLL_D2
+};
+
+static const int nfi_infra_parents[] = {
+	CLK_XTAL,
+	CLK_XTAL,
+	CLK_XTAL,
+	CLK_XTAL,
+	CLK_XTAL,
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D8,
+	CLK_TOP_UNIVPLL3_D4,
+	CLK_TOP_SYSPLL1_D8,
+	CLK_TOP_UNIVPLL1_D8,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_SYSPLL2_D4,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_UNIVPLL3_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_SYSPLL_D7
+};
+
+static const int flash_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL_D80_D4,
+	CLK_TOP_SYSPLL2_D8,
+	CLK_TOP_SYSPLL3_D4,
+	CLK_TOP_UNIVPLL3_D4,
+	CLK_TOP_UNIVPLL1_D8,
+	CLK_TOP_SYSPLL2_D4,
+	CLK_TOP_UNIVPLL2_D4
+};
+
+static const int uart_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D8
+};
+
+static const int spi0_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL3_D2,
+	CLK_XTAL,
+	CLK_TOP_SYSPLL2_D4,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_UNIVPLL1_D8,
+	CLK_XTAL
+};
+
+static const int spi1_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL3_D2,
+	CLK_XTAL,
+	CLK_TOP_SYSPLL4_D4,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_UNIVPLL1_D8,
+	CLK_XTAL
+};
+
+static const int msdc30_0_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D16,
+	CLK_TOP_UNIV48M
+};
+
+static const int msdc30_1_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D16,
+	CLK_TOP_UNIV48M,
+	CLK_TOP_SYSPLL2_D4,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_SYSPLL_D7,
+	CLK_TOP_SYSPLL2_D2,
+	CLK_TOP_UNIVPLL2_D2
+};
+
+static const int ap2wbmcu_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_UNIV48M,
+	CLK_TOP_SYSPLL1_D8,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_SYSPLL_D7,
+	CLK_TOP_SYSPLL2_D2,
+	CLK_TOP_UNIVPLL2_D2
+};
+
+static const int audio_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL3_D4,
+	CLK_TOP_SYSPLL4_D4,
+	CLK_TOP_SYSPLL1_D16
+};
+
+static const int aud_intbus_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_SYSPLL4_D2,
+	CLK_TOP_DMPLL_D4
+};
+
+static const int pmicspi_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D8,
+	CLK_TOP_SYSPLL3_D4,
+	CLK_TOP_SYSPLL1_D16,
+	CLK_TOP_UNIVPLL3_D4,
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D4,
+	CLK_TOP_DMPLL_D8
+};
+
+static const int scp_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D8,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_UNIVPLL2_D4
+};
+
+static const int atb_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_SYSPLL_D5
+};
+
+static const int hif_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_UNIVPLL1_D2,
+	CLK_TOP_SYSPLL1_D4,
+	CLK_TOP_UNIVPLL_D5,
+	-1,
+	CLK_TOP_UNIVPLL_D7
+};
+
+static const int sata_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL2_D4
+};
+
+static const int usb20_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL3_D4,
+	CLK_TOP_SYSPLL1_D8
+};
+
+static const int aud1_parents[] = {
+	CLK_XTAL
+};
+
+static const int irrx_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_SYSPLL4_D16
+};
+
+static const int crypto_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_UNIVPLL_D3,
+	CLK_TOP_UNIVPLL1_D2,
+	CLK_TOP_SYSPLL1_D2,
+	CLK_TOP_UNIVPLL_D5,
+	CLK_TOP_SYSPLL_D5,
+	CLK_TOP_UNIVPLL2_D2,
+	CLK_TOP_SYSPLL_D2
+};
+
+static const int gpt10m_parents[] = {
+	CLK_XTAL,
+	CLK_TOP_CLKXTAL_D4
+};
+
+static const struct mtk_composite top_muxes[] = {
+	/* CLK_CFG_0 */
+	MUX_GATE(CLK_TOP_AXI_SEL, axi_parents, 0x40, 0, 3, 7),
+	MUX_GATE(CLK_TOP_MEM_SEL, mem_parents, 0x40, 8, 1, 15),
+	MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, ddrphycfg_parents, 0x40, 16, 1, 23),
+	MUX_GATE(CLK_TOP_ETH_SEL, eth_parents, 0x40, 24, 3, 31),
+
+	/* CLK_CFG_1 */
+	MUX_GATE(CLK_TOP_PWM_SEL, pwm_parents, 0x50, 0, 2, 7),
+	MUX_GATE(CLK_TOP_F10M_REF_SEL, f10m_ref_parents, 0x50, 8, 1, 15),
+	MUX_GATE(CLK_TOP_NFI_INFRA_SEL, nfi_infra_parents, 0x50, 16, 4, 23),
+	MUX_GATE(CLK_TOP_FLASH_SEL, flash_parents, 0x50, 24, 3, 31),
+
+	/* CLK_CFG_2 */
+	MUX_GATE(CLK_TOP_UART_SEL, uart_parents, 0x60, 0, 1, 7),
+	MUX_GATE(CLK_TOP_SPI0_SEL, spi0_parents, 0x60, 8, 3, 15),
+	MUX_GATE(CLK_TOP_SPI1_SEL, spi1_parents, 0x60, 16, 3, 23),
+	MUX_GATE(CLK_TOP_MSDC50_0_SEL, uart_parents, 0x60, 24, 3, 31),
+
+	/* CLK_CFG_3 */
+	MUX_GATE(CLK_TOP_MSDC30_0_SEL, msdc30_0_parents, 0x70, 0, 3, 7),
+	MUX_GATE(CLK_TOP_MSDC30_1_SEL, msdc30_1_parents, 0x70, 8, 3, 15),
+	MUX_GATE(CLK_TOP_AP2WBMCU_SEL, ap2wbmcu_parents, 0x70, 16, 3, 23),
+	MUX_GATE(CLK_TOP_AP2WBHIF_SEL, ap2wbmcu_parents, 0x70, 24, 3, 31),
+
+	/* CLK_CFG_4 */
+	MUX_GATE(CLK_TOP_AUDIO_SEL, audio_parents, 0x80, 0, 2, 7),
+	MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, aud_intbus_parents, 0x80, 8, 2, 15),
+	MUX_GATE(CLK_TOP_PMICSPI_SEL, pmicspi_parents, 0x80, 16, 3, 23),
+	MUX_GATE(CLK_TOP_SCP_SEL, scp_parents, 0x80, 24, 2, 31),
+
+	/* CLK_CFG_5 */
+	MUX_GATE(CLK_TOP_ATB_SEL, atb_parents, 0x90, 0, 2, 7),
+	MUX_GATE_FLAGS(CLK_TOP_HIF_SEL, hif_parents, 0x90, 8, 3, 15,
+		       CLK_DOMAIN_SCPSYS),
+	MUX_GATE(CLK_TOP_SATA_SEL, sata_parents, 0x90, 16, 1, 23),
+	MUX_GATE(CLK_TOP_U2_SEL, usb20_parents, 0x90, 24, 2, 31),
+
+	/* CLK_CFG_6 */
+	MUX_GATE(CLK_TOP_AUD1_SEL, aud1_parents, 0xA0, 0, 1, 7),
+	MUX_GATE(CLK_TOP_AUD2_SEL, aud1_parents, 0xA0, 8, 1, 15),
+	MUX_GATE(CLK_TOP_IRRX_SEL, irrx_parents, 0xA0, 16, 1, 23),
+	MUX_GATE(CLK_TOP_IRTX_SEL, irrx_parents, 0xA0, 24, 1, 31),
+
+	/* CLK_CFG_7 */
+	MUX_GATE(CLK_TOP_SATA_MCU_SEL, scp_parents, 0xB0, 0, 2, 7),
+	MUX_GATE(CLK_TOP_PCIE0_MCU_SEL, scp_parents, 0xB0, 8, 2, 15),
+	MUX_GATE(CLK_TOP_PCIE1_MCU_SEL, scp_parents, 0xB0, 16, 2, 23),
+	MUX_GATE(CLK_TOP_SSUSB_MCU_SEL, scp_parents, 0xB0, 24, 2, 31),
+
+	/* CLK_CFG_8 */
+	MUX_GATE(CLK_TOP_CRYPTO_SEL, crypto_parents, 0xC0, 0, 3, 7),
+	MUX_GATE(CLK_TOP_SGMII_REF_1_SEL, f10m_ref_parents, 0xC0, 8, 1, 15),
+	MUX_GATE(CLK_TOP_10M_SEL, gpt10m_parents, 0xC0, 16, 1, 23),
+};
+
+/* infracfg */
+static const struct mtk_gate_regs infra_cg_regs = {
+	.set_ofs = 0x40,
+	.clr_ofs = 0x44,
+	.sta_ofs = 0x48,
+};
+
+#define GATE_INFRA(_id, _parent, _shift) {			\
+		.id = _id,					\
+		.parent = _parent,				\
+		.regs = &infra_cg_regs,				\
+		.shift = _shift,				\
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN,	\
+	}
+
+static const struct mtk_gate infra_cgs[] = {
+	GATE_INFRA(CLK_INFRA_DBGCLK_PD, CLK_TOP_HD_FAXI, 0),
+	GATE_INFRA(CLK_INFRA_TRNG_PD, CLK_TOP_HD_FAXI, 2),
+	GATE_INFRA(CLK_INFRA_DEVAPC_PD, CLK_TOP_HD_FAXI, 4),
+	GATE_INFRA(CLK_INFRA_APXGPT_PD, CLK_TOP_10M_INFRAO, 18),
+	GATE_INFRA(CLK_INFRA_SEJ_PD, CLK_TOP_10M_INFRAO, 19),
+};
+
+/* pericfg */
+static const struct mtk_gate_regs peri0_cg_regs = {
+	.set_ofs = 0x8,
+	.clr_ofs = 0x10,
+	.sta_ofs = 0x18,
+};
+
+static const struct mtk_gate_regs peri1_cg_regs = {
+	.set_ofs = 0xC,
+	.clr_ofs = 0x14,
+	.sta_ofs = 0x1C,
+};
+
+#define GATE_PERI0(_id, _parent, _shift) {			\
+		.id = _id,					\
+		.parent = _parent,				\
+		.regs = &peri0_cg_regs,				\
+		.shift = _shift,				\
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN,	\
+	}
+
+#define GATE_PERI1(_id, _parent, _shift) {			\
+		.id = _id,					\
+		.parent = _parent,				\
+		.regs = &peri1_cg_regs,				\
+		.shift = _shift,				\
+		.flags = CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN,	\
+	}
+
+static const struct mtk_gate peri_cgs[] = {
+	GATE_PERI0(CLK_PERI_PWM1_PD, CLK_TOP_PWM_QTR_26M, 2),
+	GATE_PERI0(CLK_PERI_PWM2_PD, CLK_TOP_PWM_QTR_26M, 3),
+	GATE_PERI0(CLK_PERI_PWM3_PD, CLK_TOP_PWM_QTR_26M, 4),
+	GATE_PERI0(CLK_PERI_PWM4_PD, CLK_TOP_PWM_QTR_26M, 5),
+	GATE_PERI0(CLK_PERI_PWM5_PD, CLK_TOP_PWM_QTR_26M, 6),
+	GATE_PERI0(CLK_PERI_PWM6_PD, CLK_TOP_PWM_QTR_26M, 7),
+	GATE_PERI0(CLK_PERI_PWM7_PD, CLK_TOP_PWM_QTR_26M, 8),
+	GATE_PERI0(CLK_PERI_PWM_PD, CLK_TOP_PWM_QTR_26M, 9),
+	GATE_PERI0(CLK_PERI_AP_DMA_PD, CLK_TOP_FAXI, 12),
+	GATE_PERI0(CLK_PERI_MSDC30_1_PD, CLK_TOP_MSDC30_1, 14),
+	GATE_PERI0(CLK_PERI_UART0_PD, CLK_TOP_FAXI, 17),
+	GATE_PERI0(CLK_PERI_UART1_PD, CLK_TOP_FAXI, 18),
+	GATE_PERI0(CLK_PERI_UART2_PD, CLK_TOP_FAXI, 19),
+	GATE_PERI0(CLK_PERI_UART3_PD, CLK_TOP_FAXI, 20),
+	GATE_PERI0(CLK_PERI_BTIF_PD, CLK_TOP_FAXI, 22),
+	GATE_PERI0(CLK_PERI_I2C0_PD, CLK_TOP_FAXI, 23),
+	GATE_PERI0(CLK_PERI_SPI0_PD, CLK_TOP_SPI, 28),
+	GATE_PERI0(CLK_PERI_SNFI_PD, CLK_TOP_SF, 29),
+	GATE_PERI0(CLK_PERI_NFI_PD, CLK_TOP_FAXI, 30),
+	GATE_PERI0(CLK_PERI_NFIECC_PD, CLK_TOP_FAXI, 31),
+	GATE_PERI1(CLK_PERI_FLASH_PD, CLK_TOP_FLASH, 1),
+};
+
+/* ethsys */
+static const struct mtk_gate_regs eth_cg_regs = {
+	.sta_ofs = 0x30,
+};
+
+#define GATE_ETH(_id, _parent, _shift, _flag) {			\
+		.id = _id,					\
+		.parent = _parent,				\
+		.regs = &eth_cg_regs,				\
+		.shift = _shift,				\
+		.flags = CLK_GATE_NO_SETCLR_INV | (_flag),	\
+	}
+
+#define GATE_ETH0(_id, _parent, _shift)				\
+	GATE_ETH(_id, _parent, _shift, CLK_PARENT_APMIXED)
+
+#define GATE_ETH1(_id, _parent, _shift)				\
+	GATE_ETH(_id, _parent, _shift, CLK_PARENT_TOPCKGEN)
+
+static const struct mtk_gate eth_cgs[] = {
+	GATE_ETH0(CLK_ETH_FE_EN, CLK_APMIXED_ETH2PLL, 6),
+	GATE_ETH1(CLK_ETH_GP2_EN, CLK_TOP_TXCLK_SRC_PRE, 7),
+	GATE_ETH1(CLK_ETH_GP1_EN, CLK_TOP_TXCLK_SRC_PRE, 8),
+	GATE_ETH1(CLK_ETH_GP0_EN, CLK_TOP_TXCLK_SRC_PRE, 9),
+	GATE_ETH1(CLK_ETH_ESW_EN, CLK_TOP_ETH_500M, 16),
+};
+
+static const struct mtk_gate_regs sgmii_cg_regs = {
+	.set_ofs = 0xE4,
+	.clr_ofs = 0xE4,
+	.sta_ofs = 0xE4,
+};
+
+#define GATE_SGMII(_id, _parent, _shift) {			\
+	.id = _id,						\
+	.parent = _parent,					\
+	.regs = &sgmii_cg_regs,					\
+	.shift = _shift,					\
+	.flags = CLK_GATE_NO_SETCLR_INV | CLK_PARENT_TOPCKGEN,	\
+}
+
+static const struct mtk_gate sgmii_cgs[] = {
+	GATE_SGMII(CLK_SGMII_TX_EN, CLK_TOP_SSUSB_TX250M, 2),
+	GATE_SGMII(CLK_SGMII_RX_EN, CLK_TOP_SSUSB_EQ_RX250M, 3),
+	GATE_SGMII(CLK_SGMII_CDR_REF, CLK_TOP_SSUSB_CDR_REF, 4),
+	GATE_SGMII(CLK_SGMII_CDR_FB, CLK_TOP_SSUSB_CDR_FB, 5),
+};
+
+static const struct mtk_clk_tree mt7629_clk_tree = {
+	.xtal_rate = 40 * MHZ,
+	.xtal2_rate = 20 * MHZ,
+	.fdivs_offs = CLK_TOP_TO_USB3_SYS,
+	.muxes_offs = CLK_TOP_AXI_SEL,
+	.plls = apmixed_plls,
+	.fclks = top_fixed_clks,
+	.fdivs = top_fixed_divs,
+	.muxes = top_muxes,
+};
+
+static int mt7629_mcucfg_probe(struct udevice *dev)
+{
+	void __iomem *base;
+
+	base = dev_read_addr_ptr(dev);
+	if (!base)
+		return -ENOENT;
+
+	clrsetbits_le32(base + MCU_AXI_DIV, AXI_DIV_MSK,
+			AXI_DIV_SEL(0x12));
+	clrsetbits_le32(base + MCU_BUS_MUX, MCU_BUS_MSK,
+			MCU_BUS_SEL(0x1));
+
+	return 0;
+}
+
+static int mt7629_apmixedsys_probe(struct udevice *dev)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = mtk_common_clk_init(dev, &mt7629_clk_tree);
+	if (ret)
+		return ret;
+
+	/* reduce clock square disable time */
+	writel(0x501, priv->base + MT7629_CLKSQ_STB_CON0);
+	/* extend pwr/iso control timing to 1us */
+	writel(0x80008, priv->base + MT7629_PLL_ISO_CON0);
+
+	return 0;
+}
+
+static int mt7629_topckgen_probe(struct udevice *dev)
+{
+	return mtk_common_clk_init(dev, &mt7629_clk_tree);
+}
+
+static int mt7629_infracfg_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, infra_cgs);
+}
+
+static int mt7629_pericfg_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, peri_cgs);
+}
+
+static int mt7629_ethsys_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, eth_cgs);
+}
+
+static int mt7629_sgmiisys_probe(struct udevice *dev)
+{
+	return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, sgmii_cgs);
+}
+
+static const struct udevice_id mt7629_apmixed_compat[] = {
+	{ .compatible = "mediatek,mt7629-apmixedsys" },
+	{ }
+};
+
+static const struct udevice_id mt7629_topckgen_compat[] = {
+	{ .compatible = "mediatek,mt7629-topckgen" },
+	{ }
+};
+
+static const struct udevice_id mt7629_infracfg_compat[] = {
+	{ .compatible = "mediatek,mt7629-infracfg", },
+	{ }
+};
+
+static const struct udevice_id mt7629_pericfg_compat[] = {
+	{ .compatible = "mediatek,mt7629-pericfg", },
+	{ }
+};
+
+static const struct udevice_id mt7629_ethsys_compat[] = {
+	{ .compatible = "mediatek,mt7629-ethsys", },
+	{ }
+};
+
+static const struct udevice_id mt7629_sgmiisys_compat[] = {
+	{ .compatible = "mediatek,mt7629-sgmiisys", },
+	{ }
+};
+
+static const struct udevice_id mt7629_mcucfg_compat[] = {
+	{ .compatible = "mediatek,mt7629-mcucfg" },
+	{ }
+};
+
+U_BOOT_DRIVER(mtk_mcucfg) = {
+	.name = "mt7629-mcucfg",
+	.id = UCLASS_SYSCON,
+	.of_match = mt7629_mcucfg_compat,
+	.probe = mt7629_mcucfg_probe,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_apmixedsys) = {
+	.name = "mt7629-clock-apmixedsys",
+	.id = UCLASS_CLK,
+	.of_match = mt7629_apmixed_compat,
+	.probe = mt7629_apmixedsys_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_apmixedsys_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_topckgen) = {
+	.name = "mt7629-clock-topckgen",
+	.id = UCLASS_CLK,
+	.of_match = mt7629_topckgen_compat,
+	.probe = mt7629_topckgen_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_clk_priv),
+	.ops = &mtk_clk_topckgen_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_infracfg) = {
+	.name = "mt7629-clock-infracfg",
+	.id = UCLASS_CLK,
+	.of_match = mt7629_infracfg_compat,
+	.probe = mt7629_infracfg_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_pericfg) = {
+	.name = "mt7629-clock-pericfg",
+	.id = UCLASS_CLK,
+	.of_match = mt7629_pericfg_compat,
+	.probe = mt7629_pericfg_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRIVER(mtk_clk_ethsys) = {
+	.name = "mt7629-clock-ethsys",
+	.id = UCLASS_CLK,
+	.of_match = mt7629_ethsys_compat,
+	.probe = mt7629_ethsys_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_cg_priv),
+	.ops = &mtk_clk_gate_ops,
+};
+
+U_BOOT_DRIVER(mtk_clk_sgmiisys) = {
+	.name = "mt7629-clock-sgmiisys",
+	.id = UCLASS_CLK,
+	.of_match = mt7629_sgmiisys_compat,
+	.probe = mt7629_sgmiisys_probe,
+	.priv_auto_alloc_size = 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
new file mode 100644
index 0000000..870b14e
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -0,0 +1,493 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek common clock driver
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <asm/io.h>
+
+#include "clk-mtk.h"
+
+#define REG_CON0			0
+#define REG_CON1			4
+
+#define CON0_BASE_EN			BIT(0)
+#define CON0_PWR_ON			BIT(0)
+#define CON0_ISO_EN			BIT(1)
+#define CON1_PCW_CHG			BIT(31)
+
+#define POSTDIV_MASK			0x7
+#define INTEGER_BITS			7
+
+/* scpsys clock off control */
+#define CLK_SCP_CFG0			0x200
+#define CLK_SCP_CFG1			0x204
+#define SCP_ARMCK_OFF_EN		GENMASK(9, 0)
+#define SCP_AXICK_DCM_DIS_EN		BIT(0)
+#define SCP_AXICK_26M_SEL_EN		BIT(4)
+
+/* shared functions */
+
+/*
+ * In case the rate change propagation to parent clocks is undesirable,
+ * this function is recursively called to find the parent to calculate
+ * the accurate frequency.
+ */
+static int mtk_clk_find_parent_rate(struct clk *clk, int id,
+				    const struct driver *drv)
+{
+	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 {
+		parent.dev = clk->dev;
+	}
+
+	return clk_get_rate(&parent);
+}
+
+static int mtk_clk_mux_set_parent(void __iomem *base, u32 parent,
+				  const struct mtk_composite *mux)
+{
+	u32 val, index = 0;
+
+	while (mux->parent[index] != parent)
+		if (++index == mux->num_parents)
+			return -EINVAL;
+
+	/* switch mux to a select parent */
+	val = readl(base + mux->mux_reg);
+	val &= ~(mux->mux_mask << mux->mux_shift);
+
+	val |= index << mux->mux_shift;
+	writel(val, base + mux->mux_reg);
+
+	return 0;
+}
+
+/* apmixedsys functions */
+
+static unsigned long __mtk_pll_recalc_rate(const struct mtk_pll_data *pll,
+					   u32 fin, u32 pcw, int postdiv)
+{
+	int pcwbits = pll->pcwbits;
+	int pcwfbits;
+	u64 vco;
+	u8 c = 0;
+
+	/* The fractional part of the PLL divider. */
+	pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0;
+
+	vco = (u64)fin * pcw;
+
+	if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
+		c = 1;
+
+	vco >>= pcwfbits;
+
+	if (c)
+		vco++;
+
+	return ((unsigned long)vco + postdiv - 1) / postdiv;
+}
+
+/**
+ * MediaTek PLLs are configured through their pcw value. The pcw value
+ * describes a divider in the PLL feedback loop which consists of 7 bits
+ * for the integer part and the remaining bits (if present) for the
+ * fractional part. Also they have a 3 bit power-of-two post divider.
+ */
+static void mtk_pll_set_rate_regs(struct clk *clk, u32 pcw, int postdiv)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	u32 val;
+
+	/* set postdiv */
+	val = readl(priv->base + pll->pd_reg);
+	val &= ~(POSTDIV_MASK << pll->pd_shift);
+	val |= (ffs(postdiv) - 1) << pll->pd_shift;
+
+	/* postdiv and pcw need to set at the same time if on same register */
+	if (pll->pd_reg != pll->pcw_reg) {
+		writel(val, priv->base + pll->pd_reg);
+		val = readl(priv->base + pll->pcw_reg);
+	}
+
+	/* set pcw */
+	val &= ~GENMASK(pll->pcw_shift + pll->pcwbits - 1, pll->pcw_shift);
+	val |= pcw << pll->pcw_shift;
+	val &= ~CON1_PCW_CHG;
+	writel(val, priv->base + pll->pcw_reg);
+
+	val |= CON1_PCW_CHG;
+	writel(val, priv->base + pll->pcw_reg);
+
+	udelay(20);
+}
+
+/**
+ * mtk_pll_calc_values - calculate good values for a given input frequency.
+ * @clk:	The clk
+ * @pcw:	The pcw value (output)
+ * @postdiv:	The post divider (output)
+ * @freq:	The desired target frequency
+ */
+static void mtk_pll_calc_values(struct clk *clk, u32 *pcw, u32 *postdiv,
+				u32 freq)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	unsigned long fmin = 1000 * MHZ;
+	u64 _pcw;
+	u32 val;
+
+	if (freq > pll->fmax)
+		freq = pll->fmax;
+
+	for (val = 0; val < 5; val++) {
+		*postdiv = 1 << val;
+		if ((u64)freq * *postdiv >= fmin)
+			break;
+	}
+
+	/* _pcw = freq * postdiv / xtal_rate * 2^pcwfbits */
+	_pcw = ((u64)freq << val) << (pll->pcwbits - INTEGER_BITS);
+	do_div(_pcw, priv->tree->xtal2_rate);
+
+	*pcw = (u32)_pcw;
+}
+
+static ulong mtk_apmixedsys_set_rate(struct clk *clk, ulong rate)
+{
+	u32 pcw = 0;
+	u32 postdiv;
+
+	mtk_pll_calc_values(clk, &pcw, &postdiv, rate);
+	mtk_pll_set_rate_regs(clk, pcw, postdiv);
+
+	return 0;
+}
+
+static ulong mtk_apmixedsys_get_rate(struct clk *clk)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	u32 postdiv;
+	u32 pcw;
+
+	postdiv = (readl(priv->base + pll->pd_reg) >> pll->pd_shift) &
+		   POSTDIV_MASK;
+	postdiv = 1 << postdiv;
+
+	pcw = readl(priv->base + pll->pcw_reg) >> pll->pcw_shift;
+	pcw &= GENMASK(pll->pcwbits - 1, 0);
+
+	return __mtk_pll_recalc_rate(pll, priv->tree->xtal2_rate,
+				     pcw, postdiv);
+}
+
+static int mtk_apmixedsys_enable(struct clk *clk)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	u32 r;
+
+	r = readl(priv->base + pll->pwr_reg) | CON0_PWR_ON;
+	writel(r, priv->base + pll->pwr_reg);
+	udelay(1);
+
+	r = readl(priv->base + pll->pwr_reg) & ~CON0_ISO_EN;
+	writel(r, priv->base + pll->pwr_reg);
+	udelay(1);
+
+	r = readl(priv->base + pll->reg + REG_CON0);
+	r |= pll->en_mask;
+	writel(r, priv->base + pll->reg + REG_CON0);
+
+	udelay(20);
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl(priv->base + pll->reg + REG_CON0);
+		r |= pll->rst_bar_mask;
+		writel(r, priv->base + pll->reg + REG_CON0);
+	}
+
+	return 0;
+}
+
+static int mtk_apmixedsys_disable(struct clk *clk)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	u32 r;
+
+	if (pll->flags & HAVE_RST_BAR) {
+		r = readl(priv->base + pll->reg + REG_CON0);
+		r &= ~pll->rst_bar_mask;
+		writel(r, priv->base + pll->reg + REG_CON0);
+	}
+
+	r = readl(priv->base + pll->reg + REG_CON0);
+	r &= ~CON0_BASE_EN;
+	writel(r, priv->base + pll->reg + REG_CON0);
+
+	r = readl(priv->base + pll->pwr_reg) | CON0_ISO_EN;
+	writel(r, priv->base + pll->pwr_reg);
+
+	r = readl(priv->base + pll->pwr_reg) & ~CON0_PWR_ON;
+	writel(r, priv->base + pll->pwr_reg);
+
+	return 0;
+}
+
+/* topckgen functions */
+
+static ulong mtk_factor_recalc_rate(const struct mtk_fixed_factor *fdiv,
+				    ulong parent_rate)
+{
+	u64 rate = parent_rate * fdiv->mult;
+
+	do_div(rate, fdiv->div);
+
+	return rate;
+}
+
+static int mtk_topckgen_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_APMIXED:
+		rate = mtk_clk_find_parent_rate(clk, fdiv->parent,
+				DM_GET_DRIVER(mtk_clk_apmixedsys));
+		break;
+	case CLK_PARENT_TOPCKGEN:
+		rate = mtk_clk_find_parent_rate(clk, fdiv->parent, NULL);
+		break;
+
+	default:
+		rate = priv->tree->xtal_rate;
+	}
+
+	return mtk_factor_recalc_rate(fdiv, rate);
+}
+
+static int mtk_topckgen_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])
+		return mtk_clk_find_parent_rate(clk, mux->parent[index],
+						NULL);
+
+	return priv->tree->xtal_rate;
+}
+
+static ulong mtk_topckgen_get_rate(struct clk *clk)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (clk->id < priv->tree->fdivs_offs)
+		return priv->tree->fclks[clk->id].rate;
+	else if (clk->id < priv->tree->muxes_offs)
+		return mtk_topckgen_get_factor_rate(clk, clk->id -
+						    priv->tree->fdivs_offs);
+	else
+		return mtk_topckgen_get_mux_rate(clk, clk->id -
+						 priv->tree->muxes_offs);
+}
+
+static int mtk_topckgen_enable(struct clk *clk)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_composite *mux;
+	u32 val;
+
+	if (clk->id < priv->tree->muxes_offs)
+		return 0;
+
+	mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
+	if (mux->gate_shift < 0)
+		return 0;
+
+	/* enable clock gate */
+	val = readl(priv->base + mux->gate_reg);
+	val &= ~BIT(mux->gate_shift);
+	writel(val, priv->base + mux->gate_reg);
+
+	if (mux->flags & CLK_DOMAIN_SCPSYS) {
+		/* enable scpsys clock off control */
+		writel(SCP_ARMCK_OFF_EN, priv->base + CLK_SCP_CFG0);
+		writel(SCP_AXICK_DCM_DIS_EN | SCP_AXICK_26M_SEL_EN,
+		       priv->base + CLK_SCP_CFG1);
+	}
+
+	return 0;
+}
+
+static int mtk_topckgen_disable(struct clk *clk)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_composite *mux;
+	u32 val;
+
+	if (clk->id < priv->tree->muxes_offs)
+		return 0;
+
+	mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
+	if (mux->gate_shift < 0)
+		return 0;
+
+	/* disable clock gate */
+	val = readl(priv->base + mux->gate_reg);
+	val |= BIT(mux->gate_shift);
+	writel(val, priv->base + mux->gate_reg);
+
+	return 0;
+}
+
+static int mtk_topckgen_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (clk->id < priv->tree->muxes_offs)
+		return 0;
+
+	return mtk_clk_mux_set_parent(priv->base, parent->id,
+			&priv->tree->muxes[clk->id - priv->tree->muxes_offs]);
+}
+
+/* CG functions */
+
+static int mtk_clk_gate_enable(struct clk *clk)
+{
+	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_gate *gate = &priv->gates[clk->id];
+	u32 bit = BIT(gate->shift);
+
+	switch (gate->flags & CLK_GATE_MASK) {
+	case CLK_GATE_SETCLR:
+		writel(bit, priv->base + gate->regs->clr_ofs);
+		break;
+	case CLK_GATE_NO_SETCLR_INV:
+		clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, bit);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mtk_clk_gate_disable(struct clk *clk)
+{
+	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
+	const struct mtk_gate *gate = &priv->gates[clk->id];
+	u32 bit = BIT(gate->shift);
+
+	switch (gate->flags & CLK_GATE_MASK) {
+	case CLK_GATE_SETCLR:
+		writel(bit, priv->base + gate->regs->set_ofs);
+		break;
+	case CLK_GATE_NO_SETCLR_INV:
+		clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static ulong mtk_clk_gate_get_rate(struct clk *clk)
+{
+	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_GET_DRIVER(mtk_clk_apmixedsys));
+		break;
+	case CLK_PARENT_TOPCKGEN:
+		return mtk_clk_find_parent_rate(clk, gate->parent,
+				DM_GET_DRIVER(mtk_clk_topckgen));
+		break;
+
+	default:
+		return priv->tree->xtal_rate;
+	}
+}
+
+const struct clk_ops mtk_clk_apmixedsys_ops = {
+	.enable = mtk_apmixedsys_enable,
+	.disable = mtk_apmixedsys_disable,
+	.set_rate = mtk_apmixedsys_set_rate,
+	.get_rate = mtk_apmixedsys_get_rate,
+};
+
+const struct clk_ops mtk_clk_topckgen_ops = {
+	.enable = mtk_topckgen_enable,
+	.disable = mtk_topckgen_disable,
+	.get_rate = mtk_topckgen_get_rate,
+	.set_parent = mtk_topckgen_set_parent,
+};
+
+const struct clk_ops mtk_clk_gate_ops = {
+	.enable = mtk_clk_gate_enable,
+	.disable = mtk_clk_gate_disable,
+	.get_rate = mtk_clk_gate_get_rate,
+};
+
+int mtk_common_clk_init(struct udevice *dev,
+			const struct mtk_clk_tree *tree)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (!priv->base)
+		return -ENOENT;
+
+	priv->tree = tree;
+
+	return 0;
+}
+
+int mtk_common_clk_gate_init(struct udevice *dev,
+			     const struct mtk_clk_tree *tree,
+			     const struct mtk_gate *gates)
+{
+	struct mtk_cg_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (!priv->base)
+		return -ENOENT;
+
+	priv->tree = tree;
+	priv->gates = gates;
+
+	return 0;
+}
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
new file mode 100644
index 0000000..74152ed
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#ifndef __DRV_CLK_MTK_H
+#define __DRV_CLK_MTK_H
+
+#define CLK_XTAL			0
+#define MHZ				(1000 * 1000)
+
+#define HAVE_RST_BAR			BIT(0)
+#define CLK_DOMAIN_SCPSYS		BIT(0)
+
+#define CLK_GATE_SETCLR			BIT(0)
+#define CLK_GATE_SETCLR_INV		BIT(1)
+#define CLK_GATE_NO_SETCLR		BIT(2)
+#define CLK_GATE_NO_SETCLR_INV		BIT(3)
+#define CLK_GATE_MASK			GENMASK(3, 0)
+
+#define CLK_PARENT_APMIXED		BIT(4)
+#define CLK_PARENT_TOPCKGEN		BIT(5)
+#define CLK_PARENT_MASK			GENMASK(5, 4)
+
+/* struct mtk_pll_data - hardware-specific PLLs data */
+struct mtk_pll_data {
+	const int id;
+	u32 reg;
+	u32 pwr_reg;
+	u32 en_mask;
+	u32 pd_reg;
+	int pd_shift;
+	u32 flags;
+	u32 rst_bar_mask;
+	u64 fmax;
+	int pcwbits;
+	u32 pcw_reg;
+	int pcw_shift;
+};
+
+/**
+ * struct mtk_fixed_clk - fixed clocks
+ *
+ * @id:		index of clocks
+ * @parent:	index of parnet clocks
+ * @rate:	fixed rate
+ */
+struct mtk_fixed_clk {
+	const int id;
+	const int parent;
+	unsigned long rate;
+};
+
+#define FIXED_CLK(_id, _parent, _rate) {		\
+		.id = _id,				\
+		.parent = _parent,			\
+		.rate = _rate,				\
+	}
+
+/**
+ * struct mtk_fixed_factor - fixed multiplier and divider clocks
+ *
+ * @id:		index of clocks
+ * @parent:	index of parnet clocks
+ * @mult:	multiplier
+ * @div:	divider
+ * @flag:	hardware-specific flags
+ */
+struct mtk_fixed_factor {
+	const int id;
+	const int parent;
+	u32 mult;
+	u32 div;
+	u32 flags;
+};
+
+#define FACTOR(_id, _parent, _mult, _div, _flags) {	\
+		.id = _id,				\
+		.parent = _parent,			\
+		.mult = _mult,				\
+		.div = _div,				\
+		.flags = _flags,			\
+	}
+
+/**
+ * struct mtk_composite - aggregate clock of mux, divider and gate clocks
+ *
+ * @id:			index of clocks
+ * @parent:		index of parnet clocks
+ * @mux_reg:		hardware-specific mux register
+ * @gate_reg:		hardware-specific gate register
+ * @mux_mask:		mask to the mux bit field
+ * @mux_shift:		shift to the mux bit field
+ * @gate_shift:		shift to the gate bit field
+ * @num_parents:	number of parent clocks
+ * @flags:		hardware-specific flags
+ */
+struct mtk_composite {
+	const int id;
+	const int *parent;
+	u32 mux_reg;
+	u32 gate_reg;
+	u32 mux_mask;
+	signed char mux_shift;
+	signed char gate_shift;
+	signed char num_parents;
+	u16 flags;
+};
+
+#define MUX_GATE_FLAGS(_id, _parents, _reg, _shift, _width, _gate,	\
+		       _flags) {					\
+		.id = _id,						\
+		.mux_reg = _reg,					\
+		.mux_shift = _shift,					\
+		.mux_mask = BIT(_width) - 1,				\
+		.gate_reg = _reg,					\
+		.gate_shift = _gate,					\
+		.parent = _parents,					\
+		.num_parents = ARRAY_SIZE(_parents),			\
+		.flags = _flags,					\
+	}
+
+#define MUX_GATE(_id, _parents, _reg, _shift, _width, _gate)		\
+	MUX_GATE_FLAGS(_id, _parents, _reg, _shift, _width, _gate, 0)
+
+#define MUX(_id, _parents, _reg, _shift, _width) {			\
+		.id = _id,						\
+		.mux_reg = _reg,					\
+		.mux_shift = _shift,					\
+		.mux_mask = BIT(_width) - 1,				\
+		.gate_shift = -1,					\
+		.parent = _parents,					\
+		.num_parents = ARRAY_SIZE(_parents),			\
+		.flags = 0,						\
+	}
+
+struct mtk_gate_regs {
+	u32 sta_ofs;
+	u32 clr_ofs;
+	u32 set_ofs;
+};
+
+/**
+ * struct mtk_gate - gate clocks
+ *
+ * @id:		index of gate clocks
+ * @parent:	index of parnet clocks
+ * @regs:	hardware-specific mux register
+ * @shift:	shift to the gate bit field
+ * @flags:	hardware-specific flags
+ */
+struct mtk_gate {
+	const int id;
+	const int parent;
+	const struct mtk_gate_regs *regs;
+	int shift;
+	u32 flags;
+};
+
+/* struct mtk_clk_tree - clock tree */
+struct mtk_clk_tree {
+	unsigned long xtal_rate;
+	unsigned long xtal2_rate;
+	const int fdivs_offs;
+	const int muxes_offs;
+	const struct mtk_pll_data *plls;
+	const struct mtk_fixed_clk *fclks;
+	const struct mtk_fixed_factor *fdivs;
+	const struct mtk_composite *muxes;
+};
+
+struct mtk_clk_priv {
+	void __iomem *base;
+	const struct mtk_clk_tree *tree;
+};
+
+struct mtk_cg_priv {
+	void __iomem *base;
+	const struct mtk_clk_tree *tree;
+	const struct mtk_gate *gates;
+};
+
+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_gate_ops;
+
+int mtk_common_clk_init(struct udevice *dev,
+			const struct mtk_clk_tree *tree);
+int mtk_common_clk_gate_init(struct udevice *dev,
+			     const struct mtk_clk_tree *tree,
+			     const struct mtk_gate *gates);
+
+#endif /* __DRV_CLK_MTK_H */
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 3f7458d..fbd1396 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -602,6 +602,17 @@
 	help
 		This can enable ftsdc010 sdio function.
 
+config MMC_MTK
+	bool "MediaTek SD/MMC Card Interface support"
+	depends on ARCH_MEDIATEK
+	depends on BLK && DM_MMC
+	depends on OF_CONTROL
+	help
+	  This selects the MediaTek(R) Secure digital and Multimedia card Interface.
+	  If you have a machine with a integrated SD/MMC card reader, say Y or M here.
+	  This is needed if support for any SD/SDIO/MMC devices is required.
+	  If unsure, say N.
+
 endif
 
 config TEGRA124_MMC_DISABLE_EXT_LOOPBACK
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 23c5b0d..801a26d 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -65,3 +65,4 @@
 obj-$(CONFIG_MMC_UNIPHIER)		+= tmio-common.o uniphier-sd.o
 obj-$(CONFIG_RENESAS_SDHI)		+= tmio-common.o renesas-sdhi.o
 obj-$(CONFIG_MMC_BCM2835)		+= bcm2835_sdhost.o
+obj-$(CONFIG_MMC_MTK)			+= mtk-sd.o
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
new file mode 100644
index 0000000..0741a52
--- /dev/null
+++ b/drivers/mmc/mtk-sd.c
@@ -0,0 +1,1394 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek SD/MMC Card Interface driver
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <mmc.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <asm/gpio.h>
+#include <dm/pinctrl.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+
+/* MSDC_CFG */
+#define MSDC_CFG_HS400_CK_MODE_EXT	BIT(22)
+#define MSDC_CFG_CKMOD_EXT_M		0x300000
+#define MSDC_CFG_CKMOD_EXT_S		20
+#define MSDC_CFG_CKDIV_EXT_M		0xfff00
+#define MSDC_CFG_CKDIV_EXT_S		8
+#define MSDC_CFG_HS400_CK_MODE		BIT(18)
+#define MSDC_CFG_CKMOD_M		0x30000
+#define MSDC_CFG_CKMOD_S		16
+#define MSDC_CFG_CKDIV_M		0xff00
+#define MSDC_CFG_CKDIV_S		8
+#define MSDC_CFG_CKSTB			BIT(7)
+#define MSDC_CFG_PIO			BIT(3)
+#define MSDC_CFG_RST			BIT(2)
+#define MSDC_CFG_CKPDN			BIT(1)
+#define MSDC_CFG_MODE			BIT(0)
+
+/* MSDC_IOCON */
+#define MSDC_IOCON_W_DSPL		BIT(8)
+#define MSDC_IOCON_DSPL			BIT(2)
+#define MSDC_IOCON_RSPL			BIT(1)
+
+/* MSDC_PS */
+#define MSDC_PS_DAT0			BIT(16)
+#define MSDC_PS_CDDBCE_M		0xf000
+#define MSDC_PS_CDDBCE_S		12
+#define MSDC_PS_CDSTS			BIT(1)
+#define MSDC_PS_CDEN			BIT(0)
+
+/* #define MSDC_INT(EN) */
+#define MSDC_INT_ACMDRDY		BIT(3)
+#define MSDC_INT_ACMDTMO		BIT(4)
+#define MSDC_INT_ACMDCRCERR		BIT(5)
+#define MSDC_INT_CMDRDY			BIT(8)
+#define MSDC_INT_CMDTMO			BIT(9)
+#define MSDC_INT_RSPCRCERR		BIT(10)
+#define MSDC_INT_XFER_COMPL		BIT(12)
+#define MSDC_INT_DATTMO			BIT(14)
+#define MSDC_INT_DATCRCERR		BIT(15)
+
+/* MSDC_FIFOCS */
+#define MSDC_FIFOCS_CLR			BIT(31)
+#define MSDC_FIFOCS_TXCNT_M		0xff0000
+#define MSDC_FIFOCS_TXCNT_S		16
+#define MSDC_FIFOCS_RXCNT_M		0xff
+#define MSDC_FIFOCS_RXCNT_S		0
+
+/* #define SDC_CFG */
+#define SDC_CFG_DTOC_M			0xff000000
+#define SDC_CFG_DTOC_S			24
+#define SDC_CFG_SDIOIDE			BIT(20)
+#define SDC_CFG_SDIO			BIT(19)
+#define SDC_CFG_BUSWIDTH_M		0x30000
+#define SDC_CFG_BUSWIDTH_S		16
+
+/* SDC_CMD */
+#define SDC_CMD_BLK_LEN_M		0xfff0000
+#define SDC_CMD_BLK_LEN_S		16
+#define SDC_CMD_STOP			BIT(14)
+#define SDC_CMD_WR			BIT(13)
+#define SDC_CMD_DTYPE_M			0x1800
+#define SDC_CMD_DTYPE_S			11
+#define SDC_CMD_RSPTYP_M		0x380
+#define SDC_CMD_RSPTYP_S		7
+#define SDC_CMD_CMD_M			0x3f
+#define SDC_CMD_CMD_S			0
+
+/* SDC_STS */
+#define SDC_STS_CMDBUSY			BIT(1)
+#define SDC_STS_SDCBUSY			BIT(0)
+
+/* SDC_ADV_CFG0 */
+#define SDC_RX_ENHANCE_EN		BIT(20)
+
+/* PATCH_BIT0 */
+#define MSDC_INT_DAT_LATCH_CK_SEL_M	0x380
+#define MSDC_INT_DAT_LATCH_CK_SEL_S	7
+
+/* PATCH_BIT1 */
+#define MSDC_PB1_STOP_DLY_M		0xf00
+#define MSDC_PB1_STOP_DLY_S		8
+
+/* PATCH_BIT2 */
+#define MSDC_PB2_CRCSTSENSEL_M		0xe0000000
+#define MSDC_PB2_CRCSTSENSEL_S		29
+#define MSDC_PB2_CFGCRCSTS		BIT(28)
+#define MSDC_PB2_RESPSTSENSEL_M		0x70000
+#define MSDC_PB2_RESPSTSENSEL_S		16
+#define MSDC_PB2_CFGRESP		BIT(15)
+#define MSDC_PB2_RESPWAIT_M		0x0c
+#define MSDC_PB2_RESPWAIT_S		2
+
+/* PAD_TUNE */
+#define MSDC_PAD_TUNE_CMDRRDLY_M	0x7c00000
+#define MSDC_PAD_TUNE_CMDRRDLY_S	22
+#define MSDC_PAD_TUNE_CMD_SEL		BIT(21)
+#define MSDC_PAD_TUNE_CMDRDLY_M		0x1f0000
+#define MSDC_PAD_TUNE_CMDRDLY_S		16
+#define MSDC_PAD_TUNE_RXDLYSEL		BIT(15)
+#define MSDC_PAD_TUNE_RD_SEL		BIT(13)
+#define MSDC_PAD_TUNE_DATRRDLY_M	0x1f00
+#define MSDC_PAD_TUNE_DATRRDLY_S	8
+#define MSDC_PAD_TUNE_DATWRDLY_M	0x1f
+#define MSDC_PAD_TUNE_DATWRDLY_S	0
+
+/* EMMC50_CFG0 */
+#define EMMC50_CFG_CFCSTS_SEL		BIT(4)
+
+/* SDC_FIFO_CFG */
+#define SDC_FIFO_CFG_WRVALIDSEL		BIT(24)
+#define SDC_FIFO_CFG_RDVALIDSEL		BIT(25)
+
+/* SDC_CFG_BUSWIDTH */
+#define MSDC_BUS_1BITS			0x0
+#define MSDC_BUS_4BITS			0x1
+#define MSDC_BUS_8BITS			0x2
+
+#define MSDC_FIFO_SIZE			128
+
+#define PAD_DELAY_MAX			32
+
+#define DEFAULT_CD_DEBOUNCE		8
+
+#define CMD_INTS_MASK	\
+	(MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO)
+
+#define DATA_INTS_MASK	\
+	(MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR)
+
+/* Register offset */
+struct mtk_sd_regs {
+	u32 msdc_cfg;
+	u32 msdc_iocon;
+	u32 msdc_ps;
+	u32 msdc_int;
+	u32 msdc_inten;
+	u32 msdc_fifocs;
+	u32 msdc_txdata;
+	u32 msdc_rxdata;
+	u32 reserved0[4];
+	u32 sdc_cfg;
+	u32 sdc_cmd;
+	u32 sdc_arg;
+	u32 sdc_sts;
+	u32 sdc_resp[4];
+	u32 sdc_blk_num;
+	u32 sdc_vol_chg;
+	u32 sdc_csts;
+	u32 sdc_csts_en;
+	u32 sdc_datcrc_sts;
+	u32 sdc_adv_cfg0;
+	u32 reserved1[2];
+	u32 emmc_cfg0;
+	u32 emmc_cfg1;
+	u32 emmc_sts;
+	u32 emmc_iocon;
+	u32 sd_acmd_resp;
+	u32 sd_acmd19_trg;
+	u32 sd_acmd19_sts;
+	u32 dma_sa_high4bit;
+	u32 dma_sa;
+	u32 dma_ca;
+	u32 dma_ctrl;
+	u32 dma_cfg;
+	u32 sw_dbg_sel;
+	u32 sw_dbg_out;
+	u32 dma_length;
+	u32 reserved2;
+	u32 patch_bit0;
+	u32 patch_bit1;
+	u32 patch_bit2;
+	u32 reserved3;
+	u32 dat0_tune_crc;
+	u32 dat1_tune_crc;
+	u32 dat2_tune_crc;
+	u32 dat3_tune_crc;
+	u32 cmd_tune_crc;
+	u32 sdio_tune_wind;
+	u32 reserved4[5];
+	u32 pad_tune;
+	u32 pad_tune0;
+	u32 pad_tune1;
+	u32 dat_rd_dly[4];
+	u32 reserved5[2];
+	u32 hw_dbg_sel;
+	u32 main_ver;
+	u32 eco_ver;
+	u32 reserved6[27];
+	u32 pad_ds_tune;
+	u32 reserved7[31];
+	u32 emmc50_cfg0;
+	u32 reserved8[7];
+	u32 sdc_fifo_cfg;
+};
+
+struct msdc_compatible {
+	u8 clk_div_bits;
+	bool pad_tune0;
+	bool async_fifo;
+	bool data_tune;
+	bool busy_check;
+	bool stop_clk_fix;
+	bool enhance_rx;
+};
+
+struct msdc_delay_phase {
+	u8 maxlen;
+	u8 start;
+	u8 final_phase;
+};
+
+struct msdc_plat {
+	struct mmc_config cfg;
+	struct mmc mmc;
+};
+
+struct msdc_tune_para {
+	u32 iocon;
+	u32 pad_tune;
+};
+
+struct msdc_host {
+	struct mtk_sd_regs *base;
+	struct mmc *mmc;
+
+	struct msdc_compatible *dev_comp;
+
+	struct clk src_clk;	/* for SD/MMC bus clock */
+	struct clk h_clk;	/* MSDC core clock */
+
+	u32 src_clk_freq;	/* source clock */
+	u32 mclk;		/* mmc framework required bus clock */
+	u32 sclk;		/* actual calculated bus clock */
+
+	/* operation timeout clocks */
+	u32 timeout_ns;
+	u32 timeout_clks;
+
+	/* tuning options */
+	u32 hs400_ds_delay;
+	u32 hs200_cmd_int_delay;
+	u32 hs200_write_int_delay;
+	u32 latch_ck;
+	u32 r_smpl;		/* sample edge */
+	bool hs400_mode;
+
+	/* whether to use gpio detection or built-in hw detection */
+	bool builtin_cd;
+
+	/* card detection / write protection GPIOs */
+#ifdef CONFIG_DM_GPIO
+	struct gpio_desc gpio_wp;
+	struct gpio_desc gpio_cd;
+#endif
+
+	uint last_resp_type;
+	uint last_data_write;
+
+	enum bus_mode timing;
+
+	struct msdc_tune_para def_tune_para;
+	struct msdc_tune_para saved_tune_para;
+};
+
+static void msdc_reset_hw(struct msdc_host *host)
+{
+	u32 reg;
+
+	setbits_le32(&host->base->msdc_cfg, MSDC_CFG_RST);
+
+	readl_poll_timeout(&host->base->msdc_cfg, reg,
+			   !(reg & MSDC_CFG_RST), 1000000);
+}
+
+static void msdc_fifo_clr(struct msdc_host *host)
+{
+	u32 reg;
+
+	setbits_le32(&host->base->msdc_fifocs, MSDC_FIFOCS_CLR);
+
+	readl_poll_timeout(&host->base->msdc_fifocs, reg,
+			   !(reg & MSDC_FIFOCS_CLR), 1000000);
+}
+
+static u32 msdc_fifo_rx_bytes(struct msdc_host *host)
+{
+	return (readl(&host->base->msdc_fifocs) &
+		MSDC_FIFOCS_RXCNT_M) >> MSDC_FIFOCS_RXCNT_S;
+}
+
+static u32 msdc_fifo_tx_bytes(struct msdc_host *host)
+{
+	return (readl(&host->base->msdc_fifocs) &
+		MSDC_FIFOCS_TXCNT_M) >> MSDC_FIFOCS_TXCNT_S;
+}
+
+static u32 msdc_cmd_find_resp(struct msdc_host *host, struct mmc_cmd *cmd)
+{
+	u32 resp;
+
+	switch (cmd->resp_type) {
+		/* Actually, R1, R5, R6, R7 are the same */
+	case MMC_RSP_R1:
+		resp = 0x1;
+		break;
+	case MMC_RSP_R1b:
+		resp = 0x7;
+		break;
+	case MMC_RSP_R2:
+		resp = 0x2;
+		break;
+	case MMC_RSP_R3:
+		resp = 0x3;
+		break;
+	case MMC_RSP_NONE:
+	default:
+		resp = 0x0;
+		break;
+	}
+
+	return resp;
+}
+
+static u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
+				    struct mmc_cmd *cmd,
+				    struct mmc_data *data)
+{
+	u32 opcode = cmd->cmdidx;
+	u32 resp_type = msdc_cmd_find_resp(host, cmd);
+	uint blocksize = 0;
+	u32 dtype = 0;
+	u32 rawcmd = 0;
+
+	switch (opcode) {
+	case MMC_CMD_WRITE_MULTIPLE_BLOCK:
+	case MMC_CMD_READ_MULTIPLE_BLOCK:
+		dtype = 2;
+		break;
+	case MMC_CMD_WRITE_SINGLE_BLOCK:
+	case MMC_CMD_READ_SINGLE_BLOCK:
+	case SD_CMD_APP_SEND_SCR:
+		dtype = 1;
+		break;
+	case SD_CMD_SWITCH_FUNC: /* same as MMC_CMD_SWITCH */
+	case SD_CMD_SEND_IF_COND: /* same as MMC_CMD_SEND_EXT_CSD */
+	case SD_CMD_APP_SD_STATUS: /* same as MMC_CMD_SEND_STATUS */
+		if (data)
+			dtype = 1;
+	}
+
+	if (data) {
+		if (data->flags == MMC_DATA_WRITE)
+			rawcmd |= SDC_CMD_WR;
+
+		if (data->blocks > 1)
+			dtype = 2;
+
+		blocksize = data->blocksize;
+	}
+
+	rawcmd |= ((opcode << SDC_CMD_CMD_S) & SDC_CMD_CMD_M) |
+		((resp_type << SDC_CMD_RSPTYP_S) & SDC_CMD_RSPTYP_M) |
+		((blocksize << SDC_CMD_BLK_LEN_S) & SDC_CMD_BLK_LEN_M) |
+		((dtype << SDC_CMD_DTYPE_S) & SDC_CMD_DTYPE_M);
+
+	if (opcode == MMC_CMD_STOP_TRANSMISSION)
+		rawcmd |= SDC_CMD_STOP;
+
+	return rawcmd;
+}
+
+static int msdc_cmd_done(struct msdc_host *host, int events,
+			 struct mmc_cmd *cmd)
+{
+	u32 *rsp = cmd->response;
+	int ret = 0;
+
+	if (cmd->resp_type & MMC_RSP_PRESENT) {
+		if (cmd->resp_type & MMC_RSP_136) {
+			rsp[0] = readl(&host->base->sdc_resp[3]);
+			rsp[1] = readl(&host->base->sdc_resp[2]);
+			rsp[2] = readl(&host->base->sdc_resp[1]);
+			rsp[3] = readl(&host->base->sdc_resp[0]);
+		} else {
+			rsp[0] = readl(&host->base->sdc_resp[0]);
+		}
+	}
+
+	if (!(events & MSDC_INT_CMDRDY)) {
+		if (cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK &&
+		    cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK_HS200)
+			/*
+			 * should not clear fifo/interrupt as the tune data
+			 * may have alreay come.
+			 */
+			msdc_reset_hw(host);
+
+		if (events & MSDC_INT_CMDTMO)
+			ret = -ETIMEDOUT;
+		else
+			ret = -EIO;
+	}
+
+	return ret;
+}
+
+static bool msdc_cmd_is_ready(struct msdc_host *host)
+{
+	int ret;
+	u32 reg;
+
+	/* The max busy time we can endure is 20ms */
+	ret = readl_poll_timeout(&host->base->sdc_sts, reg,
+				 !(reg & SDC_STS_CMDBUSY), 20000);
+
+	if (ret) {
+		pr_err("CMD bus busy detected\n");
+		msdc_reset_hw(host);
+		return false;
+	}
+
+	if (host->last_resp_type == MMC_RSP_R1b && host->last_data_write) {
+		ret = readl_poll_timeout(&host->base->msdc_ps, reg,
+					 reg & MSDC_PS_DAT0, 1000000);
+
+		if (ret) {
+			pr_err("Card stuck in programming state!\n");
+			msdc_reset_hw(host);
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static int msdc_start_command(struct msdc_host *host, struct mmc_cmd *cmd,
+			      struct mmc_data *data)
+{
+	u32 rawcmd;
+	u32 status;
+	u32 blocks = 0;
+	int ret;
+
+	if (!msdc_cmd_is_ready(host))
+		return -EIO;
+
+	msdc_fifo_clr(host);
+
+	host->last_resp_type = cmd->resp_type;
+	host->last_data_write = 0;
+
+	rawcmd = msdc_cmd_prepare_raw_cmd(host, cmd, data);
+
+	if (data)
+		blocks = data->blocks;
+
+	writel(CMD_INTS_MASK, &host->base->msdc_int);
+	writel(blocks, &host->base->sdc_blk_num);
+	writel(cmd->cmdarg, &host->base->sdc_arg);
+	writel(rawcmd, &host->base->sdc_cmd);
+
+	ret = readl_poll_timeout(&host->base->msdc_int, status,
+				 status & CMD_INTS_MASK, 1000000);
+
+	if (ret)
+		status = MSDC_INT_CMDTMO;
+
+	return msdc_cmd_done(host, status, cmd);
+}
+
+static void msdc_fifo_read(struct msdc_host *host, u8 *buf, u32 size)
+{
+	u32 *wbuf;
+
+	while ((size_t)buf % 4) {
+		*buf++ = readb(&host->base->msdc_rxdata);
+		size--;
+	}
+
+	wbuf = (u32 *)buf;
+	while (size >= 4) {
+		*wbuf++ = readl(&host->base->msdc_rxdata);
+		size -= 4;
+	}
+
+	buf = (u8 *)wbuf;
+	while (size) {
+		*buf++ = readb(&host->base->msdc_rxdata);
+		size--;
+	}
+}
+
+static void msdc_fifo_write(struct msdc_host *host, const u8 *buf, u32 size)
+{
+	const u32 *wbuf;
+
+	while ((size_t)buf % 4) {
+		writeb(*buf++, &host->base->msdc_txdata);
+		size--;
+	}
+
+	wbuf = (const u32 *)buf;
+	while (size >= 4) {
+		writel(*wbuf++, &host->base->msdc_txdata);
+		size -= 4;
+	}
+
+	buf = (const u8 *)wbuf;
+	while (size) {
+		writeb(*buf++, &host->base->msdc_txdata);
+		size--;
+	}
+}
+
+static int msdc_pio_read(struct msdc_host *host, u8 *ptr, u32 size)
+{
+	u32 status;
+	u32 chksz;
+	int ret = 0;
+
+	while (1) {
+		status = readl(&host->base->msdc_int);
+		writel(status, &host->base->msdc_int);
+		status &= DATA_INTS_MASK;
+
+		if (status & MSDC_INT_DATCRCERR) {
+			ret = -EIO;
+			break;
+		}
+
+		if (status & MSDC_INT_DATTMO) {
+			ret = -ETIMEDOUT;
+			break;
+		}
+
+		if (status & MSDC_INT_XFER_COMPL) {
+			if (size) {
+				pr_err("data not fully read\n");
+				ret = -EIO;
+			}
+
+			break;
+		}
+
+		chksz = min(size, (u32)MSDC_FIFO_SIZE);
+
+		if (msdc_fifo_rx_bytes(host) >= chksz) {
+			msdc_fifo_read(host, ptr, chksz);
+			ptr += chksz;
+			size -= chksz;
+		}
+	}
+
+	return ret;
+}
+
+static int msdc_pio_write(struct msdc_host *host, const u8 *ptr, u32 size)
+{
+	u32 status;
+	u32 chksz;
+	int ret = 0;
+
+	while (1) {
+		status = readl(&host->base->msdc_int);
+		writel(status, &host->base->msdc_int);
+		status &= DATA_INTS_MASK;
+
+		if (status & MSDC_INT_DATCRCERR) {
+			ret = -EIO;
+			break;
+		}
+
+		if (status & MSDC_INT_DATTMO) {
+			ret = -ETIMEDOUT;
+			break;
+		}
+
+		if (status & MSDC_INT_XFER_COMPL) {
+			if (size) {
+				pr_err("data not fully written\n");
+				ret = -EIO;
+			}
+
+			break;
+		}
+
+		chksz = min(size, (u32)MSDC_FIFO_SIZE);
+
+		if (MSDC_FIFO_SIZE - msdc_fifo_tx_bytes(host) >= chksz) {
+			msdc_fifo_write(host, ptr, chksz);
+			ptr += chksz;
+			size -= chksz;
+		}
+	}
+
+	return ret;
+}
+
+static int msdc_start_data(struct msdc_host *host, struct mmc_data *data)
+{
+	u32 size;
+	int ret;
+
+	if (data->flags == MMC_DATA_WRITE)
+		host->last_data_write = 1;
+
+	writel(DATA_INTS_MASK, &host->base->msdc_int);
+
+	size = data->blocks * data->blocksize;
+
+	if (data->flags == MMC_DATA_WRITE)
+		ret = msdc_pio_write(host, (const u8 *)data->src, size);
+	else
+		ret = msdc_pio_read(host, (u8 *)data->dest, size);
+
+	if (ret) {
+		msdc_reset_hw(host);
+		msdc_fifo_clr(host);
+	}
+
+	return ret;
+}
+
+static int msdc_ops_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+			     struct mmc_data *data)
+{
+	struct msdc_host *host = dev_get_priv(dev);
+	int ret;
+
+	ret = msdc_start_command(host, cmd, data);
+	if (ret)
+		return ret;
+
+	if (data)
+		return msdc_start_data(host, data);
+
+	return 0;
+}
+
+static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)
+{
+	u32 timeout, clk_ns;
+	u32 mode = 0;
+
+	host->timeout_ns = ns;
+	host->timeout_clks = clks;
+
+	if (host->sclk == 0) {
+		timeout = 0;
+	} else {
+		clk_ns = 1000000000UL / host->sclk;
+		timeout = (ns + clk_ns - 1) / clk_ns + clks;
+		/* unit is 1048576 sclk cycles */
+		timeout = (timeout + (0x1 << 20) - 1) >> 20;
+		if (host->dev_comp->clk_div_bits == 8)
+			mode = (readl(&host->base->msdc_cfg) &
+				MSDC_CFG_CKMOD_M) >> MSDC_CFG_CKMOD_S;
+		else
+			mode = (readl(&host->base->msdc_cfg) &
+				MSDC_CFG_CKMOD_EXT_M) >> MSDC_CFG_CKMOD_EXT_S;
+		/* DDR mode will double the clk cycles for data timeout */
+		timeout = mode >= 2 ? timeout * 2 : timeout;
+		timeout = timeout > 1 ? timeout - 1 : 0;
+		timeout = timeout > 255 ? 255 : timeout;
+	}
+
+	clrsetbits_le32(&host->base->sdc_cfg, SDC_CFG_DTOC_M,
+			timeout << SDC_CFG_DTOC_S);
+}
+
+static void msdc_set_buswidth(struct msdc_host *host, u32 width)
+{
+	u32 val = readl(&host->base->sdc_cfg);
+
+	val &= ~SDC_CFG_BUSWIDTH_M;
+
+	switch (width) {
+	default:
+	case 1:
+		val |= (MSDC_BUS_1BITS << SDC_CFG_BUSWIDTH_S);
+		break;
+	case 4:
+		val |= (MSDC_BUS_4BITS << SDC_CFG_BUSWIDTH_S);
+		break;
+	case 8:
+		val |= (MSDC_BUS_8BITS << SDC_CFG_BUSWIDTH_S);
+		break;
+	}
+
+	writel(val, &host->base->sdc_cfg);
+}
+
+static void msdc_set_mclk(struct msdc_host *host, enum bus_mode timing, u32 hz)
+{
+	u32 mode;
+	u32 div;
+	u32 sclk;
+	u32 reg;
+
+	if (!hz) {
+		host->mclk = 0;
+		clrbits_le32(&host->base->msdc_cfg, MSDC_CFG_CKPDN);
+		return;
+	}
+
+	if (host->dev_comp->clk_div_bits == 8)
+		clrbits_le32(&host->base->msdc_cfg, MSDC_CFG_HS400_CK_MODE);
+	else
+		clrbits_le32(&host->base->msdc_cfg,
+			     MSDC_CFG_HS400_CK_MODE_EXT);
+
+	if (timing == UHS_DDR50 || timing == MMC_DDR_52 ||
+	    timing == MMC_HS_400) {
+		if (timing == MMC_HS_400)
+			mode = 0x3;
+		else
+			mode = 0x2; /* ddr mode and use divisor */
+
+		if (hz >= (host->src_clk_freq >> 2)) {
+			div = 0; /* mean div = 1/4 */
+			sclk = host->src_clk_freq >> 2; /* sclk = clk / 4 */
+		} else {
+			div = (host->src_clk_freq + ((hz << 2) - 1)) /
+			       (hz << 2);
+			sclk = (host->src_clk_freq >> 2) / div;
+			div = (div >> 1);
+		}
+
+		if (timing == MMC_HS_400 && hz >= (host->src_clk_freq >> 1)) {
+			if (host->dev_comp->clk_div_bits == 8)
+				setbits_le32(&host->base->msdc_cfg,
+					     MSDC_CFG_HS400_CK_MODE);
+			else
+				setbits_le32(&host->base->msdc_cfg,
+					     MSDC_CFG_HS400_CK_MODE_EXT);
+
+			sclk = host->src_clk_freq >> 1;
+			div = 0; /* div is ignore when bit18 is set */
+		}
+	} else if (hz >= host->src_clk_freq) {
+		mode = 0x1; /* no divisor */
+		div = 0;
+		sclk = host->src_clk_freq;
+	} else {
+		mode = 0x0; /* use divisor */
+		if (hz >= (host->src_clk_freq >> 1)) {
+			div = 0; /* mean div = 1/2 */
+			sclk = host->src_clk_freq >> 1; /* sclk = clk / 2 */
+		} else {
+			div = (host->src_clk_freq + ((hz << 2) - 1)) /
+			       (hz << 2);
+			sclk = (host->src_clk_freq >> 2) / div;
+		}
+	}
+
+	clrbits_le32(&host->base->msdc_cfg, MSDC_CFG_CKPDN);
+
+	if (host->dev_comp->clk_div_bits == 8) {
+		div = min(div, (u32)(MSDC_CFG_CKDIV_M >> MSDC_CFG_CKDIV_S));
+		clrsetbits_le32(&host->base->msdc_cfg,
+				MSDC_CFG_CKMOD_M | MSDC_CFG_CKDIV_M,
+				(mode << MSDC_CFG_CKMOD_S) |
+				(div << MSDC_CFG_CKDIV_S));
+	} else {
+		div = min(div, (u32)(MSDC_CFG_CKDIV_EXT_M >>
+				      MSDC_CFG_CKDIV_EXT_S));
+		clrsetbits_le32(&host->base->msdc_cfg,
+				MSDC_CFG_CKMOD_EXT_M | MSDC_CFG_CKDIV_EXT_M,
+				(mode << MSDC_CFG_CKMOD_EXT_S) |
+				(div << MSDC_CFG_CKDIV_EXT_S));
+	}
+
+	readl_poll_timeout(&host->base->msdc_cfg, reg,
+			   reg & MSDC_CFG_CKSTB, 1000000);
+
+	setbits_le32(&host->base->msdc_cfg, MSDC_CFG_CKPDN);
+	host->sclk = sclk;
+	host->mclk = hz;
+	host->timing = timing;
+
+	/* needed because clk changed. */
+	msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
+
+	/*
+	 * mmc_select_hs400() will drop to 50Mhz and High speed mode,
+	 * tune result of hs200/200Mhz is not suitable for 50Mhz
+	 */
+	if (host->sclk <= 52000000) {
+		writel(host->def_tune_para.iocon, &host->base->msdc_iocon);
+		writel(host->def_tune_para.pad_tune,
+		       &host->base->pad_tune);
+	} else {
+		writel(host->saved_tune_para.iocon, &host->base->msdc_iocon);
+		writel(host->saved_tune_para.pad_tune,
+		       &host->base->pad_tune);
+	}
+
+	dev_dbg(dev, "sclk: %d, timing: %d\n", host->sclk, timing);
+}
+
+static int msdc_ops_set_ios(struct udevice *dev)
+{
+	struct msdc_plat *plat = dev_get_platdata(dev);
+	struct msdc_host *host = dev_get_priv(dev);
+	struct mmc *mmc = &plat->mmc;
+	uint clock = mmc->clock;
+
+	msdc_set_buswidth(host, mmc->bus_width);
+
+	if (mmc->clk_disable)
+		clock = 0;
+	else if (clock < mmc->cfg->f_min)
+		clock = mmc->cfg->f_min;
+
+	if (host->mclk != clock || host->timing != mmc->selected_mode)
+		msdc_set_mclk(host, mmc->selected_mode, clock);
+
+	return 0;
+}
+
+static int msdc_ops_get_cd(struct udevice *dev)
+{
+	struct msdc_host *host = dev_get_priv(dev);
+	u32 val;
+
+	if (host->builtin_cd) {
+		val = readl(&host->base->msdc_ps);
+		return !(val & MSDC_PS_CDSTS);
+	}
+
+#ifdef CONFIG_DM_GPIO
+	if (!host->gpio_cd.dev)
+		return 1;
+
+	return dm_gpio_get_value(&host->gpio_cd);
+#else
+	return 1;
+#endif
+}
+
+static int msdc_ops_get_wp(struct udevice *dev)
+{
+	struct msdc_host *host = dev_get_priv(dev);
+
+#ifdef CONFIG_DM_GPIO
+	if (!host->gpio_wp.dev)
+		return 0;
+
+	return !dm_gpio_get_value(&host->gpio_wp);
+#else
+	return 0;
+#endif
+}
+
+#ifdef MMC_SUPPORTS_TUNING
+static u32 test_delay_bit(u32 delay, u32 bit)
+{
+	bit %= PAD_DELAY_MAX;
+	return delay & (1 << bit);
+}
+
+static int get_delay_len(u32 delay, u32 start_bit)
+{
+	int i;
+
+	for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) {
+		if (test_delay_bit(delay, start_bit + i) == 0)
+			return i;
+	}
+
+	return PAD_DELAY_MAX - start_bit;
+}
+
+static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
+{
+	int start = 0, len = 0;
+	int start_final = 0, len_final = 0;
+	u8 final_phase = 0xff;
+	struct msdc_delay_phase delay_phase = { 0, };
+
+	if (delay == 0) {
+		dev_err(dev, "phase error: [map:%x]\n", delay);
+		delay_phase.final_phase = final_phase;
+		return delay_phase;
+	}
+
+	while (start < PAD_DELAY_MAX) {
+		len = get_delay_len(delay, start);
+		if (len_final < len) {
+			start_final = start;
+			len_final = len;
+		}
+
+		start += len ? len : 1;
+		if (len >= 12 && start_final < 4)
+			break;
+	}
+
+	/* The rule is to find the smallest delay cell */
+	if (start_final == 0)
+		final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX;
+	else
+		final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX;
+
+	dev_info(dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+		 delay, len_final, final_phase);
+
+	delay_phase.maxlen = len_final;
+	delay_phase.start = start_final;
+	delay_phase.final_phase = final_phase;
+	return delay_phase;
+}
+
+static int msdc_tune_response(struct udevice *dev, u32 opcode)
+{
+	struct msdc_plat *plat = dev_get_platdata(dev);
+	struct msdc_host *host = dev_get_priv(dev);
+	struct mmc *mmc = &plat->mmc;
+	u32 rise_delay = 0, fall_delay = 0;
+	struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0, };
+	struct msdc_delay_phase internal_delay_phase;
+	u8 final_delay, final_maxlen;
+	u32 internal_delay = 0;
+	void __iomem *tune_reg = &host->base->pad_tune;
+	int cmd_err;
+	int i, j;
+
+	if (host->dev_comp->pad_tune0)
+		tune_reg = &host->base->pad_tune0;
+
+	if (mmc->selected_mode == MMC_HS_200 ||
+	    mmc->selected_mode == UHS_SDR104)
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M,
+				host->hs200_cmd_int_delay <<
+				MSDC_PAD_TUNE_CMDRRDLY_S);
+
+	clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL);
+
+	for (i = 0; i < PAD_DELAY_MAX; i++) {
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRDLY_M,
+				i << MSDC_PAD_TUNE_CMDRDLY_S);
+
+		for (j = 0; j < 3; j++) {
+			mmc_send_tuning(mmc, opcode, &cmd_err);
+			if (!cmd_err) {
+				rise_delay |= (1 << i);
+			} else {
+				rise_delay &= ~(1 << i);
+				break;
+			}
+		}
+	}
+
+	final_rise_delay = get_best_delay(host, rise_delay);
+	/* if rising edge has enough margin, do not scan falling edge */
+	if (final_rise_delay.maxlen >= 12 ||
+	    (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
+		goto skip_fall;
+
+	setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL);
+	for (i = 0; i < PAD_DELAY_MAX; i++) {
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRDLY_M,
+				i << MSDC_PAD_TUNE_CMDRDLY_S);
+
+		for (j = 0; j < 3; j++) {
+			mmc_send_tuning(mmc, opcode, &cmd_err);
+			if (!cmd_err) {
+				fall_delay |= (1 << i);
+			} else {
+				fall_delay &= ~(1 << i);
+				break;
+			}
+		}
+	}
+
+	final_fall_delay = get_best_delay(host, fall_delay);
+
+skip_fall:
+	final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+	if (final_maxlen == final_rise_delay.maxlen) {
+		clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL);
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRDLY_M,
+				final_rise_delay.final_phase <<
+				MSDC_PAD_TUNE_CMDRDLY_S);
+		final_delay = final_rise_delay.final_phase;
+	} else {
+		setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL);
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRDLY_M,
+				final_fall_delay.final_phase <<
+				MSDC_PAD_TUNE_CMDRDLY_S);
+		final_delay = final_fall_delay.final_phase;
+	}
+
+	if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay)
+		goto skip_internal;
+
+	for (i = 0; i < PAD_DELAY_MAX; i++) {
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M,
+				i << MSDC_PAD_TUNE_CMDRRDLY_S);
+
+		mmc_send_tuning(mmc, opcode, &cmd_err);
+		if (!cmd_err)
+			internal_delay |= (1 << i);
+	}
+
+	dev_err(dev, "Final internal delay: 0x%x\n", internal_delay);
+
+	internal_delay_phase = get_best_delay(host, internal_delay);
+	clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_CMDRRDLY_M,
+			internal_delay_phase.final_phase <<
+			MSDC_PAD_TUNE_CMDRRDLY_S);
+
+skip_internal:
+	dev_err(dev, "Final cmd pad delay: %x\n", final_delay);
+	return final_delay == 0xff ? -EIO : 0;
+}
+
+static int msdc_tune_data(struct udevice *dev, u32 opcode)
+{
+	struct msdc_plat *plat = dev_get_platdata(dev);
+	struct msdc_host *host = dev_get_priv(dev);
+	struct mmc *mmc = &plat->mmc;
+	u32 rise_delay = 0, fall_delay = 0;
+	struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0, };
+	u8 final_delay, final_maxlen;
+	void __iomem *tune_reg = &host->base->pad_tune;
+	int cmd_err;
+	int i, ret;
+
+	if (host->dev_comp->pad_tune0)
+		tune_reg = &host->base->pad_tune0;
+
+	clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_DSPL);
+	clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_W_DSPL);
+
+	for (i = 0; i < PAD_DELAY_MAX; i++) {
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M,
+				i << MSDC_PAD_TUNE_DATRRDLY_S);
+
+		ret = mmc_send_tuning(mmc, opcode, &cmd_err);
+		if (!ret) {
+			rise_delay |= (1 << i);
+		} else if (cmd_err) {
+			/* in this case, retune response is needed */
+			ret = msdc_tune_response(dev, opcode);
+			if (ret)
+				break;
+		}
+	}
+
+	final_rise_delay = get_best_delay(host, rise_delay);
+	if (final_rise_delay.maxlen >= 12 ||
+	    (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
+		goto skip_fall;
+
+	setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_DSPL);
+	setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_W_DSPL);
+
+	for (i = 0; i < PAD_DELAY_MAX; i++) {
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M,
+				i << MSDC_PAD_TUNE_DATRRDLY_S);
+
+		ret = mmc_send_tuning(mmc, opcode, &cmd_err);
+		if (!ret) {
+			fall_delay |= (1 << i);
+		} else if (cmd_err) {
+			/* in this case, retune response is needed */
+			ret = msdc_tune_response(dev, opcode);
+			if (ret)
+				break;
+		}
+	}
+
+	final_fall_delay = get_best_delay(host, fall_delay);
+
+skip_fall:
+	final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+	if (final_maxlen == final_rise_delay.maxlen) {
+		clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_DSPL);
+		clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_W_DSPL);
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M,
+				final_rise_delay.final_phase <<
+				MSDC_PAD_TUNE_DATRRDLY_S);
+		final_delay = final_rise_delay.final_phase;
+	} else {
+		setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_DSPL);
+		setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_W_DSPL);
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATRRDLY_M,
+				final_fall_delay.final_phase <<
+				MSDC_PAD_TUNE_DATRRDLY_S);
+		final_delay = final_fall_delay.final_phase;
+	}
+
+	if (mmc->selected_mode == MMC_HS_200 ||
+	    mmc->selected_mode == UHS_SDR104)
+		clrsetbits_le32(tune_reg, MSDC_PAD_TUNE_DATWRDLY_M,
+				host->hs200_write_int_delay <<
+				MSDC_PAD_TUNE_DATWRDLY_S);
+
+	dev_err(dev, "Final data pad delay: %x\n", final_delay);
+
+	return final_delay == 0xff ? -EIO : 0;
+}
+
+static int msdc_execute_tuning(struct udevice *dev, uint opcode)
+{
+	struct msdc_plat *plat = dev_get_platdata(dev);
+	struct msdc_host *host = dev_get_priv(dev);
+	struct mmc *mmc = &plat->mmc;
+	int ret;
+
+	if (mmc->selected_mode == MMC_HS_400) {
+		writel(host->hs400_ds_delay, &host->base->pad_ds_tune);
+		/* for hs400 mode it must be set to 0 */
+		clrbits_le32(&host->base->patch_bit2, MSDC_PB2_CFGCRCSTS);
+		host->hs400_mode = true;
+	}
+
+	ret = msdc_tune_response(dev, opcode);
+	if (ret == -EIO) {
+		dev_err(dev, "Tune response fail!\n");
+		return ret;
+	}
+
+	if (!host->hs400_mode) {
+		ret = msdc_tune_data(dev, opcode);
+		if (ret == -EIO)
+			dev_err(dev, "Tune data fail!\n");
+	}
+
+	host->saved_tune_para.iocon = readl(&host->base->msdc_iocon);
+	host->saved_tune_para.pad_tune = readl(&host->base->pad_tune);
+
+	return ret;
+}
+#endif
+
+static void msdc_init_hw(struct msdc_host *host)
+{
+	u32 val;
+	void __iomem *tune_reg = &host->base->pad_tune;
+
+	if (host->dev_comp->pad_tune0)
+		tune_reg = &host->base->pad_tune0;
+
+	/* Configure to MMC/SD mode, clock free running */
+	setbits_le32(&host->base->msdc_cfg, MSDC_CFG_MODE);
+
+	/* Use PIO mode */
+	setbits_le32(&host->base->msdc_cfg, MSDC_CFG_PIO);
+
+	/* Reset */
+	msdc_reset_hw(host);
+
+	/* Enable/disable hw card detection according to fdt option */
+	if (host->builtin_cd)
+		clrsetbits_le32(&host->base->msdc_ps,
+			MSDC_PS_CDDBCE_M,
+			(DEFAULT_CD_DEBOUNCE << MSDC_PS_CDDBCE_S) |
+			MSDC_PS_CDEN);
+	else
+		clrbits_le32(&host->base->msdc_ps, MSDC_PS_CDEN);
+
+	/* Clear all interrupts */
+	val = readl(&host->base->msdc_int);
+	writel(val, &host->base->msdc_int);
+
+	/* Enable data & cmd interrupts */
+	writel(DATA_INTS_MASK | CMD_INTS_MASK, &host->base->msdc_inten);
+
+	writel(0, tune_reg);
+	writel(0, &host->base->msdc_iocon);
+
+	if (host->r_smpl)
+		setbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL);
+	else
+		clrbits_le32(&host->base->msdc_iocon, MSDC_IOCON_RSPL);
+
+	writel(0x403c0046, &host->base->patch_bit0);
+	writel(0xffff4089, &host->base->patch_bit1);
+
+	if (host->dev_comp->stop_clk_fix)
+		clrsetbits_le32(&host->base->patch_bit1, MSDC_PB1_STOP_DLY_M,
+				3 << MSDC_PB1_STOP_DLY_S);
+
+	if (host->dev_comp->busy_check)
+		clrbits_le32(&host->base->patch_bit1, (1 << 7));
+
+	setbits_le32(&host->base->emmc50_cfg0, EMMC50_CFG_CFCSTS_SEL);
+
+	if (host->dev_comp->async_fifo) {
+		clrsetbits_le32(&host->base->patch_bit2, MSDC_PB2_RESPWAIT_M,
+				3 << MSDC_PB2_RESPWAIT_S);
+
+		if (host->dev_comp->enhance_rx) {
+			setbits_le32(&host->base->sdc_adv_cfg0,
+				     SDC_RX_ENHANCE_EN);
+		} else {
+			clrsetbits_le32(&host->base->patch_bit2,
+					MSDC_PB2_RESPSTSENSEL_M,
+					2 << MSDC_PB2_RESPSTSENSEL_S);
+			clrsetbits_le32(&host->base->patch_bit2,
+					MSDC_PB2_CRCSTSENSEL_M,
+					2 << MSDC_PB2_CRCSTSENSEL_S);
+		}
+
+		/* use async fifo to avoid tune internal delay */
+		clrbits_le32(&host->base->patch_bit2,
+			     MSDC_PB2_CFGRESP);
+		clrbits_le32(&host->base->patch_bit2,
+			     MSDC_PB2_CFGCRCSTS);
+	}
+
+	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);
+	} else {
+		/* choose clock tune */
+		setbits_le32(tune_reg, MSDC_PAD_TUNE_RXDLYSEL);
+	}
+
+	/* Configure to enable SDIO mode otherwise sdio cmd5 won't work */
+	setbits_le32(&host->base->sdc_cfg, SDC_CFG_SDIO);
+
+	/* disable detecting SDIO device interrupt function */
+	clrbits_le32(&host->base->sdc_cfg, SDC_CFG_SDIOIDE);
+
+	/* Configure to default data timeout */
+	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);
+}
+
+static void msdc_ungate_clock(struct msdc_host *host)
+{
+	clk_enable(&host->src_clk);
+	clk_enable(&host->h_clk);
+}
+
+static int msdc_drv_probe(struct udevice *dev)
+{
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct msdc_plat *plat = dev_get_platdata(dev);
+	struct msdc_host *host = dev_get_priv(dev);
+	struct mmc_config *cfg = &plat->cfg;
+
+	cfg->name = dev->name;
+
+	host->dev_comp = (struct msdc_compatible *)dev_get_driver_data(dev);
+
+	host->src_clk_freq = clk_get_rate(&host->src_clk);
+
+	if (host->dev_comp->clk_div_bits == 8)
+		cfg->f_min = host->src_clk_freq / (4 * 255);
+	else
+		cfg->f_min = host->src_clk_freq / (4 * 4095);
+	cfg->f_max = host->src_clk_freq / 2;
+
+	cfg->b_max = 1024;
+	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+	host->mmc = &plat->mmc;
+	host->timeout_ns = 100000000;
+	host->timeout_clks = 3 * 1048576;
+
+#ifdef CONFIG_PINCTRL
+	pinctrl_select_state(dev, "default");
+#endif
+
+	msdc_ungate_clock(host);
+	msdc_init_hw(host);
+
+	upriv->mmc = &plat->mmc;
+
+	return 0;
+}
+
+static int msdc_ofdata_to_platdata(struct udevice *dev)
+{
+	struct msdc_plat *plat = dev_get_platdata(dev);
+	struct msdc_host *host = dev_get_priv(dev);
+	struct mmc_config *cfg = &plat->cfg;
+	int ret;
+
+	host->base = (void *)dev_read_addr(dev);
+	if (!host->base)
+		return -EINVAL;
+
+	ret = mmc_of_parse(dev, cfg);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_name(dev, "source", &host->src_clk);
+	if (ret < 0)
+		return ret;
+
+	ret = clk_get_by_name(dev, "hclk", &host->h_clk);
+	if (ret < 0)
+		return ret;
+
+#ifdef CONFIG_DM_GPIO
+	gpio_request_by_name(dev, "wp-gpios", 0, &host->gpio_wp, GPIOD_IS_IN);
+	gpio_request_by_name(dev, "cd-gpios", 0, &host->gpio_cd, GPIOD_IS_IN);
+#endif
+
+	host->hs400_ds_delay = dev_read_u32_default(dev, "hs400-ds-delay", 0);
+	host->hs200_cmd_int_delay =
+			dev_read_u32_default(dev, "cmd_int_delay", 0);
+	host->hs200_write_int_delay =
+			dev_read_u32_default(dev, "write_int_delay", 0);
+	host->latch_ck = dev_read_u32_default(dev, "latch-ck", 0);
+	host->r_smpl = dev_read_u32_default(dev, "r_smpl", 0);
+	host->builtin_cd = dev_read_u32_default(dev, "builtin-cd", 0);
+
+	return 0;
+}
+
+static int msdc_drv_bind(struct udevice *dev)
+{
+	struct msdc_plat *plat = dev_get_platdata(dev);
+
+	return mmc_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct dm_mmc_ops msdc_ops = {
+	.send_cmd = msdc_ops_send_cmd,
+	.set_ios = msdc_ops_set_ios,
+	.get_cd = msdc_ops_get_cd,
+	.get_wp = msdc_ops_get_wp,
+#ifdef MMC_SUPPORTS_TUNING
+	.execute_tuning = msdc_execute_tuning,
+#endif
+};
+
+static const struct msdc_compatible mt7623_compat = {
+	.clk_div_bits = 12,
+	.pad_tune0 = true,
+	.async_fifo = true,
+	.data_tune = true,
+	.busy_check = false,
+	.stop_clk_fix = false,
+	.enhance_rx = false
+};
+
+static const struct udevice_id msdc_ids[] = {
+	{ .compatible = "mediatek,mt7623-mmc", .data = (ulong)&mt7623_compat },
+	{}
+};
+
+U_BOOT_DRIVER(mtk_sd_drv) = {
+	.name = "mtk_sd",
+	.id = UCLASS_MMC,
+	.of_match = msdc_ids,
+	.ofdata_to_platdata = msdc_ofdata_to_platdata,
+	.bind = msdc_drv_bind,
+	.probe = msdc_drv_probe,
+	.ops = &msdc_ops,
+	.platdata_auto_alloc_size = sizeof(struct msdc_plat),
+	.priv_auto_alloc_size = sizeof(struct msdc_host),
+};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index ad0b8da..7e6fad3 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -301,6 +301,7 @@
 endif
 
 source "drivers/pinctrl/meson/Kconfig"
+source "drivers/pinctrl/mediatek/Kconfig"
 source "drivers/pinctrl/nxp/Kconfig"
 source "drivers/pinctrl/renesas/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a3a6c6d..293bad3 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -16,6 +16,7 @@
 obj-$(CONFIG_PINCTRL_PIC32)	+= pinctrl_pic32.o
 obj-$(CONFIG_PINCTRL_EXYNOS)	+= exynos/
 obj-$(CONFIG_PINCTRL_MESON)	+= meson/
+obj-$(CONFIG_PINCTRL_MTK)	+= mediatek/
 obj-$(CONFIG_ARCH_MVEBU)	+= mvebu/
 obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
 obj-$(CONFIG_PINCTRL_STI)	+= pinctrl-sti.o
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
new file mode 100644
index 0000000..1bd9a92
--- /dev/null
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -0,0 +1,15 @@
+if ARCH_MEDIATEK
+
+config PINCTRL_MTK
+	depends on PINCTRL_GENERIC
+	bool
+
+config PINCTRL_MT7623
+	bool "MT7623 SoC pinctrl driver"
+	select PINCTRL_MTK
+
+config PINCTRL_MT7629
+	bool "MT7629 SoC pinctrl driver"
+	select PINCTRL_MTK
+
+endif
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
new file mode 100644
index 0000000..f6ef362
--- /dev/null
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+# Core
+obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o
+
+# SoC Drivers
+obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-mt7623.o
+obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
new file mode 100644
index 0000000..fd37dfa
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c
@@ -0,0 +1,1284 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <dm.h>
+
+#include "pinctrl-mtk-common.h"
+
+#define PIN_BOND_REG0		0xb10
+#define PIN_BOND_REG1		0xf20
+#define PIN_BOND_REG2		0xef0
+#define BOND_PCIE_CLR		(0x77 << 3)
+#define BOND_I2S_CLR		0x3
+#define BOND_MSDC0E_CLR		0x1
+
+#define PIN_FIELD15(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit,	\
+		       _x_bits, 15, false)
+
+#define PIN_FIELD16(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit,	\
+		       _x_bits, 16, false)
+
+#define PINS_FIELD16(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits)\
+	PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit,	\
+		       _x_bits, 16, true)
+
+static const struct mtk_pin_field_calc mt7623_pin_mode_range[] = {
+	PIN_FIELD15(0, 278, 0x760, 0x10, 0, 3),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_dir_range[] = {
+	PIN_FIELD16(0, 175, 0x0, 0x10, 0, 1),
+	PIN_FIELD16(176, 278, 0xc0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_di_range[] = {
+	PIN_FIELD16(0, 278, 0x630, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_do_range[] = {
+	PIN_FIELD16(0, 278, 0x500, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_ies_range[] = {
+	PINS_FIELD16(0, 6, 0xb20, 0x10, 0, 1),
+	PINS_FIELD16(7, 9, 0xb20, 0x10, 1, 1),
+	PINS_FIELD16(10, 13, 0xb30, 0x10, 3, 1),
+	PINS_FIELD16(14, 15, 0xb30, 0x10, 13, 1),
+	PINS_FIELD16(16, 17, 0xb40, 0x10, 7, 1),
+	PINS_FIELD16(18, 29, 0xb40, 0x10, 13, 1),
+	PINS_FIELD16(30, 32, 0xb40, 0x10, 7, 1),
+	PINS_FIELD16(33, 37, 0xb40, 0x10, 13, 1),
+	PIN_FIELD16(38, 38, 0xb20, 0x10, 13, 1),
+	PINS_FIELD16(39, 42, 0xb40, 0x10, 13, 1),
+	PINS_FIELD16(43, 45, 0xb20, 0x10, 10, 1),
+	PINS_FIELD16(47, 48, 0xb20, 0x10, 11, 1),
+	PIN_FIELD16(49, 49, 0xb20, 0x10, 12, 1),
+	PINS_FIELD16(50, 52, 0xb20, 0x10, 13, 1),
+	PINS_FIELD16(53, 56, 0xb20, 0x10, 14, 1),
+	PINS_FIELD16(57, 58, 0xb20, 0x10, 15, 1),
+	PIN_FIELD16(59, 59, 0xb30, 0x10, 10, 1),
+	PINS_FIELD16(60, 62, 0xb30, 0x10, 0, 1),
+	PINS_FIELD16(63, 65, 0xb30, 0x10, 1, 1),
+	PINS_FIELD16(66, 71, 0xb30, 0x10, 2, 1),
+	PINS_FIELD16(72, 74, 0xb20, 0x10, 12, 1),
+	PINS_FIELD16(75, 76, 0xb30, 0x10, 3, 1),
+	PINS_FIELD16(77, 78, 0xb30, 0x10, 4, 1),
+	PINS_FIELD16(79, 82, 0xb30, 0x10, 5, 1),
+	PINS_FIELD16(83, 84, 0xb30, 0x10, 2, 1),
+	PIN_FIELD16(85, 85, 0xda0, 0x10, 4, 1),
+	PIN_FIELD16(86, 86, 0xd90, 0x10, 4, 1),
+	PINS_FIELD16(87, 90, 0xdb0, 0x10, 4, 1),
+	PINS_FIELD16(101, 104, 0xb30, 0x10, 6, 1),
+	PIN_FIELD16(105, 105, 0xd40, 0x10, 4, 1),
+	PIN_FIELD16(106, 106, 0xd30, 0x10, 4, 1),
+	PINS_FIELD16(107, 110, 0xd50, 0x10, 4, 1),
+	PINS_FIELD16(111, 115, 0xce0, 0x10, 4, 1),
+	PIN_FIELD16(116, 116, 0xcd0, 0x10, 4, 1),
+	PIN_FIELD16(117, 117, 0xcc0, 0x10, 4, 1),
+	PINS_FIELD16(118, 121, 0xce0, 0x10, 4, 1),
+	PINS_FIELD16(122, 125, 0xb30, 0x10, 7, 1),
+	PIN_FIELD16(126, 126, 0xb20, 0x10, 12, 1),
+	PINS_FIELD16(127, 142, 0xb30, 0x10, 9, 1),
+	PINS_FIELD16(143, 160, 0xb30, 0x10, 10, 1),
+	PINS_FIELD16(161, 168, 0xb30, 0x10, 12, 1),
+	PINS_FIELD16(169, 183, 0xb30, 0x10, 10, 1),
+	PINS_FIELD16(184, 186, 0xb30, 0x10, 9, 1),
+	PIN_FIELD16(187, 187, 0xb30, 0x10, 14, 1),
+	PIN_FIELD16(188, 188, 0xb20, 0x10, 13, 1),
+	PINS_FIELD16(189, 193, 0xb30, 0x10, 15, 1),
+	PINS_FIELD16(194, 198, 0xb40, 0x10, 0, 1),
+	PIN_FIELD16(199, 199, 0xb20, 0x10, 1, 1),
+	PINS_FIELD16(200, 202, 0xb40, 0x10, 1, 1),
+	PINS_FIELD16(203, 207, 0xb40, 0x10, 2, 1),
+	PINS_FIELD16(208, 209, 0xb40, 0x10, 3, 1),
+	PIN_FIELD16(210, 210, 0xb40, 0x10, 4, 1),
+	PINS_FIELD16(211, 235, 0xb40, 0x10, 5, 1),
+	PINS_FIELD16(236, 241, 0xb40, 0x10, 6, 1),
+	PINS_FIELD16(242, 243, 0xb40, 0x10, 7, 1),
+	PINS_FIELD16(244, 247, 0xb40, 0x10, 8, 1),
+	PIN_FIELD16(248, 248, 0xb40, 0x10, 9, 1),
+	PINS_FIELD16(249, 257, 0xfc0, 0x10, 4, 1),
+	PIN_FIELD16(258, 258, 0xcb0, 0x10, 4, 1),
+	PIN_FIELD16(259, 259, 0xc90, 0x10, 4, 1),
+	PIN_FIELD16(260, 260, 0x3a0, 0x10, 4, 1),
+	PIN_FIELD16(261, 261, 0xd50, 0x10, 4, 1),
+	PINS_FIELD16(262, 277, 0xb40, 0x10, 12, 1),
+	PIN_FIELD16(278, 278, 0xb40, 0x10, 13, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_smt_range[] = {
+	PINS_FIELD16(0, 6, 0xb50, 0x10, 0, 1),
+	PINS_FIELD16(7, 9, 0xb50, 0x10, 1, 1),
+	PINS_FIELD16(10, 13, 0xb60, 0x10, 3, 1),
+	PINS_FIELD16(14, 15, 0xb60, 0x10, 13, 1),
+	PINS_FIELD16(16, 17, 0xb70, 0x10, 7, 1),
+	PINS_FIELD16(18, 29, 0xb70, 0x10, 13, 1),
+	PINS_FIELD16(30, 32, 0xb70, 0x10, 7, 1),
+	PINS_FIELD16(33, 37, 0xb70, 0x10, 13, 1),
+	PIN_FIELD16(38, 38, 0xb50, 0x10, 13, 1),
+	PINS_FIELD16(39, 42, 0xb70, 0x10, 13, 1),
+	PINS_FIELD16(43, 45, 0xb50, 0x10, 10, 1),
+	PINS_FIELD16(47, 48, 0xb50, 0x10, 11, 1),
+	PIN_FIELD16(49, 49, 0xb50, 0x10, 12, 1),
+	PINS_FIELD16(50, 52, 0xb50, 0x10, 13, 1),
+	PINS_FIELD16(53, 56, 0xb50, 0x10, 14, 1),
+	PINS_FIELD16(57, 58, 0xb50, 0x10, 15, 1),
+	PIN_FIELD16(59, 59, 0xb60, 0x10, 10, 1),
+	PINS_FIELD16(60, 62, 0xb60, 0x10, 0, 1),
+	PINS_FIELD16(63, 65, 0xb60, 0x10, 1, 1),
+	PINS_FIELD16(66, 71, 0xb60, 0x10, 2, 1),
+	PINS_FIELD16(72, 74, 0xb50, 0x10, 12, 1),
+	PINS_FIELD16(75, 76, 0xb60, 0x10, 3, 1),
+	PINS_FIELD16(77, 78, 0xb60, 0x10, 4, 1),
+	PINS_FIELD16(79, 82, 0xb60, 0x10, 5, 1),
+	PINS_FIELD16(83, 84, 0xb60, 0x10, 2, 1),
+	PIN_FIELD16(85, 85, 0xda0, 0x10, 11, 1),
+	PIN_FIELD16(86, 86, 0xd90, 0x10, 11, 1),
+	PIN_FIELD16(87, 87, 0xdc0, 0x10, 3, 1),
+	PIN_FIELD16(88, 88, 0xdc0, 0x10, 7, 1),
+	PIN_FIELD16(89, 89, 0xdc0, 0x10, 11, 1),
+	PIN_FIELD16(90, 90, 0xdc0, 0x10, 15, 1),
+	PINS_FIELD16(101, 104, 0xb60, 0x10, 6, 1),
+	PIN_FIELD16(105, 105, 0xd40, 0x10, 11, 1),
+	PIN_FIELD16(106, 106, 0xd30, 0x10, 11, 1),
+	PIN_FIELD16(107, 107, 0xd60, 0x10, 3, 1),
+	PIN_FIELD16(108, 108, 0xd60, 0x10, 7, 1),
+	PIN_FIELD16(109, 109, 0xd60, 0x10, 11, 1),
+	PIN_FIELD16(110, 110, 0xd60, 0x10, 15, 1),
+	PIN_FIELD16(111, 111, 0xd00, 0x10, 15, 1),
+	PIN_FIELD16(112, 112, 0xd00, 0x10, 11, 1),
+	PIN_FIELD16(113, 113, 0xd00, 0x10, 7, 1),
+	PIN_FIELD16(114, 114, 0xd00, 0x10, 3, 1),
+	PIN_FIELD16(115, 115, 0xd10, 0x10, 3, 1),
+	PIN_FIELD16(116, 116, 0xcd0, 0x10, 11, 1),
+	PIN_FIELD16(117, 117, 0xcc0, 0x10, 11, 1),
+	PIN_FIELD16(118, 118, 0xcf0, 0x10, 15, 1),
+	PIN_FIELD16(119, 119, 0xcf0, 0x10, 7, 1),
+	PIN_FIELD16(120, 120, 0xcf0, 0x10, 3, 1),
+	PIN_FIELD16(121, 121, 0xcf0, 0x10, 7, 1),
+	PINS_FIELD16(122, 125, 0xb60, 0x10, 7, 1),
+	PIN_FIELD16(126, 126, 0xb50, 0x10, 12, 1),
+	PINS_FIELD16(127, 142, 0xb60, 0x10, 9, 1),
+	PINS_FIELD16(143, 160, 0xb60, 0x10, 10, 1),
+	PINS_FIELD16(161, 168, 0xb60, 0x10, 12, 1),
+	PINS_FIELD16(169, 183, 0xb60, 0x10, 10, 1),
+	PINS_FIELD16(184, 186, 0xb60, 0x10, 9, 1),
+	PIN_FIELD16(187, 187, 0xb60, 0x10, 14, 1),
+	PIN_FIELD16(188, 188, 0xb50, 0x10, 13, 1),
+	PINS_FIELD16(189, 193, 0xb60, 0x10, 15, 1),
+	PINS_FIELD16(194, 198, 0xb70, 0x10, 0, 1),
+	PIN_FIELD16(199, 199, 0xb50, 0x10, 1, 1),
+	PINS_FIELD16(200, 202, 0xb70, 0x10, 1, 1),
+	PINS_FIELD16(203, 207, 0xb70, 0x10, 2, 1),
+	PINS_FIELD16(208, 209, 0xb70, 0x10, 3, 1),
+	PIN_FIELD16(210, 210, 0xb70, 0x10, 4, 1),
+	PINS_FIELD16(211, 235, 0xb70, 0x10, 5, 1),
+	PINS_FIELD16(236, 241, 0xb70, 0x10, 6, 1),
+	PINS_FIELD16(242, 243, 0xb70, 0x10, 7, 1),
+	PINS_FIELD16(244, 247, 0xb70, 0x10, 8, 1),
+	PIN_FIELD16(248, 248, 0xb70, 0x10, 9, 10),
+	PIN_FIELD16(249, 249, 0x140, 0x10, 3, 1),
+	PIN_FIELD16(250, 250, 0x130, 0x10, 15, 1),
+	PIN_FIELD16(251, 251, 0x130, 0x10, 11, 1),
+	PIN_FIELD16(252, 252, 0x130, 0x10, 7, 1),
+	PIN_FIELD16(253, 253, 0x130, 0x10, 3, 1),
+	PIN_FIELD16(254, 254, 0xf40, 0x10, 15, 1),
+	PIN_FIELD16(255, 255, 0xf40, 0x10, 11, 1),
+	PIN_FIELD16(256, 256, 0xf40, 0x10, 7, 1),
+	PIN_FIELD16(257, 257, 0xf40, 0x10, 3, 1),
+	PIN_FIELD16(258, 258, 0xcb0, 0x10, 11, 1),
+	PIN_FIELD16(259, 259, 0xc90, 0x10, 11, 1),
+	PIN_FIELD16(260, 260, 0x3a0, 0x10, 11, 1),
+	PIN_FIELD16(261, 261, 0x0b0, 0x10, 3, 1),
+	PINS_FIELD16(262, 277, 0xb70, 0x10, 12, 1),
+	PIN_FIELD16(278, 278, 0xb70, 0x10, 13, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_pullen_range[] = {
+	PIN_FIELD16(0, 278, 0x150, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_pullsel_range[] = {
+	PIN_FIELD16(0, 278, 0x280, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7623_pin_drv_range[] = {
+	PINS_FIELD16(0, 6, 0xf50, 0x10, 0, 4),
+	PINS_FIELD16(7, 9, 0xf50, 0x10, 4, 4),
+	PINS_FIELD16(10, 13, 0xf50, 0x10, 4, 4),
+	PINS_FIELD16(14, 15, 0xf50, 0x10, 12, 4),
+	PINS_FIELD16(16, 17, 0xf60, 0x10, 0, 4),
+	PINS_FIELD16(18, 21, 0xf60, 0x10, 0, 4),
+	PINS_FIELD16(22, 26, 0xf60, 0x10, 8, 4),
+	PINS_FIELD16(27, 29, 0xf60, 0x10, 12, 4),
+	PINS_FIELD16(30, 32, 0xf60, 0x10, 0, 4),
+	PINS_FIELD16(33, 37, 0xf70, 0x10, 0, 4),
+	PIN_FIELD16(38, 38, 0xf70, 0x10, 4, 4),
+	PINS_FIELD16(39, 42, 0xf70, 0x10, 8, 4),
+	PINS_FIELD16(43, 45, 0xf70, 0x10, 12, 4),
+	PINS_FIELD16(47, 48, 0xf80, 0x10, 0, 4),
+	PIN_FIELD16(49, 49, 0xf80, 0x10, 4, 4),
+	PINS_FIELD16(50, 52, 0xf70, 0x10, 4, 4),
+	PINS_FIELD16(53, 56, 0xf80, 0x10, 12, 4),
+	PINS_FIELD16(60, 62, 0xf90, 0x10, 8, 4),
+	PINS_FIELD16(63, 65, 0xf90, 0x10, 12, 4),
+	PINS_FIELD16(66, 71, 0xfa0, 0x10, 0, 4),
+	PINS_FIELD16(72, 74, 0xf80, 0x10, 4, 4),
+	PIN_FIELD16(85, 85, 0xda0, 0x10, 0, 4),
+	PIN_FIELD16(86, 86, 0xd90, 0x10, 0, 4),
+	PINS_FIELD16(87, 90, 0xdb0, 0x10, 0, 4),
+	PIN_FIELD16(105, 105, 0xd40, 0x10, 0, 4),
+	PIN_FIELD16(106, 106, 0xd30, 0x10, 0, 4),
+	PINS_FIELD16(107, 110, 0xd50, 0x10, 0, 4),
+	PINS_FIELD16(111, 115, 0xce0, 0x10, 0, 4),
+	PIN_FIELD16(116, 116, 0xcd0, 0x10, 0, 4),
+	PIN_FIELD16(117, 117, 0xcc0, 0x10, 0, 4),
+	PINS_FIELD16(118, 121, 0xce0, 0x10, 0, 4),
+	PIN_FIELD16(126, 126, 0xf80, 0x10, 4, 4),
+	PIN_FIELD16(188, 188, 0xf70, 0x10, 4, 4),
+	PINS_FIELD16(189, 193, 0xfe0, 0x10, 8, 4),
+	PINS_FIELD16(194, 198, 0xfe0, 0x10, 12, 4),
+	PIN_FIELD16(199, 199, 0xf50, 0x10, 4, 4),
+	PINS_FIELD16(200, 202, 0xfd0, 0x10, 0, 4),
+	PINS_FIELD16(203, 207, 0xfd0, 0x10, 4, 4),
+	PINS_FIELD16(208, 209, 0xfd0, 0x10, 8, 4),
+	PIN_FIELD16(210, 210, 0xfd0, 0x10, 12, 4),
+	PINS_FIELD16(211, 235, 0xff0, 0x10, 0, 4),
+	PINS_FIELD16(236, 241, 0xff0, 0x10, 4, 4),
+	PINS_FIELD16(242, 243, 0xff0, 0x10, 8, 4),
+	PIN_FIELD16(248, 248, 0xf00, 0x10, 0, 4),
+	PINS_FIELD16(249, 256, 0xfc0, 0x10, 0, 4),
+	PIN_FIELD16(257, 257, 0xce0, 0x10, 0, 4),
+	PIN_FIELD16(258, 258, 0xcb0, 0x10, 0, 4),
+	PIN_FIELD16(259, 259, 0xc90, 0x10, 0, 4),
+	PIN_FIELD16(260, 260, 0x3a0, 0x10, 0, 4),
+	PIN_FIELD16(261, 261, 0xd50, 0x10, 0, 4),
+	PINS_FIELD16(262, 277, 0xf00, 0x10, 8, 4),
+	PIN_FIELD16(278, 278, 0xf70, 0x10, 8, 4),
+};
+
+static const struct mtk_pin_reg_calc mt7623_reg_cals[] = {
+	[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7623_pin_mode_range),
+	[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7623_pin_dir_range),
+	[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7623_pin_di_range),
+	[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7623_pin_do_range),
+	[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7623_pin_ies_range),
+	[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7623_pin_smt_range),
+	[PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7623_pin_pullsel_range),
+	[PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7623_pin_pullen_range),
+	[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7623_pin_drv_range),
+};
+
+static const struct mtk_pin_desc mt7623_pins[] = {
+	MTK_PIN(0, "PWRAP_SPI0_MI", DRV_GRP3),
+	MTK_PIN(1, "PWRAP_SPI0_MO", DRV_GRP3),
+	MTK_PIN(2, "PWRAP_INT", DRV_GRP3),
+	MTK_PIN(3, "PWRAP_SPI0_CK", DRV_GRP3),
+	MTK_PIN(4, "PWRAP_SPI0_CSN", DRV_GRP3),
+	MTK_PIN(5, "PWRAP_SPI0_CK2", DRV_GRP3),
+	MTK_PIN(6, "PWRAP_SPI0_CSN2", DRV_GRP3),
+	MTK_PIN(7, "SPI1_CSN", DRV_GRP3),
+	MTK_PIN(8, "SPI1_MI", DRV_GRP3),
+	MTK_PIN(9, "SPI1_MO", DRV_GRP3),
+	MTK_PIN(10, "RTC32K_CK", DRV_GRP3),
+	MTK_PIN(11, "WATCHDOG", DRV_GRP3),
+	MTK_PIN(12, "SRCLKENA", DRV_GRP3),
+	MTK_PIN(13, "SRCLKENAI", DRV_GRP3),
+	MTK_PIN(14, "URXD2", DRV_GRP1),
+	MTK_PIN(15, "UTXD2", DRV_GRP1),
+	MTK_PIN(16, "I2S5_DATA_IN", DRV_GRP1),
+	MTK_PIN(17, "I2S5_BCK", DRV_GRP1),
+	MTK_PIN(18, "PCM_CLK", DRV_GRP1),
+	MTK_PIN(19, "PCM_SYNC", DRV_GRP1),
+	MTK_PIN(20, "PCM_RX", DRV_GRP1),
+	MTK_PIN(21, "PCM_TX", DRV_GRP1),
+	MTK_PIN(22, "EINT0", DRV_GRP1),
+	MTK_PIN(23, "EINT1", DRV_GRP1),
+	MTK_PIN(24, "EINT2", DRV_GRP1),
+	MTK_PIN(25, "EINT3", DRV_GRP1),
+	MTK_PIN(26, "EINT4", DRV_GRP1),
+	MTK_PIN(27, "EINT5", DRV_GRP1),
+	MTK_PIN(28, "EINT6", DRV_GRP1),
+	MTK_PIN(29, "EINT7", DRV_GRP1),
+	MTK_PIN(30, "I2S5_LRCK", DRV_GRP1),
+	MTK_PIN(31, "I2S5_MCLK", DRV_GRP1),
+	MTK_PIN(32, "I2S5_DATA", DRV_GRP1),
+	MTK_PIN(33, "I2S1_DATA", DRV_GRP1),
+	MTK_PIN(34, "I2S1_DATA_IN", DRV_GRP1),
+	MTK_PIN(35, "I2S1_BCK", DRV_GRP1),
+	MTK_PIN(36, "I2S1_LRCK", DRV_GRP1),
+	MTK_PIN(37, "I2S1_MCLK", DRV_GRP1),
+	MTK_PIN(38, "I2S2_DATA", DRV_GRP1),
+	MTK_PIN(39, "JTMS", DRV_GRP3),
+	MTK_PIN(40, "JTCK", DRV_GRP3),
+	MTK_PIN(41, "JTDI", DRV_GRP3),
+	MTK_PIN(42, "JTDO", DRV_GRP3),
+	MTK_PIN(43, "NCLE", DRV_GRP1),
+	MTK_PIN(44, "NCEB1", DRV_GRP1),
+	MTK_PIN(45, "NCEB0", DRV_GRP1),
+	MTK_PIN(46, "IR", DRV_FIXED),
+	MTK_PIN(47, "NREB", DRV_GRP1),
+	MTK_PIN(48, "NRNB", DRV_GRP1),
+	MTK_PIN(49, "I2S0_DATA", DRV_GRP1),
+	MTK_PIN(50, "I2S2_BCK", DRV_GRP1),
+	MTK_PIN(51, "I2S2_DATA_IN", DRV_GRP1),
+	MTK_PIN(52, "I2S2_LRCK", DRV_GRP1),
+	MTK_PIN(53, "SPI0_CSN", DRV_GRP1),
+	MTK_PIN(54, "SPI0_CK", DRV_GRP1),
+	MTK_PIN(55, "SPI0_MI", DRV_GRP1),
+	MTK_PIN(56, "SPI0_MO", DRV_GRP1),
+	MTK_PIN(57, "SDA1", DRV_FIXED),
+	MTK_PIN(58, "SCL1", DRV_FIXED),
+	MTK_PIN(59, "RAMBUF_I_CLK", DRV_FIXED),
+	MTK_PIN(60, "WB_RSTB", DRV_GRP3),
+	MTK_PIN(61, "F2W_DATA", DRV_GRP3),
+	MTK_PIN(62, "F2W_CLK", DRV_GRP3),
+	MTK_PIN(63, "WB_SCLK", DRV_GRP3),
+	MTK_PIN(64, "WB_SDATA", DRV_GRP3),
+	MTK_PIN(65, "WB_SEN", DRV_GRP3),
+	MTK_PIN(66, "WB_CRTL0", DRV_GRP3),
+	MTK_PIN(67, "WB_CRTL1", DRV_GRP3),
+	MTK_PIN(68, "WB_CRTL2", DRV_GRP3),
+	MTK_PIN(69, "WB_CRTL3", DRV_GRP3),
+	MTK_PIN(70, "WB_CRTL4", DRV_GRP3),
+	MTK_PIN(71, "WB_CRTL5", DRV_GRP3),
+	MTK_PIN(72, "I2S0_DATA_IN", DRV_GRP1),
+	MTK_PIN(73, "I2S0_LRCK", DRV_GRP1),
+	MTK_PIN(74, "I2S0_BCK", DRV_GRP1),
+	MTK_PIN(75, "SDA0", DRV_FIXED),
+	MTK_PIN(76, "SCL0", DRV_FIXED),
+	MTK_PIN(77, "SDA2", DRV_FIXED),
+	MTK_PIN(78, "SCL2", DRV_FIXED),
+	MTK_PIN(79, "URXD0", DRV_FIXED),
+	MTK_PIN(80, "UTXD0", DRV_FIXED),
+	MTK_PIN(81, "URXD1", DRV_FIXED),
+	MTK_PIN(82, "UTXD1", DRV_FIXED),
+	MTK_PIN(83, "LCM_RST", DRV_FIXED),
+	MTK_PIN(84, "DSI_TE", DRV_FIXED),
+	MTK_PIN(85, "MSDC2_CMD", DRV_GRP4),
+	MTK_PIN(86, "MSDC2_CLK", DRV_GRP4),
+	MTK_PIN(87, "MSDC2_DAT0", DRV_GRP4),
+	MTK_PIN(88, "MSDC2_DAT1", DRV_GRP4),
+	MTK_PIN(89, "MSDC2_DAT2", DRV_GRP4),
+	MTK_PIN(90, "MSDC2_DAT3", DRV_GRP4),
+	MTK_PIN(91, "TDN3", DRV_FIXED),
+	MTK_PIN(92, "TDP3", DRV_FIXED),
+	MTK_PIN(93, "TDN2", DRV_FIXED),
+	MTK_PIN(94, "TDP2", DRV_FIXED),
+	MTK_PIN(95, "TCN", DRV_FIXED),
+	MTK_PIN(96, "TCP", DRV_FIXED),
+	MTK_PIN(97, "TDN1", DRV_FIXED),
+	MTK_PIN(98, "TDP1", DRV_FIXED),
+	MTK_PIN(99, "TDN0", DRV_FIXED),
+	MTK_PIN(100, "TDP0", DRV_FIXED),
+	MTK_PIN(101, "SPI2_CSN", DRV_FIXED),
+	MTK_PIN(102, "SPI2_MI", DRV_FIXED),
+	MTK_PIN(103, "SPI2_MO", DRV_FIXED),
+	MTK_PIN(104, "SPI2_CLK", DRV_FIXED),
+	MTK_PIN(105, "MSDC1_CMD", DRV_GRP4),
+	MTK_PIN(106, "MSDC1_CLK", DRV_GRP4),
+	MTK_PIN(107, "MSDC1_DAT0", DRV_GRP4),
+	MTK_PIN(108, "MSDC1_DAT1", DRV_GRP4),
+	MTK_PIN(109, "MSDC1_DAT2", DRV_GRP4),
+	MTK_PIN(110, "MSDC1_DAT3", DRV_GRP4),
+	MTK_PIN(111, "MSDC0_DAT7", DRV_GRP4),
+	MTK_PIN(112, "MSDC0_DAT6", DRV_GRP4),
+	MTK_PIN(113, "MSDC0_DAT5", DRV_GRP4),
+	MTK_PIN(114, "MSDC0_DAT4", DRV_GRP4),
+	MTK_PIN(115, "MSDC0_RSTB", DRV_GRP4),
+	MTK_PIN(116, "MSDC0_CMD", DRV_GRP4),
+	MTK_PIN(117, "MSDC0_CLK", DRV_GRP4),
+	MTK_PIN(118, "MSDC0_DAT3", DRV_GRP4),
+	MTK_PIN(119, "MSDC0_DAT2", DRV_GRP4),
+	MTK_PIN(120, "MSDC0_DAT1", DRV_GRP4),
+	MTK_PIN(121, "MSDC0_DAT0", DRV_GRP4),
+	MTK_PIN(122, "CEC", DRV_FIXED),
+	MTK_PIN(123, "HTPLG", DRV_FIXED),
+	MTK_PIN(124, "HDMISCK", DRV_FIXED),
+	MTK_PIN(125, "HDMISD", DRV_FIXED),
+	MTK_PIN(126, "I2S0_MCLK", DRV_GRP1),
+	MTK_PIN(127, "RAMBUF_IDATA0", DRV_FIXED),
+	MTK_PIN(128, "RAMBUF_IDATA1", DRV_FIXED),
+	MTK_PIN(129, "RAMBUF_IDATA2", DRV_FIXED),
+	MTK_PIN(130, "RAMBUF_IDATA3", DRV_FIXED),
+	MTK_PIN(131, "RAMBUF_IDATA4", DRV_FIXED),
+	MTK_PIN(132, "RAMBUF_IDATA5", DRV_FIXED),
+	MTK_PIN(133, "RAMBUF_IDATA6", DRV_FIXED),
+	MTK_PIN(134, "RAMBUF_IDATA7", DRV_FIXED),
+	MTK_PIN(135, "RAMBUF_IDATA8", DRV_FIXED),
+	MTK_PIN(136, "RAMBUF_IDATA9", DRV_FIXED),
+	MTK_PIN(137, "RAMBUF_IDATA10", DRV_FIXED),
+	MTK_PIN(138, "RAMBUF_IDATA11", DRV_FIXED),
+	MTK_PIN(139, "RAMBUF_IDATA12", DRV_FIXED),
+	MTK_PIN(140, "RAMBUF_IDATA13", DRV_FIXED),
+	MTK_PIN(141, "RAMBUF_IDATA14", DRV_FIXED),
+	MTK_PIN(142, "RAMBUF_IDATA15", DRV_FIXED),
+	MTK_PIN(143, "RAMBUF_ODATA0", DRV_FIXED),
+	MTK_PIN(144, "RAMBUF_ODATA1", DRV_FIXED),
+	MTK_PIN(145, "RAMBUF_ODATA2", DRV_FIXED),
+	MTK_PIN(146, "RAMBUF_ODATA3", DRV_FIXED),
+	MTK_PIN(147, "RAMBUF_ODATA4", DRV_FIXED),
+	MTK_PIN(148, "RAMBUF_ODATA5", DRV_FIXED),
+	MTK_PIN(149, "RAMBUF_ODATA6", DRV_FIXED),
+	MTK_PIN(150, "RAMBUF_ODATA7", DRV_FIXED),
+	MTK_PIN(151, "RAMBUF_ODATA8", DRV_FIXED),
+	MTK_PIN(152, "RAMBUF_ODATA9", DRV_FIXED),
+	MTK_PIN(153, "RAMBUF_ODATA10", DRV_FIXED),
+	MTK_PIN(154, "RAMBUF_ODATA11", DRV_FIXED),
+	MTK_PIN(155, "RAMBUF_ODATA12", DRV_FIXED),
+	MTK_PIN(156, "RAMBUF_ODATA13", DRV_FIXED),
+	MTK_PIN(157, "RAMBUF_ODATA14", DRV_FIXED),
+	MTK_PIN(158, "RAMBUF_ODATA15", DRV_FIXED),
+	MTK_PIN(159, "RAMBUF_BE0", DRV_FIXED),
+	MTK_PIN(160, "RAMBUF_BE1", DRV_FIXED),
+	MTK_PIN(161, "AP2PT_INT", DRV_FIXED),
+	MTK_PIN(162, "AP2PT_INT_CLR", DRV_FIXED),
+	MTK_PIN(163, "PT2AP_INT", DRV_FIXED),
+	MTK_PIN(164, "PT2AP_INT_CLR", DRV_FIXED),
+	MTK_PIN(165, "AP2UP_INT", DRV_FIXED),
+	MTK_PIN(166, "AP2UP_INT_CLR", DRV_FIXED),
+	MTK_PIN(167, "UP2AP_INT", DRV_FIXED),
+	MTK_PIN(168, "UP2AP_INT_CLR", DRV_FIXED),
+	MTK_PIN(169, "RAMBUF_ADDR0", DRV_FIXED),
+	MTK_PIN(170, "RAMBUF_ADDR1", DRV_FIXED),
+	MTK_PIN(171, "RAMBUF_ADDR2", DRV_FIXED),
+	MTK_PIN(172, "RAMBUF_ADDR3", DRV_FIXED),
+	MTK_PIN(173, "RAMBUF_ADDR4", DRV_FIXED),
+	MTK_PIN(174, "RAMBUF_ADDR5", DRV_FIXED),
+	MTK_PIN(175, "RAMBUF_ADDR6", DRV_FIXED),
+	MTK_PIN(176, "RAMBUF_ADDR7", DRV_FIXED),
+	MTK_PIN(177, "RAMBUF_ADDR8", DRV_FIXED),
+	MTK_PIN(178, "RAMBUF_ADDR9", DRV_FIXED),
+	MTK_PIN(179, "RAMBUF_ADDR10", DRV_FIXED),
+	MTK_PIN(180, "RAMBUF_RW", DRV_FIXED),
+	MTK_PIN(181, "RAMBUF_LAST", DRV_FIXED),
+	MTK_PIN(182, "RAMBUF_HP", DRV_FIXED),
+	MTK_PIN(183, "RAMBUF_REQ", DRV_FIXED),
+	MTK_PIN(184, "RAMBUF_ALE", DRV_FIXED),
+	MTK_PIN(185, "RAMBUF_DLE", DRV_FIXED),
+	MTK_PIN(186, "RAMBUF_WDLE", DRV_FIXED),
+	MTK_PIN(187, "RAMBUF_O_CLK", DRV_FIXED),
+	MTK_PIN(188, "I2S2_MCLK", DRV_GRP1),
+	MTK_PIN(189, "I2S3_DATA", DRV_GRP1),
+	MTK_PIN(190, "I2S3_DATA_IN", DRV_GRP1),
+	MTK_PIN(191, "I2S3_BCK", DRV_GRP1),
+	MTK_PIN(192, "I2S3_LRCK", DRV_GRP1),
+	MTK_PIN(193, "I2S3_MCLK", DRV_GRP1),
+	MTK_PIN(194, "I2S4_DATA", DRV_GRP1),
+	MTK_PIN(195, "I2S4_DATA_IN", DRV_GRP1),
+	MTK_PIN(196, "I2S4_BCK", DRV_GRP1),
+	MTK_PIN(197, "I2S4_LRCK", DRV_GRP1),
+	MTK_PIN(198, "I2S4_MCLK", DRV_GRP1),
+	MTK_PIN(199, "SPI1_CLK", DRV_GRP3),
+	MTK_PIN(200, "SPDIF_OUT", DRV_GRP1),
+	MTK_PIN(201, "SPDIF_IN0", DRV_GRP1),
+	MTK_PIN(202, "SPDIF_IN1", DRV_GRP1),
+	MTK_PIN(203, "PWM0", DRV_GRP1),
+	MTK_PIN(204, "PWM1", DRV_GRP1),
+	MTK_PIN(205, "PWM2", DRV_GRP1),
+	MTK_PIN(206, "PWM3", DRV_GRP1),
+	MTK_PIN(207, "PWM4", DRV_GRP1),
+	MTK_PIN(208, "AUD_EXT_CK1", DRV_GRP1),
+	MTK_PIN(209, "AUD_EXT_CK2", DRV_GRP1),
+	MTK_PIN(210, "AUD_CLOCK", DRV_GRP3),
+	MTK_PIN(211, "DVP_RESET", DRV_GRP3),
+	MTK_PIN(212, "DVP_CLOCK", DRV_GRP3),
+	MTK_PIN(213, "DVP_CS", DRV_GRP3),
+	MTK_PIN(214, "DVP_CK", DRV_GRP3),
+	MTK_PIN(215, "DVP_DI", DRV_GRP3),
+	MTK_PIN(216, "DVP_DO", DRV_GRP3),
+	MTK_PIN(217, "AP_CS", DRV_GRP3),
+	MTK_PIN(218, "AP_CK", DRV_GRP3),
+	MTK_PIN(219, "AP_DI", DRV_GRP3),
+	MTK_PIN(220, "AP_DO", DRV_GRP3),
+	MTK_PIN(221, "DVD_BCLK", DRV_GRP3),
+	MTK_PIN(222, "T8032_CLK", DRV_GRP3),
+	MTK_PIN(223, "AP_BCLK", DRV_GRP3),
+	MTK_PIN(224, "HOST_CS", DRV_GRP3),
+	MTK_PIN(225, "HOST_CK", DRV_GRP3),
+	MTK_PIN(226, "HOST_DO0", DRV_GRP3),
+	MTK_PIN(227, "HOST_DO1", DRV_GRP3),
+	MTK_PIN(228, "SLV_CS", DRV_GRP3),
+	MTK_PIN(229, "SLV_CK", DRV_GRP3),
+	MTK_PIN(230, "SLV_DI0", DRV_GRP3),
+	MTK_PIN(231, "SLV_DI1", DRV_GRP3),
+	MTK_PIN(232, "AP2DSP_INT", DRV_GRP3),
+	MTK_PIN(233, "AP2DSP_INT_CLR", DRV_GRP3),
+	MTK_PIN(234, "DSP2AP_INT", DRV_GRP3),
+	MTK_PIN(235, "DSP2AP_INT_CLR", DRV_GRP3),
+	MTK_PIN(236, "EXT_SDIO3", DRV_GRP1),
+	MTK_PIN(237, "EXT_SDIO2", DRV_GRP1),
+	MTK_PIN(238, "EXT_SDIO1", DRV_GRP1),
+	MTK_PIN(239, "EXT_SDIO0", DRV_GRP1),
+	MTK_PIN(240, "EXT_XCS", DRV_GRP1),
+	MTK_PIN(241, "EXT_SCK", DRV_GRP1),
+	MTK_PIN(242, "URTS2", DRV_GRP1),
+	MTK_PIN(243, "UCTS2", DRV_GRP1),
+	MTK_PIN(244, "HDMI_SDA_RX", DRV_FIXED),
+	MTK_PIN(245, "HDMI_SCL_RX", DRV_FIXED),
+	MTK_PIN(246, "MHL_SENCE", DRV_FIXED),
+	MTK_PIN(247, "HDMI_HPD_CBUS_RX", DRV_FIXED),
+	MTK_PIN(248, "HDMI_TESTOUTP_RX", DRV_GRP1),
+	MTK_PIN(249, "MSDC0E_RSTB", DRV_GRP4),
+	MTK_PIN(250, "MSDC0E_DAT7", DRV_GRP4),
+	MTK_PIN(251, "MSDC0E_DAT6", DRV_GRP4),
+	MTK_PIN(252, "MSDC0E_DAT5", DRV_GRP4),
+	MTK_PIN(253, "MSDC0E_DAT4", DRV_GRP4),
+	MTK_PIN(254, "MSDC0E_DAT3", DRV_GRP4),
+	MTK_PIN(255, "MSDC0E_DAT2", DRV_GRP4),
+	MTK_PIN(256, "MSDC0E_DAT1", DRV_GRP4),
+	MTK_PIN(257, "MSDC0E_DAT0", DRV_GRP4),
+	MTK_PIN(258, "MSDC0E_CMD", DRV_GRP4),
+	MTK_PIN(259, "MSDC0E_CLK", DRV_GRP4),
+	MTK_PIN(260, "MSDC0E_DSL", DRV_GRP4),
+	MTK_PIN(261, "MSDC1_INS", DRV_GRP4),
+	MTK_PIN(262, "G2_TXEN", DRV_GRP1),
+	MTK_PIN(263, "G2_TXD3", DRV_GRP1),
+	MTK_PIN(264, "G2_TXD2", DRV_GRP1),
+	MTK_PIN(265, "G2_TXD1", DRV_GRP1),
+	MTK_PIN(266, "G2_TXD0", DRV_GRP1),
+	MTK_PIN(267, "G2_TXC", DRV_GRP1),
+	MTK_PIN(268, "G2_RXC", DRV_GRP1),
+	MTK_PIN(269, "G2_RXD0", DRV_GRP1),
+	MTK_PIN(270, "G2_RXD1", DRV_GRP1),
+	MTK_PIN(271, "G2_RXD2", DRV_GRP1),
+	MTK_PIN(272, "G2_RXD3", DRV_GRP1),
+	MTK_PIN(273, "ESW_INT", DRV_GRP1),
+	MTK_PIN(274, "G2_RXDV", DRV_GRP1),
+	MTK_PIN(275, "MDC", DRV_GRP1),
+	MTK_PIN(276, "MDIO", DRV_GRP1),
+	MTK_PIN(277, "ESW_RST", DRV_GRP1),
+	MTK_PIN(278, "JTAG_RESET", DRV_GRP3),
+	MTK_PIN(279, "USB3_RES_BOND", DRV_GRP1),
+};
+
+/* 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.
+ */
+
+/* AUDIO EXT CLK */
+static int mt7623_aud_ext_clk0_pins[] = { 208, };
+static int mt7623_aud_ext_clk0_funcs[] = { 1, };
+static int mt7623_aud_ext_clk1_pins[] = { 209, };
+static int mt7623_aud_ext_clk1_funcs[] = { 1, };
+
+/* DISP PWM */
+static int mt7623_disp_pwm_0_pins[] = { 72, };
+static int mt7623_disp_pwm_0_funcs[] = { 5, };
+static int mt7623_disp_pwm_1_pins[] = { 203, };
+static int mt7623_disp_pwm_1_funcs[] = { 2, };
+static int mt7623_disp_pwm_2_pins[] = { 208, };
+static int mt7623_disp_pwm_2_funcs[] = { 5, };
+
+/* ESW */
+static int mt7623_esw_int_pins[] = { 273, };
+static int mt7623_esw_int_funcs[] = { 1, };
+static int mt7623_esw_rst_pins[] = { 277, };
+static int mt7623_esw_rst_funcs[] = { 1, };
+
+/* EPHY */
+static int mt7623_ephy_pins[] = { 262, 263, 264, 265, 266, 267, 268,
+				  269, 270, 271, 272, 274, };
+static int mt7623_ephy_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* EXT_SDIO */
+static int mt7623_ext_sdio_pins[] = { 236, 237, 238, 239, 240, 241, };
+static int mt7623_ext_sdio_funcs[] = { 1, 1, 1, 1, 1, 1, };
+
+/* HDMI RX */
+static int mt7623_hdmi_rx_pins[] = { 247, 248, };
+static int mt7623_hdmi_rx_funcs[] = { 1, 1 };
+static int mt7623_hdmi_rx_i2c_pins[] = { 244, 245, };
+static int mt7623_hdmi_rx_i2c_funcs[] = { 1, 1 };
+
+/* HDMI TX */
+static int mt7623_hdmi_cec_pins[] = { 122, };
+static int mt7623_hdmi_cec_funcs[] = { 1, };
+static int mt7623_hdmi_htplg_pins[] = { 123, };
+static int mt7623_hdmi_htplg_funcs[] = { 1, };
+static int mt7623_hdmi_i2c_pins[] = { 124, 125, };
+static int mt7623_hdmi_i2c_funcs[] = { 1, 1 };
+
+/* I2C */
+static int mt7623_i2c0_pins[] = { 75, 76, };
+static int mt7623_i2c0_funcs[] = { 1, 1, };
+static int mt7623_i2c1_0_pins[] = { 57, 58, };
+static int mt7623_i2c1_0_funcs[] = { 1, 1, };
+static int mt7623_i2c1_1_pins[] = { 242, 243, };
+static int mt7623_i2c1_1_funcs[] = { 4, 4, };
+static int mt7623_i2c1_2_pins[] = { 85, 86, };
+static int mt7623_i2c1_2_funcs[] = { 3, 3, };
+static int mt7623_i2c1_3_pins[] = { 105, 106, };
+static int mt7623_i2c1_3_funcs[] = { 3, 3, };
+static int mt7623_i2c1_4_pins[] = { 124, 125, };
+static int mt7623_i2c1_4_funcs[] = { 4, 4, };
+static int mt7623_i2c2_0_pins[] = { 77, 78, };
+static int mt7623_i2c2_0_funcs[] = { 1, 1, };
+static int mt7623_i2c2_1_pins[] = { 89, 90, };
+static int mt7623_i2c2_1_funcs[] = { 3, 3, };
+static int mt7623_i2c2_2_pins[] = { 109, 110, };
+static int mt7623_i2c2_2_funcs[] = { 3, 3, };
+static int mt7623_i2c2_3_pins[] = { 122, 123, };
+static int mt7623_i2c2_3_funcs[] = { 4, 4, };
+
+/* I2S */
+static int mt7623_i2s0_pins[] = { 49, 72, 73, 74, 126, };
+static int mt7623_i2s0_funcs[] = { 1, 1, 1, 1, 1, };
+static int mt7623_i2s1_pins[] = { 33, 34, 35, 36, 37, };
+static int mt7623_i2s1_funcs[] = { 1, 1, 1, 1, 1, };
+static int mt7623_i2s2_bclk_lrclk_mclk_pins[] = { 50, 52, 188, };
+static int mt7623_i2s2_bclk_lrclk_mclk_funcs[] = { 1, 1, 1, };
+static int mt7623_i2s2_data_in_pins[] = { 51, };
+static int mt7623_i2s2_data_in_funcs[] = { 1, };
+static int mt7623_i2s2_data_0_pins[] = { 203, };
+static int mt7623_i2s2_data_0_funcs[] = { 9, };
+static int mt7623_i2s2_data_1_pins[] = { 38,  };
+static int mt7623_i2s2_data_1_funcs[] = { 4, };
+static int mt7623_i2s3_bclk_lrclk_mclk_pins[] = { 191, 192, 193, };
+static int mt7623_i2s3_bclk_lrclk_mclk_funcs[] = { 1, 1, 1, };
+static int mt7623_i2s3_data_in_pins[] = { 190, };
+static int mt7623_i2s3_data_in_funcs[] = { 1, };
+static int mt7623_i2s3_data_0_pins[] = { 204, };
+static int mt7623_i2s3_data_0_funcs[] = { 9, };
+static int mt7623_i2s3_data_1_pins[] = { 2, };
+static int mt7623_i2s3_data_1_funcs[] = { 0, };
+static int mt7623_i2s4_pins[] = { 194, 195, 196, 197, 198, };
+static int mt7623_i2s4_funcs[] = { 1, 1, 1, 1, 1, };
+static int mt7623_i2s5_pins[] = { 16, 17, 30, 31, 32, };
+static int mt7623_i2s5_funcs[] = { 1, 1, 1, 1, 1, };
+
+/* IR */
+static int mt7623_ir_pins[] = { 46, };
+static int mt7623_ir_funcs[] = { 1, };
+
+/* LCD */
+static int mt7623_mipi_tx_pins[] = { 91, 92, 93, 94, 95, 96, 97, 98,
+				     99, 100, };
+static int mt7623_mipi_tx_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+static int mt7623_dsi_te_pins[] = { 84, };
+static int mt7623_dsi_te_funcs[] = { 1, };
+static int mt7623_lcm_rst_pins[] = { 83, };
+static int mt7623_lcm_rst_funcs[] = { 1, };
+
+/* MDC/MDIO */
+static int mt7623_mdc_mdio_pins[] = { 275, 276, };
+static int mt7623_mdc_mdio_funcs[] = { 1, 1, };
+
+/* MSDC */
+static int mt7623_msdc0_pins[] = { 111, 112, 113, 114, 115, 116, 117, 118,
+				   119, 120, 121, };
+static int mt7623_msdc0_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+static int mt7623_msdc1_pins[] = { 105, 106, 107, 108, 109, 110, };
+static int mt7623_msdc1_funcs[] = { 1, 1, 1, 1, 1, 1, };
+static int mt7623_msdc1_ins_pins[] = { 261, };
+static int mt7623_msdc1_ins_funcs[] = { 1, };
+static int mt7623_msdc1_wp_0_pins[] = { 29, };
+static int mt7623_msdc1_wp_0_funcs[] = { 1, };
+static int mt7623_msdc1_wp_1_pins[] = { 55, };
+static int mt7623_msdc1_wp_1_funcs[] = { 3, };
+static int mt7623_msdc1_wp_2_pins[] = { 209, };
+static int mt7623_msdc1_wp_2_funcs[] = { 2, };
+static int mt7623_msdc2_pins[] = { 85, 86, 87, 88, 89, 90, };
+static int mt7623_msdc2_funcs[] = { 1, 1, 1, 1, 1, 1, };
+static int mt7623_msdc3_pins[] = { 249, 250, 251, 252, 253, 254, 255, 256,
+				   257, 258, 259, 260, };
+static int mt7623_msdc3_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* NAND */
+static int mt7623_nandc_pins[] = { 43, 47, 48, 111, 112, 113, 114, 115,
+				   116, 117, 118, 119, 120, 121, };
+static int mt7623_nandc_funcs[] = { 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+				   4, 4, };
+static int mt7623_nandc_ceb0_pins[] = { 45, };
+static int mt7623_nandc_ceb0_funcs[] = { 1, };
+static int mt7623_nandc_ceb1_pins[] = { 44, };
+static int mt7623_nandc_ceb1_funcs[] = { 1, };
+
+/* RTC */
+static int mt7623_rtc_pins[] = { 10, };
+static int mt7623_rtc_funcs[] = { 1, };
+
+/* OTG */
+static int mt7623_otg_iddig0_0_pins[] = { 29, };
+static int mt7623_otg_iddig0_0_funcs[] = { 1, };
+static int mt7623_otg_iddig0_1_pins[] = { 44, };
+static int mt7623_otg_iddig0_1_funcs[] = { 2, };
+static int mt7623_otg_iddig0_2_pins[] = { 236, };
+static int mt7623_otg_iddig0_2_funcs[] = { 2, };
+static int mt7623_otg_iddig1_0_pins[] = { 27, };
+static int mt7623_otg_iddig1_0_funcs[] = { 2, };
+static int mt7623_otg_iddig1_1_pins[] = { 47, };
+static int mt7623_otg_iddig1_1_funcs[] = { 2, };
+static int mt7623_otg_iddig1_2_pins[] = { 238, };
+static int mt7623_otg_iddig1_2_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus0_0_pins[] = { 28, };
+static int mt7623_otg_drv_vbus0_0_funcs[] = { 1, };
+static int mt7623_otg_drv_vbus0_1_pins[] = { 45, };
+static int mt7623_otg_drv_vbus0_1_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus0_2_pins[] = { 237, };
+static int mt7623_otg_drv_vbus0_2_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus1_0_pins[] = { 26, };
+static int mt7623_otg_drv_vbus1_0_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus1_1_pins[] = { 48, };
+static int mt7623_otg_drv_vbus1_1_funcs[] = { 2, };
+static int mt7623_otg_drv_vbus1_2_pins[] = { 239, };
+static int mt7623_otg_drv_vbus1_2_funcs[] = { 2, };
+
+/* PCIE */
+static int mt7623_pcie0_0_perst_pins[] = { 208, };
+static int mt7623_pcie0_0_perst_funcs[] = { 3, };
+static int mt7623_pcie0_1_perst_pins[] = { 22, };
+static int mt7623_pcie0_1_perst_funcs[] = { 2, };
+static int mt7623_pcie1_0_perst_pins[] = { 209, };
+static int mt7623_pcie1_0_perst_funcs[] = { 3, };
+static int mt7623_pcie1_1_perst_pins[] = { 23, };
+static int mt7623_pcie1_1_perst_funcs[] = { 2, };
+static int mt7623_pcie2_0_perst_pins[] = { 24, };
+static int mt7623_pcie2_0_perst_funcs[] = { 2, };
+static int mt7623_pcie2_1_perst_pins[] = { 29, };
+static int mt7623_pcie2_1_perst_funcs[] = { 6, };
+static int mt7623_pcie0_0_wake_pins[] = { 28, };
+static int mt7623_pcie0_0_wake_funcs[] = { 6, };
+static int mt7623_pcie0_1_wake_pins[] = { 251, };
+static int mt7623_pcie0_1_wake_funcs[] = { 6, };
+static int mt7623_pcie1_0_wake_pins[] = { 27, };
+static int mt7623_pcie1_0_wake_funcs[] = { 6, };
+static int mt7623_pcie1_1_wake_pins[] = { 253, };
+static int mt7623_pcie1_1_wake_funcs[] = { 6, };
+static int mt7623_pcie2_0_wake_pins[] = { 26, };
+static int mt7623_pcie2_0_wake_funcs[] = { 6, };
+static int mt7623_pcie2_1_wake_pins[] = { 255, };
+static int mt7623_pcie2_1_wake_funcs[] = { 6, };
+static int mt7623_pcie0_clkreq_pins[] = { 250, };
+static int mt7623_pcie0_clkreq_funcs[] = { 6, };
+static int mt7623_pcie1_clkreq_pins[] = { 252, };
+static int mt7623_pcie1_clkreq_funcs[] = { 6, };
+static int mt7623_pcie2_clkreq_pins[] = { 254, };
+static int mt7623_pcie2_clkreq_funcs[] = { 6, };
+/* the pcie_*_rev are only used for MT7623 */
+static int mt7623_pcie0_0_rev_perst_pins[] = { 208, };
+static int mt7623_pcie0_0_rev_perst_funcs[] = { 11, };
+static int mt7623_pcie0_1_rev_perst_pins[] = { 22, };
+static int mt7623_pcie0_1_rev_perst_funcs[] = { 10, };
+static int mt7623_pcie1_0_rev_perst_pins[] = { 209, };
+static int mt7623_pcie1_0_rev_perst_funcs[] = { 11, };
+static int mt7623_pcie1_1_rev_perst_pins[] = { 23, };
+static int mt7623_pcie1_1_rev_perst_funcs[] = { 10, };
+static int mt7623_pcie2_0_rev_perst_pins[] = { 24, };
+static int mt7623_pcie2_0_rev_perst_funcs[] = { 11, };
+static int mt7623_pcie2_1_rev_perst_pins[] = { 29, };
+static int mt7623_pcie2_1_rev_perst_funcs[] = { 14, };
+
+/* PCM */
+static int mt7623_pcm_clk_0_pins[] = { 18, };
+static int mt7623_pcm_clk_0_funcs[] = { 1, };
+static int mt7623_pcm_clk_1_pins[] = { 17, };
+static int mt7623_pcm_clk_1_funcs[] = { 3, };
+static int mt7623_pcm_clk_2_pins[] = { 35, };
+static int mt7623_pcm_clk_2_funcs[] = { 3, };
+static int mt7623_pcm_clk_3_pins[] = { 50, };
+static int mt7623_pcm_clk_3_funcs[] = { 3, };
+static int mt7623_pcm_clk_4_pins[] = { 74, };
+static int mt7623_pcm_clk_4_funcs[] = { 3, };
+static int mt7623_pcm_clk_5_pins[] = { 191, };
+static int mt7623_pcm_clk_5_funcs[] = { 3, };
+static int mt7623_pcm_clk_6_pins[] = { 196, };
+static int mt7623_pcm_clk_6_funcs[] = { 3, };
+static int mt7623_pcm_sync_0_pins[] = { 19, };
+static int mt7623_pcm_sync_0_funcs[] = { 1, };
+static int mt7623_pcm_sync_1_pins[] = { 30, };
+static int mt7623_pcm_sync_1_funcs[] = { 3, };
+static int mt7623_pcm_sync_2_pins[] = { 36, };
+static int mt7623_pcm_sync_2_funcs[] = { 3, };
+static int mt7623_pcm_sync_3_pins[] = { 52, };
+static int mt7623_pcm_sync_3_funcs[] = { 31, };
+static int mt7623_pcm_sync_4_pins[] = { 73, };
+static int mt7623_pcm_sync_4_funcs[] = { 3, };
+static int mt7623_pcm_sync_5_pins[] = { 192, };
+static int mt7623_pcm_sync_5_funcs[] = { 3, };
+static int mt7623_pcm_sync_6_pins[] = { 197, };
+static int mt7623_pcm_sync_6_funcs[] = { 3, };
+static int mt7623_pcm_rx_0_pins[] = { 20, };
+static int mt7623_pcm_rx_0_funcs[] = { 1, };
+static int mt7623_pcm_rx_1_pins[] = { 16, };
+static int mt7623_pcm_rx_1_funcs[] = { 3, };
+static int mt7623_pcm_rx_2_pins[] = { 34, };
+static int mt7623_pcm_rx_2_funcs[] = { 3, };
+static int mt7623_pcm_rx_3_pins[] = { 51, };
+static int mt7623_pcm_rx_3_funcs[] = { 3, };
+static int mt7623_pcm_rx_4_pins[] = { 72, };
+static int mt7623_pcm_rx_4_funcs[] = { 3, };
+static int mt7623_pcm_rx_5_pins[] = { 190, };
+static int mt7623_pcm_rx_5_funcs[] = { 3, };
+static int mt7623_pcm_rx_6_pins[] = { 195, };
+static int mt7623_pcm_rx_6_funcs[] = { 3, };
+static int mt7623_pcm_tx_0_pins[] = { 21, };
+static int mt7623_pcm_tx_0_funcs[] = { 1, };
+static int mt7623_pcm_tx_1_pins[] = { 32, };
+static int mt7623_pcm_tx_1_funcs[] = { 3, };
+static int mt7623_pcm_tx_2_pins[] = { 33, };
+static int mt7623_pcm_tx_2_funcs[] = { 3, };
+static int mt7623_pcm_tx_3_pins[] = { 38, };
+static int mt7623_pcm_tx_3_funcs[] = { 3, };
+static int mt7623_pcm_tx_4_pins[] = { 49, };
+static int mt7623_pcm_tx_4_funcs[] = { 3, };
+static int mt7623_pcm_tx_5_pins[] = { 189, };
+static int mt7623_pcm_tx_5_funcs[] = { 3, };
+static int mt7623_pcm_tx_6_pins[] = { 194, };
+static int mt7623_pcm_tx_6_funcs[] = { 3, };
+
+/* PWM */
+static int mt7623_pwm_ch1_0_pins[] = { 203, };
+static int mt7623_pwm_ch1_0_funcs[] = { 1, };
+static int mt7623_pwm_ch1_1_pins[] = { 208, };
+static int mt7623_pwm_ch1_1_funcs[] = { 2, };
+static int mt7623_pwm_ch1_2_pins[] = { 72, };
+static int mt7623_pwm_ch1_2_funcs[] = { 4, };
+static int mt7623_pwm_ch1_3_pins[] = { 88, };
+static int mt7623_pwm_ch1_3_funcs[] = { 3, };
+static int mt7623_pwm_ch1_4_pins[] = { 108, };
+static int mt7623_pwm_ch1_4_funcs[] = { 3, };
+static int mt7623_pwm_ch2_0_pins[] = { 204, };
+static int mt7623_pwm_ch2_0_funcs[] = { 1, };
+static int mt7623_pwm_ch2_1_pins[] = { 53, };
+static int mt7623_pwm_ch2_1_funcs[] = { 5, };
+static int mt7623_pwm_ch2_2_pins[] = { 88, };
+static int mt7623_pwm_ch2_2_funcs[] = { 6, };
+static int mt7623_pwm_ch2_3_pins[] = { 108, };
+static int mt7623_pwm_ch2_3_funcs[] = { 6, };
+static int mt7623_pwm_ch2_4_pins[] = { 209, };
+static int mt7623_pwm_ch2_4_funcs[] = { 5, };
+static int mt7623_pwm_ch3_0_pins[] = { 205, };
+static int mt7623_pwm_ch3_0_funcs[] = { 1, };
+static int mt7623_pwm_ch3_1_pins[] = { 55, };
+static int mt7623_pwm_ch3_1_funcs[] = { 5, };
+static int mt7623_pwm_ch3_2_pins[] = { 89, };
+static int mt7623_pwm_ch3_2_funcs[] = { 6, };
+static int mt7623_pwm_ch3_3_pins[] = { 109, };
+static int mt7623_pwm_ch3_3_funcs[] = { 6, };
+static int mt7623_pwm_ch4_0_pins[] = { 206, };
+static int mt7623_pwm_ch4_0_funcs[] = { 1, };
+static int mt7623_pwm_ch4_1_pins[] = { 90, };
+static int mt7623_pwm_ch4_1_funcs[] = { 6, };
+static int mt7623_pwm_ch4_2_pins[] = { 110, };
+static int mt7623_pwm_ch4_2_funcs[] = { 6, };
+static int mt7623_pwm_ch4_3_pins[] = { 124, };
+static int mt7623_pwm_ch4_3_funcs[] = { 5, };
+static int mt7623_pwm_ch5_0_pins[] = { 207, };
+static int mt7623_pwm_ch5_0_funcs[] = { 1, };
+static int mt7623_pwm_ch5_1_pins[] = { 125, };
+static int mt7623_pwm_ch5_1_funcs[] = { 5, };
+
+/* PWRAP */
+static int mt7623_pwrap_pins[] = { 0, 1, 2, 3, 4, 5, 6, };
+static int mt7623_pwrap_funcs[] = { 1, 1, 1, 1, 1, 1, 1, };
+
+/* SPDIF */
+static int mt7623_spdif_in0_0_pins[] = { 56, };
+static int mt7623_spdif_in0_0_funcs[] = { 3, };
+static int mt7623_spdif_in0_1_pins[] = { 201, };
+static int mt7623_spdif_in0_1_funcs[] = { 1, };
+static int mt7623_spdif_in1_0_pins[] = { 54, };
+static int mt7623_spdif_in1_0_funcs[] = { 3, };
+static int mt7623_spdif_in1_1_pins[] = { 202, };
+static int mt7623_spdif_in1_1_funcs[] = { 1, };
+static int mt7623_spdif_out_pins[] = { 202, };
+static int mt7623_spdif_out_funcs[] = { 1, };
+
+/* SPI */
+static int mt7623_spi0_pins[] = { 53, 54, 55, 56, };
+static int mt7623_spi0_funcs[] = { 1, 1, 1, 1, };
+static int mt7623_spi1_pins[] = { 7, 199, 8, 9, };
+static int mt7623_spi1_funcs[] = { 1, 1, 1, 1, };
+static int mt7623_spi2_pins[] = { 101, 104, 102, 103, };
+static int mt7623_spi2_funcs[] = { 1, 1, 1, 1, };
+
+/* UART */
+static int mt7623_uart0_0_txd_rxd_pins[] = { 79, 80, };
+static int mt7623_uart0_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7623_uart0_1_txd_rxd_pins[] = { 87, 88, };
+static int mt7623_uart0_1_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart0_2_txd_rxd_pins[] = { 107, 108, };
+static int mt7623_uart0_2_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart0_3_txd_rxd_pins[] = { 123, 122, };
+static int mt7623_uart0_3_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart0_rts_cts_pins[] = { 22, 23, };
+static int mt7623_uart0_rts_cts_funcs[] = { 1, 1, };
+static int mt7623_uart1_0_txd_rxd_pins[] = { 81, 82, };
+static int mt7623_uart1_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7623_uart1_1_txd_rxd_pins[] = { 89, 90, };
+static int mt7623_uart1_1_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart1_2_txd_rxd_pins[] = { 109, 110, };
+static int mt7623_uart1_2_txd_rxd_funcs[] = { 5, 5, };
+static int mt7623_uart1_rts_cts_pins[] = { 24, 25, };
+static int mt7623_uart1_rts_cts_funcs[] = { 1, 1, };
+static int mt7623_uart2_0_txd_rxd_pins[] = { 14, 15, };
+static int mt7623_uart2_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7623_uart2_1_txd_rxd_pins[] = { 200, 201, };
+static int mt7623_uart2_1_txd_rxd_funcs[] = { 6, 6, };
+static int mt7623_uart2_rts_cts_pins[] = { 242, 243, };
+static int mt7623_uart2_rts_cts_funcs[] = { 1, 1, };
+static int mt7623_uart3_txd_rxd_pins[] = { 242, 243, };
+static int mt7623_uart3_txd_rxd_funcs[] = { 2, 2, };
+static int mt7623_uart3_rts_cts_pins[] = { 26, 27, };
+static int mt7623_uart3_rts_cts_funcs[] = { 1, 1, };
+
+/* Watchdog */
+static int mt7623_watchdog_0_pins[] = { 11, };
+static int mt7623_watchdog_0_funcs[] = { 1, };
+static int mt7623_watchdog_1_pins[] = { 121, };
+static int mt7623_watchdog_1_funcs[] = { 5, };
+
+static const struct mtk_group_desc mt7623_groups[] = {
+	PINCTRL_PIN_GROUP("aud_ext_clk0", mt7623_aud_ext_clk0),
+	PINCTRL_PIN_GROUP("aud_ext_clk1", mt7623_aud_ext_clk1),
+	PINCTRL_PIN_GROUP("dsi_te", mt7623_dsi_te),
+	PINCTRL_PIN_GROUP("disp_pwm_0", mt7623_disp_pwm_0),
+	PINCTRL_PIN_GROUP("disp_pwm_1", mt7623_disp_pwm_1),
+	PINCTRL_PIN_GROUP("disp_pwm_2", mt7623_disp_pwm_2),
+	PINCTRL_PIN_GROUP("ephy", mt7623_ephy),
+	PINCTRL_PIN_GROUP("esw_int", mt7623_esw_int),
+	PINCTRL_PIN_GROUP("esw_rst", mt7623_esw_rst),
+	PINCTRL_PIN_GROUP("ext_sdio", mt7623_ext_sdio),
+	PINCTRL_PIN_GROUP("hdmi_cec", mt7623_hdmi_cec),
+	PINCTRL_PIN_GROUP("hdmi_htplg", mt7623_hdmi_htplg),
+	PINCTRL_PIN_GROUP("hdmi_i2c", mt7623_hdmi_i2c),
+	PINCTRL_PIN_GROUP("hdmi_rx", mt7623_hdmi_rx),
+	PINCTRL_PIN_GROUP("hdmi_rx_i2c", mt7623_hdmi_rx_i2c),
+	PINCTRL_PIN_GROUP("i2c0", mt7623_i2c0),
+	PINCTRL_PIN_GROUP("i2c1_0", mt7623_i2c1_0),
+	PINCTRL_PIN_GROUP("i2c1_1", mt7623_i2c1_1),
+	PINCTRL_PIN_GROUP("i2c1_2", mt7623_i2c1_2),
+	PINCTRL_PIN_GROUP("i2c1_3", mt7623_i2c1_3),
+	PINCTRL_PIN_GROUP("i2c1_4", mt7623_i2c1_4),
+	PINCTRL_PIN_GROUP("i2c2_0", mt7623_i2c2_0),
+	PINCTRL_PIN_GROUP("i2c2_1", mt7623_i2c2_1),
+	PINCTRL_PIN_GROUP("i2c2_2", mt7623_i2c2_2),
+	PINCTRL_PIN_GROUP("i2c2_3", mt7623_i2c2_3),
+	PINCTRL_PIN_GROUP("i2s0", mt7623_i2s0),
+	PINCTRL_PIN_GROUP("i2s1", mt7623_i2s1),
+	PINCTRL_PIN_GROUP("i2s4", mt7623_i2s4),
+	PINCTRL_PIN_GROUP("i2s5", mt7623_i2s5),
+	PINCTRL_PIN_GROUP("i2s2_bclk_lrclk_mclk", mt7623_i2s2_bclk_lrclk_mclk),
+	PINCTRL_PIN_GROUP("i2s3_bclk_lrclk_mclk", mt7623_i2s3_bclk_lrclk_mclk),
+	PINCTRL_PIN_GROUP("i2s2_data_in", mt7623_i2s2_data_in),
+	PINCTRL_PIN_GROUP("i2s3_data_in", mt7623_i2s3_data_in),
+	PINCTRL_PIN_GROUP("i2s2_data_0", mt7623_i2s2_data_0),
+	PINCTRL_PIN_GROUP("i2s2_data_1", mt7623_i2s2_data_1),
+	PINCTRL_PIN_GROUP("i2s3_data_0", mt7623_i2s3_data_0),
+	PINCTRL_PIN_GROUP("i2s3_data_1", mt7623_i2s3_data_1),
+	PINCTRL_PIN_GROUP("ir", mt7623_ir),
+	PINCTRL_PIN_GROUP("lcm_rst", mt7623_lcm_rst),
+	PINCTRL_PIN_GROUP("mdc_mdio", mt7623_mdc_mdio),
+	PINCTRL_PIN_GROUP("mipi_tx", mt7623_mipi_tx),
+	PINCTRL_PIN_GROUP("msdc0", mt7623_msdc0),
+	PINCTRL_PIN_GROUP("msdc1", mt7623_msdc1),
+	PINCTRL_PIN_GROUP("msdc1_ins", mt7623_msdc1_ins),
+	PINCTRL_PIN_GROUP("msdc1_wp_0", mt7623_msdc1_wp_0),
+	PINCTRL_PIN_GROUP("msdc1_wp_1", mt7623_msdc1_wp_1),
+	PINCTRL_PIN_GROUP("msdc1_wp_2", mt7623_msdc1_wp_2),
+	PINCTRL_PIN_GROUP("msdc2", mt7623_msdc2),
+	PINCTRL_PIN_GROUP("msdc3", mt7623_msdc3),
+	PINCTRL_PIN_GROUP("nandc", mt7623_nandc),
+	PINCTRL_PIN_GROUP("nandc_ceb0", mt7623_nandc_ceb0),
+	PINCTRL_PIN_GROUP("nandc_ceb1", mt7623_nandc_ceb1),
+	PINCTRL_PIN_GROUP("otg_iddig0_0", mt7623_otg_iddig0_0),
+	PINCTRL_PIN_GROUP("otg_iddig0_1", mt7623_otg_iddig0_1),
+	PINCTRL_PIN_GROUP("otg_iddig0_2", mt7623_otg_iddig0_2),
+	PINCTRL_PIN_GROUP("otg_iddig1_0", mt7623_otg_iddig1_0),
+	PINCTRL_PIN_GROUP("otg_iddig1_1", mt7623_otg_iddig1_1),
+	PINCTRL_PIN_GROUP("otg_iddig1_2", mt7623_otg_iddig1_2),
+	PINCTRL_PIN_GROUP("otg_drv_vbus0_0", mt7623_otg_drv_vbus0_0),
+	PINCTRL_PIN_GROUP("otg_drv_vbus0_1", mt7623_otg_drv_vbus0_1),
+	PINCTRL_PIN_GROUP("otg_drv_vbus0_2", mt7623_otg_drv_vbus0_2),
+	PINCTRL_PIN_GROUP("otg_drv_vbus1_0", mt7623_otg_drv_vbus1_0),
+	PINCTRL_PIN_GROUP("otg_drv_vbus1_1", mt7623_otg_drv_vbus1_1),
+	PINCTRL_PIN_GROUP("otg_drv_vbus1_2", mt7623_otg_drv_vbus1_2),
+	PINCTRL_PIN_GROUP("pcie0_0_perst", mt7623_pcie0_0_perst),
+	PINCTRL_PIN_GROUP("pcie0_1_perst", mt7623_pcie0_1_perst),
+	PINCTRL_PIN_GROUP("pcie1_0_perst", mt7623_pcie1_0_perst),
+	PINCTRL_PIN_GROUP("pcie1_1_perst", mt7623_pcie1_1_perst),
+	PINCTRL_PIN_GROUP("pcie1_1_perst", mt7623_pcie1_1_perst),
+	PINCTRL_PIN_GROUP("pcie0_0_rev_perst", mt7623_pcie0_0_rev_perst),
+	PINCTRL_PIN_GROUP("pcie0_1_rev_perst", mt7623_pcie0_1_rev_perst),
+	PINCTRL_PIN_GROUP("pcie1_0_rev_perst", mt7623_pcie1_0_rev_perst),
+	PINCTRL_PIN_GROUP("pcie1_1_rev_perst", mt7623_pcie1_1_rev_perst),
+	PINCTRL_PIN_GROUP("pcie2_0_rev_perst", mt7623_pcie2_0_rev_perst),
+	PINCTRL_PIN_GROUP("pcie2_1_rev_perst", mt7623_pcie2_1_rev_perst),
+	PINCTRL_PIN_GROUP("pcie2_0_perst", mt7623_pcie2_0_perst),
+	PINCTRL_PIN_GROUP("pcie2_1_perst", mt7623_pcie2_1_perst),
+	PINCTRL_PIN_GROUP("pcie0_0_wake", mt7623_pcie0_0_wake),
+	PINCTRL_PIN_GROUP("pcie0_1_wake", mt7623_pcie0_1_wake),
+	PINCTRL_PIN_GROUP("pcie1_0_wake", mt7623_pcie1_0_wake),
+	PINCTRL_PIN_GROUP("pcie1_1_wake", mt7623_pcie1_1_wake),
+	PINCTRL_PIN_GROUP("pcie2_0_wake", mt7623_pcie2_0_wake),
+	PINCTRL_PIN_GROUP("pcie2_1_wake", mt7623_pcie2_1_wake),
+	PINCTRL_PIN_GROUP("pcie0_clkreq", mt7623_pcie0_clkreq),
+	PINCTRL_PIN_GROUP("pcie1_clkreq", mt7623_pcie1_clkreq),
+	PINCTRL_PIN_GROUP("pcie2_clkreq", mt7623_pcie2_clkreq),
+	PINCTRL_PIN_GROUP("pcm_clk_0", mt7623_pcm_clk_0),
+	PINCTRL_PIN_GROUP("pcm_clk_1", mt7623_pcm_clk_1),
+	PINCTRL_PIN_GROUP("pcm_clk_2", mt7623_pcm_clk_2),
+	PINCTRL_PIN_GROUP("pcm_clk_3", mt7623_pcm_clk_3),
+	PINCTRL_PIN_GROUP("pcm_clk_4", mt7623_pcm_clk_4),
+	PINCTRL_PIN_GROUP("pcm_clk_5", mt7623_pcm_clk_5),
+	PINCTRL_PIN_GROUP("pcm_clk_6", mt7623_pcm_clk_6),
+	PINCTRL_PIN_GROUP("pcm_sync_0", mt7623_pcm_sync_0),
+	PINCTRL_PIN_GROUP("pcm_sync_1", mt7623_pcm_sync_1),
+	PINCTRL_PIN_GROUP("pcm_sync_2", mt7623_pcm_sync_2),
+	PINCTRL_PIN_GROUP("pcm_sync_3", mt7623_pcm_sync_3),
+	PINCTRL_PIN_GROUP("pcm_sync_4", mt7623_pcm_sync_4),
+	PINCTRL_PIN_GROUP("pcm_sync_5", mt7623_pcm_sync_5),
+	PINCTRL_PIN_GROUP("pcm_sync_6", mt7623_pcm_sync_6),
+	PINCTRL_PIN_GROUP("pcm_rx_0", mt7623_pcm_rx_0),
+	PINCTRL_PIN_GROUP("pcm_rx_1", mt7623_pcm_rx_1),
+	PINCTRL_PIN_GROUP("pcm_rx_2", mt7623_pcm_rx_2),
+	PINCTRL_PIN_GROUP("pcm_rx_3", mt7623_pcm_rx_3),
+	PINCTRL_PIN_GROUP("pcm_rx_4", mt7623_pcm_rx_4),
+	PINCTRL_PIN_GROUP("pcm_rx_5", mt7623_pcm_rx_5),
+	PINCTRL_PIN_GROUP("pcm_rx_6", mt7623_pcm_rx_6),
+	PINCTRL_PIN_GROUP("pcm_tx_0", mt7623_pcm_tx_0),
+	PINCTRL_PIN_GROUP("pcm_tx_1", mt7623_pcm_tx_1),
+	PINCTRL_PIN_GROUP("pcm_tx_2", mt7623_pcm_tx_2),
+	PINCTRL_PIN_GROUP("pcm_tx_3", mt7623_pcm_tx_3),
+	PINCTRL_PIN_GROUP("pcm_tx_4", mt7623_pcm_tx_4),
+	PINCTRL_PIN_GROUP("pcm_tx_5", mt7623_pcm_tx_5),
+	PINCTRL_PIN_GROUP("pcm_tx_6", mt7623_pcm_tx_6),
+	PINCTRL_PIN_GROUP("pwm_ch1_0", mt7623_pwm_ch1_0),
+	PINCTRL_PIN_GROUP("pwm_ch1_1", mt7623_pwm_ch1_1),
+	PINCTRL_PIN_GROUP("pwm_ch1_2", mt7623_pwm_ch1_2),
+	PINCTRL_PIN_GROUP("pwm_ch1_3", mt7623_pwm_ch1_3),
+	PINCTRL_PIN_GROUP("pwm_ch1_4", mt7623_pwm_ch1_4),
+	PINCTRL_PIN_GROUP("pwm_ch2_0", mt7623_pwm_ch2_0),
+	PINCTRL_PIN_GROUP("pwm_ch2_1", mt7623_pwm_ch2_1),
+	PINCTRL_PIN_GROUP("pwm_ch2_2", mt7623_pwm_ch2_2),
+	PINCTRL_PIN_GROUP("pwm_ch2_3", mt7623_pwm_ch2_3),
+	PINCTRL_PIN_GROUP("pwm_ch2_4", mt7623_pwm_ch2_4),
+	PINCTRL_PIN_GROUP("pwm_ch3_0", mt7623_pwm_ch3_0),
+	PINCTRL_PIN_GROUP("pwm_ch3_1", mt7623_pwm_ch3_1),
+	PINCTRL_PIN_GROUP("pwm_ch3_2", mt7623_pwm_ch3_2),
+	PINCTRL_PIN_GROUP("pwm_ch3_3", mt7623_pwm_ch3_3),
+	PINCTRL_PIN_GROUP("pwm_ch4_0", mt7623_pwm_ch4_0),
+	PINCTRL_PIN_GROUP("pwm_ch4_1", mt7623_pwm_ch4_1),
+	PINCTRL_PIN_GROUP("pwm_ch4_2", mt7623_pwm_ch4_2),
+	PINCTRL_PIN_GROUP("pwm_ch4_3", mt7623_pwm_ch4_3),
+	PINCTRL_PIN_GROUP("pwm_ch5_0", mt7623_pwm_ch5_0),
+	PINCTRL_PIN_GROUP("pwm_ch5_1", mt7623_pwm_ch5_1),
+	PINCTRL_PIN_GROUP("pwrap", mt7623_pwrap),
+	PINCTRL_PIN_GROUP("rtc", mt7623_rtc),
+	PINCTRL_PIN_GROUP("spdif_in0_0", mt7623_spdif_in0_0),
+	PINCTRL_PIN_GROUP("spdif_in0_1", mt7623_spdif_in0_1),
+	PINCTRL_PIN_GROUP("spdif_in1_0", mt7623_spdif_in1_0),
+	PINCTRL_PIN_GROUP("spdif_in1_1", mt7623_spdif_in1_1),
+	PINCTRL_PIN_GROUP("spdif_out", mt7623_spdif_out),
+	PINCTRL_PIN_GROUP("spi0", mt7623_spi0),
+	PINCTRL_PIN_GROUP("spi1", mt7623_spi1),
+	PINCTRL_PIN_GROUP("spi2", mt7623_spi2),
+	PINCTRL_PIN_GROUP("uart0_0_txd_rxd",  mt7623_uart0_0_txd_rxd),
+	PINCTRL_PIN_GROUP("uart0_1_txd_rxd",  mt7623_uart0_1_txd_rxd),
+	PINCTRL_PIN_GROUP("uart0_2_txd_rxd",  mt7623_uart0_2_txd_rxd),
+	PINCTRL_PIN_GROUP("uart0_3_txd_rxd",  mt7623_uart0_3_txd_rxd),
+	PINCTRL_PIN_GROUP("uart1_0_txd_rxd",  mt7623_uart1_0_txd_rxd),
+	PINCTRL_PIN_GROUP("uart1_1_txd_rxd",  mt7623_uart1_1_txd_rxd),
+	PINCTRL_PIN_GROUP("uart1_2_txd_rxd",  mt7623_uart1_2_txd_rxd),
+	PINCTRL_PIN_GROUP("uart2_0_txd_rxd",  mt7623_uart2_0_txd_rxd),
+	PINCTRL_PIN_GROUP("uart2_1_txd_rxd",  mt7623_uart2_1_txd_rxd),
+	PINCTRL_PIN_GROUP("uart3_txd_rxd",  mt7623_uart3_txd_rxd),
+	PINCTRL_PIN_GROUP("uart0_rts_cts",  mt7623_uart0_rts_cts),
+	PINCTRL_PIN_GROUP("uart1_rts_cts",  mt7623_uart1_rts_cts),
+	PINCTRL_PIN_GROUP("uart2_rts_cts",  mt7623_uart2_rts_cts),
+	PINCTRL_PIN_GROUP("uart3_rts_cts",  mt7623_uart3_rts_cts),
+	PINCTRL_PIN_GROUP("watchdog_0", mt7623_watchdog_0),
+	PINCTRL_PIN_GROUP("watchdog_1", mt7623_watchdog_1),
+};
+
+/* 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 mt7623_aud_clk_groups[] = { "aud_ext_clk0",
+						"aud_ext_clk1", };
+static const char *const mt7623_disp_pwm_groups[] = { "disp_pwm_0",
+						"disp_pwm_1",
+						"disp_pwm_2", };
+static const char *const mt7623_ethernet_groups[] = { "esw_int", "esw_rst",
+						"ephy", "mdc_mdio", };
+static const char *const mt7623_ext_sdio_groups[] = { "ext_sdio", };
+static const char *const mt7623_hdmi_groups[] = { "hdmi_cec", "hdmi_htplg",
+						"hdmi_i2c", "hdmi_rx",
+						"hdmi_rx_i2c", };
+static const char *const mt7623_i2c_groups[] = { "i2c0", "i2c1_0", "i2c1_1",
+						"i2c1_2", "i2c1_3", "i2c1_4",
+						"i2c2_0", "i2c2_1", "i2c2_2",
+						"i2c2_3", };
+static const char *const mt7623_i2s_groups[] = { "i2s0", "i2s1",
+						"i2s2_bclk_lrclk_mclk",
+						"i2s3_bclk_lrclk_mclk",
+						"i2s4", "i2s5",
+						"i2s2_data_in", "i2s3_data_in",
+						"i2s2_data_0", "i2s2_data_1",
+						"i2s3_data_0", "i2s3_data_1",};
+static const char *const mt7623_ir_groups[] = { "ir", };
+static const char *const mt7623_lcd_groups[] = { "dsi_te", "lcm_rst",
+						"mipi_tx", };
+static const char *const mt7623_msdc_groups[] = { "msdc0", "msdc1",
+						"msdc1_ins", "msdc1_wp_0",
+						"msdc1_wp_1", "msdc1_wp_2",
+						"msdc2", "msdc3", };
+static const char *const mt7623_nandc_groups[] = { "nandc", "nandc_ceb0",
+						"nandc_ceb1", };
+static const char *const mt7623_otg_groups[] = { "otg_iddig0_0",
+						"otg_iddig0_1",
+						"otg_iddig0_2",
+						"otg_iddig1_0",
+						"otg_iddig1_1",
+						"otg_iddig1_2",
+						"otg_drv_vbus0_0",
+						"otg_drv_vbus0_1",
+						"otg_drv_vbus0_2",
+						"otg_drv_vbus1_0",
+						"otg_drv_vbus1_1",
+						"otg_drv_vbus1_2", };
+static const char *const mt7623_pcie_groups[] = { "pcie0_0_perst",
+						"pcie0_1_perst",
+						"pcie1_0_perst",
+						"pcie1_1_perst",
+						"pcie2_0_perst",
+						"pcie2_1_perst",
+						"pcie0_0_rev_perst",
+						"pcie0_1_rev_perst",
+						"pcie1_0_rev_perst",
+						"pcie1_1_rev_perst",
+						"pcie2_0_rev_perst",
+						"pcie2_1_rev_perst",
+						"pcie0_0_wake", "pcie0_1_wake",
+						"pcie2_0_wake", "pcie2_1_wake",
+						"pcie0_clkreq", "pcie1_clkreq",
+						"pcie2_clkreq", };
+static const char *const mt7623_pcm_groups[] = { "pcm_clk_0", "pcm_clk_1",
+						"pcm_clk_2", "pcm_clk_3",
+						"pcm_clk_4", "pcm_clk_5",
+						"pcm_clk_6", "pcm_sync_0",
+						"pcm_sync_1", "pcm_sync_2",
+						"pcm_sync_3", "pcm_sync_4",
+						"pcm_sync_5", "pcm_sync_6",
+						"pcm_rx_0", "pcm_rx_1",
+						"pcm_rx_2", "pcm_rx_3",
+						"pcm_rx_4", "pcm_rx_5",
+						"pcm_rx_6", "pcm_tx_0",
+						"pcm_tx_1", "pcm_tx_2",
+						"pcm_tx_3", "pcm_tx_4",
+						"pcm_tx_5", "pcm_tx_6", };
+static const char *const mt7623_pwm_groups[] = { "pwm_ch1_0", "pwm_ch1_1",
+						"pwm_ch1_2", "pwm_ch2_0",
+						"pwm_ch2_1", "pwm_ch2_2",
+						"pwm_ch3_0", "pwm_ch3_1",
+						"pwm_ch3_2", "pwm_ch4_0",
+						"pwm_ch4_1", "pwm_ch4_2",
+						"pwm_ch4_3", "pwm_ch5_0",
+						"pwm_ch5_1", "pwm_ch5_2",
+						"pwm_ch6_0", "pwm_ch6_1",
+						"pwm_ch6_2", "pwm_ch6_3",
+						"pwm_ch7_0", "pwm_ch7_1",
+						"pwm_ch7_2", };
+static const char *const mt7623_pwrap_groups[] = { "pwrap", };
+static const char *const mt7623_rtc_groups[] = { "rtc", };
+static const char *const mt7623_spi_groups[] = { "spi0", "spi2", "spi2", };
+static const char *const mt7623_spdif_groups[] = { "spdif_in0_0",
+						"spdif_in0_1", "spdif_in1_0",
+						"spdif_in1_1", "spdif_out", };
+static const char *const mt7623_uart_groups[] = { "uart0_0_txd_rxd",
+						"uart0_1_txd_rxd",
+						"uart0_2_txd_rxd",
+						"uart0_3_txd_rxd",
+						"uart1_0_txd_rxd",
+						"uart1_1_txd_rxd",
+						"uart1_2_txd_rxd",
+						"uart2_0_txd_rxd",
+						"uart2_1_txd_rxd",
+						"uart3_txd_rxd",
+						"uart0_rts_cts",
+						"uart1_rts_cts",
+						"uart2_rts_cts",
+						"uart3_rts_cts", };
+static const char *const mt7623_wdt_groups[] = { "watchdog_0", "watchdog_1", };
+
+static const struct mtk_function_desc mt7623_functions[] = {
+	{"audck", mt7623_aud_clk_groups, ARRAY_SIZE(mt7623_aud_clk_groups)},
+	{"disp", mt7623_disp_pwm_groups, ARRAY_SIZE(mt7623_disp_pwm_groups)},
+	{"eth",	mt7623_ethernet_groups, ARRAY_SIZE(mt7623_ethernet_groups)},
+	{"sdio", mt7623_ext_sdio_groups, ARRAY_SIZE(mt7623_ext_sdio_groups)},
+	{"hdmi", mt7623_hdmi_groups, ARRAY_SIZE(mt7623_hdmi_groups)},
+	{"i2c", mt7623_i2c_groups, ARRAY_SIZE(mt7623_i2c_groups)},
+	{"i2s",	mt7623_i2s_groups, ARRAY_SIZE(mt7623_i2s_groups)},
+	{"ir",	mt7623_ir_groups, ARRAY_SIZE(mt7623_ir_groups)},
+	{"lcd", mt7623_lcd_groups, ARRAY_SIZE(mt7623_lcd_groups)},
+	{"msdc", mt7623_msdc_groups, ARRAY_SIZE(mt7623_msdc_groups)},
+	{"nand", mt7623_nandc_groups, ARRAY_SIZE(mt7623_nandc_groups)},
+	{"otg", mt7623_otg_groups, ARRAY_SIZE(mt7623_otg_groups)},
+	{"pcie", mt7623_pcie_groups, ARRAY_SIZE(mt7623_pcie_groups)},
+	{"pcm",	mt7623_pcm_groups, ARRAY_SIZE(mt7623_pcm_groups)},
+	{"pwm",	mt7623_pwm_groups, ARRAY_SIZE(mt7623_pwm_groups)},
+	{"pwrap", mt7623_pwrap_groups, ARRAY_SIZE(mt7623_pwrap_groups)},
+	{"rtc", mt7623_rtc_groups, ARRAY_SIZE(mt7623_rtc_groups)},
+	{"spi",	mt7623_spi_groups, ARRAY_SIZE(mt7623_spi_groups)},
+	{"spdif", mt7623_spdif_groups, ARRAY_SIZE(mt7623_spdif_groups)},
+	{"uart", mt7623_uart_groups, ARRAY_SIZE(mt7623_uart_groups)},
+	{"watchdog", mt7623_wdt_groups, ARRAY_SIZE(mt7623_wdt_groups)},
+};
+
+static struct mtk_pinctrl_soc mt7623_data = {
+	.name = "mt7623_pinctrl",
+	.reg_cal = mt7623_reg_cals,
+	.pins = mt7623_pins,
+	.npins = ARRAY_SIZE(mt7623_pins),
+	.grps = mt7623_groups,
+	.ngrps = ARRAY_SIZE(mt7623_groups),
+	.funcs = mt7623_functions,
+	.nfuncs = ARRAY_SIZE(mt7623_functions),
+};
+
+/*
+ * There are some specific pins have mux functions greater than 8,
+ * and if we want to switch thees high modes we need to disable
+ * bonding constraints firstly.
+ */
+static void mt7623_bonding_disable(struct udevice *dev)
+{
+	mtk_rmw(dev, PIN_BOND_REG0, BOND_PCIE_CLR, BOND_PCIE_CLR);
+	mtk_rmw(dev, PIN_BOND_REG1, BOND_I2S_CLR, BOND_I2S_CLR);
+	mtk_rmw(dev, PIN_BOND_REG2, BOND_MSDC0E_CLR, BOND_MSDC0E_CLR);
+}
+
+static int mtk_pinctrl_mt7623_probe(struct udevice *dev)
+{
+	int err;
+
+	err = mtk_pinctrl_common_probe(dev, &mt7623_data);
+	if (err)
+		return err;
+
+	mt7623_bonding_disable(dev);
+
+	return 0;
+}
+
+static const struct udevice_id mt7623_pctrl_match[] = {
+	{ .compatible = "mediatek,mt7623-pinctrl", },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mt7623_pinctrl) = {
+	.name = "mt7623_pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = mt7623_pctrl_match,
+	.ops = &mtk_pinctrl_ops,
+	.probe = mtk_pinctrl_mt7623_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_pinctrl_priv),
+};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7629.c b/drivers/pinctrl/mediatek/pinctrl-mt7629.c
new file mode 100644
index 0000000..aa6d1c2
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7629.c
@@ -0,0 +1,409 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <dm.h>
+
+#include "pinctrl-mtk-common.h"
+
+#define PIN_FIELD(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit, _x_bits)	\
+	PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit,	\
+		       _x_bits, 32, false)
+
+#define MT7629_PIN(_number, _name)	MTK_PIN(_number, _name, DRV_GRP1)
+
+static const struct mtk_pin_field_calc mt7629_pin_mode_range[] = {
+	PIN_FIELD(0, 78, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_dir_range[] = {
+	PIN_FIELD(0, 78, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_di_range[] = {
+	PIN_FIELD(0, 78, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_do_range[] = {
+	PIN_FIELD(0, 78, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_ies_range[] = {
+	PIN_FIELD(0, 10, 0x1000, 0x10, 0, 1),
+	PIN_FIELD(11, 18, 0x2000, 0x10, 0, 1),
+	PIN_FIELD(19, 32, 0x3000, 0x10, 0, 1),
+	PIN_FIELD(33, 48, 0x4000, 0x10, 0, 1),
+	PIN_FIELD(49, 50, 0x5000, 0x10, 0, 1),
+	PIN_FIELD(51, 69, 0x6000, 0x10, 0, 1),
+	PIN_FIELD(70, 78, 0x7000, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_smt_range[] = {
+	PIN_FIELD(0, 10, 0x1100, 0x10, 0, 1),
+	PIN_FIELD(11, 18, 0x2100, 0x10, 0, 1),
+	PIN_FIELD(19, 32, 0x3100, 0x10, 0, 1),
+	PIN_FIELD(33, 48, 0x4100, 0x10, 0, 1),
+	PIN_FIELD(49, 50, 0x5100, 0x10, 0, 1),
+	PIN_FIELD(51, 69, 0x6100, 0x10, 0, 1),
+	PIN_FIELD(70, 78, 0x7100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_pullen_range[] = {
+	PIN_FIELD(0, 10, 0x1400, 0x10, 0, 1),
+	PIN_FIELD(11, 18, 0x2400, 0x10, 0, 1),
+	PIN_FIELD(19, 32, 0x3400, 0x10, 0, 1),
+	PIN_FIELD(33, 48, 0x4400, 0x10, 0, 1),
+	PIN_FIELD(49, 50, 0x5400, 0x10, 0, 1),
+	PIN_FIELD(51, 69, 0x6400, 0x10, 0, 1),
+	PIN_FIELD(70, 78, 0x7400, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_pullsel_range[] = {
+	PIN_FIELD(0, 10, 0x1500, 0x10, 0, 1),
+	PIN_FIELD(11, 18, 0x2500, 0x10, 0, 1),
+	PIN_FIELD(19, 32, 0x3500, 0x10, 0, 1),
+	PIN_FIELD(33, 48, 0x4500, 0x10, 0, 1),
+	PIN_FIELD(49, 50, 0x5500, 0x10, 0, 1),
+	PIN_FIELD(51, 69, 0x6500, 0x10, 0, 1),
+	PIN_FIELD(70, 78, 0x7500, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7629_pin_drv_range[] = {
+	PIN_FIELD(0, 10, 0x1600, 0x10, 0, 4),
+	PIN_FIELD(11, 18, 0x2600, 0x10, 0, 4),
+	PIN_FIELD(19, 32, 0x3600, 0x10, 0, 4),
+	PIN_FIELD(33, 48, 0x4600, 0x10, 0, 4),
+	PIN_FIELD(49, 50, 0x5600, 0x10, 0, 4),
+	PIN_FIELD(51, 69, 0x6600, 0x10, 0, 4),
+	PIN_FIELD(70, 78, 0x7600, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_reg_calc mt7629_reg_cals[] = {
+	[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7629_pin_mode_range),
+	[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7629_pin_dir_range),
+	[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7629_pin_di_range),
+	[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7629_pin_do_range),
+	[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7629_pin_ies_range),
+	[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7629_pin_smt_range),
+	[PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7629_pin_pullsel_range),
+	[PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7629_pin_pullen_range),
+	[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7629_pin_drv_range),
+};
+
+static const struct mtk_pin_desc mt7629_pins[] = {
+	MT7629_PIN(0, "TOP_5G_CLK"),
+	MT7629_PIN(1, "TOP_5G_DATA"),
+	MT7629_PIN(2, "WF0_5G_HB0"),
+	MT7629_PIN(3, "WF0_5G_HB1"),
+	MT7629_PIN(4, "WF0_5G_HB2"),
+	MT7629_PIN(5, "WF0_5G_HB3"),
+	MT7629_PIN(6, "WF0_5G_HB4"),
+	MT7629_PIN(7, "WF0_5G_HB5"),
+	MT7629_PIN(8, "WF0_5G_HB6"),
+	MT7629_PIN(9, "XO_REQ"),
+	MT7629_PIN(10, "TOP_RST_N"),
+	MT7629_PIN(11, "SYS_WATCHDOG"),
+	MT7629_PIN(12, "EPHY_LED0_N_JTDO"),
+	MT7629_PIN(13, "EPHY_LED1_N_JTDI"),
+	MT7629_PIN(14, "EPHY_LED2_N_JTMS"),
+	MT7629_PIN(15, "EPHY_LED3_N_JTCLK"),
+	MT7629_PIN(16, "EPHY_LED4_N_JTRST_N"),
+	MT7629_PIN(17, "WF2G_LED_N"),
+	MT7629_PIN(18, "WF5G_LED_N"),
+	MT7629_PIN(19, "I2C_SDA"),
+	MT7629_PIN(20, "I2C_SCL"),
+	MT7629_PIN(21, "GPIO_9"),
+	MT7629_PIN(22, "GPIO_10"),
+	MT7629_PIN(23, "GPIO_11"),
+	MT7629_PIN(24, "GPIO_12"),
+	MT7629_PIN(25, "UART1_TXD"),
+	MT7629_PIN(26, "UART1_RXD"),
+	MT7629_PIN(27, "UART1_CTS"),
+	MT7629_PIN(28, "UART1_RTS"),
+	MT7629_PIN(29, "UART2_TXD"),
+	MT7629_PIN(30, "UART2_RXD"),
+	MT7629_PIN(31, "UART2_CTS"),
+	MT7629_PIN(32, "UART2_RTS"),
+	MT7629_PIN(33, "MDI_TP_P1"),
+	MT7629_PIN(34, "MDI_TN_P1"),
+	MT7629_PIN(35, "MDI_RP_P1"),
+	MT7629_PIN(36, "MDI_RN_P1"),
+	MT7629_PIN(37, "MDI_RP_P2"),
+	MT7629_PIN(38, "MDI_RN_P2"),
+	MT7629_PIN(39, "MDI_TP_P2"),
+	MT7629_PIN(40, "MDI_TN_P2"),
+	MT7629_PIN(41, "MDI_TP_P3"),
+	MT7629_PIN(42, "MDI_TN_P3"),
+	MT7629_PIN(43, "MDI_RP_P3"),
+	MT7629_PIN(44, "MDI_RN_P3"),
+	MT7629_PIN(45, "MDI_RP_P4"),
+	MT7629_PIN(46, "MDI_RN_P4"),
+	MT7629_PIN(47, "MDI_TP_P4"),
+	MT7629_PIN(48, "MDI_TN_P4"),
+	MT7629_PIN(49, "SMI_MDC"),
+	MT7629_PIN(50, "SMI_MDIO"),
+	MT7629_PIN(51, "PCIE_PERESET_N"),
+	MT7629_PIN(52, "PWM_0"),
+	MT7629_PIN(53, "GPIO_0"),
+	MT7629_PIN(54, "GPIO_1"),
+	MT7629_PIN(55, "GPIO_2"),
+	MT7629_PIN(56, "GPIO_3"),
+	MT7629_PIN(57, "GPIO_4"),
+	MT7629_PIN(58, "GPIO_5"),
+	MT7629_PIN(59, "GPIO_6"),
+	MT7629_PIN(60, "GPIO_7"),
+	MT7629_PIN(61, "GPIO_8"),
+	MT7629_PIN(62, "SPI_CLK"),
+	MT7629_PIN(63, "SPI_CS"),
+	MT7629_PIN(64, "SPI_MOSI"),
+	MT7629_PIN(65, "SPI_MISO"),
+	MT7629_PIN(66, "SPI_WP"),
+	MT7629_PIN(67, "SPI_HOLD"),
+	MT7629_PIN(68, "UART0_TXD"),
+	MT7629_PIN(69, "UART0_RXD"),
+	MT7629_PIN(70, "TOP_2G_CLK"),
+	MT7629_PIN(71, "TOP_2G_DATA"),
+	MT7629_PIN(72, "WF0_2G_HB0"),
+	MT7629_PIN(73, "WF0_2G_HB1"),
+	MT7629_PIN(74, "WF0_2G_HB2"),
+	MT7629_PIN(75, "WF0_2G_HB3"),
+	MT7629_PIN(76, "WF0_2G_HB4"),
+	MT7629_PIN(77, "WF0_2G_HB5"),
+	MT7629_PIN(78, "WF0_2G_HB6"),
+};
+
+/* 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.
+ */
+
+/* WF 5G */
+static int mt7629_wf0_5g_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, };
+static int mt7629_wf0_5g_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* LED for EPHY */
+static int mt7629_ephy_leds_pins[] = { 12, 13, 14, 15, 16, 17, 18, };
+static int mt7629_ephy_leds_funcs[] = { 1, 1, 1, 1, 1, 1, 1, };
+static int mt7629_ephy_led0_pins[] = { 12, };
+static int mt7629_ephy_led0_funcs[] = { 1, };
+static int mt7629_ephy_led1_pins[] = { 13, };
+static int mt7629_ephy_led1_funcs[] = { 1, };
+static int mt7629_ephy_led2_pins[] = { 14, };
+static int mt7629_ephy_led2_funcs[] = { 1, };
+static int mt7629_ephy_led3_pins[] = { 15, };
+static int mt7629_ephy_led3_funcs[] = { 1, };
+static int mt7629_ephy_led4_pins[] = { 16, };
+static int mt7629_ephy_led4_funcs[] = { 1, };
+static int mt7629_wf2g_led_pins[] = { 17, };
+static int mt7629_wf2g_led_funcs[] = { 1, };
+static int mt7629_wf5g_led_pins[] = { 18, };
+static int mt7629_wf5g_led_funcs[] = { 1, };
+
+/* Watchdog */
+static int mt7629_watchdog_pins[] = { 11, };
+static int mt7629_watchdog_funcs[] = { 1, };
+
+/* LED for GPHY */
+static int mt7629_gphy_leds_0_pins[] = { 21, 22, 23, };
+static int mt7629_gphy_leds_0_funcs[] = { 2, 2, 2, };
+static int mt7629_gphy_led1_0_pins[] = { 21, };
+static int mt7629_gphy_led1_0_funcs[] = { 2, };
+static int mt7629_gphy_led2_0_pins[] = { 22, };
+static int mt7629_gphy_led2_0_funcs[] = { 2, };
+static int mt7629_gphy_led3_0_pins[] = { 23, };
+static int mt7629_gphy_led3_0_funcs[] = { 2, };
+static int mt7629_gphy_leds_1_pins[] = { 57, 58, 59, };
+static int mt7629_gphy_leds_1_funcs[] = { 1, 1, 1, };
+static int mt7629_gphy_led1_1_pins[] = { 57, };
+static int mt7629_gphy_led1_1_funcs[] = { 1, };
+static int mt7629_gphy_led2_1_pins[] = { 58, };
+static int mt7629_gphy_led2_1_funcs[] = { 1, };
+static int mt7629_gphy_led3_1_pins[] = { 59, };
+static int mt7629_gphy_led3_1_funcs[] = { 1, };
+
+/* I2C */
+static int mt7629_i2c_0_pins[] = { 19, 20, };
+static int mt7629_i2c_0_funcs[] = { 1, 1, };
+static int mt7629_i2c_1_pins[] = { 53, 54, };
+static int mt7629_i2c_1_funcs[] = { 1, 1, };
+
+/* SPI */
+static int mt7629_spi_0_pins[] = { 21, 22, 23, 24, };
+static int mt7629_spi_0_funcs[] = { 1, 1, 1, 1, };
+static int mt7629_spi_1_pins[] = { 62, 63, 64, 65, };
+static int mt7629_spi_1_funcs[] = { 1, 1, 1, 1, };
+static int mt7629_spi_wp_pins[] = { 66, };
+static int mt7629_spi_wp_funcs[] = { 1, };
+static int mt7629_spi_hold_pins[] = { 67, };
+static int mt7629_spi_hold_funcs[] = { 1, };
+
+/* UART */
+static int mt7629_uart1_0_txd_rxd_pins[] = { 25, 26, };
+static int mt7629_uart1_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7629_uart1_1_txd_rxd_pins[] = { 53, 54, };
+static int mt7629_uart1_1_txd_rxd_funcs[] = { 2, 2, };
+static int mt7629_uart2_0_txd_rxd_pins[] = { 29, 30, };
+static int mt7629_uart2_0_txd_rxd_funcs[] = { 1, 1, };
+static int mt7629_uart2_1_txd_rxd_pins[] = { 57, 58, };
+static int mt7629_uart2_1_txd_rxd_funcs[] = { 2, 2, };
+static int mt7629_uart1_0_cts_rts_pins[] = { 27, 28, };
+static int mt7629_uart1_0_cts_rts_funcs[] = { 1, 1, };
+static int mt7629_uart1_1_cts_rts_pins[] = { 55, 56, };
+static int mt7629_uart1_1_cts_rts_funcs[] = { 2, 2, };
+static int mt7629_uart2_0_cts_rts_pins[] = { 31, 32, };
+static int mt7629_uart2_0_cts_rts_funcs[] = { 1, 1, };
+static int mt7629_uart2_1_cts_rts_pins[] = { 59, 60, };
+static int mt7629_uart2_1_cts_rts_funcs[] = { 2, 2, };
+static int mt7629_uart0_txd_rxd_pins[] = { 68, 69, };
+static int mt7629_uart0_txd_rxd_funcs[] = { 1, 1, };
+
+/* MDC/MDIO */
+static int mt7629_mdc_mdio_pins[] = { 49, 50, };
+static int mt7629_mdc_mdio_funcs[] = { 1, 1, };
+
+/* PCIE */
+static int mt7629_pcie_pereset_pins[] = { 51, };
+static int mt7629_pcie_pereset_funcs[] = { 1, };
+static int mt7629_pcie_wake_pins[] = { 55, };
+static int mt7629_pcie_wake_funcs[] = { 1, };
+static int mt7629_pcie_clkreq_pins[] = { 56, };
+static int mt7629_pcie_clkreq_funcs[] = { 1, };
+
+/* PWM */
+static int mt7629_pwm_0_pins[] = { 52, };
+static int mt7629_pwm_0_funcs[] = { 1, };
+static int mt7629_pwm_1_pins[] = { 61, };
+static int mt7629_pwm_1_funcs[] = { 2, };
+
+/* WF 2G */
+static int mt7629_wf0_2g_pins[] = { 70, 71, 72, 73, 74, 75, 76, 77, 78, };
+static int mt7629_wf0_2g_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, };
+
+/* SNFI */
+static int mt7629_snfi_pins[] = { 62, 63, 64, 65, 66, 67 };
+static int mt7629_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 };
+
+/* SPI NOR */
+static int mt7629_snor_pins[] = { 62, 63, 64, 65, 66, 67 };
+static int mt7629_snor_funcs[] = { 1, 1, 1, 1, 1, 1 };
+
+static const struct mtk_group_desc mt7629_groups[] = {
+	PINCTRL_PIN_GROUP("wf0_5g", mt7629_wf0_5g),
+	PINCTRL_PIN_GROUP("ephy_leds", mt7629_ephy_leds),
+	PINCTRL_PIN_GROUP("ephy_led0", mt7629_ephy_led0),
+	PINCTRL_PIN_GROUP("ephy_led1", mt7629_ephy_led1),
+	PINCTRL_PIN_GROUP("ephy_led2", mt7629_ephy_led2),
+	PINCTRL_PIN_GROUP("ephy_led3", mt7629_ephy_led3),
+	PINCTRL_PIN_GROUP("ephy_led4", mt7629_ephy_led4),
+	PINCTRL_PIN_GROUP("wf2g_led", mt7629_wf2g_led),
+	PINCTRL_PIN_GROUP("wf5g_led", mt7629_wf5g_led),
+	PINCTRL_PIN_GROUP("watchdog", mt7629_watchdog),
+	PINCTRL_PIN_GROUP("gphy_leds_0", mt7629_gphy_leds_0),
+	PINCTRL_PIN_GROUP("gphy_led1_0", mt7629_gphy_led1_0),
+	PINCTRL_PIN_GROUP("gphy_led2_0", mt7629_gphy_led2_0),
+	PINCTRL_PIN_GROUP("gphy_led3_0", mt7629_gphy_led3_0),
+	PINCTRL_PIN_GROUP("gphy_leds_1", mt7629_gphy_leds_1),
+	PINCTRL_PIN_GROUP("gphy_led1_1", mt7629_gphy_led1_1),
+	PINCTRL_PIN_GROUP("gphy_led2_1", mt7629_gphy_led2_1),
+	PINCTRL_PIN_GROUP("gphy_led3_1", mt7629_gphy_led3_1),
+	PINCTRL_PIN_GROUP("i2c_0", mt7629_i2c_0),
+	PINCTRL_PIN_GROUP("i2c_1", mt7629_i2c_1),
+	PINCTRL_PIN_GROUP("spi_0", mt7629_spi_0),
+	PINCTRL_PIN_GROUP("spi_1", mt7629_spi_1),
+	PINCTRL_PIN_GROUP("spi_wp", mt7629_spi_wp),
+	PINCTRL_PIN_GROUP("spi_hold", mt7629_spi_hold),
+	PINCTRL_PIN_GROUP("uart1_0_txd_rxd", mt7629_uart1_0_txd_rxd),
+	PINCTRL_PIN_GROUP("uart1_1_txd_rxd", mt7629_uart1_1_txd_rxd),
+	PINCTRL_PIN_GROUP("uart2_0_txd_rxd", mt7629_uart2_0_txd_rxd),
+	PINCTRL_PIN_GROUP("uart2_1_txd_rxd", mt7629_uart2_1_txd_rxd),
+	PINCTRL_PIN_GROUP("uart1_0_cts_rts", mt7629_uart1_0_cts_rts),
+	PINCTRL_PIN_GROUP("uart1_1_cts_rts", mt7629_uart1_1_cts_rts),
+	PINCTRL_PIN_GROUP("uart2_0_cts_rts", mt7629_uart2_0_cts_rts),
+	PINCTRL_PIN_GROUP("uart2_1_cts_rts", mt7629_uart2_1_cts_rts),
+	PINCTRL_PIN_GROUP("uart0_txd_rxd", mt7629_uart0_txd_rxd),
+	PINCTRL_PIN_GROUP("mdc_mdio", mt7629_mdc_mdio),
+	PINCTRL_PIN_GROUP("pcie_pereset", mt7629_pcie_pereset),
+	PINCTRL_PIN_GROUP("pcie_wake", mt7629_pcie_wake),
+	PINCTRL_PIN_GROUP("pcie_clkreq", mt7629_pcie_clkreq),
+	PINCTRL_PIN_GROUP("pwm_0", mt7629_pwm_0),
+	PINCTRL_PIN_GROUP("pwm_1", mt7629_pwm_1),
+	PINCTRL_PIN_GROUP("wf0_2g", mt7629_wf0_2g),
+	PINCTRL_PIN_GROUP("snfi", mt7629_snfi),
+	PINCTRL_PIN_GROUP("spi_nor", mt7629_snor),
+};
+
+/* 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 mt7629_ethernet_groups[] = { "mdc_mdio", };
+static const char *const mt7629_i2c_groups[] = { "i2c_0", "i2c_1", };
+static const char *const mt7629_led_groups[] = { "ephy_leds", "ephy_led0",
+						"ephy_led1", "ephy_led2",
+						"ephy_led3", "ephy_led4",
+						"wf2g_led", "wf5g_led",
+						"gphy_leds_0", "gphy_led1_0",
+						"gphy_led2_0", "gphy_led3_0",
+						"gphy_leds_1", "gphy_led1_1",
+						"gphy_led2_1", "gphy_led3_1",};
+static const char *const mt7629_pcie_groups[] = { "pcie_pereset", "pcie_wake",
+						"pcie_clkreq", };
+static const char *const mt7629_pwm_groups[] = { "pwm_0", "pwm_1", };
+static const char *const mt7629_spi_groups[] = { "spi_0", "spi_1", "spi_wp",
+						"spi_hold", };
+static const char *const mt7629_uart_groups[] = { "uart1_0_txd_rxd",
+						"uart1_1_txd_rxd",
+						"uart2_0_txd_rxd",
+						"uart2_1_txd_rxd",
+						"uart1_0_cts_rts",
+						"uart1_1_cts_rts",
+						"uart2_0_cts_rts",
+						"uart2_1_cts_rts",
+						"uart0_txd_rxd", };
+static const char *const mt7629_wdt_groups[] = { "watchdog", };
+static const char *const mt7629_wifi_groups[] = { "wf0_5g", "wf0_2g", };
+static const char *const mt7629_flash_groups[] = { "snfi", "spi_nor" };
+
+static const struct mtk_function_desc mt7629_functions[] = {
+	{"eth",	mt7629_ethernet_groups, ARRAY_SIZE(mt7629_ethernet_groups)},
+	{"i2c", mt7629_i2c_groups, ARRAY_SIZE(mt7629_i2c_groups)},
+	{"led",	mt7629_led_groups, ARRAY_SIZE(mt7629_led_groups)},
+	{"pcie", mt7629_pcie_groups, ARRAY_SIZE(mt7629_pcie_groups)},
+	{"pwm",	mt7629_pwm_groups, ARRAY_SIZE(mt7629_pwm_groups)},
+	{"spi",	mt7629_spi_groups, ARRAY_SIZE(mt7629_spi_groups)},
+	{"uart", mt7629_uart_groups, ARRAY_SIZE(mt7629_uart_groups)},
+	{"watchdog", mt7629_wdt_groups, ARRAY_SIZE(mt7629_wdt_groups)},
+	{"wifi", mt7629_wifi_groups, ARRAY_SIZE(mt7629_wifi_groups)},
+	{"flash", mt7629_flash_groups, ARRAY_SIZE(mt7629_flash_groups)},
+};
+
+static struct mtk_pinctrl_soc mt7629_data = {
+	.name = "mt7629_pinctrl",
+	.reg_cal = mt7629_reg_cals,
+	.pins = mt7629_pins,
+	.npins = ARRAY_SIZE(mt7629_pins),
+	.grps = mt7629_groups,
+	.ngrps = ARRAY_SIZE(mt7629_groups),
+	.funcs = mt7629_functions,
+	.nfuncs = ARRAY_SIZE(mt7629_functions),
+};
+
+static int mtk_pinctrl_mt7629_probe(struct udevice *dev)
+{
+	return mtk_pinctrl_common_probe(dev, &mt7629_data);
+}
+
+static const struct udevice_id mt7629_pctrl_match[] = {
+	{ .compatible = "mediatek,mt7629-pinctrl" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(mt7629_pinctrl) = {
+	.name = "mt7629_pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = mt7629_pctrl_match,
+	.ops = &mtk_pinctrl_ops,
+	.probe = mtk_pinctrl_mt7629_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_pinctrl_priv),
+};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
new file mode 100644
index 0000000..938cc75
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <asm/io.h>
+#include <asm-generic/gpio.h>
+
+#include "pinctrl-mtk-common.h"
+
+/**
+ * struct mtk_drive_desc - the structure that holds the information
+ *			    of the driving current
+ * @min:	the minimum current of this group
+ * @max:	the maximum current of this group
+ * @step:	the step current of this group
+ * @scal:	the weight factor
+ *
+ * formula: output = ((input) / step - 1) * scal
+ */
+struct mtk_drive_desc {
+	u8 min;
+	u8 max;
+	u8 step;
+	u8 scal;
+};
+
+/* The groups of drive strength */
+static const struct mtk_drive_desc mtk_drive[] = {
+	[DRV_GRP0] = { 4, 16, 4, 1 },
+	[DRV_GRP1] = { 4, 16, 4, 2 },
+	[DRV_GRP2] = { 2, 8, 2, 1 },
+	[DRV_GRP3] = { 2, 8, 2, 2 },
+	[DRV_GRP4] = { 2, 16, 2, 1 },
+};
+
+static const char *mtk_pinctrl_dummy_name = "_dummy";
+
+static void mtk_w32(struct udevice *dev, u32 reg, u32 val)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+	__raw_writel(val, priv->base + reg);
+}
+
+static u32 mtk_r32(struct udevice *dev, u32 reg)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return __raw_readl(priv->base + reg);
+}
+
+static inline int get_count_order(unsigned int count)
+{
+	int order;
+
+	order = fls(count) - 1;
+	if (count & (count - 1))
+		order++;
+	return order;
+}
+
+void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set)
+{
+	u32 val;
+
+	val = mtk_r32(dev, reg);
+	val &= ~mask;
+	val |= set;
+	mtk_w32(dev, reg, val);
+}
+
+static int mtk_hw_pin_field_lookup(struct udevice *dev, int pin,
+				   const struct mtk_pin_reg_calc *rc,
+				   struct mtk_pin_field *pfd)
+{
+	const struct mtk_pin_field_calc *c, *e;
+	u32 bits;
+
+	c = rc->range;
+	e = c + rc->nranges;
+
+	while (c < e) {
+		if (pin >= c->s_pin && pin <= c->e_pin)
+			break;
+		c++;
+	}
+
+	if (c >= e)
+		return -EINVAL;
+
+	/* Calculated bits as the overall offset the pin is located at,
+	 * if c->fixed is held, that determines the all the pins in the
+	 * range use the same field with the s_pin.
+	 */
+	bits = c->fixed ? c->s_bit : c->s_bit + (pin - c->s_pin) * (c->x_bits);
+
+	/* Fill pfd from bits. For example 32-bit register applied is assumed
+	 * when c->sz_reg is equal to 32.
+	 */
+	pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg);
+	pfd->bitpos = bits % c->sz_reg;
+	pfd->mask = (1 << c->x_bits) - 1;
+
+	/* pfd->next is used for indicating that bit wrapping-around happens
+	 * which requires the manipulation for bit 0 starting in the next
+	 * register to form the complete field read/write.
+	 */
+	pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0;
+
+	return 0;
+}
+
+static int mtk_hw_pin_field_get(struct udevice *dev, int pin,
+				int field, struct mtk_pin_field *pfd)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct mtk_pin_reg_calc *rc;
+
+	if (field < 0 || field >= PINCTRL_PIN_REG_MAX)
+		return -EINVAL;
+
+	if (priv->soc->reg_cal && priv->soc->reg_cal[field].range)
+		rc = &priv->soc->reg_cal[field];
+	else
+		return -EINVAL;
+
+	return mtk_hw_pin_field_lookup(dev, pin, rc, pfd);
+}
+
+static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l)
+{
+	*l = 32 - pf->bitpos;
+	*h = get_count_order(pf->mask) - *l;
+}
+
+static void mtk_hw_write_cross_field(struct udevice *dev,
+				     struct mtk_pin_field *pf, int value)
+{
+	int nbits_l, nbits_h;
+
+	mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
+
+	mtk_rmw(dev, pf->offset, pf->mask << pf->bitpos,
+		(value & pf->mask) << pf->bitpos);
+
+	mtk_rmw(dev, pf->offset + pf->next, BIT(nbits_h) - 1,
+		(value & pf->mask) >> nbits_l);
+}
+
+static void mtk_hw_read_cross_field(struct udevice *dev,
+				    struct mtk_pin_field *pf, int *value)
+{
+	int nbits_l, nbits_h, h, l;
+
+	mtk_hw_bits_part(pf, &nbits_h, &nbits_l);
+
+	l  = (mtk_r32(dev, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1);
+	h  = (mtk_r32(dev, pf->offset + pf->next)) & (BIT(nbits_h) - 1);
+
+	*value = (h << nbits_l) | l;
+}
+
+static int mtk_hw_set_value(struct udevice *dev, int pin, int field,
+			    int value)
+{
+	struct mtk_pin_field pf;
+	int err;
+
+	err = mtk_hw_pin_field_get(dev, pin, field, &pf);
+	if (err)
+		return err;
+
+	if (!pf.next)
+		mtk_rmw(dev, pf.offset, pf.mask << pf.bitpos,
+			(value & pf.mask) << pf.bitpos);
+	else
+		mtk_hw_write_cross_field(dev, &pf, value);
+
+	return 0;
+}
+
+static int mtk_hw_get_value(struct udevice *dev, int pin, int field,
+			    int *value)
+{
+	struct mtk_pin_field pf;
+	int err;
+
+	err = mtk_hw_pin_field_get(dev, pin, field, &pf);
+	if (err)
+		return err;
+
+	if (!pf.next)
+		*value = (mtk_r32(dev, pf.offset) >> pf.bitpos) & pf.mask;
+	else
+		mtk_hw_read_cross_field(dev, &pf, value);
+
+	return 0;
+}
+
+static int mtk_get_groups_count(struct udevice *dev)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->soc->ngrps;
+}
+
+static const char *mtk_get_pin_name(struct udevice *dev,
+				    unsigned int selector)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+	if (!priv->soc->grps[selector].name)
+		return mtk_pinctrl_dummy_name;
+
+	return priv->soc->pins[selector].name;
+}
+
+static int mtk_get_pins_count(struct udevice *dev)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->soc->npins;
+}
+
+static const char *mtk_get_group_name(struct udevice *dev,
+				      unsigned int selector)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+	if (!priv->soc->grps[selector].name)
+		return mtk_pinctrl_dummy_name;
+
+	return priv->soc->grps[selector].name;
+}
+
+static int mtk_get_functions_count(struct udevice *dev)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->soc->nfuncs;
+}
+
+static const char *mtk_get_function_name(struct udevice *dev,
+					 unsigned int selector)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+
+	if (!priv->soc->funcs[selector].name)
+		return mtk_pinctrl_dummy_name;
+
+	return priv->soc->funcs[selector].name;
+}
+
+static int mtk_pinmux_group_set(struct udevice *dev,
+				unsigned int group_selector,
+				unsigned int func_selector)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct mtk_group_desc *grp =
+			&priv->soc->grps[group_selector];
+	int i;
+
+	for (i = 0; i < grp->num_pins; i++) {
+		int *pin_modes = grp->data;
+
+		mtk_hw_set_value(dev, grp->pins[i], PINCTRL_PIN_REG_MODE,
+				 pin_modes[i]);
+	}
+
+	return 0;
+}
+
+#if CONFIG_IS_ENABLED(PINCONF)
+static const struct pinconf_param mtk_conf_params[] = {
+	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+	{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+	{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+	{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
+	{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
+	{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+	{ "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
+	{ "output-high", PIN_CONFIG_OUTPUT, 1, },
+	{ "output-low", PIN_CONFIG_OUTPUT, 0, },
+	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+};
+
+int mtk_pinconf_drive_set(struct udevice *dev, u32 pin, u32 arg)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct mtk_pin_desc *desc = &priv->soc->pins[pin];
+	const struct mtk_drive_desc *tb;
+	int err = -ENOTSUPP;
+
+	tb = &mtk_drive[desc->drv_n];
+	/* 4mA when (e8, e4) = (0, 0)
+	 * 8mA when (e8, e4) = (0, 1)
+	 * 12mA when (e8, e4) = (1, 0)
+	 * 16mA when (e8, e4) = (1, 1)
+	 */
+	if ((arg >= tb->min && arg <= tb->max) && !(arg % tb->step)) {
+		arg = (arg / tb->step - 1) * tb->scal;
+
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DRV, arg);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int mtk_pinconf_set(struct udevice *dev, unsigned int pin,
+			   unsigned int param, unsigned int arg)
+{
+	int err = 0;
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+	case PIN_CONFIG_BIAS_PULL_UP:
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
+			(param == PIN_CONFIG_BIAS_PULL_UP) ? 3 : 2;
+
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLSEL,
+				       arg & 1);
+		if (err)
+			goto err;
+
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLEN,
+				       !!(arg & 2));
+		if (err)
+			goto err;
+		break;
+	case PIN_CONFIG_OUTPUT_ENABLE:
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_SMT, 0);
+		if (err)
+			goto err;
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 1);
+		if (err)
+			goto err;
+		break;
+	case PIN_CONFIG_INPUT_ENABLE:
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_IES, 1);
+		if (err)
+			goto err;
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 0);
+		if (err)
+			goto err;
+		break;
+	case PIN_CONFIG_OUTPUT:
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR, 1);
+		if (err)
+			goto err;
+
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DO, arg);
+		if (err)
+			goto err;
+		break;
+	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+		/* arg = 1: Input mode & SMT enable ;
+		 * arg = 0: Output mode & SMT disable
+		 */
+		arg = arg ? 2 : 1;
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_DIR,
+				       arg & 1);
+		if (err)
+			goto err;
+
+		err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_SMT,
+				       !!(arg & 2));
+		if (err)
+			goto err;
+		break;
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		err = mtk_pinconf_drive_set(dev, pin, arg);
+		if (err)
+			goto err;
+		break;
+
+	default:
+		err = -ENOTSUPP;
+	}
+
+err:
+
+	return err;
+}
+
+static int mtk_pinconf_group_set(struct udevice *dev,
+				 unsigned int group_selector,
+				 unsigned int param, unsigned int arg)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct mtk_group_desc *grp =
+			&priv->soc->grps[group_selector];
+	int i, ret;
+
+	for (i = 0; i < grp->num_pins; i++) {
+		ret = mtk_pinconf_set(dev, grp->pins[i], param, arg);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+#endif
+
+const struct pinctrl_ops mtk_pinctrl_ops = {
+	.get_pins_count = mtk_get_pins_count,
+	.get_pin_name = mtk_get_pin_name,
+	.get_groups_count = mtk_get_groups_count,
+	.get_group_name = mtk_get_group_name,
+	.get_functions_count = mtk_get_functions_count,
+	.get_function_name = mtk_get_function_name,
+	.pinmux_group_set = mtk_pinmux_group_set,
+#if CONFIG_IS_ENABLED(PINCONF)
+	.pinconf_num_params = ARRAY_SIZE(mtk_conf_params),
+	.pinconf_params = mtk_conf_params,
+	.pinconf_set = mtk_pinconf_set,
+	.pinconf_group_set = mtk_pinconf_group_set,
+#endif
+	.set_state = pinctrl_generic_set_state,
+};
+
+static int mtk_gpio_get(struct udevice *dev, unsigned int off)
+{
+	int val, err;
+
+	err = mtk_hw_get_value(dev->parent, off, PINCTRL_PIN_REG_DI, &val);
+	if (err)
+		return err;
+
+	return !!val;
+}
+
+static int mtk_gpio_set(struct udevice *dev, unsigned int off, int val)
+{
+	return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DO, !!val);
+}
+
+static int mtk_gpio_get_direction(struct udevice *dev, unsigned int off)
+{
+	int val, err;
+
+	err = mtk_hw_get_value(dev->parent, off, PINCTRL_PIN_REG_DIR, &val);
+	if (err)
+		return err;
+
+	return val ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static int mtk_gpio_direction_input(struct udevice *dev, unsigned int off)
+{
+	return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DIR, 0);
+}
+
+static int mtk_gpio_direction_output(struct udevice *dev,
+				     unsigned int off, int val)
+{
+	mtk_gpio_set(dev, off, val);
+
+	/* And set the requested value */
+	return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_DIR, 1);
+}
+
+static int mtk_gpio_request(struct udevice *dev, unsigned int off,
+			    const char *label)
+{
+	return mtk_hw_set_value(dev->parent, off, PINCTRL_PIN_REG_MODE, 0);
+}
+
+static int mtk_gpio_probe(struct udevice *dev)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev->parent);
+	struct gpio_dev_priv *uc_priv;
+
+	uc_priv = dev_get_uclass_priv(dev);
+	uc_priv->bank_name = priv->soc->name;
+	uc_priv->gpio_count = priv->soc->npins;
+
+	return 0;
+}
+
+static const struct dm_gpio_ops mtk_gpio_ops = {
+	.request = mtk_gpio_request,
+	.set_value = mtk_gpio_set,
+	.get_value = mtk_gpio_get,
+	.get_function = mtk_gpio_get_direction,
+	.direction_input = mtk_gpio_direction_input,
+	.direction_output = mtk_gpio_direction_output,
+};
+
+static struct driver mtk_gpio_driver = {
+	.name = "mediatek_gpio",
+	.id	= UCLASS_GPIO,
+	.probe = mtk_gpio_probe,
+	.ops = &mtk_gpio_ops,
+};
+
+static int mtk_gpiochip_register(struct udevice *parent)
+{
+	struct uclass_driver *drv;
+	struct udevice *dev;
+	int ret;
+	ofnode node;
+
+	drv = lists_uclass_lookup(UCLASS_GPIO);
+	if (!drv)
+		return -ENOENT;
+
+	dev_for_each_subnode(node, parent)
+		if (ofnode_read_bool(node, "gpio-controller")) {
+			ret = 0;
+			break;
+		}
+
+	if (ret)
+		return ret;
+
+	ret = device_bind_with_driver_data(parent, &mtk_gpio_driver,
+					   "mediatek_gpio", 0, node,
+					   &dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int mtk_pinctrl_common_probe(struct udevice *dev,
+			     struct mtk_pinctrl_soc *soc)
+{
+	struct mtk_pinctrl_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (priv->base == (void *)FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->soc = soc;
+
+	ret = mtk_gpiochip_register(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
new file mode 100644
index 0000000..86559f0
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#ifndef __PINCTRL_MEDIATEK_H__
+#define __PINCTRL_MEDIATEK_H__
+
+#define MTK_RANGE(_a)		{ .range = (_a), .nranges = ARRAY_SIZE(_a), }
+#define MTK_PIN(_number, _name, _drv_n) {				\
+		.number = _number,					\
+		.name = _name,						\
+		.drv_n = _drv_n,					\
+	}
+
+#define PINCTRL_PIN_GROUP(name, id)					\
+	{								\
+		name,							\
+		id##_pins,						\
+		ARRAY_SIZE(id##_pins),					\
+		id##_funcs,						\
+	}
+
+#define PIN_FIELD_CALC(_s_pin, _e_pin, _s_addr, _x_addrs, _s_bit,	\
+			_x_bits, _sz_reg, _fixed) {			\
+		.s_pin = _s_pin,					\
+		.e_pin = _e_pin,					\
+		.s_addr = _s_addr,					\
+		.x_addrs = _x_addrs,					\
+		.s_bit = _s_bit,					\
+		.x_bits = _x_bits,					\
+		.sz_reg = _sz_reg,					\
+		.fixed = _fixed,					\
+	}
+
+/* List these attributes which could be modified for the pin */
+enum {
+	PINCTRL_PIN_REG_MODE,
+	PINCTRL_PIN_REG_DIR,
+	PINCTRL_PIN_REG_DI,
+	PINCTRL_PIN_REG_DO,
+	PINCTRL_PIN_REG_IES,
+	PINCTRL_PIN_REG_SMT,
+	PINCTRL_PIN_REG_PULLEN,
+	PINCTRL_PIN_REG_PULLSEL,
+	PINCTRL_PIN_REG_DRV,
+	PINCTRL_PIN_REG_MAX,
+};
+
+/* Group the pins by the driving current */
+enum {
+	DRV_FIXED,
+	DRV_GRP0,
+	DRV_GRP1,
+	DRV_GRP2,
+	DRV_GRP3,
+	DRV_GRP4,
+};
+
+/**
+ * struct mtk_pin_field - the structure that holds the information of the field
+ *			  used to describe the attribute for the pin
+ * @offset:		the register offset relative to the base address
+ * @mask:		the mask used to filter out the field from the register
+ * @bitpos:		the start bit relative to the register
+ * @next:		the indication that the field would be extended to the
+			next register
+ */
+struct mtk_pin_field {
+	u32 offset;
+	u32 mask;
+	u8 bitpos;
+	u8 next;
+};
+
+/**
+ * struct mtk_pin_field_calc - the structure that holds the range providing
+ *			       the guide used to look up the relevant field
+ * @s_pin:		the start pin within the range
+ * @e_pin:		the end pin within the range
+ * @s_addr:		the start address for the range
+ * @x_addrs:		the address distance between two consecutive registers
+ *			within the range
+ * @s_bit:		the start bit for the first register within the range
+ * @x_bits:		the bit distance between two consecutive pins within
+ *			the range
+ * @sz_reg:		the size of bits in a register
+ * @fixed:		the consecutive pins share the same bits with the 1st
+ *			pin
+ */
+struct mtk_pin_field_calc {
+	u16 s_pin;
+	u16 e_pin;
+	u32 s_addr;
+	u8 x_addrs;
+	u8 s_bit;
+	u8 x_bits;
+	u8 sz_reg;
+	u8 fixed;
+};
+
+/**
+ * struct mtk_pin_reg_calc - the structure that holds all ranges used to
+ *			     determine which register the pin would make use of
+ *			     for certain pin attribute.
+ * @range:		     the start address for the range
+ * @nranges:		     the number of items in the range
+ */
+struct mtk_pin_reg_calc {
+	const struct mtk_pin_field_calc *range;
+	unsigned int nranges;
+};
+
+/**
+ * struct mtk_pin_desc - the structure that providing information
+ *			 for each pin of chips
+ * @number:		unique pin number from the global pin number space
+ * @name:		name for this pin
+ * @drv_n:		the index with the driving group
+ */
+struct mtk_pin_desc {
+	unsigned int number;
+	const char *name;
+	u8 drv_n;
+};
+
+/**
+ * struct mtk_group_desc - generic pin group descriptor
+ * @name: name of the pin group
+ * @pins: array of pins that belong to the group
+ * @num_pins: number of pins in the group
+ * @data: pin controller driver specific data
+ */
+struct mtk_group_desc {
+	const char *name;
+	int *pins;
+	int num_pins;
+	void *data;
+};
+
+/**
+ * struct mtk_function_desc - generic function descriptor
+ * @name: name of the function
+ * @group_names: array of pin group names
+ * @num_group_names: number of pin group names
+ */
+struct mtk_function_desc {
+	const char *name;
+	const char * const *group_names;
+	int num_group_names;
+};
+
+/* struct mtk_pin_soc - the structure that holds SoC-specific data */
+struct mtk_pinctrl_soc {
+	const char *name;
+	const struct mtk_pin_reg_calc *reg_cal;
+	const struct mtk_pin_desc *pins;
+	int npins;
+	const struct mtk_group_desc *grps;
+	int ngrps;
+	const struct mtk_function_desc *funcs;
+	int nfuncs;
+};
+
+/**
+ * struct mtk_pinctrl_priv - private data for MTK pinctrl driver
+ *
+ * @base: base address of the pinctrl device
+ * @soc: SoC specific data
+ */
+struct mtk_pinctrl_priv {
+	void __iomem *base;
+	struct mtk_pinctrl_soc *soc;
+};
+
+extern const struct pinctrl_ops mtk_pinctrl_ops;
+
+/* A common read-modify-write helper for MediaTek chips */
+void mtk_rmw(struct udevice *dev, u32 reg, u32 mask, u32 set);
+int mtk_pinctrl_common_probe(struct udevice *dev,
+			     struct mtk_pinctrl_soc *soc);
+
+#endif /* __PINCTRL_MEDIATEK_H__ */
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index a08b428..93deaef 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -23,6 +23,13 @@
           Enable support for manipulating NXP i.MX8 on-SoC power domains via IPC
           requests to the SCU.
 
+config MTK_POWER_DOMAIN
+	bool "Enable the MediaTek power domain driver"
+	depends on POWER_DOMAIN && ARCH_MEDIATEK
+	help
+	  Enable support for manipulating MediaTek power domains via MMIO
+	  mapped registers.
+
 config MESON_GX_VPU_POWER_DOMAIN
 	bool "Enable Amlogic Meson GX VPU power domain driver"
 	depends on ARCH_MESON
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index b08d18f..695aafe 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_$(SPL_)POWER_DOMAIN) += power-domain-uclass.o
 obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
 obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain.o
+obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o
 obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o
 obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
 obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
diff --git a/drivers/power/domain/mtk-power-domain.c b/drivers/power/domain/mtk-power-domain.c
new file mode 100644
index 0000000..c67e880
--- /dev/null
+++ b/drivers/power/domain/mtk-power-domain.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <power-domain-uclass.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <linux/iopoll.h>
+
+#include <dt-bindings/power/mt7623-power.h>
+#include <dt-bindings/power/mt7629-power.h>
+
+#define SPM_EN			(0xb16 << 16 | 0x1)
+#define SPM_VDE_PWR_CON		0x0210
+#define SPM_MFG_PWR_CON		0x0214
+#define SPM_ISP_PWR_CON		0x0238
+#define SPM_DIS_PWR_CON		0x023c
+#define SPM_CONN_PWR_CON	0x0280
+#define SPM_BDP_PWR_CON		0x029c
+#define SPM_ETH_PWR_CON		0x02a0
+#define SPM_HIF_PWR_CON		0x02a4
+#define SPM_IFR_MSC_PWR_CON	0x02a8
+#define SPM_ETHSYS_PWR_CON	0x2e0
+#define SPM_HIF0_PWR_CON	0x2e4
+#define SPM_HIF1_PWR_CON	0x2e8
+#define SPM_PWR_STATUS		0x60c
+#define SPM_PWR_STATUS_2ND	0x610
+
+#define PWR_RST_B_BIT		BIT(0)
+#define PWR_ISO_BIT		BIT(1)
+#define PWR_ON_BIT		BIT(2)
+#define PWR_ON_2ND_BIT		BIT(3)
+#define PWR_CLK_DIS_BIT		BIT(4)
+
+#define PWR_STATUS_CONN		BIT(1)
+#define PWR_STATUS_DISP		BIT(3)
+#define PWR_STATUS_MFG		BIT(4)
+#define PWR_STATUS_ISP		BIT(5)
+#define PWR_STATUS_VDEC		BIT(7)
+#define PWR_STATUS_BDP		BIT(14)
+#define PWR_STATUS_ETH		BIT(15)
+#define PWR_STATUS_HIF		BIT(16)
+#define PWR_STATUS_IFR_MSC	BIT(17)
+#define PWR_STATUS_ETHSYS	BIT(24)
+#define PWR_STATUS_HIF0		BIT(25)
+#define PWR_STATUS_HIF1		BIT(26)
+
+/* Infrasys configuration */
+#define INFRA_TOPDCM_CTRL	0x10
+#define INFRA_TOPAXI_PROT_EN	0x220
+#define INFRA_TOPAXI_PROT_STA1	0x228
+
+#define DCM_TOP_EN		BIT(0)
+
+enum scp_domain_type {
+	SCPSYS_MT7623,
+	SCPSYS_MT7629,
+};
+
+struct scp_domain;
+
+struct scp_domain_data {
+	struct scp_domain *scpd;
+	u32 sta_mask;
+	int ctl_offs;
+	u32 sram_pdn_bits;
+	u32 sram_pdn_ack_bits;
+	u32 bus_prot_mask;
+};
+
+struct scp_domain {
+	void __iomem *base;
+	void __iomem *infracfg;
+	enum scp_domain_type type;
+	struct scp_domain_data *data;
+};
+
+static struct scp_domain_data scp_domain_mt7623[] = {
+	[MT7623_POWER_DOMAIN_CONN] = {
+		.sta_mask = PWR_STATUS_CONN,
+		.ctl_offs = SPM_CONN_PWR_CON,
+		.bus_prot_mask = BIT(8) | BIT(2),
+	},
+	[MT7623_POWER_DOMAIN_DISP] = {
+		.sta_mask = PWR_STATUS_DISP,
+		.ctl_offs = SPM_DIS_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.bus_prot_mask = BIT(2),
+	},
+	[MT7623_POWER_DOMAIN_MFG] = {
+		.sta_mask = PWR_STATUS_MFG,
+		.ctl_offs = SPM_MFG_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(12, 12),
+	},
+	[MT7623_POWER_DOMAIN_VDEC] = {
+		.sta_mask = PWR_STATUS_VDEC,
+		.ctl_offs = SPM_VDE_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(12, 12),
+	},
+	[MT7623_POWER_DOMAIN_ISP] = {
+		.sta_mask = PWR_STATUS_ISP,
+		.ctl_offs = SPM_ISP_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(13, 12),
+	},
+	[MT7623_POWER_DOMAIN_BDP] = {
+		.sta_mask = PWR_STATUS_BDP,
+		.ctl_offs = SPM_BDP_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+	},
+	[MT7623_POWER_DOMAIN_ETH] = {
+		.sta_mask = PWR_STATUS_ETH,
+		.ctl_offs = SPM_ETH_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+	},
+	[MT7623_POWER_DOMAIN_HIF] = {
+		.sta_mask = PWR_STATUS_HIF,
+		.ctl_offs = SPM_HIF_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+	},
+	[MT7623_POWER_DOMAIN_IFR_MSC] = {
+		.sta_mask = PWR_STATUS_IFR_MSC,
+		.ctl_offs = SPM_IFR_MSC_PWR_CON,
+	},
+};
+
+static struct scp_domain_data scp_domain_mt7629[] = {
+	[MT7629_POWER_DOMAIN_ETHSYS] = {
+		.sta_mask = PWR_STATUS_ETHSYS,
+		.ctl_offs = SPM_ETHSYS_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.bus_prot_mask = (BIT(3) | BIT(17)),
+	},
+	[MT7629_POWER_DOMAIN_HIF0] = {
+		.sta_mask = PWR_STATUS_HIF0,
+		.ctl_offs = SPM_HIF0_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.bus_prot_mask = GENMASK(25, 24),
+	},
+	[MT7629_POWER_DOMAIN_HIF1] = {
+		.sta_mask = PWR_STATUS_HIF1,
+		.ctl_offs = SPM_HIF1_PWR_CON,
+		.sram_pdn_bits = GENMASK(11, 8),
+		.sram_pdn_ack_bits = GENMASK(15, 12),
+		.bus_prot_mask = GENMASK(28, 26),
+	},
+};
+
+/**
+ * This function enables the bus protection bits for disabled power
+ * domains so that the system does not hang when some unit accesses the
+ * bus while in power down.
+ */
+static int mtk_infracfg_set_bus_protection(void __iomem *infracfg,
+					   u32 mask)
+{
+	u32 val;
+
+	clrsetbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask, mask);
+
+	return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val,
+				  (val & mask) == mask, 100);
+}
+
+static int mtk_infracfg_clear_bus_protection(void __iomem *infracfg,
+					     u32 mask)
+{
+	u32 val;
+
+	clrbits_le32(infracfg + INFRA_TOPAXI_PROT_EN, mask);
+
+	return readl_poll_timeout(infracfg + INFRA_TOPAXI_PROT_STA1, val,
+				  !(val & mask), 100);
+}
+
+static int scpsys_domain_is_on(struct scp_domain_data *data)
+{
+	struct scp_domain *scpd = data->scpd;
+	u32 sta = readl(scpd->base + SPM_PWR_STATUS) &
+			data->sta_mask;
+	u32 sta2 = readl(scpd->base + SPM_PWR_STATUS_2ND) &
+			 data->sta_mask;
+
+	/*
+	 * A domain is on when both status bits are set. If only one is set
+	 * return an error. This happens while powering up a domain
+	 */
+	if (sta && sta2)
+		return true;
+	if (!sta && !sta2)
+		return false;
+
+	return -EINVAL;
+}
+
+static int scpsys_power_on(struct power_domain *power_domain)
+{
+	struct scp_domain *scpd = dev_get_priv(power_domain->dev);
+	struct scp_domain_data *data = &scpd->data[power_domain->id];
+	void __iomem *ctl_addr = scpd->base + data->ctl_offs;
+	u32 pdn_ack = data->sram_pdn_ack_bits;
+	u32 val;
+	int ret, tmp;
+
+	writel(SPM_EN, scpd->base);
+
+	val = readl(ctl_addr);
+	val |= PWR_ON_BIT;
+	writel(val, ctl_addr);
+
+	val |= PWR_ON_2ND_BIT;
+	writel(val, ctl_addr);
+
+	ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, tmp > 0,
+				 100);
+	if (ret < 0)
+		return ret;
+
+	val &= ~PWR_CLK_DIS_BIT;
+	writel(val, ctl_addr);
+
+	val &= ~PWR_ISO_BIT;
+	writel(val, ctl_addr);
+
+	val |= PWR_RST_B_BIT;
+	writel(val, ctl_addr);
+
+	val &= ~data->sram_pdn_bits;
+	writel(val, ctl_addr);
+
+	ret = readl_poll_timeout(ctl_addr, tmp, !(tmp & pdn_ack), 100);
+	if (ret < 0)
+		return ret;
+
+	if (data->bus_prot_mask) {
+		ret = mtk_infracfg_clear_bus_protection(scpd->infracfg,
+							data->bus_prot_mask);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int scpsys_power_off(struct power_domain *power_domain)
+{
+	struct scp_domain *scpd = dev_get_priv(power_domain->dev);
+	struct scp_domain_data *data = &scpd->data[power_domain->id];
+	void __iomem *ctl_addr = scpd->base + data->ctl_offs;
+	u32 pdn_ack = data->sram_pdn_ack_bits;
+	u32 val;
+	int ret, tmp;
+
+	if (data->bus_prot_mask) {
+		ret = mtk_infracfg_set_bus_protection(scpd->infracfg,
+						      data->bus_prot_mask);
+		if (ret)
+			return ret;
+	}
+
+	val = readl(ctl_addr);
+	val |= data->sram_pdn_bits;
+	writel(val, ctl_addr);
+
+	ret = readl_poll_timeout(ctl_addr, tmp, (tmp & pdn_ack) == pdn_ack,
+				 100);
+	if (ret < 0)
+		return ret;
+
+	val |= PWR_ISO_BIT;
+	writel(val, ctl_addr);
+
+	val &= ~PWR_RST_B_BIT;
+	writel(val, ctl_addr);
+
+	val |= PWR_CLK_DIS_BIT;
+	writel(val, ctl_addr);
+
+	val &= ~PWR_ON_BIT;
+	writel(val, ctl_addr);
+
+	val &= ~PWR_ON_2ND_BIT;
+	writel(val, ctl_addr);
+
+	ret = readx_poll_timeout(scpsys_domain_is_on, data, tmp, !tmp, 100);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int scpsys_power_request(struct power_domain *power_domain)
+{
+	struct scp_domain *scpd = dev_get_priv(power_domain->dev);
+	struct scp_domain_data *data;
+
+	data = &scpd->data[power_domain->id];
+	data->scpd = scpd;
+
+	return 0;
+}
+
+static int scpsys_power_free(struct power_domain *power_domain)
+{
+	return 0;
+}
+
+static int mtk_power_domain_hook(struct udevice *dev)
+{
+	struct scp_domain *scpd = dev_get_priv(dev);
+
+	scpd->type = (enum scp_domain_type)dev_get_driver_data(dev);
+
+	switch (scpd->type) {
+	case SCPSYS_MT7623:
+		scpd->data = scp_domain_mt7623;
+		break;
+	case SCPSYS_MT7629:
+		scpd->data = scp_domain_mt7629;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mtk_power_domain_probe(struct udevice *dev)
+{
+	struct ofnode_phandle_args args;
+	struct scp_domain *scpd = dev_get_priv(dev);
+	struct regmap *regmap;
+	struct clk_bulk bulk;
+	int err;
+
+	scpd->base = dev_read_addr_ptr(dev);
+	if (!scpd->base)
+		return -ENOENT;
+
+	err = mtk_power_domain_hook(dev);
+	if (err)
+		return err;
+
+	/* get corresponding syscon phandle */
+	err = dev_read_phandle_with_args(dev, "infracfg", NULL, 0, 0, &args);
+	if (err)
+		return err;
+
+	regmap = syscon_node_to_regmap(args.node);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	scpd->infracfg = regmap_get_range(regmap, 0);
+	if (!scpd->infracfg)
+		return -ENOENT;
+
+	/* enable Infra DCM */
+	setbits_le32(scpd->infracfg + INFRA_TOPDCM_CTRL, DCM_TOP_EN);
+
+	err = clk_get_bulk(dev, &bulk);
+	if (err)
+		return err;
+
+	return clk_enable_bulk(&bulk);
+}
+
+static const struct udevice_id mtk_power_domain_ids[] = {
+	{
+		.compatible = "mediatek,mt7623-scpsys",
+		.data = SCPSYS_MT7623,
+	},
+	{
+		.compatible = "mediatek,mt7629-scpsys",
+		.data = SCPSYS_MT7629,
+	},
+	{ /* sentinel */ }
+};
+
+struct power_domain_ops mtk_power_domain_ops = {
+	.free = scpsys_power_free,
+	.off = scpsys_power_off,
+	.on = scpsys_power_on,
+	.request = scpsys_power_request,
+};
+
+U_BOOT_DRIVER(mtk_power_domain) = {
+	.name = "mtk_power_domain",
+	.id = UCLASS_POWER_DOMAIN,
+	.ops = &mtk_power_domain_ops,
+	.probe = mtk_power_domain_probe,
+	.of_match = mtk_power_domain_ids,
+	.priv_auto_alloc_size = sizeof(struct scp_domain),
+};
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
index e14c1cf..976ec66 100644
--- a/drivers/ram/Makefile
+++ b/drivers/ram/Makefile
@@ -13,3 +13,4 @@
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 
 obj-$(CONFIG_K3_AM654_DDRSS) += k3-am654-ddrss.o
+obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
diff --git a/drivers/ram/mediatek/Makefile b/drivers/ram/mediatek/Makefile
new file mode 100644
index 0000000..95507b5
--- /dev/null
+++ b/drivers/ram/mediatek/Makefile
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2018 MediaTek Inc.
+#
+# SPDX-License-Identifier:      GPL-2.0
+#
+
+obj-$(CONFIG_TARGET_MT7629) = ddr3-mt7629.o
diff --git a/drivers/ram/mediatek/ddr3-mt7629.c b/drivers/ram/mediatek/ddr3-mt7629.c
new file mode 100644
index 0000000..b413f49
--- /dev/null
+++ b/drivers/ram/mediatek/ddr3-mt7629.c
@@ -0,0 +1,766 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek DDR3 driver for MT7629 SoC
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Wu Zou <wu.zou@mediatek.com>
+ *	   Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <asm/io.h>
+
+/* EMI */
+#define EMI_CONA			0x000
+#define EMI_CONF			0x028
+#define EMI_CONM			0x060
+
+/* DDR PHY */
+#define DDRPHY_PLL1			0x0000
+#define DDRPHY_PLL2			0x0004
+#define DDRPHY_PLL3			0x0008
+#define DDRPHY_PLL4			0x000c
+#define DDRPHY_PLL5			0x0010
+#define DDRPHY_PLL7			0x0018
+#define DDRPHY_B0_DLL_ARPI0		0x0080
+#define DDRPHY_B0_DLL_ARPI1		0x0084
+#define DDRPHY_B0_DLL_ARPI2		0x0088
+#define DDRPHY_B0_DLL_ARPI3		0x008c
+#define DDRPHY_B0_DLL_ARPI4		0x0090
+#define DDRPHY_B0_DLL_ARPI5		0x0094
+#define DDRPHY_B0_DQ2			0x00a0
+#define DDRPHY_B0_DQ3			0x00a4
+#define DDRPHY_B0_DQ4			0x00a8
+#define DDRPHY_B0_DQ5			0x00ac
+#define DDRPHY_B0_DQ6			0x00b0
+#define DDRPHY_B0_DQ7			0x00b4
+#define DDRPHY_B0_DQ8			0x00b8
+#define DDRPHY_B1_DLL_ARPI0		0x0100
+#define DDRPHY_B1_DLL_ARPI1		0x0104
+#define DDRPHY_B1_DLL_ARPI2		0x0108
+#define DDRPHY_B1_DLL_ARPI3		0x010c
+#define DDRPHY_B1_DLL_ARPI4		0x0110
+#define DDRPHY_B1_DLL_ARPI5		0x0114
+#define DDRPHY_B1_DQ2			0x0120
+#define DDRPHY_B1_DQ3			0x0124
+#define DDRPHY_B1_DQ4			0x0128
+#define DDRPHY_B1_DQ5			0x012c
+#define DDRPHY_B1_DQ6			0x0130
+#define DDRPHY_B1_DQ7			0x0134
+#define DDRPHY_B1_DQ8			0x0138
+#define DDRPHY_CA_DLL_ARPI0		0x0180
+#define DDRPHY_CA_DLL_ARPI1		0x0184
+#define DDRPHY_CA_DLL_ARPI2		0x0188
+#define DDRPHY_CA_DLL_ARPI3		0x018c
+#define DDRPHY_CA_DLL_ARPI4		0x0190
+#define DDRPHY_CA_DLL_ARPI5		0x0194
+#define DDRPHY_CA_CMD2			0x01a0
+#define DDRPHY_CA_CMD3			0x01a4
+#define DDRPHY_CA_CMD5			0x01ac
+#define DDRPHY_CA_CMD6			0x01b0
+#define DDRPHY_CA_CMD7			0x01b4
+#define DDRPHY_CA_CMD8			0x01b8
+#define DDRPHY_MISC_VREF_CTRL		0x0264
+#define DDRPHY_MISC_IMP_CTRL0		0x0268
+#define DDRPHY_MISC_IMP_CTRL1		0x026c
+#define DDRPHY_MISC_SHU_OPT		0x0270
+#define DDRPHY_MISC_SPM_CTRL0		0x0274
+#define DDRPHY_MISC_SPM_CTRL1		0x0278
+#define DDRPHY_MISC_SPM_CTRL2		0x027c
+#define DDRPHY_MISC_CG_CTRL0		0x0284
+#define DDRPHY_MISC_CG_CTRL1		0x0288
+#define DDRPHY_MISC_CG_CTRL2		0x028c
+#define DDRPHY_MISC_CG_CTRL4		0x0294
+#define DDRPHY_MISC_CTRL0		0x029c
+#define DDRPHY_MISC_CTRL1		0x02a0
+#define DDRPHY_MISC_CTRL3		0x02a8
+#define DDRPHY_MISC_RXDVS1		0x05e4
+#define DDRPHY_SHU1_B0_DQ4		0x0c10
+#define DDRPHY_SHU1_B0_DQ5		0x0c14
+#define DDRPHY_SHU1_B0_DQ6		0x0c18
+#define DDRPHY_SHU1_B0_DQ7		0x0c1c
+#define DDRPHY_SHU1_B1_DQ4		0x0c90
+#define DDRPHY_SHU1_B1_DQ5		0x0c94
+#define DDRPHY_SHU1_B1_DQ6		0x0c98
+#define DDRPHY_SHU1_B1_DQ7		0x0c9c
+#define DDRPHY_SHU1_CA_CMD2		0x0d08
+#define DDRPHY_SHU1_CA_CMD4		0x0d10
+#define DDRPHY_SHU1_CA_CMD5		0x0d14
+#define DDRPHY_SHU1_CA_CMD6		0x0d18
+#define DDRPHY_SHU1_CA_CMD7		0x0d1c
+#define DDRPHY_SHU1_PLL0		0x0d80
+#define DDRPHY_SHU1_PLL1		0x0d84
+#define DDRPHY_SHU1_PLL4		0x0d90
+#define DDRPHY_SHU1_PLL5		0x0d94
+#define DDRPHY_SHU1_PLL6		0x0d98
+#define DDRPHY_SHU1_PLL7		0x0d9C
+#define DDRPHY_SHU1_PLL8		0x0da0
+#define DDRPHY_SHU1_PLL9		0x0da4
+#define DDRPHY_SHU1_PLL10		0x0da8
+#define DDRPHY_SHU1_PLL11		0x0dac
+#define DDRPHY_SHU1_R0_B0_DQ2		0x0e08
+#define DDRPHY_SHU1_R0_B0_DQ3		0x0e0c
+#define DDRPHY_SHU1_R0_B0_DQ4		0x0e10
+#define DDRPHY_SHU1_R0_B0_DQ5		0x0e14
+#define DDRPHY_SHU1_R0_B0_DQ6		0x0e18
+#define DDRPHY_SHU1_R0_B0_DQ7		0x0e1c
+#define DDRPHY_SHU1_R0_B1_DQ2		0x0e58
+#define DDRPHY_SHU1_R0_B1_DQ3		0x0e5c
+#define DDRPHY_SHU1_R0_B1_DQ4		0x0e60
+#define DDRPHY_SHU1_R0_B1_DQ5		0x0e64
+#define DDRPHY_SHU1_R0_B1_DQ6		0x0e68
+#define DDRPHY_SHU1_R0_B1_DQ7		0x0e6c
+#define DDRPHY_SHU1_R0_CA_CMD9		0x0ec4
+#define DDRPHY_SHU1_R1_B0_DQ2		0x0f08
+#define DDRPHY_SHU1_R1_B0_DQ3		0x0f0c
+#define DDRPHY_SHU1_R1_B0_DQ4		0x0f10
+#define DDRPHY_SHU1_R1_B0_DQ5		0x0f14
+#define DDRPHY_SHU1_R1_B0_DQ6		0x0f18
+#define DDRPHY_SHU1_R1_B0_DQ7		0x0f1c
+#define DDRPHY_SHU1_R1_B1_DQ2		0x0f58
+#define DDRPHY_SHU1_R1_B1_DQ3		0x0f5c
+#define DDRPHY_SHU1_R1_B1_DQ4		0x0f60
+#define DDRPHY_SHU1_R1_B1_DQ5		0x0f64
+#define DDRPHY_SHU1_R1_B1_DQ6		0x0f68
+#define DDRPHY_SHU1_R1_B1_DQ7		0x0f6c
+#define DDRPHY_SHU1_R1_CA_CMD9		0x0fc4
+
+/* DRAMC */
+#define DRAMC_DDRCONF0			0x0000
+#define DRAMC_DRAMCTRL			0x0004
+#define DRAMC_MISCTL0			0x0008
+#define DRAMC_PERFCTL0			0x000c
+#define DRAMC_ARBCTL			0x0010
+#define DRAMC_RSTMASK			0x001c
+#define DRAMC_PADCTRL			0x0020
+#define DRAMC_CKECTRL			0x0024
+#define DRAMC_RKCFG			0x0034
+#define DRAMC_DRAMC_PD_CTRL		0x0038
+#define DRAMC_CLKAR			0x003c
+#define DRAMC_CLKCTRL			0x0040
+#define DRAMC_SREFCTRL			0x0048
+#define DRAMC_REFCTRL0			0x004c
+#define DRAMC_REFCTRL1			0x0050
+#define DRAMC_REFRATRE_FILTER		0x0054
+#define DRAMC_ZQCS			0x0058
+#define DRAMC_MRS			0x005c
+#define DRAMC_SPCMD			0x0060
+#define DRAMC_SPCMDCTRL			0x0064
+#define DRAMC_HW_MRR_FUN		0x0074
+#define DRAMC_TEST2_1			0x0094
+#define DRAMC_TEST2_2			0x0098
+#define DRAMC_TEST2_3			0x009c
+#define DRAMC_TEST2_4			0x00a0
+#define DRAMC_CATRAINING1		0x00b0
+#define DRAMC_DUMMY_RD			0x00d0
+#define DRAMC_SHUCTRL			0x00d4
+#define DRAMC_SHUCTRL2			0x00dc
+#define DRAMC_STBCAL			0x0200
+#define DRAMC_STBCAL1			0x0204
+#define DRAMC_EYESCAN			0x020c
+#define DRAMC_DVFSDLL			0x0210
+#define DRAMC_SHU_ACTIM0		0x0800
+#define DRAMC_SHU_ACTIM1		0x0804
+#define DRAMC_SHU_ACTIM2		0x0808
+#define DRAMC_SHU_ACTIM3		0x080c
+#define DRAMC_SHU_ACTIM4		0x0810
+#define DRAMC_SHU_ACTIM5		0x0814
+#define DRAMC_SHU_ACTIM_XRT		0x081c
+#define DRAMC_SHU_AC_TIME_05T		0x0820
+#define DRAMC_SHU_CONF0			0x0840
+#define DRAMC_SHU_CONF1			0x0844
+#define DRAMC_SHU_CONF2			0x0848
+#define DRAMC_SHU_CONF3			0x084c
+#define DRAMC_SHU_RANKCTL		0x0858
+#define DRAMC_SHU_CKECTRL		0x085c
+#define DRAMC_SHU_ODTCTRL		0x0860
+#define DRAMC_SHU_PIPE			0x0878
+#define DRAMC_SHU_SELPH_CA1		0x0880
+#define DRAMC_SHU_SELPH_CA2		0x0884
+#define DRAMC_SHU_SELPH_CA3		0x0888
+#define DRAMC_SHU_SELPH_CA4		0x088c
+#define DRAMC_SHU_SELPH_CA5		0x0890
+#define DRAMC_SHU_SELPH_CA6		0x0894
+#define DRAMC_SHU_SELPH_CA7		0x0898
+#define DRAMC_SHU_SELPH_CA8		0x089c
+#define DRAMC_SHU_SELPH_DQS0		0x08a0
+#define DRAMC_SHU_SELPH_DQS1		0x08a4
+#define DRAMC_SHU1_DRVING1		0x08a8
+#define DRAMC_SHU1_DRVING2		0x08ac
+#define DRAMC_SHU1_WODT			0x08c0
+#define DRAMC_SHU_SCINTV		0x08c8
+#define DRAMC_SHURK0_DQSCTL		0x0a00
+#define DRAMC_SHURK0_DQSIEN		0x0a04
+#define DRAMC_SHURK0_SELPH_ODTEN0	0x0a1c
+#define DRAMC_SHURK0_SELPH_ODTEN1	0x0a20
+#define DRAMC_SHURK0_SELPH_DQSG0	0x0a24
+#define DRAMC_SHURK0_SELPH_DQSG1	0x0a28
+#define DRAMC_SHURK0_SELPH_DQ0		0x0a2c
+#define DRAMC_SHURK0_SELPH_DQ1		0x0a30
+#define DRAMC_SHURK0_SELPH_DQ2		0x0a34
+#define DRAMC_SHURK0_SELPH_DQ3		0x0a38
+#define DRAMC_SHURK1_DQSCTL		0x0b00
+#define DRAMC_SHURK1_SELPH_ODTEN0	0x0b1c
+#define DRAMC_SHURK1_SELPH_ODTEN1	0x0b20
+#define DRAMC_SHURK1_SELPH_DQSG0	0x0b24
+#define DRAMC_SHURK1_SELPH_DQSG1	0x0b28
+#define DRAMC_SHURK1_SELPH_DQ0		0x0b2c
+#define DRAMC_SHURK1_SELPH_DQ1		0x0b30
+#define DRAMC_SHURK1_SELPH_DQ2		0x0b34
+#define DRAMC_SHURK1_SELPH_DQ3		0x0b38
+#define DRAMC_SHURK2_SELPH_ODTEN0	0x0c1c
+#define DRAMC_SHURK2_SELPH_ODTEN1	0x0c20
+#define DRAMC_SHU_DQSG_RETRY		0x0c54
+
+#define EMI_COL_ADDR_MASK		GENMASK(13, 12)
+#define EMI_COL_ADDR_SHIFT		12
+#define WALKING_PATTERN			0x12345678
+#define WALKING_STEP			0x4000000
+
+struct mtk_ddr3_priv {
+	fdt_addr_t emi;
+	fdt_addr_t ddrphy;
+	fdt_addr_t dramc_ao;
+	struct clk phy;
+	struct clk phy_mux;
+	struct clk mem;
+	struct clk mem_mux;
+};
+
+#ifdef CONFIG_SPL_BUILD
+static int mtk_ddr3_rank_size_detect(struct udevice *dev)
+{
+	struct mtk_ddr3_priv *priv = dev_get_priv(dev);
+	int step;
+	u32 start, test;
+
+	/* To detect size, we have to make sure it's single rank
+	 * and it has maximum addressing region
+	 */
+
+	writel(WALKING_PATTERN, CONFIG_SYS_SDRAM_BASE);
+
+	if (readl(CONFIG_SYS_SDRAM_BASE) != WALKING_PATTERN)
+		return -EINVAL;
+
+	for (step = 0; step < 5; step++) {
+		writel(~WALKING_PATTERN, CONFIG_SYS_SDRAM_BASE +
+		       (WALKING_STEP << step));
+
+		start = readl(CONFIG_SYS_SDRAM_BASE);
+		test = readl(CONFIG_SYS_SDRAM_BASE + (WALKING_STEP << step));
+		if ((test != ~WALKING_PATTERN) || test == start)
+			break;
+	}
+
+	step = step ? step - 1 : 3;
+	clrsetbits_le32(priv->emi + EMI_CONA, EMI_COL_ADDR_MASK,
+			step << EMI_COL_ADDR_SHIFT);
+
+	return 0;
+}
+
+static int mtk_ddr3_init(struct udevice *dev)
+{
+	struct mtk_ddr3_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = clk_set_parent(&priv->phy, &priv->phy_mux);
+	if (ret)
+		return ret;
+
+	/* EMI Setting */
+	writel(0x00003010, priv->emi + EMI_CONA);
+	writel(0x00000000, priv->emi + EMI_CONF);
+	writel(0x000006b8, priv->emi + EMI_CONM);
+	/* DQS */
+	writel(0x20c00, priv->dramc_ao + DRAMC_SHU1_DRVING1);
+	/* Clock */
+	writel(0x8320c83, priv->dramc_ao + DRAMC_SHU1_DRVING2);
+
+	/* DDRPHY setting */
+	writel(0x2201, priv->dramc_ao + DRAMC_DRAMCTRL);
+	writel(0x3000000c, priv->dramc_ao + DRAMC_CLKCTRL);
+	writel(0xe08, priv->ddrphy + DDRPHY_CA_CMD5);
+	writel(0x60e, priv->ddrphy + DDRPHY_SHU1_CA_CMD5);
+	writel(0x0, priv->ddrphy + DDRPHY_MISC_SPM_CTRL1);
+	writel(0xffffffff, priv->ddrphy + DDRPHY_MISC_SPM_CTRL0);
+	writel(0xffffffff, priv->ddrphy + DDRPHY_MISC_SPM_CTRL2);
+	writel(0x6003bf, priv->ddrphy + DDRPHY_MISC_CG_CTRL2);
+	writel(0x13300000, priv->ddrphy + DDRPHY_MISC_CG_CTRL4);
+
+	writel(0x1, priv->ddrphy + DDRPHY_SHU1_CA_CMD7);
+	writel(0x21, priv->ddrphy + DDRPHY_SHU1_B0_DQ7);
+	writel(0x1, priv->ddrphy + DDRPHY_SHU1_B1_DQ7);
+	writel(0xfff0, priv->ddrphy + DDRPHY_CA_CMD2);
+	writel(0x0, priv->ddrphy + DDRPHY_B0_DQ2);
+	writel(0x0, priv->ddrphy + DDRPHY_B1_DQ2);
+	writel(0x7, priv->ddrphy + DDRPHY_MISC_RXDVS1);
+	writel(0x10, priv->ddrphy + DDRPHY_PLL3);
+	writel(0x8e8e0000, priv->ddrphy + DDRPHY_MISC_VREF_CTRL);
+	writel(0x2e0040, priv->ddrphy + DDRPHY_MISC_IMP_CTRL0);
+	writel(0x50060e, priv->ddrphy + DDRPHY_SHU1_B0_DQ5);
+	writel(0x50060e, priv->ddrphy + DDRPHY_SHU1_B1_DQ5);
+	udelay(1);
+
+	writel(0x10, priv->ddrphy + DDRPHY_B0_DQ3);
+	writel(0x10, priv->ddrphy + DDRPHY_B1_DQ3);
+	writel(0x3f600, priv->ddrphy + DDRPHY_MISC_CG_CTRL1);
+	writel(0x1010, priv->ddrphy + DDRPHY_B0_DQ4);
+	writel(0x1110e0e, priv->ddrphy + DDRPHY_B0_DQ5);
+	writel(0x10c10d0, priv->ddrphy + DDRPHY_B0_DQ6);
+	writel(0x3110e0e, priv->ddrphy + DDRPHY_B0_DQ5);
+	writel(0x1010, priv->ddrphy + DDRPHY_B1_DQ4);
+	writel(0x1110e0e, priv->ddrphy + DDRPHY_B1_DQ5);
+	writel(0x10c10d0, priv->ddrphy + DDRPHY_B1_DQ6);
+	writel(0x3110e0e, priv->ddrphy + DDRPHY_B1_DQ5);
+	writel(0x7fffffc, priv->ddrphy + DDRPHY_CA_CMD3);
+	writel(0xc0010, priv->ddrphy + DDRPHY_CA_CMD6);
+	writel(0x101, priv->ddrphy + DDRPHY_SHU1_CA_CMD2);
+	writel(0x41e, priv->ddrphy + DDRPHY_B0_DQ3);
+	writel(0x41e, priv->ddrphy + DDRPHY_B1_DQ3);
+	writel(0x180101, priv->ddrphy + DDRPHY_CA_CMD8);
+	writel(0x0, priv->ddrphy + DDRPHY_MISC_IMP_CTRL1);
+	writel(0x11400000, priv->ddrphy + DDRPHY_MISC_CG_CTRL4);
+	writel(0xfff0f0f0, priv->ddrphy + DDRPHY_MISC_SHU_OPT);
+	writel(0x1f, priv->ddrphy + DDRPHY_MISC_CG_CTRL0);
+
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_CA_CMD6);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_B0_DQ6);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_B1_DQ6);
+	writel(0x40000, priv->ddrphy + DDRPHY_PLL4);
+	writel(0x0, priv->ddrphy + DDRPHY_PLL1);
+	writel(0x0, priv->ddrphy + DDRPHY_PLL2);
+	writel(0x666008, priv->ddrphy + DDRPHY_CA_DLL_ARPI5);
+	writel(0x80666008, priv->ddrphy + DDRPHY_B0_DLL_ARPI5);
+	writel(0x80666008, priv->ddrphy + DDRPHY_B1_DLL_ARPI5);
+	writel(0x0, priv->ddrphy + DDRPHY_CA_DLL_ARPI0);
+	writel(0x0, priv->ddrphy + DDRPHY_B0_DLL_ARPI0);
+	writel(0x0, priv->ddrphy + DDRPHY_B1_DLL_ARPI0);
+	writel(0x400, priv->ddrphy + DDRPHY_CA_DLL_ARPI2);
+	writel(0x20400, priv->ddrphy + DDRPHY_B0_DLL_ARPI2);
+	writel(0x20400, priv->ddrphy + DDRPHY_B1_DLL_ARPI2);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_PLL9);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_PLL11);
+	writel(0xf7f, priv->ddrphy + DDRPHY_SHU1_PLL0);
+	writel(0x40000, priv->ddrphy + DDRPHY_SHU1_PLL8);
+	writel(0x40000, priv->ddrphy + DDRPHY_SHU1_PLL10);
+	writel(0xe57800fe, priv->ddrphy + DDRPHY_SHU1_PLL4);
+	writel(0xe57800fe, priv->ddrphy + DDRPHY_SHU1_PLL6);
+
+	writel(0xB5000000, priv->ddrphy + DDRPHY_SHU1_PLL5);
+	writel(0xB5000000, priv->ddrphy + DDRPHY_SHU1_PLL7);
+
+	writel(0x14d0002, priv->ddrphy + DDRPHY_PLL5);
+	writel(0x14d0002, priv->ddrphy + DDRPHY_PLL7);
+	writel(0x80040000, priv->ddrphy + DDRPHY_SHU1_PLL8);
+	writel(0x80040000, priv->ddrphy + DDRPHY_SHU1_PLL10);
+	writel(0xf, priv->ddrphy + DDRPHY_SHU1_PLL1);
+	writel(0x4, priv->ddrphy + DDRPHY_CA_DLL_ARPI0);
+	writel(0x1, priv->ddrphy + DDRPHY_B0_DLL_ARPI0);
+	writel(0x1, priv->ddrphy + DDRPHY_B1_DLL_ARPI0);
+	writel(0x698600, priv->ddrphy + DDRPHY_CA_DLL_ARPI5);
+	writel(0xc0778600, priv->ddrphy + DDRPHY_B0_DLL_ARPI5);
+	writel(0xc0778600, priv->ddrphy + DDRPHY_B1_DLL_ARPI5);
+	writel(0x0, priv->ddrphy + DDRPHY_CA_DLL_ARPI4);
+	writel(0x0, priv->ddrphy + DDRPHY_B0_DLL_ARPI4);
+	writel(0x0, priv->ddrphy + DDRPHY_B1_DLL_ARPI4);
+	writel(0x2ba800, priv->ddrphy + DDRPHY_CA_DLL_ARPI1);
+	writel(0x2ae806, priv->ddrphy + DDRPHY_B0_DLL_ARPI1);
+	writel(0xae806, priv->ddrphy + DDRPHY_B1_DLL_ARPI1);
+	writel(0xba000, priv->ddrphy + DDRPHY_CA_DLL_ARPI3);
+	writel(0x2e800, priv->ddrphy + DDRPHY_B0_DLL_ARPI3);
+	writel(0x2e800, priv->ddrphy + DDRPHY_B1_DLL_ARPI3);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_CA_CMD4);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_B0_DQ4);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_B1_DQ4);
+	writel(0x4, priv->ddrphy + DDRPHY_CA_DLL_ARPI0);
+	writel(0x1, priv->ddrphy + DDRPHY_B0_DLL_ARPI0);
+	writel(0x1, priv->ddrphy + DDRPHY_B1_DLL_ARPI0);
+	writel(0x32cf0000, priv->ddrphy + DDRPHY_SHU1_CA_CMD6);
+	writel(0x32cd0000, priv->ddrphy + DDRPHY_SHU1_B0_DQ6);
+	writel(0x32cd0000, priv->ddrphy + DDRPHY_SHU1_B1_DQ6);
+	writel(0x80010000, priv->ddrphy + DDRPHY_PLL1);
+	writel(0x80000000, priv->ddrphy + DDRPHY_PLL2);
+	udelay(100);
+
+	writel(0xc, priv->ddrphy + DDRPHY_CA_DLL_ARPI0);
+	writel(0x9, priv->ddrphy + DDRPHY_B0_DLL_ARPI0);
+	writel(0x9, priv->ddrphy + DDRPHY_B1_DLL_ARPI0);
+	writel(0xd0000, priv->ddrphy + DDRPHY_PLL4);
+	udelay(1);
+
+	writel(0x82, priv->ddrphy + DDRPHY_MISC_CTRL1);
+	writel(0x2, priv->dramc_ao + DRAMC_DDRCONF0);
+	writel(0x3acf0000, priv->ddrphy + DDRPHY_SHU1_CA_CMD6);
+	writel(0x3acd0000, priv->ddrphy + DDRPHY_SHU1_B0_DQ6);
+	writel(0x3acd0000, priv->ddrphy + DDRPHY_SHU1_B1_DQ6);
+	udelay(1);
+
+	writel(0x0, priv->ddrphy + DDRPHY_CA_DLL_ARPI2);
+	writel(0x0, priv->ddrphy + DDRPHY_B0_DLL_ARPI2);
+	writel(0x0, priv->ddrphy + DDRPHY_B1_DLL_ARPI2);
+	writel(0x80, priv->ddrphy + DDRPHY_MISC_CTRL1);
+	writel(0x0, priv->dramc_ao + DRAMC_DDRCONF0);
+	writel(0x80000000, priv->ddrphy + DDRPHY_PLL1);
+	udelay(1);
+
+	writel(0x698e00, priv->ddrphy + DDRPHY_CA_DLL_ARPI5);
+	udelay(1);
+
+	writel(0xc0778e00, priv->ddrphy + DDRPHY_B0_DLL_ARPI5);
+	udelay(1);
+
+	writel(0xc0778e00, priv->ddrphy + DDRPHY_B1_DLL_ARPI5);
+	udelay(1);
+
+	ret = clk_set_parent(&priv->mem, &priv->mem_mux);
+	if (ret)
+		return ret;
+
+	/* DDR PHY PLL setting */
+	writel(0x51e, priv->ddrphy + DDRPHY_B0_DQ3);
+	writel(0x51e, priv->ddrphy + DDRPHY_B1_DQ3);
+	writel(0x8100008c, priv->ddrphy + DDRPHY_MISC_CTRL1);
+	writel(0x80101, priv->ddrphy + DDRPHY_CA_CMD8);
+	writel(0x100, priv->ddrphy + DDRPHY_CA_CMD7);
+	writel(0x0, priv->ddrphy + DDRPHY_CA_CMD7);
+	writel(0x0, priv->ddrphy + DDRPHY_B0_DQ7);
+	writel(0x0, priv->ddrphy + DDRPHY_B1_DQ7);
+	writel(0x51e, priv->ddrphy + DDRPHY_B0_DQ3);
+	writel(0xff051e, priv->ddrphy + DDRPHY_B1_DQ3);
+	writel(0x0, priv->ddrphy + DDRPHY_B0_DQ2);
+	writel(0x1ff, priv->ddrphy + DDRPHY_B1_DQ2);
+
+	/* Update initial setting */
+	writel(0x5fc, priv->ddrphy + DDRPHY_B0_DQ3);
+	writel(0xff05fc, priv->ddrphy + DDRPHY_B1_DQ3);
+	writel(0x10c12d9, priv->ddrphy + DDRPHY_B0_DQ6);
+	writel(0x10c12d9, priv->ddrphy + DDRPHY_B1_DQ6);
+	writel(0xc0259, priv->ddrphy + DDRPHY_CA_CMD6);
+	writel(0x4000, priv->ddrphy + DDRPHY_B0_DQ2);
+	writel(0x41ff, priv->ddrphy + DDRPHY_B1_DQ2);
+	writel(0x0, priv->ddrphy + DDRPHY_B0_DQ8);
+	writel(0x100, priv->ddrphy + DDRPHY_B1_DQ8);
+	writel(0x3110e0e, priv->ddrphy + DDRPHY_B0_DQ5);
+	writel(0x3110e0e, priv->ddrphy + DDRPHY_B1_DQ5);
+	writel(0x51060e, priv->ddrphy + DDRPHY_SHU1_B0_DQ5);
+	writel(0x51060e, priv->ddrphy + DDRPHY_SHU1_B1_DQ5);
+	writel(0x39eff6, priv->dramc_ao + DRAMC_SHU_SCINTV);
+	writel(0x204ffff, priv->dramc_ao + DRAMC_CLKAR);
+	writel(0x31b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL);
+	writel(0x0, priv->dramc_ao + DRAMC_PERFCTL0);
+	writel(0x80000, priv->dramc_ao + DRAMC_PERFCTL0);
+
+	/* Dramc setting PC3 */
+	writel(0x65714001, priv->dramc_ao + DRAMC_REFCTRL0);
+
+	writel(0x11351131, priv->ddrphy + DDRPHY_MISC_CTRL3);
+	writel(0x200600, priv->dramc_ao + DRAMC_SHU_DQSG_RETRY);
+	writel(0x101d007, priv->dramc_ao + DRAMC_SHUCTRL2);
+	writel(0xe090601, priv->dramc_ao + DRAMC_DVFSDLL);
+	writel(0x20003000, priv->dramc_ao + DRAMC_DDRCONF0);
+	writel(0x3900020f, priv->ddrphy + DDRPHY_MISC_CTRL0);
+	writel(0xa20810bf, priv->dramc_ao + DRAMC_SHU_CONF0);
+	writel(0x30050, priv->dramc_ao + DRAMC_SHU_ODTCTRL);
+	writel(0x25712000, priv->dramc_ao + DRAMC_REFCTRL0);
+	writel(0xb0100000, priv->dramc_ao + DRAMC_STBCAL);
+	writel(0x8000000, priv->dramc_ao + DRAMC_SREFCTRL);
+	writel(0xc0000000, priv->dramc_ao + DRAMC_SHU_PIPE);
+	writel(0x731004, priv->dramc_ao + DRAMC_RKCFG);
+	writel(0x8007320f, priv->dramc_ao + DRAMC_SHU_CONF2);
+	writel(0x2a7c0, priv->dramc_ao + DRAMC_SHU_SCINTV);
+	writel(0xc110, priv->dramc_ao + DRAMC_SHUCTRL);
+	writel(0x30000700, priv->dramc_ao + DRAMC_REFCTRL1);
+	writel(0x6543b321, priv->dramc_ao + DRAMC_REFRATRE_FILTER);
+
+	/* Update PCDDR3 default setting */
+	writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA1);
+	writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA2);
+	writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA3);
+	writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA4);
+	writel(0x10000111, priv->dramc_ao + DRAMC_SHU_SELPH_CA5);
+	writel(0x1000000, priv->dramc_ao + DRAMC_SHU_SELPH_CA6);
+	writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA7);
+	writel(0x0, priv->dramc_ao + DRAMC_SHU_SELPH_CA8);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_R0_CA_CMD9);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_R1_CA_CMD9);
+	writel(0x11112222, priv->dramc_ao + DRAMC_SHU_SELPH_DQS0);
+	writel(0x33331111, priv->dramc_ao + DRAMC_SHU_SELPH_DQS1);
+	writel(0x11112222, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ0);
+	writel(0x11112222, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ1);
+	writel(0x33331111, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ2);
+	writel(0x33331111, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ3);
+	writel(0x11112222, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQ0);
+	writel(0x11112222, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQ1);
+	writel(0x33331111, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQ2);
+	writel(0x33331111, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQ3);
+	writel(0xf0f00, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ7);
+	writel(0xf0f00, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ7);
+	writel(0xf0f00, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ7);
+	writel(0xf0f00, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ7);
+	writel(0x0, priv->dramc_ao + DRAMC_SHURK0_SELPH_ODTEN0);
+	writel(0x0, priv->dramc_ao + DRAMC_SHURK0_SELPH_ODTEN1);
+	writel(0x0, priv->dramc_ao + DRAMC_SHURK1_SELPH_ODTEN0);
+	writel(0x0, priv->dramc_ao + DRAMC_SHURK1_SELPH_ODTEN1);
+	writel(0x0, priv->dramc_ao + DRAMC_SHURK2_SELPH_ODTEN0);
+	writel(0x66666666, priv->dramc_ao + DRAMC_SHURK2_SELPH_ODTEN1);
+	writel(0x2c000b0f, priv->dramc_ao + DRAMC_SHU_CONF1);
+	writel(0x11111111, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQSG0);
+	writel(0x64646464, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQSG1);
+	writel(0x11111111, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQSG0);
+	writel(0x64646464, priv->dramc_ao + DRAMC_SHURK1_SELPH_DQSG1);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ2);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ3);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ4);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ5);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ6);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ2);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ3);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ4);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ5);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_R1_B0_DQ6);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ2);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ3);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ4);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ5);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ6);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ2);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ3);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ4);
+	writel(0xc0c0c0c, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ5);
+	writel(0x0, priv->ddrphy + DDRPHY_SHU1_R1_B1_DQ6);
+	writel(0x20000001, priv->dramc_ao + DRAMC_SHU_RANKCTL);
+	writel(0x2, priv->dramc_ao + DRAMC_SHURK0_DQSCTL);
+	writel(0x2, priv->dramc_ao + DRAMC_SHURK1_DQSCTL);
+	writel(0x4020b07, priv->dramc_ao + DRAMC_SHU_ACTIM0);
+	writel(0xb060400, priv->dramc_ao + DRAMC_SHU_ACTIM1);
+	writel(0x8090200, priv->dramc_ao + DRAMC_SHU_ACTIM2);
+	writel(0x810018, priv->dramc_ao + DRAMC_SHU_ACTIM3);
+	writel(0x1e9700ff, priv->dramc_ao + DRAMC_SHU_ACTIM4);
+	writel(0x1000908, priv->dramc_ao + DRAMC_SHU_ACTIM5);
+	writel(0x801040b, priv->dramc_ao + DRAMC_SHU_ACTIM_XRT);
+	writel(0x20000D1, priv->dramc_ao + DRAMC_SHU_AC_TIME_05T);
+	writel(0x80010000, priv->ddrphy + DDRPHY_PLL2);
+	udelay(500);
+
+	writel(0x81080000, priv->dramc_ao + DRAMC_MISCTL0);
+	writel(0xacf13, priv->dramc_ao + DRAMC_PERFCTL0);
+	writel(0xacf12, priv->dramc_ao + DRAMC_PERFCTL0);
+	writel(0x80, priv->dramc_ao + DRAMC_ARBCTL);
+	writel(0x9, priv->dramc_ao + DRAMC_PADCTRL);
+	writel(0x80000107, priv->dramc_ao + DRAMC_DRAMC_PD_CTRL);
+	writel(0x3000000c, priv->dramc_ao + DRAMC_CLKCTRL);
+	writel(0x25714001, priv->dramc_ao + DRAMC_REFCTRL0);
+	writel(0x35b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL);
+	writel(0x4300000, priv->dramc_ao + DRAMC_CATRAINING1);
+	writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL);
+	writel(0x731414, priv->dramc_ao + DRAMC_RKCFG);
+	writel(0x733414, priv->dramc_ao + DRAMC_RKCFG);
+	udelay(20);
+
+	writel(0x80002050, priv->dramc_ao + DRAMC_CKECTRL);
+	udelay(100);
+
+	writel(0x400000, priv->dramc_ao + DRAMC_MRS);
+	writel(0x401800, priv->dramc_ao + DRAMC_MRS);
+	writel(0x1, priv->dramc_ao + DRAMC_SPCMD);
+	writel(0x0, priv->dramc_ao + DRAMC_SPCMD);
+	udelay(100);
+
+	writel(0x601800, priv->dramc_ao + DRAMC_MRS);
+	writel(0x600000, priv->dramc_ao + DRAMC_MRS);
+	writel(0x1, priv->dramc_ao + DRAMC_SPCMD);
+	writel(0x0, priv->dramc_ao + DRAMC_SPCMD);
+	udelay(100);
+
+	writel(0x200000, priv->dramc_ao + DRAMC_MRS);
+	writel(0x200400, priv->dramc_ao + DRAMC_MRS);
+	writel(0x1, priv->dramc_ao + DRAMC_SPCMD);
+	writel(0x0, priv->dramc_ao + DRAMC_SPCMD);
+	udelay(100);
+
+	writel(0x400, priv->dramc_ao + DRAMC_MRS);
+	writel(0x1d7000, priv->dramc_ao + DRAMC_MRS);
+	writel(0x1, priv->dramc_ao + DRAMC_SPCMD);
+	writel(0x0, priv->dramc_ao + DRAMC_SPCMD);
+	udelay(100);
+
+	writel(0x702201, priv->dramc_ao + DRAMC_DRAMCTRL);
+	writel(0x10, priv->dramc_ao + DRAMC_SPCMD);
+	writel(0x0, priv->dramc_ao + DRAMC_SPCMD);
+	writel(0x20, priv->dramc_ao + DRAMC_SPCMD);
+	writel(0x0, priv->dramc_ao + DRAMC_SPCMD);
+	writel(0x1, priv->dramc_ao + DRAMC_HW_MRR_FUN);
+	writel(0x702301, priv->dramc_ao + DRAMC_DRAMCTRL);
+	writel(0x702301, priv->dramc_ao + DRAMC_DRAMCTRL);
+	writel(0xa56, priv->dramc_ao + DRAMC_ZQCS);
+	writel(0xff0000, priv->dramc_ao + DRAMC_SHU_CONF3);
+	writel(0x15b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL);
+	writel(0x2cb00b0f, priv->dramc_ao + DRAMC_SHU_CONF1);
+	writel(0x65714001, priv->dramc_ao + DRAMC_REFCTRL0);
+	writel(0x48000000, priv->dramc_ao + DRAMC_SREFCTRL);
+	writel(0xc0000107, priv->dramc_ao + DRAMC_DRAMC_PD_CTRL);
+	writel(0x10002, priv->dramc_ao + DRAMC_EYESCAN);
+	writel(0x15e00, priv->dramc_ao + DRAMC_STBCAL1);
+	writel(0x100000, priv->dramc_ao + DRAMC_TEST2_1);
+	writel(0x4000, priv->dramc_ao + DRAMC_TEST2_2);
+	writel(0x12000480, priv->dramc_ao + DRAMC_TEST2_3);
+	writel(0x301d007, priv->dramc_ao + DRAMC_SHUCTRL2);
+	writel(0x4782321, priv->dramc_ao + DRAMC_DRAMCTRL);
+	writel(0x30210000, priv->dramc_ao + DRAMC_SHU_CKECTRL);
+	writel(0x20000, priv->dramc_ao + DRAMC_DUMMY_RD);
+	writel(0x4080110d, priv->dramc_ao + DRAMC_TEST2_4);
+	writel(0x30000721, priv->dramc_ao + DRAMC_REFCTRL1);
+	writel(0x0, priv->dramc_ao + DRAMC_RSTMASK);
+	writel(0x4782320, priv->dramc_ao + DRAMC_DRAMCTRL);
+	writel(0x80002000, priv->dramc_ao + DRAMC_CKECTRL);
+	writel(0x45714001, priv->dramc_ao + DRAMC_REFCTRL0);
+
+	/* Apply config before calibration */
+	writel(0x120, priv->dramc_ao + DRAMC_DRAMC_PD_CTRL);
+	writel(0x11351131, priv->ddrphy + DDRPHY_MISC_CTRL3);
+	writel(0xffffffff, priv->ddrphy + DDRPHY_MISC_CG_CTRL0);
+	writel(0x2a7fe, priv->dramc_ao + DRAMC_SHU_SCINTV);
+	writel(0xff01ff, priv->dramc_ao + DRAMC_SHU_CONF3);
+	writel(0x4782320, priv->dramc_ao + DRAMC_DRAMCTRL);
+	writel(0xa56, priv->dramc_ao + DRAMC_ZQCS);
+	writel(0x80000000, priv->dramc_ao + DRAMC_SHU1_WODT);
+	writel(0x21, priv->ddrphy + DDRPHY_SHU1_B0_DQ7);
+	writel(0x1, priv->ddrphy + DDRPHY_SHU1_B1_DQ7);
+	writel(0x35b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL);
+	writel(0x35b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL);
+	writel(0x35b1f1cf, priv->dramc_ao + DRAMC_SPCMDCTRL);
+	writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL);
+	writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL);
+	writel(0x10002, priv->dramc_ao + DRAMC_EYESCAN);
+	writel(0x8100008c, priv->ddrphy + DDRPHY_MISC_CTRL1);
+	writel(0x45714001, priv->dramc_ao + DRAMC_REFCTRL0);
+	writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL);
+	writel(0xb0300000, priv->dramc_ao + DRAMC_STBCAL);
+
+	/* Write leveling */
+	writel(0x1f2e2e00, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ7);
+	writel(0x202f2f00, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ7);
+	writel(0x33221100, priv->dramc_ao + DRAMC_SHU_SELPH_DQS1);
+	writel(0x11112222, priv->dramc_ao + DRAMC_SHU_SELPH_DQS0);
+
+	/* RX dqs gating cal */
+	writel(0x11111010, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQSG0);
+	writel(0x20201717, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQSG1);
+	writel(0x1d1f, priv->dramc_ao + DRAMC_SHURK0_DQSIEN);
+
+	/* RX window per-bit cal */
+	writel(0x03030404, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ2);
+	writel(0x01010303, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ3);
+	writel(0x01010303, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ4);
+	writel(0x01010000, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ5);
+	writel(0x03030606, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ2);
+	writel(0x02020202, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ3);
+	writel(0x04040303, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ4);
+	writel(0x06060101, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ5);
+
+	/* RX datlat cal */
+	writel(0x28b00a0e, priv->dramc_ao + DRAMC_SHU_CONF1);
+
+	/* TX window per-byte with 2UI cal */
+	writel(0x11112222, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ0);
+	writel(0x22220000, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ2);
+	writel(0x11112222, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ1);
+	writel(0x22220000, priv->dramc_ao + DRAMC_SHURK0_SELPH_DQ3);
+	writel(0x1f2e2e00, priv->ddrphy + DDRPHY_SHU1_R0_B0_DQ7);
+	writel(0x202f2f00, priv->ddrphy + DDRPHY_SHU1_R0_B1_DQ7);
+
+	return mtk_ddr3_rank_size_detect(dev);
+}
+#endif
+
+static int mtk_ddr3_probe(struct udevice *dev)
+{
+	struct mtk_ddr3_priv *priv = dev_get_priv(dev);
+
+	priv->emi = dev_read_addr_index(dev, 0);
+	if (priv->emi == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->ddrphy = dev_read_addr_index(dev, 1);
+	if (priv->ddrphy == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->dramc_ao = dev_read_addr_index(dev, 2);
+	if (priv->dramc_ao == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+#ifdef CONFIG_SPL_BUILD
+	int ret;
+
+	ret = clk_get_by_index(dev, 0, &priv->phy);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_index(dev, 1, &priv->phy_mux);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_index(dev, 2, &priv->mem);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_index(dev, 3, &priv->mem_mux);
+	if (ret)
+		return ret;
+
+	ret = mtk_ddr3_init(dev);
+	if (ret)
+		return ret;
+#endif
+	return 0;
+}
+
+static int mtk_ddr3_get_info(struct udevice *dev, struct ram_info *info)
+{
+	struct mtk_ddr3_priv *priv = dev_get_priv(dev);
+	u32 val = readl(priv->emi + EMI_CONA);
+
+	info->base = CONFIG_SYS_SDRAM_BASE;
+
+	switch ((val & EMI_COL_ADDR_MASK) >> EMI_COL_ADDR_SHIFT) {
+	case 0:
+		info->size = SZ_128M;
+		break;
+	case 1:
+		info->size = SZ_256M;
+		break;
+	case 2:
+		info->size = SZ_512M;
+		break;
+	case 3:
+		info->size = SZ_1G;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct ram_ops mtk_ddr3_ops = {
+	.get_info = mtk_ddr3_get_info,
+};
+
+static const struct udevice_id mtk_ddr3_ids[] = {
+	{ .compatible = "mediatek,mt7629-dramc" },
+	{ }
+};
+
+U_BOOT_DRIVER(mediatek_ddr3) = {
+	.name     = "mediatek_ddr3",
+	.id       = UCLASS_RAM,
+	.of_match = mtk_ddr3_ids,
+	.ops      = &mtk_ddr3_ops,
+	.probe    = mtk_ddr3_probe,
+	.priv_auto_alloc_size = sizeof(struct mtk_ddr3_priv),
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 6625a65..3bcc61e 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -368,6 +368,16 @@
 	  You will need to provide parameters to make this work. The driver
 	  will be available until the real driver model serial is running.
 
+config DEBUG_UART_MTK
+	bool "MediaTek High-speed UART"
+	depends on MTK_SERIAL
+	help
+	  Select this to enable a debug UART using the MediaTek High-speed
+	  UART driver.
+	  You will need to provide parameters to make this work. The
+	  driver will be available until the real driver model serial is
+	  running.
+
 endchoice
 
 config DEBUG_UART_BASE
@@ -698,6 +708,16 @@
 	  This driver supports the Cadence UART. It is found e.g. in Xilinx
 	  Zynq/ZynqMP.
 
+config MTK_SERIAL
+	bool "MediaTek High-speed UART support"
+	depends on DM_SERIAL
+	help
+	  Select this to enable UART support for MediaTek High-speed UART
+	  devices. This driver uses driver model and requires a device
+	  tree binding to operate.
+	  The High-speed UART is compatible with the ns16550a UART and have
+	  its own high-speed registers.
+
 config MPC8XX_CONS
 	bool "Console driver for MPC8XX"
 	depends on MPC8xx
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index a48458f..b6377b1 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -67,6 +67,7 @@
 obj-$(CONFIG_NULLDEV_SERIAL) += serial_nulldev.o
 obj-$(CONFIG_OWL_SERIAL) += serial_owl.o
 obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
+obj-$(CONFIG_MTK_SERIAL) += serial_mtk.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_USB_TTY) += usbtty.o
diff --git a/drivers/serial/serial_mtk.c b/drivers/serial/serial_mtk.c
new file mode 100644
index 0000000..bce1be8
--- /dev/null
+++ b/drivers/serial/serial_mtk.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek High-speed UART driver
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <div64.h>
+#include <dm.h>
+#include <errno.h>
+#include <serial.h>
+#include <watchdog.h>
+#include <asm/io.h>
+#include <asm/types.h>
+
+struct mtk_serial_regs {
+	u32 rbr;
+	u32 ier;
+	u32 fcr;
+	u32 lcr;
+	u32 mcr;
+	u32 lsr;
+	u32 msr;
+	u32 spr;
+	u32 mdr1;
+	u32 highspeed;
+	u32 sample_count;
+	u32 sample_point;
+	u32 fracdiv_l;
+	u32 fracdiv_m;
+	u32 escape_en;
+	u32 guard;
+	u32 rx_sel;
+};
+
+#define thr rbr
+#define iir fcr
+#define dll rbr
+#define dlm ier
+
+#define UART_LCR_WLS_8	0x03		/* 8 bit character length */
+#define UART_LCR_DLAB	0x80		/* Divisor latch access bit */
+
+#define UART_LSR_DR	0x01		/* Data ready */
+#define UART_LSR_THRE	0x20		/* Xmit holding register empty */
+
+/* the data is correct if the real baud is within 3%. */
+#define BAUD_ALLOW_MAX(baud)	((baud) + (baud) * 3 / 100)
+#define BAUD_ALLOW_MIX(baud)	((baud) - (baud) * 3 / 100)
+
+struct mtk_serial_priv {
+	struct mtk_serial_regs __iomem *regs;
+	u32 clock;
+};
+
+static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
+{
+	bool support_clk12m_baud115200;
+	u32 quot, samplecount, realbaud;
+
+	if ((baud <= 115200) && (priv->clock == 12000000))
+		support_clk12m_baud115200 = true;
+	else
+		support_clk12m_baud115200 = false;
+
+	if (baud <= 115200) {
+		writel(0, &priv->regs->highspeed);
+		quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
+
+		if (support_clk12m_baud115200) {
+			writel(3, &priv->regs->highspeed);
+			quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
+			if (quot == 0)
+				quot = 1;
+
+			samplecount = DIV_ROUND_CLOSEST(priv->clock,
+							quot * baud);
+			if (samplecount != 0) {
+				realbaud = priv->clock / samplecount / quot;
+				if ((realbaud > BAUD_ALLOW_MAX(baud)) ||
+				    (realbaud < BAUD_ALLOW_MIX(baud))) {
+					pr_info("baud %d can't be handled\n",
+						baud);
+				}
+			} else {
+				pr_info("samplecount is 0\n");
+			}
+		}
+	} else if (baud <= 576000) {
+		writel(2, &priv->regs->highspeed);
+
+		/* Set to next lower baudrate supported */
+		if ((baud == 500000) || (baud == 576000))
+			baud = 460800;
+		quot = DIV_ROUND_UP(priv->clock, 4 * baud);
+	} else {
+		writel(3, &priv->regs->highspeed);
+		quot = DIV_ROUND_UP(priv->clock, 256 * baud);
+	}
+
+	/* set divisor */
+	writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr);
+	writel(quot & 0xff, &priv->regs->dll);
+	writel((quot >> 8) & 0xff, &priv->regs->dlm);
+	writel(UART_LCR_WLS_8, &priv->regs->lcr);
+
+	if (baud > 460800) {
+		u32 tmp;
+
+		tmp = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
+		writel(tmp - 1, &priv->regs->sample_count);
+		writel((tmp - 2) >> 1, &priv->regs->sample_point);
+	} else {
+		writel(0, &priv->regs->sample_count);
+		writel(0xff, &priv->regs->sample_point);
+	}
+
+	if (support_clk12m_baud115200) {
+		writel(samplecount - 1, &priv->regs->sample_count);
+		writel((samplecount - 2) >> 1, &priv->regs->sample_point);
+	}
+}
+
+static int mtk_serial_setbrg(struct udevice *dev, int baudrate)
+{
+	struct mtk_serial_priv *priv = dev_get_priv(dev);
+
+	_mtk_serial_setbrg(priv, baudrate);
+
+	return 0;
+}
+
+static int mtk_serial_putc(struct udevice *dev, const char ch)
+{
+	struct mtk_serial_priv *priv = dev_get_priv(dev);
+
+	if (!(readl(&priv->regs->lsr) & UART_LSR_THRE))
+		return -EAGAIN;
+
+	writel(ch, &priv->regs->thr);
+
+	if (ch == '\n')
+		WATCHDOG_RESET();
+
+	return 0;
+}
+
+static int mtk_serial_getc(struct udevice *dev)
+{
+	struct mtk_serial_priv *priv = dev_get_priv(dev);
+
+	if (!(readl(&priv->regs->lsr) & UART_LSR_DR))
+		return -EAGAIN;
+
+	return readl(&priv->regs->rbr);
+}
+
+static int mtk_serial_pending(struct udevice *dev, bool input)
+{
+	struct mtk_serial_priv *priv = dev_get_priv(dev);
+
+	if (input)
+		return (readl(&priv->regs->lsr) & UART_LSR_DR) ? 1 : 0;
+	else
+		return (readl(&priv->regs->lsr) & UART_LSR_THRE) ? 0 : 1;
+}
+
+static int mtk_serial_probe(struct udevice *dev)
+{
+	struct mtk_serial_priv *priv = dev_get_priv(dev);
+
+	/* Disable interrupt */
+	writel(0, &priv->regs->ier);
+
+	return 0;
+}
+
+static int mtk_serial_ofdata_to_platdata(struct udevice *dev)
+{
+	struct mtk_serial_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	struct clk clk;
+	int err;
+
+	addr = dev_read_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	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;
+	}
+
+	return 0;
+}
+
+static const struct dm_serial_ops mtk_serial_ops = {
+	.putc = mtk_serial_putc,
+	.pending = mtk_serial_pending,
+	.getc = mtk_serial_getc,
+	.setbrg = mtk_serial_setbrg,
+};
+
+static const struct udevice_id mtk_serial_ids[] = {
+	{ .compatible = "mediatek,hsuart" },
+	{ .compatible = "mediatek,mt6577-uart" },
+	{ }
+};
+
+U_BOOT_DRIVER(serial_mtk) = {
+	.name = "serial_mtk",
+	.id = UCLASS_SERIAL,
+	.of_match = mtk_serial_ids,
+	.ofdata_to_platdata = mtk_serial_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct mtk_serial_priv),
+	.probe = mtk_serial_probe,
+	.ops = &mtk_serial_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DEBUG_UART_MTK
+
+#include <debug_uart.h>
+
+static inline void _debug_uart_init(void)
+{
+	struct mtk_serial_priv priv;
+
+	priv.regs = (void *) CONFIG_DEBUG_UART_BASE;
+	priv.clock = CONFIG_DEBUG_UART_CLOCK;
+
+	writel(0, &priv.regs->ier);
+
+	_mtk_serial_setbrg(&priv, CONFIG_BAUDRATE);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+	struct mtk_serial_regs __iomem *regs =
+		(void *) CONFIG_DEBUG_UART_BASE;
+
+	while (!(readl(&regs->lsr) & UART_LSR_THRE))
+		;
+
+	writel(ch, &regs->thr);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
\ No newline at end of file
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index d0cfc35..b0e6f32 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -160,4 +160,11 @@
 	help
 	  Select this to enable Time-Stamp Counter (TSC) timer for x86.
 
+config MTK_TIMER
+	bool "MediaTek timer support"
+	depends on TIMER
+	help
+	  Select this to enable support for the timer found on
+	  MediaTek devices.
+
 endmenu
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index 7f19c49..c4fbab2 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -18,3 +18,4 @@
 obj-$(CONFIG_STI_TIMER)		+= sti-timer.o
 obj-$(CONFIG_STM32_TIMER)	+= stm32_timer.o
 obj-$(CONFIG_X86_TSC_TIMER)	+= tsc_timer.o
+obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
diff --git a/drivers/timer/mtk_timer.c b/drivers/timer/mtk_timer.c
new file mode 100644
index 0000000..b5e76bd
--- /dev/null
+++ b/drivers/timer/mtk_timer.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek timer driver
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <timer.h>
+#include <asm/io.h>
+
+#define MTK_GPT4_CTRL	0x40
+#define MTK_GPT4_CLK	0x44
+#define MTK_GPT4_CNT	0x48
+
+#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
+
+struct mtk_timer_priv {
+	void __iomem *base;
+};
+
+static int mtk_timer_get_count(struct udevice *dev, u64 *count)
+{
+	struct mtk_timer_priv *priv = dev_get_priv(dev);
+	u32 val = readl(priv->base + MTK_GPT4_CNT);
+
+	*count = timer_conv_64(val);
+
+	return 0;
+}
+
+static int mtk_timer_probe(struct udevice *dev)
+{
+	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;
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (!priv->base)
+		return -ENOENT;
+
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_index(dev, 1, &parent);
+	if (!ret) {
+		ret = clk_set_parent(&clk, &parent);
+		if (ret)
+			return ret;
+	}
+
+	uc_priv->clock_rate = clk_get_rate(&clk);
+	if (!uc_priv->clock_rate)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct timer_ops mtk_timer_ops = {
+	.get_count = mtk_timer_get_count,
+};
+
+static const struct udevice_id mtk_timer_ids[] = {
+	{ .compatible = "mediatek,timer" },
+	{ }
+};
+
+U_BOOT_DRIVER(mtk_timer) = {
+	.name = "mtk_timer",
+	.id = UCLASS_TIMER,
+	.of_match = mtk_timer_ids,
+	.priv_auto_alloc_size = sizeof(struct mtk_timer_priv),
+	.probe = mtk_timer_probe,
+	.ops = &mtk_timer_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 4796da0..4a9ebb6 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -103,6 +103,14 @@
 	   Select this to enable Cadence watchdog timer, which can be found on some
 	   Xilinx Microzed Platform.
 
+config WDT_MTK
+	bool "MediaTek watchdog timer support"
+	depends on WDT && ARCH_MEDIATEK
+	help
+	  Select this to enable watchdog timer for MediaTek SoCs.
+	  The watchdog timer is stopped when initialized.
+	  It performs full SoC reset.
+
 config XILINX_TB_WATCHDOG
 	bool "Xilinx Axi watchdog timer support"
 	depends on WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index b8f2842..74738ee 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -24,3 +24,4 @@
 obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
 obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o
 obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o
+obj-$(CONFIG_WDT_MTK) += mtk_wdt.o
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
new file mode 100644
index 0000000..0b50173
--- /dev/null
+++ b/drivers/watchdog/mtk_wdt.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Watchdog driver for MediaTek SoCs
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <wdt.h>
+#include <asm/io.h>
+
+#define MTK_WDT_MODE			0x00
+#define MTK_WDT_LENGTH			0x04
+#define MTK_WDT_RESTART			0x08
+#define MTK_WDT_STATUS			0x0c
+#define MTK_WDT_INTERVAL		0x10
+#define MTK_WDT_SWRST			0x14
+#define MTK_WDT_REQ_MODE		0x30
+#define MTK_WDT_DEBUG_CTL		0x40
+
+#define WDT_MODE_KEY			(0x22 << 24)
+#define WDT_MODE_EN			BIT(0)
+#define WDT_MODE_EXTPOL			BIT(1)
+#define WDT_MODE_EXTEN			BIT(2)
+#define WDT_MODE_IRQ_EN			BIT(3)
+#define WDT_MODE_DUAL_EN		BIT(6)
+
+#define WDT_LENGTH_KEY			0x8
+#define WDT_LENGTH_TIMEOUT(n)		((n) << 5)
+
+#define WDT_RESTART_KEY			0x1971
+#define WDT_SWRST_KEY			0x1209
+
+struct mtk_wdt_priv {
+	void __iomem *base;
+};
+
+static int mtk_wdt_reset(struct udevice *dev)
+{
+	struct mtk_wdt_priv *priv = dev_get_priv(dev);
+
+	/* Reload watchdog duration */
+	writel(WDT_RESTART_KEY, priv->base + MTK_WDT_RESTART);
+
+	return 0;
+}
+
+static int mtk_wdt_stop(struct udevice *dev)
+{
+	struct mtk_wdt_priv *priv = dev_get_priv(dev);
+
+	clrsetbits_le32(priv->base + MTK_WDT_MODE, WDT_MODE_EN, WDT_MODE_KEY);
+
+	return 0;
+}
+
+static int mtk_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+	struct mtk_wdt_priv *priv = dev_get_priv(dev);
+
+	/* Kick watchdog to prevent counter == 0 */
+	writel(WDT_RESTART_KEY, priv->base + MTK_WDT_RESTART);
+
+	/* Reset */
+	writel(WDT_SWRST_KEY, priv->base + MTK_WDT_SWRST);
+	hang();
+
+	return 0;
+}
+
+static void mtk_wdt_set_timeout(struct udevice *dev, unsigned int timeout)
+{
+	struct mtk_wdt_priv *priv = dev_get_priv(dev);
+
+	/*
+	 * One bit is the value of 512 ticks
+	 * The clock has 32 KHz
+	 */
+	timeout = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY;
+	writel(timeout, priv->base + MTK_WDT_LENGTH);
+
+	mtk_wdt_reset(dev);
+}
+
+static int mtk_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+	struct mtk_wdt_priv *priv = dev_get_priv(dev);
+
+	mtk_wdt_set_timeout(dev, timeout);
+
+	/* Enable watchdog reset signal */
+	setbits_le32(priv->base + MTK_WDT_MODE,
+		     WDT_MODE_EN | WDT_MODE_KEY | WDT_MODE_EXTEN);
+
+	return 0;
+}
+
+static int mtk_wdt_probe(struct udevice *dev)
+{
+	struct mtk_wdt_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (!priv->base)
+		return -ENOENT;
+
+	/* Clear status */
+	clrsetbits_le32(priv->base + MTK_WDT_MODE,
+			WDT_MODE_IRQ_EN | WDT_MODE_EXTPOL, WDT_MODE_KEY);
+
+	return mtk_wdt_stop(dev);
+}
+
+static const struct wdt_ops mtk_wdt_ops = {
+	.start = mtk_wdt_start,
+	.reset = mtk_wdt_reset,
+	.stop = mtk_wdt_stop,
+	.expire_now = mtk_wdt_expire_now,
+};
+
+static const struct udevice_id mtk_wdt_ids[] = {
+	{ .compatible = "mediatek,wdt"},
+	{}
+};
+
+U_BOOT_DRIVER(mtk_wdt) = {
+	.name = "mtk_wdt",
+	.id = UCLASS_WDT,
+	.of_match = mtk_wdt_ids,
+	.priv_auto_alloc_size = sizeof(struct mtk_wdt_priv),
+	.probe = mtk_wdt_probe,
+	.ops = &mtk_wdt_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/include/configs/mt7623.h b/include/configs/mt7623.h
new file mode 100644
index 0000000..68da920
--- /dev/null
+++ b/include/configs/mt7623.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Configuration for MediaTek MT7623 SoC
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef __MT7623_H
+#define __MT7623_H
+
+#include <linux/sizes.h>
+
+/* Miscellaneous configurable options */
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG
+
+#define CONFIG_SYS_MAXARGS		8
+#define CONFIG_SYS_BOOTM_LEN		SZ_64M
+#define CONFIG_SYS_CBSIZE		SZ_1K
+#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE +	\
+					sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN		SZ_4M
+
+/* Environment */
+#define CONFIG_ENV_SIZE			SZ_4K
+/* Allow to overwrite serial and ethaddr */
+#define CONFIG_ENV_OVERWRITE
+
+/* Preloader -> Uboot */
+#define CONFIG_SYS_UBOOT_START		CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_TEXT_BASE + SZ_2M - \
+					 GENERATED_GBL_DATA_SIZE)
+
+/* UBoot -> Kernel */
+#define CONFIG_LOADADDR			0x84000000
+#define CONFIG_SYS_LOAD_ADDR		CONFIG_LOADADDR
+
+/* MMC */
+#define MMC_SUPPORTS_TUNING
+#define CONFIG_SUPPORT_EMMC_BOOT
+
+/* DRAM */
+#define CONFIG_SYS_SDRAM_BASE		0x80000000
+
+/* This is neede for kernel booting */
+#define FDT_HIGH			"fdt_high=0xac000000\0"
+
+/* Extra environment variables */
+#define CONFIG_EXTRA_ENV_SETTINGS	\
+	FDT_HIGH
+
+#endif
diff --git a/include/configs/mt7629.h b/include/configs/mt7629.h
new file mode 100644
index 0000000..a665a5e
--- /dev/null
+++ b/include/configs/mt7629.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Configuration for MediaTek MT7629 SoC
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Ryder Lee <ryder.lee@mediatek.com>
+ */
+
+#ifndef __MT7629_H
+#define __MT7629_H
+
+#include <linux/sizes.h>
+
+/* Miscellaneous configurable options */
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG
+
+#define CONFIG_SYS_MAXARGS		8
+#define CONFIG_SYS_BOOTM_LEN		SZ_64M
+#define CONFIG_SYS_CBSIZE		SZ_1K
+#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE +	\
+					sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN		SZ_4M
+
+/* Environment */
+#define CONFIG_ENV_SIZE			SZ_4K
+/* Allow to overwrite serial and ethaddr */
+#define CONFIG_ENV_OVERWRITE
+
+/* Defines for SPL */
+#define CONFIG_SPL_STACK		0x106000
+#define CONFIG_SPL_TEXT_BASE		0x201000
+#define CONFIG_SPL_MAX_SIZE		SZ_64K
+#define CONFIG_SPL_MAX_FOOTPRINT	SZ_64K
+#define CONFIG_SPL_PAD_TO		0x10000
+
+#define CONFIG_SPI_ADDR			0x30000000
+#define CONFIG_SYS_SPI_U_BOOT_OFFS	CONFIG_SPL_PAD_TO
+#define CONFIG_SYS_UBOOT_BASE		(CONFIG_SPI_ADDR + CONFIG_SPL_PAD_TO)
+
+/* SPL -> Uboot */
+#define CONFIG_SYS_UBOOT_START		CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_TEXT_BASE + SZ_2M - \
+					 GENERATED_GBL_DATA_SIZE)
+
+/* UBoot -> Kernel */
+#define CONFIG_SYS_SPL_ARGS_ADDR	0x40000000
+#define CONFIG_LOADADDR			0x42007f1c
+#define CONFIG_SYS_LOAD_ADDR		CONFIG_LOADADDR
+
+/* DRAM */
+#define CONFIG_SYS_SDRAM_BASE		0x40000000
+
+#endif
diff --git a/include/dt-bindings/clock/mt7623-clk.h b/include/dt-bindings/clock/mt7623-clk.h
new file mode 100644
index 0000000..71ced15
--- /dev/null
+++ b/include/dt-bindings/clock/mt7623-clk.h
@@ -0,0 +1,413 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT2701_H
+#define _DT_BINDINGS_CLK_MT2701_H
+
+/* TOPCKGEN */
+#define CLK_TOP_FCLKS_OFF			0
+
+#define CLK_TOP_DPI				0
+#define CLK_TOP_DMPLL				1
+#define CLK_TOP_VENCPLL				2
+#define CLK_TOP_HDMI_0_PIX340M			3
+#define CLK_TOP_HDMI_0_DEEP340M			4
+#define CLK_TOP_HDMI_0_PLL340M			5
+#define CLK_TOP_HADDS2_FB			6
+#define CLK_TOP_WBG_DIG_416M			7
+#define CLK_TOP_DSI0_LNTC_DSI			8
+#define CLK_TOP_HDMI_SCL_RX			9
+#define CLK_TOP_32K_EXTERNAL			10
+#define CLK_TOP_HDMITX_CLKDIG_CTS		11
+#define CLK_TOP_AUD_EXT1			12
+#define CLK_TOP_AUD_EXT2			13
+#define CLK_TOP_NFI1X_PAD			14
+
+#define CLK_TOP_SYSPLL				15
+#define CLK_TOP_SYSPLL_D2			16
+#define CLK_TOP_SYSPLL_D3			17
+#define CLK_TOP_SYSPLL_D5			18
+#define CLK_TOP_SYSPLL_D7			19
+#define CLK_TOP_SYSPLL1_D2			20
+#define CLK_TOP_SYSPLL1_D4			21
+#define CLK_TOP_SYSPLL1_D8			22
+#define CLK_TOP_SYSPLL1_D16			23
+#define CLK_TOP_SYSPLL2_D2			24
+#define CLK_TOP_SYSPLL2_D4			25
+#define CLK_TOP_SYSPLL2_D8			26
+#define CLK_TOP_SYSPLL3_D2			27
+#define CLK_TOP_SYSPLL3_D4			28
+#define CLK_TOP_SYSPLL4_D2			29
+#define CLK_TOP_SYSPLL4_D4			30
+#define CLK_TOP_UNIVPLL				31
+#define CLK_TOP_UNIVPLL_D2			32
+#define CLK_TOP_UNIVPLL_D3			33
+#define CLK_TOP_UNIVPLL_D5			34
+#define CLK_TOP_UNIVPLL_D7			35
+#define CLK_TOP_UNIVPLL_D26			36
+#define CLK_TOP_UNIVPLL_D52			37
+#define CLK_TOP_UNIVPLL_D108			38
+#define CLK_TOP_USB_PHY48M			39
+#define CLK_TOP_UNIVPLL1_D2			40
+#define CLK_TOP_UNIVPLL1_D4			41
+#define CLK_TOP_UNIVPLL1_D8			42
+#define CLK_TOP_UNIVPLL2_D2			43
+#define CLK_TOP_UNIVPLL2_D4			44
+#define CLK_TOP_UNIVPLL2_D8			45
+#define CLK_TOP_UNIVPLL2_D16			46
+#define CLK_TOP_UNIVPLL2_D32			47
+#define CLK_TOP_UNIVPLL3_D2			48
+#define CLK_TOP_UNIVPLL3_D4			49
+#define CLK_TOP_UNIVPLL3_D8			50
+#define CLK_TOP_MSDCPLL				51
+#define CLK_TOP_MSDCPLL_D2			52
+#define CLK_TOP_MSDCPLL_D4			53
+#define CLK_TOP_MSDCPLL_D8			54
+#define CLK_TOP_MMPLL				55
+#define CLK_TOP_MMPLL_D2			56
+#define CLK_TOP_DMPLL_D2			57
+#define CLK_TOP_DMPLL_D4			58
+#define CLK_TOP_DMPLL_X2			59
+#define CLK_TOP_TVDPLL				60
+#define CLK_TOP_TVDPLL_D2			61
+#define CLK_TOP_TVDPLL_D4			62
+#define CLK_TOP_VDECPLL				63
+#define CLK_TOP_TVD2PLL				64
+#define CLK_TOP_TVD2PLL_D2			65
+#define CLK_TOP_MIPIPLL				66
+#define CLK_TOP_MIPIPLL_D2			67
+#define CLK_TOP_MIPIPLL_D4			68
+#define CLK_TOP_HDMIPLL				69
+#define CLK_TOP_HDMIPLL_D2			70
+#define CLK_TOP_HDMIPLL_D3			71
+#define CLK_TOP_ARMPLL_1P3G			72
+#define CLK_TOP_AUDPLL				73
+#define CLK_TOP_AUDPLL_D4			74
+#define CLK_TOP_AUDPLL_D8			75
+#define CLK_TOP_AUDPLL_D16			76
+#define CLK_TOP_AUDPLL_D24			77
+#define CLK_TOP_AUD1PLL_98M			78
+#define CLK_TOP_AUD2PLL_90M			79
+#define CLK_TOP_HADDS2PLL_98M			80
+#define CLK_TOP_HADDS2PLL_294M			81
+#define CLK_TOP_ETHPLL_500M			82
+#define CLK_TOP_CLK26M_D8			83
+#define CLK_TOP_32K_INTERNAL			84
+#define CLK_TOP_AXISEL_D4			85
+#define CLK_TOP_8BDAC				86
+
+#define CLK_TOP_AXI_SEL				87
+#define CLK_TOP_MEM_SEL				88
+#define CLK_TOP_DDRPHYCFG_SEL			89
+#define CLK_TOP_MM_SEL				90
+#define CLK_TOP_PWM_SEL				91
+#define CLK_TOP_VDEC_SEL			92
+#define CLK_TOP_MFG_SEL				93
+#define CLK_TOP_CAMTG_SEL			94
+#define CLK_TOP_UART_SEL			95
+#define CLK_TOP_SPI0_SEL			96
+#define CLK_TOP_USB20_SEL			97
+#define CLK_TOP_MSDC30_0_SEL			98
+#define CLK_TOP_MSDC30_1_SEL			99
+#define CLK_TOP_MSDC30_2_SEL			100
+#define CLK_TOP_AUDIO_SEL			101
+#define CLK_TOP_AUDINTBUS_SEL			102
+#define CLK_TOP_PMICSPI_SEL			103
+#define CLK_TOP_SCP_SEL				104
+#define CLK_TOP_DPI0_SEL			105
+#define CLK_TOP_DPI1_SEL			106
+#define CLK_TOP_TVE_SEL				107
+#define CLK_TOP_HDMI_SEL			108
+#define CLK_TOP_APLL_SEL			109
+#define CLK_TOP_RTC_SEL				110
+#define CLK_TOP_NFI2X_SEL			111
+#define CLK_TOP_EMMC_HCLK_SEL			112
+#define CLK_TOP_FLASH_SEL			113
+#define CLK_TOP_DI_SEL				114
+#define CLK_TOP_NR_SEL				115
+#define CLK_TOP_OSD_SEL				116
+#define CLK_TOP_HDMIRX_BIST_SEL			117
+#define CLK_TOP_INTDIR_SEL			118
+#define CLK_TOP_ASM_I_SEL			119
+#define CLK_TOP_ASM_M_SEL			120
+#define CLK_TOP_ASM_H_SEL			121
+#define CLK_TOP_MS_CARD_SEL			122
+#define CLK_TOP_ETHIF_SEL			123
+#define CLK_TOP_HDMIRX26_24_SEL			124
+#define CLK_TOP_MSDC30_3_SEL			125
+#define CLK_TOP_CMSYS_SEL			126
+#define CLK_TOP_SPI1_SEL			127
+#define CLK_TOP_SPI2_SEL			128
+#define CLK_TOP_8BDAC_SEL			129
+#define CLK_TOP_AUD2DVD_SEL			130
+#define CLK_TOP_PADMCLK_SEL			131
+#define CLK_TOP_AUD_MUX1_SEL			132
+#define CLK_TOP_AUD_MUX2_SEL			133
+#define CLK_TOP_AUDPLL_MUX_SEL			134
+#define CLK_TOP_AUD_K1_SRC_SEL			135
+#define CLK_TOP_AUD_K2_SRC_SEL			136
+#define CLK_TOP_AUD_K3_SRC_SEL			137
+#define CLK_TOP_AUD_K4_SRC_SEL			138
+#define CLK_TOP_AUD_K5_SRC_SEL			139
+#define CLK_TOP_AUD_K6_SRC_SEL			140
+
+#define CLK_TOP_AUD_EXTCK1_DIV			141
+#define CLK_TOP_AUD_EXTCK2_DIV			142
+#define CLK_TOP_AUD_MUX1_DIV			143
+#define CLK_TOP_AUD_MUX2_DIV			144
+#define CLK_TOP_AUD_K1_SRC_DIV			145
+#define CLK_TOP_AUD_K2_SRC_DIV			146
+#define CLK_TOP_AUD_K3_SRC_DIV			147
+#define CLK_TOP_AUD_K4_SRC_DIV			148
+#define CLK_TOP_AUD_K5_SRC_DIV			149
+#define CLK_TOP_AUD_K6_SRC_DIV			150
+#define CLK_TOP_AUD_48K_TIMING			151
+#define CLK_TOP_AUD_44K_TIMING			152
+#define CLK_TOP_AUD_I2S1_MCLK			153
+#define CLK_TOP_AUD_I2S2_MCLK			154
+#define CLK_TOP_AUD_I2S3_MCLK			155
+#define CLK_TOP_AUD_I2S4_MCLK			156
+#define CLK_TOP_AUD_I2S5_MCLK			157
+#define CLK_TOP_AUD_I2S6_MCLK			158
+#define CLK_TOP_NR				159
+
+/* APMIXEDSYS */
+#define CLK_APMIXED_ARMPLL			0
+#define CLK_APMIXED_MAINPLL			1
+#define CLK_APMIXED_UNIVPLL			2
+#define CLK_APMIXED_MMPLL			3
+#define CLK_APMIXED_MSDCPLL			4
+#define CLK_APMIXED_TVDPLL			5
+#define CLK_APMIXED_AUD1PLL			6
+#define CLK_APMIXED_TRGPLL			7
+#define CLK_APMIXED_ETHPLL			8
+#define CLK_APMIXED_VDECPLL			9
+#define CLK_APMIXED_HADDS2PLL			10
+#define CLK_APMIXED_AUD2PLL			11
+#define CLK_APMIXED_TVD2PLL			12
+#define CLK_APMIXED_NR				13
+
+/* INFRACFG */
+#define CLK_INFRA_DBG				0
+#define CLK_INFRA_SMI				1
+#define CLK_INFRA_QAXI_CM4			2
+#define CLK_INFRA_AUD_SPLIN_B			3
+#define CLK_INFRA_AUDIO				4
+#define CLK_INFRA_EFUSE				5
+#define CLK_INFRA_L2C_SRAM			6
+#define CLK_INFRA_M4U				7
+#define CLK_INFRA_CONNMCU			8
+#define CLK_INFRA_TRNG				9
+#define CLK_INFRA_RAMBUFIF			10
+#define CLK_INFRA_CPUM				11
+#define CLK_INFRA_KP				12
+#define CLK_INFRA_CEC				13
+#define CLK_INFRA_IRRX				14
+#define CLK_INFRA_PMICSPI			15
+#define CLK_INFRA_PMICWRAP			16
+#define CLK_INFRA_DDCCI				17
+#define CLK_INFRA_CPUSEL			18
+#define CLK_INFRA_NR				19
+
+/* PERICFG */
+#define CLK_PERI_NFI				0
+#define CLK_PERI_THERM				1
+#define CLK_PERI_PWM1				2
+#define CLK_PERI_PWM2				3
+#define CLK_PERI_PWM3				4
+#define CLK_PERI_PWM4				5
+#define CLK_PERI_PWM5				6
+#define CLK_PERI_PWM6				7
+#define CLK_PERI_PWM7				8
+#define CLK_PERI_PWM				9
+#define CLK_PERI_USB0				10
+#define CLK_PERI_USB1				11
+#define CLK_PERI_AP_DMA				12
+#define CLK_PERI_MSDC30_0			13
+#define CLK_PERI_MSDC30_1			14
+#define CLK_PERI_MSDC30_2			15
+#define CLK_PERI_MSDC30_3			16
+#define CLK_PERI_MSDC50_3			17
+#define CLK_PERI_NLI				18
+#define CLK_PERI_UART0				19
+#define CLK_PERI_UART1				20
+#define CLK_PERI_UART2				21
+#define CLK_PERI_UART3				22
+#define CLK_PERI_BTIF				23
+#define CLK_PERI_I2C0				24
+#define CLK_PERI_I2C1				25
+#define CLK_PERI_I2C2				26
+#define CLK_PERI_I2C3				27
+#define CLK_PERI_AUXADC				28
+#define CLK_PERI_SPI0				39
+#define CLK_PERI_ETH				30
+#define CLK_PERI_USB0_MCU			31
+
+#define CLK_PERI_USB1_MCU			32
+#define CLK_PERI_USB_SLV			33
+#define CLK_PERI_GCPU				34
+#define CLK_PERI_NFI_ECC			35
+#define CLK_PERI_NFI_PAD			36
+#define CLK_PERI_FLASH				37
+#define CLK_PERI_HOST89_INT			38
+#define CLK_PERI_HOST89_SPI			39
+#define CLK_PERI_HOST89_DVD			40
+#define CLK_PERI_SPI1				41
+#define CLK_PERI_SPI2				42
+#define CLK_PERI_FCI				43
+#define CLK_PERI_NR				44
+
+/* AUDIO */
+#define CLK_AUD_AFE				0
+#define CLK_AUD_LRCK_DETECT			1
+#define CLK_AUD_I2S				2
+#define CLK_AUD_APLL_TUNER			3
+#define CLK_AUD_HDMI				4
+#define CLK_AUD_SPDF				5
+#define CLK_AUD_SPDF2				6
+#define CLK_AUD_APLL				7
+#define CLK_AUD_TML				8
+#define CLK_AUD_AHB_IDLE_EXT			9
+#define CLK_AUD_AHB_IDLE_INT			10
+
+#define CLK_AUD_I2SIN1				11
+#define CLK_AUD_I2SIN2				12
+#define CLK_AUD_I2SIN3				13
+#define CLK_AUD_I2SIN4				14
+#define CLK_AUD_I2SIN5				15
+#define CLK_AUD_I2SIN6				16
+#define CLK_AUD_I2SO1				17
+#define CLK_AUD_I2SO2				18
+#define CLK_AUD_I2SO3				19
+#define CLK_AUD_I2SO4				20
+#define CLK_AUD_I2SO5				21
+#define CLK_AUD_I2SO6				22
+#define CLK_AUD_ASRCI1				23
+#define CLK_AUD_ASRCI2				24
+#define CLK_AUD_ASRCO1				25
+#define CLK_AUD_ASRCO2				26
+#define CLK_AUD_ASRC11				27
+#define CLK_AUD_ASRC12				28
+#define CLK_AUD_HDMIRX				29
+#define CLK_AUD_INTDIR				30
+#define CLK_AUD_A1SYS				31
+#define CLK_AUD_A2SYS				32
+#define CLK_AUD_AFE_CONN			33
+#define CLK_AUD_AFE_PCMIF			34
+#define CLK_AUD_AFE_MRGIF			35
+
+#define CLK_AUD_MMIF_UL1			36
+#define CLK_AUD_MMIF_UL2			37
+#define CLK_AUD_MMIF_UL3			38
+#define CLK_AUD_MMIF_UL4			39
+#define CLK_AUD_MMIF_UL5			40
+#define CLK_AUD_MMIF_UL6			41
+#define CLK_AUD_MMIF_DL1			42
+#define CLK_AUD_MMIF_DL2			43
+#define CLK_AUD_MMIF_DL3			44
+#define CLK_AUD_MMIF_DL4			45
+#define CLK_AUD_MMIF_DL5			46
+#define CLK_AUD_MMIF_DL6			47
+#define CLK_AUD_MMIF_DLMCH			48
+#define CLK_AUD_MMIF_ARB1			49
+#define CLK_AUD_MMIF_AWB1			50
+#define CLK_AUD_MMIF_AWB2			51
+#define CLK_AUD_MMIF_DAI			52
+
+#define CLK_AUD_DMIC1				53
+#define CLK_AUD_DMIC2				54
+#define CLK_AUD_ASRCI3				55
+#define CLK_AUD_ASRCI4				56
+#define CLK_AUD_ASRCI5				57
+#define CLK_AUD_ASRCI6				58
+#define CLK_AUD_ASRCO3				59
+#define CLK_AUD_ASRCO4				60
+#define CLK_AUD_ASRCO5				61
+#define CLK_AUD_ASRCO6				62
+#define CLK_AUD_MEM_ASRC1			63
+#define CLK_AUD_MEM_ASRC2			64
+#define CLK_AUD_MEM_ASRC3			65
+#define CLK_AUD_MEM_ASRC4			66
+#define CLK_AUD_MEM_ASRC5			67
+#define CLK_AUD_DSD_ENC				68
+#define CLK_AUD_ASRC_BRG			60
+#define CLK_AUD_NR				70
+
+/* MMSYS */
+#define CLK_MM_SMI_COMMON			0
+#define CLK_MM_SMI_LARB0			1
+#define CLK_MM_CMDQ				2
+#define CLK_MM_MUTEX				3
+#define CLK_MM_DISP_COLOR			4
+#define CLK_MM_DISP_BLS				5
+#define CLK_MM_DISP_WDMA			6
+#define CLK_MM_DISP_RDMA			7
+#define CLK_MM_DISP_OVL				8
+#define CLK_MM_MDP_TDSHP			9
+#define CLK_MM_MDP_WROT				10
+#define CLK_MM_MDP_WDMA				11
+#define CLK_MM_MDP_RSZ1				12
+#define CLK_MM_MDP_RSZ0				13
+#define CLK_MM_MDP_RDMA				14
+#define CLK_MM_MDP_BLS_26M			15
+#define CLK_MM_CAM_MDP				16
+#define CLK_MM_FAKE_ENG				17
+#define CLK_MM_MUTEX_32K			18
+#define CLK_MM_DISP_RDMA1			19
+#define CLK_MM_DISP_UFOE			20
+
+#define CLK_MM_DSI_ENGINE			21
+#define CLK_MM_DSI_DIG				22
+#define CLK_MM_DPI_DIGL				23
+#define CLK_MM_DPI_ENGINE			24
+#define CLK_MM_DPI1_DIGL			25
+#define CLK_MM_DPI1_ENGINE			26
+#define CLK_MM_TVE_OUTPUT			27
+#define CLK_MM_TVE_INPUT			28
+#define CLK_MM_HDMI_PIXEL			29
+#define CLK_MM_HDMI_PLL				30
+#define CLK_MM_HDMI_AUDIO			31
+#define CLK_MM_HDMI_SPDIF			32
+#define CLK_MM_TVE_FMM				33
+#define CLK_MM_NR				34
+
+/* IMGSYS */
+#define CLK_IMG_SMI_COMM			0
+#define CLK_IMG_RESZ				1
+#define CLK_IMG_JPGDEC_SMI			2
+#define CLK_IMG_JPGDEC				3
+#define CLK_IMG_VENC_LT				4
+#define CLK_IMG_VENC				5
+#define CLK_IMG_NR				6
+
+/* VDEC */
+#define CLK_VDEC_CKGEN				0
+#define CLK_VDEC_LARB				1
+#define CLK_VDEC_NR				2
+
+/* HIFSYS */
+#define CLK_HIFSYS_USB0PHY			0
+#define CLK_HIFSYS_USB1PHY			1
+#define CLK_HIFSYS_PCIE0			2
+#define CLK_HIFSYS_PCIE1			3
+#define CLK_HIFSYS_PCIE2			4
+#define CLK_HIFSYS_NR				5
+
+/* ETHSYS */
+#define CLK_ETHSYS_HSDMA			0
+#define CLK_ETHSYS_ESW				1
+#define CLK_ETHSYS_GP2				2
+#define CLK_ETHSYS_GP1				3
+#define CLK_ETHSYS_PCM				4
+#define CLK_ETHSYS_GDMA				5
+#define CLK_ETHSYS_I2S				6
+#define CLK_ETHSYS_CRYPTO			7
+#define CLK_ETHSYS_NR				8
+
+/* G3DSYS */
+#define CLK_G3DSYS_CORE				0
+#define CLK_G3DSYS_NR				1
+
+#endif /* _DT_BINDINGS_CLK_MT2701_H */
diff --git a/include/dt-bindings/clock/mt7629-clk.h b/include/dt-bindings/clock/mt7629-clk.h
new file mode 100644
index 0000000..0bbfbfa
--- /dev/null
+++ b/include/dt-bindings/clock/mt7629-clk.h
@@ -0,0 +1,206 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT7629_H
+#define _DT_BINDINGS_CLK_MT7629_H
+
+/* TOPCKGEN */
+#define CLK_TOP_FCLKS_OFF		0
+
+#define CLK_TOP_TO_U2_PHY		0
+#define CLK_TOP_TO_U2_PHY_1P		1
+#define CLK_TOP_PCIE0_PIPE_EN		2
+#define CLK_TOP_PCIE1_PIPE_EN		3
+#define CLK_TOP_SSUSB_TX250M		4
+#define CLK_TOP_SSUSB_EQ_RX250M		5
+#define CLK_TOP_SSUSB_CDR_REF		6
+#define CLK_TOP_SSUSB_CDR_FB		7
+#define CLK_TOP_SATA_ASIC		8
+#define CLK_TOP_SATA_RBC		9
+
+#define CLK_TOP_TO_USB3_SYS		10
+#define CLK_TOP_P1_1MHZ			11
+#define CLK_TOP_4MHZ			12
+#define CLK_TOP_P0_1MHZ			13
+#define CLK_TOP_ETH_500M		14
+#define CLK_TOP_TXCLK_SRC_PRE		15
+#define CLK_TOP_RTC			16
+#define CLK_TOP_PWM_QTR_26M		17
+#define CLK_TOP_CPUM_TCK_IN		18
+#define CLK_TOP_TO_USB3_DA_TOP		19
+#define CLK_TOP_MEMPLL			20
+#define CLK_TOP_DMPLL			21
+#define CLK_TOP_DMPLL_D4		22
+#define CLK_TOP_DMPLL_D8		23
+#define CLK_TOP_SYSPLL_D2		24
+#define CLK_TOP_SYSPLL1_D2		25
+#define CLK_TOP_SYSPLL1_D4		26
+#define CLK_TOP_SYSPLL1_D8		27
+#define CLK_TOP_SYSPLL1_D16		28
+#define CLK_TOP_SYSPLL2_D2		29
+#define CLK_TOP_SYSPLL2_D4		30
+#define CLK_TOP_SYSPLL2_D8		31
+#define CLK_TOP_SYSPLL_D5		32
+#define CLK_TOP_SYSPLL3_D2		33
+#define CLK_TOP_SYSPLL3_D4		34
+#define CLK_TOP_SYSPLL_D7		35
+#define CLK_TOP_SYSPLL4_D2		36
+#define CLK_TOP_SYSPLL4_D4		37
+#define CLK_TOP_SYSPLL4_D16		38
+#define CLK_TOP_UNIVPLL			39
+#define CLK_TOP_UNIVPLL1_D2		40
+#define CLK_TOP_UNIVPLL1_D4		41
+#define CLK_TOP_UNIVPLL1_D8		42
+#define CLK_TOP_UNIVPLL_D3		43
+#define CLK_TOP_UNIVPLL2_D2		44
+#define CLK_TOP_UNIVPLL2_D4		45
+#define CLK_TOP_UNIVPLL2_D8		46
+#define CLK_TOP_UNIVPLL2_D16		47
+#define CLK_TOP_UNIVPLL_D5		48
+#define CLK_TOP_UNIVPLL3_D2		49
+#define CLK_TOP_UNIVPLL3_D4		50
+#define CLK_TOP_UNIVPLL3_D16		51
+#define CLK_TOP_UNIVPLL_D7		52
+#define CLK_TOP_UNIVPLL_D80_D4		53
+#define CLK_TOP_UNIV48M			54
+#define CLK_TOP_SGMIIPLL_D2		55
+#define CLK_TOP_CLKXTAL_D4		56
+#define CLK_TOP_HD_FAXI			57
+#define CLK_TOP_FAXI			58
+#define CLK_TOP_F_FAUD_INTBUS		59
+#define CLK_TOP_AP2WBHIF_HCLK		60
+#define CLK_TOP_10M_INFRAO		61
+#define CLK_TOP_MSDC30_1		62
+#define CLK_TOP_SPI			63
+#define CLK_TOP_SF			64
+#define CLK_TOP_FLASH			65
+#define CLK_TOP_TO_USB3_REF		66
+#define CLK_TOP_TO_USB3_MCU		67
+#define CLK_TOP_TO_USB3_DMA		68
+#define CLK_TOP_FROM_TOP_AHB		69
+#define CLK_TOP_FROM_TOP_AXI		70
+#define CLK_TOP_PCIE1_MAC_EN		71
+#define CLK_TOP_PCIE0_MAC_EN		72
+
+#define CLK_TOP_AXI_SEL			73
+#define CLK_TOP_MEM_SEL			74
+#define CLK_TOP_DDRPHYCFG_SEL		75
+#define CLK_TOP_ETH_SEL			76
+#define CLK_TOP_PWM_SEL			77
+#define CLK_TOP_F10M_REF_SEL		78
+#define CLK_TOP_NFI_INFRA_SEL		79
+#define CLK_TOP_FLASH_SEL		80
+#define CLK_TOP_UART_SEL		81
+#define CLK_TOP_SPI0_SEL		82
+#define CLK_TOP_SPI1_SEL		83
+#define CLK_TOP_MSDC50_0_SEL		84
+#define CLK_TOP_MSDC30_0_SEL		85
+#define CLK_TOP_MSDC30_1_SEL		86
+#define CLK_TOP_AP2WBMCU_SEL		87
+#define CLK_TOP_AP2WBHIF_SEL		88
+#define CLK_TOP_AUDIO_SEL		89
+#define CLK_TOP_AUD_INTBUS_SEL		90
+#define CLK_TOP_PMICSPI_SEL		91
+#define CLK_TOP_SCP_SEL			92
+#define CLK_TOP_ATB_SEL			93
+#define CLK_TOP_HIF_SEL			94
+#define CLK_TOP_SATA_SEL		95
+#define CLK_TOP_U2_SEL			96
+#define CLK_TOP_AUD1_SEL		97
+#define CLK_TOP_AUD2_SEL		98
+#define CLK_TOP_IRRX_SEL		99
+#define CLK_TOP_IRTX_SEL		100
+#define CLK_TOP_SATA_MCU_SEL		101
+#define CLK_TOP_PCIE0_MCU_SEL		102
+#define CLK_TOP_PCIE1_MCU_SEL		103
+#define CLK_TOP_SSUSB_MCU_SEL		104
+#define CLK_TOP_CRYPTO_SEL		105
+#define CLK_TOP_SGMII_REF_1_SEL		106
+#define CLK_TOP_10M_SEL			107
+#define CLK_TOP_NR_CLK			108
+
+/* INFRACFG */
+#define CLK_INFRA_MUX1_SEL		0
+#define CLK_INFRA_DBGCLK_PD		1
+#define CLK_INFRA_TRNG_PD		2
+#define CLK_INFRA_DEVAPC_PD		3
+#define CLK_INFRA_APXGPT_PD		4
+#define CLK_INFRA_SEJ_PD		5
+#define CLK_INFRA_NR_CLK		6
+
+/* PERICFG */
+#define CLK_PERIBUS_SEL			0
+#define CLK_PERI_PWM1_PD		1
+#define CLK_PERI_PWM2_PD		2
+#define CLK_PERI_PWM3_PD		3
+#define CLK_PERI_PWM4_PD		4
+#define CLK_PERI_PWM5_PD		5
+#define CLK_PERI_PWM6_PD		6
+#define CLK_PERI_PWM7_PD		7
+#define CLK_PERI_PWM_PD			8
+#define CLK_PERI_AP_DMA_PD		9
+#define CLK_PERI_MSDC30_1_PD		10
+#define CLK_PERI_UART0_PD		11
+#define CLK_PERI_UART1_PD		12
+#define CLK_PERI_UART2_PD		13
+#define CLK_PERI_UART3_PD		14
+#define CLK_PERI_BTIF_PD		15
+#define CLK_PERI_I2C0_PD		16
+#define CLK_PERI_SPI0_PD		17
+#define CLK_PERI_SNFI_PD		18
+#define CLK_PERI_NFI_PD			19
+#define CLK_PERI_NFIECC_PD		20
+#define CLK_PERI_FLASH_PD		21
+#define CLK_PERI_NR_CLK			22
+
+/* APMIXEDSYS */
+#define CLK_APMIXED_ARMPLL		0
+#define CLK_APMIXED_MAINPLL		1
+#define CLK_APMIXED_UNIV2PLL		2
+#define CLK_APMIXED_ETH1PLL		3
+#define CLK_APMIXED_ETH2PLL		4
+#define CLK_APMIXED_SGMIPLL		5
+#define CLK_APMIXED_NR_CLK		6
+
+/* SSUSBSYS */
+#define CLK_SSUSB_U2_PHY_1P_EN		0
+#define CLK_SSUSB_U2_PHY_EN		1
+#define CLK_SSUSB_REF_EN		2
+#define CLK_SSUSB_SYS_EN		3
+#define CLK_SSUSB_MCU_EN		4
+#define CLK_SSUSB_DMA_EN		5
+#define CLK_SSUSB_NR_CLK		6
+
+/* PCIESYS */
+#define CLK_PCIE_P1_AUX_EN		0
+#define CLK_PCIE_P1_OBFF_EN		1
+#define CLK_PCIE_P1_AHB_EN		2
+#define CLK_PCIE_P1_AXI_EN		3
+#define CLK_PCIE_P1_MAC_EN		4
+#define CLK_PCIE_P1_PIPE_EN		5
+#define CLK_PCIE_P0_AUX_EN		6
+#define CLK_PCIE_P0_OBFF_EN		7
+#define CLK_PCIE_P0_AHB_EN		8
+#define CLK_PCIE_P0_AXI_EN		9
+#define CLK_PCIE_P0_MAC_EN		10
+#define CLK_PCIE_P0_PIPE_EN		11
+#define CLK_PCIE_NR_CLK			12
+
+/* ETHSYS */
+#define CLK_ETH_FE_EN			0
+#define CLK_ETH_GP2_EN			1
+#define CLK_ETH_GP1_EN			2
+#define CLK_ETH_GP0_EN			3
+#define CLK_ETH_ESW_EN			4
+#define CLK_ETH_NR_CLK			5
+
+/* SGMIISYS */
+#define CLK_SGMII_TX_EN			0
+#define CLK_SGMII_RX_EN			1
+#define CLK_SGMII_CDR_REF		2
+#define CLK_SGMII_CDR_FB		3
+#define CLK_SGMII_NR_CLK		4
+
+#endif /* _DT_BINDINGS_CLK_MT7629_H */
diff --git a/include/dt-bindings/power/mt7623-power.h b/include/dt-bindings/power/mt7623-power.h
new file mode 100644
index 0000000..0e73bb4
--- /dev/null
+++ b/include/dt-bindings/power/mt7623-power.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef _DT_BINDINGS_MT7623_POWER_H
+#define _DT_BINDINGS_MT7623_POWER_H
+
+#define MT7623_POWER_DOMAIN_CONN	0
+#define MT7623_POWER_DOMAIN_DISP	1
+#define MT7623_POWER_DOMAIN_MFG		2
+#define MT7623_POWER_DOMAIN_VDEC	3
+#define MT7623_POWER_DOMAIN_ISP		4
+#define MT7623_POWER_DOMAIN_BDP		5
+#define MT7623_POWER_DOMAIN_ETH		6
+#define MT7623_POWER_DOMAIN_HIF		7
+#define MT7623_POWER_DOMAIN_IFR_MSC	8
+
+#endif /* _DT_BINDINGS_MT7623_POWER_H */
diff --git a/include/dt-bindings/power/mt7629-power.h b/include/dt-bindings/power/mt7629-power.h
new file mode 100644
index 0000000..c7e6130
--- /dev/null
+++ b/include/dt-bindings/power/mt7629-power.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ */
+
+#ifndef _DT_BINDINGS_MT7629_POWER_H
+#define _DT_BINDINGS_MT7629_POWER_H
+
+#define MT7629_POWER_DOMAIN_ETHSYS	0
+#define MT7629_POWER_DOMAIN_HIF0	1
+#define MT7629_POWER_DOMAIN_HIF1	2
+
+#endif /* _DT_BINDINGS_MT7629_POWER_H */
diff --git a/include/image.h b/include/image.h
index 031c355..f67502e 100644
--- a/include/image.h
+++ b/include/image.h
@@ -278,6 +278,7 @@
 	IH_TYPE_PMMC,            /* TI Power Management Micro-Controller Firmware */
 	IH_TYPE_STM32IMAGE,		/* STMicroelectronics STM32 Image */
 	IH_TYPE_SOCFPGAIMAGE_V1,	/* Altera SOCFPGA A10 Preloader	*/
+	IH_TYPE_MTKIMAGE,		/* MediaTek BootROM loadable Image */
 
 	IH_TYPE_COUNT,			/* Number of image types */
 };
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 7416abe..22bd8f7 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -219,6 +219,8 @@
 ALL-$(CONFIG_ARCH_ZYNQ)		+= $(obj)/boot.bin
 ALL-$(CONFIG_ARCH_ZYNQMP)	+= $(obj)/boot.bin
 
+ALL-$(CONFIG_ARCH_MEDIATEK)	+= $(obj)/u-boot-spl-mtk.bin
+
 all:	$(ALL-y)
 
 quiet_cmd_cat = CAT     $@
@@ -349,6 +351,15 @@
 $(obj)/sunxi-spl-with-ecc.bin: $(obj)/sunxi-spl.bin
 	$(call if_changed,sunxi_spl_image_builder)
 
+
+# MediaTek's specific SPL build
+MKIMAGEFLAGS_u-boot-spl-mtk.bin = -T mtk_image \
+	-a $(CONFIG_SPL_TEXT_BASE) -e $(CONFIG_SPL_TEXT_BASE) \
+	-n "$(patsubst "%",%,$(CONFIG_MTK_BROM_HEADER_INFO))"
+
+$(obj)/u-boot-spl-mtk.bin: $(obj)/u-boot-spl.bin FORCE
+	$(call if_changed,mkimage)
+
 # Rule to link u-boot-spl
 # May be overridden by arch/$(ARCH)/config.mk
 quiet_cmd_u-boot-spl ?= LD      $@
diff --git a/tools/Makefile b/tools/Makefile
index 3c0521f..c93d17a 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -116,6 +116,7 @@
 			$(LIBFDT_OBJS) \
 			gpimage.o \
 			gpimage-common.o \
+			mtk_image.o \
 			$(RSA_OBJS-y)
 
 dumpimage-objs := $(dumpimage-mkimage-objs) dumpimage.o
diff --git a/tools/mtk_image.c b/tools/mtk_image.c
new file mode 100644
index 0000000..2706d2d
--- /dev/null
+++ b/tools/mtk_image.c
@@ -0,0 +1,749 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Generate MediaTek BootROM header for SPL/U-Boot images
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <image.h>
+#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
+	}
+};
+
+static const struct brom_img_type {
+	const char *name;
+	enum brlyt_img_type type;
+} brom_images[] = {
+	{
+		.name = "nand",
+		.type = BRLYT_TYPE_NAND
+	}, {
+		.name = "emmc",
+		.type = BRLYT_TYPE_EMMC
+	}, {
+		.name = "nor",
+		.type = BRLYT_TYPE_NOR
+	}, {
+		.name = "sdmmc",
+		.type = BRLYT_TYPE_SDMMC
+	}, {
+		.name = "snand",
+		.type = BRLYT_TYPE_SNAND
+	}
+};
+
+/* Image type selected by user */
+static enum brlyt_img_type hdr_media;
+static int use_lk_hdr;
+
+/* LK image name */
+static char lk_name[32] = "U-Boot";
+
+/* NAND header selected by user */
+static const union nand_boot_header *hdr_nand;
+
+/* GFH header + 2 * 4KB pages of NAND */
+static char hdr_tmp[sizeof(struct gfh_header) + 0x2000];
+
+static int mtk_image_check_image_types(uint8_t type)
+{
+	if (type == IH_TYPE_MTKIMAGE)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+}
+
+static int mtk_brom_parse_imagename(const char *imagename)
+{
+#define is_blank_char(c) \
+	((c) == '\t' || (c) == '\n' || (c) == '\r' || (c) == ' ')
+
+	char *buf = strdup(imagename), *key, *val, *end, *next;
+	int i;
+
+	/* User passed arguments from image name */
+	static const char *media = "";
+	static const char *nandinfo = "";
+	static const char *lk = "";
+
+	key = buf;
+	while (key) {
+		next = strchr(key, ';');
+		if (next)
+			*next = 0;
+
+		val = strchr(key, '=');
+		if (val) {
+			*val++ = 0;
+
+			/* Trim key */
+			while (is_blank_char(*key))
+				key++;
+
+			end = key + strlen(key) - 1;
+			while ((end >= key) && is_blank_char(*end))
+				end--;
+			end++;
+
+			if (is_blank_char(*end))
+				*end = 0;
+
+			/* Trim value */
+			while (is_blank_char(*val))
+				val++;
+
+			end = val + strlen(val) - 1;
+			while ((end >= val) && is_blank_char(*end))
+				end--;
+			end++;
+
+			if (is_blank_char(*end))
+				*end = 0;
+
+			/* record user passed arguments */
+			if (!strcmp(key, "media"))
+				media = val;
+
+			if (!strcmp(key, "nandinfo"))
+				nandinfo = val;
+
+			if (!strcmp(key, "lk"))
+				lk = val;
+
+			if (!strcmp(key, "lkname"))
+				strncpy(lk_name, val, sizeof(lk_name));
+		}
+
+		if (next)
+			key = next + 1;
+		else
+			break;
+	}
+
+	/* if user specified LK image header, skip following checks */
+	if (lk && lk[0] == '1') {
+		use_lk_hdr = 1;
+		free(buf);
+		return 0;
+	}
+
+	/* parse media type */
+	for (i = 0; i < ARRAY_SIZE(brom_images); i++) {
+		if (!strcmp(brom_images[i].name, media)) {
+			hdr_media = brom_images[i].type;
+			break;
+		}
+	}
+
+	/* 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;
+		}
+	}
+
+	free(buf);
+
+	if (hdr_media == BRLYT_TYPE_INVALID) {
+		fprintf(stderr, "Error: media type is invalid or missing.\n");
+		fprintf(stderr, "       Please specify -n \"media=<type>\"\n");
+		return -EINVAL;
+	}
+
+	if ((hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND) &&
+	    !hdr_nand) {
+		fprintf(stderr, "Error: nand info is invalid or missing.\n");
+		fprintf(stderr, "       Please specify -n \"media=%s;"
+				"nandinfo=<info>\"\n", media);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mtk_image_check_params(struct image_tool_params *params)
+{
+	if (!params->addr) {
+		fprintf(stderr, "Error: Load Address must be set.\n");
+		return -EINVAL;
+	}
+
+	if (!params->imagename) {
+		fprintf(stderr, "Error: Image Name must be set.\n");
+		return -EINVAL;
+	}
+
+	return mtk_brom_parse_imagename(params->imagename);
+}
+
+static int mtk_image_vrec_header(struct image_tool_params *params,
+				 struct image_type_params *tparams)
+{
+	if (use_lk_hdr) {
+		tparams->header_size = sizeof(union lk_hdr);
+		tparams->hdr = &hdr_tmp;
+		memset(&hdr_tmp, 0xff, tparams->header_size);
+		return 0;
+	}
+
+	if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND)
+		tparams->header_size = 2 * le16_to_cpu(hdr_nand->pagesize);
+	else
+		tparams->header_size = sizeof(struct gen_device_header);
+
+	tparams->header_size += sizeof(struct gfh_header);
+	tparams->hdr = &hdr_tmp;
+
+	memset(&hdr_tmp, 0xff, tparams->header_size);
+
+	return SHA256_SUM_LEN;
+}
+
+static int mtk_image_verify_gen_header(const uint8_t *ptr, int print)
+{
+	union gen_boot_header *gbh = (union gen_boot_header *)ptr;
+	struct brom_layout_header *bh;
+	struct gfh_header *gfh;
+	const char *bootmedia;
+
+	if (!strcmp(gbh->name, SF_BOOT_NAME))
+		bootmedia = "Serial NOR";
+	else if (!strcmp(gbh->name, EMMC_BOOT_NAME))
+		bootmedia = "eMMC";
+	else if (!strcmp(gbh->name, SDMMC_BOOT_NAME))
+		bootmedia = "SD/MMC";
+	else
+		return -1;
+
+	if (print)
+		printf("Boot Media:   %s\n", bootmedia);
+
+	if (le32_to_cpu(gbh->version) != 1 ||
+	    le32_to_cpu(gbh->size) != sizeof(union gen_boot_header))
+		return -1;
+
+	bh = (struct brom_layout_header *)(ptr + le32_to_cpu(gbh->size));
+
+	if (strcmp(bh->name, BRLYT_NAME))
+		return -1;
+
+	if (le32_to_cpu(bh->magic) != BRLYT_MAGIC ||
+	    (le32_to_cpu(bh->type) != BRLYT_TYPE_NOR &&
+	    le32_to_cpu(bh->type) != BRLYT_TYPE_EMMC &&
+	    le32_to_cpu(bh->type) != BRLYT_TYPE_SDMMC))
+		return -1;
+
+	gfh = (struct gfh_header *)(ptr + le32_to_cpu(bh->header_size));
+
+	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));
+
+	return 0;
+}
+
+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 gfh_header *gfh;
+	const char *bootmedia;
+
+	if (strncmp(nh->version, NAND_BOOT_VERSION, sizeof(nh->version)) ||
+	    strcmp(nh->id, NAND_BOOT_ID))
+		return -1;
+
+	bh = (struct brom_layout_header *)(ptr + le16_to_cpu(nh->pagesize));
+
+	if (strcmp(bh->name, BRLYT_NAME))
+		return -1;
+
+	if (le32_to_cpu(bh->magic) != BRLYT_MAGIC) {
+		return -1;
+	} else {
+		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";
+		else
+			return -1;
+	}
+
+	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));
+		}
+
+		if (le16_to_cpu(nh->pagesize) >= 1024)
+			printf("Page Size:    %dKB\n",
+			       le16_to_cpu(nh->pagesize) >> 10);
+		else
+			printf("Page Size:    %dB\n",
+			       le16_to_cpu(nh->pagesize));
+
+		printf("Spare Size:   %dB\n", le16_to_cpu(nh->oobsize));
+	}
+
+	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;
+
+	if (print)
+		printf("Load Address: %08x\n",
+		       le32_to_cpu(gfh->file_info.load_addr) +
+		       le32_to_cpu(gfh->file_info.jump_offset));
+
+	return 0;
+}
+
+static int mtk_image_verify_header(unsigned char *ptr, int image_size,
+				   struct image_tool_params *params)
+{
+	union lk_hdr *lk = (union lk_hdr *)ptr;
+
+	/* nothing to verify for LK image header */
+	if (le32_to_cpu(lk->magic) == LK_PART_MAGIC)
+		return 0;
+
+	if (!strcmp((char *)ptr, NAND_BOOT_NAME))
+		return mtk_image_verify_nand_header(ptr, 0);
+	else
+		return mtk_image_verify_gen_header(ptr, 0);
+
+	return -1;
+}
+
+static void mtk_image_print_header(const void *ptr)
+{
+	union lk_hdr *lk = (union lk_hdr *)ptr;
+
+	if (le32_to_cpu(lk->magic) == LK_PART_MAGIC) {
+		printf("Image Type:   MediaTek LK Image\n");
+		printf("Load Address: %08x\n", le32_to_cpu(lk->loadaddr));
+		return;
+	}
+
+	printf("Image Type:   MediaTek BootROM Loadable Image\n");
+
+	if (!strcmp((char *)ptr, NAND_BOOT_NAME))
+		mtk_image_verify_nand_header(ptr, 1);
+	else
+		mtk_image_verify_gen_header(ptr, 1);
+}
+
+static void put_brom_layout_header(struct brom_layout_header *hdr, int type)
+{
+	strncpy(hdr->name, BRLYT_NAME, sizeof(hdr->name));
+	hdr->version = cpu_to_le32(1);
+	hdr->magic = cpu_to_le32(BRLYT_MAGIC);
+	hdr->type = cpu_to_le32(type);
+}
+
+static void put_ghf_common_header(struct gfh_common_header *gfh, int size,
+				  int type, int ver)
+{
+	memcpy(gfh->magic, GFH_HEADER_MAGIC, sizeof(gfh->magic));
+	gfh->version = ver;
+	gfh->size = cpu_to_le16(size);
+	gfh->type = cpu_to_le16(type);
+}
+
+static void put_ghf_header(struct gfh_header *gfh, int file_size,
+			   int dev_hdr_size, int load_addr, int flash_type)
+{
+	memset(gfh, 0, sizeof(struct gfh_header));
+
+	/* GFH_FILE_INFO header */
+	put_ghf_common_header(&gfh->file_info.gfh, sizeof(gfh->file_info),
+			      GFH_TYPE_FILE_INFO, 1);
+	strncpy(gfh->file_info.name, GFH_FILE_INFO_NAME,
+		sizeof(gfh->file_info.name));
+	gfh->file_info.unused = cpu_to_le32(1);
+	gfh->file_info.file_type = cpu_to_le16(1);
+	gfh->file_info.flash_type = flash_type;
+	gfh->file_info.sig_type = GFH_SIG_TYPE_SHA256;
+	gfh->file_info.load_addr = cpu_to_le32(load_addr - sizeof(*gfh));
+	gfh->file_info.total_size = cpu_to_le32(file_size - dev_hdr_size);
+	gfh->file_info.max_size = cpu_to_le32(file_size);
+	gfh->file_info.hdr_size = sizeof(*gfh);
+	gfh->file_info.sig_size = SHA256_SUM_LEN;
+	gfh->file_info.jump_offset = sizeof(*gfh);
+	gfh->file_info.processed = cpu_to_le32(1);
+
+	/* GFH_BL_INFO header */
+	put_ghf_common_header(&gfh->bl_info.gfh, sizeof(gfh->bl_info),
+			      GFH_TYPE_BL_INFO, 1);
+	gfh->bl_info.attr = cpu_to_le32(1);
+
+	/* GFH_BROM_CFG header */
+	put_ghf_common_header(&gfh->brom_cfg.gfh, sizeof(gfh->brom_cfg),
+			      GFH_TYPE_BROM_CFG, 3);
+	gfh->brom_cfg.cfg_bits = cpu_to_le32(
+		GFH_BROM_CFG_USBDL_AUTO_DETECT_DIS |
+		GFH_BROM_CFG_USBDL_BY_KCOL0_TIMEOUT_EN |
+		GFH_BROM_CFG_USBDL_BY_FLAG_TIMEOUT_EN);
+	gfh->brom_cfg.usbdl_by_kcol0_timeout_ms = cpu_to_le32(5000);
+
+	/* GFH_BL_SEC_KEY header */
+	put_ghf_common_header(&gfh->bl_sec_key.gfh, sizeof(gfh->bl_sec_key),
+			      GFH_TYPE_BL_SEC_KEY, 1);
+
+	/* GFH_ANTI_CLONE header */
+	put_ghf_common_header(&gfh->anti_clone.gfh, sizeof(gfh->anti_clone),
+			      GFH_TYPE_ANTI_CLONE, 1);
+	gfh->anti_clone.ac_offset = cpu_to_le32(0x10);
+	gfh->anti_clone.ac_len = cpu_to_le32(0x80);
+
+	/* GFH_BROM_SEC_CFG header */
+	put_ghf_common_header(&gfh->brom_sec_cfg.gfh,
+			      sizeof(gfh->brom_sec_cfg),
+			      GFH_TYPE_BROM_SEC_CFG, 1);
+	gfh->brom_sec_cfg.cfg_bits =
+		cpu_to_le32(BROM_SEC_CFG_JTAG_EN | BROM_SEC_CFG_UART_EN);
+}
+
+static void put_hash(uint8_t *buff, int size)
+{
+	sha256_context ctx;
+
+	sha256_starts(&ctx);
+	sha256_update(&ctx, buff, size);
+	sha256_finish(&ctx, buff + size);
+}
+
+static void mtk_image_set_gen_header(void *ptr, off_t filesize,
+				     uint32_t loadaddr)
+{
+	struct gen_device_header *hdr = (struct gen_device_header *)ptr;
+	struct gfh_header *gfh;
+	const char *bootname = NULL;
+
+	if (hdr_media == BRLYT_TYPE_NOR)
+		bootname = SF_BOOT_NAME;
+	else if (hdr_media == BRLYT_TYPE_EMMC)
+		bootname = EMMC_BOOT_NAME;
+	else if (hdr_media == BRLYT_TYPE_SDMMC)
+		bootname = SDMMC_BOOT_NAME;
+
+	/* Generic device header */
+	strncpy(hdr->boot.name, bootname, sizeof(hdr->boot.name));
+	hdr->boot.version = cpu_to_le32(1);
+	hdr->boot.size = cpu_to_le32(sizeof(hdr->boot));
+
+	/* BRLYT header */
+	put_brom_layout_header(&hdr->brlyt, hdr_media);
+	hdr->brlyt.header_size = cpu_to_le32(sizeof(struct gen_device_header));
+	hdr->brlyt.total_size = cpu_to_le32(filesize);
+	hdr->brlyt.header_size_2 = hdr->brlyt.header_size;
+	hdr->brlyt.total_size_2 = hdr->brlyt.total_size;
+
+	/* GFH header */
+	gfh = (struct gfh_header *)(ptr + sizeof(struct gen_device_header));
+	put_ghf_header(gfh, filesize, sizeof(struct gen_device_header),
+		       loadaddr, GFH_FLASH_TYPE_GEN);
+
+	/* Generate SHA256 hash */
+	put_hash((uint8_t *)gfh,
+		 filesize - sizeof(struct gen_device_header) - SHA256_SUM_LEN);
+}
+
+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;
+
+	/* NAND device header, repeat 4 times */
+	for (i = 0; i < 4; i++)
+		memcpy(nh + i, hdr_nand, sizeof(union nand_boot_header));
+
+	/* 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);
+
+	/* 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);
+
+	/* Generate SHA256 hash */
+	put_hash((uint8_t *)gfh,
+		 filesize - 2 * le16_to_cpu(hdr_nand->pagesize) - SHA256_SUM_LEN);
+}
+
+static void mtk_image_set_header(void *ptr, struct stat *sbuf, int ifd,
+				 struct image_tool_params *params)
+{
+	union lk_hdr *lk = (union lk_hdr *)ptr;
+
+	if (use_lk_hdr) {
+		lk->magic = cpu_to_le32(LK_PART_MAGIC);
+		lk->size = cpu_to_le32(sbuf->st_size - sizeof(union lk_hdr));
+		lk->loadaddr = cpu_to_le32(params->addr);
+		lk->mode = 0xffffffff; /* must be non-zero */
+		memset(lk->name, 0, sizeof(lk->name));
+		strncpy(lk->name, lk_name, sizeof(lk->name));
+		return;
+	}
+
+	if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND)
+		mtk_image_set_nand_header(ptr, sbuf->st_size, params->addr);
+	else
+		mtk_image_set_gen_header(ptr, sbuf->st_size, params->addr);
+}
+
+U_BOOT_IMAGE_TYPE(
+	mtk_image,
+	"MediaTek BootROM Loadable Image support",
+	0,
+	NULL,
+	mtk_image_check_params,
+	mtk_image_verify_header,
+	mtk_image_print_header,
+	mtk_image_set_header,
+	NULL,
+	mtk_image_check_image_types,
+	NULL,
+	mtk_image_vrec_header
+);
diff --git a/tools/mtk_image.h b/tools/mtk_image.h
new file mode 100644
index 0000000..0a9eab3
--- /dev/null
+++ b/tools/mtk_image.h
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * MediaTek BootROM header definitions
+ *
+ * Copyright (C) 2018 MediaTek Inc.
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _MTK_IMAGE_H
+#define _MTK_IMAGE_H
+
+/* Device header definitions */
+
+/* Header for NOR/SD/eMMC */
+union gen_boot_header {
+	struct {
+		char name[12];
+		__le32 version;
+		__le32 size;
+	};
+
+	uint8_t pad[0x200];
+};
+
+#define EMMC_BOOT_NAME		"EMMC_BOOT"
+#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];
+		__le16 ioif;
+		__le16 pagesize;
+		__le16 addrcycles;
+		__le16 oobsize;
+		__le16 pages_of_block;
+		__le16 numblocks;
+		__le16 writesize_shift;
+		__le16 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];
+	__le32 version;
+	__le32 header_size;
+	__le32 total_size;
+	__le32 magic;
+	__le32 type;
+	__le32 header_size_2;
+	__le32 total_size_2;
+	__le32 unused;
+};
+
+#define BRLYT_NAME		"BRLYT"
+#define BRLYT_MAGIC		0x42424242
+
+enum brlyt_img_type {
+	BRLYT_TYPE_INVALID = 0,
+	BRLYT_TYPE_NAND = 0x10002,
+	BRLYT_TYPE_EMMC = 0x10005,
+	BRLYT_TYPE_NOR = 0x10007,
+	BRLYT_TYPE_SDMMC = 0x10008,
+	BRLYT_TYPE_SNAND = 0x10009
+};
+
+/* Combined device header for NOR/SD/eMMC */
+struct gen_device_header {
+	union gen_boot_header boot;
+
+	union {
+		struct brom_layout_header brlyt;
+		uint8_t brlyt_pad[0x400];
+	};
+};
+
+/* BootROM header definitions */
+struct gfh_common_header {
+	uint8_t magic[3];
+	uint8_t version;
+	__le16 size;
+	__le16 type;
+};
+
+#define GFH_HEADER_MAGIC	"MMM"
+
+#define GFH_TYPE_FILE_INFO	0
+#define GFH_TYPE_BL_INFO	1
+#define GFH_TYPE_BROM_CFG	7
+#define GFH_TYPE_BL_SEC_KEY	3
+#define GFH_TYPE_ANTI_CLONE	2
+#define GFH_TYPE_BROM_SEC_CFG	8
+
+struct gfh_file_info {
+	struct gfh_common_header gfh;
+	char name[12];
+	__le32 unused;
+	__le16 file_type;
+	uint8_t flash_type;
+	uint8_t sig_type;
+	__le32 load_addr;
+	__le32 total_size;
+	__le32 max_size;
+	__le32 hdr_size;
+	__le32 sig_size;
+	__le32 jump_offset;
+	__le32 processed;
+};
+
+#define GFH_FILE_INFO_NAME	"FILE_INFO"
+
+#define GFH_FLASH_TYPE_GEN	5
+#define GFH_FLASH_TYPE_NAND	2
+
+#define GFH_SIG_TYPE_NONE	0
+#define GFH_SIG_TYPE_SHA256	1
+
+struct gfh_bl_info {
+	struct gfh_common_header gfh;
+	__le32 attr;
+};
+
+struct gfh_brom_cfg {
+	struct gfh_common_header gfh;
+	__le32 cfg_bits;
+	__le32 usbdl_by_auto_detect_timeout_ms;
+	uint8_t unused[0x48];
+	__le32 usbdl_by_kcol0_timeout_ms;
+	__le32 usbdl_by_flag_timeout_ms;
+	uint32_t pad;
+};
+
+#define GFH_BROM_CFG_USBDL_BY_AUTO_DETECT_TIMEOUT_EN	0x02
+#define GFH_BROM_CFG_USBDL_AUTO_DETECT_DIS		0x10
+#define GFH_BROM_CFG_USBDL_BY_KCOL0_TIMEOUT_EN		0x80
+#define GFH_BROM_CFG_USBDL_BY_FLAG_TIMEOUT_EN		0x100
+
+struct gfh_bl_sec_key {
+	struct gfh_common_header gfh;
+	uint8_t pad[0x20c];
+};
+
+struct gfh_anti_clone {
+	struct gfh_common_header gfh;
+	uint8_t ac_b2k;
+	uint8_t ac_b2c;
+	uint16_t pad;
+	__le32 ac_offset;
+	__le32 ac_len;
+};
+
+struct gfh_brom_sec_cfg {
+	struct gfh_common_header gfh;
+	__le32 cfg_bits;
+	char customer_name[0x20];
+	__le32 pad;
+};
+
+#define BROM_SEC_CFG_JTAG_EN	1
+#define BROM_SEC_CFG_UART_EN	2
+
+struct gfh_header {
+	struct gfh_file_info file_info;
+	struct gfh_bl_info bl_info;
+	struct gfh_brom_cfg brom_cfg;
+	struct gfh_bl_sec_key bl_sec_key;
+	struct gfh_anti_clone anti_clone;
+	struct gfh_brom_sec_cfg brom_sec_cfg;
+};
+
+/* LK image header */
+
+union lk_hdr {
+	struct {
+		__le32 magic;
+		__le32 size;
+		char name[32];
+		__le32 loadaddr;
+		__le32 mode;
+	};
+
+	uint8_t data[512];
+};
+
+#define LK_PART_MAGIC		0x58881688
+
+#endif /* _MTK_IMAGE_H */