[rdkb][common][bsp][Refactor and sync kernl from openwrt]

[Description]
371e2ed [kernel][common][eth][Add phylink_pcs support for the SGMII/USXGMII]
e7f06c4 [MAC80211][wed][remove wed rx_drv interrupt]
ea09f72 [MAC80211][hnat][Fix DL floodind issue for the C50 UDP BiDi test]
619bce8 [kernel][mt7986][spi][spi-calibration: Fix probe flow error if flash devices don't need calibration]
c9239e3 [kernel][mt7986][spim][dts: Fix SPIM-NAND/NOR max frequency]
63cebb7 [kernel][mt7986][spi][spi-calibration: Add support for 4B mode NOR flashes]
889cfec [kernel][common][eth][Fix CISCO FET-10G SFP+ IOT issue]

[Release-log]

Change-Id: I9c01ed134f843403614182575be97d694a028d25
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/430-v6.3-ubi-Fix-failure-attaching-when-vid_hdr-offset-equals.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/430-v6.3-ubi-Fix-failure-attaching-when-vid_hdr-offset-equals.patch
new file mode 100644
index 0000000..afb8e5e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/430-v6.3-ubi-Fix-failure-attaching-when-vid_hdr-offset-equals.patch
@@ -0,0 +1,69 @@
+From 1e020e1b96afdecd20680b5b5be2a6ffc3d27628 Mon Sep 17 00:00:00 2001
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+Date: Mon, 6 Mar 2023 09:33:08 +0800
+Subject: [PATCH] ubi: Fix failure attaching when vid_hdr offset equals to
+ (sub)page size
+
+Following process will make ubi attaching failed since commit
+1b42b1a36fc946 ("ubi: ensure that VID header offset ... size"):
+
+ID="0xec,0xa1,0x00,0x15" # 128M 128KB 2KB
+modprobe nandsim id_bytes=$ID
+flash_eraseall /dev/mtd0
+modprobe ubi mtd="0,2048"  # set vid_hdr offset as 2048 (one page)
+(dmesg):
+  ubi0 error: ubi_attach_mtd_dev [ubi]: VID header offset 2048 too large.
+  UBI error: cannot attach mtd0
+  UBI error: cannot initialize UBI, error -22
+
+Rework original solution, the key point is making sure
+'vid_hdr_shift + UBI_VID_HDR_SIZE < ubi->vid_hdr_alsize',
+so we should check vid_hdr_shift rather not vid_hdr_offset.
+Then, ubi still support (sub)page aligined VID header offset.
+
+Fixes: 1b42b1a36fc946 ("ubi: ensure that VID header offset ... size")
+Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Tested-by: Nicolas Schichan <nschichan@freebox.fr>
+Tested-by: Miquel Raynal <miquel.raynal@bootlin.com> # v5.10, v4.19
+Signed-off-by: Richard Weinberger <richard@nod.at>
+---
+ drivers/mtd/ubi/build.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -644,12 +644,6 @@ static int io_init(struct ubi_device *ub
+ 	ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size);
+ 	ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
+ 
+-	if (ubi->vid_hdr_offset && ((ubi->vid_hdr_offset + UBI_VID_HDR_SIZE) >
+-	    ubi->vid_hdr_alsize)) {
+-		ubi_err(ubi, "VID header offset %d too large.", ubi->vid_hdr_offset);
+-		return -EINVAL;
+-	}
+-
+ 	dbg_gen("min_io_size      %d", ubi->min_io_size);
+ 	dbg_gen("max_write_size   %d", ubi->max_write_size);
+ 	dbg_gen("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
+@@ -667,6 +661,21 @@ static int io_init(struct ubi_device *ub
+ 						ubi->vid_hdr_aloffset;
+ 	}
+ 
++	/*
++	 * Memory allocation for VID header is ubi->vid_hdr_alsize
++	 * which is described in comments in io.c.
++	 * Make sure VID header shift + UBI_VID_HDR_SIZE not exceeds
++	 * ubi->vid_hdr_alsize, so that all vid header operations
++	 * won't access memory out of bounds.
++	 */
++	if ((ubi->vid_hdr_shift + UBI_VID_HDR_SIZE) > ubi->vid_hdr_alsize) {
++		ubi_err(ubi, "Invalid VID header offset %d, VID header shift(%d)"
++			" + VID header size(%zu) > VID header aligned size(%d).",
++			ubi->vid_hdr_offset, ubi->vid_hdr_shift,
++			UBI_VID_HDR_SIZE, ubi->vid_hdr_alsize);
++		return -EINVAL;
++	}
++
+ 	/* Similar for the data offset */
+ 	ubi->leb_start = ubi->vid_hdr_offset + UBI_VID_HDR_SIZE;
+ 	ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
index 49c01ad..17984f4 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
@@ -175,6 +175,7 @@
     file://417-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch \
     file://420-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch \
     file://430-mtd-spinand-macronix-Add-support-for-MX31LF1GE4BC.patch \
+    file://430-v6.3-ubi-Fix-failure-attaching-when-vid_hdr-offset-equals.patch \
     file://431-mtd-spinand-macronix-Add-support-for-MX31UF1GE4BC.patch \
     file://432-mtd-spinand-macronix-Add-support-for-MX35LFxGE4AD.patch \
     file://433-mtd-spinand-macronix-Add-support-for-MX35LFxG24AD.patch \
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
index b21daea..cc19a5e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/pending-5.4/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
@@ -8,7 +8,7 @@
 
 --- a/drivers/mtd/ubi/build.c
 +++ b/drivers/mtd/ubi/build.c
-@@ -1168,6 +1168,73 @@ static struct mtd_info * __init open_mtd
+@@ -1177,6 +1177,73 @@ static struct mtd_info * __init open_mtd
  	return mtd;
  }
  
@@ -82,7 +82,7 @@
  static int __init ubi_init(void)
  {
  	int err, i, k;
-@@ -1251,6 +1318,12 @@ static int __init ubi_init(void)
+@@ -1260,6 +1327,12 @@ static int __init ubi_init(void)
  		}
  	}
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts
index 6f23b2f..bc505d6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-gsw-spim-nand-rfb.dts
@@ -173,7 +173,7 @@
 		#size-cells = <1>;
 		compatible = "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
@@ -183,7 +183,7 @@
 		#size-cells = <1>;
 		compatible = "spi-nand";
 		reg = <1>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts
index 61b68af..0fd7371 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nand-rfb.dts
@@ -187,7 +187,7 @@
 		#size-cells = <1>;
 		compatible = "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
@@ -197,7 +197,7 @@
 		#size-cells = <1>;
 		compatible = "spi-nand";
 		reg = <1>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-gsw-spim-nand-rfb.dts
index 997306c..973fb18 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-gsw-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-gsw-spim-nand-rfb.dts
@@ -144,7 +144,7 @@
 		#size-cells = <1>;
 		compatible = "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
@@ -154,7 +154,7 @@
 		#size-cells = <1>;
 		compatible = "spi-nand";
 		reg = <1>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nand-rfb.dts
index 1dc1551..5f4d1fa 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986b-2500wan-spim-nand-rfb.dts
@@ -158,7 +158,7 @@
 		#size-cells = <1>;
 		compatible = "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
@@ -168,7 +168,7 @@
 		#size-cells = <1>;
 		compatible = "spi-nand";
 		reg = <1>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts
index 6f23b2f..bc505d6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-gsw-spim-nand-rfb.dts
@@ -173,7 +173,7 @@
 		#size-cells = <1>;
 		compatible = "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
@@ -183,7 +183,7 @@
 		#size-cells = <1>;
 		compatible = "spi-nand";
 		reg = <1>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts
index 61b68af..0fd7371 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nand-rfb.dts
@@ -187,7 +187,7 @@
 		#size-cells = <1>;
 		compatible = "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
@@ -197,7 +197,7 @@
 		#size-cells = <1>;
 		compatible = "spi-nand";
 		reg = <1>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-gsw-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-gsw-spim-nand-rfb.dts
index 997306c..973fb18 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-gsw-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-gsw-spim-nand-rfb.dts
@@ -144,7 +144,7 @@
 		#size-cells = <1>;
 		compatible = "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
@@ -154,7 +154,7 @@
 		#size-cells = <1>;
 		compatible = "spi-nand";
 		reg = <1>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nand-rfb.dts
index 1dc1551..5f4d1fa 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-spim-nand-rfb.dts
@@ -158,7 +158,7 @@
 		#size-cells = <1>;
 		compatible = "jedec,spi-nor";
 		reg = <0>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
@@ -168,7 +168,7 @@
 		#size-cells = <1>;
 		compatible = "spi-nand";
 		reg = <1>;
-		spi-max-frequency = <20000000>;
+		spi-max-frequency = <52000000>;
 		spi-tx-buswidth = <4>;
 		spi-rx-buswidth = <4>;
 	};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
index f246e85..eebec74 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_reset.c
@@ -209,9 +209,9 @@
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
 		mtk_dump_reg(eth, "XGMAC0", 0x12000, 0x300);
 		mtk_dump_reg(eth, "XGMAC1", 0x13000, 0x300);
-		mtk_dump_usxgmii(eth->xgmii->regmap_usxgmii[0],
+		mtk_dump_usxgmii(eth->usxgmii->pcs[0].regmap,
 			"USXGMII0", 0, 0x1000);
-		mtk_dump_usxgmii(eth->xgmii->regmap_usxgmii[1],
+		mtk_dump_usxgmii(eth->usxgmii->pcs[1].regmap,
 			"USXGMII1", 0, 0x1000);
 	}
 }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 134e579..1368a7b 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -500,6 +500,34 @@
 		mtk_w32(eth, mcr, MTK_MAC_MCR(mac->id));
 }
 
+static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config,
+					      phy_interface_t interface)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	struct mtk_eth *eth = mac->hw;
+	unsigned int sid;
+
+	if (interface == PHY_INTERFACE_MODE_SGMII ||
+	    phy_interface_mode_is_8023z(interface)) {
+		sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
+		       0 : mtk_mac2xgmii_id(eth, mac->id);
+
+		return mtk_sgmii_select_pcs(eth->sgmii, sid);
+	} else if (interface == PHY_INTERFACE_MODE_USXGMII ||
+		   interface == PHY_INTERFACE_MODE_10GKR ||
+		   interface == PHY_INTERFACE_MODE_5GBASER) {
+		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) &&
+		    mac->id != MTK_GMAC1_ID) {
+			sid = mtk_mac2xgmii_id(eth, mac->id);
+
+			return mtk_usxgmii_select_pcs(eth->usxgmii, sid);
+		}
+	}
+
+	return NULL;
+}
+
 static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
 			   const struct phylink_link_state *state)
 {
@@ -649,38 +677,13 @@
 		sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
 		       0 : mac->id;
 
-		/* Setup SGMIISYS with the determined property */
-		if (state->interface != PHY_INTERFACE_MODE_SGMII)
-			err = mtk_sgmii_setup_mode_force(eth->xgmii, sid,
-							 state);
-		else
-			err = mtk_sgmii_setup_mode_an(eth->xgmii, sid);
-
-		if (err) {
-			spin_unlock(&eth->syscfg0_lock);
-			goto init_err;
-		}
-
-		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
-				   SYSCFG0_SGMII_MASK, val);
+		/* Save the syscfg0 value for mac_finish */
+		mac->syscfg0 = val;
 		spin_unlock(&eth->syscfg0_lock);
 	} else if (state->interface == PHY_INTERFACE_MODE_USXGMII ||
 		   state->interface == PHY_INTERFACE_MODE_10GKR ||
 		   state->interface == PHY_INTERFACE_MODE_5GBASER) {
-		sid = mac->id;
-
-		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) &&
-		    sid != MTK_GMAC1_ID) {
-			if (phylink_autoneg_inband(mode))
-				err = mtk_usxgmii_setup_mode_force(eth->xgmii, sid,
-								   state);
-			else
-				err = mtk_usxgmii_setup_mode_an(eth->xgmii, sid,
-								SPEED_10000);
-
-			if (err)
-				goto init_err;
-		}
+		/* Nothing to do */
 	} else if (phylink_autoneg_inband(mode)) {
 		dev_err(eth->dev,
 			"In-band mode not supported in non SGMII mode!\n");
@@ -730,6 +733,10 @@
 			}
 		}
 
+		/* FIXME: In current hardware design, we have to reset FE
+		 * when swtiching XGDM to GDM. Therefore, here trigger an SER
+		 * to let GDM go back to the initial state.
+		 */
 		if (mac->type != mac_type) {
 			if (atomic_read(&reset_pending) == 0) {
 				atomic_inc(&force);
@@ -752,6 +759,22 @@
 		mac->id, phy_modes(state->interface), err);
 }
 
+static int mtk_mac_finish(struct phylink_config *config, unsigned int mode,
+			  phy_interface_t interface)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	struct mtk_eth *eth = mac->hw;
+
+	/* Enable SGMII */
+	if (interface == PHY_INTERFACE_MODE_SGMII ||
+	    phy_interface_mode_is_8023z(interface))
+		regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
+				   SYSCFG0_SGMII_MASK, mac->syscfg0);
+
+	return 0;
+}
+
 static int mtk_mac_pcs_get_state(struct phylink_config *config,
 				 struct phylink_link_state *state)
 {
@@ -764,7 +787,7 @@
 		if (mac->id == MTK_GMAC2_ID)
 			sts = sts >> 16;
 
-		state->duplex = 1;
+		state->duplex = DUPLEX_FULL;
 
 		switch (FIELD_GET(MTK_USXGMII_PCS_MODE, sts)) {
 		case 0:
@@ -785,18 +808,19 @@
 		state->link = FIELD_GET(MTK_USXGMII_PCS_LINK, sts);
 	} else if (mac->type == MTK_GDM_TYPE) {
 		struct mtk_eth *eth = mac->hw;
-		struct mtk_xgmii *ss = eth->xgmii;
+		struct mtk_sgmii *ss = eth->sgmii;
 		u32 id = mtk_mac2xgmii_id(eth, mac->id);
 		u32 pmsr = mtk_r32(mac->hw, MTK_MAC_MSR(mac->id));
-		u32 val = 0;
+		u32 rgc3, val = 0;
 
-		regmap_read(ss->regmap_sgmii[id], SGMSYS_PCS_CONTROL_1, &val);
+		regmap_read(ss->pcs[id].regmap, SGMSYS_PCS_CONTROL_1, &val);
 
 		state->interface = mac->interface;
 		state->link = FIELD_GET(SGMII_LINK_STATYS, val);
 
 		if (FIELD_GET(SGMII_AN_ENABLE, val)) {
-			regmap_read(ss->regmap_sgmii[id], SGMII_PCS_SPEED_ABILITY, &val);
+			regmap_read(ss->pcs[id].regmap,
+				    SGMII_PCS_SPEED_ABILITY, &val);
 
 			val = val >> 16;
 
@@ -814,9 +838,10 @@
 				break;
 			}
 		} else {
-			regmap_read(ss->regmap_sgmii[id], SGMSYS_SGMII_MODE, &val);
+			regmap_read(ss->pcs[id].regmap,
+				    SGMSYS_SGMII_MODE, &val);
 
-			state->duplex = !FIELD_GET(SGMII_DUPLEX_FULL, val);
+			state->duplex = !FIELD_GET(SGMII_DUPLEX_HALF, val);
 
 			switch (FIELD_GET(SGMII_SPEED_MASK, val)) {
 			case 0:
@@ -826,8 +851,10 @@
 				state->speed = SPEED_100;
 				break;
 			case 2:
-				regmap_read(ss->regmap_sgmii[id], ss->ana_rgc3, &val);
-				state->speed = (FIELD_GET(RG_PHY_SPEED_3_125G, val)) ? SPEED_2500 : SPEED_1000;
+				regmap_read(ss->pcs[id].regmap,
+					    ss->pcs[id].ana_rgc3, &val);
+				rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, val);
+				state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
 				break;
 			}
 		}
@@ -842,15 +869,6 @@
 	return 1;
 }
 
