diff --git a/MAINTAINERS b/MAINTAINERS
index 5891fd08b6a700c967f74dc441089dcfbffb037f..33fd4652a42554599e6ced49d26613546b902ab2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -578,6 +578,7 @@ F:	configs/mscc*
 F:	drivers/gpio/mscc_sgpio.c
 F:	drivers/spi/mscc_bb_spi.c
 F:	include/configs/vcoreiii.h
+F:	include/dt-bindings/mscc/
 F:	drivers/pinctrl/mscc/
 F:	drivers/net/mscc_eswitch/
 
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 194f4f349ed5bbb14f08c6ceee5ae4d2116f9f25..9cf8e9800d8305361c54dc70dd2d8bd43e072084 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -74,8 +74,8 @@ config ARCH_BMIPS
 	select SYSRESET
 	imply CMD_DM
 
-config ARCH_MT7620
-	bool "Support MT7620/7688 SoCs"
+config ARCH_MTMIPS
+	bool "Support MediaTek MIPS platforms"
 	imply CMD_DM
 	select DISPLAY_CPUINFO
 	select DM
@@ -153,7 +153,7 @@ source "arch/mips/mach-mscc/Kconfig"
 source "arch/mips/mach-bmips/Kconfig"
 source "arch/mips/mach-jz47xx/Kconfig"
 source "arch/mips/mach-pic32/Kconfig"
-source "arch/mips/mach-mt7620/Kconfig"
+source "arch/mips/mach-mtmips/Kconfig"
 
 if MIPS
 
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 029d290f1e06665869b80efdfe64c3e64047f73a..af3f227436ee3b80440c5c7e08ead4ddf506efbe 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -15,7 +15,7 @@ machine-$(CONFIG_ARCH_ATH79) += ath79
 machine-$(CONFIG_ARCH_BMIPS) += bmips
 machine-$(CONFIG_ARCH_JZ47XX) += jz47xx
 machine-$(CONFIG_MACH_PIC32) += pic32
-machine-$(CONFIG_ARCH_MT7620) += mt7620
+machine-$(CONFIG_ARCH_MTMIPS) += mtmips
 machine-$(CONFIG_ARCH_MSCC) += mscc
 
 machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))
diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
index 3522e6cdc82e5662424569a471d3202a11ce082f..e2de1da147e45c10b90e0d894b37aa9690e20cd6 100644
--- a/arch/mips/dts/Makefile
+++ b/arch/mips/dts/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0+
 
-dtb-$(CONFIG_ARCH_MT7620) += \
+dtb-$(CONFIG_ARCH_MTMIPS) += \
 	gardena-smart-gateway-mt7688.dtb \
 	linkit-smart-7688.dtb
 dtb-$(CONFIG_TARGET_AP121) += ap121.dtb
diff --git a/arch/mips/dts/luton_pcb090.dts b/arch/mips/dts/luton_pcb090.dts
index fe457bae9d56e6ab49b2b051d0cf8de85c5c59d8..ea3e3b7fbd83ccda37f207e99c2885b552141757 100644
--- a/arch/mips/dts/luton_pcb090.dts
+++ b/arch/mips/dts/luton_pcb090.dts
@@ -5,6 +5,7 @@
 
 /dts-v1/;
 #include "mscc,luton.dtsi"
+#include <dt-bindings/mscc/luton_data.h>
 
 / {
 	model = "Luton26 PCB090 Reference Board";
@@ -57,52 +58,195 @@
 
 &mdio0 {
 	status = "okay";
-};
-
-&port0 {
-	phy-handle = <&phy0>;
-};
-
-&port1 {
-	phy-handle = <&phy1>;
-};
-
-&port2 {
-	phy-handle = <&phy2>;
-};
-
-&port3 {
-	phy-handle = <&phy3>;
-};
-
-&port4 {
-	phy-handle = <&phy4>;
-};
-
-&port5 {
-	phy-handle = <&phy5>;
-};
-
-&port6 {
-	phy-handle = <&phy6>;
-};
-
-&port7 {
-	phy-handle = <&phy7>;
-};
 
-&port8 {
-	phy-handle = <&phy8>;
+	phy0: ethernet-phy@0 {
+		reg = <0>;
+	};
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+	};
+	phy2: ethernet-phy@2 {
+		reg = <2>;
+	};
+	phy3: ethernet-phy@3 {
+		reg = <3>;
+	};
+	phy4: ethernet-phy@4 {
+		reg = <4>;
+	};
+	phy5: ethernet-phy@5 {
+		reg = <5>;
+	};
+	phy6: ethernet-phy@6 {
+		reg = <6>;
+	};
+	phy7: ethernet-phy@7 {
+		reg = <7>;
+	};
+	phy8: ethernet-phy@8 {
+		reg = <8>;
+	};
+	phy9: ethernet-phy@9 {
+		reg = <9>;
+	};
+	phy10: ethernet-phy@10 {
+		reg = <10>;
+	};
+	phy11: ethernet-phy@11 {
+		reg = <11>;
+	};
 };
 
-&port9 {
-	phy-handle = <&phy9>;
-};
+&mdio1 {
+	status = "okay";
 
-&port10 {
-	phy-handle = <&phy10>;
+	phy12: ethernet-phy@12 {
+		reg = <0>;
+	};
+	phy13: ethernet-phy@13 {
+		reg = <1>;
+	};
+	phy14: ethernet-phy@14 {
+		reg = <2>;
+	};
+	phy15: ethernet-phy@15 {
+		reg = <3>;
+	};
+	phy16: ethernet-phy@16 {
+		reg = <4>;
+	};
+	phy17: ethernet-phy@17 {
+		reg = <5>;
+	};
+	phy18: ethernet-phy@18 {
+		reg = <6>;
+	};
+	phy19: ethernet-phy@19 {
+		reg = <7>;
+	};
+	phy20: ethernet-phy@20 {
+		reg = <8>;
+	};
+	phy21: ethernet-phy@21 {
+		reg = <9>;
+	};
+	phy22: ethernet-phy@22 {
+		reg = <10>;
+	};
+	phy23: ethernet-phy@23 {
+		reg = <11>;
+	};
 };
 
-&port11 {
-	phy-handle = <&phy11>;
+&switch {
+	ethernet-ports {
+		port0: port@0 {
+			reg = <0>;
+			phy-handle = <&phy0>;
+		};
+		port1: port@1 {
+			reg = <1>;
+			phy-handle = <&phy1>;
+		};
+		port2: port@2 {
+			reg = <2>;
+			phy-handle = <&phy2>;
+		};
+		port3: port@3 {
+			reg = <3>;
+			phy-handle = <&phy3>;
+		};
+		port4: port@4 {
+			reg = <4>;
+			phy-handle = <&phy4>;
+		};
+		port5: port@5 {
+			reg = <5>;
+			phy-handle = <&phy5>;
+		};
+		port6: port@6 {
+			reg = <6>;
+			phy-handle = <&phy6>;
+		};
+		port7: port@7 {
+			reg = <7>;
+			phy-handle = <&phy7>;
+		};
+		port8: port@8 {
+			reg = <8>;
+			phy-handle = <&phy8>;
+		};
+		port9: port@9 {
+			reg = <9>;
+			phy-handle = <&phy9>;
+		};
+		port10: port@10 {
+			reg = <10>;
+			phy-handle = <&phy10>;
+		};
+		port11: port@11 {
+			reg = <11>;
+			phy-handle = <&phy11>;
+		};
+		port12: port@12 {
+			reg = <12>;
+			phy-handle = <&phy12>;
+			phys = <&serdes_hsio 12 SERDES6G(1) PHY_MODE_QSGMII>;
+		};
+		port13: port@13 {
+			reg = <13>;
+			phy-handle = <&phy13>;
+			phys = <&serdes_hsio 13 0xff PHY_MODE_QSGMII>;
+		};
+		port14: port@14 {
+			reg = <14>;
+			phy-handle = <&phy14>;
+			phys = <&serdes_hsio 14 0xff PHY_MODE_QSGMII>;
+		};
+		port15: port@15 {
+			reg = <15>;
+			phy-handle = <&phy15>;
+			phys = <&serdes_hsio 15 0xff PHY_MODE_QSGMII>;
+		};
+		port16: port@16 {
+			reg = <16>;
+			phy-handle = <&phy16>;
+			phys = <&serdes_hsio 16 SERDES6G(2) PHY_MODE_QSGMII>;
+		};
+		port17: port@17 {
+			reg = <17>;
+			phy-handle = <&phy17>;
+			phys = <&serdes_hsio 17 0xff PHY_MODE_QSGMII>;
+		};
+		port18: port@18 {
+			reg = <18>;
+			phy-handle = <&phy18>;
+			phys = <&serdes_hsio 18 0xff PHY_MODE_QSGMII>;
+		};
+		port19: port@19 {
+			reg = <19>;
+			phy-handle = <&phy19>;
+			phys = <&serdes_hsio 19 0xff PHY_MODE_QSGMII>;
+		};
+		port20: port@20 {
+			reg = <20>;
+			phy-handle = <&phy20>;
+			phys = <&serdes_hsio 20 SERDES6G(3) PHY_MODE_QSGMII>;
+		};
+		port21: port@21 {
+			reg = <21>;
+			phy-handle = <&phy21>;
+			phys = <&serdes_hsio 21 0xff PHY_MODE_QSGMII>;
+		};
+		port22: port@22 {
+			reg = <22>;
+			phy-handle = <&phy22>;
+			phys = <&serdes_hsio 22 0xff PHY_MODE_QSGMII>;
+		};
+		port23: port@23 {
+			reg = <23>;
+			phy-handle = <&phy23>;
+			phys = <&serdes_hsio 23 0xff PHY_MODE_QSGMII>;
+		};
+	};
 };
diff --git a/arch/mips/dts/luton_pcb091.dts b/arch/mips/dts/luton_pcb091.dts
index f684cc8dd6332eb0c584030342ad04da1fdc932e..cb78c5751bb5bbcc8bc2cd1774e9a3e8d9eea466 100644
--- a/arch/mips/dts/luton_pcb091.dts
+++ b/arch/mips/dts/luton_pcb091.dts
@@ -63,52 +63,94 @@
 
 &mdio0 {
 	status = "okay";
-};
-
-&port0 {
-	phy-handle = <&phy0>;
-};
-
-&port1 {
-	phy-handle = <&phy1>;
-};
-
-&port2 {
-	phy-handle = <&phy2>;
-};
-
-&port3 {
-	phy-handle = <&phy3>;
-};
 
-&port4 {
-	phy-handle = <&phy4>;
-};
-
-&port5 {
-	phy-handle = <&phy5>;
-};
-
-&port6 {
-	phy-handle = <&phy6>;
-};
-
-&port7 {
-	phy-handle = <&phy7>;
-};
-
-&port8 {
-	phy-handle = <&phy8>;
-};
-
-&port9 {
-	phy-handle = <&phy9>;
-};
-
-&port10 {
-	phy-handle = <&phy10>;
+	phy0: ethernet-phy@0 {
+		reg = <0>;
+	};
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+	};
+	phy2: ethernet-phy@2 {
+		reg = <2>;
+	};
+	phy3: ethernet-phy@3 {
+		reg = <3>;
+	};
+	phy4: ethernet-phy@4 {
+		reg = <4>;
+	};
+	phy5: ethernet-phy@5 {
+		reg = <5>;
+	};
+	phy6: ethernet-phy@6 {
+		reg = <6>;
+	};
+	phy7: ethernet-phy@7 {
+		reg = <7>;
+	};
+	phy8: ethernet-phy@8 {
+		reg = <8>;
+	};
+	phy9: ethernet-phy@9 {
+		reg = <9>;
+	};
+	phy10: ethernet-phy@10 {
+		reg = <10>;
+	};
+	phy11: ethernet-phy@11 {
+		reg = <11>;
+	};
 };
 
-&port11 {
-	phy-handle = <&phy11>;
+&switch {
+	ethernet-ports {
+		port0: port@0 {
+			reg = <0>;
+			phy-handle = <&phy0>;
+		};
+		port1: port@1 {
+			reg = <1>;
+			phy-handle = <&phy1>;
+		};
+		port2: port@2 {
+			reg = <2>;
+			phy-handle = <&phy2>;
+		};
+		port3: port@3 {
+			reg = <3>;
+			phy-handle = <&phy3>;
+		};
+		port4: port@4 {
+			reg = <4>;
+			phy-handle = <&phy4>;
+		};
+		port5: port@5 {
+			reg = <5>;
+			phy-handle = <&phy5>;
+		};
+		port6: port@6 {
+			reg = <6>;
+			phy-handle = <&phy6>;
+		};
+		port7: port@7 {
+			reg = <7>;
+			phy-handle = <&phy7>;
+		};
+		port8: port@8 {
+			reg = <8>;
+			phy-handle = <&phy8>;
+		};
+		port9: port@9 {
+			reg = <9>;
+			phy-handle = <&phy9>;
+		};
+		port10: port@10 {
+			reg = <10>;
+			phy-handle = <&phy10>;
+		};
+		port11: port@11 {
+			reg = <11>;
+			phy-handle = <&phy11>;
+		};
+	};
 };
diff --git a/arch/mips/dts/mscc,luton.dtsi b/arch/mips/dts/mscc,luton.dtsi
index de354fe2ce26173903fff8c844937d4febadc2cb..c8231018f1029e9bc415f751505fa7053858d687 100644
--- a/arch/mips/dts/mscc,luton.dtsi
+++ b/arch/mips/dts/mscc,luton.dtsi
@@ -124,7 +124,7 @@
 			      <0x030000 0x1000>, // VTSS_TO_REW
 			      <0x070000 0x1000>, // VTSS_TO_DEVCPU_GCB
 			      <0x080000 0x0100>, // VTSS_TO_DEVCPU_QS
-			      <0x0a0000 0x0100>; // VTSS_TO_HSIO
+			      <0x0a0000 0x10000>; // VTSS_TO_HSIO
 			reg-names = "port0", "port1", "port2", "port3",
 				    "port4", "port5", "port6", "port7",
 				    "port8", "port9", "port10", "port11",
@@ -137,79 +137,6 @@
 			ethernet-ports {
 				#address-cells = <1>;
 				#size-cells = <0>;
-
-				port0: port@0 {
-					reg = <0>;
-				};
-				port1: port@1 {
-					reg = <1>;
-				};
-				port2: port@2 {
-					reg = <2>;
-				};
-				port3: port@3 {
-					reg = <3>;
-				};
-				port4: port@4 {
-					reg = <4>;
-				};
-				port5: port@5 {
-					reg = <5>;
-				};
-				port6: port@6 {
-					reg = <6>;
-				};
-				port7: port@7 {
-					reg = <7>;
-				};
-				port8: port@8 {
-					reg = <8>;
-				};
-				port9: port@9 {
-					reg = <9>;
-				};
-				port10: port@10 {
-					reg = <10>;
-				};
-				port11: port@11 {
-					reg = <11>;
-				};
-				port12: port@12 {
-					reg = <12>;
-				};
-				port13: port@13 {
-					reg = <13>;
-				};
-				port14: port@14 {
-					reg = <14>;
-				};
-				port15: port@15 {
-					reg = <15>;
-				};
-				port16: port@16 {
-					reg = <16>;
-				};
-				port17: port@17 {
-					reg = <17>;
-				};
-				port18: port@18 {
-					reg = <18>;
-				};
-				port19: port@19 {
-					reg = <19>;
-				};
-				port20: port@20 {
-					reg = <20>;
-				};
-				port21: port@21 {
-					reg = <21>;
-				};
-				port22: port@22 {
-					reg = <22>;
-				};
-				port23: port@23 {
-					reg = <23>;
-				};
 			};
 		};
 
@@ -219,42 +146,23 @@
 			compatible = "mscc,luton-miim";
 			reg = <0x700a0 0x24>;
 			status = "disabled";
+		};
 
