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

[Description]
920ddcf2 [MAC80211][hnat][Update IPv6 unbind issue for the routing mode]
937ac411 [kernel][common][Update kernel config to prevent build stop]
3d4ced59 [kernel][common][eth][Add netdev_upper_dev_link feature to the dsa_slave_create() function]
5a77ee07 [kernel][common][eth][Add dsa_port_from_netdev API to dsa framework]
ffb7812c [kernel][common][leds][Update kernel config to prevent build stop]
1f4d9d3a [openwrt][common][Add test tool to pass test vector]
5e041364 [openwrt][common][Change package category in menuconfig]
81974696 [openwrt][common][Fix aes ccm mode encrypt bug]
28b6a279 [openwrt][common][Fix build error in openssl-fips-ext]
769c7697 [kernel][common][Add patch to achieve fips140-3 compliance]
9b59f267 [openwrt][common][Add libkcapi to test fips140-3]
46bf5245 [openwrt][common][Add jitterrng package]
bf6fe74a [kernel][common][Backport libkcapi to v5.10]
8ad792d1 [kernel][common][Backport jitterrng to 2.2.0]
13ee647a [MAC80211][hnat][Fix IPv6 unbind issue for the routing mode]
05856c54 [kernel][mt7988][eth][Add 10G WAN support to mt7988d base on dsa-10g-spim-nand DTS]
313f5766 [openwrt][mt7988][tops][remove script 98-mtk-vpn]
4605625c [openwrt][mt7988][tops][support v1.2.0]
02a32c90 [openwrt][common][audio][Remove obsolete mt79xx audio driver from module.mk]
33b9a8df [openwrt][common][audio][Add WM8960 codec and MT7986 audio drivers to sound.mk]
7583e3a7 [kernel][mt7988][eth][Fix Link Partner link down issue for the SFP+ optical module]
259d232d [MAC80211][WED][Fix MT7981 wed detach occur call trace issue]
38b67904 [openwrt][mt7988][crypto][Refactor FP setting in IPSec hnat binding flow]
29f07a46 [openwrt][mt7988][crypto][Add check for algorithm used in xfrm_state]
68a3a4d8 [MAC80211][WED][Fix 2G WMM test fail]
f4a9a9af [kernel][common][leds][Add backport leds pwm multicolor from kernel 6.4]
86e8737c [kernel][mt7988][eth][Add DIP dynamic allocation to the LRO]
5433dd92 [kernel][mt7988][eth][i2.5Gphy: Add safer sequence to loadfirmware]
57514f1b [kernel][common][Refactor pinctrl spinlock patch name]
9a1a5b6c [kernel][pinctrl][Rename backport pinctrl patch]
2a50af6c [kernel][mt7988][crypto][Change backport patch name to satisfy naming rule]
dbbaf2d8 [openwrt][mt7988][tops][support v1.1.0]
a8235047 [kernel][common][eth][Fix refcount underflow issue in the pending_work]
ed7846eb [MAC80211][hnat][Improve ETH to ETH performace in an unbalanced PHY rate test for the mt7988]
30b53d1f [kernel][mt7988][hnat][Fix issue with 3PPE HNAT BIND during LAN WAN role swap]
5b4aef62 [kernel][mt7988][crypto][Fix xfrm_state add to hashtable]
8eefe83b [kernel][mt7988][hnat][Correct maximum rate limit criteria for the qdma_txqX and qdma_schX commands]
69a4f5af [kernel][mt7986][hnat][Fix issue of inactive HQoS functionality under PPPQ mode]
7a74acf7 [openwrt][common][Upgrade kernel version from 5.4.246 to 5.4.260]
1345887d [openwrt][common][crypto][Add kmod-crypto-chacha20-poly1305]
1404373a [kernel][common][Refactor rtq6056 backport patch path]
62742395 [openwrt][mt7988][pce][fix coverity defects]
ce4a3c4a [kernel][common][Refactor dhrystone backport patch path]
7fa2cbf9 [kernel][common][audio][Refactor mt7986 audio driver backport patch path]
026e4289 [MAC80211][hnat][Fix 64B short packets test cannot reach line rate for the mt7988]
3a75d682 [kernel][mt7988][crypto][Change xfrm policy check for IPsec decryption path]
eb84c73c [kernel][common][eth][Fix issue with XGDM hang when reconnecting SFP+ Optical module]
ac5fc068 [openwrt][mt7988][pce][fix out-of-bound array access]
97385f3c [kernel][common][eth][Fix issue with late-col hang when operating in half-duplex on the SGMII 1G PHY]
06f8dfe6 [MAC80211][hnat][Fix the typo to enable caching of the MIB function]
6b4b77e7 [kernel][common][audio][Add mt7986 audio driver in dts files]
34d90265 [kernel][common][audio][Add mt7986proslic machine driver to Kconfig and Makefile]
6f715d67 [kernel][common][audio][Add mt7986proslic machine driver]
b8c2e923 [kernel][common][audio][Add backport mt7986 audio driver from kernel 6.7]
2f1abd04 [kernel][common][audio][Remove mt79xx audio driver]
98e9ba78 [kernel][common][eth][Fix a traffic stuck issue when changing the SGMII autoneg mode]
0b6f8d87 [MAC80211][hnat][Add multiple PPE allocation of the ETH for mt7988]
162c66eb [openwrt][common][crypto][Remove ipsec service in strongswan]
8669e93b [openwrt][common][crypto][Change strongswan package dependency]
0c532b0d [kernel][mt7988][hnat][Add support for preventing hardware acceleration via skb mark checking]
7967721e [openwrt][mt7988][audio][Add -spi and  driver to Kconfig and Makefile]
42c9b50b [openwrt][mt7988][audio][Add -spi for  slic driver test]
8fe39e57 [openwrt][mt7988][crypto][Fix compile error without hnat]

[Release-log]

Change-Id: Ic979c02edfaccd00ea95b478ca0113a3434b4987
diff --git a/recipes-bsp/mediatek-eth-firmware/files/mediatek-2p5ge-phy-pmb.bin b/recipes-bsp/mediatek-eth-firmware/files/i2p5ge-phy-pmb.bin
similarity index 100%
rename from recipes-bsp/mediatek-eth-firmware/files/mediatek-2p5ge-phy-pmb.bin
rename to recipes-bsp/mediatek-eth-firmware/files/i2p5ge-phy-pmb.bin
Binary files differ
diff --git a/recipes-bsp/mediatek-eth-firmware/files/mediatek-2p5ge-phy-dmb.bin b/recipes-bsp/mediatek-eth-firmware/files/mediatek-2p5ge-phy-dmb.bin
deleted file mode 100644
index 12f3be4..0000000
--- a/recipes-bsp/mediatek-eth-firmware/files/mediatek-2p5ge-phy-dmb.bin
+++ /dev/null
Binary files differ
diff --git a/recipes-bsp/mediatek-eth-firmware/mediatek-eth-firmware.bb b/recipes-bsp/mediatek-eth-firmware/mediatek-eth-firmware.bb
index 8962af2..d8ccad1 100644
--- a/recipes-bsp/mediatek-eth-firmware/mediatek-eth-firmware.bb
+++ b/recipes-bsp/mediatek-eth-firmware/mediatek-eth-firmware.bb
@@ -4,20 +4,18 @@
 LICENSE = "CLOSED"
 
 SRC_URI = " \
-    file://mediatek-2p5ge-phy-dmb.bin \
-    file://mediatek-2p5ge-phy-pmb.bin \
+    file://i2p5ge-phy-pmb.bin \
 "
 S = "${WORKDIR}"
 
 inherit allarch
 
 do_install() {
-    install -d ${D}/${base_libdir}/firmware/
-    install -m 644 ${WORKDIR}/mediatek-2p5ge-phy-dmb.bin ${D}${base_libdir}/firmware/
-    install -m 644 ${WORKDIR}/mediatek-2p5ge-phy-pmb.bin ${D}${base_libdir}/firmware/
+    install -d ${D}/${base_libdir}/firmware/mediatek/mt7988/
+    install -m 644 ${WORKDIR}/i2p5ge-phy-pmb.bin ${D}${base_libdir}/firmware/mediatek/mt7988/
 }
 
-FILES_${PN} += "${base_libdir}/firmware/*"
+FILES_${PN} += "${base_libdir}/firmware/mediatek/mt7988/*"
 
 # Make Mediatek-eth-firmware depend on all of the split-out packages.
 python populate_packages_prepend () {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/711-v6.3-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/711-v6.3-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch
deleted file mode 100644
index 54f077b..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/711-v6.3-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From 327dabbd0111910a7d174b0b812d608d6b67bead Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
-Date: Mon, 8 Aug 2022 23:05:25 +0200
-Subject: [PATCH] bgmac: fix *initial* chip reset to support BCM5358
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-While bringing hardware up we should perform a full reset including the
-switch bit (BGMAC_BCMA_IOCTL_SW_RESET aka SICF_SWRST). It's what
-specification says and what reference driver does.
-
-This seems to be critical for the BCM5358. Without this hardware doesn't
-get initialized properly and doesn't seem to transmit or receive any
-packets.
-
-Originally bgmac was calling bgmac_chip_reset() before setting
-"has_robosw" property which resulted in expected behaviour. That has
-changed as a side effect of adding platform device support which
-regressed BCM5358 support.
-
-Fixes: f6a95a24957a ("net: ethernet: bgmac: Add platform device support")
-Cc: Jon Mason <jdmason@kudzu.us>
-Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
----
- drivers/net/ethernet/broadcom/bgmac.c | 8 ++++++--
- drivers/net/ethernet/broadcom/bgmac.h | 2 ++
- 2 files changed, 8 insertions(+), 2 deletions(-)
-
---- a/drivers/net/ethernet/broadcom/bgmac.c
-+++ b/drivers/net/ethernet/broadcom/bgmac.c
-@@ -890,13 +890,13 @@ static void bgmac_chip_reset_idm_config(
- 
- 		if (iost & BGMAC_BCMA_IOST_ATTACHED) {
- 			flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
--			if (!bgmac->has_robosw)
-+			if (bgmac->in_init || !bgmac->has_robosw)
- 				flags |= BGMAC_BCMA_IOCTL_SW_RESET;
- 		}
- 		bgmac_clk_enable(bgmac, flags);
- 	}
- 
--	if (iost & BGMAC_BCMA_IOST_ATTACHED && !bgmac->has_robosw)
-+	if (iost & BGMAC_BCMA_IOST_ATTACHED && (bgmac->in_init || !bgmac->has_robosw))
- 		bgmac_idm_write(bgmac, BCMA_IOCTL,
- 				bgmac_idm_read(bgmac, BCMA_IOCTL) &
- 				~BGMAC_BCMA_IOCTL_SW_RESET);
-@@ -1489,6 +1489,8 @@ int bgmac_enet_probe(struct bgmac *bgmac
- 	struct net_device *net_dev = bgmac->net_dev;
- 	int err;
- 
-+	bgmac->in_init = true;
-+
- 	bgmac_chip_intrs_off(bgmac);
- 
- 	net_dev->irq = bgmac->irq;
-@@ -1538,6 +1540,8 @@ int bgmac_enet_probe(struct bgmac *bgmac
- 	net_dev->hw_features = net_dev->features;
- 	net_dev->vlan_features = net_dev->features;
- 
-+	bgmac->in_init = false;
-+
- 	err = register_netdev(bgmac->net_dev);
- 	if (err) {
- 		dev_err(bgmac->dev, "Cannot register net device\n");
---- a/drivers/net/ethernet/broadcom/bgmac.h
-+++ b/drivers/net/ethernet/broadcom/bgmac.h
-@@ -511,6 +511,8 @@ struct bgmac {
- 	int irq;
- 	u32 int_mask;
- 
-+	bool in_init;
-+
- 	/* Current MAC state */
- 	int mac_speed;
- 	int mac_duplex;
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 10b63da..b8f3dfc 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
@@ -205,7 +205,6 @@
     file://709-v5.8-0006-net-dsa-b53-remove-redundant-premature-assignment-to.patch \
     file://710-v5.16-0001-net-bgmac-improve-handling-PHY.patch \
     file://710-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch \
-    file://711-v6.3-bgmac-fix-initial-chip-reset-to-support-BCM5358.patch \
     file://712-v6.5-net-bgmac-postpone-turning-IRQs-off-to-avoid-SoC-han.patch \
     file://716-v5.5-net-sfp-move-fwnode-parsing-into-sfp-bus-layer.patch \
     file://717-v5.5-net-sfp-rework-upstream-interface.patch \
@@ -301,8 +300,6 @@
     file://900-v5.9-0002-leds-Add-multicolor-ID-to-the-color-ID-list.patch \
     file://900-v5.9-0003-leds-add-RGB-color-option-as-that-is-different-from-.patch \
     file://999-1410-mtd-spinand-gigadevice-Support-for-modify-GD-Serial-NAND-from-v6-4-9.patch \
-    file://999-1900-lib-add-Dhrystone-benchmark-test.patch \
-    file://999-2210-v6.1-iio-adc-add-rtq6056-support.patch \
     file://999-2310-v5.7-mtd-nand-spi-rework-detect-procedure-for-different-read-id-op.patch \
     file://999-2312-mtd-spinand-macronix-Add-support-for-MX31LF1GE4BC.patch \
     file://999-2313-mtd-spinand-macronix-Add-support-for-MX31UF1GE4BC.patch \
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts
index 40c41b6..9c0c072 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-emmc-rfb.dts
@@ -32,15 +32,22 @@
 		regulator-always-on;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 };
 
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 b9faeec..af0c1c3 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
@@ -21,15 +21,22 @@
 		reg = <0 0x40000000 0 0x10000000>;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts
index 32f9320..de4569c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-sd-rfb.dts
@@ -14,15 +14,22 @@
 		reg = <0 0x40000000 0 0x10000000>;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	reg_3p3v: regulator-3p3v {
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 9080933..28f576a 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
@@ -14,15 +14,22 @@
 		reg = <0 0x40000000 0 0x10000000>;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts
index 85ee3b7..7bd9be8 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-2500wan-spim-nor-rfb.dts
@@ -14,15 +14,22 @@
 		reg = <0 0x40000000 0 0x10000000>;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts
index 91c2234..fcde1dc 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-emmc-rfb.dts
@@ -33,21 +33,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts
index d7ec46c..e56a291 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-snfi-nand-rfb.dts
@@ -15,21 +15,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts
index 472232d..59afe17 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nand-rfb.dts
@@ -15,21 +15,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts
index 1e125c6..bf55f74 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a-spim-nor-rfb.dts
@@ -15,21 +15,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi
index bf62aa1..1750c0a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm/boot/dts/mt7986a.dtsi
@@ -745,7 +745,7 @@
 	};
 
 	afe: audio-controller@11210000 {
-		compatible = "mediatek,mt79xx-audio";
+		compatible = "mediatek,mt7986-afe";
 		reg = <0 0x11210000 0 0x9000>;
 		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&infracfg_ao CK_INFRA_AUD_BUS_CK>,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-gsw.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-gsw.dts
index 192a457..cad1f45 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-gsw.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-gsw.dts
@@ -71,21 +71,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 
         gsw: gsw@0 {
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-rfb.dts
index 726447f..21e54f6 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981-spim-nand-rfb.dts
@@ -71,21 +71,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981.dtsi
index 3b304d5..91415e4 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7981.dtsi
@@ -507,6 +507,8 @@
 			     <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
 		chip_id = <0x7981>;
 		memory-region = <&wmcpu_emi>;
+		nvmem-cells = <&consys_variant>;
+		nvmem-cell-names = "variant";
 	};
 
 	wed_pcie: wed_pcie@10003000 {
@@ -634,6 +636,10 @@
 			reg = <0x274 0xc>;
 		};
 
+		consys_variant: consys@284 {
+			reg = <0x284 0x4>;
+		};
+
 		phy_calibration: calib@8dc {
 			reg = <0x8dc 0x10>;
 		};
@@ -655,7 +661,7 @@
 	};
 
 	afe: audio-controller@11210000 {
-		compatible = "mediatek,mt79xx-audio";
+		compatible = "mediatek,mt7981-afe", "mediatek,mt7986-afe";
 		reg = <0 0x11210000 0 0x9000>;
 		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&infracfg_ao CK_INFRA_AUD_BUS_CK>,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
index 40c41b6..9c0c072 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
@@ -32,15 +32,22 @@
 		regulator-always-on;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 };
 
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 b9faeec..af0c1c3 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
@@ -21,15 +21,22 @@
 		reg = <0 0x40000000 0 0x10000000>;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts
index 32f9320..de4569c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-sd-rfb.dts
@@ -14,15 +14,22 @@
 		reg = <0 0x40000000 0 0x10000000>;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	reg_3p3v: regulator-3p3v {
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 9080933..28f576a 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
@@ -14,15 +14,22 @@
 		reg = <0 0x40000000 0 0x10000000>;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts
index 85ee3b7..7bd9be8 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-spim-nor-rfb.dts
@@ -14,15 +14,22 @@
 		reg = <0 0x40000000 0 0x10000000>;
 	};
 
-	sound {
-		compatible = "mediatek,mt7986-wm8960-machine";
-		mediatek,platform = <&afe>;
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
index 91c2234..fcde1dc 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
@@ -33,21 +33,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts
index d7ec46c..e56a291 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-snfi-nand-rfb.dts
@@ -15,21 +15,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts
index 472232d..59afe17 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nand-rfb.dts
@@ -15,21 +15,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts
index 1e125c6..bf55f74 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-spim-nor-rfb.dts
@@ -15,21 +15,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "okay";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
index bf62aa1..1750c0a 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -745,7 +745,7 @@
 	};
 
 	afe: audio-controller@11210000 {
-		compatible = "mediatek,mt79xx-audio";
+		compatible = "mediatek,mt7986-afe";
 		reg = <0 0x11210000 0 0x9000>;
 		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&infracfg_ao CK_INFRA_AUD_BUS_CK>,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
index 5d9357d..51a1c81 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
@@ -436,9 +436,8 @@
 
 	phyfw: phy-firmware@f000000 {
 		compatible = "mediatek,2p5gphy-fw";
-		reg = <0 0x0f000000 0 0x8000>,
-		      <0 0x0f100000 0 0x20000>,
-		      <0 0x0f0f0000 0 0x200>;
+		reg = <0 0x0f100000 0 0x20000>,
+		      <0 0x0f0f0018 0 0x20>;
 	};
 
 	boottrap: boottrap@1001f6f0 {
@@ -600,7 +599,7 @@
 	};
 
 	afe: audio-controller@11210000 {
-		compatible = "mediatek,mt79xx-audio";
+		compatible = "mediatek,mt7988-afe", "mediatek,mt7986-afe";
 		reg = <0 0x11210000 0 0x9000>;
 		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&infracfg_ao CK_INFRA_66M_AUD_SLV_BCK>,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
index 5701c3e..785bf71 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
@@ -77,21 +77,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand-CASAN.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand-CASAN.dts
index 3d21585..9dcd2b7 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand-CASAN.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand-CASAN.dts
@@ -73,21 +73,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
index 32e2b15..7bd3e26 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
@@ -73,21 +73,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts
index 7f7ddfd..37b7fb6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts
@@ -315,6 +315,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-emmc.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-emmc.dts
index 8176802..0aa4012 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-emmc.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-emmc.dts
@@ -246,6 +246,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sd.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sd.dts
index aee27de..fea639f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sd.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sd.dts
@@ -237,6 +237,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sfp-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sfp-spim-nand.dts
index ed91a18..00a3179 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sfp-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-sfp-spim-nand.dts
@@ -368,6 +368,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-snfi-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-snfi-nand.dts
index 2df4cc2..09b1772 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-snfi-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-snfi-nand.dts
@@ -272,6 +272,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand-CASAN.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand-CASAN.dts
index 9f3bb0f..a938ea8 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand-CASAN.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand-CASAN.dts
@@ -77,21 +77,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
@@ -412,6 +425,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
index 1f8952d..11d872e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
@@ -77,21 +77,34 @@
 	};
 
 	sound_wm8960 {
-		compatible = "mediatek,mt79xx-wm8960-machine";
-		mediatek,platform = <&afe>;
+		compatible = "mediatek,mt7986-wm8960-sound";
 		audio-routing = "Headphone", "HP_L",
 				"Headphone", "HP_R",
 				"LINPUT1", "AMIC",
 				"RINPUT1", "AMIC";
-		mediatek,audio-codec = <&wm8960>;
+
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
 	};
 
 	sound_si3218x {
-		compatible = "mediatek,mt79xx-si3218x-machine";
-		mediatek,platform = <&afe>;
-		mediatek,ext-codec = <&proslic_spi>;
+		compatible = "mediatek,mt7986-si3218x-sound";
 		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
 	};
 };
 
@@ -412,6 +425,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
index e8e3a69..5cb069e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nor.dts
@@ -264,6 +264,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-wan-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-wan-spim-nand.dts
new file mode 100644
index 0000000..d844ddb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-wan-spim-nand.dts
@@ -0,0 +1,549 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+#include "mt7988.dtsi"
+
+/ {
+	model = "MediaTek MT7988D DSA 10G WAN SPIM-NAND RFB";
+	compatible = "mediatek,mt7988d-dsa-10g-wan-spim-snand",
+		     /* Reserve this for DVFS if creating new dts */
+		     "mediatek,mt7988";
+
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+			    earlycon=uart8250,mmio32,0x11000000 \
+			    pci=pcie_bus_perf";
+	};
+
+	cpus {
+		/delete-node/ cpu@3;
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	nmbm_spim_nand {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&spi_nand>;
+		forced-create;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition@0 {
+				label = "BL2";
+				reg = <0x00000 0x0100000>;
+				read-only;
+			};
+
+			partition@100000 {
+				label = "u-boot-env";
+				reg = <0x0100000 0x0080000>;
+			};
+
+			factory: partition@180000 {
+				label = "Factory";
+				reg = <0x180000 0x0400000>;
+			};
+
+			partition@580000 {
+				label = "FIP";
+				reg = <0x580000 0x0200000>;
+			};
+
+			partition@780000 {
+				label = "ubi";
+				reg = <0x780000 0x7080000>;
+			};
+		};
+	};
+
+	wsys_adie: wsys_adie@0 {
+	// fpga cases need to manual change adie_id / sku_type for dvt only
+		compatible = "mediatek,rebb-mt7988-adie";
+		adie_id = <7976>;
+		sku_type = <3000>;
+	};
+
+	sound_wm8960 {
+		compatible = "mediatek,mt7986-wm8960-sound";
+		audio-routing = "Headphone", "HP_L",
+				"Headphone", "HP_R",
+				"LINPUT1", "AMIC",
+				"RINPUT1", "AMIC";
+
+		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&wm8960>;
+		};
+	};
+
+	sound_si3218x {
+		compatible = "mediatek,mt7986-si3218x-sound";
+		status = "disabled";
+
+		platform {
+			sound-dai = <&afe>;
+		};
+
+		codec {
+			sound-dai = <&proslic_spi>;
+		};
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	status = "okay";
+};
+
+&afe {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcm_pins>;
+	status = "okay";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+	status = "okay";
+
+	rt5190a_64: rt5190a@64 {
+		compatible = "richtek,rt5190a";
+		reg = <0x64>;
+		/*interrupts-extended = <&gpio26 0 IRQ_TYPE_LEVEL_LOW>;*/
+		vin2-supply = <&rt5190_buck1>;
+		vin3-supply = <&rt5190_buck1>;
+		vin4-supply = <&rt5190_buck1>;
+
+		regulators {
+			rt5190_buck1: buck1 {
+				regulator-name = "rt5190a-buck1";
+				regulator-min-microvolt = <5090000>;
+				regulator-max-microvolt = <5090000>;
+				regulator-allowed-modes =
+				<RT5190A_OPMODE_AUTO RT5190A_OPMODE_FPWM>;
+				regulator-boot-on;
+			};
+			buck2 {
+				regulator-name = "vcore";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+			};
+			buck3 {
+				regulator-name = "proc";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <1400000>;
+				regulator-boot-on;
+			};
+			buck4 {
+				regulator-name = "rt5190a-buck4";
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-allowed-modes =
+				<RT5190A_OPMODE_AUTO RT5190A_OPMODE_FPWM>;
+				regulator-boot-on;
+			};
+			ldo {
+				regulator-name = "rt5190a-ldo";
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-boot-on;
+			};
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	status = "okay";
+
+	wm8960: wm8960@1a {
+		compatible = "wlf,wm8960";
+		reg = <0x1a>;
+	};
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_flash_pins>;
+	status = "okay";
+
+	spi_nand: spi_nand@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		spi-cal-enable;
+		spi-cal-mode = "read-data";
+		spi-cal-datalen = <7>;
+		spi-cal-data = /bits/ 8 <0x53 0x50 0x49 0x4E 0x41 0x4E 0x44>;
+		spi-cal-addrlen = <5>;
+		spi-cal-addr = /bits/ 32 <0x0 0x0 0x0 0x0 0x0>;
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+
+	proslic_spi: proslic_spi@0 {
+		compatible = "silabs,proslic_spi";
+		reg = <0>;
+		spi-max-frequency = <10000000>;
+		spi-cpha = <1>;
+		spi-cpol = <1>;
+		channel_count = <1>;
+		debug_level = <4>;       /* 1 = TRC, 2 = DBG, 4 = ERR */
+		reset_gpio = <&pio 54 0>;
+		ig,enable-spi = <1>;     /* 1: Enable, 0: Disable */
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "disabled";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	mdio0_pins: mdio0-pins {
+		mux {
+			function = "mdio";
+			groups = "mdc_mdio0";
+		};
+
+		conf {
+			groups = "mdc_mdio0";
+			drive-strength = <MTK_DRIVE_10mA>;
+		};
+	};
+
+	gbe0_led0_pins: gbe0-pins {
+		mux {
+			function = "led";
+			groups = "gbe0_led0";
+		};
+	};
+
+	gbe1_led0_pins: gbe1-pins {
+		mux {
+			function = "led";
+			groups = "gbe1_led0";
+		};
+	};
+
+	gbe2_led0_pins: gbe2-pins {
+		mux {
+			function = "led";
+			groups = "gbe2_led0";
+		};
+	};
+
+	gbe3_led0_pins: gbe3-pins {
+		mux {
+			function = "led";
+			groups = "gbe3_led0";
+		};
+	};
+
+	i2p5gbe_led0_pins: 2p5gbe-pins {
+		mux {
+			function = "led";
+			groups = "2p5gbe_led0";
+		};
+	};
+
+	i2c0_pins: i2c0-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c0_1";
+		};
+	};
+
+	pcie0_pins: pcie0-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_2l_0_pereset", "pcie_clk_req_n0_0",
+				 "pcie_wake_n0_0";
+		};
+	};
+
+	pcie1_pins: pcie1-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_2l_1_pereset", "pcie_clk_req_n1",
+				 "pcie_wake_n1_0";
+		};
+	};
+
+	pcie2_pins: pcie2-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_1l_0_pereset", "pcie_clk_req_n2_0",
+				 "pcie_wake_n2_0";
+		};
+	};
+
+	pcie3_pins: pcie3-pins {
+		mux {
+			function = "pcie";
+			groups = "pcie_1l_1_pereset", "pcie_clk_req_n3",
+				 "pcie_wake_n3_0";
+		};
+	};
+
+	spi0_flash_pins: spi0-pins {
+		mux {
+			function = "spi";
+			groups = "spi0", "spi0_wp_hold";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1";
+		};
+	};
+
+	i2c1_pins: i2c1-pins {
+		mux {
+			function = "i2c";
+			groups = "i2c1_0";
+		};
+	};
+
+	i2s_pins: i2s-pins {
+		mux {
+			function = "audio";
+			groups = "i2s";
+		};
+	};
+
+	pcm_pins: pcm-pins {
+		mux {
+			function = "audio";
+			groups = "pcm";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mdio0_pins>;
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		mac-type = "xgdm";
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <10000>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		mac-type = "xgdm";
+		phy-mode = "xgmii";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		mac-type = "xgdm";
+		phy-mode = "usxgmii";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clock-frequency = <10500000>;
+
+		phy0: ethernet-phy@0 {
+			pinctrl-names = "i2p5gbe-led";
+			pinctrl-0 = <&i2p5gbe_led0_pins>;
+			reg = <15>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			phy-mode = "xgmii";
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 3 1>;
+			reset-assert-us = <100000>;
+			reset-deassert-us = <221000>;
+			mdi-reversal = /bits/ 16 <1>;
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7988";
+			reg = <31>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+					phy-mode = "gmii";
+					phy-handle = <&sphy0>;
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+					phy-mode = "gmii";
+					phy-handle = <&sphy1>;
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+					phy-mode = "gmii";
+					phy-handle = <&sphy2>;
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+					phy-mode = "gmii";
+					phy-handle = <&sphy3>;
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "10gbase-kr";
+
+					fixed-link {
+						speed = <10000>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+
+			mdio {
+				compatible = "mediatek,dsa-slave-mdio";
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				sphy0: switch_phy0@0 {
+					compatible = "ethernet-phy-id03a2.9481";
+					reg = <0>;
+					pinctrl-names = "gbe-led";
+					pinctrl-0 = <&gbe0_led0_pins>;
+					nvmem-cells = <&phy_calibration_p0>;
+					nvmem-cell-names = "phy-cal-data";
+				};
+
+				sphy1: switch_phy1@1 {
+					compatible = "ethernet-phy-id03a2.9481";
+					reg = <1>;
+					pinctrl-names = "gbe-led";
+					pinctrl-0 = <&gbe1_led0_pins>;
+					nvmem-cells = <&phy_calibration_p1>;
+					nvmem-cell-names = "phy-cal-data";
+				};
+
+				sphy2: switch_phy2@2 {
+					compatible = "ethernet-phy-id03a2.9481";
+					reg = <2>;
+					pinctrl-names = "gbe-led";
+					pinctrl-0 = <&gbe2_led0_pins>;
+					nvmem-cells = <&phy_calibration_p2>;
+					nvmem-cell-names = "phy-cal-data";
+				};
+
+				sphy3: switch_phy3@3 {
+					compatible = "ethernet-phy-id03a2.9481";
+					reg = <3>;
+					pinctrl-names = "gbe-led";
+					pinctrl-0 = <&gbe3_led0_pins>;
+					nvmem-cells = <&phy_calibration_p3>;
+					nvmem-cell-names = "phy-cal-data";
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth2";
+	mtketh-lan = "lan";
+	mtketh-lan2 = "eth1";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
+
+&slot0 {
+	mt7996@0,0 {
+		reg = <0x0000 0 0 0 0>;
+		device_type = "pci";
+		mediatek,mtd-eeprom = <&factory 0x0>;
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-e2p5g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-e2p5g-spim-nand.dts
index f3af5da..0e5064b 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-e2p5g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-dsa-e2p5g-spim-nand.dts
@@ -342,6 +342,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-sfp-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-sfp-spim-nand.dts
index df35a38..9308de6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-sfp-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-sfp-spim-nand.dts
@@ -357,6 +357,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-spim-nand.dts
index 8b9fe35..e939bff 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-spim-nand.dts
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988d-gsw-10g-spim-nand.dts
@@ -388,6 +388,8 @@
 			pinctrl-names = "i2p5gbe-led";
 			pinctrl-0 = <&i2p5gbe_led0_pins>;
 			reg = <15>;
+			power-domains = <&topmisc MT7988_POWER_DOMAIN_ETH2P5>;
+			power-domain-names = "i2p5gbe-pd";
 			compatible = "ethernet-phy-ieee802.3-c45";
 			phy-mode = "xgmii";
 		};
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 6cf9fc5..010c992 100644
--- 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
@@ -444,7 +444,7 @@
 
 	/* Force Port1 XGMAC Link Up */
 	val = mtk_r32(eth, MTK_XGMAC_STS(MTK_GMAC1_ID));
-	mtk_w32(eth, val | MTK_XGMAC_FORCE_LINK(MTK_GMAC1_ID),
+	mtk_w32(eth, val | MTK_XGMAC_FORCE_MODE(MTK_GMAC1_ID),
 		MTK_XGMAC_STS(MTK_GMAC1_ID));
 
 	/* Adjust GSW bridge IPG to 11*/
@@ -573,6 +573,28 @@
 	return NULL;
 }
 
+static int mtk_mac_prepare(struct phylink_config *config, unsigned int mode,
+			   phy_interface_t iface)
+{
+	struct mtk_mac *mac = container_of(config, struct mtk_mac,
+					   phylink_config);
+	u32 val;
+
+	if (mac->type == MTK_XGDM_TYPE && mac->id != MTK_GMAC1_ID) {
+		val = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
+		val &= 0xfffffff0;
+		val |= XMAC_MCR_TRX_DISABLE;
+		mtk_w32(mac->hw, val, MTK_XMAC_MCR(mac->id));
+
+		val = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
+		val |= MTK_XGMAC_FORCE_MODE(mac->id);
+		val &= ~MTK_XGMAC_FORCE_LINK(mac->id);
+		mtk_w32(mac->hw, val, MTK_XGMAC_STS(mac->id));
+	}
+
+	return 0;
+}
+
 static void mtk_mac_config(struct phylink_config *config, unsigned int mode,
 			   const struct phylink_link_state *state)
 {
@@ -702,6 +724,9 @@
 		regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
 		spin_unlock(&eth->syscfg0_lock);
 
+		/* Save the syscfg0 value for mac_finish */
+		mac->syscfg0 = val;
+
 		mac->interface = state->interface;
 	}
 
@@ -721,9 +746,6 @@
 		/* Decide how GMAC and SGMIISYS be mapped */
 		sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ?
 		       0 : mac->id;
-
-		/* 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 ||
@@ -987,7 +1009,6 @@
 
 		id = mtk_mac2xgmii_id(eth, mac->id);
 		mpcs = &eth->usxgmii->pcs[id];
-		cancel_delayed_work_sync(&mpcs->link_poll);
 	}
 }
 
@@ -997,7 +1018,7 @@
 {
 	struct mtk_mac *mac = container_of(config, struct mtk_mac,
 					   phylink_config);
-	u32 mcr, mcr_cur, sts, force_link;
+	u32 mcr, mcr_cur, sts;
 
 	mac->speed = speed;
 
@@ -1022,7 +1043,8 @@
 		}
 
 		/* Configure duplex */
-		if (duplex == DUPLEX_FULL)
+		if (duplex == DUPLEX_FULL ||
+		    interface == PHY_INTERFACE_MODE_SGMII)
 			mcr |= MAC_MCR_FORCE_DPX;
 
 		/* Configure pause modes -
@@ -1042,27 +1064,17 @@
 		if (mode == MLO_AN_PHY && phy)
 			mtk_setup_eee(mac, phy_init_eee(phy, false) >= 0);
 	} else if (mac->type == MTK_XGDM_TYPE && mac->id != MTK_GMAC1_ID) {
+		if (mode == MLO_AN_INBAND)
+			mdelay(1000);
+
 		/* Eliminate the interference(before link-up) caused by PHY noise */
 		mtk_m32(mac->hw, XMAC_LOGIC_RST, 0x0, MTK_XMAC_LOGIC_RST(mac->id));
 		mdelay(20);
 		mtk_m32(mac->hw, XMAC_GLB_CNTCLR, 0x1, MTK_XMAC_CNT_CTRL(mac->id));
 
-		switch (mac->id) {
-		case MTK_GMAC2_ID:
-			force_link = (mac->interface ==
-				      PHY_INTERFACE_MODE_XGMII) ?
-				      MTK_XGMAC_FORCE_LINK(mac->id) : 0;
-			sts = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
-			mtk_w32(mac->hw, sts | force_link,
-				MTK_XGMAC_STS(mac->id));
-			break;
-		case MTK_GMAC3_ID:
-			sts = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
-			mtk_w32(mac->hw,
-				sts | MTK_XGMAC_FORCE_LINK(mac->id),
-				MTK_XGMAC_STS(mac->id));
-			break;
-		}
+		sts = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id));
+		sts |= MTK_XGMAC_FORCE_LINK(mac->id);
+		mtk_w32(mac->hw, sts, MTK_XGMAC_STS(mac->id));
 
 		mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
 
@@ -1220,6 +1232,7 @@
 	.validate = mtk_validate,
 	.mac_select_pcs = mtk_mac_select_pcs,
 	.mac_link_state = mtk_mac_pcs_get_state,
+	.mac_prepare = mtk_mac_prepare,
 	.mac_config = mtk_mac_config,
 	.mac_finish = mtk_mac_finish,
 	.mac_link_down = mtk_mac_link_down,
@@ -2966,6 +2979,68 @@
 	return cnt;
 }
 
+static int mtk_hwlro_add_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	u32 reg_val;
+	int i;
+
+	/* check for duplicate IP address in the current DIP list */
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i <= MTK_HW_LRO_RING_NUM) {
+		netdev_warn(dev, "Duplicate IP address at DIP(%d)!\n", i);
+		return -EEXIST;
+	}
+
+	/* find out available DIP index */
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == 0UL)
+			break;
+	}
+
+	if (i > MTK_HW_LRO_RING_NUM) {
+		netdev_warn(dev, "DIP index is currently out of resource!\n");
+		return -EBUSY;
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2))
+		i -= 1;
+
+	return i;
+}
+
+static int mtk_hwlro_get_ipaddr_idx(struct net_device *dev, u32 ip4dst)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	u32 reg_val;
+	int i;
+
+	/* find out DIP index that matches the given IP address */
+	for (i = 1; i <= MTK_HW_LRO_RING_NUM; i++) {
+		reg_val = mtk_r32(eth, MTK_LRO_DIP_DW0_CFG(i));
+		if (reg_val == ip4dst)
+			break;
+	}
+
+	if (i > MTK_HW_LRO_RING_NUM) {
+		netdev_warn(dev, "DIP address is not exist!\n");
+		return -ENOENT;
+	}
+
+	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2))
+		i -= 1;
+
+	return i;
+}
+
 static int mtk_hwlro_add_ipaddr(struct net_device *dev,
 				struct ethtool_rxnfc *cmd)
 {
@@ -2974,15 +3049,19 @@
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if ((fsp->flow_type != TCP_V4_FLOW) ||
 	    (!fsp->h_u.tcp_ip4_spec.ip4dst) ||
 	    (fsp->location > 1))
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = htonl(fsp->h_u.tcp_ip4_spec.ip4dst);
+	hwlro_idx = mtk_hwlro_add_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = ip4dst;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[fsp->location]);
@@ -2998,13 +3077,17 @@
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
 	int hwlro_idx;
+	u32 ip4dst;
 
 	if (fsp->location > 1)
 		return -EINVAL;
 
-	mac->hwlro_ip[fsp->location] = 0;
-	hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + fsp->location;
+	ip4dst = mac->hwlro_ip[fsp->location];
+	hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, ip4dst);
+	if (hwlro_idx < 0)
+		return hwlro_idx;
 
+	mac->hwlro_ip[fsp->location] = 0;
 	mac->hwlro_ip_cnt = mtk_hwlro_get_ip_cnt(mac);
 
 	mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
@@ -3012,6 +3095,24 @@
 	return 0;
 }
 
+static void mtk_hwlro_netdev_enable(struct net_device *dev)
+{
+	struct mtk_mac *mac = netdev_priv(dev);
+	struct mtk_eth *eth = mac->hw;
+	int i, hwlro_idx;
+
+	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
+		mtk_hwlro_val_ipaddr(eth, hwlro_idx, mac->hwlro_ip[i]);
+	}
+}
+
 static void mtk_hwlro_netdev_disable(struct net_device *dev)
 {
 	struct mtk_mac *mac = netdev_priv(dev);
@@ -3019,8 +3120,14 @@
 	int i, hwlro_idx;
 
 	for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) {
+		if (mac->hwlro_ip[i] == 0)
+			continue;
+
+		hwlro_idx = mtk_hwlro_get_ipaddr_idx(dev, mac->hwlro_ip[i]);
+		if (hwlro_idx < 0)
+			continue;
+
 		mac->hwlro_ip[i] = 0;
-		hwlro_idx = (mac->id * MTK_MAX_LRO_IP_CNT) + i;
 
 		mtk_hwlro_inval_ipaddr(eth, hwlro_idx);
 	}
@@ -3210,13 +3317,17 @@
 {
 	struct mtk_mac *mac = netdev_priv(dev);
 	struct mtk_eth *eth = mac->hw;
+	netdev_features_t lro;
 	int err = 0;
 
 	if (!((dev->features ^ features) & MTK_SET_FEATURES))
 		return 0;
 
-	if (!(features & NETIF_F_LRO))
+	lro = dev->features & NETIF_F_LRO;
+	if (!(features & NETIF_F_LRO) && lro)
 		mtk_hwlro_netdev_disable(dev);
+	else if ((features & NETIF_F_LRO) && !lro)
+		mtk_hwlro_netdev_enable(dev);
 
 	if (!(features & NETIF_F_HW_VLAN_CTAG_RX))
 		mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
@@ -4150,7 +4261,7 @@
 	pr_info("[%s] mtk_stop starts !\n", __func__);
 	/* stop all devices to make sure that dma is properly shut down */
 	for (i = 0; i < MTK_MAC_COUNT; i++) {
-		if (!eth->netdev[i])
+		if (!eth->netdev[i] || !netif_running(eth->netdev[i]))
 			continue;
 		mtk_stop(eth->netdev[i]);
 		__set_bit(i, &restart);
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 7811de7..913302e 100644
--- 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
@@ -676,7 +676,8 @@
 
 /* XMAC status registers */
 #define MTK_XGMAC_STS(x)	((x == MTK_GMAC3_ID) ? 0x1001C : 0x1000C)
-#define MTK_XGMAC_FORCE_LINK(x)	((x == MTK_GMAC2_ID) ? BIT(31) : BIT(15))
+#define MTK_XGMAC_FORCE_MODE(x)	((x == MTK_GMAC2_ID) ? BIT(31) : BIT(15))
+#define MTK_XGMAC_FORCE_LINK(x)	((x == MTK_GMAC2_ID) ? BIT(27) : BIT(11))
 #define MTK_USXGMII_PCS_LINK	BIT(8)
 #define MTK_XGMAC_RX_FC		BIT(5)
 #define MTK_XGMAC_TX_FC		BIT(4)
@@ -1732,7 +1733,7 @@
 	struct mtk_eth		*eth;
 	struct regmap		*regmap;
 	struct regmap		*regmap_pextp;
-	struct delayed_work	link_poll;
+	spinlock_t		regmap_lock;
 	phy_interface_t		interface;
 	unsigned int		mode;
 	u8			id;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
index 8f11a83..6d86f25 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
@@ -867,6 +867,11 @@
 #endif
 #define CFG_PPE_NUM		(hnat_priv->ppe_num)
 
+/* If the user wants to set skb->mark to prevent hardware acceleration
+ * for the packet flow.
+ */
+#define HNAT_EXCEPTION_TAG	0x99
+
 struct mib_entry {
 	u32 byt_cnt_l;
 	u16 byt_cnt_h;
@@ -1218,13 +1223,11 @@
 #define UDF_PINGPONG_IFIDX GENMASK(3, 0)
 #define UDF_HNAT_PRE_FILLED BIT(4)
 
-#if defined(CONFIG_MEDIATEK_NETSYS_V3)
-#define TPORT_FLAG(dev, skb, qid)			\
+#define HQOS_FLAG(dev, skb, qid)			\
 	((IS_HQOS_UL_MODE && IS_WAN(dev)) ||		\
 	 (IS_HQOS_DL_MODE && IS_LAN_GRP(dev)) ||	\
 	 (IS_PPPQ_MODE && (IS_PPPQ_PATH(dev, skb) ||	\
 			   qid >= MAX_PPPQ_PORT_NUM)))
-#endif
 
 extern const struct of_device_id of_hnat_match[];
 extern struct mtk_hnat *hnat_priv;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
index f6c6499..7efe182 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
@@ -2069,11 +2069,9 @@
 		return -EFAULT;
 
 #if defined(CONFIG_MEDIATEK_NETSYS_V3)
-	if (rate > 100000000 || rate < 0 ||
-	    rate > 100000000 || rate < 0)
+	if (rate > 10000000 || rate < 0)
 #else
-	if (rate > 10000000 || rate < 0 ||
-	    rate > 10000000 || rate < 0)
+	if (rate > 1000000 || rate < 0)
 #endif
 		return -EINVAL;
 
@@ -2228,11 +2226,11 @@
 	line[length] = '\0';
 
 #if defined(CONFIG_MEDIATEK_NETSYS_V3)
-	if (max_rate > 100000000 || max_rate < 0 ||
-	    min_rate > 100000000 || min_rate < 0)
-#else
 	if (max_rate > 10000000 || max_rate < 0 ||
 	    min_rate > 10000000 || min_rate < 0)
+#else
+	if (max_rate > 1000000 || max_rate < 0 ||
+	    min_rate > 1000000 || min_rate < 0)
 #endif
 		return -EINVAL;
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
index 7af79ee..75ae019 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -1747,7 +1747,7 @@
 		return 0;
 	}
 
-	if (IS_HQOS_MODE || skb->mark >= MAX_PPPQ_PORT_NUM)
+	if (IS_HQOS_MODE || (skb->mark & MTK_QDMA_TX_MASK) >= MAX_PPPQ_PORT_NUM)
 		qid = skb->mark & (MTK_QDMA_TX_MASK);
 	else if (IS_PPPQ_MODE && IS_PPPQ_PATH(dev, skb))
 		qid = port_id & MTK_QDMA_TX_MASK;
@@ -1780,18 +1780,13 @@
 				}
 			}
 
-			if (FROM_EXT(skb) || skb_hnat_sport(skb) == NR_QDMA_PORT ||
-			    (IS_PPPQ_MODE && (qid < MAX_PPPQ_PORT_NUM) &&
-			     !IS_DSA_LAN(dev) && !IS_DSA_WAN(dev)))
+			if (FROM_EXT(skb) || skb_hnat_sport(skb) == NR_QDMA_PORT)
 				entry.ipv4_hnapt.iblk2.fqos = 0;
 			else
 #if defined(CONFIG_MEDIATEK_NETSYS_V3)
-				entry.ipv4_hnapt.tport_id = TPORT_FLAG(dev, skb, qid) ? 1 : 0;
+				entry.ipv4_hnapt.tport_id = HQOS_FLAG(dev, skb, qid) ? 1 : 0;
 #else
-				entry.ipv4_hnapt.iblk2.fqos =
-					(!IS_PPPQ_MODE ||
-					(IS_PPPQ_MODE &&
-					 IS_PPPQ_PATH(dev, skb)));
+				entry.ipv4_hnapt.iblk2.fqos = HQOS_FLAG(dev, skb, qid) ? 1 : 0;
 #endif
 		} else {
 			entry.ipv4_hnapt.iblk2.fqos = 0;
@@ -1821,9 +1816,7 @@
 				}
 			}
 
-			if (FROM_EXT(skb) ||
-			    (IS_PPPQ_MODE && (qid < MAX_PPPQ_PORT_NUM) &&
-			     !IS_DSA_LAN(dev) && !IS_DSA_WAN(dev)))
+			if (FROM_EXT(skb) || skb_hnat_sport(skb) == NR_QDMA_PORT)
 				entry.ipv6_5t_route.iblk2.fqos = 0;
 			else
 #if defined(CONFIG_MEDIATEK_NETSYS_V3)
@@ -1831,23 +1824,20 @@
 				case IPV4_MAP_E:
 				case IPV4_MAP_T:
 					entry.ipv4_mape.tport_id =
-						TPORT_FLAG(dev, skb, qid) ? 1 : 0;
+						HQOS_FLAG(dev, skb, qid) ? 1 : 0;
 					break;
 				case IPV6_HNAPT:
 				case IPV6_HNAT:
 					entry.ipv6_hnapt.tport_id =
-						TPORT_FLAG(dev, skb, qid) ? 1 : 0;
+						HQOS_FLAG(dev, skb, qid) ? 1 : 0;
 					break;
 				default:
 					entry.ipv6_5t_route.tport_id =
-						TPORT_FLAG(dev, skb, qid) ? 1 : 0;
+						HQOS_FLAG(dev, skb, qid) ? 1 : 0;
 					break;
 				}
 #else
-				entry.ipv6_5t_route.iblk2.fqos =
-					(!IS_PPPQ_MODE ||
-					 (IS_PPPQ_MODE &&
-					  IS_PPPQ_PATH(dev, skb)));
+				entry.ipv6_5t_route.iblk2.fqos = HQOS_FLAG(dev, skb, qid) ? 1 : 0;
 #endif
 		} else {
 			entry.ipv6_5t_route.iblk2.fqos = 0;
@@ -2673,6 +2663,9 @@
 	if (unlikely(!skb_hnat_is_hashed(skb)))
 		return 0;
 
+	if (unlikely(skb->mark == HNAT_EXCEPTION_TAG))
+		return 0;
+
 	if (out->netdev_ops->ndo_flow_offload_check) {
 		out->netdev_ops->ndo_flow_offload_check(&hw_path);
 		out = (IS_GMAC1_MODE) ? hw_path.virt_dev : hw_path.dev;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
index 3c16948..d297994 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
@@ -112,9 +112,9 @@
 #define skb_hnat_hf(skb) (((struct hnat_desc *)((skb)->head))->hf)
 #define skb_hnat_amsdu(skb) (((struct hnat_desc *)((skb)->head))->amsdu)
 #define skb_hnat_ppe2(skb)						\
-	((skb_hnat_iface(skb) == FOE_MAGIC_GE_LAN2) && (CFG_PPE_NUM == 3))
+	((skb_hnat_sport(skb) == NR_GMAC3_PORT) && (CFG_PPE_NUM == 3))
 #define skb_hnat_ppe1(skb)						\
-	((skb_hnat_iface(skb) == FOE_MAGIC_GE_WAN) && (CFG_PPE_NUM == 3))
+	((skb_hnat_sport(skb) == NR_GMAC2_PORT) && (CFG_PPE_NUM >= 2))
 #define skb_hnat_ppe(skb)						\
 	(skb_hnat_ppe2(skb) ? 2 : (skb_hnat_ppe1(skb) ? 1 : 0))
 #define headroom_iface(h) (h.iface)
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 3cc8f90..bdb6662 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
@@ -144,7 +144,7 @@
 	mdelay(1);
 }
 
-int mtk_sgmii_need_powerdown(struct mtk_sgmii_pcs *mpcs)
+int mtk_sgmii_need_powerdown(struct mtk_sgmii_pcs *mpcs, unsigned int bmcr)
 {
 	u32 val;
 
@@ -153,6 +153,10 @@
 	if (!(val & SGMII_LINK_STATYS))
 		return true;
 
+	/* need to power down sgmii if autoneg change */
+	if ((val & SGMII_AN_ENABLE) != bmcr)
+		return true;
+
 	return false;
 }
 
@@ -455,7 +459,7 @@
 	}
 
 	if (mpcs->interface != interface ||
-	    mtk_sgmii_need_powerdown(mpcs)) {
+	    mtk_sgmii_need_powerdown(mpcs, bmcr)) {
 		link_timer = phylink_get_link_timer_ns(interface);
 		if (link_timer < 0)
 			return link_timer;
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 0cadc85..cdb2a55 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
@@ -568,6 +568,8 @@
 	unsigned int an_ctrl = 0, link_timer = 0, xfi_mode = 0, adapt_mode = 0;
 	bool mode_changed = false;
 
+	spin_lock(&mpcs->regmap_lock);
+
 	if (interface == PHY_INTERFACE_MODE_USXGMII) {
 		an_ctrl = FIELD_PREP(USXGMII_AN_SYNC_CNT, 0x1FF) |
 			  USXGMII_AN_ENABLE;
@@ -656,6 +658,8 @@
 	else if (interface == PHY_INTERFACE_MODE_5GBASER)
 		mtk_usxgmii_setup_phya_5gbaser(mpcs);
 
+	spin_unlock(&mpcs->regmap_lock);
+
 	return mode_changed;
 }
 
@@ -665,6 +669,7 @@
 	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)];
+	static unsigned long t_start;
 	u32 val = 0;
 
 	regmap_read(mpcs->regmap, RG_PCS_AN_CTRL0, &val);
@@ -727,9 +732,14 @@
 		state->duplex = DUPLEX_FULL;
 	}
 
-	if (state->link == 0)
+	/* Reconfiguring USXGMII every second to ensure that PCS can
+	 * link up with the Link Partner when a module is inserted.
+	 */
+	if (state->link == 0 && time_after(jiffies, t_start + HZ)) {
+		t_start = jiffies;
 		mtk_usxgmii_pcs_config(pcs, MLO_AN_INBAND,
 				       state->interface, NULL, false);
+	}
 }
 
 void mtk_usxgmii_pcs_restart_an(struct phylink_pcs *pcs)
@@ -745,25 +755,12 @@
 	regmap_write(mpcs->regmap, RG_PCS_AN_CTRL0, val);
 }
 
-void mtk_usxgmii_link_poll(struct work_struct *work)
-{
-	struct delayed_work *dwork = to_delayed_work(work);
-	struct mtk_usxgmii_pcs *mpcs = container_of(dwork, struct mtk_usxgmii_pcs, link_poll);
-
-	if (!mtk_usxgmii_link_status(mpcs)) {
-		mtk_usxgmii_pcs_config(&mpcs->pcs, mpcs->mode,
-				       mpcs->interface, NULL, false);
-
-		queue_delayed_work(system_power_efficient_wq, &mpcs->link_poll,
-				   msecs_to_jiffies(1000));
-	}
-}
-
 static void mtk_usxgmii_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
 				    phy_interface_t interface,
 				    int speed, int duplex)
 {
 	struct mtk_usxgmii_pcs *mpcs = pcs_to_mtk_usxgmii_pcs(pcs);
+	unsigned long t_start = jiffies;
 
 	/* Reconfiguring USXGMII to ensure the quality of the RX signal
 	 * after the line side link up.
@@ -771,8 +768,18 @@
 	mtk_usxgmii_pcs_config(pcs, mode,
 			       interface, NULL, false);
 
-	queue_delayed_work(system_power_efficient_wq, &mpcs->link_poll,
-			   msecs_to_jiffies(1000));
+	do {
+		msleep(1000);
+
+		if (mtk_usxgmii_link_status(mpcs))
+			return;
+
+		if (mpcs->mode == MLO_AN_PHY)
+			mtk_usxgmii_pcs_config(&mpcs->pcs, mode,
+						interface, NULL, false);
+	} while (time_before(jiffies, t_start + msecs_to_jiffies(3000)));
+
+	pr_warn("%s wait link up timeout!\n", __func__);
 }
 
 static const struct phylink_pcs_ops mtk_usxgmii_pcs_ops = {
@@ -804,7 +811,7 @@
 		ss->pcs[i].pcs.poll = true;
 		ss->pcs[i].interface = PHY_INTERFACE_MODE_NA;
 
-		INIT_DELAYED_WORK(&ss->pcs[i].link_poll, mtk_usxgmii_link_poll);
+		spin_lock_init(&ss->pcs[i].regmap_lock);
 
 		of_node_put(np);
 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-2p5ge.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-2p5ge.c
index 6a1c9e0..ab87e93 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-2p5ge.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-2p5ge.c
@@ -7,12 +7,14 @@
 #include <linux/of_platform.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/phy.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 
-#define MEDAITEK_2P5GE_PHY_DMB_FW "mediatek-2p5ge-phy-dmb.bin"
-#define MEDIATEK_2P5GE_PHY_PMB_FW "mediatek-2p5ge-phy-pmb.bin"
+#define MT7988_2P5GE_PMB "mediatek/mt7988/i2p5ge-phy-pmb.bin"
 
-#define MD32_EN_CFG	0x18
-#define   MD32_EN	BIT(0)
+#define MD32_EN			BIT(0)
+#define PMEM_PRIORITY		BIT(8)
+#define DMEM_PRIORITY		BIT(16)
 
 #define BASE100T_STATUS_EXTEND		(0x10)
 #define BASE1000T_STATUS_EXTEND		(0x11)
@@ -42,6 +44,14 @@
 #define   MTK_PHY_LED1_ON_HDX			BIT(5)
 #define   MTK_PHY_LED1_POLARITY			BIT(14)
 
+#define MTK_EXT_PAGE_ACCESS			0x1f
+#define MTK_PHY_PAGE_STANDARD			0x0000
+#define MTK_PHY_PAGE_EXTENDED_52B5		0x52b5
+
+struct mtk_i2p5ge_phy_priv {
+	bool fw_loaded;
+};
+
 enum {
 	PHY_AUX_SPD_10 = 0,
 	PHY_AUX_SPD_100,
@@ -49,60 +59,100 @@
 	PHY_AUX_SPD_2500,
 };
 
-static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
+static int mtk_2p5ge_phy_read_page(struct phy_device *phydev)
 {
-	int ret;
-	int i;
+	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+}
+
+static int mtk_2p5ge_phy_write_page(struct phy_device *phydev, int page)
+{
+	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+}
+
+static int mt7988_2p5ge_phy_probe(struct phy_device *phydev)
+{
+	struct mtk_i2p5ge_phy_priv *phy_priv;
+
+	phy_priv = devm_kzalloc(&phydev->mdio.dev,
+				sizeof(struct mtk_i2p5ge_phy_priv), GFP_KERNEL);
+	if (!phy_priv)
+		return -ENOMEM;
+
+	phydev->priv = phy_priv;
+
+	return 0;
+}
+
+static int mt7988_2p5ge_phy_config_init(struct phy_device *phydev)
+{
+	int ret, i;
 	const struct firmware *fw;
 	struct device *dev = &phydev->mdio.dev;
+	struct device *pm_dev;
 	struct device_node *np;
-	void __iomem *dmb_addr;
 	void __iomem *pmb_addr;
-	void __iomem *mcucsr_base;
+	void __iomem *md32_en_cfg_base;
+	struct mtk_i2p5ge_phy_priv *phy_priv = phydev->priv;
 	u16 reg;
 	struct pinctrl *pinctrl;
 
+	if (!phy_priv->fw_loaded) {
+		pm_dev = dev_pm_domain_attach_by_name(dev, "i2p5gbe-pd");
+		if (IS_ERR(pm_dev)) {
+			ret = PTR_ERR(pm_dev);
+			dev_err(dev, "failed to get i2p5g pm-domain: %d\n", ret);
+			return ret;
+		}
+		if (!pm_dev->pm_domain)
+			dev_info(dev, "pm_dev domain is not ready yet\n");
+
+		/* We need to add 1 to power domain counter first so that
+		 * we can correctly power off internal 2.5Gphy
+		 */
+		ret = pm_runtime_get_sync(pm_dev);
+		if (ret < 0) {
+			dev_err(&phydev->mdio.dev, "failed to power on!\n");
+			return ret;
+		}
+		pm_runtime_put_sync(pm_dev);
+		ret = pm_runtime_get_sync(pm_dev);
+		if (ret < 0) {
+			dev_err(&phydev->mdio.dev, "failed to power on!\n");
+			return ret;
+		}
 
-	np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
-	if (!np)
-		return -ENOENT;
+		np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
+		if (!np)
+			return -ENOENT;
+		pmb_addr = of_iomap(np, 0);
+		if (!pmb_addr)
+			return -ENOMEM;
+		md32_en_cfg_base = of_iomap(np, 1);
+		if (!md32_en_cfg_base)
+			return -ENOMEM;
 
-	dmb_addr = of_iomap(np, 0);
-	if (!dmb_addr)
-		return -ENOMEM;
-	pmb_addr = of_iomap(np, 1);
-	if (!pmb_addr)
-		return -ENOMEM;
-	mcucsr_base = of_iomap(np, 2);
-	if (!mcucsr_base)
-		return -ENOMEM;
+		ret = request_firmware(&fw, MT7988_2P5GE_PMB, dev);
+		if (ret) {
+			dev_err(dev, "failed to load firmware: %s, ret: %d\n",
+				MT7988_2P5GE_PMB, ret);
+			return ret;
+		}
 
-	ret = request_firmware(&fw, MEDAITEK_2P5GE_PHY_DMB_FW, dev);
-	if (ret) {
-		dev_err(dev, "failed to load firmware: %s, ret: %d\n",
-			MEDAITEK_2P5GE_PHY_DMB_FW, ret);
-		return ret;
-	}
-	for (i = 0; i < fw->size - 1; i += 4)
-		writel(*((uint32_t *)(fw->data + i)), dmb_addr + i);
-	release_firmware(fw);
+		reg = readw(md32_en_cfg_base);
+		writew(reg | DMEM_PRIORITY | PMEM_PRIORITY, md32_en_cfg_base);
 
-	ret = request_firmware(&fw, MEDIATEK_2P5GE_PHY_PMB_FW, dev);
-	if (ret) {
-		dev_err(dev, "failed to load firmware: %s, ret: %d\n",
-			MEDIATEK_2P5GE_PHY_PMB_FW, ret);
-		return ret;
-	}
-	for (i = 0; i < fw->size - 1; i += 4)
-		writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
-	release_firmware(fw);
+		for (i = 0; i < fw->size - 1; i += 4)
+			writel(*((uint32_t *)(fw->data + i)), pmb_addr + i);
+		release_firmware(fw);
 
-	reg = readw(mcucsr_base + MD32_EN_CFG);
-	writew(reg | MD32_EN, mcucsr_base + MD32_EN_CFG);
-	dev_info(dev, "Firmware loading/trigger ok.\n");
+		reg = readw(md32_en_cfg_base);
+		reg &= ~(DMEM_PRIORITY | PMEM_PRIORITY | MD32_EN);
+		writew(reg, md32_en_cfg_base);
+		writew(reg | MD32_EN, md32_en_cfg_base);
+		dev_info(dev, "Firmware loading/trigger ok.\n");
 
-	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL,
-		       MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0);
+		phy_priv->fw_loaded = true;
+	}
 
 	/* Setup LED */
 	phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL,
@@ -118,10 +168,20 @@
 		return PTR_ERR(pinctrl);
 	}
 
+	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LPI_PCS_DSP_CTRL,
+		       MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK, 0);
+
+	/* Enable 16-bit next page exchange bit if 1000-BT isn't advertizing */
+	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+	__phy_write(phydev, 0x11, 0xfbfa);
+	__phy_write(phydev, 0x12, 0xc3);
+	__phy_write(phydev, 0x10, 0x87f8);
+	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
 	return 0;
 }
 
-static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev)
+static int mt7988_2p5ge_phy_config_aneg(struct phy_device *phydev)
 {
 	bool changed = false;
 	u32 adv;
@@ -154,7 +214,7 @@
 	return genphy_c45_check_and_restart_aneg(phydev, changed);
 }
 
-static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
+static int mt7988_2p5ge_phy_get_features(struct phy_device *phydev)
 {
 	int ret;
 
@@ -162,7 +222,7 @@
 	if (ret)
 		return ret;
 
-	/* We don't support HDX at MAC layer on mt798x.
+	/* We don't support HDX at MAC layer on mt7988.
 	 * So mask phy's HDX capabilities, too.
 	 */
 	linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
@@ -178,7 +238,7 @@
 	return 0;
 }
 
-static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev)
+static int mt7988_2p5ge_phy_read_status(struct phy_device *phydev)
 {
 	int ret;
 
@@ -234,7 +294,7 @@
 	return 0;
 }
 
-static int mt798x_2p5ge_phy_get_rate_matching(struct phy_device *phydev,
+static int mt7988_2p5ge_phy_get_rate_matching(struct phy_device *phydev,
 					      phy_interface_t iface)
 {
 	if (iface == PHY_INTERFACE_MODE_XGMII)
@@ -244,17 +304,18 @@
 
 static struct phy_driver mtk_gephy_driver[] = {
 	{
-		PHY_ID_MATCH_EXACT(0x00339c11),
+		PHY_ID_MATCH_MODEL(0x00339c11),
 		.name		= "MediaTek MT798x 2.5GbE PHY",
-		.config_init	= mt798x_2p5ge_phy_config_init,
-		.config_aneg    = mt798x_2p5ge_phy_config_aneg,
-		.get_features	= mt798x_2p5ge_phy_get_features,
-		.read_status	= mt798x_2p5ge_phy_read_status,
-		.get_rate_matching	= mt798x_2p5ge_phy_get_rate_matching,
-		//.config_intr	= genphy_no_config_intr,
-		//.handle_interrupt = genphy_no_ack_interrupt,
+		.probe		= mt7988_2p5ge_phy_probe,
+		.config_init	= mt7988_2p5ge_phy_config_init,
+		.config_aneg    = mt7988_2p5ge_phy_config_aneg,
+		.get_features	= mt7988_2p5ge_phy_get_features,
+		.read_status	= mt7988_2p5ge_phy_read_status,
+		.get_rate_matching	= mt7988_2p5ge_phy_get_rate_matching,
 		.suspend	= genphy_suspend,
 		.resume		= genphy_resume,
+		.read_page	= mtk_2p5ge_phy_read_page,
+		.write_page	= mtk_2p5ge_phy_write_page,
 	},
 };
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-si3218x.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt7986/mt7986-si3218x.c
similarity index 63%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-si3218x.c
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt7986/mt7986-si3218x.c
index 6a45595..b91ee07 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-si3218x.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt7986/mt7986-si3218x.c
@@ -1,17 +1,18 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * mt79xx-si3218x.c  --  MT79xx WM8960 ALSA SoC machine driver
+ * mt7986-si3218x.c  --  MT7986-SI3218X ALSA SoC machine driver
  *
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Vic Wu <vic.wu@mediatek.com>
+ * Copyright (c) 2023 MediaTek Inc.
+ * Authors: Vic Wu <vic.wu@mediatek.com>
+ *          Maso Huang <maso.huang@mediatek.com>
  */
 
+#include <linux/bitfield.h>
 #include <linux/module.h>
 #include <sound/soc.h>
 
-#include "mt79xx-afe-clk.h"
-#include "mt79xx-afe-common.h"
-#include "mt79xx-reg.h"
+#include "mt7986-afe-common.h"
+#include "mt7986-reg.h"
 #include "../common/mtk-afe-platform-driver.h"
 
 enum {
@@ -62,23 +63,23 @@
 	ETDM_FS_176K = 20,
 };
 
-struct mt79xx_si3218x_priv {
-	struct device_node *platform_node;
-	struct device_node *codec_node;
-};
-
-static int mt79xx_si3218x_init(struct snd_soc_pcm_runtime *rtd)
+static int mt7986_si3218x_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_component *component =
 		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
 	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+	struct mt7986_afe_private *afe_priv = afe->platform_priv;
+	int ret;
 
 	/* enable clk */
-	mt79xx_afe_enable_clock(afe);
-	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
-			   0);
-	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
-			   0);
+	ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
+	if (ret) {
+		dev_err(afe->dev, "Failed to enable clocks\n");
+		return ret;
+	}
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);
 	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
 	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
 			   AUD_APLL2_EN);
@@ -89,15 +90,15 @@
 	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_SYNC_MASK,
 			   ETDM_SYNC);
 	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_FMT_MASK,
-			   ETDM_FMT(PCMA));
+			   FIELD_PREP(ETDM_FMT_MASK, PCMA));
 	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_BIT_LEN_MASK,
-			   ETDM_BIT_LEN(16));
+			   FIELD_PREP(ETDM_BIT_LEN_MASK, 16 - 1));
 	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_WRD_LEN_MASK,
-			   ETDM_WRD_LEN(16));
+			   FIELD_PREP(ETDM_WRD_LEN_MASK, 16 - 1));
 	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_CH_NUM_MASK,
-			   ETDM_CH_NUM(4));
+			   FIELD_PREP(ETDM_CH_NUM_MASK, 4 - 1));
 	regmap_update_bits(afe->regmap, ETDM_IN5_CON0, RELATCH_SRC_MASK,
-			   RELATCH_SRC(APLL_CLK));
+			   FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK));
 
 	/* set ETDM_IN5_CON2 */
 	regmap_update_bits(afe->regmap, ETDM_IN5_CON2, IN_CLK_SRC_MASK,
@@ -115,15 +116,15 @@
 
 	/* set ETDM_OUT5_CON0 */
 	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_FMT_MASK,
-			   ETDM_FMT(PCMA));
+			   FIELD_PREP(ETDM_FMT_MASK, PCMA));
 	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_BIT_LEN_MASK,
-			   ETDM_BIT_LEN(16));
+			   FIELD_PREP(ETDM_BIT_LEN_MASK, 16 - 1));
 	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_WRD_LEN_MASK,
-			   ETDM_WRD_LEN(16));
+			   FIELD_PREP(ETDM_WRD_LEN_MASK, 16 - 1));
 	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_CH_NUM_MASK,
-			   ETDM_CH_NUM(4));
+			   FIELD_PREP(ETDM_CH_NUM_MASK, 4 - 1));
 	regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, RELATCH_SRC_MASK,
-			   RELATCH_SRC(APLL_CLK));
+			   FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK));
 
 	/* set ETDM_OUT5_CON4 */
 	regmap_update_bits(afe->regmap, ETDM_OUT5_CON4, OUT_SEL_FS_MASK,
@@ -167,7 +168,7 @@
 	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "proslic_spi-aif")),
 	DAILINK_COMP_ARRAY(COMP_EMPTY()));
 
-static struct snd_soc_dai_link mt79xx_si3218x_dai_links[] = {
+static struct snd_soc_dai_link mt7986_si3218x_dai_links[] = {
 	/* FE */
 	{
 		.name = "si3218x-playback",
@@ -194,34 +195,41 @@
 		.dai_fmt = SND_SOC_DAIFMT_DSP_A |
 			SND_SOC_DAIFMT_IB_NF |
 			SND_SOC_DAIFMT_CBS_CFS,
-		.init = mt79xx_si3218x_init,
+		.init = mt7986_si3218x_init,
 		.dpcm_playback = 1,
 		.dpcm_capture = 1,
 		SND_SOC_DAILINK_REG(codec),
 	},
 };
 
-static struct snd_soc_card mt79xx_si3218x_card = {
-	.name = "mt79xx-si3218x",
+static struct snd_soc_card mt7986_si3218x_card = {
+	.name = "mt7986-si3218x",
 	.owner = THIS_MODULE,
-	.dai_link = mt79xx_si3218x_dai_links,
-	.num_links = ARRAY_SIZE(mt79xx_si3218x_dai_links),
+	.dai_link = mt7986_si3218x_dai_links,
+	.num_links = ARRAY_SIZE(mt7986_si3218x_dai_links),
 };
 
-static int mt79xx_si3218x_machine_probe(struct platform_device *pdev)
+static int mt7986_si3218x_machine_probe(struct platform_device *pdev)
 {
-	struct snd_soc_card *card = &mt79xx_si3218x_card;
+	struct snd_soc_card *card = &mt7986_si3218x_card;
 	struct snd_soc_dai_link *dai_link;
-	struct mt79xx_si3218x_priv *priv;
+	struct device_node *platform, *codec;
+	struct device_node *platform_dai_node, *codec_dai_node;
 	int ret, i;
 
+	card->dev = &pdev->dev;
+
+	platform = of_get_child_by_name(pdev->dev.of_node, "platform");
+
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	if (platform) {
+		platform_dai_node = of_parse_phandle(platform, "sound-dai", 0);
+		of_node_put(platform);
 
-	priv->platform_node = of_parse_phandle(pdev->dev.of_node,
-					       "mediatek,platform", 0);
-	if (!priv->platform_node) {
+		if (!platform_dai_node) {
+			dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
+			return -EINVAL;
+		}
+	} else {
 		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
 		return -EINVAL;
 	}
@@ -229,70 +237,61 @@
 	for_each_card_prelinks(card, i, dai_link) {
 		if (dai_link->platforms->name)
 			continue;
-		dai_link->platforms->of_node = priv->platform_node;
+		dai_link->platforms->of_node = platform_dai_node;
 	}
 
-	card->dev = &pdev->dev;
+	codec = of_get_child_by_name(pdev->dev.of_node, "codec");
+
+	if (codec) {
+		codec_dai_node = of_parse_phandle(codec, "sound-dai", 0);
+		of_node_put(codec);
 
-	priv->codec_node = of_parse_phandle(pdev->dev.of_node,
-					    "mediatek,ext-codec", 0);
-	if (!priv->codec_node) {
-		dev_err(&pdev->dev,
-			"Property 'audio-codec' missing or invalid\n");
-		of_node_put(priv->platform_node);
+		if (!codec_dai_node) {
+			of_node_put(platform_dai_node);
+			dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
+			return -EINVAL;
+		}
+	} else {
+		of_node_put(platform_dai_node);
+		dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
 		return -EINVAL;
 	}
 
 	for_each_card_prelinks(card, i, dai_link) {
 		if (dai_link->codecs->name)
 			continue;
-		dai_link->codecs->of_node = priv->codec_node;
+		dai_link->codecs->of_node = codec_dai_node;
 	}
 
 	ret = devm_snd_soc_register_card(&pdev->dev, card);
 	if (ret) {
-		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
-			__func__, ret);
-		of_node_put(priv->codec_node);
-		of_node_put(priv->platform_node);
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret);
+		goto err_of_node_put;
 	}
 
+err_of_node_put:
+	of_node_put(platform_dai_node);
+	of_node_put(codec_dai_node);
 	return ret;
 }
 
-static int mt79xx_si3218x_machine_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct mt79xx_si3218x_priv *priv = snd_soc_card_get_drvdata(card);
-
-	of_node_put(priv->codec_node);
-	of_node_put(priv->platform_node);
-
-	return 0;
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id mt79xx_si3218x_machine_dt_match[] = {
-	{.compatible = "mediatek,mt79xx-si3218x-machine",},
-	{}
+static const struct of_device_id mt7986_si3218x_machine_dt_match[] = {
+	{.compatible = "mediatek,mt7986-si3218x-sound"},
+	{ /* sentinel */ }
 };
-#endif
 
-static struct platform_driver mt79xx_si3218x_machine = {
+static struct platform_driver mt7986_si3218x_machine = {
 	.driver = {
-		.name = "mt79xx-si3218x",
-#ifdef CONFIG_OF
-		.of_match_table = mt79xx_si3218x_machine_dt_match,
-#endif
+		.name = "mt7986-si3218x",
+		.of_match_table = mt7986_si3218x_machine_dt_match,
 	},
-	.probe = mt79xx_si3218x_machine_probe,
-	.remove = mt79xx_si3218x_machine_remove,
+	.probe = mt7986_si3218x_machine_probe,
 };
 
-module_platform_driver(mt79xx_si3218x_machine);
+module_platform_driver(mt7986_si3218x_machine);
 
 /* Module information */
-MODULE_DESCRIPTION("MT79xx SI3218x ALSA SoC machine driver");
+MODULE_DESCRIPTION("MT7986 SI3218X ALSA SoC machine driver");
 MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("mt79xx si3218x soc card");
+MODULE_ALIAS("mt7986 si3218x soc card");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/Makefile
deleted file mode 100644
index 958ad63..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-# platform driver
-snd-soc-mt79xx-afe-objs := \
-	mt79xx-afe-pcm.o \
-	mt79xx-afe-clk.o \
-	mt79xx-dai-etdm.o
-
-obj-$(CONFIG_SND_SOC_MT79XX) += snd-soc-mt79xx-afe.o
-obj-$(CONFIG_SND_SOC_MT79XX_WM8960) += mt79xx-wm8960.o
-obj-$(CONFIG_SND_SOC_MT79XX_SI3218X) += mt79xx-si3218x.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.c
deleted file mode 100644
index 6f13c42..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// mt79xx-afe-clk.c  --  Mediatek 79xx afe clock ctrl
-//
-// Copyright (c) 2021 MediaTek Inc.
-// Author: Vic Wu <vic.wu@mediatek.com>
-
-#include <linux/clk.h>
-
-#include "mt79xx-afe-common.h"
-#include "mt79xx-afe-clk.h"
-#include "mt79xx-reg.h"
-
-enum {
-	CK_INFRA_AUD_BUS_CK = 0,
-	CK_INFRA_AUD_26M_CK,
-	CK_INFRA_AUD_L_CK,
-	CK_INFRA_AUD_AUD_CK,
-	CK_INFRA_AUD_EG2_CK,
-	CLK_NUM
-};
-
-static const char *aud_clks[CLK_NUM] = {
-	[CK_INFRA_AUD_BUS_CK] = "aud_bus_ck",
-	[CK_INFRA_AUD_26M_CK] = "aud_26m_ck",
-	[CK_INFRA_AUD_L_CK] = "aud_l_ck",
-	[CK_INFRA_AUD_AUD_CK] = "aud_aud_ck",
-	[CK_INFRA_AUD_EG2_CK] = "aud_eg2_ck",
-};
-
-int mt79xx_init_clock(struct mtk_base_afe *afe)
-{
-	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
-	int i;
-
-	afe_priv->clk = devm_kcalloc(afe->dev, CLK_NUM, sizeof(*afe_priv->clk),
-				     GFP_KERNEL);
-	if (!afe_priv->clk)
-		return -ENOMEM;
-
-	for (i = 0; i < CLK_NUM; i++) {
-		afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
-		if (IS_ERR(afe_priv->clk[i])) {
-			dev_err(afe->dev, "%s(), devm_clk_get %s fail,\
-				ret %ld\n", __func__, aud_clks[i],
-				PTR_ERR(afe_priv->clk[i]));
-			return PTR_ERR(afe_priv->clk[i]);
-		}
-	}
-
-	return 0;
-}
-
-int mt79xx_afe_enable_clock(struct mtk_base_afe *afe)
-{
-	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
-	int ret;
-
-	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_BUS_CK]);
-	if (ret) {
-		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
-			__func__, aud_clks[CK_INFRA_AUD_BUS_CK], ret);
-		goto CK_INFRA_AUD_BUS_CK_ERR;
-	}
-
-	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_26M_CK]);
-	if (ret) {
-		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
-			__func__, aud_clks[CK_INFRA_AUD_26M_CK], ret);
-		goto CK_INFRA_AUD_26M_ERR;
-	}
-
-	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_L_CK]);
-	if (ret) {
-		dev_err(afe->dev, "%s(), clk_prepare_enable %s fail %d\n",
-			__func__, aud_clks[CK_INFRA_AUD_L_CK], ret);
-		goto CK_INFRA_AUD_L_CK_ERR;
-	}
-
-	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_AUD_CK]);
-	if (ret) {
-		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
-			__func__, aud_clks[CK_INFRA_AUD_AUD_CK], ret);
-		goto CK_INFRA_AUD_AUD_CK_ERR;
-	}
-
-	ret = clk_prepare_enable(afe_priv->clk[CK_INFRA_AUD_EG2_CK]);
-	if (ret) {
-		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
-			__func__, aud_clks[CK_INFRA_AUD_EG2_CK], ret);
-		goto CK_INFRA_AUD_EG2_CK_ERR;
-	}
-
-	return 0;
-
-CK_INFRA_AUD_EG2_CK_ERR:
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_AUD_CK]);
-CK_INFRA_AUD_AUD_CK_ERR:
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_L_CK]);
-CK_INFRA_AUD_L_CK_ERR:
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_26M_CK]);
-CK_INFRA_AUD_26M_ERR:
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_BUS_CK]);
-CK_INFRA_AUD_BUS_CK_ERR:
-	return ret;
-}
-EXPORT_SYMBOL_GPL(mt79xx_afe_enable_clock);
-
-int mt79xx_afe_disable_clock(struct mtk_base_afe *afe)
-{
-	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
-
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_EG2_CK]);
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_AUD_CK]);
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_L_CK]);
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_26M_CK]);
-	clk_disable_unprepare(afe_priv->clk[CK_INFRA_AUD_BUS_CK]);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(mt79xx_afe_disable_clock);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.h
deleted file mode 100644
index 50424d8..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-clk.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * mt79xx-afe-clk.h  --  Mediatek 79xx afe clock ctrl definition
- *
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Vic Wu <vic.wu@mediatek.com>
- */
-
-#ifndef _MT79XX_AFE_CLK_H_
-#define _MT79XX_AFE_CLK_H_
-
-struct mtk_base_afe;
-
-int mt79xx_init_clock(struct mtk_base_afe *afe);
-int mt79xx_afe_enable_clock(struct mtk_base_afe *afe);
-int mt79xx_afe_disable_clock(struct mtk_base_afe *afe);
-#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-common.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-common.h
deleted file mode 100644
index 277d10c..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-common.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * mt79xx-afe-common.h  --  Mediatek 79xx audio driver definitions
- *
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Vic Wu <vic.wu@mediatek.com>
- */
-
-#ifndef _MT_79XX_AFE_COMMON_H_
-#define _MT_79XX_AFE_COMMON_H_
-
-#include <sound/soc.h>
-#include <linux/list.h>
-#include <linux/regmap.h>
-#include "../common/mtk-base-afe.h"
-
-enum {
-	MT79XX_MEMIF_DL1,
-	MT79XX_MEMIF_VUL12,
-	MT79XX_MEMIF_NUM,
-	MT79XX_DAI_ETDM = MT79XX_MEMIF_NUM,
-	MT79XX_DAI_NUM,
-};
-
-enum {
-	MT79XX_IRQ_0,
-	MT79XX_IRQ_1,
-	MT79XX_IRQ_2,
-	MT79XX_IRQ_NUM,
-};
-
-struct clk;
-
-struct mt79xx_afe_private {
-	struct clk **clk;
-
-	int pm_runtime_bypass_reg_ctl;
-
-	/* dai */
-	void *dai_priv[MT79XX_DAI_NUM];
-};
-
-unsigned int mt79xx_afe_rate_transform(struct device *dev,
-				       unsigned int rate);
-
-/* dai register */
-int mt79xx_dai_etdm_register(struct mtk_base_afe *afe);
-#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-pcm.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-pcm.c
deleted file mode 100644
index 63162c7..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-afe-pcm.c
+++ /dev/null
@@ -1,607 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// Mediatek ALSA SoC AFE platform driver for 79xx
-//
-// Copyright (c) 2021 MediaTek Inc.
-// Author: Vic Wu <vic.wu@mediatek.com>
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/pm_runtime.h>
-
-#include "mt79xx-afe-common.h"
-#include "mt79xx-afe-clk.h"
-#include "mt79xx-reg.h"
-#include "../common/mtk-afe-platform-driver.h"
-#include "../common/mtk-afe-fe-dai.h"
-
-enum {
-	MTK_AFE_RATE_8K = 0,
-	MTK_AFE_RATE_11K = 1,
-	MTK_AFE_RATE_12K = 2,
-	MTK_AFE_RATE_16K = 4,
-	MTK_AFE_RATE_22K = 5,
-	MTK_AFE_RATE_24K = 6,
-	MTK_AFE_RATE_32K = 8,
-	MTK_AFE_RATE_44K = 9,
-	MTK_AFE_RATE_48K = 10,
-	MTK_AFE_RATE_88K = 13,
-	MTK_AFE_RATE_96K = 14,
-	MTK_AFE_RATE_176K = 17,
-	MTK_AFE_RATE_192K = 18,
-};
-
-unsigned int mt79xx_afe_rate_transform(struct device *dev,
-				       unsigned int rate)
-{
-	switch (rate) {
-	case 8000:
-		return MTK_AFE_RATE_8K;
-	case 11025:
-		return MTK_AFE_RATE_11K;
-	case 12000:
-		return MTK_AFE_RATE_12K;
-	case 16000:
-		return MTK_AFE_RATE_16K;
-	case 22050:
-		return MTK_AFE_RATE_22K;
-	case 24000:
-		return MTK_AFE_RATE_24K;
-	case 32000:
-		return MTK_AFE_RATE_32K;
-	case 44100:
-		return MTK_AFE_RATE_44K;
-	case 48000:
-		return MTK_AFE_RATE_48K;
-	case 88200:
-		return MTK_AFE_RATE_88K;
-	case 96000:
-		return MTK_AFE_RATE_96K;
-	case 176400:
-		return MTK_AFE_RATE_176K;
-	case 192000:
-		return MTK_AFE_RATE_192K;
-	default:
-		dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
-			 __func__, rate, MTK_AFE_RATE_48K);
-		return MTK_AFE_RATE_48K;
-	}
-}
-
-static const struct snd_pcm_hardware mt79xx_afe_hardware = {
-	.info = SNDRV_PCM_INFO_MMAP |
-		SNDRV_PCM_INFO_INTERLEAVED |
-		SNDRV_PCM_INFO_MMAP_VALID,
-	.formats = SNDRV_PCM_FMTBIT_S16_LE |
-		   SNDRV_PCM_FMTBIT_S24_LE |
-		   SNDRV_PCM_FMTBIT_S32_LE,
-	.period_bytes_min = 256,
-	.period_bytes_max = 4 * 48 * 1024,
-	.periods_min = 2,
-	.periods_max = 256,
-	.buffer_bytes_max = 8 * 48 * 1024,
-	.fifo_size = 0,
-};
-
-static int mt79xx_memif_fs(struct snd_pcm_substream *substream,
-			   unsigned int rate)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_component *component =
-		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
-	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
-
-	return mt79xx_afe_rate_transform(afe->dev, rate);
-}
-
-static int mt79xx_irq_fs(struct snd_pcm_substream *substream,
-			 unsigned int rate)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_component *component =
-		snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
-	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
-
-	return mt79xx_afe_rate_transform(afe->dev, rate);
-}
-
-#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
-		       SNDRV_PCM_RATE_88200 |\
-		       SNDRV_PCM_RATE_96000 |\
-		       SNDRV_PCM_RATE_176400 |\
-		       SNDRV_PCM_RATE_192000)
-
-#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-			 SNDRV_PCM_FMTBIT_S24_LE |\
-			 SNDRV_PCM_FMTBIT_S32_LE)
-
-static struct snd_soc_dai_driver mt79xx_memif_dai_driver[] = {
-	/* FE DAIs: memory intefaces to CPU */
-	{
-		.name = "DL1",
-		.id = MT79XX_MEMIF_DL1,
-		.playback = {
-			.stream_name = "DL1",
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = MTK_PCM_RATES,
-			.formats = MTK_PCM_FORMATS,
-		},
-		.ops = &mtk_afe_fe_ops,
-	},
-	{
-		.name = "UL1",
-		.id = MT79XX_MEMIF_VUL12,
-		.capture = {
-			.stream_name = "UL1",
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = MTK_PCM_RATES,
-			.formats = MTK_PCM_FORMATS,
-		},
-		.ops = &mtk_afe_fe_ops,
-	},
-};
-
-static const struct snd_kcontrol_new o018_mix[] = {
-	SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0),
-};
-
-static const struct snd_kcontrol_new o019_mix[] = {
-	SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0),
-};
-
-static const struct snd_soc_dapm_widget mt79xx_memif_widgets[] = {
-	/* DL */
-	SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0),
-
-	/* UL */
-	SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0,
-			   o018_mix, ARRAY_SIZE(o018_mix)),
-	SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0,
-			   o019_mix, ARRAY_SIZE(o019_mix)),
-};
-
-static const struct snd_soc_dapm_route mt79xx_memif_routes[] = {
-	{"I032", NULL, "DL1"},
-	{"I033", NULL, "DL1"},
-	{"UL1", NULL, "O018"},
-	{"UL1", NULL, "O019"},
-	{"O018", "I150_Switch", "I150"},
-	{"O019", "I151_Switch", "I151"},
-};
-
-static const struct snd_soc_component_driver mt79xx_afe_pcm_dai_component = {
-	.name = "mt79xx-afe-pcm-dai",
-};
-
-static const struct mtk_base_memif_data memif_data[MT79XX_MEMIF_NUM] = {
-	[MT79XX_MEMIF_DL1] = {
-		.name = "DL1",
-		.id = MT79XX_MEMIF_DL1,
-		.reg_ofs_base = AFE_DL0_BASE,
-		.reg_ofs_cur = AFE_DL0_CUR,
-		.reg_ofs_end = AFE_DL0_END,
-		.reg_ofs_base_msb = AFE_DL0_BASE_MSB,
-		.reg_ofs_cur_msb = AFE_DL0_CUR_MSB,
-		.reg_ofs_end_msb = AFE_DL0_END_MSB,
-		.fs_reg = AFE_DL0_CON0,
-		.fs_shift =  DL0_MODE_SFT,
-		.fs_maskbit =  DL0_MODE_MASK,
-		.mono_reg = AFE_DL0_CON0,
-		.mono_shift = DL0_MONO_SFT,
-		.enable_reg = AFE_DL0_CON0,
-		.enable_shift = DL0_ON_SFT,
-		.hd_reg = AFE_DL0_CON0,
-		.hd_shift = DL0_HD_MODE_SFT,
-		.hd_align_reg = AFE_DL0_CON0,
-		.hd_align_mshift = DL0_HALIGN_SFT,
-		.pbuf_reg = AFE_DL0_CON0,
-		.pbuf_shift = DL0_PBUF_SIZE_SFT,
-		.minlen_reg = AFE_DL0_CON0,
-		.minlen_shift = DL0_MINLEN_SFT,
-	},
-	[MT79XX_MEMIF_VUL12] = {
-		.name = "VUL12",
-		.id = MT79XX_MEMIF_VUL12,
-		.reg_ofs_base = AFE_VUL0_BASE,
-		.reg_ofs_cur = AFE_VUL0_CUR,
-		.reg_ofs_end = AFE_VUL0_END,
-		.reg_ofs_base_msb = AFE_VUL0_BASE_MSB,
-		.reg_ofs_cur_msb = AFE_VUL0_CUR_MSB,
-		.reg_ofs_end_msb = AFE_VUL0_END_MSB,
-		.fs_reg = AFE_VUL0_CON0,
-		.fs_shift = VUL0_MODE_SFT,
-		.fs_maskbit = VUL0_MODE_MASK,
-		.mono_reg = AFE_VUL0_CON0,
-		.mono_shift = VUL0_MONO_SFT,
-		.enable_reg = AFE_VUL0_CON0,
-		.enable_shift = VUL0_ON_SFT,
-		.hd_reg = AFE_VUL0_CON0,
-		.hd_shift = VUL0_HD_MODE_SFT,
-		.hd_align_reg = AFE_VUL0_CON0,
-		.hd_align_mshift = VUL0_HALIGN_SFT,
-	},
-};
-
-static const struct mtk_base_irq_data irq_data[MT79XX_IRQ_NUM] = {
-	[MT79XX_IRQ_0] = {
-		.id = MT79XX_IRQ_0,
-		.irq_cnt_reg = AFE_IRQ0_MCU_CFG1,
-		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
-		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
-		.irq_fs_reg = AFE_IRQ0_MCU_CFG0,
-		.irq_fs_shift = IRQ_MCU_MODE_SFT,
-		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
-		.irq_en_reg = AFE_IRQ0_MCU_CFG0,
-		.irq_en_shift = IRQ_MCU_ON_SFT,
-		.irq_clr_reg = AFE_IRQ_MCU_CLR,
-		.irq_clr_shift = IRQ0_MCU_CLR_SFT,
-	},
-	[MT79XX_IRQ_1] = {
-		.id = MT79XX_IRQ_1,
-		.irq_cnt_reg = AFE_IRQ1_MCU_CFG1,
-		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
-		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
-		.irq_fs_reg = AFE_IRQ1_MCU_CFG0,
-		.irq_fs_shift = IRQ_MCU_MODE_SFT,
-		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
-		.irq_en_reg = AFE_IRQ1_MCU_CFG0,
-		.irq_en_shift = IRQ_MCU_ON_SFT,
-		.irq_clr_reg = AFE_IRQ_MCU_CLR,
-		.irq_clr_shift = IRQ1_MCU_CLR_SFT,
-	},
-	[MT79XX_IRQ_2] = {
-		.id = MT79XX_IRQ_2,
-		.irq_cnt_reg = AFE_IRQ2_MCU_CFG1,
-		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
-		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
-		.irq_fs_reg = AFE_IRQ2_MCU_CFG0,
-		.irq_fs_shift = IRQ_MCU_MODE_SFT,
-		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
-		.irq_en_reg = AFE_IRQ2_MCU_CFG0,
-		.irq_en_shift = IRQ_MCU_ON_SFT,
-		.irq_clr_reg = AFE_IRQ_MCU_CLR,
-		.irq_clr_shift = IRQ2_MCU_CLR_SFT,
-	},
-};
-
-static bool mt79xx_is_volatile_reg(struct device *dev, unsigned int reg)
-{
-	/* these auto-gen reg has read-only bit, so put it as volatile */
-	/* volatile reg cannot be cached, so cannot be set when power off */
-	switch (reg) {
-	case AFE_DL0_CUR_MSB:
-	case AFE_DL0_CUR:
-	case AFE_DL0_RCH_MON:
-	case AFE_DL0_LCH_MON:
-	case AFE_VUL0_CUR_MSB:
-	case AFE_VUL0_CUR:
-	case AFE_IRQ_MCU_STATUS:
-	case AFE_MEMIF_RD_MON:
-	case AFE_MEMIF_WR_MON:
-		return true;
-	default:
-		return false;
-	};
-}
-
-static const struct regmap_config mt79xx_afe_regmap_config = {
-	.reg_bits = 32,
-	.reg_stride = 4,
-	.val_bits = 32,
-	.volatile_reg = mt79xx_is_volatile_reg,
-	.max_register = AFE_MAX_REGISTER,
-	.num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1),
-};
-
-static irqreturn_t mt79xx_afe_irq_handler(int irq_id, void *dev)
-{
-	struct mtk_base_afe *afe = dev;
-	struct mtk_base_afe_irq *irq;
-	unsigned int status;
-	unsigned int status_mcu;
-	unsigned int mcu_en;
-	int ret;
-	int i;
-	irqreturn_t irq_ret = IRQ_HANDLED;
-
-	/* get irq that is sent to MCU */
-	regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
-
-	ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
-	/* only care IRQ which is sent to MCU */
-	status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
-
-	if (ret || status_mcu == 0) {
-		dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x,\
-			mcu_en 0x%x\n", __func__, ret, status, mcu_en);
-
-		irq_ret = IRQ_NONE;
-		goto err_irq;
-	}
-
-	for (i = 0; i < MT79XX_MEMIF_NUM; i++) {
-		struct mtk_base_afe_memif *memif = &afe->memif[i];
-
-		if (!memif->substream)
-			continue;
-
-		if (memif->irq_usage < 0)
-			continue;
-
-		irq = &afe->irqs[memif->irq_usage];
-
-		if (status_mcu & (1 << irq->irq_data->irq_en_shift))
-			snd_pcm_period_elapsed(memif->substream);
-	}
-
-err_irq:
-	/* clear irq */
-	regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu);
-
-	return irq_ret;
-}
-
-static int mt79xx_afe_runtime_suspend(struct device *dev)
-{
-	struct mtk_base_afe *afe = dev_get_drvdata(dev);
-	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
-
-	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
-		goto skip_regmap;
-
-	/* disable clk*/
-	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff);
-	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
-			   0);
-	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
-			   0);
-
-	/* make sure all irq status are cleared, twice intended */
-	regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
-
-skip_regmap:
-	return mt79xx_afe_disable_clock(afe);
-}
-
-static int mt79xx_afe_runtime_resume(struct device *dev)
-{
-	struct mtk_base_afe *afe = dev_get_drvdata(dev);
-	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
-	int ret;
-
-	ret = mt79xx_afe_enable_clock(afe);
-	if (ret)
-		return ret;
-
-	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
-		goto skip_regmap;
-
-	/* enable clk*/
-	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
-	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
-			   AUD_APLL2_EN);
-	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
-			   AUD_26M_EN);
-
-skip_regmap:
-	return 0;
-}
-
-static int mt79xx_afe_component_probe(struct snd_soc_component *component)
-{
-	return mtk_afe_add_sub_dai_control(component);
-}
-
-static const struct snd_soc_component_driver mt79xx_afe_component = {
-	.name = AFE_PCM_NAME,
-	.ops = &mtk_afe_pcm_ops,
-	.pcm_new = mtk_afe_pcm_new,
-	.pcm_free = mtk_afe_pcm_free,
-	.probe = mt79xx_afe_component_probe,
-};
-
-static int mt79xx_dai_memif_register(struct mtk_base_afe *afe)
-{
-	struct mtk_base_afe_dai *dai;
-
-	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
-	if (!dai)
-		return -ENOMEM;
-
-	list_add(&dai->list, &afe->sub_dais);
-
-	dai->dai_drivers = mt79xx_memif_dai_driver;
-	dai->num_dai_drivers = ARRAY_SIZE(mt79xx_memif_dai_driver);
-
-	dai->dapm_widgets = mt79xx_memif_widgets;
-	dai->num_dapm_widgets = ARRAY_SIZE(mt79xx_memif_widgets);
-	dai->dapm_routes = mt79xx_memif_routes;
-	dai->num_dapm_routes = ARRAY_SIZE(mt79xx_memif_routes);
-
-	return 0;
-}
-
-typedef int (*dai_register_cb)(struct mtk_base_afe *);
-static const dai_register_cb dai_register_cbs[] = {
-	mt79xx_dai_etdm_register,
-	mt79xx_dai_memif_register,
-};
-
-static int mt79xx_afe_pcm_dev_probe(struct platform_device *pdev)
-{
-	struct mtk_base_afe *afe;
-	struct mt79xx_afe_private *afe_priv;
-	struct device *dev;
-	int i, irq_id, ret;
-
-	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
-	if (!afe)
-		return -ENOMEM;
-	platform_set_drvdata(pdev, afe);
-
-	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
-					  GFP_KERNEL);
-	if (!afe->platform_priv)
-		return -ENOMEM;
-
-	afe_priv = afe->platform_priv;
-	afe->dev = &pdev->dev;
-	dev = afe->dev;
-
-	afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(afe->base_addr))
-		return PTR_ERR(afe->base_addr);
-
-	/* initial audio related clock */
-	ret = mt79xx_init_clock(afe);
-	if (ret) {
-		dev_err(dev, "init clock error\n");
-		return ret;
-	}
-
-	pm_runtime_enable(dev);
-
-	/* enable clock for regcache get default value from hw */
-	afe_priv->pm_runtime_bypass_reg_ctl = true;
-	pm_runtime_get_sync(&pdev->dev);
-
-	afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
-		      &mt79xx_afe_regmap_config);
-	if (IS_ERR(afe->regmap)) {
-		ret = PTR_ERR(afe->regmap);
-		goto err_pm_disable;
-	}
-
-	pm_runtime_put_sync(&pdev->dev);
-	afe_priv->pm_runtime_bypass_reg_ctl = false;
-
-	/* init memif */
-	afe->memif_size = MT79XX_MEMIF_NUM;
-	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
-				  GFP_KERNEL);
-	if (!afe->memif)
-		goto err_pm_disable;
-
-	for (i = 0; i < afe->memif_size; i++) {
-		afe->memif[i].data = &memif_data[i];
-		afe->memif[i].irq_usage = -1;
-	}
-
-	mutex_init(&afe->irq_alloc_lock);
-
-	/* irq initialize */
-	afe->irqs_size = MT79XX_IRQ_NUM;
-	afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
-				 GFP_KERNEL);
-	if (!afe->irqs)
-		goto err_pm_disable;
-
-	for (i = 0; i < afe->irqs_size; i++)
-		afe->irqs[i].irq_data = &irq_data[i];
-
-	/* request irq */
-	irq_id = platform_get_irq(pdev, 0);
-	if (!irq_id) {
-		dev_err(dev, "%pOFn no irq found\n", dev->of_node);
-		goto err_pm_disable;
-	}
-	ret = devm_request_irq(dev, irq_id, mt79xx_afe_irq_handler,
-			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
-	if (ret) {
-		dev_err(dev, "could not request_irq for asys-isr\n");
-		goto err_pm_disable;
-	}
-
-	/* init sub_dais */
-	INIT_LIST_HEAD(&afe->sub_dais);
-
-	for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
-		ret = dai_register_cbs[i](afe);
-		if (ret) {
-			dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
-				 i, ret);
-			goto err_pm_disable;
-		}
-	}
-
-	/* init dai_driver and component_driver */
-	ret = mtk_afe_combine_sub_dai(afe);
-	if (ret) {
-		dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
-			 ret);
-		goto err_pm_disable;
-	}
-
-	afe->mtk_afe_hardware = &mt79xx_afe_hardware;
-	afe->memif_fs = mt79xx_memif_fs;
-	afe->irq_fs = mt79xx_irq_fs;
-
-	afe->runtime_resume = mt79xx_afe_runtime_resume;
-	afe->runtime_suspend = mt79xx_afe_runtime_suspend;
-
-	/* register component */
-	ret = devm_snd_soc_register_component(&pdev->dev,
-					      &mt79xx_afe_component,
-					      NULL, 0);
-	if (ret) {
-		dev_warn(dev, "err_platform\n");
-		goto err_pm_disable;
-	}
-
-	ret = devm_snd_soc_register_component(afe->dev,
-					      &mt79xx_afe_pcm_dai_component,
-					      afe->dai_drivers,
-					      afe->num_dai_drivers);
-	if (ret) {
-		dev_warn(dev, "err_dai_component\n");
-		goto err_pm_disable;
-	}
-
-	return ret;
-
-err_pm_disable:
-	pm_runtime_put_sync(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	return ret;
-}
-
-static int mt79xx_afe_pcm_dev_remove(struct platform_device *pdev)
-{
-	pm_runtime_disable(&pdev->dev);
-	if (!pm_runtime_status_suspended(&pdev->dev))
-		mt79xx_afe_runtime_suspend(&pdev->dev);
-
-	return 0;
-}
-
-static const struct of_device_id mt79xx_afe_pcm_dt_match[] = {
-	{ .compatible = "mediatek,mt79xx-audio", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, mt79xx_afe_pcm_dt_match);
-
-static const struct dev_pm_ops mt79xx_afe_pm_ops = {
-	SET_RUNTIME_PM_OPS(mt79xx_afe_runtime_suspend,
-			   mt79xx_afe_runtime_resume, NULL)
-};
-
-static struct platform_driver mt79xx_afe_pcm_driver = {
-	.driver = {
-		   .name = "mt79xx-audio",
-		   .of_match_table = mt79xx_afe_pcm_dt_match,
-		   .pm = &mt79xx_afe_pm_ops,
-	},
-	.probe = mt79xx_afe_pcm_dev_probe,
-	.remove = mt79xx_afe_pcm_dev_remove,
-};
-
-module_platform_driver(mt79xx_afe_pcm_driver);
-
-MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 79xx");
-MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
-MODULE_LICENSE("GPL");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-dai-etdm.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-dai-etdm.c
deleted file mode 100644
index 0048647..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-dai-etdm.c
+++ /dev/null
@@ -1,419 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// MediaTek ALSA SoC Audio DAI eTDM Control
-//
-// Copyright (c) 2021 MediaTek Inc.
-// Author: Vic Wu <vic.wu@mediatek.com>
-
-#include <linux/bitops.h>
-#include <linux/regmap.h>
-#include <sound/pcm_params.h>
-#include "mt79xx-afe-clk.h"
-#include "mt79xx-afe-common.h"
-#include "mt79xx-reg.h"
-
-enum {
-	HOPPING_CLK = 0,
-	APLL_CLK = 1,
-};
-
-enum {
-	MTK_DAI_ETDM_FORMAT_I2S = 0,
-	MTK_DAI_ETDM_FORMAT_DSPA = 4,
-	MTK_DAI_ETDM_FORMAT_DSPB = 5,
-};
-
-enum {
-	ETDM_IN5 = 2,
-	ETDM_OUT5 = 10,
-};
-
-enum {
-	MTK_ETDM_RATE_8K = 0,
-	MTK_ETDM_RATE_12K = 1,
-	MTK_ETDM_RATE_16K = 2,
-	MTK_ETDM_RATE_24K = 3,
-	MTK_ETDM_RATE_32K = 4,
-	MTK_ETDM_RATE_48K = 5,
-	MTK_ETDM_RATE_96K = 7,
-	MTK_ETDM_RATE_192K = 9,
-	MTK_ETDM_RATE_11K = 16,
-	MTK_ETDM_RATE_22K = 17,
-	MTK_ETDM_RATE_44K = 18,
-	MTK_ETDM_RATE_88K = 19,
-	MTK_ETDM_RATE_176K = 20,
-};
-
-struct mtk_dai_etdm_priv {
-	bool bck_inv;
-	bool lrck_inv;
-	bool slave_mode;
-	unsigned int format;
-};
-
-static unsigned int mt79xx_etdm_rate_transform(struct device *dev,
-					unsigned int rate)
-{
-	switch (rate) {
-	case 8000:
-		return MTK_ETDM_RATE_8K;
-	case 11025:
-		return MTK_ETDM_RATE_11K;
-	case 12000:
-		return MTK_ETDM_RATE_12K;
-	case 16000:
-		return MTK_ETDM_RATE_16K;
-	case 22050:
-		return MTK_ETDM_RATE_22K;
-	case 24000:
-		return MTK_ETDM_RATE_24K;
-	case 32000:
-		return MTK_ETDM_RATE_32K;
-	case 44100:
-		return MTK_ETDM_RATE_44K;
-	case 48000:
-		return MTK_ETDM_RATE_48K;
-	case 88200:
-		return MTK_ETDM_RATE_88K;
-	case 96000:
-		return MTK_ETDM_RATE_96K;
-	case 176400:
-		return MTK_ETDM_RATE_176K;
-	case 192000:
-		return MTK_ETDM_RATE_192K;
-	default:
-		dev_warn(dev, "%s(), rate %u invalid, use %d!!!\n",
-			 __func__, rate, MTK_ETDM_RATE_48K);
-		return MTK_ETDM_RATE_48K;
-	}
-}
-
-static int get_etdm_wlen(unsigned int bitwidth)
-{
-	return bitwidth <= 16 ? 16 : 32;
-}
-
-/* dai component */
-/* interconnection */
-
-static const struct snd_kcontrol_new o124_mix[] = {
-	SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0),
-};
-
-static const struct snd_kcontrol_new o125_mix[] = {
-	SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0),
-};
-
-static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
-
-	/* DL */
-	SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0),
-	SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0),
-	/* UL */
-	SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0,
-			   o124_mix, ARRAY_SIZE(o124_mix)),
-	SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0,
-			   o125_mix, ARRAY_SIZE(o125_mix)),
-};
-
-static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
-	{"I150", NULL, "ETDM Capture"},
-	{"I151", NULL, "ETDM Capture"},
-	{"ETDM Playback", NULL, "O124"},
-	{"ETDM Playback", NULL, "O125"},
-	{"O124", "I032_Switch", "I032"},
-	{"O125", "I033_Switch", "I033"},
-};
-
-/* dai ops */
-static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
-				struct snd_soc_dai *dai)
-{
-	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
-
-	mt79xx_afe_enable_clock(afe);
-
-	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
-			   0);
-	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
-			   0);
-
-	return 0;
-}
-
-static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
-				  struct snd_soc_dai *dai)
-{
-	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
-
-	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
-			   CLK_OUT5_PDN);
-	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
-			   CLK_IN5_PDN);
-
-	mt79xx_afe_disable_clock(afe);
-}
-
-static unsigned int get_etdm_ch_fixup(unsigned int channels)
-{
-	if (channels > 16)
-		return 24;
-	else if (channels > 8)
-		return 16;
-	else if (channels > 4)
-		return 8;
-	else if (channels > 2)
-		return 4;
-	else
-		return 2;
-}
-
-static int mtk_dai_etdm_config(struct mtk_base_afe *afe,
-			       struct snd_pcm_hw_params *params,
-			       struct snd_soc_dai *dai,
-			       int stream)
-{
-	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
-	struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];
-	unsigned int rate = params_rate(params);
-	unsigned int etdm_rate = mt79xx_etdm_rate_transform(afe->dev, rate);
-	unsigned int afe_rate = mt79xx_afe_rate_transform(afe->dev, rate);
-	unsigned int channels = params_channels(params);
-	unsigned int bit_width = params_width(params);
-	unsigned int wlen = get_etdm_wlen(bit_width);
-	unsigned int val = 0;
-	unsigned int mask = 0;
-
-	dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",
-		 __func__, stream, rate, bit_width);
-
-	/* CON0 */
-	mask |= ETDM_BIT_LEN_MASK;
-	val |= ETDM_BIT_LEN(bit_width);
-	mask |= ETDM_WRD_LEN_MASK;
-	val |= ETDM_WRD_LEN(wlen);
-	mask |= ETDM_FMT_MASK;
-	val |= ETDM_FMT(etdm_data->format);
-	mask |= ETDM_CH_NUM_MASK;
-	val |= ETDM_CH_NUM(get_etdm_ch_fixup(channels));
-	mask |= RELATCH_SRC_MASK;
-	val |= RELATCH_SRC(APLL_CLK);
-
-	switch (stream) {
-	case SNDRV_PCM_STREAM_PLAYBACK:
-		/* set ETDM_OUT5_CON0 */
-		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val);
-
-		/* set ETDM_OUT5_CON4 */
-		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
-				   OUT_RELATCH_MASK, OUT_RELATCH(afe_rate));
-		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
-				   OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK));
-		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
-				   OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate));
-
-		/* set ETDM_OUT5_CON5 */
-		regmap_update_bits(afe->regmap, ETDM_OUT5_CON5,
-				   ETDM_CLK_DIV_MASK, ETDM_CLK_DIV);
-		break;
-	case SNDRV_PCM_STREAM_CAPTURE:
-		/* set ETDM_IN5_CON0 */
-		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val);
-		regmap_update_bits(afe->regmap, ETDM_IN5_CON0,
-				   ETDM_SYNC_MASK, ETDM_SYNC);
-
-		/* set ETDM_IN5_CON2 */
-		regmap_update_bits(afe->regmap, ETDM_IN5_CON2,
-				   IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK));
-
-		/* set ETDM_IN5_CON3 */
-		regmap_update_bits(afe->regmap, ETDM_IN5_CON3,
-				   IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate));
-
-		/* set ETDM_IN5_CON4 */
-		regmap_update_bits(afe->regmap, ETDM_IN5_CON4,
-				   IN_RELATCH_MASK, IN_RELATCH(afe_rate));
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
-				  struct snd_pcm_hw_params *params,
-				  struct snd_soc_dai *dai)
-{
-	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
-
-	mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
-	mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
-
-	return 0;
-}
-
-static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,
-				struct snd_soc_dai *dai)
-{
-	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
-
-	dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id);
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
-				   ETDM_EN);
-		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
-				   ETDM_EN);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
-				   0);
-		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
-				   0);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
-{
-	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
-	struct mt79xx_afe_private *afe_priv = afe->platform_priv;
-	struct mtk_dai_etdm_priv *etdm_data;
-	void *priv_data;
-
-	switch (dai->id) {
-	case MT79XX_DAI_ETDM:
-		break;
-	default:
-		dev_warn(afe->dev, "%s(), id %d not support\n",
-			 __func__, dai->id);
-		return -EINVAL;
-	}
-
-	priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),
-				 GFP_KERNEL);
-	if (!priv_data)
-		return -ENOMEM;
-
-	afe_priv->dai_priv[dai->id] = priv_data;
-	etdm_data = afe_priv->dai_priv[dai->id];
-
-	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-	case SND_SOC_DAIFMT_I2S:
-		etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
-		break;
-	case SND_SOC_DAIFMT_DSP_A:
-		etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
-		break;
-	case SND_SOC_DAIFMT_DSP_B:
-		etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF:
-		etdm_data->bck_inv = false;
-		etdm_data->lrck_inv = false;
-		break;
-	case SND_SOC_DAIFMT_NB_IF:
-		etdm_data->bck_inv = false;
-		etdm_data->lrck_inv = true;
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		etdm_data->bck_inv = true;
-		etdm_data->lrck_inv = false;
-		break;
-	case SND_SOC_DAIFMT_IB_IF:
-		etdm_data->bck_inv = true;
-		etdm_data->lrck_inv = true;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBM_CFM:
-		etdm_data->slave_mode = true;
-		break;
-	case SND_SOC_DAIFMT_CBS_CFS:
-		etdm_data->slave_mode = false;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
-	.startup = mtk_dai_etdm_startup,
-	.shutdown = mtk_dai_etdm_shutdown,
-	.hw_params = mtk_dai_etdm_hw_params,
-	.trigger = mtk_dai_etdm_trigger,
-	.set_fmt = mtk_dai_etdm_set_fmt,
-};
-
-/* dai driver */
-#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
-			SNDRV_PCM_RATE_88200 |\
-			SNDRV_PCM_RATE_96000 |\
-			SNDRV_PCM_RATE_176400 |\
-			SNDRV_PCM_RATE_192000)
-
-#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-			  SNDRV_PCM_FMTBIT_S24_LE |\
-			  SNDRV_PCM_FMTBIT_S32_LE)
-
-static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
-	{
-		.name = "ETDM",
-		.id = MT79XX_DAI_ETDM,
-		.capture = {
-			.stream_name = "ETDM Capture",
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = MTK_ETDM_RATES,
-			.formats = MTK_ETDM_FORMATS,
-		},
-		.playback = {
-			.stream_name = "ETDM Playback",
-			.channels_min = 1,
-			.channels_max = 2,
-			.rates = MTK_ETDM_RATES,
-			.formats = MTK_ETDM_FORMATS,
-		},
-		.ops = &mtk_dai_etdm_ops,
-		.symmetric_rates = 1,
-		.symmetric_samplebits = 1,
-	},
-};
-
-int mt79xx_dai_etdm_register(struct mtk_base_afe *afe)
-{
-	struct mtk_base_afe_dai *dai;
-
-	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
-	if (!dai)
-		return -ENOMEM;
-
-	list_add(&dai->list, &afe->sub_dais);
-
-	dai->dai_drivers = mtk_dai_etdm_driver;
-	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
-
-	dai->dapm_widgets = mtk_dai_etdm_widgets;
-	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
-	dai->dapm_routes = mtk_dai_etdm_routes;
-	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
-
-	return 0;
-}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-reg.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-reg.h
deleted file mode 100644
index b8d2d56..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-reg.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * mt79xx-reg.h  --  Mediatek 79xx audio driver reg definition
- *
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Vic Wu <vic.wu@mediatek.com>
- */
-
-#ifndef _MT79XX_REG_H_
-#define _MT79XX_REG_H_
-
-#define AUDIO_TOP_CON2                  0x0008
-#define AUDIO_TOP_CON4                  0x0010
-#define AUDIO_ENGEN_CON0                0x0014
-#define AFE_IRQ_MCU_EN                  0x0100
-#define AFE_IRQ_MCU_STATUS              0x0120
-#define AFE_IRQ_MCU_CLR                 0x0128
-#define AFE_IRQ0_MCU_CFG0               0x0140
-#define AFE_IRQ0_MCU_CFG1               0x0144
-#define AFE_IRQ1_MCU_CFG0               0x0148
-#define AFE_IRQ1_MCU_CFG1               0x014c
-#define AFE_IRQ2_MCU_CFG0               0x0150
-#define AFE_IRQ2_MCU_CFG1               0x0154
-#define ETDM_IN5_CON0                   0x13f0
-#define ETDM_IN5_CON1                   0x13f4
-#define ETDM_IN5_CON2                   0x13f8
-#define ETDM_IN5_CON3                   0x13fc
-#define ETDM_IN5_CON4                   0x1400
-#define ETDM_OUT5_CON0                  0x1570
-#define ETDM_OUT5_CON4                  0x1580
-#define ETDM_OUT5_CON5                  0x1584
-#define ETDM_4_7_COWORK_CON0            0x15e0
-#define ETDM_4_7_COWORK_CON1            0x15e4
-#define AFE_CONN018_1                   0x1b44
-#define AFE_CONN018_4                   0x1b50
-#define AFE_CONN019_1                   0x1b64
-#define AFE_CONN019_4                   0x1b70
-#define AFE_CONN124_1                   0x2884
-#define AFE_CONN124_4                   0x2890
-#define AFE_CONN125_1                   0x28a4
-#define AFE_CONN125_4                   0x28b0
-#define AFE_CONN_RS_0                   0x3920
-#define AFE_CONN_RS_3                   0x392c
-#define AFE_CONN_16BIT_0                0x3960
-#define AFE_CONN_16BIT_3                0x396c
-#define AFE_CONN_24BIT_0                0x3980
-#define AFE_CONN_24BIT_3                0x398c
-#define AFE_MEMIF_CON0                  0x3d98
-#define AFE_MEMIF_RD_MON                0x3da0
-#define AFE_MEMIF_WR_MON                0x3da4
-#define AFE_DL0_BASE_MSB                0x3e40
-#define AFE_DL0_BASE                    0x3e44
-#define AFE_DL0_CUR_MSB                 0x3e48
-#define AFE_DL0_CUR                     0x3e4c
-#define AFE_DL0_END_MSB                 0x3e50
-#define AFE_DL0_END                     0x3e54
-#define AFE_DL0_RCH_MON                 0x3e58
-#define AFE_DL0_LCH_MON                 0x3e5c
-#define AFE_DL0_CON0                    0x3e60
-#define AFE_VUL0_BASE_MSB               0x4220
-#define AFE_VUL0_BASE                   0x4224
-#define AFE_VUL0_CUR_MSB                0x4228
-#define AFE_VUL0_CUR                    0x422c
-#define AFE_VUL0_END_MSB                0x4230
-#define AFE_VUL0_END                    0x4234
-#define AFE_VUL0_CON0                   0x4238
-
-#define AFE_MAX_REGISTER AFE_VUL0_CON0
-#define AFE_IRQ_STATUS_BITS             0x7
-#define AFE_IRQ_CNT_SHIFT               0
-#define AFE_IRQ_CNT_MASK	        0xffffff
-
-/* AUDIO_TOP_CON2 */
-#define CLK_OUT5_PDN                    BIT(14)
-#define CLK_OUT5_PDN_MASK               BIT(14)
-#define CLK_IN5_PDN                     BIT(7)
-#define CLK_IN5_PDN_MASK                BIT(7)
-
-/* AUDIO_TOP_CON4 */
-#define PDN_APLL_TUNER2                 BIT(12)
-#define PDN_APLL_TUNER2_MASK            BIT(12)
-
-/* AUDIO_ENGEN_CON0 */
-#define AUD_APLL2_EN                    BIT(3)
-#define AUD_APLL2_EN_MASK               BIT(3)
-#define AUD_26M_EN                      BIT(0)
-#define AUD_26M_EN_MASK                 BIT(0)
-
-/* AFE_DL0_CON0 */
-#define DL0_ON_SFT                      28
-#define DL0_ON_MASK                     0x1
-#define DL0_ON_MASK_SFT                 BIT(28)
-#define DL0_MINLEN_SFT                  20
-#define DL0_MINLEN_MASK                 0xf
-#define DL0_MINLEN_MASK_SFT             (0xf << 20)
-#define DL0_MODE_SFT                    8
-#define DL0_MODE_MASK                   0x1f
-#define DL0_MODE_MASK_SFT               (0x1f << 8)
-#define DL0_PBUF_SIZE_SFT               5
-#define DL0_PBUF_SIZE_MASK              0x3
-#define DL0_PBUF_SIZE_MASK_SFT          (0x3 << 5)
-#define DL0_MONO_SFT                    4
-#define DL0_MONO_MASK                   0x1
-#define DL0_MONO_MASK_SFT               BIT(4)
-#define DL0_HALIGN_SFT                  2
-#define DL0_HALIGN_MASK                 0x1
-#define DL0_HALIGN_MASK_SFT             BIT(2)
-#define DL0_HD_MODE_SFT                 0
-#define DL0_HD_MODE_MASK                0x3
-#define DL0_HD_MODE_MASK_SFT            (0x3 << 0)
-
-/* AFE_VUL0_CON0 */
-#define VUL0_ON_SFT                     28
-#define VUL0_ON_MASK                    0x1
-#define VUL0_ON_MASK_SFT                BIT(28)
-#define VUL0_MODE_SFT                   8
-#define VUL0_MODE_MASK                  0x1f
-#define VUL0_MODE_MASK_SFT              (0x1f << 8)
-#define VUL0_MONO_SFT                   4
-#define VUL0_MONO_MASK                  0x1
-#define VUL0_MONO_MASK_SFT              BIT(4)
-#define VUL0_HALIGN_SFT                 2
-#define VUL0_HALIGN_MASK                0x1
-#define VUL0_HALIGN_MASK_SFT            BIT(2)
-#define VUL0_HD_MODE_SFT                0
-#define VUL0_HD_MODE_MASK               0x3
-#define VUL0_HD_MODE_MASK_SFT           (0x3 << 0)
-
-/* AFE_IRQ_MCU_CON */
-#define IRQ_MCU_MODE_SFT                4
-#define IRQ_MCU_MODE_MASK               0x1f
-#define IRQ_MCU_MODE_MASK_SFT           (0x1f << 4)
-#define IRQ_MCU_ON_SFT                  0
-#define IRQ_MCU_ON_MASK                 0x1
-#define IRQ_MCU_ON_MASK_SFT             BIT(0)
-#define IRQ0_MCU_CLR_SFT                0
-#define IRQ0_MCU_CLR_MASK               0x1
-#define IRQ0_MCU_CLR_MASK_SFT           BIT(0)
-#define IRQ1_MCU_CLR_SFT                1
-#define IRQ1_MCU_CLR_MASK               0x1
-#define IRQ1_MCU_CLR_MASK_SFT           BIT(1)
-#define IRQ2_MCU_CLR_SFT                2
-#define IRQ2_MCU_CLR_MASK               0x1
-#define IRQ2_MCU_CLR_MASK_SFT           BIT(2)
-
-/* ETDM_IN5_CON2 */
-#define IN_CLK_SRC(x)                   ((x) << 10)
-#define IN_CLK_SRC_SFT                  10
-#define IN_CLK_SRC_MASK                 GENMASK(12, 10)
-
-/* ETDM_IN5_CON3 */
-#define IN_SEL_FS(x)                    ((x) << 26)
-#define IN_SEL_FS_SFT                   26
-#define IN_SEL_FS_MASK                  GENMASK(30, 26)
-
-/* ETDM_IN5_CON4 */
-#define IN_RELATCH(x)                   ((x) << 20)
-#define IN_RELATCH_SFT                  20
-#define IN_RELATCH_MASK                 GENMASK(24, 20)
-#define IN_CLK_INV                      BIT(18)
-#define IN_CLK_INV_MASK                 BIT(18)
-
-/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */
-#define RELATCH_SRC(x)                  ((x) << 28)
-#define RELATCH_SRC_SFT                 28
-#define RELATCH_SRC_MASK                GENMASK(30, 28)
-#define ETDM_CH_NUM(x)                  (((x) - 1) << 23)
-#define ETDM_CH_NUM_SFT                 23
-#define ETDM_CH_NUM_MASK                GENMASK(27, 23)
-#define ETDM_WRD_LEN(x)                 (((x) - 1) << 16)
-#define ETDM_WRD_LEN_SFT                16
-#define ETDM_WRD_LEN_MASK               GENMASK(20, 16)
-#define ETDM_BIT_LEN(x)                 (((x) - 1) << 11)
-#define ETDM_BIT_LEN_SFT                11
-#define ETDM_BIT_LEN_MASK               GENMASK(15, 11)
-#define ETDM_FMT(x)                     ((x) << 6)
-#define ETDM_FMT_SFT                    6
-#define ETDM_FMT_MASK                   GENMASK(8, 6)
-#define ETDM_SYNC                       BIT(1)
-#define ETDM_SYNC_MASK                  BIT(1)
-#define ETDM_EN                         BIT(0)
-#define ETDM_EN_MASK                    BIT(0)
-
-/* ETDM_OUT5_CON4 */
-#define OUT_RELATCH(x)                  ((x) << 24)
-#define OUT_RELATCH_SFT                 24
-#define OUT_RELATCH_MASK                GENMASK(28, 24)
-#define OUT_CLK_SRC(x)                  ((x) << 6)
-#define OUT_CLK_SRC_SFT                 6
-#define OUT_CLK_SRC_MASK                GENMASK(8, 6)
-#define OUT_SEL_FS(x)                   ((x) << 0)
-#define OUT_SEL_FS_SFT                  0
-#define OUT_SEL_FS_MASK                 GENMASK(4, 0)
-
-/* ETDM_OUT5_CON5 */
-#define ETDM_CLK_DIV                    BIT(12)
-#define ETDM_CLK_DIV_MASK               BIT(12)
-#define OUT_CLK_INV                     BIT(9)
-#define OUT_CLK_INV_MASK                BIT(9)
-
-/* ETDM_4_7_COWORK_CON0 */
-#define OUT_SEL(x)                      ((x) << 12)
-#define OUT_SEL_SFT                     12
-#define OUT_SEL_MASK                    GENMASK(15, 12)
-#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-wm8960.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-wm8960.c
deleted file mode 100644
index c66a117..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/sound/soc/mediatek/mt79xx/mt79xx-wm8960.c
+++ /dev/null
@@ -1,184 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * mt79xx-wm8960.c  --  MT79xx WM8960 ALSA SoC machine driver
- *
- * Copyright (c) 2021 MediaTek Inc.
- * Author: Vic Wu <vic.wu@mediatek.com>
- */
-
-#include <linux/module.h>
-#include <sound/soc.h>
-
-#include "mt79xx-afe-common.h"
-
-struct mt79xx_wm8960_priv {
-	struct device_node *platform_node;
-	struct device_node *codec_node;
-};
-
-static const struct snd_soc_dapm_widget mt79xx_wm8960_widgets[] = {
-	SND_SOC_DAPM_HP("Headphone", NULL),
-	SND_SOC_DAPM_MIC("AMIC", NULL),
-};
-
-static const struct snd_kcontrol_new mt79xx_wm8960_controls[] = {
-	SOC_DAPM_PIN_SWITCH("Headphone"),
-	SOC_DAPM_PIN_SWITCH("AMIC"),
-};
-
-SND_SOC_DAILINK_DEFS(playback,
-	DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
-	DAILINK_COMP_ARRAY(COMP_DUMMY()),
-	DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(capture,
-	DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
-	DAILINK_COMP_ARRAY(COMP_DUMMY()),
-	DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-SND_SOC_DAILINK_DEFS(codec,
-	DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
-	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
-	DAILINK_COMP_ARRAY(COMP_EMPTY()));
-
-static struct snd_soc_dai_link mt79xx_wm8960_dai_links[] = {
-	/* FE */
-	{
-		.name = "wm8960-playback",
-		.stream_name = "wm8960-playback",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.dynamic = 1,
-		.dpcm_playback = 1,
-		SND_SOC_DAILINK_REG(playback),
-	},
-	{
-		.name = "wm8960-capture",
-		.stream_name = "wm8960-capture",
-		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
-			    SND_SOC_DPCM_TRIGGER_POST},
-		.dynamic = 1,
-		.dpcm_capture = 1,
-		SND_SOC_DAILINK_REG(capture),
-	},
-	/* BE */
-	{
-		.name = "wm8960-codec",
-		.no_pcm = 1,
-		.dai_fmt = SND_SOC_DAIFMT_I2S |
-			SND_SOC_DAIFMT_NB_NF |
-			SND_SOC_DAIFMT_CBS_CFS |
-			SND_SOC_DAIFMT_GATED,
-		.dpcm_playback = 1,
-		.dpcm_capture = 1,
-		SND_SOC_DAILINK_REG(codec),
-	},
-};
-
-static struct snd_soc_card mt79xx_wm8960_card = {
-	.name = "mt79xx-wm8960",
-	.owner = THIS_MODULE,
-	.dai_link = mt79xx_wm8960_dai_links,
-	.num_links = ARRAY_SIZE(mt79xx_wm8960_dai_links),
-	.controls = mt79xx_wm8960_controls,
-	.num_controls = ARRAY_SIZE(mt79xx_wm8960_controls),
-	.dapm_widgets = mt79xx_wm8960_widgets,
-	.num_dapm_widgets = ARRAY_SIZE(mt79xx_wm8960_widgets),
-};
-
-static int mt79xx_wm8960_machine_probe(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = &mt79xx_wm8960_card;
-	struct snd_soc_dai_link *dai_link;
-	struct mt79xx_wm8960_priv *priv;
-	int ret, i;
-
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->platform_node = of_parse_phandle(pdev->dev.of_node,
-					       "mediatek,platform", 0);
-	if (!priv->platform_node) {
-		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
-		return -EINVAL;
-	}
-
-	for_each_card_prelinks(card, i, dai_link) {
-		if (dai_link->platforms->name)
-			continue;
-		dai_link->platforms->of_node = priv->platform_node;
-	}
-
-	card->dev = &pdev->dev;
-
-	priv->codec_node = of_parse_phandle(pdev->dev.of_node,
-					    "mediatek,audio-codec", 0);
-	if (!priv->codec_node) {
-		dev_err(&pdev->dev,
-			"Property 'audio-codec' missing or invalid\n");
-		of_node_put(priv->platform_node);
-		return -EINVAL;
-	}
-
-	for_each_card_prelinks(card, i, dai_link) {
-		if (dai_link->codecs->name)
-			continue;
-		dai_link->codecs->of_node = priv->codec_node;
-	}
-
-	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
-	if (ret) {
-		dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
-		goto err_of_node_put;
-	}
-
-	ret = devm_snd_soc_register_card(&pdev->dev, card);
-	if (ret) {
-		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
-			__func__, ret);
-		goto err_of_node_put;
-	}
-
-err_of_node_put:
-	of_node_put(priv->codec_node);
-	of_node_put(priv->platform_node);
-	return ret;
-}
-
-static int mt79xx_wm8960_machine_remove(struct platform_device *pdev)
-{
-	struct snd_soc_card *card = platform_get_drvdata(pdev);
-	struct mt79xx_wm8960_priv *priv = snd_soc_card_get_drvdata(card);
-
-	of_node_put(priv->codec_node);
-	of_node_put(priv->platform_node);
-
-	return 0;
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id mt79xx_wm8960_machine_dt_match[] = {
-	{.compatible = "mediatek,mt79xx-wm8960-machine",},
-	{}
-};
-#endif
-
-static struct platform_driver mt79xx_wm8960_machine = {
-	.driver = {
-		.name = "mt79xx-wm8960",
-#ifdef CONFIG_OF
-		.of_match_table = mt79xx_wm8960_machine_dt_match,
-#endif
-	},
-	.probe = mt79xx_wm8960_machine_probe,
-	.remove = mt79xx_wm8960_machine_remove,
-};
-
-module_platform_driver(mt79xx_wm8960_machine);
-
-/* Module information */
-MODULE_DESCRIPTION("MT79xx WM8960 ALSA SoC machine driver");
-MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("mt79xx wm8960 soc card");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
index 528abb1..a31bee9 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3001-mt7622-backport-nf-hw-offload-framework-and-upstream.patch
@@ -17,13 +17,12 @@
  drivers/net/ppp/pppoe.c                       |   24 +
  include/linux/netdevice.h                     |   60 +
  include/linux/ppp_channel.h                   |    3 +
- include/net/dsa.h                             |   10 +
  include/net/flow_offload.h                    |    4 +
  include/net/ip6_route.h                       |    5 +-
  .../net/netfilter/ipv6/nf_conntrack_ipv6.h    |    3 -
- include/net/netfilter/nf_conntrack.h          |   12 +
+ include/net/netfilter/nf_conntrack.h          |   14 +
  include/net/netfilter/nf_conntrack_acct.h     |   11 +
- include/net/netfilter/nf_flow_table.h         |  266 +++-
+ include/net/netfilter/nf_flow_table.h         |  268 +++-
  include/net/netns/conntrack.h                 |    6 +
  .../linux/netfilter/nf_conntrack_common.h     |    9 +-
  include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h |   17 +
@@ -32,8 +31,7 @@
  net/bridge/br_private.h                       |   20 +
  net/bridge/br_vlan.c                          |   55 +
  net/core/dev.c                                |   46 +
- net/dsa/dsa.c                                 |    9 +
- net/dsa/slave.c                               |   37 +-
+ net/dsa/slave.c                               |   36 +-
  net/ipv4/netfilter/Kconfig                    |    4 +-
  net/ipv6/ip6_output.c                         |    2 +-
  net/ipv6/netfilter/Kconfig                    |    3 +-
@@ -47,8 +45,8 @@
  net/netfilter/nf_flow_table_core.c            |  462 ++++---
  net/netfilter/nf_flow_table_ip.c              |  447 +++---
  net/netfilter/nf_flow_table_offload.c         | 1199 +++++++++++++++++
- net/netfilter/xt_FLOWOFFLOAD.c                |  794 +++++++++++
- 43 files changed, 5005 insertions(+), 435 deletions(-)
+ net/netfilter/xt_FLOWOFFLOAD.c                |  798 +++++++++++
+ 41 files changed, 4993 insertions(+), 435 deletions(-)
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/Makefile
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.c
  mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -2157,34 +2155,6 @@
  };
  
  struct ppp_channel {
-diff --git a/include/net/dsa.h b/include/net/dsa.h
-index d29ee9e..43f65cb 100644
---- a/include/net/dsa.h
-+++ b/include/net/dsa.h
-@@ -562,6 +562,8 @@ struct dsa_switch_ops {
- 					  struct sk_buff *skb);
- };
- 
-+struct dsa_port *dsa_port_from_netdev(struct net_device *netdev);
-+
- struct dsa_switch_driver {
- 	struct list_head	list;
- 	const struct dsa_switch_ops *ops;
-@@ -654,6 +656,14 @@ static inline int call_dsa_notifiers(unsigned long val, struct net_device *dev,
- #define BRCM_TAG_GET_PORT(v)		((v) >> 8)
- #define BRCM_TAG_GET_QUEUE(v)		((v) & 0xff)
- 
-+#if IS_ENABLED(CONFIG_NET_DSA)
-+bool dsa_slave_dev_check(const struct net_device *dev);
-+#else
-+static inline bool dsa_slave_dev_check(const struct net_device *dev)
-+{
-+	return false;
-+}
-+#endif
- 
- netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev);
- int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data);
 diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
 index c6f7bd2..59b8736 100644
 --- a/include/net/flow_offload.h
@@ -2243,6 +2213,15 @@
 index 90690e3..ce0bc3e 100644
 --- a/include/net/netfilter/nf_conntrack.h
 +++ b/include/net/netfilter/nf_conntrack.h
+@@ -105,6 +105,8 @@ struct nf_conn {
+ 
+ 	/* Storage reserved for other modules, must be the last member */
+ 	union nf_conntrack_proto proto;
++
++	u16		inet6_mode;
+ };
+ 
+ static inline struct nf_conn *
 @@ -279,6 +279,18 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct)
  	       !nf_ct_is_dying(ct);
  }
@@ -2288,7 +2267,7 @@
 index 68d7fc9..feac793 100644
 --- a/include/net/netfilter/nf_flow_table.h
 +++ b/include/net/netfilter/nf_flow_table.h
-@@ -8,31 +8,99 @@
+@@ -8,31 +8,101 @@
  #include <linux/rcupdate.h>
  #include <linux/netfilter.h>
  #include <linux/netfilter/nf_conntrack_tuple_common.h>
@@ -2302,6 +2281,8 @@
 +struct flow_offload;
 +enum flow_offload_tuple_dir;
 +
++#define CT_INET_MODE_IPV6	2
++
 +struct nf_flow_key {
 +	struct flow_dissector_key_meta			meta;
 +	struct flow_dissector_key_control		control;
@@ -2970,26 +2951,6 @@
  /**
   *	__dev_get_by_name	- find a device by its name
   *	@net: the applicable net namespace
-diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
-index ca80f86..35a1249 100644
---- a/net/dsa/dsa.c
-+++ b/net/dsa/dsa.c
-@@ -329,6 +329,15 @@ int call_dsa_notifiers(unsigned long val, struct net_device *dev,
- }
- EXPORT_SYMBOL_GPL(call_dsa_notifiers);
- 
-+struct dsa_port *dsa_port_from_netdev(struct net_device *netdev)
-+{
-+	if (!netdev || !dsa_slave_dev_check(netdev))
-+		return ERR_PTR(-ENODEV);
-+
-+	return dsa_slave_to_port(netdev);
-+}
-+EXPORT_SYMBOL_GPL(dsa_port_from_netdev);
-+
- static int __init dsa_init_module(void)
- {
- 	int rc;
 diff --git a/net/dsa/slave.c b/net/dsa/slave.c
 index e2b91b3..2dfaa1e 100644
 --- a/net/dsa/slave.c
@@ -3058,14 +3019,6 @@
  };
  
  static struct device_type dsa_type = {
-@@ -1499,6 +1533,7 @@ bool dsa_slave_dev_check(const struct net_device *dev)
- {
- 	return dev->netdev_ops == &dsa_slave_netdev_ops;
- }
-+EXPORT_SYMBOL_GPL(dsa_slave_dev_check);
- 
- static int dsa_slave_changeupper(struct net_device *dev,
- 				 struct netdev_notifier_changeupper_info *info)
 diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
 index f17b402..803b92e 100644
 --- a/net/ipv4/netfilter/Kconfig
@@ -6136,7 +6089,7 @@
 index 0000000..2cab008
 --- /dev/null
 +++ b/net/netfilter/xt_FLOWOFFLOAD.c
-@@ -0,0 +1,794 @@
+@@ -0,0 +1,798 @@
 +/*
 + * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
 + *
@@ -6504,7 +6457,7 @@
 +	if (!nf_is_valid_ether_device(dev))
 +		goto out;
 +
-+	if (ct->status & IPS_NAT_MASK) {
++	if (ct->status & IPS_NAT_MASK || ct->inet6_mode == CT_INET_MODE_IPV6) {
 +		n = dst_neigh_lookup(dst_cache, daddr);
 +		if (!n)
 +			return -1;
@@ -6537,7 +6490,8 @@
 +	unsigned char ha[ETH_ALEN];
 +	int i;
 +
-+	if (!(ct->status & IPS_NAT_MASK) && skb_mac_header_was_set(skb)) {
++	if (!(ct->status & IPS_NAT_MASK) && skb_mac_header_was_set(skb) &&
++	    ct->inet6_mode != CT_INET_MODE_IPV6) {
 +		eth = eth_hdr(skb);
 +		skb_dir = CTINFO2DIR(skb_get_nfct(skb) & NFCT_INFOMASK);
 +
@@ -6741,6 +6695,9 @@
 +
 +	dir = CTINFO2DIR(ctinfo);
 +
++	if (skb->protocol == htons(ETH_P_IPV6))
++		ct->inet6_mode = CT_INET_MODE_IPV6;
++
 +	if (ct->status & IPS_NAT_MASK) {
 +		if (xt_flowoffload_route_nat(skb, ct, par, &route, dir, devs) < 0)
 +			goto err_flow_route;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
index 1cfa774..5cfedfc 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3006-add-wed-tx-support-for-netsys2.patch
@@ -1,22 +1,35 @@
-From a0b64514c2bfe883d0128ce5bb26559c34185d90 Mon Sep 17 00:00:00 2001
+From d76914437a405265b298b7b01235a7304634c567 Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Mon, 18 Sep 2023 11:01:55 +0800
-Subject: [PATCH 07/22] add-wed-tx-support-for-mt7986
+Subject: [PATCH] add-wed-tx-support-for-mt7986
 
 ---
+ arch/arm64/boot/dts/mediatek/mt7981.dtsi      |   1 +
  arch/arm64/boot/dts/mediatek/mt7986a.dtsi     |   2 +
  arch/arm64/boot/dts/mediatek/mt7986b.dtsi     |   2 +
  drivers/net/ethernet/mediatek/mtk_eth_soc.c   |  17 +-
  drivers/net/ethernet/mediatek/mtk_eth_soc.h   |   5 +
- drivers/net/ethernet/mediatek/mtk_wed.c       | 496 +++++++++++++-----
+ drivers/net/ethernet/mediatek/mtk_wed.c       | 498 +++++++++++++-----
  drivers/net/ethernet/mediatek/mtk_wed.h       |  18 +-
  .../net/ethernet/mediatek/mtk_wed_debugfs.c   |   3 +
  drivers/net/ethernet/mediatek/mtk_wed_regs.h  | 130 ++++-
  include/linux/soc/mediatek/mtk_wed.h          |  23 +
- 9 files changed, 547 insertions(+), 149 deletions(-)
+ 10 files changed, 549 insertions(+), 150 deletions(-)
 
+diff --git a/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
+index e1b9b2c..3e0d2c0 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7981.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
+@@ -96,6 +96,7 @@
+ 		reg = <0 0x15010000 0 0x1000>;
+ 		interrupt-parent = <&gic>;
+ 		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
++		mediatek,wed_pcie = <&wed_pcie>;
+ 	};
+ 
+ 	ap2woccif: ap2woccif@151A5000 {
 diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
-index 0c54e12..3ff8994 100644
+index 7e3101c..e9756bd 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
 @@ -64,6 +64,7 @@
@@ -36,7 +49,7 @@
  
  	ap2woccif: ap2woccif@151A5000 {
 diff --git a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
-index 2d2207f..043e509 100644
+index a780cfb..eafe314 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
 @@ -64,6 +64,7 @@
@@ -55,23 +68,11 @@
  	};
  
  	ap2woccif: ap2woccif@151A5000 {
-diff --git a/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-index b2f53b13..d34943e7 100644
---- a/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-+++ b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
-@@ -96,6 +96,7 @@
- 		reg = <0 0x15010000 0 0x1000>;
- 		interrupt-parent = <&gic>;
- 		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
-+		mediatek,wed_pcie = <&wed_pcie>;
- 	};
- 
- 	ap2woccif: ap2woccif@151A5000 {
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index ee5e0c6..2cab49a 100644
+index 3685926..51fe4b3 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -4968,6 +4968,7 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5091,6 +5091,7 @@ static int mtk_probe(struct platform_device *pdev)
  {
  	struct device_node *mac_np, *mux_np;
  	struct mtk_eth *eth;
@@ -79,7 +80,7 @@
  	int err, i;
  
  	eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
-@@ -4988,13 +4989,12 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5111,13 +5112,12 @@ static int mtk_probe(struct platform_device *pdev)
  			return PTR_ERR(eth->sram_base);
  	}
  
@@ -98,7 +99,7 @@
  
  	mtk_get_hwver(eth);
  
-@@ -5090,12 +5090,15 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5213,12 +5213,15 @@ static int mtk_probe(struct platform_device *pdev)
  			MTK_WDMA1_BASE
  		};
  		void __iomem *wdma;
@@ -114,12 +115,12 @@
 +		mtk_wed_add_hw(np, eth, wdma, wdma_phy, i);
  	}
  
- 	for (i = 0; i < MTK_PDMA_IRQ_NUM; i++)
+ 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_PDMA_INT)) {
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 783166d..960b979 100644
+index b714c27..e9d88f1 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -583,8 +583,13 @@
+@@ -593,8 +593,13 @@
  #define RX_DMA_SPORT_MASK       0x7
  #define RX_DMA_SPORT_MASK_V2    0xf
  
@@ -134,7 +135,7 @@
  /* QDMA descriptor txd4 */
  #define TX_DMA_CHKSUM		(0x7 << 29)
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
-index ea1cbdf..0588e32 100644
+index ea1cbdf..948f013 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
 @@ -18,15 +18,6 @@
@@ -434,7 +435,7 @@
  	struct mtk_wed_hw *hw = dev->hw;
  
  	mutex_lock(&hw_lock);
-@@ -279,9 +420,12 @@ mtk_wed_detach(struct mtk_wed_device *dev)
+@@ -279,11 +420,14 @@ mtk_wed_detach(struct mtk_wed_device *dev)
  	mtk_wed_free_buffer(dev);
  	mtk_wed_free_tx_rings(dev);
  
@@ -448,8 +449,11 @@
 +					   BIT(hw->index), BIT(hw->index));
 +	}
  
- 	if (!hw_list[!hw->index]->wed_dev &&
+-	if (!hw_list[!hw->index]->wed_dev &&
++	if ((!hw_list[!hw->index] || !hw_list[!hw->index]->wed_dev) &&
  	    hw->eth->dma_dev != hw->eth->dev)
+ 		mtk_eth_set_dma_device(hw->eth, hw->eth->dev);
+ 
 @@ -294,15 +438,87 @@ mtk_wed_detach(struct mtk_wed_device *dev)
  	mutex_unlock(&hw_lock);
  }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3011-flow-offload-add-mtkhnat-flow-accounting.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3011-flow-offload-add-mtkhnat-flow-accounting.patch
index 3699263..c516fd6 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3011-flow-offload-add-mtkhnat-flow-accounting.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3011-flow-offload-add-mtkhnat-flow-accounting.patch
@@ -294,7 +294,7 @@
 +		ppe_w32(ppe, MTK_PPE_MIB_TB_BASE, ppe->mib_phys);
 +		ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_EN, MTK_PPE_MIB_CFG_EN);
 +		ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_RD_CLR, MTK_PPE_MIB_CFG_RD_CLR);
-+		ppe_m32(ppe, MTK_PPE_MIB_CACHE_CTL, MTK_PPE_MIB_CACHE_CTL_EN, MTK_PPE_MIB_CFG_RD_CLR);
++		ppe_m32(ppe, MTK_PPE_MIB_CACHE_CTL, MTK_PPE_MIB_CACHE_CTL_EN, MTK_PPE_MIB_CACHE_CTL_EN);
 +	}
 +
  	return 0;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-update-net-bridge-for-bridger.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-update-net-bridge-for-bridger.patch
index b01d689..89e664f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-update-net-bridge-for-bridger.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3014-update-net-bridge-for-bridger.patch
@@ -14,8 +14,7 @@
  net/bridge/br_vlan.c           | 698 +++++++++++++++++++++++++++++++--
  net/bridge/br_vlan_options.c   | 346 ++++++++++++++++
  net/core/rtnetlink.c           |   1 +
- net/dsa/slave.c                |  11 +
- 11 files changed, 1365 insertions(+), 34 deletions(-)
+ 10 files changed, 1354 insertions(+), 34 deletions(-)
  create mode 100644 net/bridge/br_vlan_options.c
 
 diff --git a/include/net/switchdev.h b/include/net/switchdev.h
@@ -1817,30 +1816,6 @@
  			err = rtnl_fill_ifinfo(skb, dev, net,
  					       RTM_NEWLINK,
  					       NETLINK_CB(cb->skb).portid,
-diff --git a/net/dsa/slave.c b/net/dsa/slave.c
-index 2dfaa1e..a60a26c 100644
---- a/net/dsa/slave.c
-+++ b/net/dsa/slave.c
-@@ -1495,8 +1495,19 @@ int dsa_slave_create(struct dsa_port *port)
- 		goto out_phy;
- 	}
- 
-+	rtnl_lock();
-+
-+	ret = netdev_upper_dev_link(master, slave_dev, NULL);
-+
-+	rtnl_unlock();
-+
-+	if (ret)
-+		goto out_unregister;
-+
- 	return 0;
- 
-+out_unregister:
-+	unregister_netdev(slave_dev);
- out_phy:
- 	rtnl_lock();
- 	phylink_disconnect_phy(p->dp->pl);
 -- 
 2.18.0
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
index ef970de..bedf09e 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/flow_patch/999-3015-ethernet-update-ppe-from-netsys2-to-netsys3.patch
@@ -1,22 +1,22 @@
-From 1e2da129898cd45b4196c0aaf2de9d0e9ed46d77 Mon Sep 17 00:00:00 2001
+From 5481f7ecbd3cfffd8234bc8e952a6e07f42de76c Mon Sep 17 00:00:00 2001
 From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
-Date: Wed, 25 Oct 2023 11:39:09 +0800
+Date: Tue, 21 Nov 2023 16:42:01 +0800
 Subject: [PATCH 16/22] ethernet-update-ppe-from-netsys2-to-netsys3
 
 ---
  drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 14 ++++---
- drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  9 +++--
- drivers/net/ethernet/mediatek/mtk_ppe.c       | 31 ++++++++++++---
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  7 ++--
+ drivers/net/ethernet/mediatek/mtk_ppe.c       | 35 ++++++++++++++---
  drivers/net/ethernet/mediatek/mtk_ppe.h       | 38 ++++++++++++++++---
  .../net/ethernet/mediatek/mtk_ppe_offload.c   |  6 ++-
- drivers/net/ethernet/mediatek/mtk_ppe_regs.h  |  5 +++
- 6 files changed, 81 insertions(+), 22 deletions(-)
+ drivers/net/ethernet/mediatek/mtk_ppe_regs.h  |  7 ++++
+ 6 files changed, 85 insertions(+), 22 deletions(-)
 
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 31c60a0..37355d9 100644
+index 850bc4f..8910d40 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2244,17 +2244,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
+@@ -2248,17 +2248,17 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
  			skb_checksum_none_assert(skb);
  		skb->protocol = eth_type_trans(skb, netdev);
  
@@ -38,7 +38,7 @@
  		reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
  		if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
  			for (i = 0; i < eth->ppe_num; i++) {
-@@ -5262,7 +5262,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5290,7 +5290,8 @@ static int mtk_probe(struct platform_device *pdev)
  
  		for (i = 0; i < eth->ppe_num; i++) {
  			eth->ppe[i] = mtk_ppe_init(eth,
@@ -48,7 +48,7 @@
  						   2, eth->soc->hash_way, i,
  						   eth->soc->has_accounting);
  			if (!eth->ppe[i]) {
-@@ -5529,6 +5530,9 @@ static const struct mtk_soc_data mt7988_data = {
+@@ -5557,6 +5558,9 @@ static const struct mtk_soc_data mt7988_data = {
  	.required_clks = MT7988_CLKS_BITMAP,
  	.required_pctl = false,
  	.has_sram = true,
@@ -59,10 +59,10 @@
  	.txrx = {
  		.txd_size = sizeof(struct mtk_tx_dma_v2),
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index 0282d25..48ecdc8 100644
+index 9c77f14..c7d36c5 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -130,9 +130,10 @@
+@@ -134,9 +134,10 @@
  #define MTK_GDMA_UCS_EN		BIT(20)
  #define MTK_GDMA_STRP_CRC	BIT(16)
  #define MTK_GDMA_TO_PDMA	0x0
@@ -70,11 +70,11 @@
 +#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
  #define MTK_GDMA_TO_PPE0	0x3333
  #define MTK_GDMA_TO_PPE1	0x4444
-+#define MTK_GMAC_TO_PPE2	0xcccc
++#define MTK_GDMA_TO_PPE2	0xcccc
  #else
  #define MTK_GDMA_TO_PPE0	0x4444
  #endif
-@@ -1972,13 +1973,13 @@ extern u32 dbg_show_level;
+@@ -1978,14 +1979,14 @@ extern u32 dbg_show_level;
  
  static inline void mtk_set_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe, u32 val)
  {
@@ -91,9 +91,8 @@
  	return FIELD_GET(MTK_FOE_IB1_UNBIND_SRC_PORT, foe->ib1);
  #else
  	return 0;
- #endif
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
-index 1ed1b60..5a1036f 100755
+index 8388f65..184e29d 100755
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -91,7 +91,7 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe)
@@ -183,7 +182,16 @@
  	      MTK_PPE_TB_CFG_INFO_SEL |
  #endif
  	      FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS,
-@@ -993,7 +1012,7 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
+@@ -988,12 +1007,16 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
+ 	      MTK_PPE_GLO_CFG_IP4_L4_CS_DROP |
+ 	      MTK_PPE_GLO_CFG_IP4_CS_DROP |
+ 	      MTK_PPE_GLO_CFG_MCAST_TB_EN |
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	      MTK_PPE_GLO_CFG_CS0_PIPE_EN |
++	      MTK_PPE_GLO_CFG_SRH_CACHE_FIRST_EN |
++#endif
+ 	      MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE;
+ 	ppe_w32(ppe, MTK_PPE_GLO_CFG, val);
  
  	ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0);
  
@@ -308,10 +316,19 @@
  		ctx.dev = idev;
  		idev->netdev_ops->ndo_fill_receive_path(&ctx, &path);
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
-index 8d3ebe1..f8425df 100644
+index 8d3ebe1..55b9b0c 100644
 --- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
-@@ -155,9 +155,14 @@ enum {
+@@ -18,6 +18,8 @@
+ #define MTK_PPE_GLO_CFG_UDP_LITE_EN		BIT(10)
+ #define MTK_PPE_GLO_CFG_UDP_LEN_DROP		BIT(11)
+ #define MTK_PPE_GLO_CFG_MCAST_ENTRIES		GNEMASK(13, 12)
++#define MTK_PPE_GLO_CFG_CS0_PIPE_EN		BIT(29)
++#define MTK_PPE_GLO_CFG_SRH_CACHE_FIRST_EN	BIT(30)
+ #define MTK_PPE_GLO_CFG_BUSY			BIT(31)
+ 
+ #define MTK_PPE_FLOW_CFG			0x204
+@@ -155,9 +157,14 @@ enum {
  #define MTK_PPE_MIB_SER_R1			0x344
  #define MTK_PPE_MIB_SER_R1_PKT_CNT_LOW		GENMASK(31, 16)
  #define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH	GENMASK(15, 0)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
index 33046cd..20984c3 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
@@ -288,6 +288,7 @@
 CONFIG_IRQ_TIME_ACCOUNTING=y
 CONFIG_IRQ_WORK=y
 CONFIG_JUMP_LABEL=y
+# CONFIG_LEDS_CLASS_MULTICOLOR is not set
 # CONFIG_LEDS_UBNT_LEDBAR is not set
 CONFIG_LIBFDT=y
 CONFIG_LOCK_DEBUGGING_SUPPORT=y
@@ -549,3 +550,6 @@
 # CONFIG_FUNCTION_ERROR_INJECTION is not set
 CONFIG_RICHTEK_RTQ6056=y
 CONFIG_ZTS8032=y
+# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
+# CONFIG_CRYPTO_CAVP_TEST is not set
+# CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG is not set
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
index 06ec24b..a36a0db 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7988.cfg
@@ -260,6 +260,7 @@
 CONFIG_IRQ_TIME_ACCOUNTING=y
 CONFIG_IRQ_WORK=y
 CONFIG_JUMP_LABEL=y
+# CONFIG_LEDS_CLASS_MULTICOLOR is not set
 # CONFIG_LEDS_UBNT_LEDBAR is not set
 CONFIG_LIBFDT=y
 CONFIG_LOCK_DEBUGGING_SUPPORT=y
@@ -520,3 +521,6 @@
 # CONFIG_FUNCTION_ERROR_INJECTION is not set
 CONFIG_RICHTEK_RTQ6056=y
 CONFIG_ZTS8032=y
+# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
+# CONFIG_CRYPTO_CAVP_TEST is not set
+# CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG is not set
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-backport-linux-6.2-xfrm-packet-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-v6.2-xfrm-packet-mode.patch
similarity index 97%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-backport-linux-6.2-xfrm-packet-mode.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-v6.2-xfrm-packet-mode.patch
index 9eb9347..57817da 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-backport-linux-6.2-xfrm-packet-mode.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-1022-v6.2-xfrm-packet-mode.patch
@@ -644,7 +644,7 @@
  static void xfrm_hash_transfer(struct hlist_head *list,
  			       struct hlist_head *ndsttable,
  			       struct hlist_head *nsrctable,
-@@ -93,18 +112,20 @@ static void xfrm_hash_transfer(struct hl
+@@ -93,18 +112,19 @@ static void xfrm_hash_transfer(struct hl
  		h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
  				    x->props.reqid, x->props.family,
  				    nhashmask);
@@ -661,13 +661,13 @@
  			h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
  					    x->id.proto, x->props.family,
  					    nhashmask);
- 			hlist_add_head_rcu(&x->byspi, nspitable + h);
+-			hlist_add_head_rcu(&x->byspi, nspitable + h);
 +			XFRM_STATE_INSERT(byspi, &x->byspi, nspitable + h,
 +					  x->xso.type);
  		}
  	}
  }
-@@ -527,6 +548,8 @@ static enum hrtimer_restart xfrm_timer_h
+@@ -527,6 +547,8 @@ static enum hrtimer_restart xfrm_timer_h
  	int err = 0;
  
  	spin_lock(&x->lock);
@@ -676,7 +676,7 @@
  	if (x->km.state == XFRM_STATE_DEAD)
  		goto out;
  	if (x->km.state == XFRM_STATE_EXPIRED)
-@@ -923,6 +946,49 @@ xfrm_init_tempstate(struct xfrm_state *x
+@@ -923,6 +945,49 @@ xfrm_init_tempstate(struct xfrm_state *x
  	x->props.family = tmpl->encap_family;
  }
  
@@ -726,7 +726,7 @@
  static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
  					      const xfrm_address_t *daddr,
  					      __be32 spi, u8 proto,
-@@ -1062,6 +1128,23 @@ xfrm_state_find(const xfrm_address_t *da
+@@ -1062,6 +1127,23 @@ xfrm_state_find(const xfrm_address_t *da
  	rcu_read_lock();
  	h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
  	hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) {
@@ -750,7 +750,7 @@
  		if (x->props.family == encap_family &&
  		    x->props.reqid == tmpl->reqid &&
  		    (mark & x->mark.m) == x->mark.v &&
-@@ -1079,6 +1162,23 @@ xfrm_state_find(const xfrm_address_t *da
+@@ -1079,6 +1161,23 @@ xfrm_state_find(const xfrm_address_t *da
  
  	h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
  	hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) {
@@ -774,7 +774,7 @@
  		if (x->props.family == encap_family &&
  		    x->props.reqid == tmpl->reqid &&
  		    (mark & x->mark.m) == x->mark.v &&
-@@ -1096,8 +1196,10 @@ found:
+@@ -1096,8 +1195,10 @@ found:
  	x = best;
  	if (!x && !error && !acquire_in_progress) {
  		if (tmpl->id.spi &&
@@ -787,7 +787,7 @@
  			to_put = x0;
  			error = -EEXIST;
  			goto out;
-@@ -1131,17 +1233,42 @@ found:
+@@ -1131,17 +1232,42 @@ found:
  			x = NULL;
  			goto out;
  		}
@@ -834,7 +834,7 @@
  			}
  			x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
  			hrtimer_start(&x->mtimer,
-@@ -1151,6 +1278,16 @@ found:
+@@ -1151,6 +1277,16 @@ found:
  			xfrm_hash_grow_check(net, x->bydst.next != NULL);
  			spin_unlock_bh(&net->xfrm.xfrm_state_lock);
  		} else {
@@ -851,7 +851,7 @@
  			x->km.state = XFRM_STATE_DEAD;
  			to_put = x;
  			x = NULL;
-@@ -1246,16 +1383,19 @@ static void __xfrm_state_insert(struct x
+@@ -1246,16 +1382,19 @@ static void __xfrm_state_insert(struct x
  
  	h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
  			  x->props.reqid, x->props.family);
@@ -874,7 +874,7 @@
  	}
  
  	hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT);
-@@ -1369,9 +1509,11 @@ static struct xfrm_state *__find_acq_cor
+@@ -1369,9 +1508,11 @@ static struct xfrm_state *__find_acq_cor
  			      ktime_set(net->xfrm.sysctl_acq_expires, 0),
  			      HRTIMER_MODE_REL_SOFT);
  		list_add(&x->km.all, &net->xfrm.state_all);
@@ -888,7 +888,7 @@
  
  		net->xfrm.state_num++;
  
-@@ -1742,6 +1884,8 @@ EXPORT_SYMBOL(xfrm_state_update);
+@@ -1742,6 +1883,8 @@ EXPORT_SYMBOL(xfrm_state_update);
  
  int xfrm_state_check_expire(struct xfrm_state *x)
  {
@@ -897,7 +897,7 @@
  	if (!x->curlft.use_time)
  		x->curlft.use_time = ktime_get_real_seconds();
  
-@@ -2043,7 +2187,8 @@ int xfrm_alloc_spi(struct xfrm_state *x,
+@@ -2043,7 +2186,8 @@ int xfrm_alloc_spi(struct xfrm_state *x,
  		spin_lock_bh(&net->xfrm.xfrm_state_lock);
  		x->id.spi = newspi;
  		h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2728-xfrm-extend-packet-mode-to-support-esp-tunnel-mode.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2728-xfrm-extend-packet-mode-to-support-esp-tunnel-mode.patch
index d41c0f3..17ae470 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2728-xfrm-extend-packet-mode-to-support-esp-tunnel-mode.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-2728-xfrm-extend-packet-mode-to-support-esp-tunnel-mode.patch
@@ -33,3 +33,31 @@
  		if (skb_is_gso(skb))
  			return xfrm_output_gso(net, sk, skb);
  	}
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -3703,6 +3703,10 @@ int __xfrm_policy_check(struct sock *sk,
+ 		}
+ 	}
+ #endif
++	/* Inbound HW offload packets, pass the check directly */
++	if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET &&
++	    (pol->xdo.dir == XFRM_DEV_OFFLOAD_IN || pol->xdo.dir == XFRM_DEV_OFFLOAD_FWD))
++		return 1;
+ 
+ 	if (pol->action == XFRM_POLICY_ALLOW) {
+ 		static struct sec_path dummy;
+@@ -3712,6 +3716,14 @@ int __xfrm_policy_check(struct sock *sk,
+ 		int ti = 0;
+ 		int i, k;
+ 
++		/* Strongswan install FWD policy for inbound HW offload
++		 * packets. But cannot find corresponding packet offload
++		 * state here and will be drop. So, we bypass following
++		 * check for FWD policy with acction allow.
++		 */
++		if (dir == XFRM_POLICY_FWD)
++			return 1;
++
+ 		sp = skb_sec_path(skb);
+ 		if (!sp)
+ 			sp = &dummy;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tunnel-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tunnel-offload-support.patch
index 299c7b4..6c26c22 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tunnel-offload-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tunnel-offload-support.patch
@@ -1,489 +1,488 @@
---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c

-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c

-@@ -245,6 +245,9 @@ static const char * const mtk_clks_source_name[] = {

- 	"top_netsys_warp_sel",

- };

- 

-+struct net_device *(*mtk_get_tnl_dev)(int tnl_idx) = NULL;

-+EXPORT_SYMBOL(mtk_get_tnl_dev);

-+

- void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)

- {

- 	__raw_writel(val, eth->base + reg);

-@@ -2186,6 +2189,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,

- 	u64 addr64 = 0;

- 	u8 *data, *new_data;

- 	struct mtk_rx_dma_v2 *rxd, trxd;

-+	int tnl_idx = 0;

- 	int done = 0;

- 

- 	if (unlikely(!ring))

-@@ -2229,11 +2233,20 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,

- 				      0 : RX_DMA_GET_SPORT(trxd.rxd4) - 1;

- 		}

- 

--		if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||

--			     !eth->netdev[mac]))

--			goto release_desc;

-+		tnl_idx = RX_DMA_GET_TOPS_CRSN(trxd.rxd6);

-+		if (mtk_get_tnl_dev && tnl_idx) {

-+			netdev = mtk_get_tnl_dev(tnl_idx);

-+			if (unlikely(IS_ERR(netdev)))

-+				netdev = NULL;

-+		}

- 

--		netdev = eth->netdev[mac];

-+		if (!netdev) {

-+			if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||

-+				     !eth->netdev[mac]))

-+				goto release_desc;

-+

-+			netdev = eth->netdev[mac];

-+		}

- 

- 		if (unlikely(test_bit(MTK_RESETTING, &eth->state)))

- 			goto release_desc;

-@@ -2318,6 +2331,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,

- 		skb_hnat_alg(skb) = 0;

- 		skb_hnat_filled(skb) = 0;

- 		skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;

-+		skb_hnat_set_tops(skb, 0);

-+		skb_hnat_set_is_decap(skb, 0);

- 

- 		if (skb_hnat_reason(skb) == HIT_BIND_FORCE_TO_CPU) {

- 			trace_printk("[%s] reason=0x%x(force to CPU) from WAN to Ext\n",

---- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c

-+++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c

-@@ -43,6 +43,12 @@ void (*ppe_dev_register_hook)(struct net_device *dev) = NULL;

- EXPORT_SYMBOL(ppe_dev_register_hook);

- void (*ppe_dev_unregister_hook)(struct net_device *dev) = NULL;

- EXPORT_SYMBOL(ppe_dev_unregister_hook);

-+int (*mtk_tnl_encap_offload)(struct sk_buff *skb) = NULL;

-+EXPORT_SYMBOL(mtk_tnl_encap_offload);

-+int (*mtk_tnl_decap_offload)(struct sk_buff *skb) = NULL;

-+EXPORT_SYMBOL(mtk_tnl_decap_offload);

-+bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb) = NULL;

-+EXPORT_SYMBOL(mtk_tnl_decap_offloadable);

- 

- static void hnat_sma_build_entry(struct timer_list *t)

- {

-@@ -53,6 +59,16 @@ static void hnat_sma_build_entry(struct timer_list *t)

- 			     SMA, SMA_FWD_CPU_BUILD_ENTRY);

- }

- 

-+struct foe_entry *hnat_get_foe_entry(u32 ppe_id, u32 index)

-+{

-+	if (index == 0x7fff || index >= hnat_priv->foe_etry_num

-+	    || ppe_id >= CFG_PPE_NUM)

-+		return ERR_PTR(-EINVAL);

-+

-+	return &hnat_priv->foe_table_cpu[ppe_id][index];

-+}

-+EXPORT_SYMBOL(hnat_get_foe_entry);

-+

- void hnat_cache_ebl(int enable)

- {

- 	int i;

-@@ -63,6 +79,7 @@ void hnat_cache_ebl(int enable)

- 		cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_EN, enable);

- 	}

- }

-+EXPORT_SYMBOL(hnat_cache_ebl);

- 

- static void hnat_reset_timestamp(struct timer_list *t)

- {

---- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h

-+++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h

-@@ -1133,6 +1133,8 @@ enum FoeIpAct {

- #define NR_WDMA1_PORT 9

- #define NR_WDMA2_PORT 13

- #define NR_GMAC3_PORT 15

-+#define NR_TDMA_TPORT 4

-+#define NR_TDMA_QDMA_TPORT 5

- #define LAN_DEV_NAME hnat_priv->lan

- #define LAN2_DEV_NAME hnat_priv->lan2

- #define IS_WAN(dev)                                                            \

-@@ -1256,6 +1258,8 @@ static inline bool hnat_dsa_is_enable(struct mtk_hnat *priv)

- }

- #endif

- 

-+struct foe_entry *hnat_get_foe_entry(u32 ppe_id, u32 index);

-+

- void hnat_deinit_debugfs(struct mtk_hnat *h);

- int hnat_init_debugfs(struct mtk_hnat *h);

- int hnat_register_nf_hooks(void);

-@@ -1272,6 +1276,9 @@ extern int qos_ul_toggle;

- extern int hook_toggle;

- extern int mape_toggle;

- extern int qos_toggle;

-+extern int (*mtk_tnl_encap_offload)(struct sk_buff *skb);

-+extern int (*mtk_tnl_decap_offload)(struct sk_buff *skb);

-+extern bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb);

- 

- int ext_if_add(struct extdev_entry *ext_entry);

- int ext_if_del(struct extdev_entry *ext_entry);

---- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c

-+++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c

-@@ -726,10 +726,14 @@ static unsigned int is_ppe_support_type(struct sk_buff *skb)

- 	case ETH_P_IP:

- 		iph = ip_hdr(skb);

- 

--		/* do not accelerate non tcp/udp traffic */

--		if ((iph->protocol == IPPROTO_TCP) ||

-+		if (mtk_tnl_decap_offloadable && mtk_tnl_decap_offloadable(skb)) {

-+			/* tunnel protocol is offloadable */

-+			skb_hnat_set_is_decap(skb, 1);

-+			return 1;

-+		} else if ((iph->protocol == IPPROTO_TCP) ||

- 		    (iph->protocol == IPPROTO_UDP) ||

- 		    (iph->protocol == IPPROTO_IPV6)) {

-+			/* do not accelerate non tcp/udp traffic */

- 			return 1;

- 		}

- 

-@@ -846,6 +850,13 @@ mtk_hnat_ipv4_nf_pre_routing(void *priv, struct sk_buff *skb,

- 

- 	hnat_set_head_frags(state, skb, -1, hnat_set_iif);

- 

-+	if (skb_hnat_tops(skb) && skb_hnat_is_decap(skb)

-+	    && is_magic_tag_valid(skb)

-+	    && skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL

-+	    && mtk_tnl_decap_offload && mtk_tnl_decap_offload(skb)) {

-+		return NF_ACCEPT;

-+	}

-+

- 	/*

- 	 * Avoid mistakenly binding of outer IP, ports in SW L2TP decap flow.

- 	 * In pre-routing, if dev is virtual iface, TOPS module is not loaded,

-@@ -921,6 +932,13 @@ mtk_hnat_br_nf_local_in(void *priv, struct sk_buff *skb,

- 

- 	hnat_set_head_frags(state, skb, -1, hnat_set_iif);

- 

-+	if (skb_hnat_tops(skb) && skb_hnat_is_decap(skb)

-+	    && is_magic_tag_valid(skb)

-+	    && skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL

-+	    && mtk_tnl_decap_offload && mtk_tnl_decap_offload(skb)) {

-+		return NF_ACCEPT;

-+	}

-+

- 	pre_routing_print(skb, state->in, state->out, __func__);

- 

- 	if (unlikely(debug_level >= 7)) {

-@@ -1073,9 +1091,22 @@ static unsigned int hnat_ipv4_get_nexthop(struct sk_buff *skb,

- 		return -1;

- 	}

- 

-+	/*

-+	 * if this packet is a tunnel packet and is about to construct

-+	 * outer header, we must update its outer mac header pointer

-+	 * before filling outer mac or it may screw up inner mac

-+	 */

-+	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) {

-+		skb_push(skb, sizeof(struct ethhdr));

-+		skb_reset_mac_header(skb);

-+	}

-+

- 	memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);

- 	memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN);

- 

-+	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb))

-+		skb_pull(skb, sizeof(struct ethhdr));

-+

- 	rcu_read_unlock_bh();

- 

- 	return 0;

-@@ -1201,6 +1232,81 @@ static struct ethhdr *get_ipv6_ipip_ethhdr(struct sk_buff *skb,

- 	return eth;

- }

- 

-+static inline void hnat_get_filled_unbind_entry(struct sk_buff *skb,

-+						struct foe_entry *entry)

-+{

-+	if (unlikely(!skb || !entry))

-+		return;

-+

-+	memcpy(entry,

-+	       &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)],

-+	       sizeof(*entry));

-+

-+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)

-+	entry->bfib1.mc = 0;

-+#endif /* defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3) */

-+	entry->bfib1.ka = 0;

-+	entry->bfib1.vlan_layer = 0;

-+	entry->bfib1.psn = 0;

-+	entry->bfib1.vpm = 0;

-+	entry->bfib1.ps = 0;

-+}

-+

-+static inline void hnat_qos_tnl(u32 id, const struct net_device *dev)

-+{

-+	u32 cfg;

-+	u32 max_man = 0;

-+	u32 max_exp = 0;

-+	const struct mtk_mac *mac;

-+

-+	if (!dev)

-+		return;

-+	mac = netdev_priv(dev);

-+

-+	switch (mac->speed) {

-+	case SPEED_100:

-+	case SPEED_1000:

-+	case SPEED_2500:

-+	case SPEED_5000:

-+	case SPEED_10000:

-+		max_man = mac->speed / SPEED_100;

-+		max_exp = 5;

-+		break;

-+	default:

-+		return;

-+	}

-+

-+	cfg = QTX_SCH_MIN_RATE_EN | QTX_SCH_MAX_RATE_EN;

-+	cfg |= (1 << QTX_SCH_MIN_RATE_MAN_OFFSET) |

-+	       (4 << QTX_SCH_MIN_RATE_EXP_OFFSET) |

-+	       (max_man << QTX_SCH_MAX_RATE_MAN_OFFSET) |

-+	       (max_exp << QTX_SCH_MAX_RATE_EXP_OFFSET) |

-+	       (4 << QTX_SCH_MAX_RATE_WGHT_OFFSET);

-+	writel(cfg, hnat_priv->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));

-+}

-+

-+static inline void hnat_fill_offload_engine_entry(struct sk_buff *skb,

-+						  struct foe_entry *entry,

-+						  const struct net_device *dev)

-+{

-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)

-+	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) {

-+		/*

-+		 * if skb_hnat_tops(skb) is setup for encapsulation,

-+		 * we fill in hnat tport and tops_entry for tunnel encapsulation

-+		 * offloading

-+		 */

-+		entry->ipv4_hnapt.tport_id = NR_TDMA_QDMA_TPORT;

-+		entry->ipv4_hnapt.tops_entry = skb_hnat_tops(skb);

-+	} else {

-+		return;

-+	}

-+

-+	entry->ipv4_hnapt.iblk2.qid = 12; /* offload engine use QID 12 */

-+	hnat_qos_tnl(12, dev); /* set rate limit to line rate */

-+#endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */

-+}

-+

- static unsigned int skb_to_hnat_info(struct sk_buff *skb,

- 				     const struct net_device *dev,

- 				     struct foe_entry *foe,

-@@ -1237,6 +1343,11 @@ static unsigned int skb_to_hnat_info(struct sk_buff *skb,

- 	if (whnat && is_hnat_pre_filled(foe))

- 		return 0;

- 

-+	if (skb_hnat_tops(skb) && !(hw_path->flags & FLOW_OFFLOAD_PATH_TNL)) {

-+		hnat_get_filled_unbind_entry(skb, &entry);

-+		goto hnat_entry_bind;

-+	}

-+

- 	entry.bfib1.pkt_type = foe->udib1.pkt_type; /* Get packte type state*/

- 	entry.bfib1.state = foe->udib1.state;

- 

-@@ -1679,6 +1790,10 @@ static unsigned int skb_to_hnat_info(struct sk_buff *skb,

- 	/* Fill Layer2 Info.*/

- 	entry = ppe_fill_L2_info(eth, entry, hw_path);

- 

-+	if (skb_hnat_tops(skb) && hw_path->flags & FLOW_OFFLOAD_PATH_TNL)

-+		goto hnat_entry_skip_bind;

-+

-+hnat_entry_bind:

- 	/* Fill Info Blk*/

- 	entry = ppe_fill_info_blk(eth, entry, hw_path);

- 

-@@ -1879,7 +1994,20 @@ static unsigned int skb_to_hnat_info(struct sk_buff *skb,

- 			entry.ipv6_5t_route.act_dp |= UDF_HNAT_PRE_FILLED;

- 	}

- 

-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)

-+	hnat_fill_offload_engine_entry(skb, &entry, dev);

-+#endif

-+

-+hnat_entry_skip_bind:

- 	wmb();

-+

-+	/*

-+	 * final check before we write BIND info.

-+	 * If this entry is already bound, we should not modify it right now

-+	 */

-+	if (entry_hnat_is_bound(foe))

-+		return 0;

-+

- 	memcpy(foe, &entry, sizeof(entry));

- 	/*reset statistic for this entry*/

- 	if (hnat_priv->data->per_flow_accounting &&

-@@ -1951,6 +2079,12 @@ int mtk_sw_nat_hook_tx(struct sk_buff *skb, int gmac_no)

- 	switch ((int)entry.bfib1.pkt_type) {

- 	case IPV4_HNAPT:

- 	case IPV4_HNAT:

-+		/*

-+		 * skip if packet is an encap tnl packet or it may

-+		 * screw up inner mac header

-+		 */

-+		if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb))

-+			break;

- 		entry.ipv4_hnapt.smac_hi = swab32(*((u32 *)eth->h_source));

- 		entry.ipv4_hnapt.smac_lo = swab16(*((u16 *)&eth->h_source[4]));

- 		break;

-@@ -2112,6 +2246,10 @@ int mtk_sw_nat_hook_tx(struct sk_buff *skb, int gmac_no)

- 		entry.ipv6_5t_route.iblk2.dp = gmac_no;

- 	}

- 

-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)

-+	hnat_fill_offload_engine_entry(skb, &entry, NULL);

-+#endif

-+

- 	entry.bfib1.ttl = 1;

- 	entry.bfib1.state = BIND;

- 

-@@ -2187,6 +2325,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *skb)

- 	}

- 

- 	skb_hnat_alg(skb) = 0;

-+	skb_hnat_set_tops(skb, 0);

- 	skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;

- 

- 	if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)

-@@ -2636,6 +2775,7 @@ static unsigned int mtk_hnat_nf_post_routing(

- 	struct flow_offload_hw_path hw_path = { .dev = (struct net_device*)out,

- 						.virt_dev = (struct net_device*)out };

- 	const struct net_device *arp_dev = out;

-+	bool is_virt_dev = false;

- 

- 	if (xlat_toggle && !mtk_464xlat_post_process(skb, out))

- 		return 0;

-@@ -2652,10 +2792,29 @@ static unsigned int mtk_hnat_nf_post_routing(

- 

- 	if (out->netdev_ops->ndo_flow_offload_check) {

- 		out->netdev_ops->ndo_flow_offload_check(&hw_path);

-+

- 		out = (IS_GMAC1_MODE) ? hw_path.virt_dev : hw_path.dev;

-+		if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL && mtk_tnl_encap_offload) {

-+			if (ntohs(skb->protocol) == ETH_P_IP

-+			    && ip_hdr(skb)->protocol == IPPROTO_TCP) {

-+				skb_hnat_set_tops(skb, hw_path.tnl_type + 1);

-+			} else {

-+				/*

-+				 * we are not support protocols other than IPv4 TCP

-+				 * for tunnel protocol offload yet

-+				 */

-+				skb_hnat_alg(skb) = 1;

-+				return 0;

-+			}

-+		}

- 	}

- 

- 	if (!IS_LAN_GRP(out) && !IS_WAN(out) && !IS_EXT(out))

-+		is_virt_dev = true;

-+

-+	if (is_virt_dev

-+	    && !(skb_hnat_tops(skb) && skb_hnat_is_encap(skb)

-+		 && (hw_path.flags & FLOW_OFFLOAD_PATH_TNL)))

- 		return 0;

- 

- 	trace_printk("[%s] case hit, %x-->%s, reason=%x\n", __func__,

-@@ -2675,9 +2834,18 @@ static unsigned int mtk_hnat_nf_post_routing(

- 		if (fn && !mtk_hnat_accel_type(skb))

- 			break;

- 

--		if (fn && fn(skb, arp_dev, &hw_path))

-+		if (!is_virt_dev && fn && fn(skb, arp_dev, &hw_path))

- 			break;

- 

-+		/* skb_hnat_tops(skb) is updated in mtk_tnl_offload() */

-+		if (skb_hnat_tops(skb)) {

-+			if (skb_hnat_is_encap(skb) && !is_virt_dev

-+			    && mtk_tnl_encap_offload && mtk_tnl_encap_offload(skb))

-+				break;

-+			if (skb_hnat_is_decap(skb))

-+				break;

-+		}

-+

- 		spin_lock(&hnat_priv->entry_lock);

- 		skb_to_hnat_info(skb, out, entry, &hw_path);

- 		spin_unlock(&hnat_priv->entry_lock);

-@@ -2951,7 +3119,7 @@ mtk_hnat_ipv4_nf_local_out(void *priv, struct sk_buff *skb,

- 	if (iph->protocol == IPPROTO_IPV6) {

- 		entry->udib1.pkt_type = IPV6_6RD;

- 		hnat_set_head_frags(state, skb, 0, hnat_set_alg);

--	} else {

-+	} else if (!skb_hnat_tops(skb)) {

- 		hnat_set_head_frags(state, skb, 1, hnat_set_alg);

- 	}

- 

---- a/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h

-+++ b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h

-@@ -44,7 +44,9 @@ struct hnat_desc {

- 	u32 is_sp : 1;

- 	u32 hf : 1;

- 	u32 amsdu : 1;

--	u32 resv3 : 19;

-+	u32 tops : 6;

-+	u32 is_decap : 1;

-+	u32 resv3 : 12;

- 	u32 magic_tag_protect : 16;

- } __packed;

- #elif defined(CONFIG_MEDIATEK_NETSYS_RX_V2)

-@@ -91,6 +93,19 @@ struct hnat_desc {

- 	((((skb_headroom(skb) >= FOE_INFO_LEN) ? 1 : 0)))

- 

- #define skb_hnat_info(skb) ((struct hnat_desc *)(skb->head))

-+#if defined(CONFIG_MEDIATEK_NETSYS_V3)

-+#define skb_hnat_tops(skb) (((struct hnat_desc *)((skb)->head))->tops)

-+#define skb_hnat_is_decap(skb) (((struct hnat_desc *)((skb)->head))->is_decap)

-+#define skb_hnat_is_encap(skb) (!skb_hnat_is_decap(skb))

-+#define skb_hnat_set_tops(skb, tops) ((skb_hnat_tops(skb)) = (tops))

-+#define skb_hnat_set_is_decap(skb, is_decap) ((skb_hnat_is_decap(skb)) = (is_decap))

-+#else /* !defined(CONFIG_MEDIATEK_NETSYS_V3) */

-+#define skb_hnat_tops(skb) (0)

-+#define skb_hnat_is_decap(skb) (0)

-+#define skb_hnat_is_encap(skb) (0)

-+#define skb_hnat_set_tops(skb, tops)

-+#define skb_hnat_set_is_decap(skb, is_decap)

-+#endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */

- #define skb_hnat_magic(skb) (((struct hnat_desc *)(skb->head))->magic)

- #define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn)

- #define skb_hnat_entry(skb) (((struct hnat_desc *)(skb->head))->entry)

---- a/include/net/netfilter/nf_flow_table.h

-+++ b/include/net/netfilter/nf_flow_table.h

-@@ -98,10 +98,22 @@ struct flow_offload {

- #define FLOW_OFFLOAD_PATH_6RD		BIT(5)

- #define FLOW_OFFLOAD_PATH_TNL		BIT(6)

- 

-+enum flow_offload_tnl {

-+	FLOW_OFFLOAD_TNL_GRETAP,

-+	FLOW_OFFLOAD_TNL_PPTP,

-+	FLOW_OFFLOAD_TNL_IP_L2TP,

-+	FLOW_OFFLOAD_TNL_UDP_L2TP_CTRL,

-+	FLOW_OFFLOAD_TNL_UDP_L2TP_DATA,

-+	FLOW_OFFLOAD_VXLAN,

-+	FLOW_OFFLOAD_NATT,

-+	__FLOW_OFFLOAD_MAX,

-+};

-+

- struct flow_offload_hw_path {

- 	struct net_device *dev;

- 	struct net_device *virt_dev;

- 	u32 flags;

-+	u32 tnl_type;

- 

- 	u8 eth_src[ETH_ALEN];

- 	u8 eth_dest[ETH_ALEN];

---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h

-+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h

-@@ -1904,6 +1904,9 @@ extern const struct of_device_id of_mtk_match[];

- extern u32 mtk_hwlro_stats_ebl;

- extern u32 dbg_show_level;

- 

-+/* tunnel offload related */

-+extern struct net_device *(*mtk_get_tnl_dev)(int tnl_idx);

-+

- /* read the hardware status register */

- void mtk_stats_update_mac(struct mtk_mac *mac);

- 

+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -245,6 +245,9 @@ static const char * const mtk_clks_sourc
+ 	"top_netsys_warp_sel",
+ };
+ 
++struct net_device *(*mtk_get_tnl_dev)(int tnl_idx) = NULL;
++EXPORT_SYMBOL(mtk_get_tnl_dev);
++
+ void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
+ {
+ 	__raw_writel(val, eth->base + reg);
+@@ -2168,6 +2171,7 @@ static int mtk_poll_rx(struct napi_struc
+ 	u64 addr64 = 0;
+ 	u8 *data, *new_data;
+ 	struct mtk_rx_dma_v2 *rxd, trxd;
++	int tnl_idx = 0;
+ 	int done = 0;
+ 
+ 	if (unlikely(!ring))
+@@ -2205,11 +2209,20 @@ static int mtk_poll_rx(struct napi_struc
+ 				      0 : RX_DMA_GET_SPORT(trxd.rxd4) - 1;
+ 		}
+ 
+-		if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
+-			     !eth->netdev[mac]))
+-			goto release_desc;
++		tnl_idx = RX_DMA_GET_TOPS_CRSN(trxd.rxd6);
++		if (mtk_get_tnl_dev && tnl_idx) {
++			netdev = mtk_get_tnl_dev(tnl_idx);
++			if (unlikely(IS_ERR(netdev)))
++				netdev = NULL;
++		}
+ 
+-		netdev = eth->netdev[mac];
++		if (!netdev) {
++			if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
++				     !eth->netdev[mac]))
++				goto release_desc;
++
++			netdev = eth->netdev[mac];
++		}
+ 
+ 		if (unlikely(test_bit(MTK_RESETTING, &eth->state)))
+ 			goto release_desc;
+@@ -2294,6 +2307,8 @@ static int mtk_poll_rx(struct napi_struc
+ 		skb_hnat_alg(skb) = 0;
+ 		skb_hnat_filled(skb) = 0;
+ 		skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
++		skb_hnat_set_tops(skb, 0);
++		skb_hnat_set_is_decap(skb, 0);
+ 
+ 		if (skb_hnat_reason(skb) == HIT_BIND_FORCE_TO_CPU) {
+ 			trace_printk("[%s] reason=0x%x(force to CPU) from WAN to Ext\n",
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -1915,6 +1915,9 @@ extern const struct of_device_id of_mtk_
+ extern u32 mtk_hwlro_stats_ebl;
+ extern u32 dbg_show_level;
+ 
++/* tunnel offload related */
++extern struct net_device *(*mtk_get_tnl_dev)(int tnl_idx);
++
+ /* read the hardware status register */
+ void mtk_stats_update_mac(struct mtk_mac *mac);
+ 
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+@@ -43,6 +43,12 @@ void (*ppe_dev_register_hook)(struct net
+ EXPORT_SYMBOL(ppe_dev_register_hook);
+ void (*ppe_dev_unregister_hook)(struct net_device *dev) = NULL;
+ EXPORT_SYMBOL(ppe_dev_unregister_hook);
++int (*mtk_tnl_encap_offload)(struct sk_buff *skb) = NULL;
++EXPORT_SYMBOL(mtk_tnl_encap_offload);
++int (*mtk_tnl_decap_offload)(struct sk_buff *skb) = NULL;
++EXPORT_SYMBOL(mtk_tnl_decap_offload);
++bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb) = NULL;
++EXPORT_SYMBOL(mtk_tnl_decap_offloadable);
+ 
+ static void hnat_sma_build_entry(struct timer_list *t)
+ {
+@@ -53,6 +59,16 @@ static void hnat_sma_build_entry(struct
+ 			     SMA, SMA_FWD_CPU_BUILD_ENTRY);
+ }
+ 
++struct foe_entry *hnat_get_foe_entry(u32 ppe_id, u32 index)
++{
++	if (index == 0x7fff || index >= hnat_priv->foe_etry_num
++	    || ppe_id >= CFG_PPE_NUM)
++		return ERR_PTR(-EINVAL);
++
++	return &hnat_priv->foe_table_cpu[ppe_id][index];
++}
++EXPORT_SYMBOL(hnat_get_foe_entry);
++
+ void hnat_cache_ebl(int enable)
+ {
+ 	int i;
+@@ -63,6 +79,7 @@ void hnat_cache_ebl(int enable)
+ 		cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_EN, enable);
+ 	}
+ }
++EXPORT_SYMBOL(hnat_cache_ebl);
+ 
+ static void hnat_reset_timestamp(struct timer_list *t)
+ {
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+@@ -1140,6 +1140,8 @@ enum FoeIpAct {
+ #define NR_WDMA1_PORT 9
+ #define NR_WDMA2_PORT 13
+ #define NR_GMAC3_PORT 15
++#define NR_TDMA_TPORT 4
++#define NR_TDMA_QDMA_TPORT 5
+ #define LAN_DEV_NAME hnat_priv->lan
+ #define LAN2_DEV_NAME hnat_priv->lan2
+ #define IS_WAN(dev)                                                            \
+@@ -1269,6 +1271,8 @@ static inline bool hnat_dsa_is_enable(st
+ }
+ #endif
+ 
++struct foe_entry *hnat_get_foe_entry(u32 ppe_id, u32 index);
++
+ void hnat_deinit_debugfs(struct mtk_hnat *h);
+ int hnat_init_debugfs(struct mtk_hnat *h);
+ int hnat_register_nf_hooks(void);
+@@ -1285,6 +1289,9 @@ extern int qos_ul_toggle;
+ extern int hook_toggle;
+ extern int mape_toggle;
+ extern int qos_toggle;
++extern int (*mtk_tnl_encap_offload)(struct sk_buff *skb);
++extern int (*mtk_tnl_decap_offload)(struct sk_buff *skb);
++extern bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb);
+ 
+ int ext_if_add(struct extdev_entry *ext_entry);
+ int ext_if_del(struct extdev_entry *ext_entry);
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+@@ -728,10 +728,14 @@ static unsigned int is_ppe_support_type(
+ 	case ETH_P_IP:
+ 		iph = ip_hdr(skb);
+ 
+-		/* do not accelerate non tcp/udp traffic */
+-		if ((iph->protocol == IPPROTO_TCP) ||
++		if (mtk_tnl_decap_offloadable && mtk_tnl_decap_offloadable(skb)) {
++			/* tunnel protocol is offloadable */
++			skb_hnat_set_is_decap(skb, 1);
++			return 1;
++		} else if ((iph->protocol == IPPROTO_TCP) ||
+ 		    (iph->protocol == IPPROTO_UDP) ||
+ 		    (iph->protocol == IPPROTO_IPV6)) {
++			/* do not accelerate non tcp/udp traffic */
+ 			return 1;
+ 		}
+ 
+@@ -848,6 +852,13 @@ mtk_hnat_ipv4_nf_pre_routing(void *priv,
+ 
+ 	hnat_set_head_frags(state, skb, -1, hnat_set_iif);
+ 
++	if (skb_hnat_tops(skb) && skb_hnat_is_decap(skb)
++	    && is_magic_tag_valid(skb)
++	    && skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL
++	    && mtk_tnl_decap_offload && mtk_tnl_decap_offload(skb)) {
++		return NF_ACCEPT;
++	}
++
+ 	/*
+ 	 * Avoid mistakenly binding of outer IP, ports in SW L2TP decap flow.
+ 	 * In pre-routing, if dev is virtual iface, TOPS module is not loaded,
+@@ -923,6 +934,13 @@ mtk_hnat_br_nf_local_in(void *priv, stru
+ 
+ 	hnat_set_head_frags(state, skb, -1, hnat_set_iif);
+ 
++	if (skb_hnat_tops(skb) && skb_hnat_is_decap(skb)
++	    && is_magic_tag_valid(skb)
++	    && skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL
++	    && mtk_tnl_decap_offload && mtk_tnl_decap_offload(skb)) {
++		return NF_ACCEPT;
++	}
++
+ 	pre_routing_print(skb, state->in, state->out, __func__);
+ 
+ 	if (unlikely(debug_level >= 7)) {
+@@ -1075,8 +1093,22 @@ static unsigned int hnat_ipv4_get_nextho
+ 		return -1;
+ 	}
+ 
++	/*
++	 * if this packet is a tunnel packet and is about to construct
++	 * outer header, we must update its outer mac header pointer
++	 * before filling outer mac or it may screw up inner mac
++	 */
++	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) {
++		skb_push(skb, sizeof(struct ethhdr));
++		skb_reset_mac_header(skb);
++	}
++
+ 	memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
+ 	memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN);
++	eth_hdr(skb)->h_proto = htons(ETH_P_IP);
++
++	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
++		skb_pull(skb, sizeof(struct ethhdr));
+ 
+ 	rcu_read_unlock_bh();
+ 
+@@ -1203,6 +1235,81 @@ static struct ethhdr *get_ipv6_ipip_ethh
+ 	return eth;
+ }
+ 
++static inline void hnat_get_filled_unbind_entry(struct sk_buff *skb,
++						struct foe_entry *entry)
++{
++	if (unlikely(!skb || !entry))
++		return;
++
++	memcpy(entry,
++	       &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)],
++	       sizeof(*entry));
++
++#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
++	entry->bfib1.mc = 0;
++#endif /* defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3) */
++	entry->bfib1.ka = 0;
++	entry->bfib1.vlan_layer = 0;
++	entry->bfib1.psn = 0;
++	entry->bfib1.vpm = 0;
++	entry->bfib1.ps = 0;
++}
++
++static inline void hnat_qos_tnl(u32 id, const struct net_device *dev)
++{
++	u32 cfg;
++	u32 max_man = 0;
++	u32 max_exp = 0;
++	const struct mtk_mac *mac;
++
++	if (!dev)
++		return;
++	mac = netdev_priv(dev);
++
++	switch (mac->speed) {
++	case SPEED_100:
++	case SPEED_1000:
++	case SPEED_2500:
++	case SPEED_5000:
++	case SPEED_10000:
++		max_man = mac->speed / SPEED_100;
++		max_exp = 5;
++		break;
++	default:
++		return;
++	}
++
++	cfg = QTX_SCH_MIN_RATE_EN | QTX_SCH_MAX_RATE_EN;
++	cfg |= (1 << QTX_SCH_MIN_RATE_MAN_OFFSET) |
++	       (4 << QTX_SCH_MIN_RATE_EXP_OFFSET) |
++	       (max_man << QTX_SCH_MAX_RATE_MAN_OFFSET) |
++	       (max_exp << QTX_SCH_MAX_RATE_EXP_OFFSET) |
++	       (4 << QTX_SCH_MAX_RATE_WGHT_OFFSET);
++	writel(cfg, hnat_priv->fe_base + QTX_SCH(id % NUM_OF_Q_PER_PAGE));
++}
++
++static inline void hnat_fill_offload_engine_entry(struct sk_buff *skb,
++						  struct foe_entry *entry,
++						  const struct net_device *dev)
++{
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) {
++		/*
++		 * if skb_hnat_tops(skb) is setup for encapsulation,
++		 * we fill in hnat tport and tops_entry for tunnel encapsulation
++		 * offloading
++		 */
++		entry->ipv4_hnapt.tport_id = NR_TDMA_QDMA_TPORT;
++		entry->ipv4_hnapt.tops_entry = skb_hnat_tops(skb);
++	} else {
++		return;
++	}
++
++	entry->ipv4_hnapt.iblk2.qid = 12; /* offload engine use QID 12 */
++	hnat_qos_tnl(12, dev); /* set rate limit to line rate */
++#endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
++}
++
+ static unsigned int skb_to_hnat_info(struct sk_buff *skb,
+ 				     const struct net_device *dev,
+ 				     struct foe_entry *foe,
+@@ -1240,6 +1347,11 @@ static unsigned int skb_to_hnat_info(str
+ 	if (whnat && is_hnat_pre_filled(foe))
+ 		return 0;
+ 
++	if (skb_hnat_tops(skb) && !(hw_path->flags & FLOW_OFFLOAD_PATH_TNL)) {
++		hnat_get_filled_unbind_entry(skb, &entry);
++		goto hnat_entry_bind;
++	}
++
+ 	entry.bfib1.pkt_type = foe->udib1.pkt_type; /* Get packte type state*/
+ 	entry.bfib1.state = foe->udib1.state;
+ 
+@@ -1683,6 +1795,10 @@ static unsigned int skb_to_hnat_info(str
+ 	/* Fill Layer2 Info.*/
+ 	entry = ppe_fill_L2_info(eth, entry, hw_path);
+ 
++	if (skb_hnat_tops(skb) && hw_path->flags & FLOW_OFFLOAD_PATH_TNL)
++		goto hnat_entry_skip_bind;
++
++hnat_entry_bind:
+ 	/* Fill Info Blk*/
+ 	entry = ppe_fill_info_blk(eth, entry, hw_path);
+ 
+@@ -1881,7 +1997,20 @@ static unsigned int skb_to_hnat_info(str
+ 			entry.ipv6_5t_route.act_dp |= UDF_HNAT_PRE_FILLED;
+ 	}
+ 
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	hnat_fill_offload_engine_entry(skb, &entry, dev);
++#endif
++
++hnat_entry_skip_bind:
+ 	wmb();
++
++	/*
++	 * final check before we write BIND info.
++	 * If this entry is already bound, we should not modify it right now
++	 */
++	if (entry_hnat_is_bound(foe))
++		return 0;
++
+ 	memcpy(foe, &entry, sizeof(entry));
+ 	/*reset statistic for this entry*/
+ 	if (hnat_priv->data->per_flow_accounting &&
+@@ -1953,6 +2082,12 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
+ 	switch ((int)entry.bfib1.pkt_type) {
+ 	case IPV4_HNAPT:
+ 	case IPV4_HNAT:
++		/*
++		 * skip if packet is an encap tnl packet or it may
++		 * screw up inner mac header
++		 */
++		if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
++			break;
+ 		entry.ipv4_hnapt.smac_hi = swab32(*((u32 *)eth->h_source));
+ 		entry.ipv4_hnapt.smac_lo = swab16(*((u16 *)&eth->h_source[4]));
+ 		break;
+@@ -2144,6 +2279,10 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
+ 		entry.ipv6_5t_route.iblk2.dp = gmac_no;
+ 	}
+ 
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	hnat_fill_offload_engine_entry(skb, &entry, NULL);
++#endif
++
+ 	entry.bfib1.ttl = 1;
+ 	entry.bfib1.state = BIND;
+ 	if (IS_IPV4_GRP(&entry))
+@@ -2219,6 +2358,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
+ 	}
+ 
+ 	skb_hnat_alg(skb) = 0;
++	skb_hnat_set_tops(skb, 0);
+ 	skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+ 
+ 	if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)
+@@ -2672,6 +2812,7 @@ static unsigned int mtk_hnat_nf_post_rou
+ 	struct flow_offload_hw_path hw_path = { .dev = (struct net_device*)out,
+ 						.virt_dev = (struct net_device*)out };
+ 	const struct net_device *arp_dev = out;
++	bool is_virt_dev = false;
+ 
+ 	if (xlat_toggle && !mtk_464xlat_post_process(skb, out))
+ 		return 0;
+@@ -2691,10 +2832,29 @@ static unsigned int mtk_hnat_nf_post_rou
+ 
+ 	if (out->netdev_ops->ndo_flow_offload_check) {
+ 		out->netdev_ops->ndo_flow_offload_check(&hw_path);
++
+ 		out = (IS_GMAC1_MODE) ? hw_path.virt_dev : hw_path.dev;
++		if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL && mtk_tnl_encap_offload) {
++			if (ntohs(skb->protocol) == ETH_P_IP
++			    && ip_hdr(skb)->protocol == IPPROTO_TCP) {
++				skb_hnat_set_tops(skb, hw_path.tnl_type + 1);
++			} else {
++				/*
++				 * we are not support protocols other than IPv4 TCP
++				 * for tunnel protocol offload yet
++				 */
++				skb_hnat_alg(skb) = 1;
++				return 0;
++			}
++		}
+ 	}
+ 
+ 	if (!IS_LAN_GRP(out) && !IS_WAN(out) && !IS_EXT(out))
++		is_virt_dev = true;
++
++	if (is_virt_dev
++	    && !(skb_hnat_tops(skb) && skb_hnat_is_encap(skb)
++		 && (hw_path.flags & FLOW_OFFLOAD_PATH_TNL)))
+ 		return 0;
+ 
+ 	trace_printk("[%s] case hit, %x-->%s, reason=%x\n", __func__,
+@@ -2714,9 +2874,18 @@ static unsigned int mtk_hnat_nf_post_rou
+ 		if (fn && !mtk_hnat_accel_type(skb))
+ 			break;
+ 
+-		if (fn && fn(skb, arp_dev, &hw_path))
++		if (!is_virt_dev && fn && fn(skb, arp_dev, &hw_path))
+ 			break;
+ 
++		/* skb_hnat_tops(skb) is updated in mtk_tnl_offload() */
++		if (skb_hnat_tops(skb)) {
++			if (skb_hnat_is_encap(skb) && !is_virt_dev
++			    && mtk_tnl_encap_offload && mtk_tnl_encap_offload(skb))
++				break;
++			if (skb_hnat_is_decap(skb))
++				break;
++		}
++
+ 		spin_lock(&hnat_priv->entry_lock);
+ 		skb_to_hnat_info(skb, out, entry, &hw_path);
+ 		spin_unlock(&hnat_priv->entry_lock);
+@@ -2989,7 +3158,7 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
+ 	if (iph->protocol == IPPROTO_IPV6) {
+ 		entry->udib1.pkt_type = IPV6_6RD;
+ 		hnat_set_head_frags(state, skb, 0, hnat_set_alg);
+-	} else {
++	} else if (!skb_hnat_tops(skb)) {
+ 		hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+ 	}
+ 
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
+@@ -44,7 +44,9 @@ struct hnat_desc {
+ 	u32 is_sp : 1;
+ 	u32 hf : 1;
+ 	u32 amsdu : 1;
+-	u32 resv3 : 19;
++	u32 tops : 6;
++	u32 is_decap : 1;
++	u32 resv3 : 12;
+ 	u32 magic_tag_protect : 16;
+ } __packed;
+ #elif defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
+@@ -91,6 +93,19 @@ struct hnat_desc {
+ 	((((skb_headroom(skb) >= FOE_INFO_LEN) ? 1 : 0)))
+ 
+ #define skb_hnat_info(skb) ((struct hnat_desc *)(skb->head))
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++#define skb_hnat_tops(skb) (((struct hnat_desc *)((skb)->head))->tops)
++#define skb_hnat_is_decap(skb) (((struct hnat_desc *)((skb)->head))->is_decap)
++#define skb_hnat_is_encap(skb) (!skb_hnat_is_decap(skb))
++#define skb_hnat_set_tops(skb, tops) ((skb_hnat_tops(skb)) = (tops))
++#define skb_hnat_set_is_decap(skb, is_decap) ((skb_hnat_is_decap(skb)) = (is_decap))
++#else /* !defined(CONFIG_MEDIATEK_NETSYS_V3) */
++#define skb_hnat_tops(skb) (0)
++#define skb_hnat_is_decap(skb) (0)
++#define skb_hnat_is_encap(skb) (0)
++#define skb_hnat_set_tops(skb, tops)
++#define skb_hnat_set_is_decap(skb, is_decap)
++#endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
+ #define skb_hnat_magic(skb) (((struct hnat_desc *)(skb->head))->magic)
+ #define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn)
+ #define skb_hnat_entry(skb) (((struct hnat_desc *)(skb->head))->entry)
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -98,10 +98,21 @@ struct flow_offload {
+ #define FLOW_OFFLOAD_PATH_6RD		BIT(5)
+ #define FLOW_OFFLOAD_PATH_TNL		BIT(6)
+ 
++enum flow_offload_tnl {
++	FLOW_OFFLOAD_TNL_GRETAP,
++	FLOW_OFFLOAD_TNL_PPTP,
++	FLOW_OFFLOAD_TNL_L2TP_V2,
++	FLOW_OFFLOAD_TNL_L2TP_V3,
++	FLOW_OFFLOAD_VXLAN,
++	FLOW_OFFLOAD_NATT,
++	__FLOW_OFFLOAD_MAX,
++};
++
+ struct flow_offload_hw_path {
+ 	struct net_device *dev;
+ 	struct net_device *virt_dev;
+ 	u32 flags;
++	u32 tnl_type;
+ 
+ 	u8 eth_src[ETH_ALEN];
+ 	u8 eth_dest[ETH_ALEN];
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tunnel-network-service-error-recover-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tunnel-network-service-error-recover-support.patch
index 9f9e26a..a2579c0 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tunnel-network-service-error-recover-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tunnel-network-service-error-recover-support.patch
@@ -38,7 +38,7 @@
  
  #define MTK_ETHTOOL_STAT(x) { #x, \
  			      offsetof(struct mtk_hw_stats, x) / sizeof(u64) }
-@@ -4141,6 +4142,8 @@ static void mtk_pending_work(struct work
+@@ -4178,6 +4179,8 @@ static void mtk_pending_work(struct work
  				}
  			pr_warn("wait for MTK_FE_START_RESET\n");
  		}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch
index 96deb54..455ff04 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4102-mtk-crypto-offload-support.patch
@@ -1,21 +1,24 @@
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -1840,6 +1840,11 @@ static void mtk_tx_set_dma_desc_v3(struc
+@@ -1857,6 +1857,12 @@ static void mtk_tx_set_dma_desc_v3(struc
+ 
  	trace_printk("[%s] skb_shinfo(skb)->nr_frags=%x HNAT_SKB_CB2(skb)->magic=%x txd4=%x<-----\n",
  		     __func__, skb_shinfo(skb)->nr_frags, HNAT_SKB_CB2(skb)->magic, data);
- #endif
++
 +	/* forward to eip197 if this packet is going to encrypt */
 +	if (unlikely(skb_hnat_cdrt(skb) && is_magic_tag_valid(skb))) {
 +		data &= ((~TX_DMA_TPORT_MASK) << TX_DMA_TPORT_SHIFT);
 +		data |= (EIP197_QDMA_TPORT & TX_DMA_TPORT_MASK) << TX_DMA_TPORT_SHIFT;
 +	}
+ #endif
  	WRITE_ONCE(desc->txd4, data);
  
- 	data = 0;
-@@ -1862,6 +1867,14 @@ static void mtk_tx_set_dma_desc_v3(struc
+@@ -1880,6 +1886,17 @@ static void mtk_tx_set_dma_desc_v3(struc
  
  	WRITE_ONCE(desc->txd7, 0);
  	WRITE_ONCE(desc->txd8, 0);
++
++#if defined(CONFIG_NET_MEDIATEK_HNAT) || defined(CONFIG_NET_MEDIATEK_HNAT_MODULE)
 +	if (unlikely(skb_hnat_cdrt(skb) && is_magic_tag_valid(skb))) {
 +		/* carry cdrt index for encryption */
 +		data = (skb_hnat_cdrt(skb) & TX_DMA_CDRT_MASK) << TX_DMA_CDRT_SHIFT;
@@ -24,10 +27,11 @@
 +	} else {
 +		WRITE_ONCE(desc->txd8, 0);
 +	}
++#endif
  }
  
  static void mtk_tx_set_dma_desc(struct sk_buff *skb, struct net_device *dev, void *txd,
-@@ -2331,6 +2344,7 @@ static int mtk_poll_rx(struct napi_struc
+@@ -2307,6 +2324,7 @@ static int mtk_poll_rx(struct napi_struc
  
  		skb_hnat_alg(skb) = 0;
  		skb_hnat_filled(skb) = 0;
@@ -37,7 +41,7 @@
  		skb_hnat_set_is_decap(skb, 0);
 --- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
 +++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
-@@ -1076,6 +1076,9 @@ static unsigned int hnat_ipv4_get_nextho
+@@ -1078,6 +1078,9 @@ static unsigned int hnat_ipv4_get_nextho
  		return 0;
  	}
  
@@ -47,7 +51,7 @@
  	rcu_read_lock_bh();
  	nexthop = (__force u32)rt_nexthop(rt, ip_hdr(skb)->daddr);
  	neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
-@@ -1299,6 +1302,9 @@ static inline void hnat_fill_offload_eng
+@@ -1302,6 +1305,9 @@ static inline void hnat_fill_offload_eng
  		 */
  		entry->ipv4_hnapt.tport_id = NR_TDMA_QDMA_TPORT;
  		entry->ipv4_hnapt.tops_entry = skb_hnat_tops(skb);
@@ -57,7 +61,7 @@
  	} else {
  		return;
  	}
-@@ -1308,6 +1314,75 @@ static inline void hnat_fill_offload_eng
+@@ -1311,6 +1317,79 @@ static inline void hnat_fill_offload_eng
  #endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
  }
  
@@ -66,6 +70,7 @@
 +	struct foe_entry entry = { 0 };
 +	struct ethhdr *eth = eth_hdr(skb);
 +	u32 gmac = NR_DISCARD;
++	struct mtk_mac *mac = netdev_priv(dev);
 +
 +	if (skb_hnat_tops(skb) && mtk_tnl_encap_offload)
 +		mtk_tnl_encap_offload(skb);
@@ -89,9 +94,12 @@
 +		else
 +			gmac = NR_GMAC1_PORT;
 +	} else if (IS_LAN2(dev)) {
-+		gmac = NR_GMAC2_PORT;
++		gmac = (mac->id == MTK_GMAC2_ID) ? NR_GMAC2_PORT : NR_GMAC3_PORT;
 +	} else if (IS_WAN(dev)) {
-+		gmac = (IS_GMAC1_MODE) ? NR_GMAC1_PORT : NR_GMAC2_PORT;
++		if (IS_GMAC1_MODE)
++			gmac = NR_GMAC1_PORT;
++		else
++			gmac = (mac->id == MTK_GMAC2_ID) ? NR_GMAC2_PORT : NR_GMAC3_PORT;
 +	} else {
 +		pr_notice("Unknown case of dp, iif=%x --> %s\n", skb_hnat_iface(skb), dev->name);
 +		return -1;
@@ -133,7 +141,7 @@
  static unsigned int skb_to_hnat_info(struct sk_buff *skb,
  				     const struct net_device *dev,
  				     struct foe_entry *foe,
-@@ -2364,6 +2439,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
+@@ -2360,6 +2439,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
  
  	skb_hnat_alg(skb) = 0;
  	skb_hnat_set_tops(skb, 0);
@@ -141,7 +149,7 @@
  	skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
  
  	if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)
-@@ -2450,7 +2526,8 @@ static unsigned int mtk_hnat_accel_type(
+@@ -2446,7 +2526,8 @@ static unsigned int mtk_hnat_accel_type(
  	 * is from local_out which is also filtered in sanity check.
  	 */
  	dst = skb_dst(skb);
@@ -151,7 +159,7 @@
  		return 0;
  
  	ct = nf_ct_get(skb, &ctinfo);
-@@ -2847,6 +2924,14 @@ static unsigned int mtk_hnat_nf_post_rou
+@@ -2850,6 +2931,14 @@ static unsigned int mtk_hnat_nf_post_rou
  		}
  	}
  
@@ -166,7 +174,7 @@
  	if (!IS_LAN_GRP(out) && !IS_WAN(out) && !IS_EXT(out))
  		is_virt_dev = true;
  
-@@ -3157,7 +3242,10 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
+@@ -3159,7 +3248,10 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
  	if (iph->protocol == IPPROTO_IPV6) {
  		entry->udib1.pkt_type = IPV6_6RD;
  		hnat_set_head_frags(state, skb, 0, hnat_set_alg);
@@ -220,7 +228,7 @@
  {
 --- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
 +++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
-@@ -1135,6 +1135,8 @@ enum FoeIpAct {
+@@ -1140,6 +1140,8 @@ enum FoeIpAct {
  #define NR_WDMA1_PORT 9
  #define NR_WDMA2_PORT 13
  #define NR_GMAC3_PORT 15
@@ -229,7 +237,7 @@
  #define NR_TDMA_TPORT 4
  #define NR_TDMA_QDMA_TPORT 5
  #define LAN_DEV_NAME hnat_priv->lan
-@@ -1288,6 +1290,8 @@ extern int qos_toggle;
+@@ -1292,6 +1294,8 @@ extern int qos_toggle;
  extern int (*mtk_tnl_encap_offload)(struct sk_buff *skb);
  extern int (*mtk_tnl_decap_offload)(struct sk_buff *skb);
  extern bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb);
@@ -240,7 +248,7 @@
  int ext_if_del(struct extdev_entry *ext_entry);
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -551,6 +551,10 @@
+@@ -558,6 +558,10 @@
  
  #define MTK_QDMA_GMAC2_QID	8
  
@@ -251,7 +259,7 @@
  /* QDMA V2 descriptor txd6 */
  #define TX_DMA_INS_VLAN_V2         BIT(16)
  
-@@ -560,6 +564,9 @@
+@@ -567,6 +571,9 @@
  #define TX_DMA_SPTAG_V3            BIT(27)
  
  /* QDMA V2 descriptor txd4 */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4103-mtk-tunnel-crypto-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4103-mtk-tunnel-crypto-offload-support.patch
index 608bc91..b96f080 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4103-mtk-tunnel-crypto-offload-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4103-mtk-tunnel-crypto-offload-support.patch
@@ -1,6 +1,6 @@
 --- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
 +++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
-@@ -1139,6 +1139,8 @@ enum FoeIpAct {
+@@ -1144,6 +1144,8 @@ enum FoeIpAct {
  #define NR_EIP197_QDMA_TPORT 3
  #define NR_TDMA_TPORT 4
  #define NR_TDMA_QDMA_TPORT 5
@@ -21,9 +21,9 @@
  		skb_push(skb, sizeof(struct ethhdr));
  		skb_reset_mac_header(skb);
  	}
-@@ -1109,7 +1110,8 @@ static unsigned int hnat_ipv4_get_nextho
- 	memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
+@@ -1110,7 +1111,8 @@ static unsigned int hnat_ipv4_get_nextho
  	memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN);
+ 	eth_hdr(skb)->h_proto = htons(ETH_P_IP);
  
 -	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
 +	if ((skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
@@ -31,7 +31,7 @@
  		skb_pull(skb, sizeof(struct ethhdr));
  
  	rcu_read_unlock_bh();
-@@ -1257,6 +1259,38 @@ static inline void hnat_get_filled_unbin
+@@ -1258,6 +1260,38 @@ static inline void hnat_get_filled_unbin
  	entry->bfib1.ps = 0;
  }
  
@@ -70,7 +70,7 @@
  static inline void hnat_qos_tnl(u32 id, const struct net_device *dev)
  {
  	u32 cfg;
-@@ -1301,9 +1335,15 @@ static inline void hnat_fill_offload_eng
+@@ -1302,9 +1336,15 @@ static inline void hnat_fill_offload_eng
  		 * we fill in hnat tport and tops_entry for tunnel encapsulation
  		 * offloading
  		 */
@@ -88,7 +88,7 @@
  		entry->ipv4_hnapt.tport_id = NR_EIP197_QDMA_TPORT;
  		entry->ipv4_hnapt.cdrt_id = skb_hnat_cdrt(skb);
  	} else {
-@@ -1404,6 +1444,7 @@ static unsigned int skb_to_hnat_info(str
+@@ -1405,6 +1445,7 @@ static unsigned int skb_to_hnat_info(str
  	u32 port_id = 0;
  	u32 payload_len = 0;
  	int mape = 0;
@@ -96,7 +96,7 @@
  	struct mtk_mac *mac = netdev_priv(dev);
  
  	ct = nf_ct_get(skb, &ctinfo);
-@@ -1421,9 +1462,12 @@ static unsigned int skb_to_hnat_info(str
+@@ -1422,9 +1463,12 @@ static unsigned int skb_to_hnat_info(str
  	if (whnat && is_hnat_pre_filled(foe))
  		return 0;
  
@@ -110,7 +110,7 @@
  	}
  
  	entry.bfib1.pkt_type = foe->udib1.pkt_type; /* Get packte type state*/
-@@ -1869,7 +1913,9 @@ static unsigned int skb_to_hnat_info(str
+@@ -1870,7 +1914,9 @@ static unsigned int skb_to_hnat_info(str
  	/* Fill Layer2 Info.*/
  	entry = ppe_fill_L2_info(eth, entry, hw_path);
  
@@ -121,7 +121,7 @@
  		goto hnat_entry_skip_bind;
  
  hnat_entry_bind:
-@@ -2445,6 +2491,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
+@@ -2435,6 +2481,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
  	skb_hnat_alg(skb) = 0;
  	skb_hnat_set_tops(skb, 0);
  	skb_hnat_set_cdrt(skb, 0);
@@ -129,7 +129,7 @@
  	skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
  
  	if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)
-@@ -3248,7 +3295,8 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
+@@ -3244,7 +3291,8 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
  		entry->udib1.pkt_type = IPV6_6RD;
  		hnat_set_head_frags(state, skb, 0, hnat_set_alg);
  	} else if (is_magic_tag_valid(skb)
@@ -141,7 +141,7 @@
  		hnat_set_head_frags(state, skb, 1, hnat_set_alg);
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -2306,10 +2306,11 @@ static int mtk_poll_rx(struct napi_struc
+@@ -2324,10 +2324,11 @@ static int mtk_poll_rx(struct napi_struc
  
  		skb_hnat_alg(skb) = 0;
  		skb_hnat_filled(skb) = 0;
@@ -156,7 +156,7 @@
  			trace_printk("[%s] reason=0x%x(force to CPU) from WAN to Ext\n",
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -652,6 +652,9 @@
+@@ -656,6 +656,9 @@
  #define RX_DMA_GET_AGG_CNT_V2(_x)	(((_x) >> 16) & 0xff)
  #define RX_DMA_GET_TOPS_CRSN(_x)	(((_x) >> 24) & 0xff)
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-ppp-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-ppp-offload-support.patch
new file mode 100644
index 0000000..1409f9f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-ppp-offload-support.patch
@@ -0,0 +1,65 @@
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -296,6 +296,9 @@ static void unit_put(struct idr *p, int
+ static void *unit_find(struct idr *p, int n);
+ static void ppp_setup(struct net_device *dev);
+ 
++struct sock *ppp_netdev_get_sock(struct net_device *dev);
++EXPORT_SYMBOL(ppp_netdev_get_sock);
++
+ static const struct net_device_ops ppp_netdev_ops;
+ 
+ static struct class *ppp_class;
+@@ -1660,6 +1663,40 @@ ppp_send_frame(struct ppp *ppp, struct s
+ 	++ppp->dev->stats.tx_errors;
+ }
+ 
++struct sock *ppp_netdev_get_sock(struct net_device *dev)
++{
++	struct list_head *list;
++	struct channel *pch;
++	struct ppp *ppp;
++	struct sock *sk;
++
++	if (!dev)
++		return ERR_PTR(-EINVAL);
++
++	ppp = netdev_priv(dev);
++
++	list = &ppp->channels;
++	if (list_empty(list))
++		 /* nowhere to send the packet */
++		return ERR_PTR(-EINVAL);
++
++	if (ppp->flags & SC_MULTILINK)
++		/* not doing multilink: send it down the first channel */
++		return ERR_PTR(-EPERM);
++
++	list = list->next;
++	pch = list_entry(list, struct channel, clist);
++
++	spin_lock(&pch->downl);
++	if (pch->chan)
++		sk = (struct sock *)pch->chan->private;
++	else
++		sk = ERR_PTR(-EINVAL);
++	spin_unlock(&pch->downl);
++
++	return sk;
++}
++
+ /*
+  * Try to send the frame in xmit_pending.
+  * The caller should have the xmit path locked.
+--- a/include/linux/ppp_channel.h
++++ b/include/linux/ppp_channel.h
+@@ -75,6 +75,9 @@ extern int ppp_unit_number(struct ppp_ch
+ /* Get the device name associated with a channel, or NULL if none */
+ extern char *ppp_dev_name(struct ppp_channel *);
+ 
++/* Get the socket structure of a given ppp netdev */
++extern struct sock *ppp_netdev_get_sock(struct net_device *dev);
++
+ /*
+  * SMP locking notes:
+  * The channel code must ensure that when it calls ppp_unregister_channel,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-l2tp-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4501-mtk-l2tp-offload-support.patch
similarity index 90%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-l2tp-offload-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4501-mtk-l2tp-offload-support.patch
index e6583b6..5e16ba8 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-l2tp-offload-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4501-mtk-l2tp-offload-support.patch
@@ -13,7 +13,7 @@
  	 * make room. Adjust truesize.
 --- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
 +++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
-@@ -855,7 +855,8 @@ mtk_hnat_ipv4_nf_pre_routing(void *priv,
+@@ -865,7 +865,8 @@ mtk_hnat_ipv4_nf_pre_routing(void *priv,
  	 * and it's L2TP flow, then do not bind.
  	 */
  	if (skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL
@@ -29,7 +29,7 @@
  		return -EINVAL;
  
  	path->flags |= FLOW_OFFLOAD_PATH_TNL;
-+	path->tnl_type = FLOW_OFFLOAD_TNL_UDP_L2TP_DATA;
++	path->tnl_type = FLOW_OFFLOAD_TNL_L2TP_V2;
  
  	return 0;
  }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4501-mtk-pptp-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4501-mtk-pptp-offload-support.patch
new file mode 100644
index 0000000..ec218e1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4501-mtk-pptp-offload-support.patch
@@ -0,0 +1,100 @@
+--- a/drivers/net/ppp/pptp.c
++++ b/drivers/net/ppp/pptp.c
+@@ -33,6 +33,7 @@
+ #include <net/route.h>
+ #include <net/gre.h>
+ #include <net/pptp.h>
++#include <net/netfilter/nf_flow_table.h>
+ 
+ #include <linux/uaccess.h>
+ 
+@@ -40,6 +41,9 @@
+ 
+ #define MAX_CALLID 65535
+ 
++int (*mtk_pptp_seq_next)(u16 call_id, u32 *val) = NULL;
++EXPORT_SYMBOL(mtk_pptp_seq_next);
++
+ static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1);
+ static struct pppox_sock __rcu **callid_sock;
+ 
+@@ -128,6 +132,26 @@ static void del_chan(struct pppox_sock *
+ 	spin_unlock(&chan_lock);
+ }
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int pptp_flow_offload_check(struct ppp_channel *chan,
++				   struct flow_offload_hw_path *path)
++{
++	struct sock *sk = (struct sock *)chan->private;
++	struct pppox_sock *po = pppox_sk(sk);
++
++	if (path->flags & FLOW_OFFLOAD_PATH_TNL)
++		return -EEXIST;
++
++	if (sk_pppox(po)->sk_state & PPPOX_DEAD)
++		return -EINVAL;
++
++	path->flags |= FLOW_OFFLOAD_PATH_TNL;
++	path->tnl_type = FLOW_OFFLOAD_TNL_PPTP;
++
++	return 0;
++}
++#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
++
+ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+ {
+ 	struct sock *sk = (struct sock *) chan->private;
+@@ -140,6 +164,7 @@ static int pptp_xmit(struct ppp_channel
+ 	int islcp;
+ 	int len;
+ 	unsigned char *data;
++	u32 seq_sent_hw;
+ 	__u32 seq_recv;
+ 
+ 
+@@ -204,7 +229,14 @@ static int pptp_xmit(struct ppp_channel
+ 	hdr->gre_hd.protocol = GRE_PROTO_PPP;
+ 	hdr->call_id = htons(opt->dst_addr.call_id);
+ 
+-	hdr->seq = htonl(++opt->seq_sent);
++	if (mtk_pptp_seq_next && !mtk_pptp_seq_next(opt->dst_addr.call_id,
++						    &seq_sent_hw)) {
++		opt->seq_sent = seq_sent_hw;
++		hdr->seq = htonl(opt->seq_sent);
++	} else {
++		hdr->seq = htonl(++opt->seq_sent);
++	}
++
+ 	if (opt->ack_sent != seq_recv)	{
+ 		/* send ack with this message */
+ 		hdr->gre_hd.flags |= GRE_ACK;
+@@ -598,6 +630,9 @@ static int pptp_ppp_ioctl(struct ppp_cha
+ static const struct ppp_channel_ops pptp_chan_ops = {
+ 	.start_xmit = pptp_xmit,
+ 	.ioctl      = pptp_ppp_ioctl,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.flow_offload_check = pptp_flow_offload_check,
++#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
+ };
+ 
+ static struct proto pptp_sk_proto __read_mostly = {
+--- a/include/net/pptp.h
++++ b/include/net/pptp.h
+@@ -2,6 +2,8 @@
+ #ifndef _NET_PPTP_H
+ #define _NET_PPTP_H
+ 
++#include <net/gre.h>
++
+ #define PPP_LCP_ECHOREQ 0x09
+ #define PPP_LCP_ECHOREP 0x0A
+ #define SC_RCV_BITS     (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
+@@ -20,5 +22,7 @@ struct pptp_gre_header {
+ 	__be32 ack;
+ } __packed;
+ 
++/* symbol exported from linux kernel driver/net/ppp/pptp.c */
++extern int (*mtk_pptp_seq_next)(uint16_t call_id, uint32_t *val);
+ 
+ #endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1050-v6.4-backport-jitterrng-2.2.0.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1050-v6.4-backport-jitterrng-2.2.0.patch
new file mode 100644
index 0000000..3e85026
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1050-v6.4-backport-jitterrng-2.2.0.patch
@@ -0,0 +1,1158 @@
+diff --git a/crypto/Makefile b/crypto/Makefile
+index 4e7a0a8f7..2b5a2a9c8 100644
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -156,6 +156,7 @@ CFLAGS_jitterentropy.o = -O0
+ KASAN_SANITIZE_jitterentropy.o = n
+ UBSAN_SANITIZE_jitterentropy.o = n
+ jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o
++jitterentropy_rng-$(CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG) += jitterentropy-dbg.o
+ obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
+ obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
+ obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
+diff --git a/crypto/jitterentropy-dbg.c b/crypto/jitterentropy-dbg.c
+new file mode 100644
+index 000000000..2e7e98b9a
+--- /dev/null
++++ b/crypto/jitterentropy-dbg.c
+@@ -0,0 +1,242 @@
++/*
++ * Non-physical true random number generator based on timing jitter - DebugFS
++ *
++ * Copyright Stephan Mueller <smueller@chronox.de>, 2013
++ *
++ * License
++ * =======
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ *
++ * ALTERNATIVELY, this product may be distributed under the terms of
++ * the GNU General Public License, in which case the provisions of the GPL are
++ * required INSTEAD OF the above restrictions.  (This clause is
++ * necessary due to a potential bad interaction between the GPL and
++ * the restrictions contained in a BSD-style copyright.)
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <asm/uaccess.h>
++#include <linux/string.h>
++#include <linux/compat.h>
++#include <linux/export.h>
++#include <linux/file.h>
++#include <linux/debugfs.h>
++
++#include "jitterentropy.h"
++#include "jitterentropy-dbg.h"
++
++struct jent_debugfs {
++	struct dentry *jent_debugfs_root;
++	struct dentry *jent_debugfs_entropy;
++	struct dentry *jent_debugfs_noise;
++};
++
++struct jent_raw
++{
++	spinlock_t raw_lock;
++	struct rand_data *entropy_collector;
++};
++
++static struct jent_debugfs jent_debugfs;
++static struct jent_raw raw_entropy;
++
++void jent_drng_cleanup_raw(struct jent_raw *raw)
++{
++	spin_lock_bh(&raw->raw_lock);
++	if (NULL != raw->entropy_collector)
++		jent_entropy_collector_free(raw->entropy_collector);
++	raw->entropy_collector = NULL;
++	spin_unlock_bh(&raw->raw_lock);
++}
++
++int jent_drng_get_bytes_raw(struct jent_raw *raw, char *data, size_t len)
++{
++	int ret = 0;
++
++	spin_lock_bh(&raw->raw_lock);
++	ret = jent_read_entropy(raw->entropy_collector, data, len);
++	if (0 > ret) {
++		printk(DRIVER_NAME": Unable to obtain %zu bytes of entropy\n", len);
++		ret = -EAGAIN;
++	}
++
++	spin_unlock_bh(&raw->raw_lock);
++	return ret;
++}
++
++
++static inline int jent_dbg_raw_bytes(char *data, size_t len)
++{
++        return jent_drng_get_bytes_raw(&raw_entropy, data, len);
++}
++
++static ssize_t jent_debugfs_read_func(struct file *file,
++				      char __user *buf, size_t nbytes,
++				      loff_t *ppos, size_t chunk,
++				      int (*source)(char *out, size_t len))
++{
++	ssize_t total = 0;
++	int ret = 0;
++	loff_t pos = *ppos;
++	char *out;
++
++	if (!nbytes)
++		return -EINVAL;
++
++	out = kzalloc(chunk, GFP_KERNEL);
++	if (!out)
++		return -ENOMEM;
++
++	while (nbytes > 0) {
++		int copy = min_t(int, chunk, nbytes);
++		ret = source(out, copy);
++		if (0 > ret) {
++			printk(DRIVER_NAME": could not obtain random data: %d\n", ret);
++			ret = -EAGAIN;
++			break;
++		}
++		if (copy_to_user(buf+pos+total, out, ret)) {
++			ret = -EFAULT;
++			break;
++		}
++		nbytes -= ret;
++		total += ret;
++	}
++	kzfree(out);
++
++	return ((0 > ret) ? ret : total);
++}
++
++static ssize_t jent_debugfs_noise_read(struct file *file, char __user *buf,
++			      size_t nbytes, loff_t *ppos)
++{
++	struct rand_data *ec = raw_entropy.entropy_collector;
++	int total = 0;
++	loff_t pos = *ppos;
++	char *out;
++
++	out = kzalloc(8, GFP_KERNEL);
++
++	while (nbytes > 0) {
++		int len = min_t(int, 8, nbytes);
++		jent_lfsr_time(ec, 0, 0, 0);
++		memcpy(out, &ec->data, len);
++		if (copy_to_user(buf+pos+total, out, len)) {
++			break;
++		}
++		nbytes -= len;
++		total += len;
++	}
++	kzfree(out);
++	return total;
++
++}
++static ssize_t jent_debugfs_seed_read(struct file *file, char __user *buf,
++			      size_t nbytes, loff_t *ppos)
++{
++	int ret = jent_debugfs_read_func(file, buf, nbytes, ppos, 8,
++				      jent_dbg_raw_bytes);
++	return ret;
++}
++
++int jent_drng_init_raw(struct jent_raw *raw, unsigned int flags)
++{
++	int ret = 0;
++
++	raw->entropy_collector = jent_entropy_collector_alloc(1, flags);
++	if (!raw->entropy_collector)
++		ret = -ENOMEM;
++
++	spin_lock_init(&raw->raw_lock);
++	return ret;
++}
++
++static struct file_operations jent_seed_fops = {
++	.owner = THIS_MODULE,
++	.read = jent_debugfs_seed_read,
++};
++
++static struct file_operations jent_noise_fops = {
++	.owner = THIS_MODULE,
++	.read = jent_debugfs_noise_read,
++};
++
++
++int __init jent_dbg_init(void)
++{
++	int ret = -EINVAL;
++	jent_debugfs.jent_debugfs_root = NULL;
++	jent_debugfs.jent_debugfs_noise = NULL;
++	jent_debugfs.jent_debugfs_entropy = NULL;
++
++	ret = jent_drng_init_raw(&raw_entropy, JENT_DISABLE_STIR);
++	if (ret) {
++		printk(DRIVER_NAME": Raw entropy collector instantiation failed\n");
++		return ret;
++	}
++	jent_debugfs.jent_debugfs_root =
++		debugfs_create_dir(DRIVER_NAME, NULL);
++	if (IS_ERR(jent_debugfs.jent_debugfs_root)) {
++		printk(DRIVER_NAME": initialization of debugfs directory failed\n");
++		goto cleandir;
++	}
++
++	jent_debugfs.jent_debugfs_entropy =
++		debugfs_create_file("entropy", S_IRUGO,
++		jent_debugfs.jent_debugfs_root,
++		NULL, &jent_seed_fops);
++	if (IS_ERR(jent_debugfs.jent_debugfs_entropy)) {
++		printk(DRIVER_NAME": initialization of entropy file failed\n");
++		goto cleandir;
++	}
++
++	jent_debugfs.jent_debugfs_noise =
++		debugfs_create_file("noise", S_IRUGO,
++		jent_debugfs.jent_debugfs_root,
++		NULL, &jent_noise_fops);
++	if (IS_ERR(jent_debugfs.jent_debugfs_noise)) {
++		printk(DRIVER_NAME": initialization of noise file failed\n");
++		goto cleandir;
++	}
++	return 0;
++
++cleandir:
++	debugfs_remove_recursive(jent_debugfs.jent_debugfs_root);
++	jent_drng_cleanup_raw(&raw_entropy);
++
++	return ret;
++}
++
++void jent_dbg_exit(void)
++{
++	debugfs_remove_recursive(jent_debugfs.jent_debugfs_root);
++	jent_drng_cleanup_raw(&raw_entropy);
++}
+diff --git a/crypto/jitterentropy-dbg.h b/crypto/jitterentropy-dbg.h
+new file mode 100644
+index 000000000..921bd65dc
+--- /dev/null
++++ b/crypto/jitterentropy-dbg.h
+@@ -0,0 +1,49 @@
++/*
++ * Non-physical true random number generator based on timing jitter.
++ *
++ * Copyright Stephan Mueller <smueller@chronox.de>, 2013
++ *
++ * License
++ * =======
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, and the entire permission notice in its entirety,
++ *    including the disclaimer of warranties.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote
++ *    products derived from this software without specific prior
++ *    written permission.
++ *
++ * ALTERNATIVELY, this product may be distributed under the terms of
++ * the GNU General Public License, in which case the provisions of the GPL are
++ * required INSTEAD OF the above restrictions.  (This clause is
++ * necessary due to a potential bad interaction between the GPL and
++ * the restrictions contained in a BSD-style copyright.)
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef _JITTERENTROPY_DBG_KERNEL_H
++#define _JITTERENTROPY_DBG_KERNEL_H
++
++int __init jent_dbg_init(void);
++void jent_dbg_exit(void);
++
++
++#endif /* _JITTERENTROPY_DBG_KERNEL_H */
+diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c
+index 701b8d86a..7a3691fab 100644
+--- a/crypto/jitterentropy-kcapi.c
++++ b/crypto/jitterentropy-kcapi.c
+@@ -44,13 +44,11 @@
+ #include <linux/crypto.h>
+ #include <crypto/internal/rng.h>
+ 
+-struct rand_data;
+-int jent_read_entropy(struct rand_data *ec, unsigned char *data,
+-		      unsigned int len);
+-int jent_entropy_init(void);
+-struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
+-					       unsigned int flags);
+-void jent_entropy_collector_free(struct rand_data *entropy_collector);
++#include "jitterentropy.h"
++
++#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG
++#include "jitterentropy-dbg.h"
++#endif
+ 
+ /***************************************************************************
+  * Helper function
+@@ -148,7 +146,31 @@ static int jent_kcapi_random(struct crypto_rng *tfm,
+ 	int ret = 0;
+ 
+ 	spin_lock(&rng->jent_lock);
++
+ 	ret = jent_read_entropy(rng->entropy_collector, rdata, dlen);
++
++	if (ret == -3) {
++		/* Handle permanent health test error */
++		/*
++		 * If the kernel was booted with fips=1, it implies that
++		 * the entire kernel acts as a FIPS 140 module. In this case
++		 * an SP800-90B permanent health test error is treated as
++		 * a FIPS module error.
++		 */
++		if (fips_enabled)
++			panic("Jitter RNG permanent health test failure\n");
++
++		pr_err("Jitter RNG permanent health test failure\n");
++		ret = -EFAULT;
++	} else if (ret == -2) {
++		/* Handle intermittent health test error */
++		pr_warn_ratelimited("Reset Jitter RNG due to intermittent health test failure\n");
++		ret = -EAGAIN;
++	} else if (ret == -1) {
++		/* Handle other errors */
++		ret = -EINVAL;
++	}
++
+ 	spin_unlock(&rng->jent_lock);
+ 
+ 	return ret;
+@@ -182,15 +204,31 @@ static int __init jent_mod_init(void)
+ 
+ 	ret = jent_entropy_init();
+ 	if (ret) {
++		/* Handle permanent health test error */
++		if (fips_enabled)
++			panic("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret);
++
+ 		pr_info("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret);
+ 		return -EFAULT;
+ 	}
++
++#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG
++	ret = jent_dbg_init();
++#endif
++	if(ret)
++		return ret;
++	printk("Debug interface error\n");
+ 	return crypto_register_rng(&jent_alg);
++
+ }
+ 
+ static void __exit jent_mod_exit(void)
+ {
+ 	crypto_unregister_rng(&jent_alg);
++
++#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG
++	jent_dbg_exit();
++#endif
+ }
+ 
+ module_init(jent_mod_init);
+diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c
+index 77fa2120f..fea7a6d42 100644
+--- a/crypto/jitterentropy.c
++++ b/crypto/jitterentropy.c
+@@ -2,12 +2,12 @@
+  * Non-physical true random number generator based on timing jitter --
+  * Jitter RNG standalone code.
+  *
+- * Copyright Stephan Mueller <smueller@chronox.de>, 2015 - 2019
++ * Copyright Stephan Mueller <smueller@chronox.de>, 2015 - 2020
+  *
+  * Design
+  * ======
+  *
+- * See http://www.chronox.de/jent.html
++ * See https://www.chronox.de/jent.html
+  *
+  * License
+  * =======
+@@ -47,7 +47,7 @@
+ 
+ /*
+  * This Jitterentropy RNG is based on the jitterentropy library
+- * version 2.1.2 provided at http://www.chronox.de/jent.html
++ * version 2.2.0 provided at https://www.chronox.de/jent.html
+  */
+ 
+ #ifdef __OPTIMIZE__
+@@ -58,32 +58,8 @@ typedef	unsigned long long	__u64;
+ typedef	long long		__s64;
+ typedef	unsigned int		__u32;
+ #define NULL    ((void *) 0)
++#include "jitterentropy.h"
+ 
+-/* The entropy pool */
+-struct rand_data {
+-	/* all data values that are vital to maintain the security
+-	 * of the RNG are marked as SENSITIVE. A user must not
+-	 * access that information while the RNG executes its loops to
+-	 * calculate the next random value. */
+-	__u64 data;		/* SENSITIVE Actual random number */
+-	__u64 old_data;		/* SENSITIVE Previous random number */
+-	__u64 prev_time;	/* SENSITIVE Previous time stamp */
+-#define DATA_SIZE_BITS ((sizeof(__u64)) * 8)
+-	__u64 last_delta;	/* SENSITIVE stuck test */
+-	__s64 last_delta2;	/* SENSITIVE stuck test */
+-	unsigned int osr;	/* Oversample rate */
+-#define JENT_MEMORY_BLOCKS 64
+-#define JENT_MEMORY_BLOCKSIZE 32
+-#define JENT_MEMORY_ACCESSLOOPS 128
+-#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
+-	unsigned char *mem;	/* Memory access location with size of
+-				 * memblocks * memblocksize */
+-	unsigned int memlocation; /* Pointer to byte in *mem */
+-	unsigned int memblocks;	/* Number of memory blocks in *mem */
+-	unsigned int memblocksize; /* Size of one memory block in bytes */
+-	unsigned int memaccessloops; /* Number of memory accesses per random
+-				      * bit generation */
+-};
+ 
+ /* Flags that can be used to initialize the RNG */
+ #define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more
+@@ -98,19 +74,187 @@ struct rand_data {
+ 				   * variations (2nd derivation of time is
+ 				   * zero). */
+ #define JENT_ESTUCK		8 /* Too many stuck results during init. */
++#define JENT_EHEALTH		9 /* Health test failed during initialization */
++
++/*
++ * The output n bits can receive more than n bits of min entropy, of course,
++ * but the fixed output of the conditioning function can only asymptotically
++ * approach the output size bits of min entropy, not attain that bound. Random
++ * maps will tend to have output collisions, which reduces the creditable
++ * output entropy (that is what SP 800-90B Section 3.1.5.1.2 attempts to bound).
++ *
++ * The value "64" is justified in Appendix A.4 of the current 90C draft,
++ * and aligns with NIST's in "epsilon" definition in this document, which is
++ * that a string can be considered "full entropy" if you can bound the min
++ * entropy in each bit of output to at least 1-epsilon, where epsilon is
++ * required to be <= 2^(-32).
++ */
++#define JENT_ENTROPY_SAFETY_FACTOR	64
++
++#include <linux/fips.h>
++#include <linux/printk.h>
++
++/***************************************************************************
++ * Adaptive Proportion Test
++ *
++ * This test complies with SP800-90B section 4.4.2.
++ ***************************************************************************/
++
++/*
++ * Reset the APT counter
++ *
++ * @ec [in] Reference to entropy collector
++ */
++static void jent_apt_reset(struct rand_data *ec, unsigned int delta_masked)
++{
++	/* Reset APT counter */
++	ec->apt_count = 0;
++	ec->apt_base = delta_masked;
++	ec->apt_observations = 0;
++}
++
++/*
++ * Insert a new entropy event into APT
++ *
++ * @ec [in] Reference to entropy collector
++ * @delta_masked [in] Masked time delta to process
++ */
++static void jent_apt_insert(struct rand_data *ec, unsigned int delta_masked)
++{
++	/* Initialize the base reference */
++	if (!ec->apt_base_set) {
++		ec->apt_base = delta_masked;
++		ec->apt_base_set = 1;
++		return;
++	}
++
++	if (delta_masked == ec->apt_base)
++		ec->apt_count++;
++
++	ec->apt_observations++;
++
++	if (ec->apt_observations >= JENT_APT_WINDOW_SIZE)
++		jent_apt_reset(ec, delta_masked);
++}
++
++/* APT health test failure detection */
++static int jent_apt_permanent_failure(struct rand_data *ec)
++{
++	return (ec->apt_count >= JENT_APT_CUTOFF_PERMANENT) ? 1 : 0;
++}
++
++static int jent_apt_failure(struct rand_data *ec)
++{
++	return (ec->apt_count >= JENT_APT_CUTOFF) ? 1 : 0;
++}
+ 
+ /***************************************************************************
+- * Helper functions
++ * Stuck Test and its use as Repetition Count Test
++ *
++ * The Jitter RNG uses an enhanced version of the Repetition Count Test
++ * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical
++ * back-to-back values, the input to the RCT is the counting of the stuck
++ * values during the generation of one Jitter RNG output block.
++ *
++ * The RCT is applied with an alpha of 2^{-30} compliant to FIPS 140-2 IG 9.8.
++ *
++ * During the counting operation, the Jitter RNG always calculates the RCT
++ * cut-off value of C. If that value exceeds the allowed cut-off value,
++ * the Jitter RNG output block will be calculated completely but discarded at
++ * the end. The caller of the Jitter RNG is informed with an error code.
+  ***************************************************************************/
+ 
+-void jent_get_nstime(__u64 *out);
+-void *jent_zalloc(unsigned int len);
+-void jent_zfree(void *ptr);
+-int jent_fips_enabled(void);
+-void jent_panic(char *s);
+-void jent_memcpy(void *dest, const void *src, unsigned int n);
++/*
++ * Repetition Count Test as defined in SP800-90B section 4.4.1
++ *
++ * @ec [in] Reference to entropy collector
++ * @stuck [in] Indicator whether the value is stuck
++ */
++static void jent_rct_insert(struct rand_data *ec, int stuck)
++{
++	if (stuck) {
++		ec->rct_count++;
++	} else {
++		/* Reset RCT */
++		ec->rct_count = 0;
++	}
++}
++
++static inline __u64 jent_delta(__u64 prev, __u64 next)
++{
++#define JENT_UINT64_MAX		(__u64)(~((__u64) 0))
++	return (prev < next) ? (next - prev) :
++			       (JENT_UINT64_MAX - prev + 1 + next);
++}
++
++/*
++ * Stuck test by checking the:
++ * 	1st derivative of the jitter measurement (time delta)
++ * 	2nd derivative of the jitter measurement (delta of time deltas)
++ * 	3rd derivative of the jitter measurement (delta of delta of time deltas)
++ *
++ * All values must always be non-zero.
++ *
++ * @ec [in] Reference to entropy collector
++ * @current_delta [in] Jitter time delta
++ *
++ * @return
++ * 	0 jitter measurement not stuck (good bit)
++ * 	1 jitter measurement stuck (reject bit)
++ */
++static int jent_stuck(struct rand_data *ec, __u64 current_delta)
++{
++	__u64 delta2 = jent_delta(ec->last_delta, current_delta);
++	__u64 delta3 = jent_delta(ec->last_delta2, delta2);
++
++	ec->last_delta = current_delta;
++	ec->last_delta2 = delta2;
++
++	/*
++	 * Insert the result of the comparison of two back-to-back time
++	 * deltas.
++	 */
++	jent_apt_insert(ec, current_delta);
++
++	if (!current_delta || !delta2 || !delta3) {
++		/* RCT with a stuck bit */
++		jent_rct_insert(ec, 1);
++		return 1;
++	}
++
++	/* RCT with a non-stuck bit */
++	jent_rct_insert(ec, 0);
++
++	return 0;
++}
++
++/* RCT health test failure detection */
++static int jent_rct_permanent_failure(struct rand_data *ec)
++{
++	return (ec->rct_count >= JENT_RCT_CUTOFF_PERMANENT) ? 1 : 0;
++}
++
++static int jent_rct_failure(struct rand_data *ec)
++{
++	return (ec->rct_count >= JENT_RCT_CUTOFF) ? 1 : 0;
++}
++
++/* Report of health test failures */
++static int jent_health_failure(struct rand_data *ec)
++{
++	return jent_rct_failure(ec) | jent_apt_failure(ec);
++}
++
++static int jent_permanent_health_failure(struct rand_data *ec)
++{
++	return jent_rct_permanent_failure(ec) | jent_apt_permanent_failure(ec);
++}
++
++/***************************************************************************
++ * Noise sources
++ ***************************************************************************/
+ 
+-/**
++/*
+  * Update of the loop count used for the next round of
+  * an entropy collection.
+  *
+@@ -153,11 +297,7 @@ static __u64 jent_loop_shuffle(struct rand_data *ec,
+ 	return (shuffle + (1<<min));
+ }
+ 
+-/***************************************************************************
+- * Noise sources
+- ***************************************************************************/
+-
+-/**
++/*
+  * CPU Jitter noise source -- this is the noise source based on the CPU
+  *			      execution time jitter
+  *
+@@ -171,18 +311,19 @@ static __u64 jent_loop_shuffle(struct rand_data *ec,
+  * the CPU execution time jitter. Any change to the loop in this function
+  * implies that careful retesting must be done.
+  *
+- * Input:
+- * @ec entropy collector struct -- may be NULL
+- * @time time stamp to be injected
+- * @loop_cnt if a value not equal to 0 is set, use the given value as number of
+- *	     loops to perform the folding
++ * @ec [in] entropy collector struct
++ * @time [in] time stamp to be injected
++ * @loop_cnt [in] if a value not equal to 0 is set, use the given value as
++ *		  number of loops to perform the folding
++ * @stuck [in] Is the time stamp identified as stuck?
+  *
+  * Output:
+  * updated ec->data
+  *
+  * @return Number of loops the folding operation is performed
+  */
+-static __u64 jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt)
++void jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt,
++			   int stuck)
+ {
+ 	unsigned int i;
+ 	__u64 j = 0;
+@@ -225,12 +366,20 @@ static __u64 jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt)
+ 			new ^= tmp;
+ 		}
+ 	}
+-	ec->data = new;
+ 
+-	return fold_loop_cnt;
++	/*
++	 * If the time stamp is stuck, do not finally insert the value into
++	 * the entropy pool. Although this operation should not do any harm
++	 * even when the time stamp has no entropy, SP800-90B requires that
++	 * any conditioning operation (SP800-90B considers the LFSR to be a
++	 * conditioning operation) to have an identical amount of input
++	 * data according to section 3.1.5.
++	 */
++	if (!stuck)
++		ec->data = new;
+ }
+ 
+-/**
++/*
+  * Memory Access noise source -- this is a noise source based on variations in
+  *				 memory access times
+  *
+@@ -248,16 +397,13 @@ static __u64 jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt)
+  * to reliably access either L3 or memory, the ec->mem memory must be quite
+  * large which is usually not desirable.
+  *
+- * Input:
+- * @ec Reference to the entropy collector with the memory access data -- if
+- *     the reference to the memory block to be accessed is NULL, this noise
+- *     source is disabled
+- * @loop_cnt if a value not equal to 0 is set, use the given value as number of
+- *	     loops to perform the folding
+- *
+- * @return Number of memory access operations
++ * @ec [in] Reference to the entropy collector with the memory access data -- if
++ *	    the reference to the memory block to be accessed is NULL, this noise
++ *	    source is disabled
++ * @loop_cnt [in] if a value not equal to 0 is set, use the given value
++ *		  number of loops to perform the LFSR
+  */
+-static unsigned int jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
++static void jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
+ {
+ 	unsigned int wrap = 0;
+ 	__u64 i = 0;
+@@ -267,7 +413,7 @@ static unsigned int jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
+ 		jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
+ 
+ 	if (NULL == ec || NULL == ec->mem)
+-		return 0;
++		return;
+ 	wrap = ec->memblocksize * ec->memblocks;
+ 
+ 	/*
+@@ -293,44 +439,12 @@ static unsigned int jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
+ 		ec->memlocation = ec->memlocation + ec->memblocksize - 1;
+ 		ec->memlocation = ec->memlocation % wrap;
+ 	}
+-	return i;
+ }
+ 
+ /***************************************************************************
+  * Start of entropy processing logic
+  ***************************************************************************/
+-
+-/**
+- * Stuck test by checking the:
+- *	1st derivation of the jitter measurement (time delta)
+- *	2nd derivation of the jitter measurement (delta of time deltas)
+- *	3rd derivation of the jitter measurement (delta of delta of time deltas)
+- *
+- * All values must always be non-zero.
+- *
+- * Input:
+- * @ec Reference to entropy collector
+- * @current_delta Jitter time delta
+- *
+- * @return
+- *	0 jitter measurement not stuck (good bit)
+- *	1 jitter measurement stuck (reject bit)
+- */
+-static int jent_stuck(struct rand_data *ec, __u64 current_delta)
+-{
+-	__s64 delta2 = ec->last_delta - current_delta;
+-	__s64 delta3 = delta2 - ec->last_delta2;
+-
+-	ec->last_delta = current_delta;
+-	ec->last_delta2 = delta2;
+-
+-	if (!current_delta || !delta2 || !delta3)
+-		return 1;
+-
+-	return 0;
+-}
+-
+-/**
++/*
+  * This is the heart of the entropy generation: calculate time deltas and
+  * use the CPU jitter in the time deltas. The jitter is injected into the
+  * entropy pool.
+@@ -339,15 +453,15 @@ static int jent_stuck(struct rand_data *ec, __u64 current_delta)
+  *	    of this function! This can be done by calling this function
+  *	    and not using its result.
+  *
+- * Input:
+- * @entropy_collector Reference to entropy collector
++ * @ec [in] Reference to entropy collector
+  *
+  * @return result of stuck test
+  */
+-static int jent_measure_jitter(struct rand_data *ec)
++int jent_measure_jitter(struct rand_data *ec)
+ {
+ 	__u64 time = 0;
+ 	__u64 current_delta = 0;
++	int stuck;
+ 
+ 	/* Invoke one noise source before time measurement to add variations */
+ 	jent_memaccess(ec, 0);
+@@ -357,31 +471,33 @@ static int jent_measure_jitter(struct rand_data *ec)
+ 	 * invocation to measure the timing variations
+ 	 */
+ 	jent_get_nstime(&time);
+-	current_delta = time - ec->prev_time;
++	current_delta = jent_delta(ec->prev_time, time);
+ 	ec->prev_time = time;
++	/* Check whether we have a stuck measurement. */
++	stuck = jent_stuck(ec, current_delta);
+ 
+ 	/* Now call the next noise sources which also injects the data */
+-	jent_lfsr_time(ec, current_delta, 0);
+-
+-	/* Check whether we have a stuck measurement. */
+-	return jent_stuck(ec, current_delta);
++	jent_lfsr_time(ec, current_delta, 0, stuck);
++	return stuck;
+ }
+ 
+-/**
++/*
+  * Generator of one 64 bit random number
+  * Function fills rand_data->data
+  *
+- * Input:
+- * @ec Reference to entropy collector
++ * @ec [in] Reference to entropy collector
+  */
+ static void jent_gen_entropy(struct rand_data *ec)
+ {
+-	unsigned int k = 0;
++	unsigned int k = 0, safety_factor = 0;
++
++	if (fips_enabled)
++		safety_factor = JENT_ENTROPY_SAFETY_FACTOR;
+ 
+ 	/* priming of the ->prev_time value */
+ 	jent_measure_jitter(ec);
+ 
+-	while (1) {
++	while (!jent_health_failure(ec)) {
+ 		/* If a stuck measurement is received, repeat measurement */
+ 		if (jent_measure_jitter(ec))
+ 			continue;
+@@ -390,37 +506,12 @@ static void jent_gen_entropy(struct rand_data *ec)
+ 		 * We multiply the loop value with ->osr to obtain the
+ 		 * oversampling rate requested by the caller
+ 		 */
+-		if (++k >= (DATA_SIZE_BITS * ec->osr))
++		if (++k >= ((DATA_SIZE_BITS + safety_factor) * ec->osr))
+ 			break;
+ 	}
+ }
+ 
+-/**
+- * The continuous test required by FIPS 140-2 -- the function automatically
+- * primes the test if needed.
+- *
+- * Return:
+- * 0 if FIPS test passed
+- * < 0 if FIPS test failed
+- */
+-static void jent_fips_test(struct rand_data *ec)
+-{
+-	if (!jent_fips_enabled())
+-		return;
+-
+-	/* prime the FIPS test */
+-	if (!ec->old_data) {
+-		ec->old_data = ec->data;
+-		jent_gen_entropy(ec);
+-	}
+-
+-	if (ec->data == ec->old_data)
+-		jent_panic("jitterentropy: Duplicate output detected\n");
+-
+-	ec->old_data = ec->data;
+-}
+-
+-/**
++/*
+  * Entry function: Obtain entropy for the caller.
+  *
+  * This function invokes the entropy gathering logic as often to generate
+@@ -430,42 +521,64 @@ static void jent_fips_test(struct rand_data *ec)
+  * This function truncates the last 64 bit entropy value output to the exact
+  * size specified by the caller.
+  *
+- * Input:
+- * @ec Reference to entropy collector
+- * @data pointer to buffer for storing random data -- buffer must already
+- *	 exist
+- * @len size of the buffer, specifying also the requested number of random
+- *	in bytes
++ * @ec [in] Reference to entropy collector
++ * @data [in] pointer to buffer for storing random data -- buffer must already
++ *	      exist
++ * @len [in] size of the buffer, specifying also the requested number of random
++ *	     in bytes
+  *
+  * @return 0 when request is fulfilled or an error
+  *
+  * The following error codes can occur:
+  *	-1	entropy_collector is NULL
++ *	-2	Intermittent health failure
++ *	-3	Permanent health failure
+  */
+ int jent_read_entropy(struct rand_data *ec, unsigned char *data,
+ 		      unsigned int len)
+ {
++	int ret = 0;
+ 	unsigned char *p = data;
+ 
+ 	if (!ec)
+ 		return -1;
+ 
+-	while (0 < len) {
++	while (len > 0) {
+ 		unsigned int tocopy;
+ 
+ 		jent_gen_entropy(ec);
+-		jent_fips_test(ec);
++
++		if (jent_permanent_health_failure(ec)) {
++			/*
++			 * At this point, the Jitter RNG instance is considered
++			 * as a failed instance. There is no rerun of the
++			 * startup test any more, because the caller
++			 * is assumed to not further use this instance.
++			 */
++			return -3;
++		} else if (jent_health_failure(ec)) {
++			/*
++			 * Perform startup health tests and return permanent
++			 * error if it fails.
++			 */
++			if (jent_entropy_init())
++				return -3;
++
++			return -2;
++		}
++
+ 		if ((DATA_SIZE_BITS / 8) < len)
+ 			tocopy = (DATA_SIZE_BITS / 8);
+ 		else
+ 			tocopy = len;
+ 		jent_memcpy(p, &ec->data, tocopy);
+ 
++		ret = ret + tocopy;
+ 		len -= tocopy;
+ 		p += tocopy;
+ 	}
+ 
+-	return 0;
++	return ret;
+ }
+ 
+ /***************************************************************************
+@@ -496,7 +609,7 @@ struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
+ 	}
+ 
+ 	/* verify and set the oversampling rate */
+-	if (0 == osr)
++	if (osr == 0)
+ 		osr = 1; /* minimum sampling rate is 1 */
+ 	entropy_collector->osr = osr;
+ 
+@@ -518,11 +631,15 @@ int jent_entropy_init(void)
+ 	int i;
+ 	__u64 delta_sum = 0;
+ 	__u64 old_delta = 0;
++	unsigned int nonstuck = 0;
+ 	int time_backwards = 0;
+ 	int count_mod = 0;
+ 	int count_stuck = 0;
+ 	struct rand_data ec = { 0 };
+ 
++	/* Required for RCT */
++	ec.osr = 1;
++
+ 	/* We could perform statistical tests here, but the problem is
+ 	 * that we only have a few loop counts to do testing. These
+ 	 * loop counts may show some slight skew and we produce
+@@ -544,8 +661,10 @@ int jent_entropy_init(void)
+ 	/*
+ 	 * TESTLOOPCOUNT needs some loops to identify edge systems. 100 is
+ 	 * definitely too little.
++	 *
++	 * SP800-90B requires at least 1024 initial test cycles.
+ 	 */
+-#define TESTLOOPCOUNT 300
++#define TESTLOOPCOUNT 1024
+ #define CLEARCACHE 100
+ 	for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) {
+ 		__u64 time = 0;
+@@ -557,13 +676,13 @@ int jent_entropy_init(void)
+ 		/* Invoke core entropy collection logic */
+ 		jent_get_nstime(&time);
+ 		ec.prev_time = time;
+-		jent_lfsr_time(&ec, time, 0);
++		jent_lfsr_time(&ec, time, 0, 0);
+ 		jent_get_nstime(&time2);
+ 
+ 		/* test whether timer works */
+ 		if (!time || !time2)
+ 			return JENT_ENOTIME;
+-		delta = time2 - time;
++		delta = jent_delta(time, time2);
+ 		/*
+ 		 * test whether timer is fine grained enough to provide
+ 		 * delta even when called shortly after each other -- this
+@@ -581,11 +700,31 @@ int jent_entropy_init(void)
+ 		 * etc. with the goal to clear it to get the worst case
+ 		 * measurements.
+ 		 */
+-		if (CLEARCACHE > i)
++		if (i < CLEARCACHE)
+ 			continue;
+ 
+ 		if (stuck)
+ 			count_stuck++;
++		else {
++			nonstuck++;
++
++			/*
++			 * Ensure that the APT succeeded.
++			 *
++			 * With the check below that count_stuck must be less
++			 * than 10% of the overall generated raw entropy values
++			 * it is guaranteed that the APT is invoked at
++			 * floor((TESTLOOPCOUNT * 0.9) / 64) == 14 times.
++			 */
++			if ((nonstuck % JENT_APT_WINDOW_SIZE) == 0) {
++				jent_apt_reset(&ec,
++					       delta & JENT_APT_WORD_MASK);
++			}
++		}
++
++		/* Validate health test result */
++		if (jent_health_failure(&ec))
++			return JENT_EHEALTH;
+ 
+ 		/* test whether we have an increasing timer */
+ 		if (!(time2 > time))
+@@ -616,7 +755,7 @@ int jent_entropy_init(void)
+ 	 * should not fail. The value of 3 should cover the NTP case being
+ 	 * performed during our test run.
+ 	 */
+-	if (3 < time_backwards)
++	if (time_backwards > 3)
+ 		return JENT_ENOMONOTONIC;
+ 
+ 	/*
+diff --git a/crypto/jitterentropy.h b/crypto/jitterentropy.h
+new file mode 100644
+index 000000000..ee555f642
+--- /dev/null
++++ b/crypto/jitterentropy.h
+@@ -0,0 +1,79 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++
++#ifndef _JITTERENTROPY_H
++#define _JITTERENTROPY_H
++#include <linux/types.h>
++
++/* Flags that can be used to initialize the RNG */
++#define JENT_DISABLE_STIR (1<<0) /* Disable stirring the entropy pool */
++#define JENT_DISABLE_UNBIAS (1<<1) /* Disable the Von-Neuman Unbiaser */
++#define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more
++					     entropy, saves MEMORY_SIZE RAM for
++					     entropy collector */
++#define DRIVER_NAME     "jitterentropy"
++
++struct rand_data {
++	/* all data values that are vital to maintain the security
++	 * of the RNG are marked as SENSITIVE. A user must not
++	 * access that information while the RNG executes its loops to
++	 * calculate the next random value. */
++	__u64 data;		/* SENSITIVE Actual random number */
++	__u64 old_data;		/* SENSITIVE Previous random number */
++	__u64 prev_time;	/* SENSITIVE Previous time stamp */
++#define DATA_SIZE_BITS ((sizeof(__u64)) * 8)
++	__u64 last_delta;	/* SENSITIVE stuck test */
++	__s64 last_delta2;	/* SENSITIVE stuck test */
++	unsigned int osr;	/* Oversample rate */
++#define JENT_MEMORY_BLOCKS 64
++#define JENT_MEMORY_BLOCKSIZE 32
++#define JENT_MEMORY_ACCESSLOOPS 128
++#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
++	unsigned char *mem;	/* Memory access location with size of
++				 * memblocks * memblocksize */
++	unsigned int memlocation; /* Pointer to byte in *mem */
++	unsigned int memblocks;	/* Number of memory blocks in *mem */
++	unsigned int memblocksize; /* Size of one memory block in bytes */
++	unsigned int memaccessloops; /* Number of memory accesses per random
++				      * bit generation */
++
++	/* Repetition Count Test */
++	unsigned int rct_count;			/* Number of stuck values */
++
++	/* Intermittent health test failure threshold of 2^-30 */
++#define JENT_RCT_CUTOFF		30	/* Taken from SP800-90B sec 4.4.1 */
++#define JENT_APT_CUTOFF		325	/* Taken from SP800-90B sec 4.4.2 */
++	/* Permanent health test failure threshold of 2^-60 */
++#define JENT_RCT_CUTOFF_PERMANENT	60
++#define JENT_APT_CUTOFF_PERMANENT	355
++#define JENT_APT_WINDOW_SIZE	512	/* Data window size */
++	/* LSB of time stamp to process */
++#define JENT_APT_LSB		16
++#define JENT_APT_WORD_MASK	(JENT_APT_LSB - 1)
++	unsigned int apt_observations;	/* Number of collected observations */
++	unsigned int apt_count;		/* APT counter */
++	unsigned int apt_base;		/* APT base reference */
++	unsigned int apt_base_set:1;	/* APT base reference set? */
++	unsigned int stir:1;		/* Post-processing stirring */
++	unsigned int disable_unbias:1;	/* Deactivate Von-Neuman unbias */
++};
++extern void *jent_zalloc(unsigned int len);
++extern void jent_zfree(void *ptr);
++extern void jent_memcpy(void *dest, const void *src, unsigned int n);
++extern void jent_get_nstime(__u64 *out);
++
++struct rand_data;
++extern int jent_entropy_init(void);
++extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,
++			     unsigned int len);
++
++extern struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
++						      unsigned int flags);
++extern void jent_entropy_collector_free(struct rand_data *entropy_collector);
++
++unsigned int jent_version(void);
++
++void jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt, int stuck);
++
++int jent_measure_jitter(struct rand_data *ec);
++
++#endif /* _JITTERENTROPY_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1051-v5.10-backport-libkcapi.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1051-v5.10-backport-libkcapi.patch
new file mode 100644
index 0000000..0b196b6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1051-v5.10-backport-libkcapi.patch
@@ -0,0 +1,376 @@
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 4a2e91baa..fb6b4f8a0 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -226,6 +226,30 @@ static int alg_setkey(struct sock *sk, char __user *ukey,
+ 	return err;
+ }
+ 
++static int alg_setentropy(struct sock *sk, char __user *ukey,
++		      unsigned int entropy_len)
++{
++	struct alg_sock *ask = alg_sk(sk);
++	const struct af_alg_type *type = ask->type;
++	u8 *entropy;
++	int err;
++
++	entropy = sock_kmalloc(sk, entropy_len, GFP_KERNEL);
++	if (!entropy)
++		return -ENOMEM;
++
++	err = -EFAULT;
++	if (copy_from_user(entropy, ukey, entropy_len))
++		goto out;
++
++	err = type->setentropy(ask->private, entropy, entropy_len);
++
++out:
++	sock_kzfree_s(sk, entropy, entropy_len);
++
++	return err;
++}
++
+ static int alg_setsockopt(struct socket *sock, int level, int optname,
+ 			  char __user *optval, unsigned int optlen)
+ {
+@@ -250,7 +274,6 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
+ 			goto unlock;
+ 		if (!type->setkey)
+ 			goto unlock;
+-
+ 		err = alg_setkey(sk, optval, optlen);
+ 		break;
+ 	case ALG_SET_AEAD_AUTHSIZE:
+@@ -259,6 +282,15 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
+ 		if (!type->setauthsize)
+ 			goto unlock;
+ 		err = type->setauthsize(ask->private, optlen);
++		break;
++	case ALG_SET_DRBG_ENTROPY:
++		if (sock->state == SS_CONNECTED)
++			goto unlock;
++		if (!type->setentropy)
++			goto unlock;
++		err = alg_setentropy(sk, optval, optlen);
++		break;
++
+ 	}
+ 
+ unlock:
+@@ -291,6 +323,11 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern)
+ 	security_sock_graft(sk2, newsock);
+ 	security_sk_clone(sk, sk2);
+ 
++	/*
++	 * newsock->ops assigned here to allow type->accept call to override
++	 * them when required.
++	 */
++	newsock->ops = type->ops;
+ 	err = type->accept(ask->private, sk2);
+ 
+ 	nokey = err == -ENOKEY;
+@@ -309,7 +346,6 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern)
+ 	alg_sk(sk2)->parent = sk;
+ 	alg_sk(sk2)->type = type;
+ 
+-	newsock->ops = type->ops;
+ 	newsock->state = SS_CONNECTED;
+ 
+ 	if (nokey)
+diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
+index 22df3799a..bce3aef53 100644
+--- a/crypto/algif_rng.c
++++ b/crypto/algif_rng.c
+@@ -38,6 +38,7 @@
+  * DAMAGE.
+  */
+ 
++#include <linux/capability.h>
+ #include <linux/module.h>
+ #include <crypto/rng.h>
+ #include <linux/random.h>
+@@ -53,15 +54,26 @@ struct rng_ctx {
+ #define MAXSIZE 128
+ 	unsigned int len;
+ 	struct crypto_rng *drng;
++	u8 *addtl;
++	size_t addtl_len;
+ };
+ 
+-static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+-		       int flags)
++struct rng_parent_ctx {
++	struct crypto_rng *drng;
++	u8 *entropy;
++};
++
++static void rng_reset_addtl(struct rng_ctx *ctx)
+ {
+-	struct sock *sk = sock->sk;
+-	struct alg_sock *ask = alg_sk(sk);
+-	struct rng_ctx *ctx = ask->private;
+-	int err = -EFAULT;
++	kzfree(ctx->addtl);
++	ctx->addtl = NULL;
++	ctx->addtl_len = 0;
++}
++
++static int _rng_recvmsg(struct crypto_rng *drng, struct msghdr *msg, size_t len,
++			u8 *addtl, size_t addtl_len)
++{
++	int err = 0;
+ 	int genlen = 0;
+ 	u8 result[MAXSIZE];
+ 
+@@ -82,7 +94,7 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+ 	 * seeding as they automatically seed. The X9.31 DRNG will return
+ 	 * an error if it was not seeded properly.
+ 	 */
+-	genlen = crypto_rng_get_bytes(ctx->drng, result, len);
++	genlen = crypto_rng_generate(drng, addtl, addtl_len, result, len);
+ 	if (genlen < 0)
+ 		return genlen;
+ 
+@@ -92,6 +104,63 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+ 	return err ? err : len;
+ }
+ 
++static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
++		       int flags)
++{
++	struct sock *sk = sock->sk;
++	struct alg_sock *ask = alg_sk(sk);
++	struct rng_ctx *ctx = ask->private;
++
++	return _rng_recvmsg(ctx->drng, msg, len, NULL, 0);
++}
++
++static int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
++			    int flags)
++{
++	struct sock *sk = sock->sk;
++	struct alg_sock *ask = alg_sk(sk);
++	struct rng_ctx *ctx = ask->private;
++	int ret;
++
++	lock_sock(sock->sk);
++	ret = _rng_recvmsg(ctx->drng, msg, len, ctx->addtl, ctx->addtl_len);
++	rng_reset_addtl(ctx);
++	release_sock(sock->sk);
++
++	return ret;
++}
++
++static int rng_test_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
++{
++	int err;
++	struct alg_sock *ask = alg_sk(sock->sk);
++	struct rng_ctx *ctx = ask->private;
++
++	lock_sock(sock->sk);
++	if (len > MAXSIZE) {
++		err = -EMSGSIZE;
++		goto unlock;
++	}
++
++	rng_reset_addtl(ctx);
++	ctx->addtl = kmalloc(len, GFP_KERNEL);
++	if (!ctx->addtl) {
++		err = -ENOMEM;
++		goto unlock;
++	}
++
++	err = memcpy_from_msg(ctx->addtl, msg, len);
++	if (err) {
++		rng_reset_addtl(ctx);
++		goto unlock;
++	}
++	ctx->addtl_len = len;
++
++unlock:
++	release_sock(sock->sk);
++	return err ? err : len;
++}
++
+ static struct proto_ops algif_rng_ops = {
+ 	.family		=	PF_ALG,
+ 
+@@ -113,14 +182,53 @@ static struct proto_ops algif_rng_ops = {
+ 	.recvmsg	=	rng_recvmsg,
+ };
+ 
++static struct proto_ops __maybe_unused algif_rng_test_ops = {
++	.family		=	PF_ALG,
++
++	.connect	=	sock_no_connect,
++	.socketpair	=	sock_no_socketpair,
++	.getname	=	sock_no_getname,
++	.ioctl		=	sock_no_ioctl,
++	.listen		=	sock_no_listen,
++	.shutdown	=	sock_no_shutdown,
++	.mmap		=	sock_no_mmap,
++	.bind		=	sock_no_bind,
++	.accept		=	sock_no_accept,
++	.sendpage	=	sock_no_sendpage,
++
++	.release	=	af_alg_release,
++	.recvmsg	=	rng_test_recvmsg,
++	.sendmsg	=	rng_test_sendmsg,
++};
++
+ static void *rng_bind(const char *name, u32 type, u32 mask)
+ {
+-	return crypto_alloc_rng(name, type, mask);
++	struct rng_parent_ctx *pctx;
++	struct crypto_rng *rng;
++
++	pctx = kzalloc(sizeof(*pctx), GFP_KERNEL);
++	if (!pctx)
++		return ERR_PTR(-ENOMEM);
++
++	rng = crypto_alloc_rng(name, type, mask);
++	if (IS_ERR(rng)) {
++		kfree(pctx);
++		return ERR_CAST(rng);
++	}
++
++	pctx->drng = rng;
++	return pctx;
+ }
+ 
+ static void rng_release(void *private)
+ {
+-	crypto_free_rng(private);
++	struct rng_parent_ctx *pctx = private;
++	 if (unlikely(!pctx))
++		 return;
++	 crypto_free_rng(pctx->drng);
++	 kzfree(pctx->entropy);
++	 kzfree(pctx);
++	return;
+ }
+ 
+ static void rng_sock_destruct(struct sock *sk)
+@@ -128,6 +236,7 @@ static void rng_sock_destruct(struct sock *sk)
+ 	struct alg_sock *ask = alg_sk(sk);
+ 	struct rng_ctx *ctx = ask->private;
+ 
++	rng_reset_addtl(ctx);
+ 	sock_kfree_s(sk, ctx, ctx->len);
+ 	af_alg_release_parent(sk);
+ }
+@@ -135,6 +244,7 @@ static void rng_sock_destruct(struct sock *sk)
+ static int rng_accept_parent(void *private, struct sock *sk)
+ {
+ 	struct rng_ctx *ctx;
++	struct rng_parent_ctx *pctx = private;
+ 	struct alg_sock *ask = alg_sk(sk);
+ 	unsigned int len = sizeof(*ctx);
+ 
+@@ -143,6 +253,8 @@ static int rng_accept_parent(void *private, struct sock *sk)
+ 		return -ENOMEM;
+ 
+ 	ctx->len = len;
++	ctx->addtl = NULL;
++	ctx->addtl_len = 0;
+ 
+ 	/*
+ 	 * No seeding done at that point -- if multiple accepts are
+@@ -150,20 +262,59 @@ static int rng_accept_parent(void *private, struct sock *sk)
+ 	 * state of the RNG.
+ 	 */
+ 
+-	ctx->drng = private;
++	ctx->drng = pctx->drng;
+ 	ask->private = ctx;
+ 	sk->sk_destruct = rng_sock_destruct;
+ 
++	/*
++	 * Non NULL pctx->entropy means that CAVP test has been initiated on
++	 * this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops.
++	 */
++	if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy)
++		sk->sk_socket->ops = &algif_rng_test_ops;
+ 	return 0;
+ }
+ 
+ static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen)
+ {
++	struct rng_parent_ctx *pctx = private;
+ 	/*
+ 	 * Check whether seedlen is of sufficient size is done in RNG
+ 	 * implementations.
+ 	 */
+-	return crypto_rng_reset(private, seed, seedlen);
++	return crypto_rng_reset(pctx->drng, seed, seedlen);
++}
++
++static int __maybe_unused rng_setentropy(void *private, const u8 *entropy,
++					 unsigned int len)
++{
++	struct rng_parent_ctx *pctx = private;
++	u8 *kentropy = NULL;
++	int i;
++
++	if (!capable(CAP_SYS_ADMIN))
++		return -EACCES;
++
++	if (pctx->entropy)
++		return -EINVAL;
++
++	if (len > MAXSIZE)
++		return -EMSGSIZE;
++
++	if (len) {
++		kentropy = (u8*)kmalloc(len, GFP_KERNEL);
++		memcpy(kentropy, entropy, len);
++		if (IS_ERR(kentropy))
++			return PTR_ERR(kentropy);
++	}
++
++	crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len);
++	/*
++	 * Since rng doesn't perform any memory management for the entropy
++	 * buffer, save kentropy pointer to pctx now to free it after use.
++	 */
++	pctx->entropy = kentropy;
++	return 0;
+ }
+ 
+ static const struct af_alg_type algif_type_rng = {
+@@ -173,7 +324,10 @@ static const struct af_alg_type algif_type_rng = {
+ 	.setkey		=	rng_setkey,
+ 	.ops		=	&algif_rng_ops,
+ 	.name		=	"rng",
+-	.owner		=	THIS_MODULE
++	.owner		=	THIS_MODULE,
++#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP
++	.setentropy	=	rng_setentropy,
++#endif
+ };
+ 
+ static int __init rng_init(void)
+diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
+index c1a8d4a41..ca06787f7 100644
+--- a/include/crypto/if_alg.h
++++ b/include/crypto/if_alg.h
+@@ -46,6 +46,7 @@ struct af_alg_type {
+ 	void *(*bind)(const char *name, u32 type, u32 mask);
+ 	void (*release)(void *private);
+ 	int (*setkey)(void *private, const u8 *key, unsigned int keylen);
++	int (*setentropy)(void *private, const u8 *key, unsigned int keylen);
+ 	int (*accept)(void *private, struct sock *sk);
+ 	int (*accept_nokey)(void *private, struct sock *sk);
+ 	int (*setauthsize)(void *private, unsigned int authsize);
+diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
+index 769050771..dc52a11ba 100644
+--- a/include/uapi/linux/if_alg.h
++++ b/include/uapi/linux/if_alg.h
+@@ -51,6 +51,7 @@ struct af_alg_iv {
+ #define ALG_SET_OP			3
+ #define ALG_SET_AEAD_ASSOCLEN		4
+ #define ALG_SET_AEAD_AUTHSIZE		5
++#define ALG_SET_DRBG_ENTROPY		6
+ 
+ /* Operations */
+ #define ALG_OP_DECRYPT			0
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1700-macsec-revert-async-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1700-macsec-revert-async-support.patch
deleted file mode 100644
index 3212b6b..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1700-macsec-revert-async-support.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 8b45e5c6b6b419305ef893e1dfdd4c69c020958b Mon Sep 17 00:00:00 2001
-From: Sam Shih <sam.shih@mediatek.com>
-Date: Fri, 2 Jun 2023 13:05:59 +0800
-Subject: [PATCH] 
- [backport-networking-drivers][999-1700-macsec-revert-async-support.patch]
-
----
- drivers/net/macsec.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
-index f729f55f6..e3f03c89c 100644
---- a/drivers/net/macsec.c
-+++ b/drivers/net/macsec.c
-@@ -1311,8 +1311,7 @@ static struct crypto_aead *macsec_alloc_tfm(char *key, int key_len, int icv_len)
- 	struct crypto_aead *tfm;
- 	int ret;
- 
--	/* Pick a sync gcm(aes) cipher to ensure order is preserved. */
--	tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
-+	tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
- 
- 	if (IS_ERR(tfm))
- 		return tfm;
--- 
-2.34.1
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1713-v5.15-net-dsa-add-dsa_port_from_netdev.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1713-v5.15-net-dsa-add-dsa_port_from_netdev.patch
new file mode 100644
index 0000000..1b3468d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1713-v5.15-net-dsa-add-dsa_port_from_netdev.patch
@@ -0,0 +1,74 @@
+From b80c745d2b90b30558e4f5b12060af956ae8e76d Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Mon, 18 Sep 2023 10:52:27 +0800
+Subject: [PATCH] net dsa add dsa_port_from_netdev
+
+---
+ include/net/dsa.h                             |   10 +
+ net/dsa/dsa.c                                 |    9 +
+ net/dsa/slave.c                               |    1 +
+  3 files changed, 20 insertions(+), 0 deletions(-)
+
+diff --git a/include/net/dsa.h b/include/net/dsa.h
+index d29ee9e..43f65cb 100644
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -562,6 +562,8 @@ struct dsa_switch_ops {
+ 					  struct sk_buff *skb);
+ };
+ 
++struct dsa_port *dsa_port_from_netdev(struct net_device *netdev);
++
+ struct dsa_switch_driver {
+ 	struct list_head	list;
+ 	const struct dsa_switch_ops *ops;
+@@ -654,6 +656,14 @@ static inline int call_dsa_notifiers(unsigned long val, struct net_device *dev,
+ #define BRCM_TAG_GET_PORT(v)		((v) >> 8)
+ #define BRCM_TAG_GET_QUEUE(v)		((v) & 0xff)
+ 
++#if IS_ENABLED(CONFIG_NET_DSA)
++bool dsa_slave_dev_check(const struct net_device *dev);
++#else
++static inline bool dsa_slave_dev_check(const struct net_device *dev)
++{
++	return false;
++}
++#endif
+ 
+ netdev_tx_t dsa_enqueue_skb(struct sk_buff *skb, struct net_device *dev);
+ int dsa_port_get_phy_strings(struct dsa_port *dp, uint8_t *data);
+diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
+index ca80f86..35a1249 100644
+--- a/net/dsa/dsa.c
++++ b/net/dsa/dsa.c
+@@ -329,6 +329,15 @@ int call_dsa_notifiers(unsigned long val, struct net_device *dev,
+ }
+ EXPORT_SYMBOL_GPL(call_dsa_notifiers);
+ 
++struct dsa_port *dsa_port_from_netdev(struct net_device *netdev)
++{
++	if (!netdev || !dsa_slave_dev_check(netdev))
++		return ERR_PTR(-ENODEV);
++
++	return dsa_slave_to_port(netdev);
++}
++EXPORT_SYMBOL_GPL(dsa_port_from_netdev);
++
+ static int __init dsa_init_module(void)
+ {
+ 	int rc;
+diff --git a/net/dsa/slave.c b/net/dsa/slave.c
+index e2b91b3..2dfaa1e 100644
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1499,6 +1533,7 @@ bool dsa_slave_dev_check(const struct net_device *dev)
+ {
+ 	return dev->netdev_ops == &dsa_slave_netdev_ops;
+ }
++EXPORT_SYMBOL_GPL(dsa_slave_dev_check);
+ 
+ static int dsa_slave_changeupper(struct net_device *dev,
+ 				 struct netdev_notifier_changeupper_info *info)
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1714-v5.15-net-dsa-add-netdev_upper_dev_link.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1714-v5.15-net-dsa-add-netdev_upper_dev_link.patch
new file mode 100644
index 0000000..2b854c4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1714-v5.15-net-dsa-add-netdev_upper_dev_link.patch
@@ -0,0 +1,36 @@
+From 120baca4e8b019d03c8d1a29012cea911629247a Mon Sep 17 00:00:00 2001
+From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
+Date: Mon, 18 Sep 2023 11:13:51 +0800
+Subject: [PATCH] net dsa add netdev_upper_dev_link
+
+---
+ net/dsa/slave.c                |  11 +
+ 1 files changed, 11 insertions(+), 0 deletions(-)
+
+diff --git a/net/dsa/slave.c b/net/dsa/slave.c
+index 2dfaa1e..a60a26c 100644
+--- a/net/dsa/slave.c
++++ b/net/dsa/slave.c
+@@ -1495,8 +1495,19 @@ int dsa_slave_create(struct dsa_port *port)
+ 		goto out_phy;
+ 	}
+ 
++	rtnl_lock();
++
++	ret = netdev_upper_dev_link(master, slave_dev, NULL);
++
++	rtnl_unlock();
++
++	if (ret)
++		goto out_unregister;
++
+ 	return 0;
+ 
++out_unregister:
++	unregister_netdev(slave_dev);
+ out_phy:
+ 	rtnl_lock();
+ 	phylink_disconnect_phy(p->dp->pl);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1800-v6.7-MT7986-ASoC-platform-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1800-v6.7-MT7986-ASoC-platform-driver.patch
new file mode 100644
index 0000000..3c5096a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1800-v6.7-MT7986-ASoC-platform-driver.patch
@@ -0,0 +1,1602 @@
+From 0dc695c6d7e86562bb185214a271a2d4614d3f96 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 16 Nov 2023 12:05:02 +0800
+Subject: [PATCH] v6.7 MT7986 ASoC platform driver
+
+---
+ sound/soc/mediatek/Kconfig                    |  20 +
+ sound/soc/mediatek/Makefile                   |   1 +
+ sound/soc/mediatek/mt7986/Makefile            |   9 +
+ sound/soc/mediatek/mt7986/mt7986-afe-common.h |  49 ++
+ sound/soc/mediatek/mt7986/mt7986-afe-pcm.c    | 640 ++++++++++++++++++
+ sound/soc/mediatek/mt7986/mt7986-dai-etdm.c   | 428 ++++++++++++
+ sound/soc/mediatek/mt7986/mt7986-reg.h        | 196 ++++++
+ sound/soc/mediatek/mt7986/mt7986-wm8960.c     | 177 +++++
+ 8 files changed, 1520 insertions(+)
+ create mode 100644 sound/soc/mediatek/mt7986/Makefile
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-afe-common.h
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-reg.h
+ create mode 100644 sound/soc/mediatek/mt7986/mt7986-wm8960.c
+
+diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
+index 111e44b..99d36c4 100644
+--- a/sound/soc/mediatek/Kconfig
++++ b/sound/soc/mediatek/Kconfig
+@@ -53,6 +53,26 @@ config SND_SOC_MT6797_MT6351
+ 	  Select Y if you have such device.
+ 	  If unsure select "N".
+ 
++config SND_SOC_MT7986
++	tristate "ASoC support for Mediatek MT7986 chip"
++	depends on ARCH_MEDIATEK
++	select SND_SOC_MEDIATEK
++	help
++	  This adds ASoC platform driver support for MediaTek MT7986 chip
++	  that can be used with other codecs.
++	  Select Y if you have such device.
++	  If unsure select "N".
++
++config SND_SOC_MT7986_WM8960
++	tristate "ASoc Audio driver for MT7986 with WM8960 codec"
++	depends on SND_SOC_MT7986 && I2C
++	select SND_SOC_WM8960
++	help
++	  This adds support for ASoC machine driver for MediaTek MT7986
++	  boards with the WM8960 codecs.
++	  Select Y if you have such device.
++	  If unsure select "N".
++
+ config SND_SOC_MT8173
+ 	tristate "ASoC support for Mediatek MT8173 chip"
+ 	depends on ARCH_MEDIATEK
+diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
+index 76032ca..657325a 100644
+--- a/sound/soc/mediatek/Makefile
++++ b/sound/soc/mediatek/Makefile
+@@ -2,5 +2,6 @@
+ obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
+ obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
+ obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
++obj-$(CONFIG_SND_SOC_MT7986) += mt7986/
+ obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
+ obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
+diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile
+new file mode 100644
+index 0000000..fc4c825
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/Makefile
+@@ -0,0 +1,9 @@
++# SPDX-License-Identifier: GPL-2.0
++
++# platform driver
++snd-soc-mt7986-afe-objs := \
++	mt7986-afe-pcm.o \
++	mt7986-dai-etdm.o
++
++obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o
++obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o
+diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-common.h b/sound/soc/mediatek/mt7986/mt7986-afe-common.h
+new file mode 100644
+index 0000000..fc3bb31
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-afe-common.h
+@@ -0,0 +1,49 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * mt7986-afe-common.h  --  MediaTek 7986 audio driver definitions
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ *          Maso Huang <maso.huang@mediatek.com>
++ */
++
++#ifndef _MT_7986_AFE_COMMON_H_
++#define _MT_7986_AFE_COMMON_H_
++
++#include <sound/soc.h>
++#include <linux/clk.h>
++#include <linux/list.h>
++#include <linux/regmap.h>
++#include "../common/mtk-base-afe.h"
++
++enum {
++	MT7986_MEMIF_DL1,
++	MT7986_MEMIF_VUL12,
++	MT7986_MEMIF_NUM,
++	MT7986_DAI_ETDM = MT7986_MEMIF_NUM,
++	MT7986_DAI_NUM,
++};
++
++enum {
++	MT7986_IRQ_0,
++	MT7986_IRQ_1,
++	MT7986_IRQ_2,
++	MT7986_IRQ_NUM,
++};
++
++struct mt7986_afe_private {
++	struct clk_bulk_data *clks;
++	int num_clks;
++
++	int pm_runtime_bypass_reg_ctl;
++
++	/* dai */
++	void *dai_priv[MT7986_DAI_NUM];
++};
++
++unsigned int mt7986_afe_rate_transform(struct device *dev,
++				       unsigned int rate);
++
++/* dai register */
++int mt7986_dai_etdm_register(struct mtk_base_afe *afe);
++#endif
+diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+new file mode 100644
+index 0000000..e2f8c51
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+@@ -0,0 +1,640 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * MediaTek ALSA SoC AFE platform driver for MT7986
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ *          Maso Huang <maso.huang@mediatek.com>
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/pm_runtime.h>
++
++#include "mt7986-afe-common.h"
++#include "mt7986-reg.h"
++#include "../common/mtk-afe-platform-driver.h"
++#include "../common/mtk-afe-fe-dai.h"
++
++enum {
++	MTK_AFE_RATE_8K = 0,
++	MTK_AFE_RATE_11K = 1,
++	MTK_AFE_RATE_12K = 2,
++	MTK_AFE_RATE_16K = 4,
++	MTK_AFE_RATE_22K = 5,
++	MTK_AFE_RATE_24K = 6,
++	MTK_AFE_RATE_32K = 8,
++	MTK_AFE_RATE_44K = 9,
++	MTK_AFE_RATE_48K = 10,
++	MTK_AFE_RATE_88K = 13,
++	MTK_AFE_RATE_96K = 14,
++	MTK_AFE_RATE_176K = 17,
++	MTK_AFE_RATE_192K = 18,
++};
++
++enum {
++	CLK_INFRA_AUD_BUS_CK = 0,
++	CLK_INFRA_AUD_26M_CK,
++	CLK_INFRA_AUD_L_CK,
++	CLK_INFRA_AUD_AUD_CK,
++	CLK_INFRA_AUD_EG2_CK,
++	CLK_NUM
++};
++
++static const char *aud_clks[CLK_NUM] = {
++	[CLK_INFRA_AUD_BUS_CK] = "aud_bus_ck",
++	[CLK_INFRA_AUD_26M_CK] = "aud_26m_ck",
++	[CLK_INFRA_AUD_L_CK] = "aud_l_ck",
++	[CLK_INFRA_AUD_AUD_CK] = "aud_aud_ck",
++	[CLK_INFRA_AUD_EG2_CK] = "aud_eg2_ck",
++};
++
++unsigned int mt7986_afe_rate_transform(struct device *dev, unsigned int rate)
++{
++	switch (rate) {
++	case 8000:
++		return MTK_AFE_RATE_8K;
++	case 11025:
++		return MTK_AFE_RATE_11K;
++	case 12000:
++		return MTK_AFE_RATE_12K;
++	case 16000:
++		return MTK_AFE_RATE_16K;
++	case 22050:
++		return MTK_AFE_RATE_22K;
++	case 24000:
++		return MTK_AFE_RATE_24K;
++	case 32000:
++		return MTK_AFE_RATE_32K;
++	case 44100:
++		return MTK_AFE_RATE_44K;
++	case 48000:
++		return MTK_AFE_RATE_48K;
++	case 88200:
++		return MTK_AFE_RATE_88K;
++	case 96000:
++		return MTK_AFE_RATE_96K;
++	case 176400:
++		return MTK_AFE_RATE_176K;
++	case 192000:
++		return MTK_AFE_RATE_192K;
++	default:
++		dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
++			 __func__, rate, MTK_AFE_RATE_48K);
++		return MTK_AFE_RATE_48K;
++	}
++}
++
++static const struct snd_pcm_hardware mt7986_afe_hardware = {
++	.info = SNDRV_PCM_INFO_MMAP |
++		SNDRV_PCM_INFO_INTERLEAVED |
++		SNDRV_PCM_INFO_MMAP_VALID,
++	.formats = SNDRV_PCM_FMTBIT_S16_LE |
++		   SNDRV_PCM_FMTBIT_S24_LE |
++		   SNDRV_PCM_FMTBIT_S32_LE,
++	.period_bytes_min = 256,
++	.period_bytes_max = 4 * 48 * 1024,
++	.periods_min = 2,
++	.periods_max = 256,
++	.buffer_bytes_max = 8 * 48 * 1024,
++	.fifo_size = 0,
++};
++
++static int mt7986_memif_fs(struct snd_pcm_substream *substream,
++			   unsigned int rate)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
++	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
++
++	return mt7986_afe_rate_transform(afe->dev, rate);
++}
++
++static int mt7986_irq_fs(struct snd_pcm_substream *substream,
++			 unsigned int rate)
++{
++	struct snd_soc_pcm_runtime *rtd = substream->private_data;
++	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
++	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
++
++	return mt7986_afe_rate_transform(afe->dev, rate);
++}
++
++#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000 |\
++		       SNDRV_PCM_RATE_88200 |\
++		       SNDRV_PCM_RATE_96000 |\
++		       SNDRV_PCM_RATE_176400 |\
++		       SNDRV_PCM_RATE_192000)
++
++#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
++			 SNDRV_PCM_FMTBIT_S24_LE |\
++			 SNDRV_PCM_FMTBIT_S32_LE)
++
++static struct snd_soc_dai_driver mt7986_memif_dai_driver[] = {
++	/* FE DAIs: memory intefaces to CPU */
++	{
++		.name = "DL1",
++		.id = MT7986_MEMIF_DL1,
++		.playback = {
++			.stream_name = "DL1",
++			.channels_min = 1,
++			.channels_max = 2,
++			.rates = MTK_PCM_RATES,
++			.formats = MTK_PCM_FORMATS,
++		},
++		.ops = &mtk_afe_fe_ops,
++	},
++	{
++		.name = "UL1",
++		.id = MT7986_MEMIF_VUL12,
++		.capture = {
++			.stream_name = "UL1",
++			.channels_min = 1,
++			.channels_max = 2,
++			.rates = MTK_PCM_RATES,
++			.formats = MTK_PCM_FORMATS,
++		},
++		.ops = &mtk_afe_fe_ops,
++	},
++};
++
++static const struct snd_kcontrol_new o018_mix[] = {
++	SOC_DAPM_SINGLE_AUTODISABLE("I150_Switch", AFE_CONN018_4, 22, 1, 0),
++};
++
++static const struct snd_kcontrol_new o019_mix[] = {
++	SOC_DAPM_SINGLE_AUTODISABLE("I151_Switch", AFE_CONN019_4, 23, 1, 0),
++};
++
++static const struct snd_soc_dapm_widget mt7986_memif_widgets[] = {
++	/* DL */
++	SND_SOC_DAPM_MIXER("I032", SND_SOC_NOPM, 0, 0, NULL, 0),
++	SND_SOC_DAPM_MIXER("I033", SND_SOC_NOPM, 0, 0, NULL, 0),
++
++	/* UL */
++	SND_SOC_DAPM_MIXER("O018", SND_SOC_NOPM, 0, 0,
++			   o018_mix, ARRAY_SIZE(o018_mix)),
++	SND_SOC_DAPM_MIXER("O019", SND_SOC_NOPM, 0, 0,
++			   o019_mix, ARRAY_SIZE(o019_mix)),
++};
++
++static const struct snd_soc_dapm_route mt7986_memif_routes[] = {
++	{"I032", NULL, "DL1"},
++	{"I033", NULL, "DL1"},
++	{"UL1", NULL, "O018"},
++	{"UL1", NULL, "O019"},
++	{"O018", "I150_Switch", "I150"},
++	{"O019", "I151_Switch", "I151"},
++};
++
++static const struct snd_soc_component_driver mt7986_afe_pcm_dai_component = {
++	.name = "mt7986-afe-pcm-dai",
++};
++
++static const struct mtk_base_memif_data memif_data[MT7986_MEMIF_NUM] = {
++	[MT7986_MEMIF_DL1] = {
++		.name = "DL1",
++		.id = MT7986_MEMIF_DL1,
++		.reg_ofs_base = AFE_DL0_BASE,
++		.reg_ofs_cur = AFE_DL0_CUR,
++		.reg_ofs_end = AFE_DL0_END,
++		.reg_ofs_base_msb = AFE_DL0_BASE_MSB,
++		.reg_ofs_cur_msb = AFE_DL0_CUR_MSB,
++		.reg_ofs_end_msb = AFE_DL0_END_MSB,
++		.fs_reg = AFE_DL0_CON0,
++		.fs_shift =  DL0_MODE_SFT,
++		.fs_maskbit =  DL0_MODE_MASK,
++		.mono_reg = AFE_DL0_CON0,
++		.mono_shift = DL0_MONO_SFT,
++		.enable_reg = AFE_DL0_CON0,
++		.enable_shift = DL0_ON_SFT,
++		.hd_reg = AFE_DL0_CON0,
++		.hd_shift = DL0_HD_MODE_SFT,
++		.hd_align_reg = AFE_DL0_CON0,
++		.hd_align_mshift = DL0_HALIGN_SFT,
++		.pbuf_reg = AFE_DL0_CON0,
++		.pbuf_shift = DL0_PBUF_SIZE_SFT,
++		.minlen_reg = AFE_DL0_CON0,
++		.minlen_shift = DL0_MINLEN_SFT,
++	},
++	[MT7986_MEMIF_VUL12] = {
++		.name = "VUL12",
++		.id = MT7986_MEMIF_VUL12,
++		.reg_ofs_base = AFE_VUL0_BASE,
++		.reg_ofs_cur = AFE_VUL0_CUR,
++		.reg_ofs_end = AFE_VUL0_END,
++		.reg_ofs_base_msb = AFE_VUL0_BASE_MSB,
++		.reg_ofs_cur_msb = AFE_VUL0_CUR_MSB,
++		.reg_ofs_end_msb = AFE_VUL0_END_MSB,
++		.fs_reg = AFE_VUL0_CON0,
++		.fs_shift = VUL0_MODE_SFT,
++		.fs_maskbit = VUL0_MODE_MASK,
++		.mono_reg = AFE_VUL0_CON0,
++		.mono_shift = VUL0_MONO_SFT,
++		.enable_reg = AFE_VUL0_CON0,
++		.enable_shift = VUL0_ON_SFT,
++		.hd_reg = AFE_VUL0_CON0,
++		.hd_shift = VUL0_HD_MODE_SFT,
++		.hd_align_reg = AFE_VUL0_CON0,
++		.hd_align_mshift = VUL0_HALIGN_SFT,
++	},
++};
++
++static const struct mtk_base_irq_data irq_data[MT7986_IRQ_NUM] = {
++	[MT7986_IRQ_0] = {
++		.id = MT7986_IRQ_0,
++		.irq_cnt_reg = AFE_IRQ0_MCU_CFG1,
++		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
++		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
++		.irq_fs_reg = AFE_IRQ0_MCU_CFG0,
++		.irq_fs_shift = IRQ_MCU_MODE_SFT,
++		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
++		.irq_en_reg = AFE_IRQ0_MCU_CFG0,
++		.irq_en_shift = IRQ_MCU_ON_SFT,
++		.irq_clr_reg = AFE_IRQ_MCU_CLR,
++		.irq_clr_shift = IRQ0_MCU_CLR_SFT,
++	},
++	[MT7986_IRQ_1] = {
++		.id = MT7986_IRQ_1,
++		.irq_cnt_reg = AFE_IRQ1_MCU_CFG1,
++		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
++		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
++		.irq_fs_reg = AFE_IRQ1_MCU_CFG0,
++		.irq_fs_shift = IRQ_MCU_MODE_SFT,
++		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
++		.irq_en_reg = AFE_IRQ1_MCU_CFG0,
++		.irq_en_shift = IRQ_MCU_ON_SFT,
++		.irq_clr_reg = AFE_IRQ_MCU_CLR,
++		.irq_clr_shift = IRQ1_MCU_CLR_SFT,
++	},
++	[MT7986_IRQ_2] = {
++		.id = MT7986_IRQ_2,
++		.irq_cnt_reg = AFE_IRQ2_MCU_CFG1,
++		.irq_cnt_shift = AFE_IRQ_CNT_SHIFT,
++		.irq_cnt_maskbit = AFE_IRQ_CNT_MASK,
++		.irq_fs_reg = AFE_IRQ2_MCU_CFG0,
++		.irq_fs_shift = IRQ_MCU_MODE_SFT,
++		.irq_fs_maskbit = IRQ_MCU_MODE_MASK,
++		.irq_en_reg = AFE_IRQ2_MCU_CFG0,
++		.irq_en_shift = IRQ_MCU_ON_SFT,
++		.irq_clr_reg = AFE_IRQ_MCU_CLR,
++		.irq_clr_shift = IRQ2_MCU_CLR_SFT,
++	},
++};
++
++static bool mt7986_is_volatile_reg(struct device *dev, unsigned int reg)
++{
++	/*
++	 * Those auto-gen regs are read-only, so put it as volatile because
++	 * volatile registers cannot be cached, which means that they cannot
++	 * be set when power is off
++	 */
++
++	switch (reg) {
++	case AFE_DL0_CUR_MSB:
++	case AFE_DL0_CUR:
++	case AFE_DL0_RCH_MON:
++	case AFE_DL0_LCH_MON:
++	case AFE_VUL0_CUR_MSB:
++	case AFE_VUL0_CUR:
++	case AFE_IRQ_MCU_STATUS:
++	case AFE_MEMIF_RD_MON:
++	case AFE_MEMIF_WR_MON:
++		return true;
++	default:
++		return false;
++	};
++}
++
++static const struct regmap_config mt7986_afe_regmap_config = {
++	.reg_bits = 32,
++	.reg_stride = 4,
++	.val_bits = 32,
++	.volatile_reg = mt7986_is_volatile_reg,
++	.max_register = AFE_MAX_REGISTER,
++	.num_reg_defaults_raw = ((AFE_MAX_REGISTER / 4) + 1),
++};
++
++static int mt7986_init_clock(struct mtk_base_afe *afe)
++{
++	struct mt7986_afe_private *afe_priv = afe->platform_priv;
++	int ret, i;
++
++	afe_priv->clks = devm_kcalloc(afe->dev, CLK_NUM,
++				sizeof(*afe_priv->clks), GFP_KERNEL);
++	if (!afe_priv->clks)
++		return -ENOMEM;
++	afe_priv->num_clks = CLK_NUM;
++
++	for (i = 0; i < afe_priv->num_clks; i++)
++		afe_priv->clks[i].id = aud_clks[i];
++
++	ret = devm_clk_bulk_get(afe->dev, afe_priv->num_clks, afe_priv->clks);
++	if (ret) {
++		dev_err(afe->dev, "Failed to get clocks\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++static irqreturn_t mt7986_afe_irq_handler(int irq_id, void *dev)
++{
++	struct mtk_base_afe *afe = dev;
++	struct mtk_base_afe_irq *irq;
++	u32 mcu_en, status, status_mcu;
++	int i, ret;
++	irqreturn_t irq_ret = IRQ_HANDLED;
++
++	/* get irq that is sent to MCU */
++	regmap_read(afe->regmap, AFE_IRQ_MCU_EN, &mcu_en);
++
++	ret = regmap_read(afe->regmap, AFE_IRQ_MCU_STATUS, &status);
++	/* only care IRQ which is sent to MCU */
++	status_mcu = status & mcu_en & AFE_IRQ_STATUS_BITS;
++
++	if (ret || status_mcu == 0) {
++		dev_err(afe->dev, "%s(), irq status err, ret %d, status 0x%x, mcu_en 0x%x\n",
++			__func__, ret, status, mcu_en);
++
++		irq_ret = IRQ_NONE;
++		goto err_irq;
++	}
++
++	for (i = 0; i < MT7986_MEMIF_NUM; i++) {
++		struct mtk_base_afe_memif *memif = &afe->memif[i];
++
++		if (!memif->substream)
++			continue;
++
++		if (memif->irq_usage < 0)
++			continue;
++
++		irq = &afe->irqs[memif->irq_usage];
++
++		if (status_mcu & (1 << irq->irq_data->irq_en_shift))
++			snd_pcm_period_elapsed(memif->substream);
++	}
++
++err_irq:
++	/* clear irq */
++	regmap_write(afe->regmap, AFE_IRQ_MCU_CLR, status_mcu);
++
++	return irq_ret;
++}
++
++static int mt7986_afe_runtime_suspend(struct device *dev)
++{
++	struct mtk_base_afe *afe = dev_get_drvdata(dev);
++	struct mt7986_afe_private *afe_priv = afe->platform_priv;
++
++	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
++		goto skip_regmap;
++
++	/* disable clk*/
++	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0x3fff);
++	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK, 0);
++	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK, 0);
++
++	/* make sure all irq status are cleared, twice intended */
++	regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CLR, 0xffff, 0xffff);
++
++skip_regmap:
++	clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
++
++	return 0;
++}
++
++static int mt7986_afe_runtime_resume(struct device *dev)
++{
++	struct mtk_base_afe *afe = dev_get_drvdata(dev);
++	struct mt7986_afe_private *afe_priv = afe->platform_priv;
++	int ret;
++
++	ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
++	if (ret) {
++		dev_err(afe->dev, "Failed to enable clocks\n");
++		return ret;
++	}
++
++	if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
++		return 0;
++
++	/* enable clk*/
++	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, 0x3fff, 0);
++	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_APLL2_EN_MASK,
++			   AUD_APLL2_EN);
++	regmap_update_bits(afe->regmap, AUDIO_ENGEN_CON0, AUD_26M_EN_MASK,
++			   AUD_26M_EN);
++
++	return 0;
++}
++
++static int mt7986_afe_component_probe(struct snd_soc_component *component)
++{
++	return mtk_afe_add_sub_dai_control(component);
++}
++
++static const struct snd_soc_component_driver mt7986_afe_component = {
++	.name = AFE_PCM_NAME,
++	.ops = &mtk_afe_pcm_ops,
++	.pcm_new = mtk_afe_pcm_new,
++	.pcm_free = mtk_afe_pcm_free,
++	.probe = mt7986_afe_component_probe,
++};
++
++static int mt7986_dai_memif_register(struct mtk_base_afe *afe)
++{
++	struct mtk_base_afe_dai *dai;
++
++	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
++	if (!dai)
++		return -ENOMEM;
++
++	list_add(&dai->list, &afe->sub_dais);
++
++	dai->dai_drivers = mt7986_memif_dai_driver;
++	dai->num_dai_drivers = ARRAY_SIZE(mt7986_memif_dai_driver);
++
++	dai->dapm_widgets = mt7986_memif_widgets;
++	dai->num_dapm_widgets = ARRAY_SIZE(mt7986_memif_widgets);
++	dai->dapm_routes = mt7986_memif_routes;
++	dai->num_dapm_routes = ARRAY_SIZE(mt7986_memif_routes);
++
++	return 0;
++}
++
++typedef int (*dai_register_cb)(struct mtk_base_afe *);
++static const dai_register_cb dai_register_cbs[] = {
++	mt7986_dai_etdm_register,
++	mt7986_dai_memif_register,
++};
++
++static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev)
++{
++	struct mtk_base_afe *afe;
++	struct mt7986_afe_private *afe_priv;
++	struct device *dev;
++	int i, irq_id, ret;
++
++	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
++	if (!afe)
++		return -ENOMEM;
++	platform_set_drvdata(pdev, afe);
++
++	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
++					  GFP_KERNEL);
++	if (!afe->platform_priv)
++		return -ENOMEM;
++
++	afe_priv = afe->platform_priv;
++	afe->dev = &pdev->dev;
++	dev = afe->dev;
++
++	afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
++	if (IS_ERR(afe->base_addr))
++		return PTR_ERR(afe->base_addr);
++
++	/* initial audio related clock */
++	ret = mt7986_init_clock(afe);
++	if (ret) {
++		dev_err(dev, "Cannot initialize clocks\n");
++		return ret;
++	}
++
++	pm_runtime_enable(dev);
++
++	/* enable clock for regcache get default value from hw */
++	afe_priv->pm_runtime_bypass_reg_ctl = true;
++	pm_runtime_get_sync(&pdev->dev);
++
++	afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr,
++		      &mt7986_afe_regmap_config);
++
++	pm_runtime_put_sync(&pdev->dev);
++	if (IS_ERR(afe->regmap))
++		return PTR_ERR(afe->regmap);
++
++	afe_priv->pm_runtime_bypass_reg_ctl = false;
++
++	/* init memif */
++	afe->memif_size = MT7986_MEMIF_NUM;
++	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
++				  GFP_KERNEL);
++	if (!afe->memif)
++		return -ENOMEM;
++
++	for (i = 0; i < afe->memif_size; i++) {
++		afe->memif[i].data = &memif_data[i];
++		afe->memif[i].irq_usage = -1;
++	}
++
++	mutex_init(&afe->irq_alloc_lock);
++
++	/* irq initialize */
++	afe->irqs_size = MT7986_IRQ_NUM;
++	afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
++				 GFP_KERNEL);
++	if (!afe->irqs)
++		return -ENOMEM;
++
++	for (i = 0; i < afe->irqs_size; i++)
++		afe->irqs[i].irq_data = &irq_data[i];
++
++	/* request irq */
++	irq_id = platform_get_irq(pdev, 0);
++	if (irq_id < 0) {
++		ret = irq_id;
++		dev_err(dev, "No irq found\n");
++		return ret;
++	}
++	ret = devm_request_irq(dev, irq_id, mt7986_afe_irq_handler,
++			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
++	if (ret) {
++		dev_err(dev, "Failed to request irq for asys-isr\n");
++		return ret;
++	}
++
++	/* init sub_dais */
++	INIT_LIST_HEAD(&afe->sub_dais);
++
++	for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
++		ret = dai_register_cbs[i](afe);
++		if (ret) {
++			dev_err(dev, "DAI register failed, i: %d\n", i);
++			return ret;
++		}
++	}
++
++	/* init dai_driver and component_driver */
++	ret = mtk_afe_combine_sub_dai(afe);
++	if (ret) {
++		dev_err(dev, "mtk_afe_combine_sub_dai fail\n");
++		return ret;
++	}
++
++	afe->mtk_afe_hardware = &mt7986_afe_hardware;
++	afe->memif_fs = mt7986_memif_fs;
++	afe->irq_fs = mt7986_irq_fs;
++
++	afe->runtime_resume = mt7986_afe_runtime_resume;
++	afe->runtime_suspend = mt7986_afe_runtime_suspend;
++
++	/* register component */
++	ret = devm_snd_soc_register_component(&pdev->dev,
++					      &mt7986_afe_component,
++					      NULL, 0);
++	if (ret) {
++		dev_err(dev, "Cannot register AFE component\n");
++		return ret;
++	}
++
++	ret = devm_snd_soc_register_component(afe->dev,
++					      &mt7986_afe_pcm_dai_component,
++					      afe->dai_drivers,
++					      afe->num_dai_drivers);
++	if (ret) {
++		dev_err(dev, "Cannot register PCM DAI component\n");
++		return ret;
++	}
++
++	return 0;
++}
++
++static int mt7986_afe_pcm_dev_remove(struct platform_device *pdev)
++{
++	pm_runtime_disable(&pdev->dev);
++	if (!pm_runtime_status_suspended(&pdev->dev))
++		mt7986_afe_runtime_suspend(&pdev->dev);
++
++	return 0;
++}
++
++static const struct of_device_id mt7986_afe_pcm_dt_match[] = {
++	{ .compatible = "mediatek,mt7986-afe" },
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match);
++
++static const struct dev_pm_ops mt7986_afe_pm_ops = {
++	SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend,
++			   mt7986_afe_runtime_resume, NULL)
++};
++
++static struct platform_driver mt7986_afe_pcm_driver = {
++	.driver = {
++		   .name = "mt7986-audio",
++		   .of_match_table = mt7986_afe_pcm_dt_match,
++		   .pm = &mt7986_afe_pm_ops,
++	},
++	.probe = mt7986_afe_pcm_dev_probe,
++	.remove = mt7986_afe_pcm_dev_remove,
++};
++module_platform_driver(mt7986_afe_pcm_driver);
++
++MODULE_DESCRIPTION("MediaTek SoC AFE platform driver for ALSA MT7986");
++MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
++MODULE_LICENSE("GPL");
+diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
+new file mode 100644
+index 0000000..192f55a
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
+@@ -0,0 +1,428 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * MediaTek ALSA SoC Audio DAI eTDM Control
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ *          Maso Huang <maso.huang@mediatek.com>
++ */
++
++#include <linux/bitfield.h>
++#include <linux/bitops.h>
++#include <linux/regmap.h>
++#include <sound/pcm_params.h>
++#include "mt7986-afe-common.h"
++#include "mt7986-reg.h"
++
++#define HOPPING_CLK  0
++#define APLL_CLK     1
++#define MTK_DAI_ETDM_FORMAT_I2S   0
++#define MTK_DAI_ETDM_FORMAT_DSPA  4
++#define MTK_DAI_ETDM_FORMAT_DSPB  5
++
++enum {
++	MTK_ETDM_RATE_8K = 0,
++	MTK_ETDM_RATE_12K = 1,
++	MTK_ETDM_RATE_16K = 2,
++	MTK_ETDM_RATE_24K = 3,
++	MTK_ETDM_RATE_32K = 4,
++	MTK_ETDM_RATE_48K = 5,
++	MTK_ETDM_RATE_96K = 7,
++	MTK_ETDM_RATE_192K = 9,
++	MTK_ETDM_RATE_11K = 16,
++	MTK_ETDM_RATE_22K = 17,
++	MTK_ETDM_RATE_44K = 18,
++	MTK_ETDM_RATE_88K = 19,
++	MTK_ETDM_RATE_176K = 20,
++};
++
++struct mtk_dai_etdm_priv {
++	bool bck_inv;
++	bool lrck_inv;
++	bool slave_mode;
++	unsigned int format;
++};
++
++static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate)
++{
++	switch (rate) {
++	case 8000:
++		return MTK_ETDM_RATE_8K;
++	case 11025:
++		return MTK_ETDM_RATE_11K;
++	case 12000:
++		return MTK_ETDM_RATE_12K;
++	case 16000:
++		return MTK_ETDM_RATE_16K;
++	case 22050:
++		return MTK_ETDM_RATE_22K;
++	case 24000:
++		return MTK_ETDM_RATE_24K;
++	case 32000:
++		return MTK_ETDM_RATE_32K;
++	case 44100:
++		return MTK_ETDM_RATE_44K;
++	case 48000:
++		return MTK_ETDM_RATE_48K;
++	case 88200:
++		return MTK_ETDM_RATE_88K;
++	case 96000:
++		return MTK_ETDM_RATE_96K;
++	case 176400:
++		return MTK_ETDM_RATE_176K;
++	case 192000:
++		return MTK_ETDM_RATE_192K;
++	default:
++		dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n",
++			 __func__, rate, MTK_ETDM_RATE_48K);
++		return MTK_ETDM_RATE_48K;
++	}
++}
++
++static int get_etdm_wlen(unsigned int bitwidth)
++{
++	return bitwidth <= 16 ? 16 : 32;
++}
++
++/* dai component */
++/* interconnection */
++
++static const struct snd_kcontrol_new o124_mix[] = {
++	SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch", AFE_CONN124_1, 0, 1, 0),
++};
++
++static const struct snd_kcontrol_new o125_mix[] = {
++	SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch", AFE_CONN125_1, 1, 1, 0),
++};
++
++static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = {
++
++	/* DL */
++	SND_SOC_DAPM_MIXER("I150", SND_SOC_NOPM, 0, 0, NULL, 0),
++	SND_SOC_DAPM_MIXER("I151", SND_SOC_NOPM, 0, 0, NULL, 0),
++	/* UL */
++	SND_SOC_DAPM_MIXER("O124", SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)),
++	SND_SOC_DAPM_MIXER("O125", SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)),
++};
++
++static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = {
++	{"I150", NULL, "ETDM Capture"},
++	{"I151", NULL, "ETDM Capture"},
++	{"ETDM Playback", NULL, "O124"},
++	{"ETDM Playback", NULL, "O125"},
++	{"O124", "I032_Switch", "I032"},
++	{"O125", "I033_Switch", "I033"},
++};
++
++/* dai ops */
++static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
++				struct snd_soc_dai *dai)
++{
++	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++	struct mt7986_afe_private *afe_priv = afe->platform_priv;
++	int ret;
++
++	ret = clk_bulk_prepare_enable(afe_priv->num_clks, afe_priv->clks);
++	if (ret) {
++		dev_err(afe->dev, "Failed to enable clocks\n");
++		return ret;
++	}
++
++	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, 0);
++	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, 0);
++
++	return 0;
++}
++
++static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
++				  struct snd_soc_dai *dai)
++{
++	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++	struct mt7986_afe_private *afe_priv = afe->platform_priv;
++
++	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK,
++			   CLK_OUT5_PDN);
++	regmap_update_bits(afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK,
++			   CLK_IN5_PDN);
++
++	clk_bulk_disable_unprepare(afe_priv->num_clks, afe_priv->clks);
++}
++
++static unsigned int get_etdm_ch_fixup(unsigned int channels)
++{
++	if (channels > 16)
++		return 24;
++	else if (channels > 8)
++		return 16;
++	else if (channels > 4)
++		return 8;
++	else if (channels > 2)
++		return 4;
++	else
++		return 2;
++}
++
++static int mtk_dai_etdm_config(struct mtk_base_afe *afe,
++			       struct snd_pcm_hw_params *params,
++			       struct snd_soc_dai *dai,
++			       int stream)
++{
++	struct mt7986_afe_private *afe_priv = afe->platform_priv;
++	struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id];
++	unsigned int rate = params_rate(params);
++	unsigned int etdm_rate = mt7986_etdm_rate_transform(afe->dev, rate);
++	unsigned int afe_rate = mt7986_afe_rate_transform(afe->dev, rate);
++	unsigned int channels = params_channels(params);
++	unsigned int bit_width = params_width(params);
++	unsigned int wlen = get_etdm_wlen(bit_width);
++	unsigned int val = 0;
++	unsigned int mask = 0;
++
++	dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n",
++		 __func__, stream, rate, bit_width);
++
++	/* CON0 */
++	mask |= ETDM_BIT_LEN_MASK;
++	val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1);
++	mask |= ETDM_WRD_LEN_MASK;
++	val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1);
++	mask |= ETDM_FMT_MASK;
++	val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format);
++	mask |= ETDM_CH_NUM_MASK;
++	val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1);
++	mask |= RELATCH_SRC_MASK;
++	val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK);
++
++	switch (stream) {
++	case SNDRV_PCM_STREAM_PLAYBACK:
++		/* set ETDM_OUT5_CON0 */
++		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, mask, val);
++
++		/* set ETDM_OUT5_CON4 */
++		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
++				   OUT_RELATCH_MASK, OUT_RELATCH(afe_rate));
++		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
++				   OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK));
++		regmap_update_bits(afe->regmap, ETDM_OUT5_CON4,
++				   OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate));
++
++		/* set ETDM_OUT5_CON5 */
++		regmap_update_bits(afe->regmap, ETDM_OUT5_CON5,
++				   ETDM_CLK_DIV_MASK, ETDM_CLK_DIV);
++		break;
++	case SNDRV_PCM_STREAM_CAPTURE:
++		/* set ETDM_IN5_CON0 */
++		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, mask, val);
++		regmap_update_bits(afe->regmap, ETDM_IN5_CON0,
++				   ETDM_SYNC_MASK, ETDM_SYNC);
++
++		/* set ETDM_IN5_CON2 */
++		regmap_update_bits(afe->regmap, ETDM_IN5_CON2,
++				   IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK));
++
++		/* set ETDM_IN5_CON3 */
++		regmap_update_bits(afe->regmap, ETDM_IN5_CON3,
++				   IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate));
++
++		/* set ETDM_IN5_CON4 */
++		regmap_update_bits(afe->regmap, ETDM_IN5_CON4,
++				   IN_RELATCH_MASK, IN_RELATCH(afe_rate));
++		break;
++	default:
++		break;
++	}
++
++	return 0;
++}
++
++static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream,
++				  struct snd_pcm_hw_params *params,
++				  struct snd_soc_dai *dai)
++{
++	unsigned int rate = params_rate(params);
++	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++
++	switch (rate) {
++	case 8000:
++	case 12000:
++	case 16000:
++	case 24000:
++	case 32000:
++	case 48000:
++	case 96000:
++	case 192000:
++		mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_PLAYBACK);
++		mtk_dai_etdm_config(afe, params, dai, SNDRV_PCM_STREAM_CAPTURE);
++		return 0;
++	default:
++		dev_err(afe->dev,
++			"Sample rate %d invalid. Supported rates: 8/12/16/24/32/48/96/192 kHz\n",
++			rate);
++		return -EINVAL;
++	}
++}
++
++static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd,
++				struct snd_soc_dai *dai)
++{
++	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++
++	dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n", __func__, cmd, dai->id);
++	switch (cmd) {
++	case SNDRV_PCM_TRIGGER_START:
++	case SNDRV_PCM_TRIGGER_RESUME:
++		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
++				   ETDM_EN);
++		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
++				   ETDM_EN);
++		break;
++	case SNDRV_PCM_TRIGGER_STOP:
++	case SNDRV_PCM_TRIGGER_SUSPEND:
++		regmap_update_bits(afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK,
++				   0);
++		regmap_update_bits(afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK,
++				   0);
++		break;
++	default:
++		break;
++	}
++
++	return 0;
++}
++
++static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
++{
++	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
++	struct mt7986_afe_private *afe_priv = afe->platform_priv;
++	struct mtk_dai_etdm_priv *etdm_data;
++	void *priv_data;
++
++	switch (dai->id) {
++	case MT7986_DAI_ETDM:
++		break;
++	default:
++		dev_warn(afe->dev, "%s(), id %d not support\n",
++			 __func__, dai->id);
++		return -EINVAL;
++	}
++
++	priv_data = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_etdm_priv),
++				 GFP_KERNEL);
++	if (!priv_data)
++		return -ENOMEM;
++
++	afe_priv->dai_priv[dai->id] = priv_data;
++	etdm_data = afe_priv->dai_priv[dai->id];
++
++	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++	case SND_SOC_DAIFMT_I2S:
++		etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S;
++		break;
++	case SND_SOC_DAIFMT_DSP_A:
++		etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA;
++		break;
++	case SND_SOC_DAIFMT_DSP_B:
++		etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++	case SND_SOC_DAIFMT_NB_NF:
++		etdm_data->bck_inv = false;
++		etdm_data->lrck_inv = false;
++		break;
++	case SND_SOC_DAIFMT_NB_IF:
++		etdm_data->bck_inv = false;
++		etdm_data->lrck_inv = true;
++		break;
++	case SND_SOC_DAIFMT_IB_NF:
++		etdm_data->bck_inv = true;
++		etdm_data->lrck_inv = false;
++		break;
++	case SND_SOC_DAIFMT_IB_IF:
++		etdm_data->bck_inv = true;
++		etdm_data->lrck_inv = true;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++	case SND_SOC_DAIFMT_CBM_CFM:
++		etdm_data->slave_mode = true;
++		break;
++	case SND_SOC_DAIFMT_CBS_CFS:
++		etdm_data->slave_mode = false;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static const struct snd_soc_dai_ops mtk_dai_etdm_ops = {
++	.startup = mtk_dai_etdm_startup,
++	.shutdown = mtk_dai_etdm_shutdown,
++	.hw_params = mtk_dai_etdm_hw_params,
++	.trigger = mtk_dai_etdm_trigger,
++	.set_fmt = mtk_dai_etdm_set_fmt,
++};
++
++/* dai driver */
++#define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
++			SNDRV_PCM_RATE_88200 |\
++			SNDRV_PCM_RATE_96000 |\
++			SNDRV_PCM_RATE_176400 |\
++			SNDRV_PCM_RATE_192000)
++
++#define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
++			  SNDRV_PCM_FMTBIT_S24_LE |\
++			  SNDRV_PCM_FMTBIT_S32_LE)
++
++static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = {
++	{
++		.name = "ETDM",
++		.id = MT7986_DAI_ETDM,
++		.capture = {
++			.stream_name = "ETDM Capture",
++			.channels_min = 1,
++			.channels_max = 2,
++			.rates = MTK_ETDM_RATES,
++			.formats = MTK_ETDM_FORMATS,
++		},
++		.playback = {
++			.stream_name = "ETDM Playback",
++			.channels_min = 1,
++			.channels_max = 2,
++			.rates = MTK_ETDM_RATES,
++			.formats = MTK_ETDM_FORMATS,
++		},
++		.ops = &mtk_dai_etdm_ops,
++		.symmetric_rates = 1,
++		.symmetric_samplebits = 1,
++	},
++};
++
++int mt7986_dai_etdm_register(struct mtk_base_afe *afe)
++{
++	struct mtk_base_afe_dai *dai;
++
++	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
++	if (!dai)
++		return -ENOMEM;
++
++	list_add(&dai->list, &afe->sub_dais);
++
++	dai->dai_drivers = mtk_dai_etdm_driver;
++	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver);
++
++	dai->dapm_widgets = mtk_dai_etdm_widgets;
++	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets);
++	dai->dapm_routes = mtk_dai_etdm_routes;
++	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes);
++
++	return 0;
++}
+diff --git a/sound/soc/mediatek/mt7986/mt7986-reg.h b/sound/soc/mediatek/mt7986/mt7986-reg.h
+new file mode 100644
+index 0000000..c2b2007
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-reg.h
+@@ -0,0 +1,196 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * mt7986-reg.h  --  MediaTek 7986 audio driver reg definition
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ *          Maso Huang <maso.huang@mediatek.com>
++ */
++
++#ifndef _MT7986_REG_H_
++#define _MT7986_REG_H_
++
++#define AUDIO_TOP_CON2                  0x0008
++#define AUDIO_TOP_CON4                  0x0010
++#define AUDIO_ENGEN_CON0                0x0014
++#define AFE_IRQ_MCU_EN                  0x0100
++#define AFE_IRQ_MCU_STATUS              0x0120
++#define AFE_IRQ_MCU_CLR                 0x0128
++#define AFE_IRQ0_MCU_CFG0               0x0140
++#define AFE_IRQ0_MCU_CFG1               0x0144
++#define AFE_IRQ1_MCU_CFG0               0x0148
++#define AFE_IRQ1_MCU_CFG1               0x014c
++#define AFE_IRQ2_MCU_CFG0               0x0150
++#define AFE_IRQ2_MCU_CFG1               0x0154
++#define ETDM_IN5_CON0                   0x13f0
++#define ETDM_IN5_CON1                   0x13f4
++#define ETDM_IN5_CON2                   0x13f8
++#define ETDM_IN5_CON3                   0x13fc
++#define ETDM_IN5_CON4                   0x1400
++#define ETDM_OUT5_CON0                  0x1570
++#define ETDM_OUT5_CON4                  0x1580
++#define ETDM_OUT5_CON5                  0x1584
++#define ETDM_4_7_COWORK_CON0            0x15e0
++#define ETDM_4_7_COWORK_CON1            0x15e4
++#define AFE_CONN018_1                   0x1b44
++#define AFE_CONN018_4                   0x1b50
++#define AFE_CONN019_1                   0x1b64
++#define AFE_CONN019_4                   0x1b70
++#define AFE_CONN124_1                   0x2884
++#define AFE_CONN124_4                   0x2890
++#define AFE_CONN125_1                   0x28a4
++#define AFE_CONN125_4                   0x28b0
++#define AFE_CONN_RS_0                   0x3920
++#define AFE_CONN_RS_3                   0x392c
++#define AFE_CONN_16BIT_0                0x3960
++#define AFE_CONN_16BIT_3                0x396c
++#define AFE_CONN_24BIT_0                0x3980
++#define AFE_CONN_24BIT_3                0x398c
++#define AFE_MEMIF_CON0                  0x3d98
++#define AFE_MEMIF_RD_MON                0x3da0
++#define AFE_MEMIF_WR_MON                0x3da4
++#define AFE_DL0_BASE_MSB                0x3e40
++#define AFE_DL0_BASE                    0x3e44
++#define AFE_DL0_CUR_MSB                 0x3e48
++#define AFE_DL0_CUR                     0x3e4c
++#define AFE_DL0_END_MSB                 0x3e50
++#define AFE_DL0_END                     0x3e54
++#define AFE_DL0_RCH_MON                 0x3e58
++#define AFE_DL0_LCH_MON                 0x3e5c
++#define AFE_DL0_CON0                    0x3e60
++#define AFE_VUL0_BASE_MSB               0x4220
++#define AFE_VUL0_BASE                   0x4224
++#define AFE_VUL0_CUR_MSB                0x4228
++#define AFE_VUL0_CUR                    0x422c
++#define AFE_VUL0_END_MSB                0x4230
++#define AFE_VUL0_END                    0x4234
++#define AFE_VUL0_CON0                   0x4238
++
++#define AFE_MAX_REGISTER AFE_VUL0_CON0
++#define AFE_IRQ_STATUS_BITS             0x7
++#define AFE_IRQ_CNT_SHIFT               0
++#define AFE_IRQ_CNT_MASK	        0xffffff
++
++/* AUDIO_TOP_CON2 */
++#define CLK_OUT5_PDN                    BIT(14)
++#define CLK_OUT5_PDN_MASK               BIT(14)
++#define CLK_IN5_PDN                     BIT(7)
++#define CLK_IN5_PDN_MASK                BIT(7)
++
++/* AUDIO_TOP_CON4 */
++#define PDN_APLL_TUNER2                 BIT(12)
++#define PDN_APLL_TUNER2_MASK            BIT(12)
++
++/* AUDIO_ENGEN_CON0 */
++#define AUD_APLL2_EN                    BIT(3)
++#define AUD_APLL2_EN_MASK               BIT(3)
++#define AUD_26M_EN                      BIT(0)
++#define AUD_26M_EN_MASK                 BIT(0)
++
++/* AFE_DL0_CON0 */
++#define DL0_ON_SFT                      28
++#define DL0_ON_MASK                     0x1
++#define DL0_ON_MASK_SFT                 BIT(28)
++#define DL0_MINLEN_SFT                  20
++#define DL0_MINLEN_MASK                 0xf
++#define DL0_MINLEN_MASK_SFT             (0xf << 20)
++#define DL0_MODE_SFT                    8
++#define DL0_MODE_MASK                   0x1f
++#define DL0_MODE_MASK_SFT               (0x1f << 8)
++#define DL0_PBUF_SIZE_SFT               5
++#define DL0_PBUF_SIZE_MASK              0x3
++#define DL0_PBUF_SIZE_MASK_SFT          (0x3 << 5)
++#define DL0_MONO_SFT                    4
++#define DL0_MONO_MASK                   0x1
++#define DL0_MONO_MASK_SFT               BIT(4)
++#define DL0_HALIGN_SFT                  2
++#define DL0_HALIGN_MASK                 0x1
++#define DL0_HALIGN_MASK_SFT             BIT(2)
++#define DL0_HD_MODE_SFT                 0
++#define DL0_HD_MODE_MASK                0x3
++#define DL0_HD_MODE_MASK_SFT            (0x3 << 0)
++
++/* AFE_VUL0_CON0 */
++#define VUL0_ON_SFT                     28
++#define VUL0_ON_MASK                    0x1
++#define VUL0_ON_MASK_SFT                BIT(28)
++#define VUL0_MODE_SFT                   8
++#define VUL0_MODE_MASK                  0x1f
++#define VUL0_MODE_MASK_SFT              (0x1f << 8)
++#define VUL0_MONO_SFT                   4
++#define VUL0_MONO_MASK                  0x1
++#define VUL0_MONO_MASK_SFT              BIT(4)
++#define VUL0_HALIGN_SFT                 2
++#define VUL0_HALIGN_MASK                0x1
++#define VUL0_HALIGN_MASK_SFT            BIT(2)
++#define VUL0_HD_MODE_SFT                0
++#define VUL0_HD_MODE_MASK               0x3
++#define VUL0_HD_MODE_MASK_SFT           (0x3 << 0)
++
++/* AFE_IRQ_MCU_CON */
++#define IRQ_MCU_MODE_SFT                4
++#define IRQ_MCU_MODE_MASK               0x1f
++#define IRQ_MCU_MODE_MASK_SFT           (0x1f << 4)
++#define IRQ_MCU_ON_SFT                  0
++#define IRQ_MCU_ON_MASK                 0x1
++#define IRQ_MCU_ON_MASK_SFT             BIT(0)
++#define IRQ0_MCU_CLR_SFT                0
++#define IRQ0_MCU_CLR_MASK               0x1
++#define IRQ0_MCU_CLR_MASK_SFT           BIT(0)
++#define IRQ1_MCU_CLR_SFT                1
++#define IRQ1_MCU_CLR_MASK               0x1
++#define IRQ1_MCU_CLR_MASK_SFT           BIT(1)
++#define IRQ2_MCU_CLR_SFT                2
++#define IRQ2_MCU_CLR_MASK               0x1
++#define IRQ2_MCU_CLR_MASK_SFT           BIT(2)
++
++/* ETDM_IN5_CON2 */
++#define IN_CLK_SRC(x)                   ((x) << 10)
++#define IN_CLK_SRC_SFT                  10
++#define IN_CLK_SRC_MASK                 GENMASK(12, 10)
++
++/* ETDM_IN5_CON3 */
++#define IN_SEL_FS(x)                    ((x) << 26)
++#define IN_SEL_FS_SFT                   26
++#define IN_SEL_FS_MASK                  GENMASK(30, 26)
++
++/* ETDM_IN5_CON4 */
++#define IN_RELATCH(x)                   ((x) << 20)
++#define IN_RELATCH_SFT                  20
++#define IN_RELATCH_MASK                 GENMASK(24, 20)
++#define IN_CLK_INV                      BIT(18)
++#define IN_CLK_INV_MASK                 BIT(18)
++
++/* ETDM_IN5_CON0 & ETDM_OUT5_CON0 */
++#define RELATCH_SRC_MASK                GENMASK(30, 28)
++#define ETDM_CH_NUM_MASK                GENMASK(27, 23)
++#define ETDM_WRD_LEN_MASK               GENMASK(20, 16)
++#define ETDM_BIT_LEN_MASK               GENMASK(15, 11)
++#define ETDM_FMT_MASK                   GENMASK(8, 6)
++#define ETDM_SYNC                       BIT(1)
++#define ETDM_SYNC_MASK                  BIT(1)
++#define ETDM_EN                         BIT(0)
++#define ETDM_EN_MASK                    BIT(0)
++
++/* ETDM_OUT5_CON4 */
++#define OUT_RELATCH(x)                  ((x) << 24)
++#define OUT_RELATCH_SFT                 24
++#define OUT_RELATCH_MASK                GENMASK(28, 24)
++#define OUT_CLK_SRC(x)                  ((x) << 6)
++#define OUT_CLK_SRC_SFT                 6
++#define OUT_CLK_SRC_MASK                GENMASK(8, 6)
++#define OUT_SEL_FS(x)                   (x)
++#define OUT_SEL_FS_SFT                  0
++#define OUT_SEL_FS_MASK                 GENMASK(4, 0)
++
++/* ETDM_OUT5_CON5 */
++#define ETDM_CLK_DIV                    BIT(12)
++#define ETDM_CLK_DIV_MASK               BIT(12)
++#define OUT_CLK_INV                     BIT(9)
++#define OUT_CLK_INV_MASK                BIT(9)
++
++/* ETDM_4_7_COWORK_CON0 */
++#define OUT_SEL(x)                      ((x) << 12)
++#define OUT_SEL_SFT                     12
++#define OUT_SEL_MASK                    GENMASK(15, 12)
++#endif
+diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
+new file mode 100644
+index 0000000..c1390b3
+--- /dev/null
++++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
+@@ -0,0 +1,177 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * mt7986-wm8960.c  --  MT7986-WM8960 ALSA SoC machine driver
++ *
++ * Copyright (c) 2023 MediaTek Inc.
++ * Authors: Vic Wu <vic.wu@mediatek.com>
++ *          Maso Huang <maso.huang@mediatek.com>
++ */
++
++#include <linux/module.h>
++#include <sound/soc.h>
++
++#include "mt7986-afe-common.h"
++
++static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = {
++	SND_SOC_DAPM_HP("Headphone", NULL),
++	SND_SOC_DAPM_MIC("AMIC", NULL),
++};
++
++static const struct snd_kcontrol_new mt7986_wm8960_controls[] = {
++	SOC_DAPM_PIN_SWITCH("Headphone"),
++	SOC_DAPM_PIN_SWITCH("AMIC"),
++};
++
++SND_SOC_DAILINK_DEFS(playback,
++	DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
++	DAILINK_COMP_ARRAY(COMP_DUMMY()),
++	DAILINK_COMP_ARRAY(COMP_EMPTY()));
++
++SND_SOC_DAILINK_DEFS(capture,
++	DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
++	DAILINK_COMP_ARRAY(COMP_DUMMY()),
++	DAILINK_COMP_ARRAY(COMP_EMPTY()));
++
++SND_SOC_DAILINK_DEFS(codec,
++	DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
++	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
++	DAILINK_COMP_ARRAY(COMP_EMPTY()));
++
++static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = {
++	/* FE */
++	{
++		.name = "wm8960-playback",
++		.stream_name = "wm8960-playback",
++		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
++			    SND_SOC_DPCM_TRIGGER_POST},
++		.dynamic = 1,
++		.dpcm_playback = 1,
++		SND_SOC_DAILINK_REG(playback),
++	},
++	{
++		.name = "wm8960-capture",
++		.stream_name = "wm8960-capture",
++		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
++			    SND_SOC_DPCM_TRIGGER_POST},
++		.dynamic = 1,
++		.dpcm_capture = 1,
++		SND_SOC_DAILINK_REG(capture),
++	},
++	/* BE */
++	{
++		.name = "wm8960-codec",
++		.no_pcm = 1,
++		.dai_fmt = SND_SOC_DAIFMT_I2S |
++			SND_SOC_DAIFMT_NB_NF |
++			SND_SOC_DAIFMT_CBS_CFS |
++			SND_SOC_DAIFMT_GATED,
++		.dpcm_playback = 1,
++		.dpcm_capture = 1,
++		SND_SOC_DAILINK_REG(codec),
++	},
++};
++
++static struct snd_soc_card mt7986_wm8960_card = {
++	.name = "mt7986-wm8960",
++	.owner = THIS_MODULE,
++	.dai_link = mt7986_wm8960_dai_links,
++	.num_links = ARRAY_SIZE(mt7986_wm8960_dai_links),
++	.controls = mt7986_wm8960_controls,
++	.num_controls = ARRAY_SIZE(mt7986_wm8960_controls),
++	.dapm_widgets = mt7986_wm8960_widgets,
++	.num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets),
++};
++
++static int mt7986_wm8960_machine_probe(struct platform_device *pdev)
++{
++	struct snd_soc_card *card = &mt7986_wm8960_card;
++	struct snd_soc_dai_link *dai_link;
++	struct device_node *platform, *codec;
++	struct device_node *platform_dai_node, *codec_dai_node;
++	int ret, i;
++
++	card->dev = &pdev->dev;
++
++	platform = of_get_child_by_name(pdev->dev.of_node, "platform");
++
++	if (platform) {
++		platform_dai_node = of_parse_phandle(platform, "sound-dai", 0);
++		of_node_put(platform);
++
++		if (!platform_dai_node) {
++			dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
++			return -EINVAL;
++		}
++	} else {
++		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
++		return -EINVAL;
++	}
++
++	for_each_card_prelinks(card, i, dai_link) {
++		if (dai_link->platforms->name)
++			continue;
++		dai_link->platforms->of_node = platform_dai_node;
++	}
++
++	codec = of_get_child_by_name(pdev->dev.of_node, "codec");
++
++	if (codec) {
++		codec_dai_node = of_parse_phandle(codec, "sound-dai", 0);
++		of_node_put(codec);
++
++		if (!codec_dai_node) {
++			of_node_put(platform_dai_node);
++			dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
++			return -EINVAL;
++		}
++	} else {
++		of_node_put(platform_dai_node);
++		dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
++		return -EINVAL;
++	}
++
++	for_each_card_prelinks(card, i, dai_link) {
++		if (dai_link->codecs->name)
++			continue;
++		dai_link->codecs->of_node = codec_dai_node;
++	}
++
++	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
++	if (ret) {
++		dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret);
++		goto err_of_node_put;
++	}
++
++	ret = devm_snd_soc_register_card(&pdev->dev, card);
++	if (ret) {
++		dev_err(&pdev->dev, "%s snd_soc_register_card fail: %d\n", __func__, ret);
++		goto err_of_node_put;
++	}
++
++err_of_node_put:
++	of_node_put(platform_dai_node);
++	of_node_put(codec_dai_node);
++	return ret;
++}
++
++static const struct of_device_id mt7986_wm8960_machine_dt_match[] = {
++	{.compatible = "mediatek,mt7986-wm8960-sound"},
++	{ /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match);
++
++static struct platform_driver mt7986_wm8960_machine = {
++	.driver = {
++		.name = "mt7986-wm8960",
++		.of_match_table = mt7986_wm8960_machine_dt_match,
++	},
++	.probe = mt7986_wm8960_machine_probe,
++};
++
++module_platform_driver(mt7986_wm8960_machine);
++
++/* Module information */
++MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver");
++MODULE_AUTHOR("Vic Wu <vic.wu@mediatek.com>");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("mt7986 wm8960 soc card");
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2210-v6.1-iio-adc-add-rtq6056-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1801-v6.1-iio-adc-add-rtq6056-support.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2210-v6.1-iio-adc-add-rtq6056-support.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1801-v6.1-iio-adc-add-rtq6056-support.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1000-backport-pinctrl-pinconf-setting-combo.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1802-v6.4-backport-pinctrl-pinconf-setting-combo.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1000-backport-pinctrl-pinconf-setting-combo.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1802-v6.4-backport-pinctrl-pinconf-setting-combo.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1033-backport-pinctrl-spinlock.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1803-v6.6-pinctrl-spinlock.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1033-backport-pinctrl-spinlock.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1803-v6.6-pinctrl-spinlock.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1804-v6.4-leds-pwm-multicolor.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1804-v6.4-leds-pwm-multicolor.patch
new file mode 100644
index 0000000..ea1ab5c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1804-v6.4-leds-pwm-multicolor.patch
@@ -0,0 +1,602 @@
+From 05c42f841f6d47f888f11c0ae016c217c3c81c7f Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Mon, 4 Dec 2023 19:16:12 +0800
+Subject: [PATCH] backport leds pwm multicolor from v6.4
+
+---
+ drivers/leds/Kconfig                 |  21 +++
+ drivers/leds/Makefile                |   2 +
+ drivers/leds/led-class-multicolor.c  | 203 +++++++++++++++++++++++++++
+ drivers/leds/leds-pwm-multicolor.c   | 194 +++++++++++++++++++++++++
+ include/linux/led-class-multicolor.h | 109 ++++++++++++++
+ 5 files changed, 529 insertions(+)
+ create mode 100644 drivers/leds/led-class-multicolor.c
+ create mode 100644 drivers/leds/leds-pwm-multicolor.c
+ create mode 100644 include/linux/led-class-multicolor.h
+
+diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
+index db18084..eebfb8c 100644
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -30,6 +30,16 @@ config LEDS_CLASS_FLASH
+ 	  for the flash related features of a LED device. It can be built
+ 	  as a module.
+ 
++config LEDS_CLASS_MULTICOLOR
++	tristate "LED Multicolor Class Support"
++	depends on LEDS_CLASS
++	help
++	  This option enables the multicolor LED sysfs class in /sys/class/leds.
++	  It wraps LED class and adds multicolor LED specific sysfs attributes
++	  and kernel internal API to it. You'll need this to provide support
++	  for multicolor LEDs that are grouped together. This class is not
++	  intended for single color LEDs. It can be built as a module.
++
+ config LEDS_BRIGHTNESS_HW_CHANGED
+ 	bool "LED Class brightness_hw_changed attribute support"
+ 	depends on LEDS_CLASS
+@@ -518,6 +528,17 @@ config LEDS_PWM
+ 	help
+ 	  This option enables support for pwm driven LEDs
+ 
++config LEDS_PWM_MULTICOLOR
++	tristate "PWM driven multi-color LED Support"
++	depends on LEDS_CLASS_MULTICOLOR
++	depends on PWM
++	help
++	  This option enables support for PWM driven monochrome LEDs that are
++	  grouped into multicolor LEDs.
++
++	  To compile this driver as a module, choose M here: the module
++	  will be called leds-pwm-multicolor.
++
+ config LEDS_REGULATOR
+ 	tristate "REGULATOR driven LED support"
+ 	depends on LEDS_CLASS
+diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
+index e648275..39885e5 100644
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -4,6 +4,7 @@
+ obj-$(CONFIG_NEW_LEDS)			+= led-core.o
+ obj-$(CONFIG_LEDS_CLASS)		+= led-class.o
+ obj-$(CONFIG_LEDS_CLASS_FLASH)		+= led-class-flash.o
++obj-$(CONFIG_LEDS_CLASS_MULTICOLOR)	+= led-class-multicolor.o
+ obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
+ 
+ # LED Platform Drivers
+@@ -54,6 +55,7 @@ obj-$(CONFIG_LEDS_DA9052)		+= leds-da9052.o
+ obj-$(CONFIG_LEDS_WM831X_STATUS)	+= leds-wm831x-status.o
+ obj-$(CONFIG_LEDS_WM8350)		+= leds-wm8350.o
+ obj-$(CONFIG_LEDS_PWM)			+= leds-pwm.o
++obj-$(CONFIG_LEDS_PWM_MULTICOLOR)	+= leds-pwm-multicolor.o
+ obj-$(CONFIG_LEDS_REGULATOR)		+= leds-regulator.o
+ obj-$(CONFIG_LEDS_INTEL_SS4200)		+= leds-ss4200.o
+ obj-$(CONFIG_LEDS_LT3593)		+= leds-lt3593.o
+diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c
+new file mode 100644
+index 0000000..16f3372
+--- /dev/null
++++ b/drivers/leds/led-class-multicolor.c
+@@ -0,0 +1,203 @@
++// SPDX-License-Identifier: GPL-2.0
++// LED Multicolor class interface
++// Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/
++// Author: Dan Murphy <dmurphy@ti.com>
++
++#include <linux/device.h>
++#include <linux/init.h>
++#include <linux/led-class-multicolor.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/uaccess.h>
++
++#include "leds.h"
++
++int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
++				 enum led_brightness brightness)
++{
++	struct led_classdev *led_cdev = &mcled_cdev->led_cdev;
++	int i;
++
++	for (i = 0; i < mcled_cdev->num_colors; i++)
++		mcled_cdev->subled_info[i].brightness = brightness *
++					  mcled_cdev->subled_info[i].intensity /
++					  led_cdev->max_brightness;
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(led_mc_calc_color_components);
++
++static ssize_t multi_intensity_store(struct device *dev,
++				struct device_attribute *intensity_attr,
++				const char *buf, size_t size)
++{
++	struct led_classdev *led_cdev = dev_get_drvdata(dev);
++	struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
++	int nrchars, offset = 0;
++	int intensity_value[LED_COLOR_ID_MAX];
++	int i;
++	ssize_t ret;
++
++	mutex_lock(&led_cdev->led_access);
++
++	for (i = 0; i < mcled_cdev->num_colors; i++) {
++		ret = sscanf(buf + offset, "%i%n",
++			     &intensity_value[i], &nrchars);
++		if (ret != 1) {
++			ret = -EINVAL;
++			goto err_out;
++		}
++		offset += nrchars;
++	}
++
++	offset++;
++	if (offset < size) {
++		ret = -EINVAL;
++		goto err_out;
++	}
++
++	for (i = 0; i < mcled_cdev->num_colors; i++)
++		mcled_cdev->subled_info[i].intensity = intensity_value[i];
++
++	led_set_brightness(led_cdev, led_cdev->brightness);
++	ret = size;
++err_out:
++	mutex_unlock(&led_cdev->led_access);
++	return ret;
++}
++
++static ssize_t multi_intensity_show(struct device *dev,
++			      struct device_attribute *intensity_attr,
++			      char *buf)
++{
++	struct led_classdev *led_cdev = dev_get_drvdata(dev);
++	struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
++	int len = 0;
++	int i;
++
++	for (i = 0; i < mcled_cdev->num_colors; i++) {
++		len += sprintf(buf + len, "%d",
++			       mcled_cdev->subled_info[i].intensity);
++		if (i < mcled_cdev->num_colors - 1)
++			len += sprintf(buf + len, " ");
++	}
++
++	buf[len++] = '\n';
++	return len;
++}
++static DEVICE_ATTR_RW(multi_intensity);
++
++static ssize_t multi_index_show(struct device *dev,
++			      struct device_attribute *multi_index_attr,
++			      char *buf)
++{
++	struct led_classdev *led_cdev = dev_get_drvdata(dev);
++	struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
++	int len = 0;
++	int index;
++	int i;
++
++	for (i = 0; i < mcled_cdev->num_colors; i++) {
++		index = mcled_cdev->subled_info[i].color_index;
++		len += sprintf(buf + len, "%s", led_colors[index]);
++		if (i < mcled_cdev->num_colors - 1)
++			len += sprintf(buf + len, " ");
++	}
++
++	buf[len++] = '\n';
++	return len;
++}
++static DEVICE_ATTR_RO(multi_index);
++
++static struct attribute *led_multicolor_attrs[] = {
++	&dev_attr_multi_intensity.attr,
++	&dev_attr_multi_index.attr,
++	NULL,
++};
++ATTRIBUTE_GROUPS(led_multicolor);
++
++int led_classdev_multicolor_register_ext(struct device *parent,
++				     struct led_classdev_mc *mcled_cdev,
++				     struct led_init_data *init_data)
++{
++	struct led_classdev *led_cdev;
++
++	if (!mcled_cdev)
++		return -EINVAL;
++
++	if (mcled_cdev->num_colors <= 0)
++		return -EINVAL;
++
++	if (mcled_cdev->num_colors > LED_COLOR_ID_MAX)
++		return -EINVAL;
++
++	led_cdev = &mcled_cdev->led_cdev;
++	mcled_cdev->led_cdev.groups = led_multicolor_groups;
++
++	return led_classdev_register_ext(parent, led_cdev, init_data);
++}
++EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);
++
++void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev)
++{
++	if (!mcled_cdev)
++		return;
++
++	led_classdev_unregister(&mcled_cdev->led_cdev);
++}
++EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister);
++
++static void devm_led_classdev_multicolor_release(struct device *dev, void *res)
++{
++	led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res);
++}
++
++int devm_led_classdev_multicolor_register_ext(struct device *parent,
++					     struct led_classdev_mc *mcled_cdev,
++					     struct led_init_data *init_data)
++{
++	struct led_classdev_mc **dr;
++	int ret;
++
++	dr = devres_alloc(devm_led_classdev_multicolor_release,
++			  sizeof(*dr), GFP_KERNEL);
++	if (!dr)
++		return -ENOMEM;
++
++	ret = led_classdev_multicolor_register_ext(parent, mcled_cdev,
++						   init_data);
++	if (ret) {
++		devres_free(dr);
++		return ret;
++	}
++
++	*dr = mcled_cdev;
++	devres_add(parent, dr);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext);
++
++static int devm_led_classdev_multicolor_match(struct device *dev,
++					      void *res, void *data)
++{
++	struct led_classdev_mc **p = res;
++
++	if (WARN_ON(!p || !*p))
++		return 0;
++
++	return *p == data;
++}
++
++void devm_led_classdev_multicolor_unregister(struct device *dev,
++					     struct led_classdev_mc *mcled_cdev)
++{
++	WARN_ON(devres_release(dev,
++			       devm_led_classdev_multicolor_release,
++			       devm_led_classdev_multicolor_match, mcled_cdev));
++}
++EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister);
++
++MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
++MODULE_DESCRIPTION("Multicolor LED class interface");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/leds/leds-pwm-multicolor.c b/drivers/leds/leds-pwm-multicolor.c
+new file mode 100644
+index 0000000..e1e2daa
+--- /dev/null
++++ b/drivers/leds/leds-pwm-multicolor.c
+@@ -0,0 +1,194 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * PWM-based multi-color LED control
++ *
++ * Copyright 2022 Sven Schwermer <sven.schwermer@disruptive-technologies.com>
++ */
++
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/led-class-multicolor.h>
++#include <linux/leds.h>
++#include <linux/mod_devicetable.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/platform_device.h>
++#include <linux/property.h>
++#include <linux/pwm.h>
++
++struct pwm_led {
++	struct pwm_device *pwm;
++	struct pwm_state state;
++	bool active_low;
++};
++
++struct pwm_mc_led {
++	struct led_classdev_mc mc_cdev;
++	struct mutex lock;
++	struct pwm_led leds[];
++};
++
++static int led_pwm_mc_set(struct led_classdev *cdev,
++			  enum led_brightness brightness)
++{
++	struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
++	struct pwm_mc_led *priv = container_of(mc_cdev, struct pwm_mc_led, mc_cdev);
++	unsigned long long duty;
++	int ret = 0;
++	int i;
++
++	led_mc_calc_color_components(mc_cdev, brightness);
++
++	mutex_lock(&priv->lock);
++
++	for (i = 0; i < mc_cdev->num_colors; i++) {
++		duty = priv->leds[i].state.period;
++		duty *= mc_cdev->subled_info[i].brightness;
++		do_div(duty, cdev->max_brightness);
++
++		if (priv->leds[i].active_low)
++			duty = priv->leds[i].state.period - duty;
++
++		priv->leds[i].state.duty_cycle = duty;
++		priv->leds[i].state.enabled = duty > 0;
++		ret = pwm_apply_state(priv->leds[i].pwm,
++				      &priv->leds[i].state);
++		if (ret)
++			break;
++	}
++
++	mutex_unlock(&priv->lock);
++
++	return ret;
++}
++
++static int iterate_subleds(struct device *dev, struct pwm_mc_led *priv,
++			   struct fwnode_handle *mcnode)
++{
++	struct mc_subled *subled = priv->mc_cdev.subled_info;
++	struct fwnode_handle *fwnode;
++	struct pwm_led *pwmled;
++	u32 color;
++	int ret;
++
++	/* iterate over the nodes inside the multi-led node */
++	fwnode_for_each_child_node(mcnode, fwnode) {
++		pwmled = &priv->leds[priv->mc_cdev.num_colors];
++		pwmled->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
++		if (IS_ERR(pwmled->pwm)) {
++			ret = PTR_ERR(pwmled->pwm);
++			dev_err(dev, "unable to request PWM: %d\n", ret);
++			goto release_fwnode;
++		}
++		pwm_init_state(pwmled->pwm, &pwmled->state);
++		pwmled->active_low = fwnode_property_read_bool(fwnode, "active-low");
++
++		ret = fwnode_property_read_u32(fwnode, "color", &color);
++		if (ret) {
++			dev_err(dev, "cannot read color: %d\n", ret);
++			goto release_fwnode;
++		}
++
++		subled[priv->mc_cdev.num_colors].color_index = color;
++		priv->mc_cdev.num_colors++;
++	}
++
++	return 0;
++
++release_fwnode:
++	fwnode_handle_put(fwnode);
++	return ret;
++}
++
++static int led_pwm_mc_probe(struct platform_device *pdev)
++{
++	struct fwnode_handle *mcnode, *fwnode;
++	struct led_init_data init_data = {};
++	struct led_classdev *cdev;
++	struct mc_subled *subled;
++	struct pwm_mc_led *priv;
++	int count = 0;
++	int ret = 0;
++
++	mcnode = device_get_named_child_node(&pdev->dev, "multi-led");
++	if (!mcnode) {
++		ret = -ENODEV;
++		dev_err(&pdev->dev, "expected multi-led node\n");
++		return ret;
++	}
++
++	/* count the nodes inside the multi-led node */
++	fwnode_for_each_child_node(mcnode, fwnode)
++		count++;
++
++	priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count),
++			    GFP_KERNEL);
++	if (!priv) {
++		ret = -ENOMEM;
++		goto release_mcnode;
++	}
++	mutex_init(&priv->lock);
++
++	subled = devm_kcalloc(&pdev->dev, count, sizeof(*subled), GFP_KERNEL);
++	if (!subled) {
++		ret = -ENOMEM;
++		goto release_mcnode;
++	}
++	priv->mc_cdev.subled_info = subled;
++
++	/* init the multicolor's LED class device */
++	cdev = &priv->mc_cdev.led_cdev;
++	fwnode_property_read_u32(mcnode, "max-brightness",
++				 &cdev->max_brightness);
++	cdev->flags = LED_CORE_SUSPENDRESUME;
++	cdev->brightness_set_blocking = led_pwm_mc_set;
++
++	ret = iterate_subleds(&pdev->dev, priv, mcnode);
++	if (ret)
++		goto release_mcnode;
++
++	init_data.fwnode = mcnode;
++	ret = devm_led_classdev_multicolor_register_ext(&pdev->dev,
++							&priv->mc_cdev,
++							&init_data);
++	if (ret) {
++		dev_err(&pdev->dev,
++			"failed to register multicolor PWM led for %s: %d\n",
++			cdev->name, ret);
++		goto release_mcnode;
++	}
++
++	ret = led_pwm_mc_set(cdev, cdev->brightness);
++	if (ret) {
++		dev_err(&pdev->dev,
++                             "failed to set led PWM value for %s\n", cdev->name);
++		return ret;
++	}
++
++	platform_set_drvdata(pdev, priv);
++	return 0;
++
++release_mcnode:
++	fwnode_handle_put(mcnode);
++	return ret;
++}
++
++static const struct of_device_id of_pwm_leds_mc_match[] = {
++	{ .compatible = "pwm-leds-multicolor", },
++	{}
++};
++MODULE_DEVICE_TABLE(of, of_pwm_leds_mc_match);
++
++static struct platform_driver led_pwm_mc_driver = {
++	.probe		= led_pwm_mc_probe,
++	.driver		= {
++		.name	= "leds_pwm_multicolor",
++		.of_match_table = of_pwm_leds_mc_match,
++	},
++};
++module_platform_driver(led_pwm_mc_driver);
++
++MODULE_AUTHOR("Sven Schwermer <sven.schwermer@disruptive-technologies.com>");
++MODULE_DESCRIPTION("multi-color PWM LED driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:leds-pwm-multicolor");
+diff --git a/include/linux/led-class-multicolor.h b/include/linux/led-class-multicolor.h
+new file mode 100644
+index 0000000..210d57b
+--- /dev/null
++++ b/include/linux/led-class-multicolor.h
+@@ -0,0 +1,109 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/* LED Multicolor class interface
++ * Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/
++ */
++
++#ifndef _LINUX_MULTICOLOR_LEDS_H_INCLUDED
++#define _LINUX_MULTICOLOR_LEDS_H_INCLUDED
++
++#include <linux/leds.h>
++#include <dt-bindings/leds/common.h>
++
++struct mc_subled {
++	unsigned int color_index;
++	unsigned int brightness;
++	unsigned int intensity;
++	unsigned int channel;
++};
++
++struct led_classdev_mc {
++	/* led class device */
++	struct led_classdev led_cdev;
++	unsigned int num_colors;
++
++	struct mc_subled *subled_info;
++};
++
++static inline struct led_classdev_mc *lcdev_to_mccdev(
++						struct led_classdev *led_cdev)
++{
++	return container_of(led_cdev, struct led_classdev_mc, led_cdev);
++}
++
++#if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR)
++/**
++ * led_classdev_multicolor_register_ext - register a new object of led_classdev
++ *				      class with support for multicolor LEDs
++ * @parent: the multicolor LED to register
++ * @mcled_cdev: the led_classdev_mc structure for this device
++ * @init_data: the LED class multicolor device initialization data
++ *
++ * Returns: 0 on success or negative error value on failure
++ */
++int led_classdev_multicolor_register_ext(struct device *parent,
++					    struct led_classdev_mc *mcled_cdev,
++					    struct led_init_data *init_data);
++
++/**
++ * led_classdev_multicolor_unregister - unregisters an object of led_classdev
++ *					class with support for multicolor LEDs
++ * @mcled_cdev: the multicolor LED to unregister
++ *
++ * Unregister a previously registered via led_classdev_multicolor_register
++ * object
++ */
++void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev);
++
++/* Calculate brightness for the monochrome LED cluster */
++int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
++				 enum led_brightness brightness);
++
++int devm_led_classdev_multicolor_register_ext(struct device *parent,
++					  struct led_classdev_mc *mcled_cdev,
++					  struct led_init_data *init_data);
++
++void devm_led_classdev_multicolor_unregister(struct device *parent,
++					    struct led_classdev_mc *mcled_cdev);
++#else
++
++static inline int led_classdev_multicolor_register_ext(struct device *parent,
++					    struct led_classdev_mc *mcled_cdev,
++					    struct led_init_data *init_data)
++{
++	return 0;
++}
++
++static inline void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) {};
++static inline int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
++					       enum led_brightness brightness)
++{
++	return 0;
++}
++
++static inline int devm_led_classdev_multicolor_register_ext(struct device *parent,
++					  struct led_classdev_mc *mcled_cdev,
++					  struct led_init_data *init_data)
++{
++	return 0;
++}
++
++static inline void devm_led_classdev_multicolor_unregister(struct device *parent,
++					    struct led_classdev_mc *mcled_cdev)
++{};
++
++#endif  /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */
++
++static inline int led_classdev_multicolor_register(struct device *parent,
++					    struct led_classdev_mc *mcled_cdev)
++{
++	return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL);
++}
++
++static inline int devm_led_classdev_multicolor_register(struct device *parent,
++					     struct led_classdev_mc *mcled_cdev)
++{
++	return devm_led_classdev_multicolor_register_ext(parent, mcled_cdev,
++							 NULL);
++}
++
++#endif	/* _LINUX_MULTICOLOR_LEDS_H_INCLUDED */
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-1900-lib-add-Dhrystone-benchmark-test.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1900-v6.3-lib-add-Dhrystone-benchmark-test.patch
similarity index 100%
rename from recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-1900-lib-add-Dhrystone-benchmark-test.patch
rename to recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-1900-v6.3-lib-add-Dhrystone-benchmark-test.patch
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2152-sound-add-mt7986-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2152-sound-add-mt7986-driver.patch
deleted file mode 100644
index 41eb05e..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2152-sound-add-mt7986-driver.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From 593cfdef7ef160c49db5c7ae315cb963f32a947a Mon Sep 17 00:00:00 2001
-From: Sam Shih <sam.shih@mediatek.com>
-Date: Fri, 2 Jun 2023 13:06:08 +0800
-Subject: [PATCH] [slow-speed-io][999-2152-sound-add-mt7986-driver.patch]
-
----
- sound/soc/mediatek/Kconfig  | 30 ++++++++++++++++++++++++++++++
- sound/soc/mediatek/Makefile |  1 +
- 2 files changed, 31 insertions(+)
-
-diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
-index 111e44b64..25e392428 100644
---- a/sound/soc/mediatek/Kconfig
-+++ b/sound/soc/mediatek/Kconfig
-@@ -53,6 +53,36 @@ config SND_SOC_MT6797_MT6351
- 	  Select Y if you have such device.
- 	  If unsure select "N".
- 
-+config SND_SOC_MT79XX
-+	tristate "ASoC support for Mediatek MT79XX chip"
-+	depends on ARCH_MEDIATEK
-+	select SND_SOC_MEDIATEK
-+	help
-+	  This adds ASoC platform driver support for Mediatek MT79XX chip
-+	  that can be used with other codecs.
-+	  Select Y if you have such device.
-+	  If unsure select "N".
-+
-+config SND_SOC_MT79XX_WM8960
-+	tristate "ASoc Audio driver for MT79XX with WM8960 codec"
-+	depends on SND_SOC_MT79XX && I2C
-+	select SND_SOC_WM8960
-+	help
-+	  This adds ASoC driver for Mediatek MT79XX boards
-+	  with the WM8960 codecs.
-+	  Select Y if you have such device.
-+	  If unsure select "N".
-+
-+config SND_SOC_MT79XX_SI3218X
-+	tristate "ASoc Audio driver for MT79XX with SI3218X codec"
-+	depends on SND_SOC_MT79XX && SPI
-+	select SND_SOC_SI3218X_SPI
-+	help
-+	  This adds ASoC driver for Mediatek MT79XX boards
-+	  with the SI3218X codecs.
-+	  Select Y if you have such device.
-+	  If unsure select "N".
-+
- config SND_SOC_MT8173
- 	tristate "ASoC support for Mediatek MT8173 chip"
- 	depends on ARCH_MEDIATEK
-diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
-index 76032cae6..9690326b2 100644
---- a/sound/soc/mediatek/Makefile
-+++ b/sound/soc/mediatek/Makefile
-@@ -2,5 +2,6 @@
- obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
- obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
- obj-$(CONFIG_SND_SOC_MT6797) += mt6797/
-+obj-$(CONFIG_SND_SOC_MT79XX) += mt79xx/
- obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
- obj-$(CONFIG_SND_SOC_MT8183) += mt8183/
--- 
-2.34.1
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2152-sound-add-mt7986-si3218x-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2152-sound-add-mt7986-si3218x-driver.patch
new file mode 100644
index 0000000..b05b709
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2152-sound-add-mt7986-si3218x-driver.patch
@@ -0,0 +1,43 @@
+From f0f7fed920e63ce231c4ded63098a3abdf4b5b28 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Thu, 16 Nov 2023 15:11:30 +0800
+Subject: [PATCH] sound add mt7986 si3218x driver
+
+---
+ sound/soc/mediatek/Kconfig         | 10 ++++++++++
+ sound/soc/mediatek/mt7986/Makefile |  1 +
+ 2 files changed, 11 insertions(+)
+
+diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
+index 99d36c4..e28b5a6 100644
+--- a/sound/soc/mediatek/Kconfig
++++ b/sound/soc/mediatek/Kconfig
+@@ -73,6 +73,16 @@ config SND_SOC_MT7986_WM8960
+ 	  Select Y if you have such device.
+ 	  If unsure select "N".
+ 
++config SND_SOC_MT7986_SI3218X
++	tristate "ASoc Audio driver for MT7986 with SI3218X codec"
++	depends on SND_SOC_MT7986 && SPI
++	select SND_SOC_SI3218X_SPI
++	help
++	  This adds support for ASoC machine driver for MediaTek MT7986
++	  boards with the SI3218X codecs.
++	  Select Y if you have such device.
++	  If unsure select "N".
++
+ config SND_SOC_MT8173
+ 	tristate "ASoC support for Mediatek MT8173 chip"
+ 	depends on ARCH_MEDIATEK
+diff --git a/sound/soc/mediatek/mt7986/Makefile b/sound/soc/mediatek/mt7986/Makefile
+index fc4c825..22d2571 100644
+--- a/sound/soc/mediatek/mt7986/Makefile
++++ b/sound/soc/mediatek/mt7986/Makefile
+@@ -7,3 +7,4 @@ snd-soc-mt7986-afe-objs := \
+ 
+ obj-$(CONFIG_SND_SOC_MT7986) += snd-soc-mt7986-afe.o
+ obj-$(CONFIG_SND_SOC_MT7986_WM8960) += mt7986-wm8960.o
++obj-$(CONFIG_SND_SOC_MT7986_SI3218X) += mt7986-si3218x.o
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2153-sound-add-si3218x-spi-driver.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2153-sound-add-si3218x-spi-driver.patch
new file mode 100644
index 0000000..f6d8795
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2153-sound-add-si3218x-spi-driver.patch
@@ -0,0 +1,60 @@
+From f1ebe890b6076434fbe71890ebc10a64fa2edd57 Mon Sep 17 00:00:00 2001
+From: Maso Huang <maso.huang@mediatek.com>
+Date: Wed, 15 Nov 2023 13:37:38 +0800
+Subject: [PATCH] sound add si3218x spi driver
+
+---
+ sound/soc/codecs/Kconfig  | 9 +++++++++
+ sound/soc/codecs/Makefile | 5 +++++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index dfc536c..b5a7b2a 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -127,6 +127,7 @@ config SND_SOC_ALL_CODECS
+ 	select SND_SOC_NAU8822 if I2C
+ 	select SND_SOC_NAU8824 if I2C
+ 	select SND_SOC_NAU8825 if I2C
++	select SND_SOC_SI3218X_SPI
+ 	select SND_SOC_HDMI_CODEC
+ 	select SND_SOC_PCM1681 if I2C
+ 	select SND_SOC_PCM1789_I2C if I2C
+@@ -1488,6 +1489,14 @@ config SND_SOC_NAU8824
+ config SND_SOC_NAU8825
+ 	tristate
+ 
++#config SND_SOC_SI3218X
++#	tristate
++
++config SND_SOC_SI3218X_SPI
++	tristate "Proslic SI3218X CODEC - SPI"
++	depends on SPI
++#	select SND_SOC_SI3218X
++
+ config SND_SOC_TPA6130A2
+ 	tristate "Texas Instruments TPA6130A2 headphone amplifier"
+ 	depends on I2C
+diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
+index c498373..dbd437e 100644
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -176,6 +176,7 @@ snd-soc-alc5632-objs := alc5632.o
+ snd-soc-sigmadsp-objs := sigmadsp.o
+ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o
+ snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o
++snd-soc-si3218x-spi-objs := si3218x-spi.o
+ snd-soc-si476x-objs := si476x.o
+ snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o
+ snd-soc-spdif-tx-objs := spdif_transmitter.o
+@@ -563,3 +564,7 @@ obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
+ obj-$(CONFIG_SND_SOC_MAX98504)	+= snd-soc-max98504.o
+ obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER)	+= snd-soc-simple-amplifier.o
+ obj-$(CONFIG_SND_SOC_TPA6130A2)	+= snd-soc-tpa6130a2.o
++
++# Proslic si3218x
++#obj-$(CONFIG_SND_SOC_SI3218X)	+= si3218x/
++obj-$(CONFIG_SND_SOC_SI3218X_SPI) += snd-soc-si3218x-spi.o
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2850-fips-140-3-compliance.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2850-fips-140-3-compliance.patch
new file mode 100644
index 0000000..41f2da4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2850-fips-140-3-compliance.patch
@@ -0,0 +1,69 @@
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -1823,6 +1823,19 @@ config CRYPTO_JITTERENTROPY
+ 	  random numbers. This Jitterentropy RNG registers with
+ 	  the kernel crypto API and can be used by any caller.
+ 
++config CRYPTO_CPU_JITTERENTROPY_DEBUG
++	bool "Jitterentropy DEBUG FS"
++	default n
++	select CRYPTO_USER
++	select CRYPTO_JITTERENTROPY
++	select CRYPTO_USER_API_RNG
++	help
++	  Enable the DebugFS interface of the CPU Jitter
++	  random number generator. It is solely intended
++	  to aid testing and for performing statistical
++	  and entropy analyses. You should say no
++ 	  unless you know what you are doing.
++
+ config CRYPTO_USER_API
+ 	tristate
+ 
+@@ -1853,6 +1868,17 @@ config CRYPTO_USER_API_RNG
+ 	  This option enables the user-spaces interface for random
+ 	  number generator algorithms.
+ 
++config CRYPTO_USER_API_RNG_CAVP
++	bool "Enable CAVP testing of DRBG"
++	select CRYPTO_USER_API_HASH
++	select CRYPTO_DRBG
++	default n
++	help
++	  This option enables extra API for CAVP testing via the user-space
++	  interface: resetting of DRBG entropy, and providing Additional Data.
++	  This should only be enabled for CAVP testing. You should say
++	  no unless you know what this is.
++
+ config CRYPTO_USER_API_AEAD
+ 	tristate "User-space interface for AEAD cipher algorithms"
+ 	depends on NET
+@@ -1879,6 +1904,16 @@ config CRYPTO_STATS
+ config CRYPTO_HASH_INFO
+ 	bool
+ 
++config CRYPTO_CAVP_TEST
++	bool "Enable CAVP testing of DRBG and JITTERRNG"
++	select CRYPTO_DRBG
++	select CRYPTO_DRBG_MENU
++	select CRYPTO_CPU_JITTERENTROPY_DEBUG
++	select CRYPTO_USER_API_RNG_CAVP
++	default n
++	help
++	  This option enables DRBG CAVP test and JITTERENG CMVP test
++
+ source "lib/crypto/Kconfig"
+ source "drivers/crypto/Kconfig"
+ source "crypto/asymmetric_keys/Kconfig"
+
+--- a/crypto/algif_rng.c
++++ b/crypto/algif_rng.c
+@@ -51,7 +51,7 @@ MODULE_AUTHOR("Stephan Mueller <smueller
+ MODULE_DESCRIPTION("User-space interface for random number generators");
+ 
+ struct rng_ctx {
+-#define MAXSIZE 128
++#define MAXSIZE 256
+ 	unsigned int len;
+ 	struct crypto_rng *drng;
+ 	u8 *addtl;
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 af8b569..e927bc3 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
@@ -35,10 +35,9 @@
     file://1010-pcie-mediatek-fix-clearing-interrupt-status.patch \
     file://1020-spi-nor-w25q512jv.patch \
     file://1021-ubnt-ledbar-driver.patch \
-    file://999-1000-backport-pinctrl-pinconf-setting-combo.patch \
-    file://999-1033-backport-pinctrl-spinlock.patch \
+    file://999-1050-v6.4-backport-jitterrng-2.2.0.patch \
+    file://999-1051-v5.10-backport-libkcapi.patch \
     file://999-1600-mdiobus-add-c45.patch \
-    file://999-1700-macsec-revert-async-support.patch \
     file://999-1701-add-default-setting-to-dsa-unused-port.patch \
     file://999-1702-net-dsa-add-MT7531-Gigabit-Ethernet-PHY-setting.patch \
     file://999-1703-mxl-gpy-phy-support.patch \
@@ -51,6 +50,14 @@
     file://999-1710-net-phy-add-phylink-pcs-support.patch;apply=no \
     file://999-1711-net-phy-add-phylink-pcs-decode-helper.patch \
     file://999-1712-net-phy-add-phylink-rate-matching-support.patch;apply=no \
+    file://999-1713-v5.15-net-dsa-add-dsa_port_from_netdev.patch \
+    file://999-1714-v5.15-net-dsa-add-netdev_upper_dev_link.patch \
+    file://999-1800-v6.7-MT7986-ASoC-platform-driver.patch \
+    file://999-1801-v6.1-iio-adc-add-rtq6056-support.patch \
+    file://999-1802-v6.4-backport-pinctrl-pinconf-setting-combo.patch \
+    file://999-1803-v6.6-pinctrl-spinlock.patch \
+    file://999-1804-v6.4-leds-pwm-multicolor.patch \
+    file://999-1900-v6.3-lib-add-Dhrystone-benchmark-test.patch \
     file://999-2000-show_model_name_in_cpuinfo_on_arm64.patch \
     file://999-2001-kgdb-add-interrupt-control.patch \
     file://999-2010-clk-mtk-add-mt7986-support.patch \
@@ -77,7 +84,8 @@
     file://999-2140-mtk-thermal-add-lvts-support.patch \
     file://999-2150-sound-add-some-helpers-to-control-mtk_memif.patch \
     file://999-2151-sound-refine-hw-params-and-hw-prepare.patch \
-    file://999-2152-sound-add-mt7986-driver.patch \
+    file://999-2152-sound-add-mt7986-si3218x-driver.patch \
+    file://999-2153-sound-add-si3218x-spi-driver.patch \
     file://999-2300-mtk-sd-add-mt7986-support.patch \
     file://999-2301-mtk-sd-Add-subsys-clock-control.patch \
     file://999-2330-mtd-spinand-winbond-Support-for-W25MxxGV-W25NxxKV-series.patch \
@@ -152,6 +160,7 @@
     file://999-2729-net-phy-remove-reporting-line-rate-to-mac.patch;apply=no \
     file://999-2730-net-phy-sfp-change-shared-mod-def0.patch \
     file://999-2800-misc-add-mtk-platform.patch \
+    file://999-2850-fips-140-3-compliance.patch \
     file://999-2900-dts-mt7622-enable-new-mtk-snand-for-ubi.patch \
     file://999-2901-dts-mt7622-remove-cooling-device.patch \
     "
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-2952-net-ethernet-mtk_eth_soc-modify-fq-size-4K.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-2952-net-ethernet-mtk_eth_soc-modify-fq-size-4K.patch
new file mode 100644
index 0000000..2d4bfaa
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-2952-net-ethernet-mtk_eth_soc-modify-fq-size-4K.patch
@@ -0,0 +1,222 @@
+From 4136e3567f6904259babbe5ae5c0d0bf06413f57 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Wed, 25 Oct 2023 09:21:06 +0800
+Subject: [PATCH] 999-2952-net-ethernet-mtk_eth_soc-modify-fq-size-4K
+
+---
+ drivers/net/ethernet/mediatek/mtk_eth_dbg.c   |  2 +-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 74 ++++++++++---------
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h   |  5 +-
+ .../ethernet/mediatek/mtk_hnat/hnat_debugfs.c |  2 +-
+ .../ethernet/mediatek/mtk_hnat/hnat_nf_hook.c | 23 ++++++
+ 5 files changed, 69 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_dbg.c b/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
+index e50e1ac..7c137e5 100755
+--- a/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_dbg.c
+@@ -882,7 +882,7 @@ int hwtx_ring_read(struct seq_file *seq, void *v)
+ 	struct mtk_tx_dma_v2 *hwtx_ring;
+ 	int i = 0;
+ 
+-	for (i = 0; i < MTK_DMA_SIZE; i++) {
++	for (i = 0; i < MTK_DMA_FQ_SIZE; i++) {
+ 		dma_addr_t addr = eth->phy_scratch_ring +
+ 				  i * (dma_addr_t)eth->soc->txrx.txd_size;
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+index 1226dd6..fe9c1de 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -1557,10 +1557,10 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
+ {
+ 	const struct mtk_soc_data *soc = eth->soc;
+ 	dma_addr_t phy_ring_tail;
+-	int cnt = MTK_DMA_SIZE;
++	int cnt = MTK_DMA_FQ_SIZE;
+ 	dma_addr_t dma_addr;
+ 	u64 addr64 = 0;
+-	int i;
++	int i, j, len;
+ 
+ 	if (!eth->soc->has_sram) {
+ 		eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
+@@ -1577,40 +1577,44 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
+ 	if (unlikely(!eth->scratch_ring))
+                         return -ENOMEM;
+ 
+-	eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE, GFP_KERNEL);
+-	if (unlikely(!eth->scratch_head))
+-		return -ENOMEM;
+-
+-	dma_addr = dma_map_single(eth->dma_dev,
+-				  eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
+-				  DMA_FROM_DEVICE);
+-	if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
+-		return -ENOMEM;
+-
+ 	phy_ring_tail = eth->phy_scratch_ring +
+ 			(dma_addr_t)soc->txrx.txd_size * (cnt - 1);
+ 
+-	for (i = 0; i < cnt; i++) {
+-		struct mtk_tx_dma_v2 *txd;
++	for (j = 0; j < DIV_ROUND_UP(MTK_DMA_FQ_SIZE, MTK_DMA_FQ_LENGTH); j++) {
++		len = min_t(int, cnt - j * MTK_DMA_FQ_LENGTH, MTK_DMA_FQ_LENGTH);
+ 
+-		txd = eth->scratch_ring + i * soc->txrx.txd_size;
+-		txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE;
+-		if (i < cnt - 1)
+-			txd->txd2 = eth->phy_scratch_ring +
+-				(i + 1) * soc->txrx.txd_size;
++		eth->scratch_head[j] = kcalloc(len, MTK_QDMA_PAGE_SIZE, GFP_KERNEL);
++		if (unlikely(!eth->scratch_head[j]))
++			return -ENOMEM;
+ 
+-		addr64 = (MTK_HAS_CAPS(eth->soc->caps, MTK_8GB_ADDRESSING)) ?
+-			  TX_DMA_SDP1(dma_addr + i * MTK_QDMA_PAGE_SIZE) : 0;
++		dma_addr = dma_map_single(eth->dma_dev,
++					  eth->scratch_head[j], len * MTK_QDMA_PAGE_SIZE,
++					  DMA_FROM_DEVICE);
++		if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
++			return -ENOMEM;
+ 
+-		txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE) | addr64;
+-		txd->txd4 = 0;
++		for (i = 0; i < len; i++) {
++			struct mtk_tx_dma_v2 *txd;
+ 
+-		if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
+-		    MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+-			txd->txd5 = 0;
+-			txd->txd6 = 0;
+-			txd->txd7 = 0;
+-			txd->txd8 = 0;
++			txd = eth->scratch_ring + (j * MTK_DMA_FQ_LENGTH + i) * soc->txrx.txd_size;
++			txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE;
++			if (j * MTK_DMA_FQ_LENGTH + i < cnt)
++				txd->txd2 = eth->phy_scratch_ring +
++					(j * MTK_DMA_FQ_LENGTH + i + 1) * soc->txrx.txd_size;
++
++			addr64 = (MTK_HAS_CAPS(eth->soc->caps, MTK_8GB_ADDRESSING)) ?
++				  TX_DMA_SDP1(dma_addr + i * MTK_QDMA_PAGE_SIZE) : 0;
++
++			txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE) | addr64;
++			txd->txd4 = 0;
++
++			if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ||
++			    MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
++				txd->txd5 = 0;
++				txd->txd6 = 0;
++				txd->txd7 = 0;
++				txd->txd8 = 0;
++			}
+ 		}
+ 	}
+ 
+@@ -2541,9 +2545,9 @@ static int mtk_tx_alloc(struct mtk_eth *eth)
+ 		ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
+ 					       &ring->phys, GFP_KERNEL);
+ 	else {
+-		ring->dma =  eth->scratch_ring + MTK_DMA_SIZE * sz;
++		ring->dma =  eth->scratch_ring + MTK_DMA_FQ_SIZE * sz;
+ 		ring->phys = eth->phy_scratch_ring +
+-			     MTK_DMA_SIZE * (dma_addr_t)sz;
++			     MTK_DMA_FQ_SIZE * (dma_addr_t)sz;
+ 	}
+ 
+ 	if (!ring->dma)
+@@ -3349,9 +3353,11 @@ static void mtk_dma_free(struct mtk_eth *eth)
+ 			mtk_rx_clean(eth, &eth->rx_ring[MTK_RSS_RING(i)], 1);
+ 	}
+ 
+-	if (eth->scratch_head) {
+-		kfree(eth->scratch_head);
+-		eth->scratch_head = NULL;
++	for (i = 0; i < DIV_ROUND_UP(MTK_DMA_FQ_SIZE, MTK_DMA_FQ_LENGTH); i++) {
++		if (eth->scratch_head[i]) {
++			kfree(eth->scratch_head[i]);
++			eth->scratch_head[i] = NULL;
++		}
+ 	}
+ }
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+index fe8bdee..cd2de23 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -20,6 +20,9 @@
+ #define	MTK_MAX_RX_LENGTH	1536
+ #define MTK_MIN_TX_LENGTH	60
+ #define MTK_DMA_SIZE		2048
++#define MTK_DMA_FQ_SIZE		4096
++#define MTK_DMA_FQ_HEAD		32
++#define MTK_DMA_FQ_LENGTH	2048
+ #define MTK_NAPI_WEIGHT		256
+ 
+ #if defined(CONFIG_MEDIATEK_NETSYS_V3)
+@@ -1837,7 +1840,7 @@ struct mtk_eth {
+ 	void				*scratch_ring;
+ 	struct mtk_reset_event		reset_event;
+ 	dma_addr_t			phy_scratch_ring;
+-	void				*scratch_head;
++	void				*scratch_head[MTK_DMA_FQ_HEAD];
+ 	struct clk			*clks[MTK_CLK_MAX];
+ 
+ 	struct mii_bus			*mii_bus;
+diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+index fc7d216..b97fd6a 100644
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+@@ -2784,7 +2784,7 @@ static ssize_t hnat_qos_toggle_write(struct file *file, const char __user *buffe
+ 		qos_toggle = 1;
+ 	} else if (buf[0] == '2') {
+ 		pr_info("Per-port-per-queue mode is going to be enabled!\n");
+-		pr_info("PPPQ use qid 0~5 (scheduler 0).\n");
++		pr_info("PPPQ use qid 0~11 (scheduler 0).\n");
+ 		qos_toggle = 2;
+ 		qos_dl_toggle = 1;
+ 		qos_ul_toggle = 1;
+diff --git a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+index 85c38e0..6a373f8 100644
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+@@ -1219,6 +1219,7 @@ static unsigned int skb_to_hnat_info(struct sk_buff *skb,
+ 	int udp = 0;
+ 	u32 qid = 0;
+ 	u32 port_id = 0;
++	u32 payload_len = 0;
+ 	int mape = 0;
+ 
+ 	ct = nf_ct_get(skb, &ctinfo);
+@@ -1748,6 +1749,28 @@ static unsigned int skb_to_hnat_info(struct sk_buff *skb,
+ 	else
+ 		qid = 0;
+ 
++	if (IS_PPPQ_MODE && IS_PPPQ_PATH(dev, skb)) {
++		if (ntohs(eth->h_proto) == ETH_P_IP) {
++			iph = ip_hdr(skb);
++			if (iph->protocol == IPPROTO_TCP) {
++				skb_set_transport_header(skb, sizeof(struct iphdr));
++				payload_len = be16_to_cpu(iph->tot_len) - skb_transport_offset(skb) - tcp_hdrlen(skb);
++				/* Dispatch ACK packets to high priority queue */
++				if (payload_len == 0)
++					qid += 6;
++			}
++		} else if (ntohs(eth->h_proto) == ETH_P_IPV6) {
++			ip6h = ipv6_hdr(skb);
++			if (ip6h->nexthdr == NEXTHDR_TCP) {
++				skb_set_transport_header(skb, sizeof(struct ipv6hdr));
++				payload_len = be16_to_cpu(ip6h->payload_len) - tcp_hdrlen(skb);
++				/* Dispatch ACK packets to high priority queue */
++				if (payload_len == 0)
++					qid += 6;
++			}
++		}
++	}
++
+ 	if (IS_IPV4_GRP(foe)) {
+ 		entry.ipv4_hnapt.iblk2.dp = gmac;
+ 		entry.ipv4_hnapt.iblk2.port_mg =
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch
index 1edbab9..7b27db3 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3019-mtk-wed-add-wed3-support.patch
@@ -1,4 +1,4 @@
-From b54ca484993804cec5941bd12c6cafc9ce51e4dc Mon Sep 17 00:00:00 2001
+From 7d891b389a58e3f8c99782339df7c0b023440558 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Mon, 18 Sep 2023 13:21:15 +0800
 Subject: [PATCH] mtk:wed:add wed3 support
@@ -11,20 +11,20 @@
  drivers/net/ethernet/mediatek/mtk_eth_soc.h   |    5 +-
  drivers/net/ethernet/mediatek/mtk_ppe.c       |   17 +-
  drivers/net/ethernet/mediatek/mtk_ppe.h       |    2 +-
- .../net/ethernet/mediatek/mtk_ppe_offload.c   |   13 +-
+ .../net/ethernet/mediatek/mtk_ppe_offload.c   |   16 +-
  drivers/net/ethernet/mediatek/mtk_wed.c       | 1178 +++++++++++++----
  drivers/net/ethernet/mediatek/mtk_wed.h       |   25 +-
  .../net/ethernet/mediatek/mtk_wed_debugfs.c   |  584 +++++++-
- drivers/net/ethernet/mediatek/mtk_wed_mcu.c   |   13 +-
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c   |   14 +-
  drivers/net/ethernet/mediatek/mtk_wed_mcu.h   |    5 +-
  drivers/net/ethernet/mediatek/mtk_wed_regs.h  |  338 ++++-
  include/linux/netdevice.h                     |    7 +
  include/linux/soc/mediatek/mtk_wed.h          |   83 +-
- 16 files changed, 2069 insertions(+), 388 deletions(-)
+ 16 files changed, 2070 insertions(+), 391 deletions(-)
  mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_ppe.c
 
 diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
-index 561450e..8995ea3 100644
+index bcfa581..c866d85 100644
 --- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
 +++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
 @@ -205,44 +205,49 @@
@@ -214,7 +214,7 @@
  	};
  
  	reserved-memory {
-@@ -902,6 +939,7 @@
+@@ -906,6 +943,7 @@
  					 <&topckgen CK_TOP_CB_SGM_325M>;
  		mediatek,ethsys = <&ethsys>;
  		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
@@ -283,10 +283,10 @@
 +};
 \ No newline at end of file
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-index 8bd526a..dea66d7 100644
+index 86ab1f1..ec5e5ec 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
-@@ -5095,7 +5095,8 @@ static int mtk_probe(struct platform_device *pdev)
+@@ -5218,7 +5218,8 @@ static int mtk_probe(struct platform_device *pdev)
  							  "mediatek,wed", i);
  		static const u32 wdma_regs[] = {
  			MTK_WDMA0_BASE,
@@ -297,10 +297,10 @@
  		void __iomem *wdma;
  		u32 wdma_phy;
 diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-index ee89b4c..8656b5f 100644
+index 3ab8ab5..f10fed1 100644
 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
-@@ -613,9 +613,12 @@
+@@ -623,9 +623,12 @@
  #define RX_DMA_SPORT_MASK       0x7
  #define RX_DMA_SPORT_MASK_V2    0xf
  
@@ -317,7 +317,7 @@
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
 old mode 100755
 new mode 100644
-index 384e811..eda23c2
+index 0e9c0bd..ae0acd5
 --- a/drivers/net/ethernet/mediatek/mtk_ppe.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
 @@ -9,6 +9,7 @@
@@ -328,7 +328,7 @@
  #include "mtk_eth_soc.h"
  #include "mtk_ppe.h"
  #include "mtk_ppe_regs.h"
-@@ -396,7 +397,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
+@@ -407,7 +408,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid)
  }
  
  int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
@@ -337,7 +337,7 @@
  {
  	struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
  	u32 *ib2 = mtk_foe_entry_ib2(entry);
-@@ -408,6 +409,9 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
+@@ -419,6 +420,9 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
  
  	l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) |
  		    FIELD_PREP(MTK_FOE_WINFO_BSS, bss);
@@ -347,7 +347,7 @@
  #else
  	if (wdma_idx)
  		*ib2 |= MTK_FOE_IB2_WDMA_DEVIDX;
-@@ -443,6 +447,17 @@ int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
+@@ -454,6 +458,17 @@ int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
  	*ib2 &= ~MTK_FOE_IB2_DSCP;
  	*ib2 |= FIELD_PREP(MTK_FOE_IB2_DSCP, dscp);
  
@@ -356,7 +356,7 @@
 +
 +	if (*ib2 & MTK_FOE_IB2_WDMA_WINFO &&
 +	    l2->winfo_pao & MTK_FOE_WINFO_PAO_AMSDU_EN) {
-+		u8 tid = rt_tos2priority(dscp) & 0xf;
++		u8 tid = (dscp >> 5) & 0xf;
 +
 +		l2->winfo_pao |= FIELD_PREP(MTK_FOE_WINFO_PAO_TID, tid);
 +	}
@@ -379,7 +379,7 @@
  int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
  bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data);
 diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
-index 95174b7..eab9e9d 100644
+index 95174b7..339359e 100644
 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
 @@ -112,6 +112,7 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
@@ -407,18 +407,28 @@
  		else
  			return -EOPNOTSUPP;
  #endif
-@@ -490,8 +493,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -481,8 +484,6 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+ 	if (data.pppoe.num == 1)
+ 		mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
+ 
+-	mtk_foe_entry_set_dscp(&foe, dscp);
+-
+ 	mtk_foe_entry_set_sp(eth->ppe[ppe_index], &foe);
+ 
+ 	err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
+@@ -490,8 +491,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
  	if (err)
  		return err;
  
 -	if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
 -		return err;
++	mtk_foe_entry_set_dscp(&foe, dscp);
 +	/*if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
 +		return err;*/
  
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  	if (!entry)
-@@ -516,8 +519,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
+@@ -516,8 +518,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
  	mtk_foe_entry_clear(eth->ppe[ppe_index], entry);
  free:
  	kfree(entry);
@@ -2941,7 +2951,7 @@
  	}
  }
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
-index 96e30a3..055594d 100644
+index b5a86f6..c2d060b 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
 @@ -245,8 +245,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
@@ -2954,7 +2964,7 @@
  
  	ret = request_firmware(&fw, mcu, wo->hw->dev);
  	if (ret)
-@@ -289,8 +289,12 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+@@ -293,8 +292,12 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
  	}
  
  	/* write the start address */
@@ -2969,7 +2979,7 @@
  	wo_w32(wo, boot_cr, (wo->region[WO_REGION_EMI].addr_pa >> 16));
  
  	/* wo firmware reset */
-@@ -298,8 +302,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
+@@ -302,8 +305,7 @@ mtk_wed_load_firmware(struct mtk_wed_wo *wo)
  
  	val = wo_r32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);
  
@@ -2980,7 +2990,7 @@
  	wo_w32(wo, WOX_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
  
 diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
-index 19e1199..c07bdb6 100644
+index dbb17ae..a533b6e 100644
 --- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
 +++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.h
 @@ -17,8 +17,9 @@
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch
new file mode 100644
index 0000000..9ac533a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3022-mediatek-ethernet-add-multiple-ppe-allocation.patch
@@ -0,0 +1,89 @@
+From 9c849a6e5a246489c5c91565d4c89a32958cad29 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Thu, 16 Nov 2023 11:21:53 +0800
+Subject: [PATCH] 999-3022-mediatek-ethernet-add-multiple-ppe-allocation
+
+---
+ arch/arm64/boot/dts/mediatek/mt7988.dtsi        |  1 +
+ drivers/net/ethernet/mediatek/mtk_eth_soc.c     | 10 +++++++++-
+ drivers/net/ethernet/mediatek/mtk_eth_soc.h     |  2 ++
+ drivers/net/ethernet/mediatek/mtk_ppe_offload.c | 10 ++++++++++
+ 4 files changed, 22 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+index 8d83f6b..d378a65 100644
+--- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
++++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+@@ -950,6 +950,7 @@
+ 		mediatek,infracfg = <&topmisc>;
+ 		mediatek,toprgu = <&watchdog>;
+ 		mediatek,hwver = <&hwver>;
++		mtketh-ppe-num = <3>;
+ 		#reset-cells = <1>;
+ 		#address-cells = <1>;
+ 		#size-cells = <0>;
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+index de2eac4..55d05fd 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -3669,7 +3669,14 @@ static int mtk_open(struct net_device *dev)
+ 			     SGMSYS_QPHY_PWR_STATE_CTRL, 0);
+ 
+ 	if (eth->soc->offload_version) {
+-			gdm_config = MTK_GDMA_TO_PPE0;
++#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
++			if (eth->ppe_num >= 3 && mac->id == 2)
++				gdm_config = MTK_GDMA_TO_PPE2;
++			else if (eth->ppe_num >=2 && mac->id == 1)
++				gdm_config = MTK_GDMA_TO_PPE1;
++			else
++#endif
++				gdm_config = MTK_GDMA_TO_PPE0;
+ 
+ 			for (i = 0; i < eth->ppe_num; i++)
+ 				mtk_ppe_start(eth->ppe[i]);
+@@ -4635,6 +4642,7 @@ static const struct net_device_ops mtk_netdev_ops = {
+ 	.ndo_poll_controller	= mtk_poll_controller,
+ #endif
+ 	.ndo_setup_tc		= mtk_eth_setup_tc,
++	.ndo_fill_receive_path	= mtk_eth_fill_receive_path,
+ };
+ 
+ static void mux_poll(struct work_struct *work)
+diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+index 50024a2..e0dfc9d 100644
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -2041,6 +2041,8 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ 		     void *type_data);
+ int mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f,
+ 			   struct mtk_eth *eth);
++int mtk_eth_fill_receive_path(struct net_device_path_ctx *ctx,
++			      struct net_device_path *path);
+ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
+ u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+index eab9e9d..e5ff575 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -694,6 +694,16 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ 	}
+ }
+ 
++int mtk_eth_fill_receive_path(struct net_device_path_ctx *ctx,
++			      struct net_device_path *path)
++{
++	struct mtk_mac *mac = netdev_priv(ctx->dev);
++
++	path->mtk_wdma.wdma_idx = mac->id;
++
++	return 0;
++}
++
+ int mtk_eth_offload_init(struct mtk_eth *eth, int id)
+ {
+ 	if (!eth->ppe[id] || !eth->ppe[id]->foe_table)
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3024-mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3024-mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ.patch
new file mode 100644
index 0000000..31d8b89
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3024-mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ.patch
@@ -0,0 +1,57 @@
+From 8306aa4c52abf96af2c229762207369f279c89e2 Mon Sep 17 00:00:00 2001
+From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+Date: Tue, 28 Nov 2023 13:25:03 +0800
+Subject: [PATCH] 999-3024-mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ
+
+---
+ drivers/net/ethernet/mediatek/mtk_ppe.c | 27 +++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
+index 16aec2e..1e2b96e 100644
+--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
+@@ -451,6 +451,28 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
+ 	return 0;
+ }
+ 
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++void mtk_foe_entry_adjust_qid(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
++{
++	struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(&entry->data);
++	u32 *ib2 = mtk_foe_entry_ib2(&entry->data);
++	u8 qid;
++
++	if (l2->tport_id != 1)
++		return;
++
++	qid = FIELD_GET(MTK_FOE_IB2_QID, *ib2);
++	/* To enhance performance in the unbalanced PHY rate test,
++	 * dispatching short packets to the high priority TXQ.
++	 */
++	if (ppe->eth->qos_toggle == 2 && qid < 6) {
++		qid += 6;
++		*ib2 &= ~MTK_FOE_IB2_QID;
++		*ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, qid);
++	}
++}
++#endif
++
+ int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
+ {
+ 	u32 *ib2 = mtk_foe_entry_ib2(entry);
+@@ -790,6 +812,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
+ 			continue;
+ 		}
+ 
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++		if (skb && skb->len < 100)
++			mtk_foe_entry_adjust_qid(ppe, entry);
++#endif
++
+ 		entry->hash = hash;
+ 		__mtk_foe_entry_commit(ppe, &entry->data, hash);
+ 		found = true;
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek_5.4.bb b/recipes-kernel/linux/linux-mediatek_5.4.bb
index 6e4cf79..dde2f00 100644
--- a/recipes-kernel/linux/linux-mediatek_5.4.bb
+++ b/recipes-kernel/linux/linux-mediatek_5.4.bb
@@ -9,8 +9,8 @@
 
 KBRANCH ?= "linux-5.4.y"
 
-LINUX_VERSION ?= "5.4.246"
-SRCREV_machine ?= "f568a20f058fa1e37069cff4aac4187c1650a0e9"
+LINUX_VERSION ?= "5.4.260"
+SRCREV_machine ?= "87e8e7a7aa1f96276252a90373de1d56add31918"
 KMETA = "kernel-meta"
 SRCREV_meta ?= "feeb59687bc0f054af837a5061f8d413ec7c93e9"