-static void mtk_mac_an_restart(struct phylink_config *config)
-{
-	struct mtk_mac *mac = container_of(config, struct mtk_mac,
-					   phylink_config);
-
-	if (mac->type != MTK_XGDM_TYPE)
-		mtk_sgmii_restart_an(mac->hw, mac->id);
-}
-
 static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
 			      phy_interface_t interface)
 {
@@ -1074,9 +1092,10 @@
 
 static const struct phylink_mac_ops mtk_phylink_ops = {
 	.validate = mtk_validate,
+	.mac_select_pcs = mtk_mac_select_pcs,
 	.mac_link_state = mtk_mac_pcs_get_state,
-	.mac_an_restart = mtk_mac_an_restart,
 	.mac_config = mtk_mac_config,
+	.mac_finish = mtk_mac_finish,
 	.mac_link_down = mtk_mac_link_down,
 	.mac_link_up = mtk_mac_link_up,
 };
@@ -3397,6 +3416,7 @@
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	struct mtk_phylink_priv *phylink_priv = &mac->phylink_priv;
+	u32 id = mtk_mac2xgmii_id(eth, mac->id);
 	int err, i;
 	struct device_node *phy_node;
 
@@ -3472,8 +3492,9 @@
 	phylink_start(mac->phylink);
 	netif_start_queue(dev);
 	phy_node = of_parse_phandle(mac->of_node, "phy-handle", 0);
-	if (!phy_node && eth->xgmii->regmap_sgmii[mac->id])
-		regmap_write(eth->xgmii->regmap_sgmii[mac->id], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+	if (!phy_node && eth->sgmii->pcs[id].regmap)
+		regmap_write(eth->sgmii->pcs[id].regmap,
+			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
 
 	mtk_gdm_config(eth, mac->id, MTK_GDMA_TO_PDMA);
 
@@ -3508,6 +3529,7 @@
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int i;
+	u32 id = mtk_mac2xgmii_id(eth, mac->id);
 	u32 val = 0;
 	struct device_node *phy_node;
 
@@ -3515,10 +3537,12 @@
 	netif_tx_disable(dev);
 
 	phy_node = of_parse_phandle(mac->of_node, "phy-handle", 0);
-	if (!phy_node && eth->xgmii->regmap_sgmii[mac->id]) {
-		regmap_read(eth->xgmii->regmap_sgmii[mac->id], SGMSYS_QPHY_PWR_STATE_CTRL, &val);
+	if (!phy_node && eth->sgmii->pcs[id].regmap) {
+		regmap_read(eth->sgmii->pcs[id].regmap,
+			    SGMSYS_QPHY_PWR_STATE_CTRL, &val);
 		val |= SGMII_PHYA_PWD;
-		regmap_write(eth->xgmii->regmap_sgmii[mac->id], SGMSYS_QPHY_PWR_STATE_CTRL, val);
+		regmap_write(eth->sgmii->pcs[id].regmap,
+			     SGMSYS_QPHY_PWR_STATE_CTRL, val);
 	}
 
 	//GMAC RX disable
@@ -4589,29 +4613,24 @@
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
-		eth->xgmii = devm_kzalloc(eth->dev, sizeof(*eth->xgmii),
+		eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
 					  GFP_KERNEL);
-		if (!eth->xgmii)
+		if (!eth->sgmii)
 			return -ENOMEM;
 
-		eth->xgmii->eth = eth;
-		err = mtk_sgmii_init(eth->xgmii, pdev->dev.of_node,
+		err = mtk_sgmii_init(eth, pdev->dev.of_node,
 				     eth->soc->ana_rgc3);
-
 		if (err)
 			return err;
 	}
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) {
-		err = mtk_usxgmii_init(eth->xgmii, pdev->dev.of_node);
-		if (err)
-			return err;
-
-		err = mtk_xfi_pextp_init(eth->xgmii, pdev->dev.of_node);
-		if (err)
-			return err;
+		eth->usxgmii = devm_kzalloc(eth->dev, sizeof(*eth->usxgmii),
+					    GFP_KERNEL);
+		if (!eth->usxgmii)
+			return -ENOMEM;
 
-		err = mtk_xfi_pll_init(eth->xgmii, pdev->dev.of_node);
+		err = mtk_usxgmii_init(eth, pdev->dev.of_node);
 		if (err)
 			return err;
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 6035f46..646e557 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -852,7 +852,7 @@
 #define SGMII_SPEED_10			0x0
 #define SGMII_SPEED_100			BIT(2)
 #define SGMII_SPEED_1000		BIT(3)
-#define SGMII_DUPLEX_FULL		BIT(4)
+#define SGMII_DUPLEX_HALF		BIT(4)
 #define SGMII_IF_MODE_BIT5		BIT(5)
 #define SGMII_REMOTE_FAULT_DIS		BIT(8)
 #define SGMII_CODE_SYNC_SET_VAL		BIT(9)
@@ -902,7 +902,21 @@
 
 /* Register to control PCS AN */
 #define RG_PCS_AN_CTRL0		0x810
-#define RG_AN_ENABLE		BIT(0)
+#define USXGMII_AN_RESTART	BIT(31)
+#define USXGMII_AN_ENABLE	BIT(0)
+
+/* Register to control PCS AN */
+#define RG_PCS_AN_STS0		0x81C
+#define USXGMII_LPA_SPEED_MASK	GENMASK(11, 9)
+#define USXGMII_LPA_SPEED_10	0
+#define USXGMII_LPA_SPEED_100	1
+#define USXGMII_LPA_SPEED_1000	2
+#define USXGMII_LPA_SPEED_10000	3
+#define USXGMII_LPA_SPEED_2500	4
+#define USXGMII_LPA_SPEED_5000	5
+#define USXGMII_LPA_DUPLEX	BIT(12)
+#define USXGMII_LPA_LINK	BIT(15)
+#define USXGMII_LPA_LATCH	BIT(31)
 
 /* Register to control USXGMII XFI PLL digital */
 #define XFI_PLL_DIG_GLB8	0x08
@@ -1610,24 +1624,66 @@
 #define MTK_SGMII_PN_SWAP	       BIT(16)
 #define MTK_HAS_FLAGS(flags, _x)       (((flags) & (_x)) == (_x))
 
-/* struct mtk_xgmii -  This is the structure holding sgmii/usxgmii regmap and
- *		       its characteristics
- * @regmap:            The register map pointing at the range used to setup
- *                     SGMII/USXGMII modes
- * @flags:             The enum refers to which mode the sgmii wants to run on
- * @ana_rgc3:          The offset refers to register ANA_RGC3 related to regmap
+/* struct mtk_sgmii_pcs - This structure holds each sgmii regmap and associated
+ *			data
+ * @regmap:		The register map pointing at the range used to setup
+ *			SGMII modes
+ * @regmap_pextp:	The register map pointing at the range used to setup
+ *			PHYA
+ * @ana_rgc3:		The offset refers to register ANA_RGC3 related to regmap
+ * @id:			The element is used to record the index of PCS
+ * @pcs:		Phylink PCS structure
  */
+struct mtk_sgmii_pcs {
+	struct mtk_eth		*eth;
+	struct regmap		*regmap;
+	struct regmap		*regmap_pextp;
+	phy_interface_t		interface;
+	u32			flags;
+	u32			ana_rgc3;
+	u8			id;
+	struct phylink_pcs	pcs;
+};
 
-struct mtk_xgmii {
-	struct mtk_eth	*eth;
-	struct regmap   *regmap_sgmii[MTK_MAX_DEVS];
-	struct regmap   *regmap_usxgmii[MTK_MAX_DEVS];
-	struct regmap   *regmap_pextp[MTK_MAX_DEVS];
-	struct regmap	*regmap_pll;
-	u32             flags[MTK_MAX_DEVS];
-	u32             ana_rgc3;
+/* struct mtk_sgmii -	This is the structure holding sgmii regmap and its
+ *			characteristics
+ * @pll:		The register map pointing at the range used to setup
+ *			PLL
+ * @pcs			Array of individual PCS structures
+ */
+struct mtk_sgmii {
+	struct mtk_sgmii_pcs	pcs[MTK_MAX_DEVS];
+	struct regmap		*pll;
 };
 
+/* struct mtk_usxgmii_pcs - This structure holds each usxgmii regmap and
+ *			associated data
+ * @regmap:		The register map pointing at the range used to setup
+ *			USXGMII modes
+ * @regmap_pextp:	The register map pointing at the range used to setup
+ *			PHYA
+ * @id:			The element is used to record the index of PCS
+ * @pcs:		Phylink PCS structure
+ */
+struct mtk_usxgmii_pcs {
+	struct mtk_eth		*eth;
+	struct regmap		*regmap;
+	struct regmap		*regmap_pextp;
+	phy_interface_t		interface;
+	u8			id;
+	struct phylink_pcs	pcs;
+};
+
+/* struct mtk_usxgmii -	This is the structure holding usxgmii regmap and its
+ *			characteristics
+ * @pll:		The register map pointing at the range used to setup
+ *			PLL
+ * @pcs			Array of individual PCS structures
+ */
+struct mtk_usxgmii {
+	struct mtk_usxgmii_pcs	pcs[MTK_MAX_DEVS];
+	struct regmap		*pll;
+};
 
 /* struct mtk_reset_event - This is the structure holding statistics counters
  *			for reset events
@@ -1705,7 +1761,8 @@
 	struct regmap			*ethsys;
 	struct regmap                   *infra;
 	struct regmap                   *toprgu;
-	struct mtk_xgmii                *xgmii;
+	struct mtk_sgmii		*sgmii;
+	struct mtk_usxgmii		*usxgmii;
 	struct regmap			*pctl;
 	bool				hwlro;
 	refcount_t			dma_refcnt;
@@ -1754,6 +1811,7 @@
 	struct mtk_hw_stats		*hw_stats;
 	__be32				hwlro_ip[MTK_MAX_LRO_IP_CNT];
 	int				hwlro_ip_cnt;
+	unsigned int			syscfg0;
 	bool				tx_lpi_enabled;
 	u32				tx_lpi_timer;
 };
@@ -1770,13 +1828,9 @@
 u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
 u32 mtk_m32(struct mtk_eth *eth, u32 mask, u32 set, unsigned reg);
 
-int mtk_sgmii_init(struct mtk_xgmii *ss, struct device_node *np,
+struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id);
+int mtk_sgmii_init(struct mtk_eth *eth, struct device_node *np,
 		   u32 ana_rgc3);
-int mtk_sgmii_setup_mode_an(struct mtk_xgmii *ss, unsigned int mac_id);
-int mtk_sgmii_setup_mode_force(struct mtk_xgmii *ss, unsigned int mac_id,
-			       const struct phylink_link_state *state);
-void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id);
-void mtk_sgmii_setup_phya_gen2(struct mtk_xgmii *ss, int mac_id);
 
 int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id);
 int mtk_gmac_xgmii_path_setup(struct mtk_eth *eth, int mac_id);
@@ -1787,17 +1841,9 @@
 void ethsys_reset(struct mtk_eth *eth, u32 reset_bits);
 
 int mtk_mac2xgmii_id(struct mtk_eth *eth, int mac_id);
-int mtk_usxgmii_init(struct mtk_xgmii *ss, struct device_node *r);
-int mtk_xfi_pextp_init(struct mtk_xgmii *ss, struct device_node *r);
-int mtk_xfi_pll_init(struct mtk_xgmii *ss, struct device_node *r);
+struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, int id);
+int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r);
 int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
-int mtk_xfi_pll_enable(struct mtk_xgmii *ss);
-int mtk_usxgmii_setup_mode_an(struct mtk_xgmii *ss, int mac_id,
-			      int max_speed);
-int mtk_usxgmii_setup_mode_force(struct mtk_xgmii *ss, int mac_id,
-				 const struct phylink_link_state *state);
-void mtk_usxgmii_setup_phya_an_10000(struct mtk_xgmii *ss, int mac_id);
-void mtk_usxgmii_reset(struct mtk_xgmii *ss, int mac_id);
 int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range);
 
 void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
index 5d792ae..3c37656 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c
@@ -13,52 +13,85 @@
 
 #include "mtk_eth_soc.h"
 
-int mtk_sgmii_init(struct mtk_xgmii *ss, struct device_node *r, u32 ana_rgc3)
+static struct mtk_sgmii_pcs *pcs_to_mtk_sgmii_pcs(struct phylink_pcs *pcs)
+{
+	return container_of(pcs, struct mtk_sgmii_pcs, pcs);
+}
+
+static int mtk_sgmii_xfi_pextp_init(struct mtk_sgmii *ss, struct device_node *r)
 {
 	struct device_node *np;
 	int i;
 
-	ss->ana_rgc3 = ana_rgc3;
-
 	for (i = 0; i < MTK_MAX_DEVS; i++) {
-		np = of_parse_phandle(r, "mediatek,sgmiisys", i);
+		np = of_parse_phandle(r, "mediatek,xfi_pextp", i);
 		if (!np)
 			break;
 
-		ss->regmap_sgmii[i] = syscon_node_to_regmap(np);
-		if (IS_ERR(ss->regmap_sgmii[i]))
-			return PTR_ERR(ss->regmap_sgmii[i]);
+		ss->pcs[i].regmap_pextp = syscon_node_to_regmap(np);
+		if (IS_ERR(ss->pcs[i].regmap_pextp))
+			return PTR_ERR(ss->pcs[i].regmap_pextp);
 
-		ss->flags[i] &= ~(MTK_SGMII_PN_SWAP);
-		if (of_property_read_bool(np, "pn_swap"))
-			ss->flags[i] |= MTK_SGMII_PN_SWAP;
+		of_node_put(np);
 	}
 
 	return 0;
 }
 
+static int mtk_sgmii_xfi_pll_init(struct mtk_sgmii *ss, struct device_node *r)
+{
+	struct device_node *np;
+
+	np = of_parse_phandle(r, "mediatek,xfi_pll", 0);
+	if (!np)
+		return -1;
+
+	ss->pll = syscon_node_to_regmap(np);
+	if (IS_ERR(ss->pll))
+		return PTR_ERR(ss->pll);
+
+	of_node_put(np);
+
+	return 0;
+}
+
-void mtk_sgmii_reset(struct mtk_xgmii *ss, int mac_id)
+static int mtk_sgmii_xfi_pll_enable(struct mtk_sgmii *ss)
 {
-	struct mtk_eth *eth = ss->eth;
-	u32 id = mtk_mac2xgmii_id(eth, mac_id);
 	u32 val = 0;
 
-	if (id >= MTK_MAX_DEVS || !eth->toprgu)
+	if (!ss->pll)
+		return -EINVAL;
+
+	/* Add software workaround for USXGMII PLL TCL issue */
+	regmap_write(ss->pll, XFI_PLL_ANA_GLB8, RG_XFI_PLL_ANA_SWWA);
+
+	regmap_read(ss->pll, XFI_PLL_DIG_GLB8, &val);
+	val |= RG_XFI_PLL_EN;
+	regmap_write(ss->pll, XFI_PLL_DIG_GLB8, val);
+
+	return 0;
+}
+
+void mtk_sgmii_reset(struct mtk_eth *eth, int id)
+{
+	u32 val = 0;
+
+	if (!eth->toprgu)
 		return;
 
-	switch (mac_id) {
-	case MTK_GMAC2_ID:
+	switch (id) {
+	case 0:
 		/* Enable software reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
-		val |= SWSYSRST_XFI_PEXPT1_GRST |
-		       SWSYSRST_SGMII1_GRST;
+		val |= SWSYSRST_XFI_PEXPT0_GRST |
+		       SWSYSRST_SGMII0_GRST;
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
 
 		/* Assert SGMII reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
 		val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
-		       SWSYSRST_XFI_PEXPT1_GRST |
-		       SWSYSRST_SGMII1_GRST;
+		       SWSYSRST_XFI_PEXPT0_GRST |
+		       SWSYSRST_SGMII0_GRST;
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
 
 		udelay(100);
@@ -66,28 +99,28 @@
 		/* De-assert SGMII reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
 		val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
-		val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
-			 SWSYSRST_SGMII1_GRST);
+		val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
+			 SWSYSRST_SGMII0_GRST);
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
 
 		/* Disable software reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
-		val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
-			 SWSYSRST_SGMII1_GRST);
+		val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
+			 SWSYSRST_SGMII0_GRST);
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
 		break;
-	case MTK_GMAC3_ID:
-		/* Enable Software reset */
+	case 1:
+		/* Enable software reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
-		val |= SWSYSRST_XFI_PEXPT0_GRST |
-		       SWSYSRST_SGMII0_GRST;
+		val |= SWSYSRST_XFI_PEXPT1_GRST |
+		       SWSYSRST_SGMII1_GRST;
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
 
 		/* Assert SGMII reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
 		val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
-		       SWSYSRST_XFI_PEXPT0_GRST |
-		       SWSYSRST_SGMII0_GRST;
+		       SWSYSRST_XFI_PEXPT1_GRST |
+		       SWSYSRST_SGMII1_GRST;
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
 
 		udelay(100);
@@ -95,14 +128,14 @@
 		/* De-assert SGMII reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
 		val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
-		val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
-			 SWSYSRST_SGMII0_GRST);
+		val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
+			 SWSYSRST_SGMII1_GRST);
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
 
 		/* Disable software reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
-		val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
-			 SWSYSRST_SGMII0_GRST);
+		val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
+			 SWSYSRST_SGMII1_GRST);
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
 		break;
 	}
@@ -110,18 +143,19 @@
 	mdelay(1);
 }
 
-int mtk_sgmii_need_powerdown(struct mtk_xgmii *ss, int id, int speed)
+int mtk_sgmii_need_powerdown(struct mtk_sgmii_pcs *mpcs,
+			     phy_interface_t interface)
 {
 	u32 val;
 
 	/* need to power down sgmii if link down */
-	regmap_read(ss->regmap_sgmii[id], SGMSYS_PCS_CONTROL_1, &val);
+	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
 	if (!(val & SGMII_LINK_STATYS))
 		return true;
 
-	/* need to power down sgmii if link speed changed */
-	regmap_read(ss->regmap_sgmii[id], ss->ana_rgc3, &val);
-	if (speed == SPEED_2500) {
+	/* need to power down sgmii if interface changed */
+	regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
+	if (interface == PHY_INTERFACE_MODE_2500BASEX) {
 		if (!(val & RG_PHY_SPEED_3_125G))
 			return true;
 	} else {
@@ -132,272 +166,469 @@
 	return false;
 }
 
-void mtk_sgmii_setup_phya_gen1(struct mtk_xgmii *ss, int mac_id)
+void mtk_sgmii_setup_phya_gen1(struct mtk_sgmii_pcs *mpcs)
 {
-	u32 id = mtk_mac2xgmii_id(ss->eth, mac_id);
-
-	if (id >= MTK_MAX_DEVS ||
-	    !ss->regmap_sgmii[id] || !ss->regmap_pextp[id])
+	if (!mpcs->regmap_pextp)
 		return;
 
-	regmap_update_bits(ss->regmap_pextp[id], 0x9024, GENMASK(31, 0), 0x00D9071C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2020, GENMASK(31, 0), 0xAA8585AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2030, GENMASK(31, 0), 0x0C020207);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2034, GENMASK(31, 0), 0x0E05050F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2040, GENMASK(31, 0), 0x00200032);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50F0, GENMASK(31, 0), 0x00C014BA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E0, GENMASK(31, 0), 0x3777C12B);
-	regmap_update_bits(ss->regmap_pextp[id], 0x506C, GENMASK(31, 0), 0x005F9CFF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5070, GENMASK(31, 0), 0x9D9DFAFA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5074, GENMASK(31, 0), 0x27273F3F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5078, GENMASK(31, 0), 0xA7883C68);
-	regmap_update_bits(ss->regmap_pextp[id], 0x507C, GENMASK(31, 0), 0x11661166);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5080, GENMASK(31, 0), 0x0E000EAF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5084, GENMASK(31, 0), 0x08080E0D);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5088, GENMASK(31, 0), 0x02030B09);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E4, GENMASK(31, 0), 0x0C0C0000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E8, GENMASK(31, 0), 0x04040000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50EC, GENMASK(31, 0), 0x0F0F0606);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50A8, GENMASK(31, 0), 0x506E8C8C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x6004, GENMASK(31, 0), 0x18190000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F8, GENMASK(31, 0), 0x00FA32FA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0), 0x80201F21);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0030, GENMASK(31, 0), 0x00050C00);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x02002800);
+	regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
+			   0x00D9071C);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
+			   0xAA8585AA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
+			   0x0C020207);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
+			   0x0E05050F);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
+			   0x00200032);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
+			   0x00C014BA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
+			   0x3777C12B);
+	regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
+			   0x005F9CFF);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
+			   0x9D9DFAFA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
+			   0x27273F3F);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
+			   0xA7883C68);
+	regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
+			   0x11661166);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
+			   0x0E000EAF);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
+			   0x08080E0D);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
+			   0x02030B09);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
+			   0x0C0C0000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
+			   0x04040000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
+			   0x0F0F0606);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
+			   0x506E8C8C);
+	regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
+			   0x18190000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
+			   0x00FA32FA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
+			   0x80201F21);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
+			   0x00050C00);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x02002800);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0), 0x00000020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3028, GENMASK(31, 0), 0x00008A01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x302C, GENMASK(31, 0), 0x0000A884);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3024, GENMASK(31, 0), 0x00083002);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3010, GENMASK(31, 0), 0x00011110);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3048, GENMASK(31, 0), 0x40704000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3064, GENMASK(31, 0), 0x0000C000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3050, GENMASK(31, 0), 0xA8000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3054, GENMASK(31, 0), 0x000000AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x306C, GENMASK(31, 0), 0x20200F00);
-	regmap_update_bits(ss->regmap_pextp[id], 0xA060, GENMASK(31, 0), 0x00050000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x90D0, GENMASK(31, 0), 0x00000007);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200E800);
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
+			   0x00000020);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
+			   0x00008A01);
+	regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
+			   0x0000A884);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
+			   0x00083002);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
+			   0x00011110);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
+			   0x40704000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3064, GENMASK(31, 0),
+			   0x0000C000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
+			   0xA8000000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
+			   0x000000AA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
+			   0x20200F00);
+	regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
+			   0x00050000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
+			   0x00000007);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200E800);
 	udelay(150);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200C111);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200C101);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200C101);
 	udelay(15);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0201C111);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0201C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0201C101);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0201C101);
 	udelay(100);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0), 0x00000030);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0), 0x80201F01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3040, GENMASK(31, 0), 0x30000000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