-			phy0: ethernet-phy@0 {
-				reg = <0>;
-			};
-			phy1: ethernet-phy@1 {
-				reg = <1>;
-			};
-			phy2: ethernet-phy@2 {
-				reg = <2>;
-			};
-			phy3: ethernet-phy@3 {
-				reg = <3>;
-			};
-			phy4: ethernet-phy@4 {
-				reg = <4>;
-			};
-			phy5: ethernet-phy@5 {
-				reg = <5>;
-			};
-			phy6: ethernet-phy@6 {
-				reg = <6>;
-			};
-			phy7: ethernet-phy@7 {
-				reg = <7>;
-			};
-			phy8: ethernet-phy@8 {
-				reg = <8>;
-			};
-			phy9: ethernet-phy@9 {
-				reg = <9>;
-			};
-			phy10: ethernet-phy@10 {
-				reg = <10>;
-			};
-			phy11: ethernet-phy@11 {
-				reg = <11>;
+		mdio1: mdio@700c4 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "mscc,luton-miim";
+			reg = <0x700c4 0x24>;
+			status = "disabled";
+		};
+
+		hsio: syscon@10d0000 {
+			compatible = "mscc,luton-hsio", "syscon", "simple-mfd";
+			reg = <0xa0000 0x10000>;
+
+			serdes_hsio: serdes_hsio {
+				compatible = "mscc,vsc7527-serdes";
+				#phy-cells = <3>;
 			};
 		};
 	};
diff --git a/arch/mips/dts/mscc,ocelot.dtsi b/arch/mips/dts/mscc,ocelot.dtsi
index 4f3fe356c45654fd9cda9fd5f8cc882649e44bd7..9a187b6e5880a9975010d19cefc1c8a42a768449 100644
--- a/arch/mips/dts/mscc,ocelot.dtsi
+++ b/arch/mips/dts/mscc,ocelot.dtsi
@@ -112,32 +112,33 @@
 			status = "disabled";
 		};
 
-		switch@1010000 {
+		switch: switch@1010000 {
 			pinctrl-0 = <&miim1_pins>;
 			pinctrl-names = "default";
 
 			compatible = "mscc,vsc7514-switch";
-			reg = <0x1010000 0x10000>, /* VTSS_TO_SYS */
-			      <0x1030000 0x10000>, /* VTSS_TO_REW */
-			      <0x1080000 0x100>, /* VTSS_TO_DEVCPU_QS */
-			      <0x10d0000 0x10000>, /* VTSS_TO_HSIO */
-			      <0x11e0000 0x100>, /* VTSS_TO_DEV_0 */
-			      <0x11f0000 0x100>, /* VTSS_TO_DEV_1 */
-			      <0x1200000 0x100>, /* VTSS_TO_DEV_2 */
-			      <0x1210000 0x100>, /* VTSS_TO_DEV_3 */
-			      <0x1220000 0x100>, /* VTSS_TO_DEV_4 */
-			      <0x1230000 0x100>, /* VTSS_TO_DEV_5 */
-			      <0x1240000 0x100>, /* VTSS_TO_DEV_6 */
-			      <0x1250000 0x100>, /* VTSS_TO_DEV_7 */
-			      <0x1260000 0x100>, /* VTSS_TO_DEV_8 */
-			      <0x1270000 0x100>, /* NA */
-			      <0x1280000 0x100>, /* NA */
-			      <0x1800000 0x80000>, /* VTSS_TO_QSYS */
-			      <0x1880000 0x10000>; /* VTSS_TO_ANA */
-			reg-names = "sys", "rew", "qs", "hsio", "port0",
-				    "port1", "port2", "port3", "port4", "port5",
-				    "port6", "port7", "port8", "port9",
-				    "port10", "qsys", "ana";
+
+			reg = <0x11e0000 0x100>, // VTSS_TO_DEV_0
+			      <0x11f0000 0x100>, // VTSS_TO_DEV_1
+			      <0x1200000 0x100>, // VTSS_TO_DEV_2
+			      <0x1210000 0x100>, // VTSS_TO_DEV_3
+			      <0x1220000 0x100>, // VTSS_TO_DEV_4
+			      <0x1230000 0x100>, // VTSS_TO_DEV_5
+			      <0x1240000 0x100>, // VTSS_TO_DEV_6
+			      <0x1250000 0x100>, // VTSS_TO_DEV_7
+			      <0x1260000 0x100>, // VTSS_TO_DEV_8
+			      <0x1270000 0x100>, // VTSS_TO_DEV_9
+			      <0x1280000 0x100>, // VTSS_TO_DEV_10
+			      <0x1010000 0x10000>, // VTSS_TO_SYS
+			      <0x1030000 0x10000>, // VTSS_TO_REW
+			      <0x1080000 0x100>, // VTSS_TO_DEVCPU_QS
+			      <0x10d0000 0x10000>, // VTSS_TO_HSIO
+			      <0x1800000 0x80000>,// VTSS_TO_QSYS
+			      <0x1880000 0x10000>;// VTSS_TO_ANA
+			reg-names = "port0", "port1", "port2", "port3", "port4",
+				    "port5", "port6", "port7", "port8", "port9",
+				    "port10",
+				    "sys", "rew", "qs", "hsio", "qsys", "ana";
 			interrupts = <21 22>;
 			interrupt-names = "xtr", "inj";
 			status = "okay";
@@ -145,40 +146,6 @@
 			ethernet-ports {
 				#address-cells = <1>;
 				#size-cells = <0>;
-
-				port0: port@0 {
-					reg = <0>;
-				};
-				port1: port@1 {
-					reg = <1>;
-				};
-				port2: port@2 {
-					reg = <2>;
-				};
-				port3: port@3 {
-					reg = <3>;
-				};
-				port4: port@4 {
-					reg = <4>;
-				};
-				port5: port@5 {
-					reg = <5>;
-				};
-				port6: port@6 {
-					reg = <6>;
-				};
-				port7: port@7 {
-					reg = <7>;
-				};
-				port8: port@8 {
-					reg = <8>;
-				};
-				port9: port@9 {
-					reg = <9>;
-				};
-				port10: port@10 {
-					reg = <10>;
-				};
 			};
 		};
 
@@ -186,21 +153,27 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			compatible = "mscc,ocelot-miim";
-			reg = <0x107009c 0x24>, <0x10700f0 0x8>;
+			reg = <0x107009c 0x24>;
 			interrupts = <14>;
 			status = "disabled";
+		};
 
-			phy0: ethernet-phy@0 {
-				reg = <0>;
-			};
-			phy1: ethernet-phy@1 {
-				reg = <1>;
-			};
-			phy2: ethernet-phy@2 {
-				reg = <2>;
-			};
-			phy3: ethernet-phy@3 {
-				reg = <3>;
+		mdio1: mdio@10700f0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "mscc,ocelot-miim";
+			reg = <0x10700c0 0x24>;
+			interrupts = <14>;
+			status = "disabled";
+		};
+
+		hsio: syscon@10d0000 {
+			compatible = "mscc,ocelot-hsio", "syscon", "simple-mfd";
+			reg = <0x10d0000 0x10000>;
+
+			serdes_hsio: serdes_hsio {
+				compatible = "mscc,vsc7514-serdes";
+				#phy-cells = <3>;
 			};
 		};
 
diff --git a/arch/mips/dts/mscc,serval.dtsi b/arch/mips/dts/mscc,serval.dtsi
index bd60051719bde65271ee2dee86ecd4b75a61e2f4..90eeebd3a4ea8586820c63ead8a9feaf3dac74be 100644
--- a/arch/mips/dts/mscc,serval.dtsi
+++ b/arch/mips/dts/mscc,serval.dtsi
@@ -145,5 +145,63 @@
 			#gpio-cells = <2>;
 			gpio-ranges = <&sgpio 0 0 64>;
 		};
+
+		switch: switch@011e0000 {
+			compatible = "mscc,vsc7418-switch";
+			reg = <0x011e0000 0x0100>,   // VTSS_TO_DEV0
+			      <0x011f0000 0x0100>,   // VTSS_TO_DEV1
+			      <0x01200000 0x0100>,   // VTSS_TO_DEV2
+			      <0x01210000 0x0100>,   // VTSS_TO_DEV3
+			      <0x01220000 0x0100>,   // VTSS_TO_DEV4
+			      <0x01230000 0x0100>,   // VTSS_TO_DEV5
+			      <0x01240000 0x0100>,   // VTSS_TO_DEV6
+			      <0x01250000 0x0100>,   // VTSS_TO_DEV7
+			      <0x01260000 0x0100>,   // VTSS_TO_DEV8
+			      <0x01270000 0x0100>,   // VTSS_TO_DEV9
+			      <0x01280000 0x0100>,   // VTSS_TO_DEV10
+			      <0x01900000 0x100000>, // ANA
+			      <0x01080000 0x20000>,  // QS
+			      <0x01800000 0x100000>, // QSYS
+			      <0x01030000 0x10000>,  // REW
+			      <0x01010000 0x20000>,  // SYS
+			      <0x010a0000 0x10000>;  // HSIO
+			reg-names = "port0", "port1", "port2", "port3",
+				    "port4", "port5", "port6", "port7",
+				    "port8", "port9", "port10",
+				    "ana", "qs", "qsys", "rew", "sys",
+				    "hsio";
+			status = "okay";
+
+			ethernet-ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
+		mdio0: mdio@0107005c {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "mscc,serval-miim";
+			reg = <0x0107005c 0x24>;
+			status = "disabled";
+		};
+
+		mdio1: mdio@01070080 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "mscc,serval-miim";
+			reg = <0x01070080 0x24>;
+			status = "disabled";
+		};
+
+		hsio: syscon@10d0000 {
+			compatible = "mscc,serval-hsio", "syscon", "simple-mfd";
+			reg = <0x10a0000 0x10000>;
+
+			serdes_hsio: serdes_hsio {
+				compatible = "mscc,vsc7418-serdes";
+				#phy-cells = <3>;
+			};
+		};
 	};
 };
diff --git a/arch/mips/dts/ocelot_pcb120.dts b/arch/mips/dts/ocelot_pcb120.dts
index 658719e684f84e3fc4376107401fa546dfcb989e..e608029a3f8217248763c622ed8afe14adda18ce 100644
--- a/arch/mips/dts/ocelot_pcb120.dts
+++ b/arch/mips/dts/ocelot_pcb120.dts
@@ -5,6 +5,7 @@
 
 /dts-v1/;
 #include "mscc,ocelot_pcb.dtsi"
+#include <dt-bindings/mscc/ocelot_data.h>
 
 / {
 	model = "Ocelot PCB120 Reference Board";
@@ -86,3 +87,77 @@
 	mscc,sgpio-ports = <0x000FFFFF>;
 };
 
+&mdio0 {
+	status = "okay";
+
+	phy4: ethernet-phy@4 {
+		reg = <3>;
+	};
+	phy5: ethernet-phy@5 {
+		reg = <2>;
+	};
+	phy6: ethernet-phy@6 {
+		reg = <1>;
+	};
+	phy7: ethernet-phy@7 {
+		reg = <0>;
+	};
+};
+
+&mdio1 {
+	status = "okay";
+
+	phy0: ethernet-phy@0 {
+		reg = <3>;
+	};
+	phy1: ethernet-phy@1 {
+		reg = <2>;
+	};
+	phy2: ethernet-phy@2 {
+		reg = <1>;
+	};
+	phy3: ethernet-phy@3 {
+		reg = <0>;
+	};
+};
+
+&switch {
+	ethernet-ports {
+		port0: port@0 {
+			reg = <5>;
+			phy-handle = <&phy0>;
+			phys = <&serdes_hsio 5 SERDES1G(2) PHY_MODE_SGMII>;
+		};
+		port1: port@1 {
+			reg = <9>;
+			phy-handle = <&phy1>;
+			phys = <&serdes_hsio 9 SERDES1G(3) PHY_MODE_SGMII>;
+		};
+		port2: port@2 {
+			reg = <6>;
+			phy-handle = <&phy2>;
+			phys = <&serdes_hsio 6 SERDES1G(4) PHY_MODE_SGMII>;
+		};
+		port3: port@3 {
+			reg = <4>;
+			phy-handle = <&phy3>;
+			phys = <&serdes_hsio 4 SERDES1G(5) PHY_MODE_SGMII>;
+		};
+		port4: port@4 {
+			reg = <3>;
+			phy-handle = <&phy4>;
+		};
+		port5: port@5 {
+			reg = <2>;
+			phy-handle = <&phy5>;
+		};
+		port6: port@6 {
+			reg = <1>;
+			phy-handle = <&phy6>;
+		};
+		port7: port@7 {
+			reg = <0>;
+			phy-handle = <&phy7>;
+		};
+	};
+};
diff --git a/arch/mips/dts/ocelot_pcb123.dts b/arch/mips/dts/ocelot_pcb123.dts
index a4fa37001f2400cc36c8262ab0992aae1bc9f849..1b0156e503c943801783129aeee4f48a7dd6b949 100644
--- a/arch/mips/dts/ocelot_pcb123.dts
+++ b/arch/mips/dts/ocelot_pcb123.dts
@@ -38,20 +38,38 @@
 
 &mdio0 {
 	status = "okay";
-};
-
-&port0 {
-	phy-handle = <&phy0>;
-};
 
-&port1 {
-	phy-handle = <&phy1>;
-};
-
-&port2 {
-	phy-handle = <&phy2>;
+	phy0: ethernet-phy@0 {
+		reg = <0>;
+	};
+	phy1: ethernet-phy@1 {
+		reg = <1>;
+	};
+	phy2: ethernet-phy@2 {
+		reg = <2>;
+	};
+	phy3: ethernet-phy@3 {
+		reg = <3>;
+	};
 };
 