+			   0x00000030);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
+			   0x80201F01);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
+			   0x30000000);
 	udelay(400);
 }
 
-void mtk_sgmii_setup_phya_gen2(struct mtk_xgmii *ss, int mac_id)
+void mtk_sgmii_setup_phya_gen2(struct mtk_sgmii_pcs *mpcs)
 {
-	u32 id = mtk_mac2xgmii_id(ss->eth, mac_id);
-
-	if (id >= MTK_MAX_DEVS ||
-	    !ss->regmap_sgmii[id] || !ss->regmap_pextp[id])
+	if (!mpcs->regmap_pextp)
 		return;
 
-	regmap_update_bits(ss->regmap_pextp[id], 0x9024, GENMASK(31, 0), 0x00D9071C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2020, GENMASK(31, 0), 0xAA8585AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2030, GENMASK(31, 0), 0x0C020707);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2034, GENMASK(31, 0), 0x0E050F0F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2040, GENMASK(31, 0), 0x00140032);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50F0, GENMASK(31, 0), 0x00C014AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E0, GENMASK(31, 0), 0x3777C12B);
-	regmap_update_bits(ss->regmap_pextp[id], 0x506C, GENMASK(31, 0), 0x005F9CFF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5070, GENMASK(31, 0), 0x9D9DFAFA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5074, GENMASK(31, 0), 0x27273F3F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5078, GENMASK(31, 0), 0xA7883C68);
-	regmap_update_bits(ss->regmap_pextp[id], 0x507C, GENMASK(31, 0), 0x11661166);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5080, GENMASK(31, 0), 0x0E000AAF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5084, GENMASK(31, 0), 0x08080D0D);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5088, GENMASK(31, 0), 0x02030909);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E4, GENMASK(31, 0), 0x0C0C0000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E8, GENMASK(31, 0), 0x04040000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50EC, GENMASK(31, 0), 0x0F0F0C06);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50A8, GENMASK(31, 0), 0x506E8C8C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x6004, GENMASK(31, 0), 0x18190000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F8, GENMASK(31, 0), 0x009C329C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0), 0x80201F21);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0030, GENMASK(31, 0), 0x00050C00);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x02002800);
+	regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
+			   0x00D9071C);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
+			   0xAA8585AA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
+			   0x0C020707);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
+			   0x0E050F0F);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
+			   0x00140032);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
+			   0x00C014AA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
+			   0x3777C12B);
+	regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
+			   0x005F9CFF);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
+			   0x9D9DFAFA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
+			   0x27273F3F);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
+			   0xA7883C68);
+	regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
+			   0x11661166);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
+			   0x0E000AAF);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
+			   0x08080D0D);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
+			   0x02030909);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
+			   0x0C0C0000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
+			   0x04040000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
+			   0x0F0F0C06);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
+			   0x506E8C8C);
+	regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
+			   0x18190000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
+			   0x009C329C);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
+			   0x80201F21);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
+			   0x00050C00);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x02002800);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0), 0x00000020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3028, GENMASK(31, 0), 0x00008A01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x302C, GENMASK(31, 0), 0x0000A884);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3024, GENMASK(31, 0), 0x00083002);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3010, GENMASK(31, 0), 0x00011110);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3048, GENMASK(31, 0), 0x40704000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3050, GENMASK(31, 0), 0xA8000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3054, GENMASK(31, 0), 0x000000AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x306C, GENMASK(31, 0), 0x22000F00);
-	regmap_update_bits(ss->regmap_pextp[id], 0xA060, GENMASK(31, 0), 0x00050000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x90D0, GENMASK(31, 0), 0x00000005);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200E800);
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
+			   0x00000020);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
+			   0x00008A01);
+	regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
+			   0x0000A884);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
+			   0x00083002);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
+			   0x00011110);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
+			   0x40704000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
+			   0xA8000000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
+			   0x000000AA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
+			   0x22000F00);
+	regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
+			   0x00050000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
+			   0x00000005);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200E800);
 	udelay(150);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200C111);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200C101);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200C101);
 	udelay(15);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0201C111);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0201C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0201C101);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0201C101);
 	udelay(100);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0), 0x00000030);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0), 0x80201F01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3040, GENMASK(31, 0), 0x30000000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
+			   0x00000030);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
+			   0x80201F01);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
+			   0x30000000);
 	udelay(400);
 }
 
-int mtk_sgmii_setup_mode_an(struct mtk_xgmii *ss, unsigned int mac_id)
+int mtk_sgmii_setup_mode_an(struct mtk_sgmii_pcs *mpcs)
 {
-	struct mtk_eth *eth = ss->eth;
+	struct mtk_eth *eth = mpcs->eth;
 	unsigned int val = 0;
-	u32 id = mtk_mac2xgmii_id(ss->eth, mac_id);
 
-	if (!ss->regmap_sgmii[id])
+	if (!mpcs->regmap)
 		return -EINVAL;
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
-		mtk_xfi_pll_enable(ss);
-		mtk_sgmii_reset(ss, mac_id);
+		mtk_sgmii_xfi_pll_enable(eth->sgmii);
+		mtk_sgmii_reset(eth, mpcs->id);
 	}
 
 	/* Assert PHYA power down state when needed */
-	if (mtk_sgmii_need_powerdown(ss, id, SPEED_1000))
-		regmap_write(ss->regmap_sgmii[id], SGMSYS_QPHY_PWR_STATE_CTRL,
+	if (mtk_sgmii_need_powerdown(mpcs, PHY_INTERFACE_MODE_SGMII))
+		regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
 			     SGMII_PHYA_PWD);
 
 	/* Reset SGMII PCS state */
-	regmap_write(ss->regmap_sgmii[id], SGMII_RESERVED_0, SGMII_SW_RESET);
+	regmap_write(mpcs->regmap, SGMII_RESERVED_0, SGMII_SW_RESET);
 
-	regmap_read(ss->regmap_sgmii[id], ss->ana_rgc3, &val);
+	regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
 	val &= ~RG_PHY_SPEED_3_125G;
-	regmap_write(ss->regmap_sgmii[id], ss->ana_rgc3, val);
+	regmap_write(mpcs->regmap, mpcs->ana_rgc3, val);
 
 	/* Setup the link timer and QPHY power up inside SGMIISYS */
-	regmap_write(ss->regmap_sgmii[id], SGMSYS_PCS_LINK_TIMER,
+	regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
 		     SGMII_LINK_TIMER_DEFAULT);
 
-	regmap_read(ss->regmap_sgmii[id], SGMSYS_SGMII_MODE, &val);
+	regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
 	val |= SGMII_REMOTE_FAULT_DIS;
-	regmap_write(ss->regmap_sgmii[id], SGMSYS_SGMII_MODE, val);
+	regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
 
 	/* SGMII AN mode setting */
-	regmap_read(ss->regmap_sgmii[id], SGMSYS_SGMII_MODE, &val);
+	regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
 	val &= ~SGMII_IF_MODE_MASK;
 	val |= SGMII_SPEED_DUPLEX_AN;
-	regmap_write(ss->regmap_sgmii[id], SGMSYS_SGMII_MODE, val);
+	regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
 
 	/* Enable SGMII AN */
-	regmap_read(ss->regmap_sgmii[id], SGMSYS_PCS_CONTROL_1, &val);
+	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
 	val |= SGMII_AN_ENABLE;
-	regmap_write(ss->regmap_sgmii[id], SGMSYS_PCS_CONTROL_1, val);
+	regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
 
-	if(MTK_HAS_FLAGS(ss->flags[id],MTK_SGMII_PN_SWAP))
-		regmap_update_bits(ss->regmap_sgmii[id], SGMSYS_QPHY_WRAP_CTRL,
+	if (MTK_HAS_FLAGS(mpcs->flags, MTK_SGMII_PN_SWAP))
+		regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
 				   SGMII_PN_SWAP_MASK, SGMII_PN_SWAP_TX_RX);
 
 	/* Release PHYA power down state */
-	regmap_write(ss->regmap_sgmii[id], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+	regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3))
-		mtk_sgmii_setup_phya_gen1(ss, mac_id);
+		mtk_sgmii_setup_phya_gen1(mpcs);
 
 	return 0;
 }
 
-int mtk_sgmii_setup_mode_force(struct mtk_xgmii *ss, unsigned int mac_id,
-			       const struct phylink_link_state *state)
+int mtk_sgmii_setup_mode_force(struct mtk_sgmii_pcs *mpcs,
+			       phy_interface_t interface)
 {
-	struct mtk_eth *eth = ss->eth;
+	struct mtk_eth *eth = mpcs->eth;
 	unsigned int val = 0;
-	u32 id = mtk_mac2xgmii_id(eth, mac_id);
 
-	if (!ss->regmap_sgmii[id])
+	if (!mpcs->regmap)
 		return -EINVAL;
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
-		mtk_xfi_pll_enable(ss);
-		mtk_sgmii_reset(ss, mac_id);
+		mtk_sgmii_xfi_pll_enable(eth->sgmii);
+		mtk_sgmii_reset(eth, mpcs->id);
 	}
 
 	/* Assert PHYA power down state when needed */
-	if (mtk_sgmii_need_powerdown(ss, id, state->speed))
-		regmap_write(ss->regmap_sgmii[id], SGMSYS_QPHY_PWR_STATE_CTRL,
+	if (mtk_sgmii_need_powerdown(mpcs, interface))
+		regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL,
 			     SGMII_PHYA_PWD);
 
 	/* Reset SGMII PCS state */
-	regmap_write(ss->regmap_sgmii[id], SGMII_RESERVED_0, SGMII_SW_RESET);
+	regmap_write(mpcs->regmap, SGMII_RESERVED_0, SGMII_SW_RESET);
 
-	regmap_read(ss->regmap_sgmii[id], ss->ana_rgc3, &val);
+	regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
 	val &= ~RG_PHY_SPEED_MASK;
-	if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
+	if (interface == PHY_INTERFACE_MODE_2500BASEX)
 		val |= RG_PHY_SPEED_3_125G;
-	regmap_write(ss->regmap_sgmii[id], ss->ana_rgc3, val);
+	regmap_write(mpcs->regmap, mpcs->ana_rgc3, val);
 
 	/* Disable SGMII AN */
-	regmap_read(ss->regmap_sgmii[id], SGMSYS_PCS_CONTROL_1, &val);
+	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
 	val &= ~SGMII_AN_ENABLE;
-	regmap_write(ss->regmap_sgmii[id], SGMSYS_PCS_CONTROL_1, val);
+	regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
 
-	/* SGMII force mode setting */
-	regmap_read(ss->regmap_sgmii[id], SGMSYS_SGMII_MODE, &val);
-	val &= ~SGMII_IF_MODE_MASK;
+	/* Set the speed etc but leave the duplex unchanged */
+	regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
+	val &= SGMII_DUPLEX_HALF | ~SGMII_IF_MODE_MASK;
 	val &= ~SGMII_REMOTE_FAULT_DIS;
+	val |= SGMII_SPEED_1000;
+	regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
 