-&port3 {
-	phy-handle = <&phy3>;
+&switch {
+	ethernet-ports {
+		port0: port@0 {
+			reg = <2>;
+			phy-handle = <&phy2>;
+		};
+		port1: port@1 {
+			reg = <3>;
+			phy-handle = <&phy3>;
+		};
+		port2: port@2 {
+			reg = <0>;
+			phy-handle = <&phy0>;
+		};
+		port3: port@3 {
+			reg = <1>;
+			phy-handle = <&phy1>;
+		};
+	};
 };
diff --git a/arch/mips/dts/serval_pcb105.dts b/arch/mips/dts/serval_pcb105.dts
index 1598669447fdd0a9cbe04674ac3fea3762122cdf..667277080f2da5ad1d1643829bcd698506f625c1 100644
--- a/arch/mips/dts/serval_pcb105.dts
+++ b/arch/mips/dts/serval_pcb105.dts
@@ -5,6 +5,7 @@
 
 /dts-v1/;
 #include "mscc,serval.dtsi"
+#include <dt-bindings/mscc/serval_data.h>
 
 / {
 	model = "Serval PCB105 Reference Board";
@@ -54,3 +55,46 @@
 	status = "okay";
 	sgpio-ports = <0x00FFFFFF>;
 };
+
+&mdio1 {
+	status = "okay";
+
+	phy16: ethernet-phy@16 {
+		reg = <16>;
+	};
+	phy17: ethernet-phy@17 {
+		reg = <17>;
+	};
+	phy18: ethernet-phy@18 {
+		reg = <18>;
+	};
+	phy19: ethernet-phy@19 {
+		reg = <19>;
+	};
+};
+
+&switch {
+	ethernet-ports {
+
+		port0: port@0 {
+			reg = <7>;
+			phy-handle = <&phy16>;
+			phys = <&serdes_hsio 7 SERDES1G(7) PHY_MODE_SGMII>;
+		};
+		port1: port@1 {
+			reg = <6>;
+			phy-handle = <&phy17>;
+			phys = <&serdes_hsio 6 SERDES1G(6) PHY_MODE_SGMII>;
+		};
+		port2: port@2 {
+			reg = <5>;
+			phy-handle = <&phy18>;
+			phys = <&serdes_hsio 5 SERDES1G(5) PHY_MODE_SGMII>;
+		};
+		port3: port@3 {
+			reg = <4>;
+			phy-handle = <&phy19>;
+			phys = <&serdes_hsio 4 SERDES1G(4) PHY_MODE_SGMII>;
+		};
+	};
+};
diff --git a/arch/mips/dts/serval_pcb106.dts b/arch/mips/dts/serval_pcb106.dts
index fb3524bb31e0cab2aab8ea9a028ab34acc38bd04..e77c357868b82348a8938bba94d162cf9d7b13a3 100644
--- a/arch/mips/dts/serval_pcb106.dts
+++ b/arch/mips/dts/serval_pcb106.dts
@@ -5,6 +5,7 @@
 
 /dts-v1/;
 #include "mscc,serval.dtsi"
+#include <dt-bindings/mscc/serval_data.h>
 
 / {
 	model = "Serval PCB106 Reference Board";
@@ -54,3 +55,46 @@
 	status = "okay";
 	sgpio-ports = <0x00FFFFFF>;
 };
+
+&mdio1 {
+	status = "okay";
+
+	phy16: ethernet-phy@16 {
+		reg = <16>;
+	};
+	phy17: ethernet-phy@17 {
+		reg = <17>;
+	};
+	phy18: ethernet-phy@18 {
+		reg = <18>;
+	};
+	phy19: ethernet-phy@19 {
+		reg = <19>;
+	};
+};
+
+&switch {
+	ethernet-ports {
+
+		port0: port@0 {
+			reg = <7>;
+			phy-handle = <&phy16>;
+			phys = <&serdes_hsio 7 SERDES1G(7) PHY_MODE_SGMII>;
+		};
+		port1: port@1 {
+			reg = <6>;
+			phy-handle = <&phy17>;
+			phys = <&serdes_hsio 6 SERDES1G(6) PHY_MODE_SGMII>;
+		};
+		port2: port@2 {
+			reg = <5>;
+			phy-handle = <&phy18>;
+			phys = <&serdes_hsio 5 SERDES1G(5) PHY_MODE_SGMII>;
+		};
+		port3: port@3 {
+			reg = <4>;
+			phy-handle = <&phy19>;
+			phys = <&serdes_hsio 4 SERDES1G(4) PHY_MODE_SGMII>;
+		};
+	};
+};
diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c
index 35152cb3f64afe122c1defb58b40fa006fe38d8a..6a462f3e5a5edf45ecb9f704d85d5bae6897a80a 100644
--- a/arch/mips/lib/bootm.c
+++ b/arch/mips/lib/bootm.c
@@ -247,6 +247,8 @@ int arch_fixup_fdt(void *blob)
 
 static int boot_setup_fdt(bootm_headers_t *images)
 {
+	images->initrd_start = virt_to_phys((void *)images->initrd_start);
+	images->initrd_end = virt_to_phys((void *)images->initrd_end);
 	return image_setup_libfdt(images, images->ft_addr, images->ft_len,
 		&images->lmb);
 }
diff --git a/arch/mips/mach-mscc/Kconfig b/arch/mips/mach-mscc/Kconfig
index 34584a1909905365ed82f9b43b320c336008d423..affc4721f82ea8379f1eb43022d5a091017e52d9 100644
--- a/arch/mips/mach-mscc/Kconfig
+++ b/arch/mips/mach-mscc/Kconfig
@@ -29,7 +29,6 @@ config SOC_OCELOT
 config SOC_LUTON
 	bool "Luton SOC Family"
 	select SOC_VCOREIII
-	select MSCC_BITBANG_SPI_GPIO
 	help
 	  This supports MSCC Luton family of SOCs.
 
diff --git a/arch/mips/mach-mscc/include/mach/ddr.h b/arch/mips/mach-mscc/include/mach/ddr.h
index 84ecfbdd9206da3766dd645a466a95bb17ff66ba..d1f4287f654661727bba043984843c5c697002f8 100644
--- a/arch/mips/mach-mscc/include/mach/ddr.h
+++ b/arch/mips/mach-mscc/include/mach/ddr.h
@@ -401,23 +401,7 @@ static inline void sleep_100ns(u32 val)
 		;
 }
 
-#if defined(CONFIG_SOC_OCELOT)
-static inline void hal_vcoreiii_ddr_reset_assert(void)
-{
-	/* DDR has reset pin on GPIO 19 toggle Low-High to release */
-	setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
-	writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_CLR);
-	sleep_100ns(10000);
-}
-
-static inline void hal_vcoreiii_ddr_reset_release(void)
-{
-	/* DDR has reset pin on GPIO 19 toggle Low-High to release */
-	setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
-	writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_SET);
-	sleep_100ns(10000);
-}
-
+#if defined(CONFIG_SOC_OCELOT) || defined(CONFIG_SOC_SERVAL)
 /*
  * DDR memory sanity checking failed, tally and do hard reset
  *
@@ -427,9 +411,11 @@ static inline void hal_vcoreiii_ddr_failed(void)
 {
 	register u32 reset;
 
+#if defined(CONFIG_SOC_OCELOT)
 	writel(readl(BASE_CFG + ICPU_GPR(6)) + 1, BASE_CFG + ICPU_GPR(6));
 
 	clrbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
+#endif
 
 	/* We have to execute the reset function from cache. Indeed,
 	 * the reboot workaround in _machine_restart() will change the
@@ -452,6 +438,33 @@ static inline void hal_vcoreiii_ddr_failed(void)
 
 	panic("DDR init failed\n");
 }
+#else				/* JR2 || ServalT */
+static inline void hal_vcoreiii_ddr_failed(void)
+{
+	writel(0, BASE_CFG + ICPU_RESET);
+	writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_CFG + PERF_SOFT_RST);
+
+	panic("DDR init failed\n");
+}
+#endif
+
+#if defined(CONFIG_SOC_OCELOT)
+static inline void hal_vcoreiii_ddr_reset_assert(void)
+{
+	/* DDR has reset pin on GPIO 19 toggle Low-High to release */
+	setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
+	writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_CLR);
+	sleep_100ns(10000);
+}
+
+static inline void hal_vcoreiii_ddr_reset_release(void)
+{
+	/* DDR has reset pin on GPIO 19 toggle Low-High to release */
+	setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
+	writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_SET);
+	sleep_100ns(10000);
+}
+
 #else				/* JR2 || ServalT || Serval */
 static inline void hal_vcoreiii_ddr_reset_assert(void)
 {
@@ -463,14 +476,6 @@ static inline void hal_vcoreiii_ddr_reset_assert(void)
 	writel(readl(BASE_CFG + ICPU_RESET) |
 	       ICPU_RESET_MEM_RST_FORCE, BASE_CFG + ICPU_RESET);
 }
-
-static inline void hal_vcoreiii_ddr_failed(void)
-{
-	writel(0, BASE_CFG + ICPU_RESET);
-	writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_CFG + PERF_SOFT_RST);
-
-	panic("DDR init failed\n");
-}
 #endif				/* JR2 || ServalT || Serval */
 
 /*
diff --git a/arch/mips/mach-mscc/include/mach/ocelot/ocelot_devcpu_gcb.h b/arch/mips/mach-mscc/include/mach/ocelot/ocelot_devcpu_gcb.h
index d3a76412e2e66c5b894abb7768651d5cc3f95722..b2a4203644aa7c8c88ee44f4ef6c388750c3686b 100644
--- a/arch/mips/mach-mscc/include/mach/ocelot/ocelot_devcpu_gcb.h
+++ b/arch/mips/mach-mscc/include/mach/ocelot/ocelot_devcpu_gcb.h
@@ -20,4 +20,5 @@
 
 #define GPIO_ALT(x)				(0x54 + 4 * (x))
 
+#define PERF_PHY_CFG                                      0xf0
 #endif
diff --git a/arch/mips/mach-mscc/reset.c b/arch/mips/mach-mscc/reset.c
index a555fc9d9a9ffd3647b1c6ab149fb78feded17b1..a1214573b51aa5d1d0bff5c1194f37cf3ab39a6e 100644
--- a/arch/mips/mach-mscc/reset.c
+++ b/arch/mips/mach-mscc/reset.c
@@ -36,7 +36,7 @@ void _machine_restart(void)
 	/* Do global reset */
 	writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST);
 
-	for (i = 0; i < 1000; i++)
+	for (i = 0; i < 2000; i++)
 		;
 
 	/* Power down DDR for clean DDR re-training */
diff --git a/arch/mips/mach-mt7620/Kconfig b/arch/mips/mach-mtmips/Kconfig
similarity index 93%
rename from arch/mips/mach-mt7620/Kconfig
rename to arch/mips/mach-mtmips/Kconfig
index a9834439993de448bd132a8edade956fe0ea9885..4af2d545288aed64da2ef0f0d3d403e52e479eab 100644
--- a/arch/mips/mach-mt7620/Kconfig
+++ b/arch/mips/mach-mtmips/Kconfig
@@ -1,20 +1,20 @@
 menu "MediaTek MIPS platforms"
-	depends on ARCH_MT7620
+	depends on ARCH_MTMIPS
 
 config SYS_MALLOC_F_LEN
 	default 0x1000
 
 config SYS_SOC
-	default "mt7620" if SOC_MT7620
+	default "mt7628" if SOC_MT7628
 
 choice
 	prompt "MediaTek MIPS SoC select"
 
-config SOC_MT7620
-	bool "MT7620/8"
+config SOC_MT7628
+	bool "MT7628"
 	select MIPS_L1_CACHE_SHIFT_5
 	help
-	  This supports MediaTek MIPS MT7620 family.
+	  This supports MediaTek MT7628/MT7688.
 
 endchoice
 
@@ -23,7 +23,7 @@ choice
 
 config BOARD_GARDENA_SMART_GATEWAY_MT7688
 	bool "GARDENA smart Gateway"
-	depends on SOC_MT7620
+	depends on SOC_MT7628
 	select BOARD_LATE_INIT
 	select SUPPORTS_BOOT_RAM
 	help
@@ -32,7 +32,7 @@ config BOARD_GARDENA_SMART_GATEWAY_MT7688
 
 config BOARD_LINKIT_SMART_7688
 	bool "LinkIt Smart 7688"
-	depends on SOC_MT7620
+	depends on SOC_MT7628
 	select SUPPORTS_BOOT_RAM
 	help
 	  Seeed LinkIt Smart 7688 boards have a MT7688 SoC with 128 MiB of RAM
diff --git a/arch/mips/mach-mt7620/Makefile b/arch/mips/mach-mtmips/Makefile
similarity index 100%
rename from arch/mips/mach-mt7620/Makefile
rename to arch/mips/mach-mtmips/Makefile
diff --git a/arch/mips/mach-mt7620/cpu.c b/arch/mips/mach-mtmips/cpu.c
similarity index 100%
rename from arch/mips/mach-mt7620/cpu.c
rename to arch/mips/mach-mtmips/cpu.c
diff --git a/arch/mips/mach-mt7620/ddr_calibrate.c b/arch/mips/mach-mtmips/ddr_calibrate.c
similarity index 100%
rename from arch/mips/mach-mt7620/ddr_calibrate.c
rename to arch/mips/mach-mtmips/ddr_calibrate.c
diff --git a/arch/mips/mach-mt7620/lowlevel_init.S b/arch/mips/mach-mtmips/lowlevel_init.S
similarity index 100%
rename from arch/mips/mach-mt7620/lowlevel_init.S
rename to arch/mips/mach-mtmips/lowlevel_init.S
diff --git a/arch/mips/mach-mt7620/mt76xx.h b/arch/mips/mach-mtmips/mt76xx.h
similarity index 100%
rename from arch/mips/mach-mt7620/mt76xx.h
rename to arch/mips/mach-mtmips/mt76xx.h
diff --git a/board/mscc/luton/luton.c b/board/mscc/luton/luton.c
index 807c717e33a470ba5d55f11123ceae5682ce03cf..114f7fd9d9b25a4df1206630195f9fed8dd277e4 100644
--- a/board/mscc/luton/luton.c
+++ b/board/mscc/luton/luton.c
@@ -6,8 +6,7 @@
 #include <common.h>
 #include <asm/io.h>
 #include <led.h>
-
-DECLARE_GLOBAL_DATA_PTR;
+#include <miiphy.h>
 
 enum {
 	BOARD_TYPE_PCB090 = 0xAABBCD00,
@@ -36,6 +35,16 @@ int board_early_init_r(void)
 	return 0;
 }
 
+int board_phy_config(struct phy_device *phydev)
+{
+	phy_write(phydev, 0, 31, 0x10);
+	phy_write(phydev, 0, 18, 0x80A0);
+	while (phy_read(phydev, 0, 18) & 0x8000)
+		;
+	phy_write(phydev, 0, 31, 0);
+	return 0;
+}
+
 static void do_board_detect(void)
 {
 	u32 chipid = (readl(BASE_DEVCPU_GCB + CHIP_ID) >> 12) & 0xFFFF;
diff --git a/board/mscc/ocelot/ocelot.c b/board/mscc/ocelot/ocelot.c
index 532d06f00031fc15177d12db4305b3bb91f7639e..bcae8fa50ca2b5bce19621af0e6fc095230a38d0 100644
--- a/board/mscc/ocelot/ocelot.c
+++ b/board/mscc/ocelot/ocelot.c
@@ -11,6 +11,7 @@
 #include <spi.h>
 #include <led.h>
 #include <wait_bit.h>
+#include <miiphy.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -42,6 +43,20 @@ void mscc_switch_reset(bool enter)
 	mscc_gpio_set_alternate(19, 0);
 }
 
+int board_phy_config(struct phy_device *phydev)
+{
+	if (gd->board_type == BOARD_TYPE_PCB123)
+		return 0;
+
+	phy_write(phydev, 0, 31, 0x10);
+	phy_write(phydev, 0, 18, 0x80F0);
+	while (phy_read(phydev, 0, 18) & 0x8000)
+		;
+	phy_write(phydev, 0, 31, 0);
+
+	return 0;
+}
+
 void board_debug_uart_init(void)
 {
 	/* too early for the pinctrl driver, so configure the UART pins here */
diff --git a/board/mscc/serval/serval.c b/board/mscc/serval/serval.c
index 24ee5e528d9f9de85da837ba799e6e3cc552b168..da7f55620debec24178a77bd12829cdfb9af01cc 100644
--- a/board/mscc/serval/serval.c
+++ b/board/mscc/serval/serval.c
@@ -6,6 +6,7 @@
 #include <common.h>
 #include <asm/io.h>
 #include <led.h>
+#include <miiphy.h>
 
 enum {
 	BOARD_TYPE_PCB106 = 0xAABBCD00,
@@ -27,6 +28,17 @@ int board_early_init_r(void)
 	return 0;
 }
 
+int board_phy_config(struct phy_device *phydev)
+{
+	phy_write(phydev, 0, 31, 0x10);
+	phy_write(phydev, 0, 18, 0x80F0);
+	while (phy_read(phydev, 0, 18) & 0x8000)
+		;
+	phy_write(phydev, 0, 14, 0x800);
+	phy_write(phydev, 0, 31, 0);
+	return 0;
+}
+
 static void do_board_detect(void)
 {
 	u16 gpio_in_reg;
@@ -42,10 +54,10 @@ static void do_board_detect(void)
 			gd->board_type = BOARD_TYPE_PCB106;
 		else
 			gd->board_type = BOARD_TYPE_PCB105;
-		mscc_phy_wr(1, 16, 15, 0);
 	} else {
 		gd->board_type = BOARD_TYPE_PCB105;
 	}
+	mscc_phy_wr(1, 16, 31, 0x0);
 }
 
 #if defined(CONFIG_MULTI_DTB_FIT)
diff --git a/configs/gardena-smart-gateway-mt7688-ram_defconfig b/configs/gardena-smart-gateway-mt7688-ram_defconfig
index 7c8ae0f6474e4c3458ae4f7e0f17371f2ce10748..e09950637ff9ee38e587656840415da1e0a7b872 100644
--- a/configs/gardena-smart-gateway-mt7688-ram_defconfig
+++ b/configs/gardena-smart-gateway-mt7688-ram_defconfig
@@ -1,7 +1,7 @@
 CONFIG_MIPS=y
 CONFIG_SYS_TEXT_BASE=0x80010000
 CONFIG_NR_DRAM_BANKS=1
-CONFIG_ARCH_MT7620=y
+CONFIG_ARCH_MTMIPS=y
 # CONFIG_MIPS_BOOT_ENV_LEGACY is not set
 CONFIG_MIPS_BOOT_FDT=y
 CONFIG_ENV_VARS_UBOOT_CONFIG=y
diff --git a/configs/gardena-smart-gateway-mt7688_defconfig b/configs/gardena-smart-gateway-mt7688_defconfig
index 8fd676025aadc03341d0c42030f5293184b3895b..ad0db2e7235d122214309aeef0fc7f0f726afded 100644
--- a/configs/gardena-smart-gateway-mt7688_defconfig
+++ b/configs/gardena-smart-gateway-mt7688_defconfig
@@ -1,7 +1,7 @@
 CONFIG_MIPS=y
 CONFIG_SYS_TEXT_BASE=0x9c000000
 CONFIG_NR_DRAM_BANKS=1
-CONFIG_ARCH_MT7620=y
+CONFIG_ARCH_MTMIPS=y
 CONFIG_BOOT_ROM=y
 CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y
 CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y
diff --git a/configs/linkit-smart-7688-ram_defconfig b/configs/linkit-smart-7688-ram_defconfig
index 6e9aa7adefcd19d8b0ec6bdc9dd98853612f03c9..c2502b27139dacf05acbe3cde97e6b77052d76c5 100644
--- a/configs/linkit-smart-7688-ram_defconfig
+++ b/configs/linkit-smart-7688-ram_defconfig
@@ -1,7 +1,7 @@
 CONFIG_MIPS=y
 CONFIG_SYS_TEXT_BASE=0x80010000
 CONFIG_NR_DRAM_BANKS=1
-CONFIG_ARCH_MT7620=y
+CONFIG_ARCH_MTMIPS=y
 CONFIG_BOARD_LINKIT_SMART_7688=y
 # CONFIG_MIPS_BOOT_ENV_LEGACY is not set
 CONFIG_MIPS_BOOT_FDT=y
diff --git a/configs/linkit-smart-7688_defconfig b/configs/linkit-smart-7688_defconfig
index 5660f41e8e348488ef345c786873bcc85c2b6ec9..fba1bfd653cbdbb361032d7a670c1269baf4dd22 100644
--- a/configs/linkit-smart-7688_defconfig
+++ b/configs/linkit-smart-7688_defconfig
@@ -1,7 +1,7 @@
 CONFIG_MIPS=y
 CONFIG_SYS_TEXT_BASE=0x9c000000
 CONFIG_NR_DRAM_BANKS=1
-CONFIG_ARCH_MT7620=y
+CONFIG_ARCH_MTMIPS=y
 CONFIG_BOARD_LINKIT_SMART_7688=y
 CONFIG_BOOT_ROM=y
 CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y
diff --git a/configs/mscc_serval_defconfig b/configs/mscc_serval_defconfig
index 146188bb0c90f73af7188e573681e3b1573165cf..753a11aa122bd38514775e7ea42fbfd14479378a 100644
--- a/configs/mscc_serval_defconfig
+++ b/configs/mscc_serval_defconfig
@@ -25,7 +25,6 @@ CONFIG_CMD_MEMTEST=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
-# CONFIG_CMD_NFS is not set
 CONFIG_CMD_MTDPARTS=y
 CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
 CONFIG_MTDPARTS_DEFAULT="mtdparts=spi_flash:1m(UBoot),256k(Env),256k(Env.bk)"
@@ -58,3 +57,8 @@ CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_LZMA=y
+CONFIG_CMD_DHCP=y
+# CONFIG_NET_TFTP_VARS is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_CMD_PING=y
+CONFIG_MSCC_SERVAL_SWITCH=y
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b3e4ecc50e1e23b5a66e152b5e6acd2359645f74..684ca9d868fc4233cfa5602337489f0824e69c08 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -351,7 +351,7 @@ config MPC8XXX_GPIO
 
 config MT7621_GPIO
 	bool "MediaTek MT7621 GPIO driver"
-	depends on DM_GPIO && ARCH_MT7620
+	depends on DM_GPIO && SOC_MT7628
 	default y
 	help
 	  Say yes here to support MediaTek MT7621 compatible GPIOs.
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6e436b56abf064e40a639b7c198d5d8f0c574513..64cdc58f92c318fe4b5048d12b809f712793c28a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -269,7 +269,7 @@ config MACB_ZYNQ
 
 config MT7628_ETH
 	bool "MediaTek MT7628 Ethernet Interface"
-	depends on ARCH_MT7620
+	depends on SOC_MT7628
 	help
 	  The MediaTek MT7628 ethernet interface is used on MT7628 and
 	  MT7688 based boards.
diff --git a/drivers/net/mscc_eswitch/Kconfig b/drivers/net/mscc_eswitch/Kconfig
index 6359d0b61015915b7a0f63cdff9bd056e77fed3f..80dd22f98b7f591768c28a67b66e3a2b5dd095f9 100644
--- a/drivers/net/mscc_eswitch/Kconfig
+++ b/drivers/net/mscc_eswitch/Kconfig
@@ -29,3 +29,10 @@ config MSCC_SERVALT_SWITCH
 	select PHYLIB
 	help
 	  This driver supports the Servalt network switch device.
+
+config MSCC_SERVAL_SWITCH
+	bool "Serval switch driver"
+	depends on DM_ETH && ARCH_MSCC
+	select PHYLIB
+	help
+	  This driver supports the Serval network switch device.
diff --git a/drivers/net/mscc_eswitch/Makefile b/drivers/net/mscc_eswitch/Makefile
index bffd8ec77b0f6a11f00c12db1df91ac9b3f6be24..02f39a76bb0fa13eb070f59b36cc2c6e9e6909d9 100644
--- a/drivers/net/mscc_eswitch/Makefile
+++ b/drivers/net/mscc_eswitch/Makefile
@@ -1,5 +1,6 @@
 
-obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o
-obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_miim.o mscc_xfer.o mscc_mac_table.o
+obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o
+obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o
 obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o
 obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o
+obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o
diff --git a/drivers/net/mscc_eswitch/luton_switch.c b/drivers/net/mscc_eswitch/luton_switch.c
index 6667614966daf38b77edb5be3b27891f8be10984..94852b06e745995d1867660f871444f47df7da63 100644
--- a/drivers/net/mscc_eswitch/luton_switch.c
+++ b/drivers/net/mscc_eswitch/luton_switch.c
@@ -15,10 +15,21 @@
 #include <net.h>
 #include <wait_bit.h>
 
-#include "mscc_miim.h"
 #include "mscc_xfer.h"
 #include "mscc_mac_table.h"
 
+#define GCB_MIIM_MII_STATUS			0x0
+#define		GCB_MIIM_STAT_BUSY			BIT(3)
+#define GCB_MIIM_MII_CMD			0x8
+#define		GCB_MIIM_MII_CMD_OPR_WRITE		BIT(1)
+#define		GCB_MIIM_MII_CMD_OPR_READ		BIT(2)
+#define		GCB_MIIM_MII_CMD_WRDATA(x)		((x) << 4)
+#define		GCB_MIIM_MII_CMD_REGAD(x)		((x) << 20)
+#define		GCB_MIIM_MII_CMD_PHYAD(x)		((x) << 25)
+#define		GCB_MIIM_MII_CMD_VLD			BIT(31)
+#define GCB_MIIM_DATA				0xC
+#define		GCB_MIIM_DATA_ERROR			(0x2 << 16)
+
 #define ANA_PORT_VLAN_CFG(x)		(0x00 + 0x80 * (x))
 #define		ANA_PORT_VLAN_CFG_AWARE_ENA	BIT(20)
 #define		ANA_PORT_VLAN_CFG_POP_CNT(x)	((x) << 18)
@@ -136,61 +147,53 @@
 #define PGID_UNICAST		29
 #define PGID_SRC		80
 
-enum luton_target {
-	PORT0,
-	PORT1,
-	PORT2,
-	PORT3,
-	PORT4,
-	PORT5,
-	PORT6,
-	PORT7,
-	PORT8,
-	PORT9,
-	PORT10,
-	PORT11,
-	PORT12,
-	PORT13,
-	PORT14,
-	PORT15,
-	PORT16,
-	PORT17,
-	PORT18,
-	PORT19,
-	PORT20,
-	PORT21,
-	PORT22,
-	PORT23,
-	SYS,
+static const char * const regs_names[] = {
+	"port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
+	"port8", "port9", "port10", "port11", "port12", "port13", "port14",
+	"port15", "port16", "port17", "port18", "port19", "port20", "port21",
+	"port22", "port23",
+	"sys", "ana", "rew", "gcb", "qs", "hsio",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 24
+
+enum luton_ctrl_regs {
+	SYS = MAX_PORT,
 	ANA,
 	REW,
 	GCB,
 	QS,
-	HSIO,
-	TARGET_MAX,
+	HSIO
 };
 
-#define MAX_PORT (PORT23 - PORT0 + 1)
+#define MIN_INT_PORT	0
+#define PORT10		10
+#define PORT11		11
+#define MAX_INT_PORT	12
+#define MIN_EXT_PORT	MAX_INT_PORT
+#define MAX_EXT_PORT	MAX_PORT
 
-#define MIN_INT_PORT PORT0
-#define MAX_INT_PORT (PORT11 - PORT0  + 1)
-#define MIN_EXT_PORT PORT12
-#define MAX_EXT_PORT MAX_PORT
+#define LUTON_MIIM_BUS_COUNT 2
 
-enum luton_mdio_target {
-	MIIM,
-	TARGET_MDIO_MAX,
+struct luton_phy_port_t {
+	size_t phy_addr;
+	struct mii_dev *bus;
+	u8 serdes_index;
+	u8 phy_mode;
 };
 
-enum luton_phy_id {
-	INTERNAL,
-	EXTERNAL,
-	NUM_PHY,
+struct luton_private {
+	void __iomem *regs[REGS_NAMES_COUNT];
+	struct mii_dev *bus[LUTON_MIIM_BUS_COUNT];
+	struct luton_phy_port_t ports[MAX_PORT];
 };
 
-struct luton_private {
-	void __iomem *regs[TARGET_MAX];
-	struct mii_dev *bus[NUM_PHY];
+struct mscc_miim_dev {
+	void __iomem *regs;
+	phys_addr_t miim_base;
+	unsigned long miim_size;
+	struct mii_dev *bus;
 };
 
 static const unsigned long luton_regs_qs[] = {
@@ -207,53 +210,85 @@ static const unsigned long luton_regs_ana_table[] = {
 	[MSCC_ANA_TABLES_MACACCESS] = 0x11b8,
 };
 
-static struct mscc_miim_dev miim[NUM_PHY];
+static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT];
+static int miim_count = -1;
 
-static struct mii_dev *luton_mdiobus_init(struct udevice *dev,
-					  int mdiobus_id)
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+	return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
+				 GCB_MIIM_STAT_BUSY, false, 250, false);
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+	u32 val;
+	int ret;
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret)
+		goto out;
+
+	writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+	       GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
+	       miim->regs + GCB_MIIM_MII_CMD);
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret)
+		goto out;
+
+	val = readl(miim->regs + GCB_MIIM_DATA);
+	if (val & GCB_MIIM_DATA_ERROR) {
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = val & 0xFFFF;
+ out:
+	return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+			   u16 val)
+{
+	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+	int ret;
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret < 0)
+		goto out;
+
+	writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+	       GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
+	       GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
+ out:
+	return ret;
+}
+
+static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
+					   unsigned long miim_size)
 {
-	unsigned long phy_size[NUM_PHY];
-	phys_addr_t phy_base[NUM_PHY];
-	struct ofnode_phandle_args phandle;
-	ofnode eth_node, node, mdio_node;
-	struct resource res;
 	struct mii_dev *bus;
-	fdt32_t faddr;
-	int i;
 
 	bus = mdio_alloc();
 	if (!bus)
 		return NULL;
 
-	/* gather only the first mdio bus */
-	eth_node = dev_read_first_subnode(dev);
-	node = ofnode_first_subnode(eth_node);
-	ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
-				       &phandle);
-	mdio_node = ofnode_get_parent(phandle.node);
-
-	for (i = 0; i < TARGET_MDIO_MAX; i++) {
-		if (ofnode_read_resource(mdio_node, i, &res)) {
-			pr_err("%s: get OF resource failed\n", __func__);
-			return NULL;
-		}
-
-		faddr = cpu_to_fdt32(res.start);
-		phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
-		phy_size[i] = res.end - res.start;
-	}
+	++miim_count;
+	sprintf(bus->name, "miim-bus%d", miim_count);
 
-	strcpy(bus->name, "miim-internal");
-	miim[mdiobus_id].regs = ioremap(phy_base[mdiobus_id],
-					phy_size[mdiobus_id]);
-	bus->priv = &miim[mdiobus_id];
+	miim[miim_count].regs = ioremap(miim_base, miim_size);
+	miim[miim_count].miim_base = miim_base;
+	miim[miim_count].miim_size = miim_size;
+	bus->priv = &miim[miim_count];
 	bus->read = mscc_miim_read;
 	bus->write = mscc_miim_write;
 
 	if (mdio_register(bus))
 		return NULL;
-	else
-		return bus;
+
+	miim[miim_count].bus = bus;
+	return bus;
 }
 
 static void luton_stop(struct udevice *dev)
@@ -324,10 +359,10 @@ static void luton_gmii_port_init(struct luton_private *priv, int port)
 	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
 	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
 	       MAC_VID,
-	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
 
 	/* Enable switching to/from port */
-	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
 		     SYS_SWITCH_PORT_MODE_PORT_ENA);
 }
 
@@ -346,10 +381,10 @@ static void luton_port_init(struct luton_private *priv, int port)
 	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
 	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
 	       MAC_VID,
-	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
 
 	/* Enable switching to/from port */
-	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
 		     SYS_SWITCH_PORT_MODE_PORT_ENA);
 }
 
@@ -393,35 +428,34 @@ static void luton_ext_port_init(struct luton_private *priv, int port)
 	writel(ANA_PORT_VLAN_CFG_AWARE_ENA |
 	       ANA_PORT_VLAN_CFG_POP_CNT(1) |
 	       MAC_VID,
-	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+	       priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
 
 	/* Enable switching to/from port */
-	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port - PORT0),
+	setbits_le32(priv->regs[SYS] + SYS_SWITCH_PORT_MODE(port),
 		     SYS_SWITCH_PORT_MODE_PORT_ENA);
 }
 
-static void serdes6g_write(struct luton_private *priv, u32 addr)
+static void serdes6g_write(void __iomem *base, u32 addr)
 {
 	u32 data;
 
 	writel(HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT |
 	       HSIO_MCB_SERDES6G_CFG_ADDR(addr),
-	       priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
+	       base + HSIO_MCB_SERDES6G_CFG);
 
 	do {
-		data = readl(priv->regs[HSIO] + HSIO_MCB_SERDES6G_CFG);
+		data = readl(base + HSIO_MCB_SERDES6G_CFG);
 	} while (data & HSIO_MCB_SERDES6G_CFG_WR_ONE_SHOT);
-
-	mdelay(100);
 }
 
-static void serdes6g_cfg(struct luton_private *priv)
+static void serdes6g_setup(void __iomem *base, uint32_t addr,
+			   phy_interface_t interface)
 {
 	writel(HSIO_RCOMP_CFG_CFG0_MODE_SEL(0x3) |
 	       HSIO_RCOMP_CFG_CFG0_RUN_CAL,
-	       priv->regs[HSIO] + HSIO_RCOMP_CFG_CFG0);
+	       base + HSIO_RCOMP_CFG_CFG0);
 