-	switch (state->speed) {
-	case SPEED_10:
-		val |= SGMII_SPEED_10;
-		break;
-	case SPEED_100:
-		val |= SGMII_SPEED_100;
-		break;
-	case SPEED_2500:
-	case SPEED_1000:
-	default:
-		val |= SGMII_SPEED_1000;
-		break;
-	};
-
-	/* SGMII 1G and 2.5G force mode can only work in full duplex
-	 * mode, no matter SGMII_FORCE_HALF_DUPLEX is set or not.
-	 */
-	if (state->duplex != DUPLEX_FULL)
-		val |= SGMII_DUPLEX_FULL;
-
-	regmap_write(ss->regmap_sgmii[id], SGMSYS_SGMII_MODE, val);
-
-	if(MTK_HAS_FLAGS(ss->flags[id],MTK_SGMII_PN_SWAP))
-		regmap_update_bits(ss->regmap_sgmii[id], SGMSYS_QPHY_WRAP_CTRL,
+	if (MTK_HAS_FLAGS(mpcs->flags, MTK_SGMII_PN_SWAP))
+		regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
 				   SGMII_PN_SWAP_MASK, SGMII_PN_SWAP_TX_RX);
 
 	/* Release PHYA power down state */
-	regmap_write(ss->regmap_sgmii[id], SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+	regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0);
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3))
-		mtk_sgmii_setup_phya_gen2(ss, mac_id);
+		mtk_sgmii_setup_phya_gen2(mpcs);
 
 	return 0;
 }
 
+static void mtk_sgmii_pcs_get_state(struct phylink_pcs *pcs,
+				    struct phylink_link_state *state)
+{
+	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
+	u32 rgc3, val = 0;
+
+	state->interface = mpcs->interface;
+
+	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
+	if (FIELD_GET(SGMII_AN_ENABLE, val)) {
+		regmap_read(mpcs->regmap, SGMII_PCS_SPEED_ABILITY, &val);
+		val = val >> 16;
+		state->link = FIELD_GET(SGMII_PCS_SPEED_LINK, val);
+		state->duplex = FIELD_GET(SGMII_PCS_SPEED_DUPLEX, val);
+		switch (FIELD_GET(SGMII_PCS_SPEED_MASK, val)) {
+		case 0:
+			state->speed = SPEED_10;
+			break;
+		case 1:
+			state->speed = SPEED_100;
+			break;
+		case 2:
+			state->speed = SPEED_1000;
+			break;
+		}
+	} else {
+		state->link = FIELD_GET(SGMII_LINK_STATYS, val);
+
+		regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
+		state->duplex = !FIELD_GET(SGMII_DUPLEX_HALF, val);
+		switch (FIELD_GET(SGMII_SPEED_MASK, val)) {
+		case 0:
+			state->speed = SPEED_10;
+			break;
+		case 1:
+			state->speed = SPEED_100;
+			break;
+		case 2:
+			regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
+			rgc3 = FIELD_GET(RG_PHY_SPEED_3_125G, val);
+			state->speed = rgc3 ? SPEED_2500 : SPEED_1000;
+			break;
+		}
+	}
+}
+
-void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id)
+static int mtk_sgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
+				phy_interface_t interface,
+				const unsigned long *advertising,
+				bool permit_pause_to_mac)
 {
-	struct mtk_xgmii *ss = eth->xgmii;
-	unsigned int val = 0, sid = mtk_mac2xgmii_id(eth, mac_id);
+	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
+	int err = 0;
+
+	mpcs->interface = interface;
 
-	/* Decide how GMAC and SGMIISYS be mapped */
-	sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
-	       0 : sid;
+	/* Setup SGMIISYS with the determined property */
+	if (interface != PHY_INTERFACE_MODE_SGMII)
+		err = mtk_sgmii_setup_mode_force(mpcs, interface);
+	else
+		err = mtk_sgmii_setup_mode_an(mpcs);
 
-	if (!ss->regmap_sgmii[sid])
+	return err;
+}
+
+void mtk_sgmii_pcs_restart_an(struct phylink_pcs *pcs)
+{
+	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
+	unsigned int val = 0;
+
+	if (!mpcs->regmap)
 		return;
 
-	regmap_read(ss->regmap_sgmii[sid], SGMSYS_PCS_CONTROL_1, &val);
+	regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
 	val |= SGMII_AN_RESTART;
-	regmap_write(ss->regmap_sgmii[sid], SGMSYS_PCS_CONTROL_1, val);
+	regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
+}
+
+static void mtk_sgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
+				  phy_interface_t interface,
+				  int speed, int duplex)
+{
+	struct mtk_sgmii_pcs *mpcs = pcs_to_mtk_sgmii_pcs(pcs);
+	unsigned int val;
+
+	if (!phy_interface_mode_is_8023z(interface))
+		return;
+
+	/* SGMII force duplex setting */
+	regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
+	val &= ~SGMII_DUPLEX_HALF;
+	if (duplex != DUPLEX_FULL)
+		val |= SGMII_DUPLEX_HALF;
+
+	regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
+}
+
+static const struct phylink_pcs_ops mtk_sgmii_pcs_ops = {
+	.pcs_config = mtk_sgmii_pcs_config,
+	.pcs_get_state = mtk_sgmii_pcs_get_state,
+	.pcs_an_restart = mtk_sgmii_pcs_restart_an,
+	.pcs_link_up = mtk_sgmii_pcs_link_up,
+};
+
+int mtk_sgmii_init(struct mtk_eth *eth, struct device_node *r, u32 ana_rgc3)
+{
+	struct mtk_sgmii *ss = eth->sgmii;
+	struct device_node *np;
+	int ret, i;
+
+	for (i = 0; i < MTK_MAX_DEVS; i++) {
+		np = of_parse_phandle(r, "mediatek,sgmiisys", i);
+		if (!np)
+			break;
+
+		ss->pcs[i].id = i;
+		ss->pcs[i].eth = eth;
+		ss->pcs[i].ana_rgc3 = ana_rgc3;
+
+		ss->pcs[i].regmap = syscon_node_to_regmap(np);
+		if (IS_ERR(ss->pcs[i].regmap))
+			return PTR_ERR(ss->pcs[i].regmap);
+
+		ss->pcs[i].flags &= ~(MTK_SGMII_PN_SWAP);
+		if (of_property_read_bool(np, "pn_swap"))
+			ss->pcs[i].flags |= MTK_SGMII_PN_SWAP;
+
+		ss->pcs[i].pcs.ops = &mtk_sgmii_pcs_ops;
+		ss->pcs[i].pcs.poll = true;
+		ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
+
+		of_node_put(np);
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		ret = mtk_sgmii_xfi_pextp_init(ss, r);
+		if (ret)
+			return ret;
+
+		ret = mtk_sgmii_xfi_pll_init(ss, r);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id)
+{
+	if (!ss->pcs[id].regmap)
+		return NULL;
+
+	return &ss->pcs[id].pcs;
 }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
index 8fb28ca..73f84f6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_usxgmii.c
@@ -9,25 +9,12 @@
 #include <linux/regmap.h>
 #include "mtk_eth_soc.h"
 
-int mtk_usxgmii_init(struct mtk_xgmii *ss, struct device_node *r)
+static struct mtk_usxgmii_pcs *pcs_to_mtk_usxgmii_pcs(struct phylink_pcs *pcs)
 {
-	struct device_node *np;
-	int i;
-
-	for (i = 0; i < MTK_MAX_DEVS; i++) {
-		np = of_parse_phandle(r, "mediatek,usxgmiisys", i);
-		if (!np)
-			break;
-
-		ss->regmap_usxgmii[i] = syscon_node_to_regmap(np);
-		if (IS_ERR(ss->regmap_usxgmii[i]))
-			return PTR_ERR(ss->regmap_usxgmii[i]);
-	}
-
-	return 0;
+	return container_of(pcs, struct mtk_usxgmii_pcs, pcs);
 }
 
-int mtk_xfi_pextp_init(struct mtk_xgmii *ss, struct device_node *r)
+int mtk_usxgmii_xfi_pextp_init(struct mtk_usxgmii *ss, struct device_node *r)
 {
 	struct device_node *np;
 	int i;
@@ -37,25 +24,32 @@
 		if (!np)
 			break;
 
-		ss->regmap_pextp[i] = syscon_node_to_regmap(np);
-		if (IS_ERR(ss->regmap_pextp[i]))
-			return PTR_ERR(ss->regmap_pextp[i]);
+		ss->pcs[i].regmap_pextp = syscon_node_to_regmap(np);
+		if (IS_ERR(ss->pcs[i].regmap_pextp))
+			return PTR_ERR(ss->pcs[i].regmap_pextp);
+
+		of_node_put(np);
 	}
 
 	return 0;
 }
 
-int mtk_xfi_pll_init(struct mtk_xgmii *ss, struct device_node *r)
+int mtk_usxgmii_xfi_pll_init(struct mtk_usxgmii *ss, struct device_node *r)
 {
 	struct device_node *np;
+	int i;
 
 	np = of_parse_phandle(r, "mediatek,xfi_pll", 0);
 	if (!np)
 		return -1;
 
+	for (i = 0; i < MTK_MAX_DEVS; i++) {
+		ss->pll = syscon_node_to_regmap(np);
+		if (IS_ERR(ss->pll))
+			return PTR_ERR(ss->pll);
+	}
+
-	ss->regmap_pll = syscon_node_to_regmap(np);
-	if (IS_ERR(ss->regmap_pll))
-		return PTR_ERR(ss->regmap_pll);
+	of_node_put(np);
 
 	return 0;
 }
@@ -75,19 +69,19 @@
 	return 0;
 }
 
-int mtk_xfi_pll_enable(struct mtk_xgmii *ss)
+static int mtk_usxgmii_xfi_pll_enable(struct mtk_usxgmii *ss)
 {
 	u32 val = 0;
 
-	if (!ss->regmap_pll)
+	if (!ss->pll)
 		return -EINVAL;
 
 	/* Add software workaround for USXGMII PLL TCL issue */
-	regmap_write(ss->regmap_pll, XFI_PLL_ANA_GLB8, RG_XFI_PLL_ANA_SWWA);
+	regmap_write(ss->pll, XFI_PLL_ANA_GLB8, RG_XFI_PLL_ANA_SWWA);
 
-	regmap_read(ss->regmap_pll, XFI_PLL_DIG_GLB8, &val);
+	regmap_read(ss->pll, XFI_PLL_DIG_GLB8, &val);
 	val |= RG_XFI_PLL_EN;
-	regmap_write(ss->regmap_pll, XFI_PLL_DIG_GLB8, val);
+	regmap_write(ss->pll, XFI_PLL_DIG_GLB8, val);
 
 	return 0;
 }
@@ -114,376 +108,444 @@
 	return xgmii_id;
 }
 
-void mtk_usxgmii_setup_phya_an_10000(struct mtk_xgmii *ss, int mac_id)
+int mtk_xgmii2mac_id(struct mtk_eth *eth, int xgmii_id)
 {
-	u32 id = mtk_mac2xgmii_id(ss->eth, mac_id);
+	u32 mac_id = xgmii_id;
 
-	if (id >= MTK_MAX_DEVS ||
-	    !ss->regmap_usxgmii[id] || !ss->regmap_pextp[id])
-		return;
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		switch (xgmii_id) {
+		case 0:
+			mac_id = 2;
+			break;
+		case 1:
+			mac_id = 1;
+			break;
+		default:
+			pr_info("[%s] Warning: get illegal xgmii_id=%d !=!!!\n",
+				__func__, xgmii_id);
+		}
+	}
+
+	return mac_id;
+}
+
+int mtk_usxgmii_setup_phya_an_10000(struct mtk_usxgmii_pcs *mpcs)
+{
+	if (!mpcs->regmap || !mpcs->regmap_pextp)
+		return -EINVAL;
 
-	regmap_update_bits(ss->regmap_usxgmii[id], 0x810, GENMASK(31, 0), 0x000FFE6D);
-	regmap_update_bits(ss->regmap_usxgmii[id], 0x818, GENMASK(31, 0), 0x07B1EC7B);
-	regmap_update_bits(ss->regmap_usxgmii[id], 0x80C, GENMASK(31, 0), 0x30000000);
+	regmap_update_bits(mpcs->regmap, 0x810, GENMASK(31, 0),
+			   0x000FFE6D);
+	regmap_update_bits(mpcs->regmap, 0x818, GENMASK(31, 0),
+			   0x07B1EC7B);
+	regmap_update_bits(mpcs->regmap, 0x80C, GENMASK(31, 0),
+			   0x30000000);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_usxgmii[id], 0x80C, GENMASK(31, 0), 0x10000000);
+	regmap_update_bits(mpcs->regmap, 0x80C, GENMASK(31, 0),
+			   0x10000000);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_usxgmii[id], 0x80C, GENMASK(31, 0), 0x00000000);
+	regmap_update_bits(mpcs->regmap, 0x80C, GENMASK(31, 0),
+			   0x00000000);
 
-	regmap_update_bits(ss->regmap_pextp[id], 0x9024, GENMASK(31, 0), 0x00C9071C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2020, GENMASK(31, 0), 0xAA8585AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2030, GENMASK(31, 0), 0x0C020707);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2034, GENMASK(31, 0), 0x0E050F0F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2040, GENMASK(31, 0), 0x00140032);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50F0, GENMASK(31, 0), 0x00C014AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E0, GENMASK(31, 0), 0x3777C12B);
-	regmap_update_bits(ss->regmap_pextp[id], 0x506C, GENMASK(31, 0), 0x005F9CFF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5070, GENMASK(31, 0), 0x9D9DFAFA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5074, GENMASK(31, 0), 0x27273F3F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5078, GENMASK(31, 0), 0xA7883C68);
-	regmap_update_bits(ss->regmap_pextp[id], 0x507C, GENMASK(31, 0), 0x11661166);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5080, GENMASK(31, 0), 0x0E000AAF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5084, GENMASK(31, 0), 0x08080D0D);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5088, GENMASK(31, 0), 0x02030909);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E4, GENMASK(31, 0), 0x0C0C0000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E8, GENMASK(31, 0), 0x04040000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50EC, GENMASK(31, 0), 0x0F0F0C06);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50A8, GENMASK(31, 0), 0x506E8C8C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x6004, GENMASK(31, 0), 0x18190000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F8, GENMASK(31, 0), 0x01423342);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0), 0x80201F20);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0030, GENMASK(31, 0), 0x00050C00);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x02002800);
+	regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
+			   0x00C9071C);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
+			   0xAA8585AA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
+			   0x0C020707);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
+			   0x0E050F0F);
+	regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
+			   0x00140032);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
+			   0x00C014AA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
+			   0x3777C12B);
+	regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
+			   0x005F9CFF);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
+			   0x9D9DFAFA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
+			   0x27273F3F);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
+			   0xA7883C68);
+	regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
+			   0x11661166);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
+			   0x0E000AAF);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
+			   0x08080D0D);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
+			   0x02030909);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
+			   0x0C0C0000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
+			   0x04040000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
+			   0x0F0F0C06);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
+			   0x506E8C8C);
+	regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
+			   0x18190000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
+			   0x01423342);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
+			   0x80201F20);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
+			   0x00050C00);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x02002800);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0), 0x00000020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3028, GENMASK(31, 0), 0x00008A01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x302C, GENMASK(31, 0), 0x0000A884);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3024, GENMASK(31, 0), 0x00083002);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3010, GENMASK(31, 0), 0x00022220);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5064, GENMASK(31, 0), 0x0F020A01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50B4, GENMASK(31, 0), 0x06100600);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3048, GENMASK(31, 0), 0x40704000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3050, GENMASK(31, 0), 0xA8000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3054, GENMASK(31, 0), 0x000000AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x306C, GENMASK(31, 0), 0x00000F00);
-	regmap_update_bits(ss->regmap_pextp[id], 0xA060, GENMASK(31, 0), 0x00040000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x90D0, GENMASK(31, 0), 0x00000001);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200E800);
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
+			   0x00000020);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
+			   0x00008A01);
+	regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
+			   0x0000A884);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
+			   0x00083002);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
+			   0x00022220);
+	regmap_update_bits(mpcs->regmap_pextp, 0x5064, GENMASK(31, 0),
+			   0x0F020A01);
+	regmap_update_bits(mpcs->regmap_pextp, 0x50B4, GENMASK(31, 0),
+			   0x06100600);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
+			   0x40704000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
+			   0xA8000000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
+			   0x000000AA);
+	regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
+			   0x00000F00);
+	regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
+			   0x00040000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
+			   0x00000001);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200E800);
 	udelay(150);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200C111);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0200C101);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0200C101);
 	udelay(15);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0202C111);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0202C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0), 0x0202C101);
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
+			   0x0202C101);
 	udelay(100);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0), 0x00000030);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0), 0x80201F00);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3040, GENMASK(31, 0), 0x30000000);
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
+			   0x00000030);
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
+			   0x80201F00);
+	regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
+			   0x30000000);
 	udelay(400);