-	while (readl(priv->regs[HSIO] + HSIO_RCOMP_STATUS) &
+	while (readl(base + HSIO_RCOMP_STATUS) &
 	       HSIO_RCOMP_STATUS_BUSY)
 		;
 
@@ -430,50 +464,64 @@ static void serdes6g_cfg(struct luton_private *priv)
 	       HSIO_SERDES6G_ANA_CFG_OB_CFG_POST0(0x10) |
 	       HSIO_SERDES6G_ANA_CFG_OB_CFG_POL |
 	       HSIO_SERDES6G_ANA_CFG_OB_CFG_ENA1V_MODE,
-	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG);
+	       base + HSIO_SERDES6G_ANA_CFG_OB_CFG);
 	writel(HSIO_SERDES6G_ANA_CFG_OB_CFG1_LEV(0x18) |
 	       HSIO_SERDES6G_ANA_CFG_OB_CFG1_ENA_CAS(0x1),
-	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
+	       base + HSIO_SERDES6G_ANA_CFG_OB_CFG1);
 	writel(HSIO_SERDES6G_ANA_CFG_IB_CFG_RESISTOR_CTRL(0xc) |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG_VBCOM(0x4) |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG_VBAC(0x5) |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG_RT(0xf) |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG_RF(0x4),
-	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG);
+	       base + HSIO_SERDES6G_ANA_CFG_IB_CFG);
 	writel(HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSDC |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ENA_OFFSAC |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_ANEG_MODE |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_CHF |
 	       HSIO_SERDES6G_ANA_CFG_IB_CFG1_C(0x4),
-	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
+	       base + HSIO_SERDES6G_ANA_CFG_IB_CFG1);
 	writel(HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_ANA(0x5) |
 	       HSIO_SERDES6G_ANA_CFG_DES_CFG_BW_HYST(0x5) |
 	       HSIO_SERDES6G_ANA_CFG_DES_CFG_MBTR_CTRL(0x2) |
 	       HSIO_SERDES6G_ANA_CFG_DES_CFG_PHS_CTRL(0x6),
-	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_DES_CFG);
+	       base + HSIO_SERDES6G_ANA_CFG_DES_CFG);
 	writel(HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_ENA |
 	       HSIO_SERDES6G_ANA_CFG_PLL_CFG_FSM_CTRL_DATA(0x78),
-	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
+	       base + HSIO_SERDES6G_ANA_CFG_PLL_CFG);
 	writel(HSIO_SERDES6G_ANA_CFG_COMMON_CFG_IF_MODE(0x30) |
 	       HSIO_SERDES6G_ANA_CFG_COMMON_CFG_ENA_LANE,
-	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
+	       base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
 	/*
 	 * There are 4 serdes6g, configure all except serdes6g0, therefore
 	 * the address is b1110
 	 */
-	serdes6g_write(priv, 0xe);
+	serdes6g_write(base, addr);
 
-	writel(readl(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
+	writel(readl(base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG) |
 	       HSIO_SERDES6G_ANA_CFG_COMMON_CFG_SYS_RST,
-	       priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
-	serdes6g_write(priv, 0xe);
+	       base + HSIO_SERDES6G_ANA_CFG_COMMON_CFG);
+	serdes6g_write(base, addr);
 
-	clrbits_le32(priv->regs[HSIO] + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
+	clrbits_le32(base + HSIO_SERDES6G_ANA_CFG_IB_CFG1,
 		     HSIO_SERDES6G_ANA_CFG_IB_CFG1_RST);
 	writel(HSIO_SERDES6G_DIG_CFG_MISC_CFG_LANE_RST,
-	       priv->regs[HSIO] + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
-	serdes6g_write(priv, 0xe);
+	       base + HSIO_SERDES6G_DIG_CFG_MISC_CFG);
+	serdes6g_write(base, addr);
+}
+
+static void serdes_setup(struct luton_private *priv)
+{
+	size_t mask;
+	int i = 0;
+
+	for (i = 0; i < MAX_PORT; ++i) {
+		if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
+			continue;
+
+		mask = BIT(priv->ports[i].serdes_index);
+		serdes6g_setup(priv->regs[HSIO], mask, priv->ports[i].phy_mode);
+	}
 }
 
 static int luton_switch_init(struct luton_private *priv)
@@ -495,8 +543,8 @@ static int luton_switch_init(struct luton_private *priv)
 	setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
 		     SYS_SYSTEM_RST_CORE_ENA);
 
-	/* Setup the Serdes6g macros */
-	serdes6g_cfg(priv);
+	/* Setup the Serdes macros */
+	serdes_setup(priv);
 
 	return 0;
 }
@@ -525,7 +573,7 @@ static int luton_initialize(struct luton_private *priv)
 	writel(2000000000 / 4,
 	       priv->regs[SYS] + SYS_FRM_AGING);
 
-	for (i = PORT0; i < MAX_PORT; i++) {
+	for (i = 0; i < MAX_PORT; i++) {
 		if (i < PORT10)
 			luton_gmii_port_init(priv, i);
 		else
@@ -608,56 +656,51 @@ static int luton_recv(struct udevice *dev, int flags, uchar **packetp)
 	return byte_cnt;
 }
 
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+	int i = 0;
+
+	for (i = 0; i < LUTON_MIIM_BUS_COUNT; ++i)
+		if (miim[i].miim_base == base && miim[i].miim_size == size)
+			return miim[i].bus;
+
+	return NULL;
+}
+
+static void add_port_entry(struct luton_private *priv, size_t index,
+			   size_t phy_addr, struct mii_dev *bus,
+			   u8 serdes_index, u8 phy_mode)
+{
+	priv->ports[index].phy_addr = phy_addr;
+	priv->ports[index].bus = bus;
+	priv->ports[index].serdes_index = serdes_index;
+	priv->ports[index].phy_mode = phy_mode;
+}
+
 static int luton_probe(struct udevice *dev)
 {
 	struct luton_private *priv = dev_get_priv(dev);
-	int i;
-
-	struct {
-		enum luton_target id;
-		char *name;
-	} reg[] = {
-		{ PORT0, "port0" },
-		{ PORT1, "port1" },
-		{ PORT2, "port2" },
-		{ PORT3, "port3" },
-		{ PORT4, "port4" },
-		{ PORT5, "port5" },
-		{ PORT6, "port6" },
-		{ PORT7, "port7" },
-		{ PORT8, "port8" },
-		{ PORT9, "port9" },
-		{ PORT10, "port10" },
-		{ PORT11, "port11" },
-		{ PORT12, "port12" },
-		{ PORT13, "port13" },
-		{ PORT14, "port14" },
-		{ PORT15, "port15" },
-		{ PORT16, "port16" },
-		{ PORT17, "port17" },
-		{ PORT18, "port18" },
-		{ PORT19, "port19" },
-		{ PORT20, "port20" },
-		{ PORT21, "port21" },
-		{ PORT22, "port22" },
-		{ PORT23, "port23" },
-		{ SYS, "sys" },
-		{ ANA, "ana" },
-		{ REW, "rew" },
-		{ GCB, "gcb" },
-		{ QS, "qs" },
-		{ HSIO, "hsio" },
-	};
+	int i, ret;
+	struct resource res;
+	fdt32_t faddr;
+	phys_addr_t addr_base;
+	unsigned long addr_size;
+	ofnode eth_node, node, mdio_node;
+	size_t phy_addr;
+	struct mii_dev *bus;
+	struct ofnode_phandle_args phandle;
+	struct phy_device *phy;
 
 	if (!priv)
 		return -EINVAL;
 
-	for (i = 0; i < ARRAY_SIZE(reg); i++) {
-		priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
-		if (!priv->regs[reg[i].id]) {
+	/* Get registers and map them to the private structure */
+	for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+		priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+		if (!priv->regs[i]) {
 			debug
 			    ("Error can't get regs base addresses for %s\n",
-			     reg[i].name);
+			     regs_names[i]);
 			return -ENOMEM;
 		}
 	}
@@ -666,7 +709,7 @@ static int luton_probe(struct udevice *dev)
 	writel(0, priv->regs[GCB] + GCB_DEVCPU_RST_SOFT_CHIP_RST);
 
 	/* Ports with ext phy don't need to reset clk */
-	for (i = PORT0; i < MAX_INT_PORT; i++) {
+	for (i = 0; i < MAX_INT_PORT; i++) {
 		if (i < PORT10)
 			clrbits_le32(priv->regs[i] + DEV_GMII_PORT_MODE_CLK,
 				     DEV_GMII_PORT_MODE_CLK_PHY_RST);
@@ -680,20 +723,76 @@ static int luton_probe(struct udevice *dev)
 			      GCB_MISC_STAT_PHY_READY, true, 500, false))
 		return -EACCES;
 
-	priv->bus[INTERNAL] = luton_mdiobus_init(dev, INTERNAL);
 
-	for (i = 0; i < MAX_INT_PORT; i++) {
-		phy_connect(priv->bus[INTERNAL], i, dev,
-			    PHY_INTERFACE_MODE_NONE);
+	/* Initialize miim buses */
+	memset(&miim, 0x0, sizeof(miim) * LUTON_MIIM_BUS_COUNT);
+
+	/* iterate all the ports and find out on which bus they are */
+	i = 0;
+	eth_node = dev_read_first_subnode(dev);
+	for (node = ofnode_first_subnode(eth_node);
+	     ofnode_valid(node);
+	     node = ofnode_next_subnode(node)) {
+		if (ofnode_read_resource(node, 0, &res))
+			return -ENOMEM;
+		i = res.start;
+
+		ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
+						     0, 0, &phandle);
+		if (ret)
+			continue;
+
+		/* Get phy address on mdio bus */
+		if (ofnode_read_resource(phandle.node, 0, &res))
+			return -ENOMEM;
+		phy_addr = res.start;
+
+		/* Get mdio node */
+		mdio_node = ofnode_get_parent(phandle.node);
+
+		if (ofnode_read_resource(mdio_node, 0, &res))
+			return -ENOMEM;
+		faddr = cpu_to_fdt32(res.start);
+
+		addr_base = ofnode_translate_address(mdio_node, &faddr);
+		addr_size = res.end - res.start;
+
+		/* If the bus is new then create a new bus */
+		if (!get_mdiobus(addr_base, addr_size))
+			priv->bus[miim_count] =
+				serval_mdiobus_init(addr_base, addr_size);
+
+		/* Connect mdio bus with the port */
+		bus = get_mdiobus(addr_base, addr_size);
+
+		/* Get serdes info */
+		ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+						     3, 0, &phandle);
+		if (ret)
+			add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
+		else
+			add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+				       phandle.args[2]);
+	}
+
+	for (i = 0; i < MAX_PORT; i++) {
+		if (!priv->ports[i].bus)
+			continue;
+
+		phy = phy_connect(priv->ports[i].bus,
+				  priv->ports[i].phy_addr, dev,
+				  PHY_INTERFACE_MODE_NONE);
+		if (phy && i >= MAX_INT_PORT)
+			board_phy_config(phy);
 	}
 
 	/*
 	 * coma_mode is need on only one phy, because all the other phys
 	 * will be affected.
 	 */
-	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0x10);
-	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 14, 0x800);
-	mscc_miim_write(priv->bus[INTERNAL], 0, 0, 31, 0);
+	mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0x10);
+	mscc_miim_write(priv->ports[0].bus, 0, 0, 14, 0x800);
+	mscc_miim_write(priv->ports[0].bus, 0, 0, 31, 0);
 
 	return 0;
 }
@@ -703,7 +802,7 @@ static int luton_remove(struct udevice *dev)
 	struct luton_private *priv = dev_get_priv(dev);
 	int i;
 