+
+	return 0;
 }
 
-void mtk_usxgmii_setup_phya_force_5000(struct mtk_xgmii *ss, int mac_id)
+int mtk_usxgmii_setup_phya_force_5000(struct mtk_usxgmii_pcs *mpcs)
 {
 	unsigned int val;
-	u32 id = mtk_mac2xgmii_id(ss->eth, mac_id);
 
-	if (id >= MTK_MAX_DEVS ||
-	    !ss->regmap_usxgmii[id] || !ss->regmap_pextp[id])
-		return;
+	if (!mpcs->regmap || !mpcs->regmap_pextp)
+		return -EINVAL;
 
 	/* Setup USXGMII speed */
 	val = FIELD_PREP(RG_XFI_RX_MODE, RG_XFI_RX_MODE_5G) |
 	      FIELD_PREP(RG_XFI_TX_MODE, RG_XFI_TX_MODE_5G);
-	regmap_write(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val);
+	regmap_write(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, val);
 
 	/* Disable USXGMII AN mode */
-	regmap_read(ss->regmap_usxgmii[id], RG_PCS_AN_CTRL0, &val);
-	val &= ~RG_AN_ENABLE;
-	regmap_write(ss->regmap_usxgmii[id], RG_PCS_AN_CTRL0, val);
+	regmap_read(mpcs->regmap, RG_PCS_AN_CTRL0, &val);
+	val &= ~USXGMII_AN_ENABLE;
+	regmap_write(mpcs->regmap, RG_PCS_AN_CTRL0, val);
 
 	/* Gated USXGMII */
-	regmap_read(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val);
+	regmap_read(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, &val);
 	val |= RG_MAC_CK_GATED;
-	regmap_write(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val);
+	regmap_write(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, val);
 
 	ndelay(1020);
 
 	/* USXGMII force mode setting */
-	regmap_read(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val);
+	regmap_read(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, &val);
 	val |= RG_USXGMII_RATE_UPDATE_MODE;
 	val |= RG_IF_FORCE_EN;
 	val |= FIELD_PREP(RG_RATE_ADAPT_MODE, RG_RATE_ADAPT_MODE_X1);
-	regmap_write(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val);
+	regmap_write(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, val);
 
 	/* Un-gated USXGMII */
-	regmap_read(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val);
+	regmap_read(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, &val);
 	val &= ~RG_MAC_CK_GATED;
-	regmap_write(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val);
+	regmap_write(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, val);
 
 	ndelay(1020);
 
-	regmap_update_bits(ss->regmap_pextp[id], 0x9024, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
 			   0x00D9071C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2020, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
 			   0xAAA5A5AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2030, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
 			   0x0C020707);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2034, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
 			   0x0E050F0F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2040, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
 			   0x00140032);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50F0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
 			   0x00C018AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
 			   0x3777812B);
-	regmap_update_bits(ss->regmap_pextp[id], 0x506C, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
 			   0x005C9CFF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
 			   0x9DFAFAFA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5074, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
 			   0x273F3F3F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5078, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
 			   0xA8883868);
-	regmap_update_bits(ss->regmap_pextp[id], 0x507C, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
 			   0x14661466);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5080, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
 			   0x0E001ABF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5084, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
 			   0x080B0D0D);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5088, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
 			   0x02050909);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E4, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
 			   0x0C000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E8, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
 			   0x04000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50EC, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
 			   0x0F0F0C06);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50A8, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
 			   0x50808C8C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x6004, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
 			   0x18000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F8, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
 			   0x00A132A1);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
 			   0x80201F20);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0030, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
 			   0x00050C00);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x02002800);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
 			   0x00000020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3028, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
 			   0x00008A01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x302C, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
 			   0x0000A884);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3024, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
 			   0x00083002);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3010, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
 			   0x00022220);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5064, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5064, GENMASK(31, 0),
 			   0x0F020A01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50B4, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50B4, GENMASK(31, 0),
 			   0x06100600);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3048, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
 			   0x40704000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3050, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
 			   0xA8000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3054, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
 			   0x000000AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x306C, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
 			   0x00000F00);
-	regmap_update_bits(ss->regmap_pextp[id], 0xA060, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
 			   0x00040000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x90D0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
 			   0x00000003);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0200E800);
 	udelay(150);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0200C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0200C101);
 	udelay(15);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0202C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0202C101);
 	udelay(100);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
 			   0x00000030);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
 			   0x80201F00);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3040, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
 			   0x30000000);
 	udelay(400);
+
+	return 0;
 }
 
-void mtk_usxgmii_setup_phya_force_10000(struct mtk_xgmii *ss, int mac_id)
+int mtk_usxgmii_setup_phya_force_10000(struct mtk_usxgmii_pcs *mpcs)
 {
 	unsigned int val;
-	u32 id = mtk_mac2xgmii_id(ss->eth, mac_id);
 
-	if (id >= MTK_MAX_DEVS ||
-	    !ss->regmap_usxgmii[id] || !ss->regmap_pextp[id])
-		return;
+	if (!mpcs->regmap || !mpcs->regmap_pextp)
+		return -EINVAL;
 
 	/* Setup USXGMII speed */
 	val = FIELD_PREP(RG_XFI_RX_MODE, RG_XFI_RX_MODE_10G) |
 	      FIELD_PREP(RG_XFI_TX_MODE, RG_XFI_TX_MODE_10G);
-	regmap_write(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val);
+	regmap_write(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, val);
 
 	/* Disable USXGMII AN mode */
-	regmap_read(ss->regmap_usxgmii[id], RG_PCS_AN_CTRL0, &val);
-	val &= ~RG_AN_ENABLE;
-	regmap_write(ss->regmap_usxgmii[id], RG_PCS_AN_CTRL0, val);
+	regmap_read(mpcs->regmap, RG_PCS_AN_CTRL0, &val);
+	val &= ~USXGMII_AN_ENABLE;
+	regmap_write(mpcs->regmap, RG_PCS_AN_CTRL0, val);
 
 	/* Gated USXGMII */
-	regmap_read(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val);
+	regmap_read(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, &val);
 	val |= RG_MAC_CK_GATED;
-	regmap_write(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val);
+	regmap_write(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, val);
 
 	ndelay(1020);
 
 	/* USXGMII force mode setting */
-	regmap_read(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val);
+	regmap_read(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, &val);
 	val |= RG_USXGMII_RATE_UPDATE_MODE;
 	val |= RG_IF_FORCE_EN;
 	val |= FIELD_PREP(RG_RATE_ADAPT_MODE, RG_RATE_ADAPT_MODE_X1);
-	regmap_write(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val);
+	regmap_write(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, val);
 
 	/* Un-gated USXGMII */
-	regmap_read(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val);
+	regmap_read(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, &val);
 	val &= ~RG_MAC_CK_GATED;
-	regmap_write(ss->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val);
+	regmap_write(mpcs->regmap, RG_PHY_TOP_SPEED_CTRL1, val);
 
 	ndelay(1020);
 
-	regmap_update_bits(ss->regmap_pextp[id], 0x9024, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x9024, GENMASK(31, 0),
 			   0x00C9071C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2020, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x2020, GENMASK(31, 0),
 			   0xAA8585AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2030, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x2030, GENMASK(31, 0),
 			   0x0C020707);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2034, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x2034, GENMASK(31, 0),
 			   0x0E050F0F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x2040, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x2040, GENMASK(31, 0),
 			   0x00140032);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50F0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50F0, GENMASK(31, 0),
 			   0x00C014AA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E0, GENMASK(31, 0),
 			   0x3777C12B);
-	regmap_update_bits(ss->regmap_pextp[id], 0x506C, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x506C, GENMASK(31, 0),
 			   0x005F9CFF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5070, GENMASK(31, 0),
 			   0x9D9DFAFA);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5074, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5074, GENMASK(31, 0),
 			   0x27273F3F);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5078, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5078, GENMASK(31, 0),
 			   0xA7883C68);
-	regmap_update_bits(ss->regmap_pextp[id], 0x507C, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x507C, GENMASK(31, 0),
 			   0x11661166);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5080, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5080, GENMASK(31, 0),
 			   0x0E000AAF);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5084, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5084, GENMASK(31, 0),
 			   0x08080D0D);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5088, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5088, GENMASK(31, 0),
 			   0x02030909);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E4, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E4, GENMASK(31, 0),
 			   0x0C0C0000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50E8, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50E8, GENMASK(31, 0),
 			   0x04040000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50EC, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50EC, GENMASK(31, 0),
 			   0x0F0F0C06);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50A8, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50A8, GENMASK(31, 0),
 			   0x506E8C8C);
-	regmap_update_bits(ss->regmap_pextp[id], 0x6004, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x6004, GENMASK(31, 0),
 			   0x18190000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F8, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F8, GENMASK(31, 0),
 			   0x01423342);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
 			   0x80201F20);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0030, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0030, GENMASK(31, 0),
 			   0x00050C00);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x02002800);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
 			   0x00000020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3028, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3028, GENMASK(31, 0),
 			   0x00008A01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x302C, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x302C, GENMASK(31, 0),
 			   0x0000A884);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3024, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3024, GENMASK(31, 0),
 			   0x00083002);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3010, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3010, GENMASK(31, 0),
 			   0x00022220);
-	regmap_update_bits(ss->regmap_pextp[id], 0x5064, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x5064, GENMASK(31, 0),
 			   0x0F020A01);
-	regmap_update_bits(ss->regmap_pextp[id], 0x50B4, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x50B4, GENMASK(31, 0),
 			   0x06100600);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3048, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3048, GENMASK(31, 0),
 			   0x49664100);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3050, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3050, GENMASK(31, 0),
 			   0x00000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3054, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3054, GENMASK(31, 0),
 			   0x00000000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x306C, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x306C, GENMASK(31, 0),
 			   0x00000F00);
-	regmap_update_bits(ss->regmap_pextp[id], 0xA060, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0xA060, GENMASK(31, 0),
 			   0x00040000);
-	regmap_update_bits(ss->regmap_pextp[id], 0x90D0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x90D0, GENMASK(31, 0),
 			   0x00000001);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0200E800);
 	udelay(150);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0200C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0200C101);
 	udelay(15);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0202C111);
 	ndelay(1020);
-	regmap_update_bits(ss->regmap_pextp[id], 0x0070, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x0070, GENMASK(31, 0),
 			   0x0202C101);
 	udelay(100);
-	regmap_update_bits(ss->regmap_pextp[id], 0x30B0, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x30B0, GENMASK(31, 0),
 			   0x00000030);
-	regmap_update_bits(ss->regmap_pextp[id], 0x00F4, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x00F4, GENMASK(31, 0),
 			   0x80201F00);
-	regmap_update_bits(ss->regmap_pextp[id], 0x3040, GENMASK(31, 0),
+	regmap_update_bits(mpcs->regmap_pextp, 0x3040, GENMASK(31, 0),
 			   0x30000000);
 	udelay(400);
+
+	return 0;
 }
 
-void mtk_usxgmii_reset(struct mtk_xgmii *ss, int mac_id)
+void mtk_usxgmii_reset(struct mtk_eth *eth, int id)
 {
-	struct mtk_eth *eth = ss->eth;
-	u32 id = mtk_mac2xgmii_id(eth, mac_id);
 	u32 val = 0;
 
 	if (id >= MTK_MAX_DEVS || !eth->toprgu)
 		return;
 
-	switch (mac_id) {
-	case MTK_GMAC2_ID:
+	switch (id) {
+	case 0:
 		/* Enable software reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
-		val |= SWSYSRST_XFI_PEXPT1_GRST |
-		       SWSYSRST_XFI1_GRST;
+		val |= SWSYSRST_XFI_PEXPT0_GRST |
+		       SWSYSRST_XFI0_GRST;
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
 
 		/* Assert USXGMII reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
 		val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
-		       SWSYSRST_XFI_PEXPT1_GRST |
-		       SWSYSRST_XFI1_GRST;
+		       SWSYSRST_XFI_PEXPT0_GRST |
+		       SWSYSRST_XFI0_GRST;
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
 
 		udelay(100);
@@ -491,28 +553,28 @@
 		/* De-assert USXGMII reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
 		val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
-		val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
-			 SWSYSRST_XFI1_GRST);
+		val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
+			 SWSYSRST_XFI0_GRST);
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
 
 		/* Disable software reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
-		val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
-			 SWSYSRST_XFI1_GRST);
+		val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
+			 SWSYSRST_XFI0_GRST);
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
 		break;
-	case MTK_GMAC3_ID:
+	case 1:
 		/* Enable software reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
-		val |= SWSYSRST_XFI_PEXPT0_GRST |
-		       SWSYSRST_XFI0_GRST;
+		val |= SWSYSRST_XFI_PEXPT1_GRST |
+		       SWSYSRST_XFI1_GRST;
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
 
 		/* Assert USXGMII reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
 		val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) |
-		       SWSYSRST_XFI_PEXPT0_GRST |
-		       SWSYSRST_XFI0_GRST;
+		       SWSYSRST_XFI_PEXPT1_GRST |
+		       SWSYSRST_XFI1_GRST;
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
 
 		udelay(100);
@@ -520,14 +582,14 @@
 		/* De-assert USXGMII reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val);
 		val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88);
-		val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
-			 SWSYSRST_XFI0_GRST);
+		val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
+			 SWSYSRST_XFI1_GRST);
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val);
 
 		/* Disable software reset */
 		regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val);
-		val &= ~(SWSYSRST_XFI_PEXPT0_GRST |
-			 SWSYSRST_XFI0_GRST);
+		val &= ~(SWSYSRST_XFI_PEXPT1_GRST |
+			 SWSYSRST_XFI1_GRST);
 		regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val);
 		break;
 	}
@@ -535,37 +597,163 @@
 	mdelay(10);
 }
 
-int mtk_usxgmii_setup_mode_an(struct mtk_xgmii *ss, int mac_id, int max_speed)
+static void mtk_usxgmii_pcs_get_state(struct phylink_pcs *pcs,
+				    struct phylink_link_state *state)
 {
-	if (mac_id < 0 || mac_id >= MTK_MAX_DEVS)
-		return -EINVAL;
+	struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
+	struct mtk_eth *eth = mpcs->eth;
+	struct mtk_mac *mac = eth->mac[mtk_xgmii2mac_id(eth, mpcs->id)];
+	u32 val = 0;
 
-	if ((max_speed != SPEED_10000) && (max_speed != SPEED_5000))
-		return -EINVAL;
+	regmap_read(mpcs->regmap, RG_PCS_AN_CTRL0, &val);
+	if (FIELD_GET(USXGMII_AN_ENABLE, val)) {
+		/* Refresh LPA by inverting LPA_LATCH */
+		regmap_read(mpcs->regmap, RG_PCS_AN_STS0, &val);
+		regmap_update_bits(mpcs->regmap, RG_PCS_AN_STS0,
+				   USXGMII_LPA_LATCH,
+				   !(val & USXGMII_LPA_LATCH));
 
-	mtk_xfi_pll_enable(ss);
-	mtk_usxgmii_reset(ss, mac_id);
-	mtk_usxgmii_setup_phya_an_10000(ss, mac_id);
+		regmap_read(mpcs->regmap, RG_PCS_AN_STS0, &val);
 
-	return 0;
+		state->interface = mpcs->interface;
+		state->link = FIELD_GET(USXGMII_LPA_LINK, val);
+		state->duplex = FIELD_GET(USXGMII_LPA_DUPLEX, val);
+
+		switch (FIELD_GET(USXGMII_LPA_SPEED_MASK, val)) {
+		case USXGMII_LPA_SPEED_10:
+			state->speed = SPEED_10;
+			break;
+		case USXGMII_LPA_SPEED_100:
+			state->speed = SPEED_100;
+			break;
+		case USXGMII_LPA_SPEED_1000:
+			state->speed = SPEED_1000;
+			break;
+		case USXGMII_LPA_SPEED_2500:
+			state->speed = SPEED_2500;
+			break;
+		case USXGMII_LPA_SPEED_5000:
+			state->speed = SPEED_5000;
+			break;
+		case USXGMII_LPA_SPEED_10000:
+			state->speed = SPEED_10000;
+			break;
+		}
+	} else {
+		val = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
+
+		if (mac->id == MTK_GMAC2_ID)
+			val = val >> 16;
+
+		switch (FIELD_GET(MTK_USXGMII_PCS_MODE, val)) {
+		case 0:
+			state->speed = SPEED_10000;
+			break;
+		case 1:
+			state->speed = SPEED_5000;
+			break;
+		case 2:
+			state->speed = SPEED_2500;
+			break;
+		case 3:
+			state->speed = SPEED_1000;
+			break;
+		}
+
+		state->interface = mpcs->interface;
+		state->link = FIELD_GET(MTK_USXGMII_PCS_LINK, val);
+		state->duplex = DUPLEX_FULL;
+	}
 }
 