-	for (i = 0; i < NUM_PHY; i++) {
+	for (i = 0; i < LUTON_MIIM_BUS_COUNT; i++) {
 		mdio_unregister(priv->bus[i]);
 		mdio_free(priv->bus[i]);
 	}
diff --git a/drivers/net/mscc_eswitch/ocelot_switch.c b/drivers/net/mscc_eswitch/ocelot_switch.c
index 815c2da26469c54ff26388316b8ad7081bf19e5c..5c7e6961be43668f655eba905a6ab82a6f5f6011 100644
--- a/drivers/net/mscc_eswitch/ocelot_switch.c
+++ b/drivers/net/mscc_eswitch/ocelot_switch.c
@@ -15,7 +15,6 @@
 #include <net.h>
 #include <wait_bit.h>
 
-#include "mscc_miim.h"
 #include "mscc_xfer.h"
 #include "mscc_mac_table.h"
 
@@ -26,6 +25,20 @@
 #define PHY_STAT			0x4
 #define PHY_STAT_SUPERVISOR_COMPLETE		BIT(0)
 
+#define GCB_MIIM_MII_STATUS		0x0
+#define		GCB_MIIM_STAT_BUSY		BIT(3)
+#define GCB_MIIM_MII_CMD		0x8
+#define		GCB_MIIM_MII_CMD_SCAN		BIT(0)
+#define		GCB_MIIM_MII_CMD_OPR_WRITE	BIT(1)
+#define		GCB_MIIM_MII_CMD_OPR_READ	BIT(2)
+#define		GCB_MIIM_MII_CMD_SINGLE_SCAN	BIT(3)
+#define		GCB_MIIM_MII_CMD_WRDATA(x)	((x) << 4)
+#define		GCB_MIIM_MII_CMD_REGAD(x)	((x) << 20)
+#define		GCB_MIIM_MII_CMD_PHYAD(x)	((x) << 25)
+#define		GCB_MIIM_MII_CMD_VLD		BIT(31)
+#define GCB_MIIM_DATA			0xC
+#define		GCB_MIIM_DATA_ERROR		(0x3 << 16)
+
 #define ANA_PORT_VLAN_CFG(x)		(0x7000 + 0x100 * (x))
 #define		ANA_PORT_VLAN_CFG_AWARE_ENA	BIT(20)
 #define		ANA_PORT_VLAN_CFG_POP_CNT(x)	((x) << 18)
@@ -33,6 +46,41 @@
 #define		ANA_PORT_PORT_CFG_RECV_ENA	BIT(6)
 #define ANA_PGID(x)			(0x8c00 + 4 * (x))
 
+#define HSIO_ANA_SERDES1G_DES_CFG		0x4c
+#define		HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x)		((x) << 1)
+#define		HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x)		((x) << 5)
+#define		HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x)		((x) << 8)
+#define		HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x)		((x) << 13)
+#define HSIO_ANA_SERDES1G_IB_CFG		0x50
+#define		HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x)	(x)
+#define		HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x)		((x) << 6)
+#define		HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP	BIT(9)
+#define		HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV		BIT(11)
+#define		HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM		BIT(13)
+#define		HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x)		((x) << 24)
+#define HSIO_ANA_SERDES1G_OB_CFG		0x54
+#define		HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x)	(x)
+#define		HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x)		((x) << 4)
+#define		HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x)	((x) << 10)
+#define		HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x)		((x) << 13)
+#define		HSIO_ANA_SERDES1G_OB_CFG_SLP(x)			((x) << 17)
+#define HSIO_ANA_SERDES1G_SER_CFG		0x58
+#define HSIO_ANA_SERDES1G_COMMON_CFG		0x5c
+#define		HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE		BIT(0)
+#define		HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE		BIT(18)
+#define		HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST		BIT(31)
+#define HSIO_ANA_SERDES1G_PLL_CFG		0x60
+#define		HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA		BIT(7)
+#define		HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x)	((x) << 8)
+#define		HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2		BIT(21)
+#define HSIO_DIG_SERDES1G_DFT_CFG0		0x68
+#define HSIO_DIG_SERDES1G_MISC_CFG		0x7c
+#define		HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST		BIT(0)
+#define HSIO_MCB_SERDES1G_CFG			0x88
+#define		HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT		BIT(31)
+#define		HSIO_MCB_SERDES1G_CFG_ADDR(x)			(x)
+#define HSIO_HW_CFGSTAT_HW_CFG			0x10c
+
 #define SYS_FRM_AGING			0x574
 #define		SYS_FRM_AGING_ENA		BIT(20)
 
@@ -83,49 +131,58 @@
 #define		QS_INJ_GRP_CFG_BYTE_SWAP	BIT(0)
 
 #define IFH_INJ_BYPASS		BIT(31)
-#define	IFH_TAG_TYPE_C		0
-#define	MAC_VID			1
+#define IFH_TAG_TYPE_C		0
+#define MAC_VID			1
 #define CPU_PORT		11
-#define INTERNAL_PORT_MSK	0xF
+#define INTERNAL_PORT_MSK	0x2FF
 #define IFH_LEN			4
 #define ETH_ALEN		6
-#define	PGID_BROADCAST		13
-#define	PGID_UNICAST		14
-#define	PGID_SRC		80
+#define PGID_BROADCAST		13
+#define PGID_UNICAST		14
+#define PGID_SRC		80
 
-enum ocelot_target {
-	ANA,
-	QS,
-	QSYS,
+static const char * const regs_names[] = {
+	"port0", "port1", "port2", "port3", "port4", "port5", "port6", "port7",
+	"port8", "port9", "port10", "sys", "rew", "qs", "hsio", "qsys", "ana",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 11
+
+enum ocelot_ctrl_regs {
+	SYS = MAX_PORT,
 	REW,
-	SYS,
+	QS,
 	HSIO,
-	PORT0,
-	PORT1,
-	PORT2,
-	PORT3,
-	TARGET_MAX,
+	QSYS,
+	ANA,
 };
 
-#define MAX_PORT (PORT3 - PORT0)
+#define OCELOT_MIIM_BUS_COUNT 2
 
-enum ocelot_mdio_target {
-	MIIM,
-	PHY,
-	TARGET_MDIO_MAX,
+struct ocelot_phy_port_t {
+	size_t phy_addr;
+	struct mii_dev *bus;
+	u8 serdes_index;
+	u8 phy_mode;
 };
 
-enum ocelot_phy_id {
-	INTERNAL,
-	EXTERNAL,
-	NUM_PHY,
+struct ocelot_private {
+	void __iomem *regs[REGS_NAMES_COUNT];
+	struct mii_dev *bus[OCELOT_MIIM_BUS_COUNT];
+	struct ocelot_phy_port_t ports[MAX_PORT];
 };
 
-struct ocelot_private {
-	void __iomem *regs[TARGET_MAX];
-	struct mii_dev *bus[NUM_PHY];
+struct mscc_miim_dev {
+	void __iomem *regs;
+	phys_addr_t miim_base;
+	unsigned long miim_size;
+	struct mii_dev *bus;
 };
 
+static struct mscc_miim_dev miim[OCELOT_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
 static const unsigned long ocelot_regs_qs[] = {
 	[MSCC_QS_XTR_RD] = 0x8,
 	[MSCC_QS_XTR_FLUSH] = 0x18,
@@ -140,65 +197,95 @@ static const unsigned long ocelot_regs_ana_table[] = {
 	[MSCC_ANA_TABLES_MACACCESS] = 0x8b3c,
 };
 
-static struct mscc_miim_dev miim[NUM_PHY];
-
 static void mscc_phy_reset(void)
 {
-	writel(0, miim[INTERNAL].phy_regs + PHY_CFG);
+	writel(0, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG);
 	writel(PHY_CFG_RST | PHY_CFG_COMMON_RST
-	       | PHY_CFG_ENA, miim[INTERNAL].phy_regs + PHY_CFG);
-	if (wait_for_bit_le32(miim[INTERNAL].phy_regs + PHY_STAT,
-			      PHY_STAT_SUPERVISOR_COMPLETE,
+	       | PHY_CFG_ENA, BASE_DEVCPU_GCB + PERF_PHY_CFG + PHY_CFG);
+	if (wait_for_bit_le32((const void *)(BASE_DEVCPU_GCB + PERF_PHY_CFG) +
+			      PHY_STAT, PHY_STAT_SUPERVISOR_COMPLETE,
 			      true, 2000, false)) {
 		pr_err("Timeout in phy reset\n");
 	}
 }
 
-/* For now only setup the internal mdio bus */
-static struct mii_dev *ocelot_mdiobus_init(struct udevice *dev)
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+	return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
+				 GCB_MIIM_STAT_BUSY, false, 250, false);
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+	u32 val;
+	int ret;
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret)
+		goto out;
+
+	writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+	       GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
+	       miim->regs + GCB_MIIM_MII_CMD);
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret)
+		goto out;
+
+	val = readl(miim->regs + GCB_MIIM_DATA);
+	if (val & GCB_MIIM_DATA_ERROR) {
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = val & 0xFFFF;
+ out:
+	return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+			   u16 val)
+{
+	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+	int ret;
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret < 0)
+		goto out;
+
+	writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+	       GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
+	       GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
+ out:
+	return ret;
+}
+
+static struct mii_dev *ocelot_mdiobus_init(phys_addr_t miim_base,
+					   unsigned long miim_size)
 {
-	unsigned long phy_size[TARGET_MAX];
-	phys_addr_t phy_base[TARGET_MAX];
-	struct ofnode_phandle_args phandle;
-	ofnode eth_node, node, mdio_node;
-	struct resource res;
 	struct mii_dev *bus;
-	fdt32_t faddr;
-	int i;
 
 	bus = mdio_alloc();
 
 	if (!bus)
 		return NULL;
 
-	/* gathered only the first mdio bus */
-	eth_node = dev_read_first_subnode(dev);
-	node = ofnode_first_subnode(eth_node);
-	ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
-				       &phandle);
-	mdio_node = ofnode_get_parent(phandle.node);
-
-	for (i = 0; i < TARGET_MDIO_MAX; i++) {
-		if (ofnode_read_resource(mdio_node, i, &res)) {
-			pr_err("%s: get OF resource failed\n", __func__);
-			return NULL;
-		}
-		faddr = cpu_to_fdt32(res.start);
-		phy_base[i] = ofnode_translate_address(mdio_node, &faddr);
-		phy_size[i] = res.end - res.start;
-	}
+	++miim_count;
+	sprintf(bus->name, "miim-bus%d", miim_count);
 
-	strcpy(bus->name, "miim-internal");
-	miim[INTERNAL].phy_regs = ioremap(phy_base[PHY], phy_size[PHY]);
-	miim[INTERNAL].regs = ioremap(phy_base[MIIM], phy_size[MIIM]);
-	bus->priv = &miim[INTERNAL];
+	miim[miim_count].regs = ioremap(miim_base, miim_size);
+	miim[miim_count].miim_base = miim_base;
+	miim[miim_count].miim_size = miim_size;
+	bus->priv = &miim[miim_count];
 	bus->read = mscc_miim_read;
 	bus->write = mscc_miim_write;
 
 	if (mdio_register(bus))
 		return NULL;
-	else
-		return bus;
+
+	miim[miim_count].bus = bus;
+	return bus;
 }
 
 __weak void mscc_switch_reset(void)
@@ -291,13 +378,87 @@ static void ocelot_port_init(struct ocelot_private *priv, int port)
 
 	/* Make VLAN aware for CPU traffic */
 	writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
-	       MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port - PORT0));
+	       MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
 
 	/* Enable the port in the core */
-	setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port - PORT0),
+	setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
 		     QSYS_SWITCH_PORT_MODE_PORT_ENA);
 }
 
+static void serdes1g_write(void __iomem *base, u32 addr)
+{
+	u32 data;
+
+	writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
+	       HSIO_MCB_SERDES1G_CFG_ADDR(addr),
+	       base + HSIO_MCB_SERDES1G_CFG);
+
+	do {
+		data = readl(base + HSIO_MCB_SERDES1G_CFG);
+	} while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
+}
+
+static void serdes1g_setup(void __iomem *base, uint32_t addr,
+			   phy_interface_t interface)
+{
+	writel(0x34, base + HSIO_HW_CFGSTAT_HW_CFG);
+
+	writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
+	writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
+	writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
+	       HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
+	       HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
+	       HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
+	       HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
+	       base + HSIO_ANA_SERDES1G_IB_CFG);
+	writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
+	       HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
+	       HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
+	       HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
+	       base + HSIO_ANA_SERDES1G_DES_CFG);
+	writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
+	       HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
+	       HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
+	       HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
+	       HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
+	       base + HSIO_ANA_SERDES1G_OB_CFG);
+	writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+	       HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
+	       base + HSIO_ANA_SERDES1G_COMMON_CFG);
+	writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
+	       HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
+	       HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
+	       base + HSIO_ANA_SERDES1G_PLL_CFG);
+	writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
+	       base + HSIO_DIG_SERDES1G_MISC_CFG);
+
+	serdes1g_write(base, addr);
+
+	writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+	       HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
+	       HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
+	       base + HSIO_ANA_SERDES1G_COMMON_CFG);
+	serdes1g_write(base, addr);
+
+	writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
+	serdes1g_write(base, addr);
+}
+
+static void serdes_setup(struct ocelot_private *priv)
+{
+	size_t mask;
+	int i = 0;
+
+	for (i = 0; i < MAX_PORT; ++i) {
+		if (!priv->ports[i].bus || priv->ports[i].serdes_index == 0xff)
+			continue;
+
+		mask = BIT(priv->ports[i].serdes_index);
+		serdes1g_setup(priv->regs[HSIO], mask,
+			       priv->ports[i].phy_mode);
+	}
+}
+
 static int ocelot_switch_init(struct ocelot_private *priv)
 {
 	/* Reset switch & memories */
@@ -315,6 +476,7 @@ static int ocelot_switch_init(struct ocelot_private *priv)
 	setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
 		     SYS_SYSTEM_RST_CORE_ENA);
 
+	serdes_setup(priv);
 	return 0;
 }
 
@@ -331,7 +493,7 @@ static int ocelot_initialize(struct ocelot_private *priv)
 	 * Put fron ports in "port isolation modes" - i.e. they cant send
 	 * to other ports - via the PGID sorce masks.
 	 */
-	for (i = 0; i <= MAX_PORT; i++)
+	for (i = 0; i < MAX_PORT; i++)
 		writel(0, priv->regs[ANA] + ANA_PGID(PGID_SRC + i));
 
 	/* Flush queues */
@@ -341,7 +503,7 @@ static int ocelot_initialize(struct ocelot_private *priv)
 	writel(SYS_FRM_AGING_ENA | (20000000 / 65),
 	       priv->regs[SYS] + SYS_FRM_AGING);
 
-	for (i = PORT0; i <= PORT3; i++)
+	for (i = 0; i < MAX_PORT; i++)
 		ocelot_port_init(priv, i);
 
 	ocelot_cpu_capture_setup(priv);
@@ -433,43 +595,119 @@ static int ocelot_recv(struct udevice *dev, int flags, uchar **packetp)
 	return byte_cnt;
 }
 
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+	int i = 0;
+
+	for (i = 0; i < OCELOT_MIIM_BUS_COUNT; ++i)
+		if (miim[i].miim_base == base && miim[i].miim_size == size)
+			return miim[i].bus;
+
+	return NULL;
+}
+
+static void add_port_entry(struct ocelot_private *priv, size_t index,
+			   size_t phy_addr, struct mii_dev *bus,
+			   u8 serdes_index, u8 phy_mode)
+{
+	priv->ports[index].phy_addr = phy_addr;
+	priv->ports[index].bus = bus;
+	priv->ports[index].serdes_index = serdes_index;
+	priv->ports[index].phy_mode = phy_mode;
+}
+
+static int external_bus(struct ocelot_private *priv, size_t port_index)
+{
+	return priv->ports[port_index].serdes_index != 0xff;
+}
+
 static int ocelot_probe(struct udevice *dev)
 {
 	struct ocelot_private *priv = dev_get_priv(dev);
-	int ret, i;
+	int i, ret;
+	struct resource res;
+	fdt32_t faddr;
+	phys_addr_t addr_base;
+	unsigned long addr_size;
+	ofnode eth_node, node, mdio_node;
+	size_t phy_addr;
+	struct mii_dev *bus;
+	struct ofnode_phandle_args phandle;
+	struct phy_device *phy;
+
+	if (!priv)
+		return -EINVAL;
 
-	struct {
-		enum ocelot_target id;
-		char *name;
-	} reg[] = {
-		{ SYS, "sys" },
-		{ REW, "rew" },
-		{ QSYS, "qsys" },
-		{ ANA, "ana" },
-		{ QS, "qs" },
-		{ HSIO, "hsio" },
-		{ PORT0, "port0" },
-		{ PORT1, "port1" },
-		{ PORT2, "port2" },
-		{ PORT3, "port3" },
-	};
-
-	for (i = 0; i < ARRAY_SIZE(reg); i++) {
-		priv->regs[reg[i].id] = dev_remap_addr_name(dev, reg[i].name);
-		if (!priv->regs[reg[i].id]) {
-			pr_err
-			    ("Error %d: can't get regs base addresses for %s\n",
-			     ret, reg[i].name);
+	for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+		priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+		if (!priv->regs[i]) {
+			debug
+			    ("Error can't get regs base addresses for %s\n",
+			     regs_names[i]);
 			return -ENOMEM;
 		}
 	}
 
-	priv->bus[INTERNAL] = ocelot_mdiobus_init(dev);
+	/* Initialize miim buses */
+	memset(&miim, 0x0, sizeof(struct mscc_miim_dev) *
+	       OCELOT_MIIM_BUS_COUNT);
+
+	/* iterate all the ports and find out on which bus they are */
+	i = 0;
+	eth_node = dev_read_first_subnode(dev);
+	for (node = ofnode_first_subnode(eth_node); ofnode_valid(node);
+	     node = ofnode_next_subnode(node)) {
+		if (ofnode_read_resource(node, 0, &res))
+			return -ENOMEM;
+		i = res.start;
+
+		ofnode_parse_phandle_with_args(node, "phy-handle", NULL, 0, 0,
+					       &phandle);
+
+		/* Get phy address on mdio bus */
+		if (ofnode_read_resource(phandle.node, 0, &res))
+			return -ENOMEM;
+		phy_addr = res.start;
+
+		/* Get mdio node */
+		mdio_node = ofnode_get_parent(phandle.node);
+
+		if (ofnode_read_resource(mdio_node, 0, &res))
+			return -ENOMEM;
+		faddr = cpu_to_fdt32(res.start);
+
+		addr_base = ofnode_translate_address(mdio_node, &faddr);
+		addr_size = res.end - res.start;
+
+		/* If the bus is new then create a new bus */
+		if (!get_mdiobus(addr_base, addr_size))
+			priv->bus[miim_count] =
+				ocelot_mdiobus_init(addr_base, addr_size);
+
+		/* Connect mdio bus with the port */
+		bus = get_mdiobus(addr_base, addr_size);
+
+		/* Get serdes info */
+		ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+						     3, 0, &phandle);
+		if (ret)
+			add_port_entry(priv, i, phy_addr, bus, 0xff, 0xff);
+		else
+			add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+				       phandle.args[2]);
+	}
+
 	mscc_phy_reset();
 
-	for (i = 0; i < 4; i++) {
-		phy_connect(priv->bus[INTERNAL], i, dev,
-			    PHY_INTERFACE_MODE_NONE);
+	for (i = 0; i < MAX_PORT; i++) {
+		if (!priv->ports[i].bus)
+			continue;
+
+		phy = phy_connect(priv->ports[i].bus,
+				  priv->ports[i].phy_addr, dev,
+				  PHY_INTERFACE_MODE_NONE);
+		if (phy && external_bus(priv, i))
+			board_phy_config(phy);
 	}
 
 	return 0;
@@ -480,7 +718,7 @@ static int ocelot_remove(struct udevice *dev)
 	struct ocelot_private *priv = dev_get_priv(dev);
 	int i;
 
-	for (i = 0; i < NUM_PHY; i++) {
+	for (i = 0; i < OCELOT_MIIM_BUS_COUNT; i++) {
 		mdio_unregister(priv->bus[i]);
 		mdio_free(priv->bus[i]);
 	}
diff --git a/drivers/net/mscc_eswitch/serval_switch.c b/drivers/net/mscc_eswitch/serval_switch.c
new file mode 100644
index 0000000000000000000000000000000000000000..2559f5d0cd1ff272497381ceb9a6ed44de4d3c3e
--- /dev/null
+++ b/drivers/net/mscc_eswitch/serval_switch.c
@@ -0,0 +1,703 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/of_access.h>
+#include <dm/of_addr.h>
+#include <fdt_support.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <miiphy.h>
+#include <net.h>
+#include <wait_bit.h>
+
+#include "mscc_xfer.h"
+#include "mscc_mac_table.h"
+
+#define GCB_MIIM_MII_STATUS			0x0
+#define		GCB_MIIM_STAT_BUSY			BIT(3)
+#define GCB_MIIM_MII_CMD			0x8
+#define		GCB_MIIM_MII_CMD_OPR_WRITE		BIT(1)
+#define		GCB_MIIM_MII_CMD_OPR_READ		BIT(2)
+#define		GCB_MIIM_MII_CMD_WRDATA(x)		((x) << 4)
+#define		GCB_MIIM_MII_CMD_REGAD(x)		((x) << 20)
+#define		GCB_MIIM_MII_CMD_PHYAD(x)		((x) << 25)
+#define		GCB_MIIM_MII_CMD_VLD			BIT(31)
+#define GCB_MIIM_DATA				0xC
+#define		GCB_MIIM_DATA_ERROR			(0x2 << 16)
+
+#define ANA_PORT_VLAN_CFG(x)			(0xc000 + 0x100 * (x))
+#define		ANA_PORT_VLAN_CFG_AWARE_ENA		BIT(20)
+#define		ANA_PORT_VLAN_CFG_POP_CNT(x)		((x) << 18)
+#define ANA_PORT_PORT_CFG(x)			(0xc070 + 0x100 * (x))
+#define		ANA_PORT_PORT_CFG_RECV_ENA		BIT(6)
+#define ANA_PGID(x)				(0x9c00 + 4 * (x))
+
+#define HSIO_ANA_SERDES1G_DES_CFG		0x3c
+#define		HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(x)		((x) << 1)
+#define		HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(x)		((x) << 5)
+#define		HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(x)		((x) << 8)
+#define		HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(x)		((x) << 13)
+#define HSIO_ANA_SERDES1G_IB_CFG		0x40
+#define		HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(x)	(x)
+#define		HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(x)		((x) << 6)
+#define		HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP	BIT(9)
+#define		HSIO_ANA_SERDES1G_IB_CFG_ENA_DETLEV		BIT(11)
+#define		HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM		BIT(13)
+#define		HSIO_ANA_SERDES1G_IB_CFG_DET_LEV(x)		((x) << 19)
+#define		HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(x)		((x) << 24)
+#define HSIO_ANA_SERDES1G_OB_CFG		0x44
+#define		HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(x)	(x)
+#define		HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(x)		((x) << 4)
+#define		HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(x)	((x) << 10)
+#define		HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(x)		((x) << 13)
+#define		HSIO_ANA_SERDES1G_OB_CFG_SLP(x)			((x) << 17)
+#define HSIO_ANA_SERDES1G_SER_CFG		0x48
+#define HSIO_ANA_SERDES1G_COMMON_CFG		0x4c
+#define		HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE		BIT(0)
+#define		HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE		BIT(18)
+#define		HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST		BIT(31)
+#define HSIO_ANA_SERDES1G_PLL_CFG		0x50
+#define		HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA		BIT(7)
+#define		HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(x)	((x) << 8)
+#define		HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2		BIT(21)
+#define HSIO_DIG_SERDES1G_DFT_CFG0		0x58
+#define HSIO_DIG_SERDES1G_MISC_CFG		0x6c
+#define		HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST		BIT(0)
+#define HSIO_MCB_SERDES1G_CFG			0x74
+#define		HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT	BIT(31)
+#define		HSIO_MCB_SERDES1G_CFG_ADDR(x)		(x)
+
+#define SYS_FRM_AGING				0x584
+#define		SYS_FRM_AGING_ENA			BIT(20)
+#define SYS_SYSTEM_RST_CFG			0x518
+#define		SYS_SYSTEM_RST_MEM_INIT			BIT(5)
+#define		SYS_SYSTEM_RST_MEM_ENA			BIT(6)
+#define		SYS_SYSTEM_RST_CORE_ENA			BIT(7)
+#define SYS_PORT_MODE(x)			(0x524 + 0x4 * (x))
+#define		SYS_PORT_MODE_INCL_INJ_HDR(x)		((x) << 4)
+#define		SYS_PORT_MODE_INCL_XTR_HDR(x)		((x) << 2)
+#define SYS_PAUSE_CFG(x)			(0x65c + 0x4 * (x))
+#define		SYS_PAUSE_CFG_PAUSE_ENA			BIT(0)
+
+#define QSYS_SWITCH_PORT_MODE(x)		(0x15a34 + 0x4 * (x))
+#define		QSYS_SWITCH_PORT_MODE_PORT_ENA		BIT(13)
+#define QSYS_EGR_NO_SHARING			0x15a9c
+#define QSYS_QMAP				0x15adc
+
+/* Port registers */
+#define DEV_CLOCK_CFG				0x0
+#define DEV_CLOCK_CFG_LINK_SPEED_1000			1
+#define DEV_MAC_ENA_CFG				0x10
+#define		DEV_MAC_ENA_CFG_RX_ENA			BIT(4)
+#define		DEV_MAC_ENA_CFG_TX_ENA			BIT(0)
+#define DEV_MAC_IFG_CFG				0x24
+#define		DEV_MAC_IFG_CFG_TX_IFG(x)		((x) << 8)
+#define		DEV_MAC_IFG_CFG_RX_IFG2(x)		((x) << 4)
+#define		DEV_MAC_IFG_CFG_RX_IFG1(x)		(x)
+#define PCS1G_CFG				0x3c
+#define		PCS1G_MODE_CFG_SGMII_MODE_ENA		BIT(0)
+#define PCS1G_MODE_CFG				0x40
+#define PCS1G_SD_CFG				0x44
+#define PCS1G_ANEG_CFG				0x48
+#define		PCS1G_ANEG_CFG_ADV_ABILITY(x)		((x) << 16)
+
+#define QS_XTR_GRP_CFG(x)			(4 * (x))
+#define		QS_XTR_GRP_CFG_MODE(x)			((x) << 2)
+#define		QS_XTR_GRP_CFG_BYTE_SWAP		BIT(0)
+#define QS_INJ_GRP_CFG(x)			(0x24 + (x) * 4)
+#define		QS_INJ_GRP_CFG_MODE(x)			((x) << 2)
+#define		QS_INJ_GRP_CFG_BYTE_SWAP		BIT(0)
+
+#define IFH_INJ_BYPASS		BIT(31)
+#define IFH_TAG_TYPE_C		0
+#define MAC_VID			1
+#define CPU_PORT		11
+#define INTERNAL_PORT_MSK	0xFF
+#define IFH_LEN			4
+#define ETH_ALEN		6
+#define PGID_BROADCAST		13
+#define PGID_UNICAST		14
+
+static const char *const regs_names[] = {
+	"port0", "port1", "port2", "port3", "port4", "port5", "port6",
+	"port7", "port8", "port9", "port10",
+	"ana", "qs", "qsys", "rew", "sys", "hsio",
+};
+
+#define REGS_NAMES_COUNT ARRAY_SIZE(regs_names) + 1
+#define MAX_PORT 11
+
+enum serval_ctrl_regs {
+	ANA = MAX_PORT,
+	QS,
+	QSYS,
+	REW,
+	SYS,
+	HSIO,
+};
+
+#define SERVAL_MIIM_BUS_COUNT 2
+
+struct serval_phy_port_t {
+	size_t phy_addr;
+	struct mii_dev *bus;
+	u8 serdes_index;
+	u8 phy_mode;
+};
+
+struct serval_private {
+	void __iomem *regs[REGS_NAMES_COUNT];
+	struct mii_dev *bus[SERVAL_MIIM_BUS_COUNT];
+	struct serval_phy_port_t ports[MAX_PORT];
+};
+
+struct mscc_miim_dev {
+	void __iomem *regs;
+	phys_addr_t miim_base;
+	unsigned long miim_size;
+	struct mii_dev *bus;
+};
+
+static const unsigned long serval_regs_qs[] = {
+	[MSCC_QS_XTR_RD] = 0x8,
+	[MSCC_QS_XTR_FLUSH] = 0x18,
+	[MSCC_QS_XTR_DATA_PRESENT] = 0x1c,
+	[MSCC_QS_INJ_WR] = 0x2c,
+	[MSCC_QS_INJ_CTRL] = 0x34,
+};
+
+static const unsigned long serval_regs_ana_table[] = {
+	[MSCC_ANA_TABLES_MACHDATA] = 0x9b34,
+	[MSCC_ANA_TABLES_MACLDATA] = 0x9b38,
+	[MSCC_ANA_TABLES_MACACCESS] = 0x9b3c,
+};
+
+static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT];
+static int miim_count = -1;
+
+static int mscc_miim_wait_ready(struct mscc_miim_dev *miim)
+{
+	return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS,
+				 GCB_MIIM_STAT_BUSY, false, 250, false);
+}
+
+static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+	u32 val;
+	int ret;
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret)
+		goto out;
+
+	writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+	       GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ,
+	       miim->regs + GCB_MIIM_MII_CMD);
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret)
+		goto out;
+
+	val = readl(miim->regs + GCB_MIIM_DATA);
+	if (val & GCB_MIIM_DATA_ERROR) {
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = val & 0xFFFF;
+ out:
+	return ret;
+}
+
+static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg,
+			   u16 val)
+{
+	struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv;
+	int ret;
+
+	ret = mscc_miim_wait_ready(miim);
+	if (ret < 0)
+		goto out;
+
+	writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) |
+	       GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) |
+	       GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD);
+ out:
+	return ret;
+}
+
+static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base,
+					   unsigned long miim_size)
+{
+	struct mii_dev *bus;
+
+	bus = mdio_alloc();
+	if (!bus)
+		return NULL;
+
+	++miim_count;
+	sprintf(bus->name, "miim-bus%d", miim_count);
+
+	miim[miim_count].regs = ioremap(miim_base, miim_size);
+	miim[miim_count].miim_base = miim_base;
+	miim[miim_count].miim_size = miim_size;
+	bus->priv = &miim[miim_count];
+	bus->read = mscc_miim_read;
+	bus->write = mscc_miim_write;
+
+	if (mdio_register(bus))
+		return NULL;
+
+	miim[miim_count].bus = bus;
+	return bus;
+}
+
+static void serval_cpu_capture_setup(struct serval_private *priv)
+{
+	int i;
+
+	/* map the 8 CPU extraction queues to CPU port 11 */
+	writel(0, priv->regs[QSYS] + QSYS_QMAP);
+
+	for (i = 0; i <= 1; i++) {
+		/*
+		 * Do byte-swap and expect status after last data word
+		 * Extraction: Mode: manual extraction) | Byte_swap
+		 */
+		writel(QS_XTR_GRP_CFG_MODE(1) | QS_XTR_GRP_CFG_BYTE_SWAP,
+		       priv->regs[QS] + QS_XTR_GRP_CFG(i));
+		/*
+		 * Injection: Mode: manual extraction | Byte_swap
+		 */
+		writel(QS_INJ_GRP_CFG_MODE(1) | QS_INJ_GRP_CFG_BYTE_SWAP,
+		       priv->regs[QS] + QS_INJ_GRP_CFG(i));
+	}
+
+	for (i = 0; i <= 1; i++)
+		/* Enable IFH insertion/parsing on CPU ports */
+		writel(SYS_PORT_MODE_INCL_INJ_HDR(1) |
+		       SYS_PORT_MODE_INCL_XTR_HDR(1),
+		       priv->regs[SYS] + SYS_PORT_MODE(CPU_PORT + i));
+	/*
+	 * Setup the CPU port as VLAN aware to support switching frames
+	 * based on tags
+	 */
+	writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
+	       MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(CPU_PORT));
+
+	/* Disable learning (only RECV_ENA must be set) */
+	writel(ANA_PORT_PORT_CFG_RECV_ENA,
+	       priv->regs[ANA] + ANA_PORT_PORT_CFG(CPU_PORT));
+
+	/* Enable switching to/from cpu port */
+	setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(CPU_PORT),
+		     QSYS_SWITCH_PORT_MODE_PORT_ENA);
+
+	/* No pause on CPU port - not needed (off by default) */
+	clrbits_le32(priv->regs[SYS] + SYS_PAUSE_CFG(CPU_PORT),
+		     SYS_PAUSE_CFG_PAUSE_ENA);
+
+	setbits_le32(priv->regs[QSYS] + QSYS_EGR_NO_SHARING, BIT(CPU_PORT));
+}
+
+static void serval_port_init(struct serval_private *priv, int port)
+{
+	void __iomem *regs = priv->regs[port];
+
+	/* Enable PCS */
+	writel(PCS1G_MODE_CFG_SGMII_MODE_ENA, regs + PCS1G_CFG);
+
+	/* Disable Signal Detect */
+	writel(0, regs + PCS1G_SD_CFG);
+
+	/* Enable MAC RX and TX */
+	writel(DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA,
+	       regs + DEV_MAC_ENA_CFG);
+
+	/* Clear sgmii_mode_ena */
+	writel(0, regs + PCS1G_MODE_CFG);
+
+	/*
+	 * Clear sw_resolve_ena(bit 0) and set adv_ability to
+	 * something meaningful just in case
+	 */
+	writel(PCS1G_ANEG_CFG_ADV_ABILITY(0x20), regs + PCS1G_ANEG_CFG);
+
+	/* Set MAC IFG Gaps */
+	writel(DEV_MAC_IFG_CFG_TX_IFG(5) | DEV_MAC_IFG_CFG_RX_IFG1(5) |
+	       DEV_MAC_IFG_CFG_RX_IFG2(1), regs + DEV_MAC_IFG_CFG);
+
+	/* Set link speed and release all resets */
+	writel(DEV_CLOCK_CFG_LINK_SPEED_1000, regs + DEV_CLOCK_CFG);
+
+	/* Make VLAN aware for CPU traffic */
+	writel(ANA_PORT_VLAN_CFG_AWARE_ENA | ANA_PORT_VLAN_CFG_POP_CNT(1) |
+	       MAC_VID, priv->regs[ANA] + ANA_PORT_VLAN_CFG(port));
+
+	/* Enable the port in the core */
+	setbits_le32(priv->regs[QSYS] + QSYS_SWITCH_PORT_MODE(port),
+		     QSYS_SWITCH_PORT_MODE_PORT_ENA);
+}
+
+static void serdes_write(void __iomem *base, u32 addr)
+{
+	u32 data;
+
+	writel(HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT |
+	       HSIO_MCB_SERDES1G_CFG_ADDR(addr),
+	       base + HSIO_MCB_SERDES1G_CFG);
+
+	do {
+		data = readl(base + HSIO_MCB_SERDES1G_CFG);
+	} while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT);
+
+	mdelay(100);
+}
+
+static void serdes1g_setup(void __iomem *base, uint32_t addr,
+			   phy_interface_t interface)
+{
+	writel(0x0, base + HSIO_ANA_SERDES1G_SER_CFG);
+	writel(0x0, base + HSIO_DIG_SERDES1G_DFT_CFG0);
+	writel(HSIO_ANA_SERDES1G_IB_CFG_RESISTOR_CTRL(11) |
+	       HSIO_ANA_SERDES1G_IB_CFG_EQ_GAIN(0) |
+	       HSIO_ANA_SERDES1G_IB_CFG_ENA_OFFSET_COMP |
+	       HSIO_ANA_SERDES1G_IB_CFG_ENA_CMV_TERM |
+	       HSIO_ANA_SERDES1G_IB_CFG_ACJTAG_HYST(1),
+	       base + HSIO_ANA_SERDES1G_IB_CFG);
+	writel(HSIO_ANA_SERDES1G_DES_CFG_BW_HYST(7) |
+	       HSIO_ANA_SERDES1G_DES_CFG_BW_ANA(6) |
+	       HSIO_ANA_SERDES1G_DES_CFG_MBTR_CTRL(2) |
+	       HSIO_ANA_SERDES1G_DES_CFG_PHS_CTRL(6),
+	       base + HSIO_ANA_SERDES1G_DES_CFG);
+	writel(HSIO_ANA_SERDES1G_OB_CFG_RESISTOR_CTRL(1) |
+	       HSIO_ANA_SERDES1G_OB_CFG_VCM_CTRL(4) |
+	       HSIO_ANA_SERDES1G_OB_CFG_CMM_BIAS_CTRL(2) |
+	       HSIO_ANA_SERDES1G_OB_CFG_AMP_CTRL(12) |
+	       HSIO_ANA_SERDES1G_OB_CFG_SLP(3),
+	       base + HSIO_ANA_SERDES1G_OB_CFG);
+	writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+	       HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE,
+	       base + HSIO_ANA_SERDES1G_COMMON_CFG);
+	writel(HSIO_ANA_SERDES1G_PLL_CFG_FSM_ENA |
+	       HSIO_ANA_SERDES1G_PLL_CFG_FSM_CTRL_DATA(200) |
+	       HSIO_ANA_SERDES1G_PLL_CFG_ENA_RC_DIV2,
+	       base + HSIO_ANA_SERDES1G_PLL_CFG);
+	writel(HSIO_DIG_SERDES1G_MISC_CFG_LANE_RST,
+	       base + HSIO_DIG_SERDES1G_MISC_CFG);
+	serdes_write(base, addr);
+
+	writel(HSIO_ANA_SERDES1G_COMMON_CFG_IF_MODE |
+	       HSIO_ANA_SERDES1G_COMMON_CFG_ENA_LANE |
+	       HSIO_ANA_SERDES1G_COMMON_CFG_SYS_RST,
+	       base + HSIO_ANA_SERDES1G_COMMON_CFG);
+	serdes_write(base, addr);
+
+	writel(0x0, base + HSIO_DIG_SERDES1G_MISC_CFG);
+	serdes_write(base, addr);
+}
+
+static void serdes_setup(struct serval_private *priv)
+{
+	size_t mask;
+	int i = 0;
+
+	for (i = 0; i < MAX_PORT; ++i) {
+		if (!priv->ports[i].bus)
+			continue;
+
+		mask = BIT(priv->ports[i].serdes_index);
+		serdes1g_setup(priv->regs[HSIO], mask,
+			       priv->ports[i].phy_mode);
+	}
+}
+
+static int serval_switch_init(struct serval_private *priv)
+{
+	/* Reset switch & memories */
+	writel(SYS_SYSTEM_RST_MEM_ENA | SYS_SYSTEM_RST_MEM_INIT,
+	       priv->regs[SYS] + SYS_SYSTEM_RST_CFG);
+
+	if (wait_for_bit_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+			      SYS_SYSTEM_RST_MEM_INIT, false, 2000, false)) {
+		pr_err("Timeout in memory reset\n");
+		return -EIO;
+	}
+
+	/* Enable switch core */
+	setbits_le32(priv->regs[SYS] + SYS_SYSTEM_RST_CFG,
+		     SYS_SYSTEM_RST_CORE_ENA);
+
+	serdes_setup(priv);
+
+	return 0;
+}
+
+static int serval_initialize(struct serval_private *priv)
+{
+	int ret, i;
+
+	/* Initialize switch memories, enable core */
+	ret = serval_switch_init(priv);
+	if (ret)
+		return ret;
+
+	/* Flush queues */
+	mscc_flush(priv->regs[QS], serval_regs_qs);
+
+	/* Setup frame ageing - "2 sec" - The unit is 6.5us on serval */
+	writel(SYS_FRM_AGING_ENA | (20000000 / 65),
+	       priv->regs[SYS] + SYS_FRM_AGING);
+
+	for (i = 0; i < MAX_PORT; i++)
+		serval_port_init(priv, i);
+
+	serval_cpu_capture_setup(priv);
+
+	debug("Ports enabled\n");
+
+	return 0;
+}
+
+static int serval_write_hwaddr(struct udevice *dev)
+{
+	struct serval_private *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+
+	mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
+			   pdata->enetaddr, PGID_UNICAST);
+
+	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+
+	return 0;
+}
+
+static int serval_start(struct udevice *dev)
+{
+	struct serval_private *priv = dev_get_priv(dev);
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	const unsigned char mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff,
+					      0xff };
+	int ret;
+
+	ret = serval_initialize(priv);
+	if (ret)
+		return ret;
+
+	/* Set MAC address tables entries for CPU redirection */
+	mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table, mac,
+			   PGID_BROADCAST);
+
+	writel(BIT(CPU_PORT) | INTERNAL_PORT_MSK,
+	       priv->regs[ANA] + ANA_PGID(PGID_BROADCAST));
+
+	/* It should be setup latter in serval_write_hwaddr */
+	mscc_mac_table_add(priv->regs[ANA], serval_regs_ana_table,
+			   pdata->enetaddr, PGID_UNICAST);
+
+	writel(BIT(CPU_PORT), priv->regs[ANA] + ANA_PGID(PGID_UNICAST));
+	return 0;
+}
+
+static void serval_stop(struct udevice *dev)
+{
+	writel(ICPU_RESET_CORE_RST_PROTECT, BASE_CFG + ICPU_RESET);
+	writel(PERF_SOFT_RST_SOFT_CHIP_RST, BASE_DEVCPU_GCB + PERF_SOFT_RST);
+}
+
+static int serval_send(struct udevice *dev, void *packet, int length)
+{
+	struct serval_private *priv = dev_get_priv(dev);
+	u32 ifh[IFH_LEN];
+	u32 *buf = packet;
+
+	/*
+	 * Generate the IFH for frame injection
+	 *
+	 * The IFH is a 128bit-value
+	 * bit 127: bypass the analyzer processing
+	 * bit 57-67: destination mask
+	 * bit 28-29: pop_cnt: 3 disables all rewriting of the frame
+	 * bit 20-27: cpu extraction queue mask
+	 * bit 16: tag type 0: C-tag, 1: S-tag
+	 * bit 0-11: VID
+	 */
+	ifh[0] = IFH_INJ_BYPASS;
+	ifh[1] = (0x07);
+	ifh[2] = (0x7f) << 25;
+	ifh[3] = (IFH_TAG_TYPE_C << 16);
+
+	return mscc_send(priv->regs[QS], serval_regs_qs,
+			 ifh, IFH_LEN, buf, length);
+}
+
+static int serval_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct serval_private *priv = dev_get_priv(dev);
+	u32 *rxbuf = (u32 *)net_rx_packets[0];
+	int byte_cnt = 0;
+
+	byte_cnt = mscc_recv(priv->regs[QS], serval_regs_qs, rxbuf, IFH_LEN,
+			     false);
+
+	*packetp = net_rx_packets[0];
+
+	return byte_cnt;
+}
+
+static struct mii_dev *get_mdiobus(phys_addr_t base, unsigned long size)
+{
+	int i = 0;
+
+	for (i = 0; i < SERVAL_MIIM_BUS_COUNT; ++i)
+		if (miim[i].miim_base == base && miim[i].miim_size == size)
+			return miim[i].bus;
+
+	return NULL;
+}
+
+static void add_port_entry(struct serval_private *priv, size_t index,
+			   size_t phy_addr, struct mii_dev *bus,
+			   u8 serdes_index, u8 phy_mode)
+{
+	priv->ports[index].phy_addr = phy_addr;
+	priv->ports[index].bus = bus;
+	priv->ports[index].serdes_index = serdes_index;
+	priv->ports[index].phy_mode = phy_mode;
+}
+
+static int serval_probe(struct udevice *dev)
+{
+	struct serval_private *priv = dev_get_priv(dev);
+	int i, ret;
+	struct resource res;
+	fdt32_t faddr;
+	phys_addr_t addr_base;
+	unsigned long addr_size;
+	ofnode eth_node, node, mdio_node;
+	size_t phy_addr;
+	struct mii_dev *bus;
+	struct ofnode_phandle_args phandle;
+	struct phy_device *phy;
+
+	if (!priv)
+		return -EINVAL;
+
+	/* Get registers and map them to the private structure */
+	for (i = 0; i < ARRAY_SIZE(regs_names); i++) {
+		priv->regs[i] = dev_remap_addr_name(dev, regs_names[i]);
+		if (!priv->regs[i]) {
+			debug
+			    ("Error can't get regs base addresses for %s\n",
+			     regs_names[i]);
+			return -ENOMEM;
+		}
+	}
+
+	/* Initialize miim buses */
+	memset(&miim, 0x0, sizeof(miim) * SERVAL_MIIM_BUS_COUNT);
+
+	/* iterate all the ports and find out on which bus they are */
+	i = 0;
+	eth_node = dev_read_first_subnode(dev);
+	for (node = ofnode_first_subnode(eth_node);
+	     ofnode_valid(node);
+	     node = ofnode_next_subnode(node)) {
+		if (ofnode_read_resource(node, 0, &res))
+			return -ENOMEM;
+		i = res.start;
+
+		ret = ofnode_parse_phandle_with_args(node, "phy-handle", NULL,
+						     0, 0, &phandle);
+		if (ret)
+			continue;
+
+		/* Get phy address on mdio bus */
+		if (ofnode_read_resource(phandle.node, 0, &res))
+			return -ENOMEM;
+		phy_addr = res.start;
+
+		/* Get mdio node */
+		mdio_node = ofnode_get_parent(phandle.node);
+
+		if (ofnode_read_resource(mdio_node, 0, &res))
+			return -ENOMEM;
+		faddr = cpu_to_fdt32(res.start);
+
+		addr_base = ofnode_translate_address(mdio_node, &faddr);
+		addr_size = res.end - res.start;
+
+		/* If the bus is new then create a new bus */
+		if (!get_mdiobus(addr_base, addr_size))
+			priv->bus[miim_count] =
+				serval_mdiobus_init(addr_base, addr_size);
+
+		/* Connect mdio bus with the port */
+		bus = get_mdiobus(addr_base, addr_size);
+
+		/* Get serdes info */
+		ret = ofnode_parse_phandle_with_args(node, "phys", NULL,
+						     3, 0, &phandle);
+		if (ret)
+			return -ENOMEM;
+
+		add_port_entry(priv, i, phy_addr, bus, phandle.args[1],
+			       phandle.args[2]);
+	}
+
+	for (i = 0; i < MAX_PORT; i++) {
+		if (!priv->ports[i].bus)
+			continue;
+
+		phy = phy_connect(priv->ports[i].bus,
+				  priv->ports[i].phy_addr, dev,
+				  PHY_INTERFACE_MODE_NONE);
+		if (phy)
+			board_phy_config(phy);
+	}
+
+	return 0;
+}
+
+static int serval_remove(struct udevice *dev)
+{
+	struct serval_private *priv = dev_get_priv(dev);
+	int i;
+
+	for (i = 0; i < SERVAL_MIIM_BUS_COUNT; i++) {
+		mdio_unregister(priv->bus[i]);
+		mdio_free(priv->bus[i]);
+	}
+
+	return 0;
+}
+
+static const struct eth_ops serval_ops = {
+	.start        = serval_start,
+	.stop         = serval_stop,
+	.send         = serval_send,
+	.recv         = serval_recv,
+	.write_hwaddr = serval_write_hwaddr,
+};
+
+static const struct udevice_id mscc_serval_ids[] = {
+	{.compatible = "mscc,vsc7418-switch"},
+	{ /* Sentinel */ }
+};
+
+U_BOOT_DRIVER(serval) = {
+	.name				= "serval-switch",
+	.id				= UCLASS_ETH,
+	.of_match			= mscc_serval_ids,
+	.probe				= serval_probe,
+	.remove				= serval_remove,
+	.ops				= &serval_ops,
+	.priv_auto_alloc_size		= sizeof(struct serval_private),
+	.platdata_auto_alloc_size	= sizeof(struct eth_pdata),
+};
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index fb794adae725d8e1736dedd2ed5c35d31a39b610..2830f765877bbc9ca49f330923f051528178fffc 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -133,7 +133,7 @@ config MPC8XX_SPI
 
 config MT7621_SPI
 	bool "MediaTek MT7621 SPI driver"