-int mtk_usxgmii_setup_mode_force(struct mtk_xgmii *ss, int mac_id,
-				 const struct phylink_link_state *state)
+static int mtk_usxgmii_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
+				  phy_interface_t interface,
+				  const unsigned long *advertising,
+				  bool permit_pause_to_mac)
 {
-	if (mac_id < 0 || mac_id >= MTK_MAX_DEVS)
-		return -EINVAL;
+	struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
+	struct mtk_eth *eth = mpcs->eth;
+	int err = 0;
+
+	mpcs->interface = interface;
+
+	mtk_usxgmii_xfi_pll_enable(eth->usxgmii);
+	mtk_usxgmii_reset(eth, mpcs->id);
+
+	/* Setup USXGMIISYS with the determined property */
+	if (interface == PHY_INTERFACE_MODE_USXGMII)
+		err = mtk_usxgmii_setup_phya_an_10000(mpcs);
+	else if (interface == PHY_INTERFACE_MODE_10GKR)
+		err = mtk_usxgmii_setup_phya_force_10000(mpcs);
+	else if (interface == PHY_INTERFACE_MODE_5GBASER)
+		err = mtk_usxgmii_setup_phya_force_5000(mpcs);
+
+	return err;
+}
+
+void mtk_usxgmii_pcs_restart_an(struct phylink_pcs *pcs)
+{
+	struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
+	unsigned int val = 0;
+
+	if (!mpcs->regmap)
+		return;
 
-	mtk_xfi_pll_enable(ss);
-	mtk_usxgmii_reset(ss, mac_id);
-	if (state->interface == PHY_INTERFACE_MODE_5GBASER)
-		mtk_usxgmii_setup_phya_force_5000(ss, mac_id);
-	else
-		mtk_usxgmii_setup_phya_force_10000(ss, mac_id);
+	regmap_read(mpcs->regmap, RG_PCS_AN_CTRL0, &val);
+	val |= USXGMII_AN_RESTART;
+	regmap_write(mpcs->regmap, RG_PCS_AN_CTRL0, val);
+}
+
+static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = {
+	.pcs_config = mtk_usxgmii_pcs_config,
+	.pcs_get_state = mtk_usxgmii_pcs_get_state,
+	.pcs_an_restart = mtk_usxgmii_pcs_restart_an,
+};
+
+int mtk_usxgmii_init(struct mtk_eth *eth, struct device_node *r)
+{
+	struct mtk_usxgmii *ss = eth->usxgmii;
+	struct device_node *np;
+	int ret, i;
+
+	for (i = 0; i < MTK_MAX_DEVS; i++) {
+		np = of_parse_phandle(r, "mediatek,usxgmiisys", i);
+		if (!np)
+			break;
+
+		ss->pcs[i].id = i;
+		ss->pcs[i].eth = eth;
+
+		ss->pcs[i].regmap = syscon_node_to_regmap(np);
+		if (IS_ERR(ss->pcs[i].regmap))
+			return PTR_ERR(ss->pcs[i].regmap);
+
+		ss->pcs[i].pcs.ops = &mtk_usxgmii_pcs_ops;
+		ss->pcs[i].pcs.poll = true;
+		ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
+
+		of_node_put(np);
+	}
+
+	ret = mtk_usxgmii_xfi_pextp_init(ss, r);
+	if (ret)
+		return ret;
+
+	ret = mtk_usxgmii_xfi_pll_init(ss, r);
+	if (ret)
+		return ret;
 
 	return 0;
 }
 