-	depends on ARCH_MT7620
+	depends on SOC_MT7628
 	help
 	  Enable the MT7621 SPI driver. This driver can be used to access
 	  the SPI NOR flash on platforms embedding this Ralink / MediaTek
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 16d47b88858ed2ac31b316ef7e2ad22ee655a509..f909d40f45588e27af74f626770268458fafc165 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -143,7 +143,7 @@ config WDT_AT91
 
 config WDT_MT7621
 	bool "MediaTek MT7621 watchdog timer support"
-	depends on WDT && ARCH_MT7620
+	depends on WDT && SOC_MT7628
 	help
 	   Select this to enable Ralink / Mediatek watchdog timer,
 	   which can be found on some MediaTek chips.
diff --git a/include/dt-bindings/mscc/luton_data.h b/include/dt-bindings/mscc/luton_data.h
new file mode 100644
index 0000000000000000000000000000000000000000..e488567729d1aa3e95033b77a81f0097bd93a7d4
--- /dev/null
+++ b/include/dt-bindings/mscc/luton_data.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#ifndef _LUTON_DATA_H_
+#define _LUTON_DATA_H_
+
+#define SERDES6G(x)     (x)
+#define SERDES6G_MAX    SERDES6G(5)
+#define SERDES_MAX      (SERDES6G_MAX)
+
+/* similar with phy_interface_t */
+#define PHY_MODE_SGMII  2
+#define PHY_MODE_QSGMII 4
+
+#endif
diff --git a/include/dt-bindings/mscc/ocelot_data.h b/include/dt-bindings/mscc/ocelot_data.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a5a1bf36e87a3f386718cfb24947cb1576cb752
--- /dev/null
+++ b/include/dt-bindings/mscc/ocelot_data.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#ifndef _OCELOT_DATA_H_
+#define _OCELOT_DATA_H_
+
+#define SERDES1G(x)     (x)
+#define SERDES1G_MAX    SERDES1G(7)
+#define SERDES6G(x)     (SERDES1G_MAX + 1 + (x))
+#define SERDES6G_MAX    SERDES6G(11)
+#define SERDES_MAX      (SERDES6G_MAX + 1)
+
+/* similar with phy_interface_t */
+#define PHY_MODE_SGMII  2
+#define PHY_MODE_QSGMII 4
+
+#endif
diff --git a/include/dt-bindings/mscc/serval_data.h b/include/dt-bindings/mscc/serval_data.h
new file mode 100644
index 0000000000000000000000000000000000000000..b374fda05e7c8e86c4de9b8d4cc9d1211ea277e9
--- /dev/null
+++ b/include/dt-bindings/mscc/serval_data.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _SERVAL_DATA_H_
+#define _SERVAL_DATA_H_
+
+#define SERDES1G(x)     (x)
+#define SERDES1G_MAX    SERDES1G(9)
+#define SERDES6G(x)     (SERDES1G_MAX + 1 + (x))
+#define SERDES6G_MAX    SERDES6G(11)
+#define SERDES_MAX      (SERDES6G_MAX + 1)
+
+/* similar with phy_interface_t */
+#define PHY_MODE_SGMII  2
+#define PHY_MODE_QSGMII 4
+
+#endif