+struct phylink_pcs *mtk_usxgmii_select_pcs(struct mtk_usxgmii *ss, int id)
+{
+	if (!ss->pcs[id].regmap)
+		return NULL;
+
+	return &ss->pcs[id].pcs;
+}
+
 int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range)
 {
 	unsigned int cur = offset;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9990-mt7622-backport-nf-hw-offload-framework-and-ups.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9990-mt7622-backport-nf-hw-offload-framework-and-ups.patch
index 7d4c5d6..a7dfc86 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9990-mt7622-backport-nf-hw-offload-framework-and-ups.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9990-mt7622-backport-nf-hw-offload-framework-and-ups.patch
@@ -6125,7 +6125,7 @@
 index 000000000..ae1eb2656
 --- /dev/null
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -0,0 +1,776 @@
+@@ -0,0 +1,785 @@
 +/*
 + * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
 + *
@@ -6510,19 +6510,28 @@
 +	return dev_fill_forward_path(dev, ha, stack);
 +}
 +
-+static int nf_dev_forward_path(struct nf_flow_route *route,
++static int nf_dev_forward_path(struct sk_buff *skb,
++				struct nf_flow_route *route,
 +				const struct nf_conn *ct,
 +				enum ip_conntrack_dir dir,
 +				struct net_device **devs)
 +{
 +	const struct dst_entry *dst = route->tuple[dir].dst;
++	struct ethhdr *eth = eth_hdr(skb);
 +	struct net_device_path_stack stack;
 +	struct nf_forward_info info = {};
 +	unsigned char ha[ETH_ALEN];
 +	int i;
 +
-+	if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0)
++	if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0) {
++		if (!(ct->status & IPS_NAT_MASK)) {
++			if (dir == IP_CT_DIR_ORIGINAL)
++				memcpy(info.h_source, eth->h_source, ETH_ALEN);
++			else if (dir == IP_CT_DIR_REPLY)
++				memcpy(info.h_source, eth->h_dest, ETH_ALEN);
++		}
 +		nf_dev_path_info(&stack, &info, ha);
++	}
 +
 +	devs[!dir] = (struct net_device *)info.indev;
 +	if (!info.indev)
@@ -6608,11 +6617,11 @@
 +	nf_default_forward_path(route, this_dst, dir, devs);
 +	nf_default_forward_path(route, other_dst, !dir, devs);
 +
-+	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH &&
++	if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
 +	    route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
-+		if (nf_dev_forward_path(route, ct, dir, devs))
++		if (nf_dev_forward_path(skb, route, ct, dir, devs))
 +			return -1;
-+		if (nf_dev_forward_path(route, ct, !dir, devs))
++		if (nf_dev_forward_path(skb, route, ct, !dir, devs))
 +			return -1;
 +	}
 +
@@ -6639,10 +6648,10 @@
 +	if (ret)
 +		goto err_route_dir1;
 +
-+	if (route->tuple[dir].xmit_type	== FLOW_OFFLOAD_XMIT_NEIGH &&
++	if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH &&
 +	    route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) {
-+		if (nf_dev_forward_path(route, ct, dir, devs) ||
-+		    nf_dev_forward_path(route, ct, !dir, devs)) {
++		if (nf_dev_forward_path(skb, route, ct, dir, devs) ||
++		    nf_dev_forward_path(skb, route, ct, !dir, devs)) {
 +			ret = -1;
 +			goto err_route_dir2;
 +		}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9996-add-wed-tx-support-for-mt7986.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9996-add-wed-tx-support-for-mt7986.patch
index 16a2b27..7734ce2 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9996-add-wed-tx-support-for-mt7986.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/9996-add-wed-tx-support-for-mt7986.patch
@@ -1011,7 +1011,7 @@
  #define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH		BIT(12)
  #define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH		BIT(13)
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR	BIT(16)
-@@ -57,16 +72,24 @@ struct mtk_wdma_desc {
+@@ -57,16 +71,23 @@ struct mtk_wdma_desc {
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN	BIT(19)
  #define MTK_WED_EXT_INT_STATUS_RX_DRV_BM_DMAD_COHERENT	BIT(20)
  #define MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR	BIT(21)
@@ -1030,7 +1030,6 @@
 +							 MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH | \
  							 MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \
  							 MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \
-+							 MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT | \
  							 MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \
 -							 MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR | \
 -							 MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
index 65698d9..a7a4481 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/755-net-phy-sfp-add-rollball-support.patch
@@ -676,7 +676,7 @@
  
  #if IS_ENABLED(CONFIG_HWMON)
  	struct sfp_diag diag;
-@@ -303,6 +313,136 @@ static const struct of_device_id sfp_of_
+@@ -303,6 +313,144 @@ static const struct of_device_id sfp_of_
  };
  MODULE_DEVICE_TABLE(of, sfp_of_match);
  
@@ -721,6 +721,12 @@
 +	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes);
 +}
 +
++static void sfp_quirk_10000baseSR(const struct sfp_eeprom_id *id,
++				  unsigned long *modes)
++{
++	linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, modes);
++}
++
 +static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
 +				      unsigned long *modes)
 +{
@@ -758,6 +764,8 @@
 +	// 2500MBd NRZ in their EEPROM
 +	SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex),
 +
++	SFP_QUIRK_M("CISCO-JDSU", "PLRXPL-VC-S43-CG", sfp_quirk_10000baseSR),
++
 +	SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant),
 +
 +	SFP_QUIRK_F("ETU", "ESP-T5-R", sfp_fixup_rollball_cc),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/757-net-phy-add-phylink-pcs-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/757-net-phy-add-phylink-pcs-support.patch
new file mode 100644
index 0000000..f449505
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/757-net-phy-add-phylink-pcs-support.patch
@@ -0,0 +1,774 @@
+diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
+index 67f34ed..ead9b37 100644
+--- a/drivers/net/phy/phylink.c
++++ b/drivers/net/phy/phylink.c
+@@ -40,8 +40,9 @@ enum {
+ struct phylink {
+ 	/* private: */
+ 	struct net_device *netdev;
+-	const struct phylink_mac_ops *ops;
++	const struct phylink_mac_ops *mac_ops;
+ 	struct phylink_config *config;
++	struct phylink_pcs *pcs;
+ 	struct device *dev;
+ 	unsigned int old_link_state:1;
+ 
+@@ -70,6 +71,7 @@ struct phylink {
+ 	struct work_struct resolve;
+ 
+ 	bool mac_link_dropped;
++	bool using_mac_select_pcs;
+ 
+ 	struct sfp_bus *sfp_bus;
+ 	bool sfp_may_have_phy;
+@@ -153,14 +155,60 @@ static const char *phylink_an_mode_str(unsigned int mode)
+ 	return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
+ }
+ 
+-static int phylink_validate(struct phylink *pl, unsigned long *supported,
+-			    struct phylink_link_state *state)
++static int phylink_validate_mac_and_pcs(struct phylink *pl,
++					unsigned long *supported,
++					struct phylink_link_state *state)
+ {
+-	pl->ops->validate(pl->config, supported, state);
++	struct phylink_pcs *pcs;
++	int ret;
++
++	/* Get the PCS for this interface mode */
++	if (pl->using_mac_select_pcs) {
++		pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
++		if (IS_ERR(pcs))
++			return PTR_ERR(pcs);
++	} else {
++		pcs = pl->pcs;
++	}
++
++	if (pcs) {
++		/* The PCS, if present, must be setup before phylink_create()
++		 * has been called. If the ops is not initialised, print an
++		 * error and backtrace rather than oopsing the kernel.
++		 */
++		if (!pcs->ops) {
++			phylink_err(pl, "interface %s: uninitialised PCS\n",
++				    phy_modes(state->interface));
++			dump_stack();
++			return -EINVAL;
++		}
++
++		/* Validate the link parameters with the PCS */
++		if (pcs->ops->pcs_validate) {
++			ret = pcs->ops->pcs_validate(pcs, supported, state);
++			if (ret < 0 || phylink_is_empty_linkmode(supported))
++				return -EINVAL;
++
++			/* Ensure the advertising mask is a subset of the
++			 * supported mask.
++			 */
++			linkmode_and(state->advertising, state->advertising,
++				     supported);
++		}
++	}
++
++	/* Then validate the link parameters with the MAC */
++	pl->mac_ops->validate(pl->config, supported, state);
+ 
+ 	return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
+ }
+ 
++static int phylink_validate(struct phylink *pl, unsigned long *supported,
++			    struct phylink_link_state *state)
++{
++	return phylink_validate_mac_and_pcs(pl, supported, state);
++}
++
+ static int phylink_parse_fixedlink(struct phylink *pl,
+ 				   struct fwnode_handle *fwnode)
+ {
+@@ -338,6 +386,18 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
+ 	return 0;
+ }
+ 
++static void phylink_pcs_poll_stop(struct phylink *pl)
++{
++	if (pl->cfg_link_an_mode == MLO_AN_INBAND)
++		del_timer(&pl->link_poll);
++}
++
++static void phylink_pcs_poll_start(struct phylink *pl)
++{
++	if (pl->pcs && pl->pcs->poll && pl->cfg_link_an_mode == MLO_AN_INBAND)
++		mod_timer(&pl->link_poll, jiffies + HZ);
++}
++
+ static void phylink_mac_config(struct phylink *pl,
+ 			       const struct phylink_link_state *state)
+ {
+@@ -350,37 +410,113 @@ static void phylink_mac_config(struct phylink *pl,
+ 		    __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
+ 		    state->pause, state->link, state->an_enabled);
+ 
+-	pl->ops->mac_config(pl->config, pl->cur_link_an_mode, state);
++	pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, state);
+ }
+ 
+-static void phylink_mac_config_up(struct phylink *pl,
+-				  const struct phylink_link_state *state)
++static void phylink_mac_pcs_an_restart(struct phylink *pl)
+ {
+-	if (state->link)
+-		phylink_mac_config(pl, state);
++	if (pl->link_config.an_enabled &&
++	    phy_interface_mode_is_8023z(pl->link_config.interface) &&
++	    phylink_autoneg_inband(pl->cur_link_an_mode)) {
++		if (pl->pcs)
++			pl->pcs->ops->pcs_an_restart(pl->pcs);
++		else if (pl->mac_ops->mac_an_restart)
++			pl->mac_ops->mac_an_restart(pl->config);
++	}
+ }
+ 
+-static void phylink_mac_an_restart(struct phylink *pl)
++static void phylink_major_config(struct phylink *pl, bool restart,
++				  const struct phylink_link_state *state)
+ {
+-	if (pl->link_config.an_enabled &&
+-	    phy_interface_mode_is_8023z(pl->link_config.interface))
+-		pl->ops->mac_an_restart(pl->config);
++	struct phylink_pcs *pcs = NULL;
++	bool pcs_changed = false;
++	int err;
++
++	phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
++
++	if (pl->using_mac_select_pcs) {
++		pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
++		if (IS_ERR(pcs)) {
++			phylink_err(pl,
++				    "mac_select_pcs unexpectedly failed: %pe\n",
++				    pcs);
++			return;
++		}
++
++		pcs_changed = pcs && pl->pcs != pcs;
++	}
++
++	phylink_pcs_poll_stop(pl);
++
++	if (pl->mac_ops->mac_prepare) {
++		err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
++					       state->interface);
++		if (err < 0) {
++			phylink_err(pl, "mac_prepare failed: %pe\n",
++				    ERR_PTR(err));
++			return;
++		}
++	}
++
++	/* If we have a new PCS, switch to the new PCS after preparing the MAC
++	 * for the change.
++	 */
++	if (pcs_changed)
++		pl->pcs = pcs;
++
++	phylink_mac_config(pl, state);
++
++	if (pl->pcs) {
++		err = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
++					       state->interface,
++					       state->advertising,
++					       !!(pl->link_config.pause &
++						  MLO_PAUSE_AN));
++		if (err < 0)
++			phylink_err(pl, "pcs_config failed: %pe\n",
++				    ERR_PTR(err));
++		if (err > 0)
++			restart = true;
++	}
++	if (restart)
++		phylink_mac_pcs_an_restart(pl);
++
++	if (pl->mac_ops->mac_finish) {
++		err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode,
++					      state->interface);
++		if (err < 0)
++			phylink_err(pl, "mac_finish failed: %pe\n",
++				    ERR_PTR(err));
++	}
++
++	phylink_pcs_poll_start(pl);
+ }
+ 
+-static int phylink_get_mac_state(struct phylink *pl, struct phylink_link_state *state)
++static void phylink_mac_pcs_get_state(struct phylink *pl,
++				      struct phylink_link_state *state)
+ {
+-
+ 	linkmode_copy(state->advertising, pl->link_config.advertising);
+ 	linkmode_zero(state->lp_advertising);
+ 	state->interface = pl->link_config.interface;
+ 	state->an_enabled = pl->link_config.an_enabled;
+-	state->speed = SPEED_UNKNOWN;
+-	state->duplex = DUPLEX_UNKNOWN;
+-	state->pause = MLO_PAUSE_NONE;
++	if (state->an_enabled) {
++		state->speed = SPEED_UNKNOWN;
++		state->duplex = DUPLEX_UNKNOWN;
++		state->pause = MLO_PAUSE_NONE;
++	} else {
++		state->speed =  pl->link_config.speed;
++		state->duplex = pl->link_config.duplex;
++		state->pause = pl->link_config.pause;
++	}
+ 	state->an_complete = 0;
+ 	state->link = 1;
+ 
+-	return pl->ops->mac_link_state(pl->config, state);
++	if (pl->pcs)
++		pl->pcs->ops->pcs_get_state(pl->pcs, state);
++	else if (pl->mac_ops->mac_link_state)
++		pl->mac_ops->mac_link_state(pl->config, state);
++	else
++		state->link = 0;
+ }
+ 
+ /* The fixed state is... fixed except for the link state,
+@@ -395,6 +531,34 @@ static void phylink_get_fixed_state(struct phylink *pl, struct phylink_link_stat
+ 		state->link = !!gpiod_get_value_cansleep(pl->link_gpio);
+ }
+ 
++static void phylink_mac_initial_config(struct phylink *pl, bool force_restart)
++{
++	struct phylink_link_state link_state;
++
++	switch (pl->cur_link_an_mode) {
++	case MLO_AN_PHY:
++		link_state = pl->phy_state;
++		break;
++
++	case MLO_AN_FIXED:
++		phylink_get_fixed_state(pl, &link_state);
++		break;
++
++	case MLO_AN_INBAND:
++		link_state = pl->link_config;
++		if (link_state.interface == PHY_INTERFACE_MODE_SGMII)
++			link_state.pause = MLO_PAUSE_NONE;
++		break;
++
++	default: /* can't happen */
++		return;
++	}
++
++	link_state.link = false;
++
++	phylink_major_config(pl, force_restart, &link_state);
++}
++
+ /* Flow control is resolved according to our and the link partners
+  * advertisements using the following drawn from the 802.3 specs:
+  *  Local device  Link partner
+@@ -445,17 +609,25 @@ static const char *phylink_pause_to_str(int pause)
+ 	}
+ }
+ 
+-static void phylink_mac_link_up(struct phylink *pl,
+-				struct phylink_link_state link_state)
++static void phylink_link_up(struct phylink *pl,
++			    struct phylink_link_state link_state)
+ {
+ 	struct net_device *ndev = pl->netdev;
++	int speed, duplex;
++
++	speed = link_state.speed;
++	duplex = link_state.duplex;
+ 
+ 	pl->cur_interface = link_state.interface;
+-	pl->ops->mac_link_up(pl->config, pl->phydev,
+-			     pl->cur_link_an_mode, pl->cur_interface,
+-			     link_state.speed, link_state.duplex,
+-			     !!(link_state.pause & MLO_PAUSE_TX),
+-			     !!(link_state.pause & MLO_PAUSE_RX));
++
++	if (pl->pcs && pl->pcs->ops->pcs_link_up)
++		pl->pcs->ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode,
++					  pl->cur_interface, speed, duplex);
++
++	pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode,
++				 pl->cur_interface, speed, duplex,
++				 !!(link_state.pause & MLO_PAUSE_TX),
++				 !!(link_state.pause & MLO_PAUSE_RX));
+ 
+ 	if (ndev)
+ 		netif_carrier_on(ndev);
+@@ -467,14 +639,14 @@ static void phylink_mac_link_up(struct phylink *pl,
+ 		     phylink_pause_to_str(link_state.pause));
+ }
+ 
+-static void phylink_mac_link_down(struct phylink *pl)
++static void phylink_link_down(struct phylink *pl)
+ {
+ 	struct net_device *ndev = pl->netdev;
+ 
+ 	if (ndev)
+ 		netif_carrier_off(ndev);
+-	pl->ops->mac_link_down(pl->config, pl->cur_link_an_mode,
+-			       pl->cur_interface);
++	pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode,
++				   pl->cur_interface);
+ 	phylink_info(pl, "Link is Down\n");
+ }
+ 
+@@ -513,7 +685,7 @@ static void phylink_resolve(struct work_struct *w)
+ 			break;
+ 
+ 		case MLO_AN_INBAND:
+-			phylink_get_mac_state(pl, &link_state);
++			phylink_mac_pcs_get_state(pl, &link_state);
+ 
+ 			/* The PCS may have a latching link-fail indicator.
+ 			 * If the link was up, bring the link down and
+@@ -524,8 +696,8 @@ static void phylink_resolve(struct work_struct *w)
+ 				if (cur_link_state)
+ 					retrigger = true;
+ 				else
+-					phylink_get_mac_state(pl,
+-							      &link_state);
++					phylink_mac_pcs_get_state(pl,
++								  &link_state);
+ 			}
+ 
+ 			/* If we have a phy, the "up" state is the union of
+@@ -564,12 +736,17 @@ static void phylink_resolve(struct work_struct *w)
+ 			 * then reconfigure.
+ 			 */
+ 			if (cur_link_state) {
+-				phylink_mac_link_down(pl);
++				phylink_link_down(pl);
+ 				cur_link_state = false;
+ 			}
+-			phylink_mac_config(pl, &link_state);
++			phylink_major_config(pl, false, &link_state);
+ 			pl->link_config.interface = link_state.interface;
+-		} else {
++		} else if (!pl->pcs) {
++			/* The interface remains unchanged, only the speed,
++			 * duplex or pause settings have changed. Call the
++			 * old mac_config() method to configure the MAC/PCS
++			 * only if we do not have a legacy MAC driver.
++			 */
+ 			phylink_mac_config(pl, &link_state);
+ 		}
+ 	}
+@@ -577,9 +754,9 @@ static void phylink_resolve(struct work_struct *w)
+ 	if (link_state.link != cur_link_state) {
+ 		pl->old_link_state = link_state.link;
+ 		if (!link_state.link)
+-			phylink_mac_link_down(pl);
++			phylink_link_down(pl);
+ 		else
+-			phylink_mac_link_up(pl, link_state);
++			phylink_link_up(pl, link_state);
+ 	}
+ 	if (!link_state.link && retrigger) {
+ 		pl->mac_link_dropped = false;
+@@ -643,7 +820,7 @@ static int phylink_register_sfp(struct phylink *pl,
+  * @fwnode: a pointer to a &struct fwnode_handle describing the network
+  *	interface
+  * @iface: the desired link mode defined by &typedef phy_interface_t
+- * @ops: a pointer to a &struct phylink_mac_ops for the MAC.
++ * @mac_ops: a pointer to a &struct phylink_mac_ops for the MAC.
+  *
+  * Create a new phylink instance, and parse the link parameters found in @np.
+  * This will parse in-band modes, fixed-link or SFP configuration.
+@@ -656,11 +833,17 @@ static int phylink_register_sfp(struct phylink *pl,
+ struct phylink *phylink_create(struct phylink_config *config,
+ 			       struct fwnode_handle *fwnode,
+ 			       phy_interface_t iface,
+-			       const struct phylink_mac_ops *ops)
++			       const struct phylink_mac_ops *mac_ops)
+ {
++	bool using_mac_select_pcs = false;
+ 	struct phylink *pl;
+ 	int ret;
+ 
++	if (mac_ops->mac_select_pcs &&
++	    mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) !=
++	      ERR_PTR(-EOPNOTSUPP))
++		using_mac_select_pcs = true;
++
+ 	pl = kzalloc(sizeof(*pl), GFP_KERNEL);
+ 	if (!pl)
+ 		return ERR_PTR(-ENOMEM);
+@@ -678,6 +861,7 @@ struct phylink *phylink_create(struct phylink_config *config,
+ 		return ERR_PTR(-EINVAL);
+ 	}
+ 
++	pl->using_mac_select_pcs = using_mac_select_pcs;
+ 	pl->phy_state.interface = iface;
+ 	pl->link_interface = iface;
+ 	if (iface == PHY_INTERFACE_MODE_MOCA)
+@@ -689,7 +873,7 @@ struct phylink *phylink_create(struct phylink_config *config,
+ 	pl->link_config.speed = SPEED_UNKNOWN;
+ 	pl->link_config.duplex = DUPLEX_UNKNOWN;
+ 	pl->link_config.an_enabled = true;
+-	pl->ops = ops;
++	pl->mac_ops = mac_ops;
+ 	__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
+ 	timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
+ 
+@@ -1016,6 +1200,8 @@ static irqreturn_t phylink_link_handler(int irq, void *data)
+  */
+ void phylink_start(struct phylink *pl)
+ {
++	bool poll = false;
++
+ 	ASSERT_RTNL();
+ 
+ 	phylink_info(pl, "configuring for %s/%s link mode\n",
+@@ -1029,15 +1215,12 @@ void phylink_start(struct phylink *pl)
+ 	/* Apply the link configuration to the MAC when starting. This allows
+ 	 * a fixed-link to start with the correct parameters, and also
+ 	 * ensures that we set the appropriate advertisement for Serdes links.
+-	 */
+-	phylink_resolve_flow(pl, &pl->link_config);
+-	phylink_mac_config(pl, &pl->link_config);
+-
+-	/* Restart autonegotiation if using 802.3z to ensure that the link
++	 *
++	 * Restart autonegotiation if using 802.3z to ensure that the link
+ 	 * parameters are properly negotiated.  This is necessary for DSA
+ 	 * switches using 802.3z negotiation to ensure they see our modes.
+ 	 */
+-	phylink_mac_an_restart(pl);
++	phylink_mac_initial_config(pl, true);
+ 
+ 	clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
+ 	phylink_run_resolve(pl);
+@@ -1055,10 +1238,19 @@ void phylink_start(struct phylink *pl)
+ 				irq = 0;
+ 		}
+ 		if (irq <= 0)
+-			mod_timer(&pl->link_poll, jiffies + HZ);
++			poll = true;
+ 	}
+-	if ((pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) ||
+-	    (pl->cfg_link_an_mode == MLO_AN_INBAND))
++
++	switch (pl->cfg_link_an_mode) {
++	case MLO_AN_FIXED:
++		poll |= pl->config->poll_fixed_state;
++		break;
++	case MLO_AN_INBAND:
++		if (pl->pcs)
++			poll |= pl->pcs->poll;
++		break;
++	}
++	if (poll)
+ 		mod_timer(&pl->link_poll, jiffies + HZ);
+ 	if (pl->phydev)
+ 		phy_start(pl->phydev);
+@@ -1202,7 +1394,7 @@ int phylink_ethtool_ksettings_get(struct phylink *pl,
+ 		if (pl->phydev)
+ 			break;
+ 
+-		phylink_get_mac_state(pl, &link_state);
++		phylink_mac_pcs_get_state(pl, &link_state);
+ 
+ 		/* The MAC is reporting the link results from its own PCS
+ 		 * layer via in-band status. Report these as the current
+@@ -1314,7 +1506,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
+ 	if (pl->cur_link_an_mode == MLO_AN_INBAND &&
+ 	    !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) {
+ 		phylink_mac_config(pl, &pl->link_config);
+-		phylink_mac_an_restart(pl);
++		phylink_mac_pcs_an_restart(pl);
+ 	}
+ 	mutex_unlock(&pl->state_mutex);
+ 
+@@ -1341,7 +1533,7 @@ int phylink_ethtool_nway_reset(struct phylink *pl)
+ 
+ 	if (pl->phydev)
+ 		ret = phy_restart_aneg(pl->phydev);
+-	phylink_mac_an_restart(pl);
++	phylink_mac_pcs_an_restart(pl);
+ 
+ 	return ret;
+ }
+@@ -1410,7 +1602,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
+ 
+ 		case MLO_AN_INBAND:
+ 			phylink_mac_config(pl, config);
+-			phylink_mac_an_restart(pl);
++			phylink_mac_pcs_an_restart(pl);
+ 			break;
+ 		}
+ 	}
+@@ -1621,10 +1813,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id,
+ 
+ 	case MLO_AN_INBAND:
+ 		if (phy_id == 0) {
+-			val = phylink_get_mac_state(pl, &state);
+-			if (val < 0)
+-				return val;
+-
++			phylink_mac_pcs_get_state(pl, &state);
+ 			val = phylink_mii_emul_read(reg, &state);
+ 		}
+ 		break;
+diff --git a/include/linux/phylink.h b/include/linux/phylink.h
+index 8229f56..ba0f09d 100644
+--- a/include/linux/phylink.h
++++ b/include/linux/phylink.h
+@@ -63,17 +63,23 @@ enum phylink_op_type {
+  * struct phylink_config - PHYLINK configuration structure
+  * @dev: a pointer to a struct device associated with the MAC
+  * @type: operation type of PHYLINK instance
++ * @poll_fixed_state: if true, starts link_poll,
++ *		      if MAC link is at %MLO_AN_FIXED mode.
+  */
+ struct phylink_config {
+ 	struct device *dev;
+ 	enum phylink_op_type type;
++	bool poll_fixed_state;
+ };
+ 
+ /**
+  * struct phylink_mac_ops - MAC operations structure.
+  * @validate: Validate and update the link configuration.
++ * @mac_select_pcs: Select a PCS for the interface mode.
+  * @mac_link_state: Read the current link state from the hardware.
++ * @mac_prepare: prepare for a major reconfiguration of the interface.
+  * @mac_config: configure the MAC for the selected mode and state.
++ * @mac_finish: finish a major reconfiguration of the interface.
+  * @mac_an_restart: restart 802.3z BaseX autonegotiation.
+  * @mac_link_down: take the link down.
+  * @mac_link_up: allow the link to come up.
+@@ -84,10 +90,16 @@ struct phylink_mac_ops {
+ 	void (*validate)(struct phylink_config *config,
+ 			 unsigned long *supported,
+ 			 struct phylink_link_state *state);
++	struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config,
++					      phy_interface_t interface);
+ 	int (*mac_link_state)(struct phylink_config *config,
+ 			      struct phylink_link_state *state);
++	int (*mac_prepare)(struct phylink_config *config, unsigned int mode,
++			   phy_interface_t iface);
+ 	void (*mac_config)(struct phylink_config *config, unsigned int mode,
+ 			   const struct phylink_link_state *state);
++	int (*mac_finish)(struct phylink_config *config, unsigned int mode,
++			  phy_interface_t iface);
+ 	void (*mac_an_restart)(struct phylink_config *config);
+ 	void (*mac_link_down)(struct phylink_config *config, unsigned int mode,
+ 			      phy_interface_t interface);
+@@ -126,6 +138,21 @@ struct phylink_mac_ops {
+  */
+ void validate(struct phylink_config *config, unsigned long *supported,
+ 	      struct phylink_link_state *state);
++/**
++ * mac_select_pcs: Select a PCS for the interface mode.
++ * @config: a pointer to a &struct phylink_config.
++ * @interface: PHY interface mode for PCS
++ *
++ * Return the &struct phylink_pcs for the specified interface mode, or
++ * NULL if none is required, or an error pointer on error.
++ *
++ * This must not modify any state. It is used to query which PCS should
++ * be used. Phylink will use this during validation to ensure that the
++ * configuration is valid, and when setting a configuration to internally
++ * set the PCS that will be used.
++ */
++struct phylink_pcs *mac_select_pcs(struct phylink_config *config,
++				   phy_interface_t interface);
+ 
+ /**
+  * mac_link_state() - Read the current link state from the hardware
+@@ -141,6 +168,31 @@ void validate(struct phylink_config *config, unsigned long *supported,
+ int mac_link_state(struct phylink_config *config,
+ 		   struct phylink_link_state *state);
+ 
++/**
++ * mac_prepare() - prepare to change the PHY interface mode
++ * @config: a pointer to a &struct phylink_config.
++ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
++ * @iface: interface mode to switch to
++ *
++ * phylink will call this method at the beginning of a full initialisation
++ * of the link, which includes changing the interface mode or at initial
++ * startup time. It may be called for the current mode. The MAC driver
++ * should perform whatever actions are required, e.g. disabling the
++ * Serdes PHY.
++ *
++ * This will be the first call in the sequence:
++ * - mac_prepare()
++ * - mac_config()
++ * - pcs_config()
++ * - possible pcs_an_restart()
++ * - mac_finish()
++ *
++ * Returns zero on success, or negative errno on failure which will be
++ * reported to the kernel log.
++ */
++int mac_prepare(struct phylink_config *config, unsigned int mode,
++		phy_interface_t iface);
++
+ /**
+  * mac_config() - configure the MAC for the selected mode and state
+  * @config: a pointer to a &struct phylink_config.
+@@ -195,6 +247,23 @@ int mac_link_state(struct phylink_config *config,
+ void mac_config(struct phylink_config *config, unsigned int mode,
+ 		const struct phylink_link_state *state);
+ 
++/**
++ * mac_finish() - finish a to change the PHY interface mode
++ * @config: a pointer to a &struct phylink_config.
++ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
++ * @iface: interface mode to switch to
++ *
++ * phylink will call this if it called mac_prepare() to allow the MAC to
++ * complete any necessary steps after the MAC and PCS have been configured
++ * for the @mode and @iface. E.g. a MAC driver may wish to re-enable the
++ * Serdes PHY here if it was previously disabled by mac_prepare().
++ *
++ * Returns zero on success, or negative errno on failure which will be
++ * reported to the kernel log.
++ */
++int mac_finish(struct phylink_config *config, unsigned int mode,
++		phy_interface_t iface);
++
+ /**
+  * mac_an_restart() - restart 802.3z BaseX autonegotiation
+  * @config: a pointer to a &struct phylink_config.
+@@ -248,6 +317,132 @@ void mac_link_up(struct phylink_config *config, struct phy_device *phy,
+ 		 int speed, int duplex, bool tx_pause, bool rx_pause);
+ #endif
+ 
++struct phylink_pcs_ops;
++
++/**
++ * struct phylink_pcs - PHYLINK PCS instance
++ * @ops: a pointer to the &struct phylink_pcs_ops structure
++ * @poll: poll the PCS for link changes
++ *
++ * This structure is designed to be embedded within the PCS private data,
++ * and will be passed between phylink and the PCS.
++ */
++struct phylink_pcs {
++	const struct phylink_pcs_ops *ops;
++	bool poll;
++};
++
++/**
++ * struct phylink_pcs_ops - MAC PCS operations structure.
++ * @pcs_validate: validate the link configuration.
++ * @pcs_get_state: read the current MAC PCS link state from the hardware.
++ * @pcs_config: configure the MAC PCS for the selected mode and state.
++ * @pcs_an_restart: restart 802.3z BaseX autonegotiation.
++ * @pcs_link_up: program the PCS for the resolved link configuration
++ *               (where necessary).
++ */
++struct phylink_pcs_ops {
++	int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
++			    const struct phylink_link_state *state);
++	void (*pcs_get_state)(struct phylink_pcs *pcs,
++			      struct phylink_link_state *state);
++	int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode,
++			  phy_interface_t interface,
++			  const unsigned long *advertising,
++			  bool permit_pause_to_mac);
++	void (*pcs_an_restart)(struct phylink_pcs *pcs);
++	void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int mode,
++			    phy_interface_t interface, int speed, int duplex);
++};
++
++#if 0 /* For kernel-doc purposes only. */
++/**
++ * pcs_validate() - validate the link configuration.
++ * @pcs: a pointer to a &struct phylink_pcs.
++ * @supported: ethtool bitmask for supported link modes.
++ * @state: a const pointer to a &struct phylink_link_state.
++ *
++ * Validate the interface mode, and advertising's autoneg bit, removing any
++ * media ethtool link modes that would not be supportable from the supported
++ * mask. Phylink will propagate the changes to the advertising mask. See the
++ * &struct phylink_mac_ops validate() method.
++ *
++ * Returns -EINVAL if the interface mode/autoneg mode is not supported.
++ * Returns non-zero positive if the link state can be supported.
++ */
++int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
++		 const struct phylink_link_state *state);
++
++/**
++ * pcs_get_state() - Read the current inband link state from the hardware
++ * @pcs: a pointer to a &struct phylink_pcs.
++ * @state: a pointer to a &struct phylink_link_state.
++ *
++ * Read the current inband link state from the MAC PCS, reporting the
++ * current speed in @state->speed, duplex mode in @state->duplex, pause
++ * mode in @state->pause using the %MLO_PAUSE_RX and %MLO_PAUSE_TX bits,
++ * negotiation completion state in @state->an_complete, and link up state
++ * in @state->link. If possible, @state->lp_advertising should also be
++ * populated.
++ *
++ * When present, this overrides mac_pcs_get_state() in &struct
++ * phylink_mac_ops.
++ */
++void pcs_get_state(struct phylink_pcs *pcs,
++		   struct phylink_link_state *state);
++
++/**
++ * pcs_config() - Configure the PCS mode and advertisement
++ * @pcs: a pointer to a &struct phylink_pcs.
++ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
++ * @interface: interface mode to be used
++ * @advertising: adertisement ethtool link mode mask
++ * @permit_pause_to_mac: permit forwarding pause resolution to MAC
++ *
++ * Configure the PCS for the operating mode, the interface mode, and set
++ * the advertisement mask. @permit_pause_to_mac indicates whether the
++ * hardware may forward the pause mode resolution to the MAC.
++ *
++ * When operating in %MLO_AN_INBAND, inband should always be enabled,
++ * otherwise inband should be disabled.
++ *
++ * For SGMII, there is no advertisement from the MAC side, the PCS should
++ * be programmed to acknowledge the inband word from the PHY.
++ *
++ * For 1000BASE-X, the advertisement should be programmed into the PCS.
++ *
++ * For most 10GBASE-R, there is no advertisement.
++ */
++int pcs_config(struct phylink_pcs *pcs, unsigned int mode,
++	       phy_interface_t interface, const unsigned long *advertising,
++	       bool permit_pause_to_mac);
++
++/**
++ * pcs_an_restart() - restart 802.3z BaseX autonegotiation
++ * @pcs: a pointer to a &struct phylink_pcs.
++ *
++ * When PCS ops are present, this overrides mac_an_restart() in &struct
++ * phylink_mac_ops.
++ */
++void pcs_an_restart(struct phylink_pcs *pcs);
++
++/**
++ * pcs_link_up() - program the PCS for the resolved link configuration
++ * @pcs: a pointer to a &struct phylink_pcs.
++ * @mode: link autonegotiation mode
++ * @interface: link &typedef phy_interface_t mode
++ * @speed: link speed
++ * @duplex: link duplex
++ *
++ * This call will be made just before mac_link_up() to inform the PCS of
++ * the resolved link parameters. For example, a PCS operating in SGMII
++ * mode without in-band AN needs to be manually configured for the link
++ * and duplex setting. Otherwise, this should be a no-op.
++ */
++void pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
++		 phy_interface_t interface, int speed, int duplex);
++#endif
++
+ struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
+ 			       phy_interface_t iface,
+ 			       const struct phylink_mac_ops *ops);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9014-drivers-spi-Add-support-for-dynamic-calibration.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9014-drivers-spi-Add-support-for-dynamic-calibration.patch
index 688f33f..17102ea 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9014-drivers-spi-Add-support-for-dynamic-calibration.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9014-drivers-spi-Add-support-for-dynamic-calibration.patch
@@ -9,19 +9,16 @@
  include/linux/spi/spi.h |  42 ++++++++++++
  2 files changed, 179 insertions(+)
 
-diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
-index e562735a3..d548036b1 100644
 --- a/drivers/spi/spi.c
 +++ b/drivers/spi/spi.c
-@@ -1109,6 +1109,70 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
+@@ -1109,6 +1109,73 @@ static int spi_transfer_wait(struct spi_
  	return 0;
  }
  
 +int spi_do_calibration(struct spi_controller *ctlr, struct spi_device *spi,
 +	int (*cal_read)(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen), void *drv_priv)
 +{
-+	int datalen = ctlr->cal_rule->datalen;
-+	int addrlen = ctlr->cal_rule->addrlen;
++	int datalen, addrlen;
 +	u8 *buf;
 +	int ret;
 +	int i;
@@ -34,7 +31,9 @@
 +
 +	/* Make sure we can start calibration */
 +	if(!ctlr->cal_target || !ctlr->cal_rule || !ctlr->append_caldata)
-+		return 0;
++		return -EINVAL;
++	datalen = ctlr->cal_rule->datalen;
++	addrlen = ctlr->cal_rule->addrlen;
 +
 +	buf = kzalloc(datalen * sizeof(u8), GFP_KERNEL);
 +	if(!buf)
@@ -72,8 +71,10 @@
 +		} else {
 +			*target->cal_item = origin;
 +			dev_warn(&spi->dev, "calibration failed, fallback to default: 0x%x", origin);
++			ret = -EIO;
 +		}
 +	}
++	list_del(&target->list);
 +
 +cal_end:
 +	kfree(buf);
@@ -84,7 +85,7 @@
  static void _spi_transfer_delay_ns(u32 ns)
  {
  	if (!ns)
-@@ -1720,6 +1784,75 @@ void spi_flush_queue(struct spi_controller *ctlr)
+@@ -1720,6 +1787,75 @@ void spi_flush_queue(struct spi_controll
  /*-------------------------------------------------------------------------*/
  
  #if defined(CONFIG_OF)
@@ -160,7 +161,7 @@
  static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
  			   struct device_node *nc)
  {
-@@ -1841,6 +1974,10 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
+@@ -1841,6 +1977,10 @@ of_register_spi_device(struct spi_contro
  	if (rc)
  		goto err_out;
  
@@ -171,8 +172,6 @@
  	/* Store a pointer to the node in the device structure */
  	of_node_get(nc);
  	spi->dev.of_node = nc;
-diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
-index 7067f85ce..5330cd9b0 100644
 --- a/include/linux/spi/spi.h
 +++ b/include/linux/spi/spi.h
 @@ -264,6 +264,40 @@ struct spi_driver {
@@ -228,7 +227,7 @@
  	int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
  };
  
-@@ -1369,6 +1408,9 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
+@@ -1369,6 +1408,9 @@ spi_register_board_info(struct spi_board
  	{ return 0; }
  #endif
  
@@ -238,6 +237,3 @@
  /* If you're hotplugging an adapter with devices (parport, usb, etc)
   * use spi_new_device() to describe each device.  You can also call
   * spi_unregister_device() to start making that device vanish, but
--- 
-2.18.0
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9018-drivers-mtd-spi-nor-Add-calibration-support-for-spi-nor.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9018-drivers-mtd-spi-nor-Add-calibration-support-for-spi-nor.patch
index 023f52e..fd1bd1a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9018-drivers-mtd-spi-nor-Add-calibration-support-for-spi-nor.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9018-drivers-mtd-spi-nor-Add-calibration-support-for-spi-nor.patch
@@ -8,11 +8,9 @@
  drivers/mtd/spi-nor/spi-nor.c | 17 +++++++++++++++++
  1 file changed, 17 insertions(+)
 
-diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
-index 945833cbb..38a8948b3 100644
 --- a/drivers/mtd/spi-nor/spi-nor.c
 +++ b/drivers/mtd/spi-nor/spi-nor.c
-@@ -4893,6 +4893,20 @@ static void spi_nor_debugfs_init(struct spi_nor *nor,
+@@ -4897,6 +4897,35 @@ static void spi_nor_debugfs_init(struct
  					 info->id_len, info->id);
  }
  
@@ -30,19 +28,39 @@
 +	return spi_nor_read_raw(nor, *addr, readlen, buf);
 +}
 +
++static int spi_nor_cal_read_4B(void *priv, u32 *addr, int addrlen, u8 *buf,
++			    int readlen)
++{
++	int ret;
++	struct spi_nor *nor = (struct spi_nor *)priv;
++
++	nor->reg_proto = SNOR_PROTO_1_1_1;
++	nor->read_proto = SNOR_PROTO_1_1_1;
++	nor->read_opcode = SPINOR_OP_READ_4B;
++	nor->addr_width = 4;
++	nor->read_dummy = 0;
++
++	return spi_nor_read_raw(nor, *addr, readlen, buf);
++}
++
  static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor,
  						       const char *name)
  {
-@@ -4967,6 +4981,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
+@@ -4971,6 +5000,17 @@ int spi_nor_scan(struct spi_nor *nor, co
  	if (!nor->bouncebuf)
  		return -ENOMEM;
  
-+	if(nor->spimem)
-+		spi_mem_do_calibration(nor->spimem, spi_nor_cal_read, nor);
++	if(nor->spimem) {
++		ret = spi_mem_do_calibration(nor->spimem,
++					     spi_nor_cal_read, nor);
++		if (ret) {
++			ret = spi_mem_do_calibration(nor->spimem,
++						     spi_nor_cal_read_4B, nor);
++			if (ret)
++				return ret;
++		}
++	}
 +
  	info = spi_nor_get_flash_info(nor, name);
  	if (IS_ERR(info))
  		return PTR_ERR(info);
--- 
-2.18.0
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9019-drivers-char-tpm-Add-calibration-example-for-SPI-TPM-module.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9019-drivers-char-tpm-Add-calibration-example-for-SPI-TPM-module.patch
index 8b39b12..5635f55 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9019-drivers-char-tpm-Add-calibration-example-for-SPI-TPM-module.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9019-drivers-char-tpm-Add-calibration-example-for-SPI-TPM-module.patch
@@ -11,11 +11,9 @@
  drivers/char/tpm/tpm_tis_spi.c  |  7 +++++++
  3 files changed, 28 insertions(+)
 
-diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
-index 70f785994..b9898a56d 100644
 --- a/drivers/char/tpm/tpm_tis_core.c
 +++ b/drivers/char/tpm/tpm_tis_core.c
-@@ -817,6 +817,21 @@ static const struct tpm_class_ops tpm_tis = {
+@@ -817,6 +817,21 @@ static const struct tpm_class_ops tpm_ti
  	.clk_enable = tpm_tis_clkrun_enable,
  };
  
@@ -37,7 +35,7 @@
  int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
  		      const struct tpm_tis_phy_ops *phy_ops,
  		      acpi_handle acpi_dev_handle)
-@@ -864,6 +879,10 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
+@@ -864,6 +879,10 @@ int tpm_tis_core_init(struct device *dev
  	if (chip->ops->clk_enable != NULL)
  		chip->ops->clk_enable(chip, true);
  
@@ -48,8 +46,6 @@
  	if (wait_startup(chip, 0) != 0) {
  		rc = -ENODEV;
  		goto out_err;
-diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
-index 7337819f5..7bb0bc8b6 100644
 --- a/drivers/char/tpm/tpm_tis_core.h
 +++ b/drivers/char/tpm/tpm_tis_core.h
 @@ -106,6 +106,7 @@ struct tpm_tis_phy_ops {
@@ -68,11 +64,9 @@
  int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
  		      const struct tpm_tis_phy_ops *phy_ops,
  		      acpi_handle acpi_dev_handle);
-diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c
-index 19513e622..3be2d53a5 100644
 --- a/drivers/char/tpm/tpm_tis_spi.c
 +++ b/drivers/char/tpm/tpm_tis_spi.c
-@@ -184,12 +184,19 @@ static int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value)
+@@ -184,12 +184,19 @@ static int tpm_tis_spi_write32(struct tp
  	return rc;
  }
  
@@ -92,6 +86,3 @@
  };
  
  static int tpm_tis_spi_probe(struct spi_device *dev)
--- 
-2.18.0
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
index c5f5cc8..24b4333 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
@@ -120,6 +120,7 @@
     file://754-net-phy-add-5GBASER.patch \
     file://755-net-phy-sfp-add-rollball-support.patch \
     file://756-net-phy-mediatek-ge-add-mt798x-support.patch \
+    file://757-net-phy-add-phylink-pcs-support.patch;apply=no \
     file://8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch \
     file://8001-PATCH-2-4-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch \
     file://8002-PATCH-3-4-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch \
diff --git a/recipes-kernel/linux/linux-mediatek_5.4.bb b/recipes-kernel/linux/linux-mediatek_5.4.bb
index d03088b..5c7b8b6 100644
--- a/recipes-kernel/linux/linux-mediatek_5.4.bb
+++ b/recipes-kernel/linux/linux-mediatek_5.4.bb
@@ -91,6 +91,7 @@
             patch -p1 < ${WORKDIR}/738-mt7531-gsw-internal_phy_calibration.patch
             patch -p1 < ${WORKDIR}/739-mt7531-gsw-port5_external_phy_init.patch
             patch -p1 < ${WORKDIR}/753-net-mt753x-phy-coverity-scan.patch
+            patch -p1 < ${WORKDIR}/757-net-phy-add-phylink-pcs-support.patch
             patch -p1 < ${WORKDIR}/9010-iwconfig-wireless-rate-fix.patch
             if [ $DISTRO_secure_boot_ENABLED = 'true' ]; then
                 patch -p1 < ${WORKDIR}/0404-mtdsplit-dm-verity.patch