[rdk-b][common][bsp][Refactor and sync kernel/wifi from Openwrt]

[Description]
Refactor and sync kernel/wifi from Openwrt
1.kernel: filogic880 initial version

[Release-log]
N/A

diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch
new file mode 100644
index 0000000..3fa70b0
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch
@@ -0,0 +1,110 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 20 Sep 2021 15:40:07 +0200
+Subject: [PATCH] mac80211: mesh: clean up rx_bcn_presp API
+
+commit a5b983c6073140b624f64e79fea6d33c3e4315a0 upstream.
+
+We currently pass the entire elements to the rx_bcn_presp()
+method, but only need mesh_config. Additionally, we use the
+length of the elements to calculate back the entire frame's
+length, but that's confusing - just pass the length of the
+frame instead.
+
+Link: https://lore.kernel.org/r/20210920154009.a18ed3d2da6c.I1824b773a0fbae4453e1433c184678ca14e8df45@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -645,10 +645,9 @@ struct ieee80211_if_ocb {
+  */
+ struct ieee802_11_elems;
+ struct ieee80211_mesh_sync_ops {
+-	void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata,
+-			     u16 stype,
+-			     struct ieee80211_mgmt *mgmt,
+-			     struct ieee802_11_elems *elems,
++	void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, u16 stype,
++			     struct ieee80211_mgmt *mgmt, unsigned int len,
++			     const struct ieee80211_meshconf_ie *mesh_cfg,
+ 			     struct ieee80211_rx_status *rx_status);
+ 
+ 	/* should be called with beacon_data under RCU read lock */
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -1354,8 +1354,8 @@ static void ieee80211_mesh_rx_bcn_presp(
+ 	}
+ 
+ 	if (ifmsh->sync_ops)
+-		ifmsh->sync_ops->rx_bcn_presp(sdata,
+-			stype, mgmt, &elems, rx_status);
++		ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
++					      elems.mesh_config, rx_status);
+ }
+ 
+ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
+--- a/net/mac80211/mesh_sync.c
++++ b/net/mac80211/mesh_sync.c
+@@ -3,6 +3,7 @@
+  * Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com>
+  * Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de>
+  * Copyright 2011-2012, cozybit Inc.
++ * Copyright (C) 2021 Intel Corporation
+  */
+ 
+ #include "ieee80211_i.h"
+@@ -35,12 +36,12 @@ struct sync_method {
+ /**
+  * mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT
+  *
+- * @ie: information elements of a management frame from the mesh peer
++ * @cfg: mesh config element from the mesh peer (or %NULL)
+  */
+-static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
++static bool mesh_peer_tbtt_adjusting(const struct ieee80211_meshconf_ie *cfg)
+ {
+-	return (ie->mesh_config->meshconf_cap &
+-			IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
++	return cfg &&
++	       (cfg->meshconf_cap & IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING);
+ }
+ 
+ void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata)
+@@ -76,11 +77,11 @@ void mesh_sync_adjust_tsf(struct ieee802
+ 	}
+ }
+ 
+-static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
+-				   u16 stype,
+-				   struct ieee80211_mgmt *mgmt,
+-				   struct ieee802_11_elems *elems,
+-				   struct ieee80211_rx_status *rx_status)
++static void
++mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype,
++			      struct ieee80211_mgmt *mgmt, unsigned int len,
++			      const struct ieee80211_meshconf_ie *mesh_cfg,
++			      struct ieee80211_rx_status *rx_status)
+ {
+ 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+ 	struct ieee80211_local *local = sdata->local;
+@@ -101,10 +102,7 @@ static void mesh_sync_offset_rx_bcn_pres
+ 	 */
+ 	if (ieee80211_have_rx_timestamp(rx_status))
+ 		t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
+-						       24 + 12 +
+-						       elems->total_len +
+-						       FCS_LEN,
+-						       24);
++						       len + FCS_LEN, 24);
+ 	else
+ 		t_r = drv_get_tsf(local, sdata);
+ 
+@@ -119,7 +117,7 @@ static void mesh_sync_offset_rx_bcn_pres
+ 	 * dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors
+ 	 */
+ 
+-	if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
++	if (mesh_peer_tbtt_adjusting(mesh_cfg)) {
+ 		msync_dbg(sdata, "STA %pM : is adjusting TBTT\n",
+ 			  sta->sta.addr);
+ 		goto no_sync;
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch
new file mode 100644
index 0000000..e44aac5
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch
@@ -0,0 +1,82 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 20 Sep 2021 15:40:08 +0200
+Subject: [PATCH] mac80211: move CRC into struct ieee802_11_elems
+
+commit c6e37ed498f958254b5459253199e816b6bfc52f upstream.
+
+We're currently returning this value, but to prepare for
+returning the allocated structure, move it into there.
+
+Link: https://lore.kernel.org/r/20210920154009.479b8ebf999d.If0d4ba75ee38998dc3eeae25058aa748efcb2fc9@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1530,6 +1530,7 @@ struct ieee80211_csa_ie {
+ struct ieee802_11_elems {
+ 	const u8 *ie_start;
+ 	size_t total_len;
++	u32 crc;
+ 
+ 	/* pointers to IEs */
+ 	const struct ieee80211_tdls_lnkie *lnk_id;
+@@ -2089,10 +2090,10 @@ static inline void ieee80211_tx_skb(stru
+ 	ieee80211_tx_skb_tid(sdata, skb, 7);
+ }
+ 
+-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+-			       struct ieee802_11_elems *elems,
+-			       u64 filter, u32 crc, u8 *transmitter_bssid,
+-			       u8 *bss_bssid);
++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
++				struct ieee802_11_elems *elems,
++				u64 filter, u32 crc, u8 *transmitter_bssid,
++				u8 *bss_bssid);
+ static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
+ 					  bool action,
+ 					  struct ieee802_11_elems *elems,
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -4102,10 +4102,11 @@ static void ieee80211_rx_mgmt_beacon(str
+ 	 */
+ 	if (!ieee80211_is_s1g_beacon(hdr->frame_control))
+ 		ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
+-	ncrc = ieee802_11_parse_elems_crc(variable,
+-					  len - baselen, false, &elems,
+-					  care_about_ies, ncrc,
+-					  mgmt->bssid, bssid);
++	ieee802_11_parse_elems_crc(variable,
++				   len - baselen, false, &elems,
++				   care_about_ies, ncrc,
++				   mgmt->bssid, bssid);
++	ncrc = elems.crc;
+ 
+ 	if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
+ 	    ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -1469,10 +1469,10 @@ static size_t ieee802_11_find_bssid_prof
+ 	return found ? profile_len : 0;
+ }
+ 
+-u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+-			       struct ieee802_11_elems *elems,
+-			       u64 filter, u32 crc, u8 *transmitter_bssid,
+-			       u8 *bss_bssid)
++void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
++				struct ieee802_11_elems *elems,
++				u64 filter, u32 crc, u8 *transmitter_bssid,
++				u8 *bss_bssid)
+ {
+ 	const struct element *non_inherit = NULL;
+ 	u8 *nontransmitted_profile;
+@@ -1524,7 +1524,7 @@ u32 ieee802_11_parse_elems_crc(const u8
+ 
+ 	kfree(nontransmitted_profile);
+ 
+-	return crc;
++	elems->crc = crc;
+ }
+ 
+ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch
new file mode 100644
index 0000000..3432c25
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/348-mac80211-mlme-find-auth-challenge-directly.patch
@@ -0,0 +1,80 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 20 Sep 2021 15:40:09 +0200
+Subject: [PATCH] mac80211: mlme: find auth challenge directly
+
+commit 49a765d6785e99157ff5091cc37485732496864e upstream.
+
+There's no need to parse all elements etc. just to find the
+authentication challenge - use cfg80211_find_elem() instead.
+This also allows us to remove WLAN_EID_CHALLENGE handling
+from the element parsing entirely.
+
+Link: https://lore.kernel.org/r/20210920154009.45f9b3a15722.Ice3159ffad03a007d6154cbf1fb3a8c48489e86f@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1540,7 +1540,6 @@ struct ieee802_11_elems {
+ 	const u8 *supp_rates;
+ 	const u8 *ds_params;
+ 	const struct ieee80211_tim_ie *tim;
+-	const u8 *challenge;
+ 	const u8 *rsn;
+ 	const u8 *rsnx;
+ 	const u8 *erp_info;
+@@ -1594,7 +1593,6 @@ struct ieee802_11_elems {
+ 	u8 ssid_len;
+ 	u8 supp_rates_len;
+ 	u8 tim_len;
+-	u8 challenge_len;
+ 	u8 rsn_len;
+ 	u8 rsnx_len;
+ 	u8 ext_supp_rates_len;
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -2889,17 +2889,17 @@ static void ieee80211_auth_challenge(str
+ {
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data;
++	const struct element *challenge;
+ 	u8 *pos;
+-	struct ieee802_11_elems elems;
+ 	u32 tx_flags = 0;
+ 	struct ieee80211_prep_tx_info info = {
+ 		.subtype = IEEE80211_STYPE_AUTH,
+ 	};
+ 
+ 	pos = mgmt->u.auth.variable;
+-	ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
+-			       mgmt->bssid, auth_data->bss->bssid);
+-	if (!elems.challenge)
++	challenge = cfg80211_find_elem(WLAN_EID_CHALLENGE, pos,
++				       len - (pos - (u8 *)mgmt));
++	if (!challenge)
+ 		return;
+ 	auth_data->expected_transaction = 4;
+ 	drv_mgd_prepare_tx(sdata->local, sdata, &info);
+@@ -2907,7 +2907,8 @@ static void ieee80211_auth_challenge(str
+ 		tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
+ 			   IEEE80211_TX_INTFL_MLME_CONN_TX;
+ 	ieee80211_send_auth(sdata, 3, auth_data->algorithm, 0,
+-			    elems.challenge - 2, elems.challenge_len + 2,
++			    (void *)challenge,
++			    challenge->datalen + sizeof(*challenge),
+ 			    auth_data->bss->bssid, auth_data->bss->bssid,
+ 			    auth_data->key, auth_data->key_len,
+ 			    auth_data->key_idx, tx_flags);
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -1120,10 +1120,6 @@ _ieee802_11_parse_elems_crc(const u8 *st
+ 			} else
+ 				elem_parse_failed = true;
+ 			break;
+-		case WLAN_EID_CHALLENGE:
+-			elems->challenge = pos;
+-			elems->challenge_len = elen;
+-			break;
+ 		case WLAN_EID_VENDOR_SPECIFIC:
+ 			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
+ 			    pos[2] == 0xf2) {
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch
new file mode 100644
index 0000000..7565527
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/349-mac80211-always-allocate-struct-ieee802_11_elems.patch
@@ -0,0 +1,1143 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 20 Sep 2021 15:40:10 +0200
+Subject: [PATCH] mac80211: always allocate struct ieee802_11_elems
+
+As the 802.11 spec evolves, we need to parse more and more
+elements. This is causing the struct to grow, and we can no
+longer get away with putting it on the stack.
+
+Change the API to always dynamically allocate and return an
+allocated pointer that must be kfree()d later.
+
+As an alternative, I contemplated a scheme whereby we'd say
+in the code which elements we needed, e.g.
+
+    DECLARE_ELEMENT_PARSER(elems,
+                           SUPPORTED_CHANNELS,
+                           CHANNEL_SWITCH,
+                           EXT(KEY_DELIVERY));
+
+    ieee802_11_parse_elems(..., &elems, ...);
+
+and while I think this is possible and will save us a lot
+since most individual places only care about a small subset
+of the elements, it ended up being a bit more work since a
+lot of places do the parsing and then pass the struct to
+other functions, sometimes with multiple levels.
+
+Link: https://lore.kernel.org/r/20210920154009.26caff6b5998.I05ae58768e990e611aee8eca8abefd9d7bc15e05@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/agg-rx.c
++++ b/net/mac80211/agg-rx.c
+@@ -478,7 +478,7 @@ void ieee80211_process_addba_request(str
+ 				     size_t len)
+ {
+ 	u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
+-	struct ieee802_11_elems elems = { };
++	struct ieee802_11_elems *elems = NULL;
+ 	u8 dialog_token;
+ 	int ies_len;
+ 
+@@ -496,16 +496,17 @@ void ieee80211_process_addba_request(str
+ 	ies_len = len - offsetof(struct ieee80211_mgmt,
+ 				 u.action.u.addba_req.variable);
+ 	if (ies_len) {
+-		ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
+-                                ies_len, true, &elems, mgmt->bssid, NULL);
+-		if (elems.parse_error)
++		elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
++					       ies_len, true, mgmt->bssid, NULL);
++		if (!elems || elems->parse_error)
+ 			return;
+ 	}
+ 
+ 	__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
+ 					start_seq_num, ba_policy, tid,
+ 					buf_size, true, false,
+-					elems.addba_ext_ie);
++					elems ? elems->addba_ext_ie : NULL);
++	kfree(elems);
+ }
+ 
+ void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -9,7 +9,7 @@
+  * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
+  * Copyright 2013-2014  Intel Mobile Communications GmbH
+  * Copyright(c) 2016 Intel Deutschland GmbH
+- * Copyright(c) 2018-2020 Intel Corporation
++ * Copyright(c) 2018-2021 Intel Corporation
+  */
+ 
+ #include <linux/delay.h>
+@@ -1589,7 +1589,7 @@ void ieee80211_rx_mgmt_probe_beacon(stru
+ 				    struct ieee80211_rx_status *rx_status)
+ {
+ 	size_t baselen;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 
+ 	BUILD_BUG_ON(offsetof(typeof(mgmt->u.probe_resp), variable) !=
+ 		     offsetof(typeof(mgmt->u.beacon), variable));
+@@ -1602,10 +1602,14 @@ void ieee80211_rx_mgmt_probe_beacon(stru
+ 	if (baselen > len)
+ 		return;
+ 
+-	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
+-			       false, &elems, mgmt->bssid, NULL);
+-
+-	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
++	elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
++				       len - baselen, false,
++				       mgmt->bssid, NULL);
++
++	if (elems) {
++		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, elems);
++		kfree(elems);
++	}
+ }
+ 
+ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+@@ -1614,7 +1618,7 @@ void ieee80211_ibss_rx_queued_mgmt(struc
+ 	struct ieee80211_rx_status *rx_status;
+ 	struct ieee80211_mgmt *mgmt;
+ 	u16 fc;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	int ies_len;
+ 
+ 	rx_status = IEEE80211_SKB_RXCB(skb);
+@@ -1651,15 +1655,16 @@ void ieee80211_ibss_rx_queued_mgmt(struc
+ 			if (ies_len < 0)
+ 				break;
+ 
+-			ieee802_11_parse_elems(
++			elems = ieee802_11_parse_elems(
+ 				mgmt->u.action.u.chan_switch.variable,
+-				ies_len, true, &elems, mgmt->bssid, NULL);
++				ies_len, true, mgmt->bssid, NULL);
+ 
+-			if (elems.parse_error)
++			if (!elems || elems->parse_error)
+ 				break;
+ 
+ 			ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
+-							rx_status, &elems);
++							rx_status, elems);
++			kfree(elems);
+ 			break;
+ 		}
+ 	}
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -2088,18 +2088,18 @@ static inline void ieee80211_tx_skb(stru
+ 	ieee80211_tx_skb_tid(sdata, skb, 7);
+ }
+ 
+-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+-				struct ieee802_11_elems *elems,
+-				u64 filter, u32 crc, u8 *transmitter_bssid,
+-				u8 *bss_bssid);
+-static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
+-					  bool action,
+-					  struct ieee802_11_elems *elems,
+-					  u8 *transmitter_bssid,
+-					  u8 *bss_bssid)
++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
++						    bool action,
++						    u64 filter, u32 crc,
++						    const u8 *transmitter_bssid,
++						    const u8 *bss_bssid);
++static inline struct ieee802_11_elems *
++ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
++		       const u8 *transmitter_bssid,
++		       const u8 *bss_bssid)
+ {
+-	ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0,
+-				   transmitter_bssid, bss_bssid);
++	return ieee802_11_parse_elems_crc(start, len, action, 0, 0,
++					  transmitter_bssid, bss_bssid);
+ }
+ 
+ 
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -1247,7 +1247,7 @@ ieee80211_mesh_rx_probe_req(struct ieee8
+ 	struct sk_buff *presp;
+ 	struct beacon_data *bcn;
+ 	struct ieee80211_mgmt *hdr;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	size_t baselen;
+ 	u8 *pos;
+ 
+@@ -1256,22 +1256,24 @@ ieee80211_mesh_rx_probe_req(struct ieee8
+ 	if (baselen > len)
+ 		return;
+ 
+-	ieee802_11_parse_elems(pos, len - baselen, false, &elems, mgmt->bssid,
+-			       NULL);
+-
+-	if (!elems.mesh_id)
++	elems = ieee802_11_parse_elems(pos, len - baselen, false, mgmt->bssid,
++				       NULL);
++	if (!elems)
+ 		return;
+ 
++	if (!elems->mesh_id)
++		goto free;
++
+ 	/* 802.11-2012 10.1.4.3.2 */
+ 	if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
+ 	     !is_broadcast_ether_addr(mgmt->da)) ||
+-	    elems.ssid_len != 0)
+-		return;
++	    elems->ssid_len != 0)
++		goto free;
+ 
+-	if (elems.mesh_id_len != 0 &&
+-	    (elems.mesh_id_len != ifmsh->mesh_id_len ||
+-	     memcmp(elems.mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
+-		return;
++	if (elems->mesh_id_len != 0 &&
++	    (elems->mesh_id_len != ifmsh->mesh_id_len ||
++	     memcmp(elems->mesh_id, ifmsh->mesh_id, ifmsh->mesh_id_len)))
++		goto free;
+ 
+ 	rcu_read_lock();
+ 	bcn = rcu_dereference(ifmsh->beacon);
+@@ -1295,6 +1297,8 @@ ieee80211_mesh_rx_probe_req(struct ieee8
+ 	ieee80211_tx_skb(sdata, presp);
+ out:
+ 	rcu_read_unlock();
++free:
++	kfree(elems);
+ }
+ 
+ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
+@@ -1305,7 +1309,7 @@ static void ieee80211_mesh_rx_bcn_presp(
+ {
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	struct ieee80211_channel *channel;
+ 	size_t baselen;
+ 	int freq;
+@@ -1320,42 +1324,47 @@ static void ieee80211_mesh_rx_bcn_presp(
+ 	if (baselen > len)
+ 		return;
+ 
+-	ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
+-			       false, &elems, mgmt->bssid, NULL);
++	elems = ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
++				       len - baselen,
++				       false, mgmt->bssid, NULL);
++	if (!elems)
++		return;
+ 
+ 	/* ignore non-mesh or secure / unsecure mismatch */
+-	if ((!elems.mesh_id || !elems.mesh_config) ||
+-	    (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
+-	    (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
+-		return;
++	if ((!elems->mesh_id || !elems->mesh_config) ||
++	    (elems->rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) ||
++	    (!elems->rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
++		goto free;
+ 
+-	if (elems.ds_params)
+-		freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
++	if (elems->ds_params)
++		freq = ieee80211_channel_to_frequency(elems->ds_params[0], band);
+ 	else
+ 		freq = rx_status->freq;
+ 
+ 	channel = ieee80211_get_channel(local->hw.wiphy, freq);
+ 
+ 	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
+-		return;
++		goto free;
+ 
+-	if (mesh_matches_local(sdata, &elems)) {
++	if (mesh_matches_local(sdata, elems)) {
+ 		mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n",
+ 			sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal);
+ 		if (!sdata->u.mesh.user_mpm ||
+ 		    sdata->u.mesh.mshcfg.rssi_threshold == 0 ||
+ 		    sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal)
+-			mesh_neighbour_update(sdata, mgmt->sa, &elems,
++			mesh_neighbour_update(sdata, mgmt->sa, elems,
+ 					      rx_status);
+ 
+ 		if (ifmsh->csa_role != IEEE80211_MESH_CSA_ROLE_INIT &&
+ 		    !sdata->vif.csa_active)
+-			ieee80211_mesh_process_chnswitch(sdata, &elems, true);
++			ieee80211_mesh_process_chnswitch(sdata, elems, true);
+ 	}
+ 
+ 	if (ifmsh->sync_ops)
+ 		ifmsh->sync_ops->rx_bcn_presp(sdata, stype, mgmt, len,
+-					      elems.mesh_config, rx_status);
++					      elems->mesh_config, rx_status);
++free:
++	kfree(elems);
+ }
+ 
+ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
+@@ -1447,7 +1456,7 @@ static void mesh_rx_csa_frame(struct iee
+ 			      struct ieee80211_mgmt *mgmt, size_t len)
+ {
+ 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	u16 pre_value;
+ 	bool fwd_csa = true;
+ 	size_t baselen;
+@@ -1460,33 +1469,37 @@ static void mesh_rx_csa_frame(struct iee
+ 	pos = mgmt->u.action.u.chan_switch.variable;
+ 	baselen = offsetof(struct ieee80211_mgmt,
+ 			   u.action.u.chan_switch.variable);
+-	ieee802_11_parse_elems(pos, len - baselen, true, &elems,
+-			       mgmt->bssid, NULL);
+-
+-	if (!mesh_matches_local(sdata, &elems))
++	elems = ieee802_11_parse_elems(pos, len - baselen, true,
++				       mgmt->bssid, NULL);
++	if (!elems)
+ 		return;
+ 
+-	ifmsh->chsw_ttl = elems.mesh_chansw_params_ie->mesh_ttl;
++	if (!mesh_matches_local(sdata, elems))
++		goto free;
++
++	ifmsh->chsw_ttl = elems->mesh_chansw_params_ie->mesh_ttl;
+ 	if (!--ifmsh->chsw_ttl)
+ 		fwd_csa = false;
+ 
+-	pre_value = le16_to_cpu(elems.mesh_chansw_params_ie->mesh_pre_value);
++	pre_value = le16_to_cpu(elems->mesh_chansw_params_ie->mesh_pre_value);
+ 	if (ifmsh->pre_value >= pre_value)
+-		return;
++		goto free;
+ 
+ 	ifmsh->pre_value = pre_value;
+ 
+ 	if (!sdata->vif.csa_active &&
+-	    !ieee80211_mesh_process_chnswitch(sdata, &elems, false)) {
++	    !ieee80211_mesh_process_chnswitch(sdata, elems, false)) {
+ 		mcsa_dbg(sdata, "Failed to process CSA action frame");
+-		return;
++		goto free;
+ 	}
+ 
+ 	/* forward or re-broadcast the CSA frame */
+ 	if (fwd_csa) {
+-		if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
++		if (mesh_fwd_csa_frame(sdata, mgmt, len, elems) < 0)
+ 			mcsa_dbg(sdata, "Failed to forward the CSA frame");
+ 	}
++free:
++	kfree(elems);
+ }
+ 
+ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
+--- a/net/mac80211/mesh_hwmp.c
++++ b/net/mac80211/mesh_hwmp.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+ /*
+  * Copyright (c) 2008, 2009 open80211s Ltd.
+- * Copyright (C) 2019 Intel Corporation
++ * Copyright (C) 2019, 2021 Intel Corporation
+  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
+  */
+ 
+@@ -908,7 +908,7 @@ static void hwmp_rann_frame_process(stru
+ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
+ 			    struct ieee80211_mgmt *mgmt, size_t len)
+ {
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	size_t baselen;
+ 	u32 path_metric;
+ 	struct sta_info *sta;
+@@ -926,37 +926,41 @@ void mesh_rx_path_sel_frame(struct ieee8
+ 	rcu_read_unlock();
+ 
+ 	baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
+-	ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
+-			       len - baselen, false, &elems, mgmt->bssid, NULL);
++	elems = ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
++				       len - baselen, false, mgmt->bssid, NULL);
++	if (!elems)
++		return;
+ 
+-	if (elems.preq) {
+-		if (elems.preq_len != 37)
++	if (elems->preq) {
++		if (elems->preq_len != 37)
+ 			/* Right now we support just 1 destination and no AE */
+-			return;
+-		path_metric = hwmp_route_info_get(sdata, mgmt, elems.preq,
++			goto free;
++		path_metric = hwmp_route_info_get(sdata, mgmt, elems->preq,
+ 						  MPATH_PREQ);
+ 		if (path_metric)
+-			hwmp_preq_frame_process(sdata, mgmt, elems.preq,
++			hwmp_preq_frame_process(sdata, mgmt, elems->preq,
+ 						path_metric);
+ 	}
+-	if (elems.prep) {
+-		if (elems.prep_len != 31)
++	if (elems->prep) {
++		if (elems->prep_len != 31)
+ 			/* Right now we support no AE */
+-			return;
+-		path_metric = hwmp_route_info_get(sdata, mgmt, elems.prep,
++			goto free;
++		path_metric = hwmp_route_info_get(sdata, mgmt, elems->prep,
+ 						  MPATH_PREP);
+ 		if (path_metric)
+-			hwmp_prep_frame_process(sdata, mgmt, elems.prep,
++			hwmp_prep_frame_process(sdata, mgmt, elems->prep,
+ 						path_metric);
+ 	}
+-	if (elems.perr) {
+-		if (elems.perr_len != 15)
++	if (elems->perr) {
++		if (elems->perr_len != 15)
+ 			/* Right now we support only one destination per PERR */
+-			return;
+-		hwmp_perr_frame_process(sdata, mgmt, elems.perr);
++			goto free;
++		hwmp_perr_frame_process(sdata, mgmt, elems->perr);
+ 	}
+-	if (elems.rann)
+-		hwmp_rann_frame_process(sdata, mgmt, elems.rann);
++	if (elems->rann)
++		hwmp_rann_frame_process(sdata, mgmt, elems->rann);
++free:
++	kfree(elems);
+ }
+ 
+ /**
+--- a/net/mac80211/mesh_plink.c
++++ b/net/mac80211/mesh_plink.c
+@@ -1,7 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+ /*
+  * Copyright (c) 2008, 2009 open80211s Ltd.
+- * Copyright (C) 2019 Intel Corporation
++ * Copyright (C) 2019, 2021 Intel Corporation
+  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
+  */
+ #include <linux/gfp.h>
+@@ -1200,7 +1200,7 @@ void mesh_rx_plink_frame(struct ieee8021
+ 			 struct ieee80211_mgmt *mgmt, size_t len,
+ 			 struct ieee80211_rx_status *rx_status)
+ {
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	size_t baselen;
+ 	u8 *baseaddr;
+ 
+@@ -1228,7 +1228,8 @@ void mesh_rx_plink_frame(struct ieee8021
+ 		if (baselen > len)
+ 			return;
+ 	}
+-	ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems,
+-			       mgmt->bssid, NULL);
+-	mesh_process_plink_frame(sdata, mgmt, &elems, rx_status);
++	elems = ieee802_11_parse_elems(baseaddr, len - baselen, true,
++				       mgmt->bssid, NULL);
++	mesh_process_plink_frame(sdata, mgmt, elems, rx_status);
++	kfree(elems);
+ }
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -3317,8 +3317,11 @@ static bool ieee80211_assoc_success(stru
+ 		aid = 0; /* TODO */
+ 	}
+ 	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
+-	ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, elems,
+-			       mgmt->bssid, assoc_data->bss->bssid);
++	elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
++				       mgmt->bssid, assoc_data->bss->bssid);
++
++	if (!elems)
++		return false;
+ 
+ 	if (elems->aid_resp)
+ 		aid = le16_to_cpu(elems->aid_resp->aid);
+@@ -3340,7 +3343,8 @@ static bool ieee80211_assoc_success(stru
+ 
+ 	if (!is_s1g && !elems->supp_rates) {
+ 		sdata_info(sdata, "no SuppRates element in AssocResp\n");
+-		return false;
++		ret = false;
++		goto out;
+ 	}
+ 
+ 	sdata->vif.bss_conf.aid = aid;
+@@ -3362,7 +3366,7 @@ static bool ieee80211_assoc_success(stru
+ 	     (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) &&
+ 	      (!elems->vht_cap_elem || !elems->vht_operation)))) {
+ 		const struct cfg80211_bss_ies *ies;
+-		struct ieee802_11_elems bss_elems;
++		struct ieee802_11_elems *bss_elems;
+ 
+ 		rcu_read_lock();
+ 		ies = rcu_dereference(cbss->ies);
+@@ -3373,13 +3377,17 @@ static bool ieee80211_assoc_success(stru
+ 		if (!bss_ies)
+ 			return false;
+ 
+-		ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
+-				       false, &bss_elems,
+-				       mgmt->bssid,
+-				       assoc_data->bss->bssid);
++		bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
++						   false, mgmt->bssid,
++						   assoc_data->bss->bssid);
++		if (!bss_elems) {
++			ret = false;
++			goto out;
++		}
++
+ 		if (assoc_data->wmm &&
+-		    !elems->wmm_param && bss_elems.wmm_param) {
+-			elems->wmm_param = bss_elems.wmm_param;
++		    !elems->wmm_param && bss_elems->wmm_param) {
++			elems->wmm_param = bss_elems->wmm_param;
+ 			sdata_info(sdata,
+ 				   "AP bug: WMM param missing from AssocResp\n");
+ 		}
+@@ -3388,30 +3396,32 @@ static bool ieee80211_assoc_success(stru
+ 		 * Also check if we requested HT/VHT, otherwise the AP doesn't
+ 		 * have to include the IEs in the (re)association response.
+ 		 */
+-		if (!elems->ht_cap_elem && bss_elems.ht_cap_elem &&
++		if (!elems->ht_cap_elem && bss_elems->ht_cap_elem &&
+ 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+-			elems->ht_cap_elem = bss_elems.ht_cap_elem;
++			elems->ht_cap_elem = bss_elems->ht_cap_elem;
+ 			sdata_info(sdata,
+ 				   "AP bug: HT capability missing from AssocResp\n");
+ 		}
+-		if (!elems->ht_operation && bss_elems.ht_operation &&
++		if (!elems->ht_operation && bss_elems->ht_operation &&
+ 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+-			elems->ht_operation = bss_elems.ht_operation;
++			elems->ht_operation = bss_elems->ht_operation;
+ 			sdata_info(sdata,
+ 				   "AP bug: HT operation missing from AssocResp\n");
+ 		}
+-		if (!elems->vht_cap_elem && bss_elems.vht_cap_elem &&
++		if (!elems->vht_cap_elem && bss_elems->vht_cap_elem &&
+ 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
+-			elems->vht_cap_elem = bss_elems.vht_cap_elem;
++			elems->vht_cap_elem = bss_elems->vht_cap_elem;
+ 			sdata_info(sdata,
+ 				   "AP bug: VHT capa missing from AssocResp\n");
+ 		}
+-		if (!elems->vht_operation && bss_elems.vht_operation &&
++		if (!elems->vht_operation && bss_elems->vht_operation &&
+ 		    !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) {
+-			elems->vht_operation = bss_elems.vht_operation;
++			elems->vht_operation = bss_elems->vht_operation;
+ 			sdata_info(sdata,
+ 				   "AP bug: VHT operation missing from AssocResp\n");
+ 		}
++
++		kfree(bss_elems);
+ 	}
+ 
+ 	/*
+@@ -3662,6 +3672,7 @@ static bool ieee80211_assoc_success(stru
+ 
+ 	ret = true;
+  out:
++	kfree(elems);
+ 	kfree(bss_ies);
+ 	return ret;
+ }
+@@ -3673,7 +3684,7 @@ static void ieee80211_rx_mgmt_assoc_resp
+ 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ 	struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
+ 	u16 capab_info, status_code, aid;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	int ac, uapsd_queues = -1;
+ 	u8 *pos;
+ 	bool reassoc;
+@@ -3730,14 +3741,16 @@ static void ieee80211_rx_mgmt_assoc_resp
+ 	    fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
+ 		return;
+ 
+-	ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false, &elems,
+-			       mgmt->bssid, assoc_data->bss->bssid);
++	elems = ieee802_11_parse_elems(pos, len - (pos - (u8 *)mgmt), false,
++				       mgmt->bssid, assoc_data->bss->bssid);
++	if (!elems)
++		goto notify_driver;
+ 
+ 	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
+-	    elems.timeout_int &&
+-	    elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
++	    elems->timeout_int &&
++	    elems->timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
+ 		u32 tu, ms;
+-		tu = le32_to_cpu(elems.timeout_int->value);
++		tu = le32_to_cpu(elems->timeout_int->value);
+ 		ms = tu * 1024 / 1000;
+ 		sdata_info(sdata,
+ 			   "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
+@@ -3757,7 +3770,7 @@ static void ieee80211_rx_mgmt_assoc_resp
+ 		event.u.mlme.reason = status_code;
+ 		drv_event_callback(sdata->local, sdata, &event);
+ 	} else {
+-		if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, &elems)) {
++		if (!ieee80211_assoc_success(sdata, cbss, mgmt, len, elems)) {
+ 			/* oops -- internal error -- send timeout for now */
+ 			ieee80211_destroy_assoc_data(sdata, false, false);
+ 			cfg80211_assoc_timeout(sdata->dev, cbss);
+@@ -3787,6 +3800,7 @@ static void ieee80211_rx_mgmt_assoc_resp
+ 			       ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
+ notify_driver:
+ 	drv_mgd_complete_tx(sdata->local, sdata, &info);
++	kfree(elems);
+ }
+ 
+ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
+@@ -3991,7 +4005,7 @@ static void ieee80211_rx_mgmt_beacon(str
+ 	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+ 	struct ieee80211_mgmt *mgmt = (void *) hdr;
+ 	size_t baselen;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct ieee80211_chanctx_conf *chanctx_conf;
+ 	struct ieee80211_channel *chan;
+@@ -4037,15 +4051,16 @@ static void ieee80211_rx_mgmt_beacon(str
+ 
+ 	if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
+ 	    ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->bss)) {
+-		ieee802_11_parse_elems(variable,
+-				       len - baselen, false, &elems,
+-				       bssid,
+-				       ifmgd->assoc_data->bss->bssid);
++		elems = ieee802_11_parse_elems(variable, len - baselen, false,
++					       bssid,
++					       ifmgd->assoc_data->bss->bssid);
++		if (!elems)
++			return;
+ 
+ 		ieee80211_rx_bss_info(sdata, mgmt, len, rx_status);
+ 
+-		if (elems.dtim_period)
+-			ifmgd->dtim_period = elems.dtim_period;
++		if (elems->dtim_period)
++			ifmgd->dtim_period = elems->dtim_period;
+ 		ifmgd->have_beacon = true;
+ 		ifmgd->assoc_data->need_beacon = false;
+ 		if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) {
+@@ -4053,17 +4068,17 @@ static void ieee80211_rx_mgmt_beacon(str
+ 				le64_to_cpu(mgmt->u.beacon.timestamp);
+ 			sdata->vif.bss_conf.sync_device_ts =
+ 				rx_status->device_timestamp;
+-			sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
++			sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
+ 		}
+ 
+-		if (elems.mbssid_config_ie)
++		if (elems->mbssid_config_ie)
+ 			bss_conf->profile_periodicity =
+-				elems.mbssid_config_ie->profile_periodicity;
++				elems->mbssid_config_ie->profile_periodicity;
+ 		else
+ 			bss_conf->profile_periodicity = 0;
+ 
+-		if (elems.ext_capab_len >= 11 &&
+-		    (elems.ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
++		if (elems->ext_capab_len >= 11 &&
++		    (elems->ext_capab[10] & WLAN_EXT_CAPA11_EMA_SUPPORT))
+ 			bss_conf->ema_ap = true;
+ 		else
+ 			bss_conf->ema_ap = false;
+@@ -4072,6 +4087,7 @@ static void ieee80211_rx_mgmt_beacon(str
+ 		ifmgd->assoc_data->timeout = jiffies;
+ 		ifmgd->assoc_data->timeout_started = true;
+ 		run_again(sdata, ifmgd->assoc_data->timeout);
++		kfree(elems);
+ 		return;
+ 	}
+ 
+@@ -4103,14 +4119,15 @@ static void ieee80211_rx_mgmt_beacon(str
+ 	 */
+ 	if (!ieee80211_is_s1g_beacon(hdr->frame_control))
+ 		ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
+-	ieee802_11_parse_elems_crc(variable,
+-				   len - baselen, false, &elems,
+-				   care_about_ies, ncrc,
+-				   mgmt->bssid, bssid);
+-	ncrc = elems.crc;
++	elems = ieee802_11_parse_elems_crc(variable, len - baselen,
++					   false, care_about_ies, ncrc,
++					   mgmt->bssid, bssid);
++	if (!elems)
++		return;
++	ncrc = elems->crc;
+ 
+ 	if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
+-	    ieee80211_check_tim(elems.tim, elems.tim_len, bss_conf->aid)) {
++	    ieee80211_check_tim(elems->tim, elems->tim_len, bss_conf->aid)) {
+ 		if (local->hw.conf.dynamic_ps_timeout > 0) {
+ 			if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+ 				local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+@@ -4180,12 +4197,12 @@ static void ieee80211_rx_mgmt_beacon(str
+ 			le64_to_cpu(mgmt->u.beacon.timestamp);
+ 		sdata->vif.bss_conf.sync_device_ts =
+ 			rx_status->device_timestamp;
+-		sdata->vif.bss_conf.sync_dtim_count = elems.dtim_count;
++		sdata->vif.bss_conf.sync_dtim_count = elems->dtim_count;
+ 	}
+ 
+ 	if ((ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) ||
+ 	    ieee80211_is_s1g_short_beacon(mgmt->frame_control))
+-		return;
++		goto free;
+ 	ifmgd->beacon_crc = ncrc;
+ 	ifmgd->beacon_crc_valid = true;
+ 
+@@ -4193,12 +4210,12 @@ static void ieee80211_rx_mgmt_beacon(str
+ 
+ 	ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+ 					 rx_status->device_timestamp,
+-					 &elems, true);
++					 elems, true);
+ 
+ 	if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
+-	    ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
+-				     elems.wmm_param_len,
+-				     elems.mu_edca_param_set))
++	    ieee80211_sta_wmm_params(local, sdata, elems->wmm_param,
++				     elems->wmm_param_len,
++				     elems->mu_edca_param_set))
+ 		changed |= BSS_CHANGED_QOS;
+ 
+ 	/*
+@@ -4207,7 +4224,7 @@ static void ieee80211_rx_mgmt_beacon(str
+ 	 */
+ 	if (!ifmgd->have_beacon) {
+ 		/* a few bogus AP send dtim_period = 0 or no TIM IE */
+-		bss_conf->dtim_period = elems.dtim_period ?: 1;
++		bss_conf->dtim_period = elems->dtim_period ?: 1;
+ 
+ 		changed |= BSS_CHANGED_BEACON_INFO;
+ 		ifmgd->have_beacon = true;
+@@ -4219,9 +4236,9 @@ static void ieee80211_rx_mgmt_beacon(str
+ 		ieee80211_recalc_ps_vif(sdata);
+ 	}
+ 
+-	if (elems.erp_info) {
++	if (elems->erp_info) {
+ 		erp_valid = true;
+-		erp_value = elems.erp_info[0];
++		erp_value = elems->erp_info[0];
+ 	} else {
+ 		erp_valid = false;
+ 	}
+@@ -4234,12 +4251,12 @@ static void ieee80211_rx_mgmt_beacon(str
+ 	mutex_lock(&local->sta_mtx);
+ 	sta = sta_info_get(sdata, bssid);
+ 
+-	changed |= ieee80211_recalc_twt_req(sdata, sta, &elems);
++	changed |= ieee80211_recalc_twt_req(sdata, sta, elems);
+ 
+-	if (ieee80211_config_bw(sdata, sta, elems.ht_cap_elem,
+-				elems.vht_cap_elem, elems.ht_operation,
+-				elems.vht_operation, elems.he_operation,
+-				elems.s1g_oper, bssid, &changed)) {
++	if (ieee80211_config_bw(sdata, sta, elems->ht_cap_elem,
++				elems->vht_cap_elem, elems->ht_operation,
++				elems->vht_operation, elems->he_operation,
++				elems->s1g_oper, bssid, &changed)) {
+ 		mutex_unlock(&local->sta_mtx);
+ 		sdata_info(sdata,
+ 			   "failed to follow AP %pM bandwidth change, disconnect\n",
+@@ -4251,21 +4268,23 @@ static void ieee80211_rx_mgmt_beacon(str
+ 					    sizeof(deauth_buf), true,
+ 					    WLAN_REASON_DEAUTH_LEAVING,
+ 					    false);
+-		return;
++		goto free;
+ 	}
+ 
+-	if (sta && elems.opmode_notif)
+-		ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
++	if (sta && elems->opmode_notif)
++		ieee80211_vht_handle_opmode(sdata, sta, *elems->opmode_notif,
+ 					    rx_status->band);
+ 	mutex_unlock(&local->sta_mtx);
+ 
+ 	changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
+-					       elems.country_elem,
+-					       elems.country_elem_len,
+-					       elems.pwr_constr_elem,
+-					       elems.cisco_dtpc_elem);
++					       elems->country_elem,
++					       elems->country_elem_len,
++					       elems->pwr_constr_elem,
++					       elems->cisco_dtpc_elem);
+ 
+ 	ieee80211_bss_info_change_notify(sdata, changed);
++free:
++	kfree(elems);
+ }
+ 
+ void ieee80211_sta_rx_queued_ext(struct ieee80211_sub_if_data *sdata,
+@@ -4294,7 +4313,6 @@ void ieee80211_sta_rx_queued_mgmt(struct
+ 	struct ieee80211_rx_status *rx_status;
+ 	struct ieee80211_mgmt *mgmt;
+ 	u16 fc;
+-	struct ieee802_11_elems elems;
+ 	int ies_len;
+ 
+ 	rx_status = (struct ieee80211_rx_status *) skb->cb;
+@@ -4326,6 +4344,8 @@ void ieee80211_sta_rx_queued_mgmt(struct
+ 		break;
+ 	case IEEE80211_STYPE_ACTION:
+ 		if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
++			struct ieee802_11_elems *elems;
++
+ 			ies_len = skb->len -
+ 				  offsetof(struct ieee80211_mgmt,
+ 					   u.action.u.chan_switch.variable);
+@@ -4334,18 +4354,21 @@ void ieee80211_sta_rx_queued_mgmt(struct
+ 				break;
+ 
+ 			/* CSA IE cannot be overridden, no need for BSSID */
+-			ieee802_11_parse_elems(
+-				mgmt->u.action.u.chan_switch.variable,
+-				ies_len, true, &elems, mgmt->bssid, NULL);
++			elems = ieee802_11_parse_elems(
++					mgmt->u.action.u.chan_switch.variable,
++					ies_len, true, mgmt->bssid, NULL);
+ 
+-			if (elems.parse_error)
++			if (!elems || elems->parse_error)
+ 				break;
+ 
+ 			ieee80211_sta_process_chanswitch(sdata,
+ 						 rx_status->mactime,
+ 						 rx_status->device_timestamp,
+-						 &elems, false);
++						 elems, false);
++			kfree(elems);
+ 		} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
++			struct ieee802_11_elems *elems;
++
+ 			ies_len = skb->len -
+ 				  offsetof(struct ieee80211_mgmt,
+ 					   u.action.u.ext_chan_switch.variable);
+@@ -4357,21 +4380,22 @@ void ieee80211_sta_rx_queued_mgmt(struct
+ 			 * extended CSA IE can't be overridden, no need for
+ 			 * BSSID
+ 			 */
+-			ieee802_11_parse_elems(
+-				mgmt->u.action.u.ext_chan_switch.variable,
+-				ies_len, true, &elems, mgmt->bssid, NULL);
++			elems = ieee802_11_parse_elems(
++					mgmt->u.action.u.ext_chan_switch.variable,
++					ies_len, true, mgmt->bssid, NULL);
+ 
+-			if (elems.parse_error)
++			if (!elems || elems->parse_error)
+ 				break;
+ 
+ 			/* for the handling code pretend this was also an IE */
+-			elems.ext_chansw_ie =
++			elems->ext_chansw_ie =
+ 				&mgmt->u.action.u.ext_chan_switch.data;
+ 
+ 			ieee80211_sta_process_chanswitch(sdata,
+ 						 rx_status->mactime,
+ 						 rx_status->device_timestamp,
+-						 &elems, false);
++						 elems, false);
++			kfree(elems);
+ 		}
+ 		break;
+ 	}
+--- a/net/mac80211/scan.c
++++ b/net/mac80211/scan.c
+@@ -9,7 +9,7 @@
+  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+  * Copyright 2013-2015  Intel Mobile Communications GmbH
+  * Copyright 2016-2017  Intel Deutschland GmbH
+- * Copyright (C) 2018-2020 Intel Corporation
++ * Copyright (C) 2018-2021 Intel Corporation
+  */
+ 
+ #include <linux/if_arp.h>
+@@ -155,7 +155,7 @@ ieee80211_bss_info_update(struct ieee802
+ 	};
+ 	bool signal_valid;
+ 	struct ieee80211_sub_if_data *scan_sdata;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	size_t baselen;
+ 	u8 *elements;
+ 
+@@ -209,8 +209,10 @@ ieee80211_bss_info_update(struct ieee802
+ 	if (baselen > len)
+ 		return NULL;
+ 
+-	ieee802_11_parse_elems(elements, len - baselen, false, &elems,
+-			       mgmt->bssid, cbss->bssid);
++	elems = ieee802_11_parse_elems(elements, len - baselen, false,
++				       mgmt->bssid, cbss->bssid);
++	if (!elems)
++		return NULL;
+ 
+ 	/* In case the signal is invalid update the status */
+ 	signal_valid = channel == cbss->channel;
+@@ -218,15 +220,17 @@ ieee80211_bss_info_update(struct ieee802
+ 		rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+ 
+ 	bss = (void *)cbss->priv;
+-	ieee80211_update_bss_from_elems(local, bss, &elems, rx_status, beacon);
++	ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon);
+ 
+ 	list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) {
+ 		non_tx_bss = (void *)non_tx_cbss->priv;
+ 
+-		ieee80211_update_bss_from_elems(local, non_tx_bss, &elems,
++		ieee80211_update_bss_from_elems(local, non_tx_bss, elems,
+ 						rx_status, beacon);
+ 	}
+ 
++	kfree(elems);
++
+ 	return bss;
+ }
+ 
+--- a/net/mac80211/tdls.c
++++ b/net/mac80211/tdls.c
+@@ -6,7 +6,7 @@
+  * Copyright 2014, Intel Corporation
+  * Copyright 2014  Intel Mobile Communications GmbH
+  * Copyright 2015 - 2016 Intel Deutschland GmbH
+- * Copyright (C) 2019 Intel Corporation
++ * Copyright (C) 2019, 2021 Intel Corporation
+  */
+ 
+ #include <linux/ieee80211.h>
+@@ -1684,7 +1684,7 @@ ieee80211_process_tdls_channel_switch_re
+ 					   struct sk_buff *skb)
+ {
+ 	struct ieee80211_local *local = sdata->local;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems = NULL;
+ 	struct sta_info *sta;
+ 	struct ieee80211_tdls_data *tf = (void *)skb->data;
+ 	bool local_initiator;
+@@ -1718,16 +1718,20 @@ ieee80211_process_tdls_channel_switch_re
+ 		goto call_drv;
+ 	}
+ 
+-	ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
+-			       skb->len - baselen, false, &elems,
+-			       NULL, NULL);
+-	if (elems.parse_error) {
++	elems = ieee802_11_parse_elems(tf->u.chan_switch_resp.variable,
++				       skb->len - baselen, false, NULL, NULL);
++	if (!elems) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	if (elems->parse_error) {
+ 		tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n");
+ 		ret = -EINVAL;
+ 		goto out;
+ 	}
+ 
+-	if (!elems.ch_sw_timing || !elems.lnk_id) {
++	if (!elems->ch_sw_timing || !elems->lnk_id) {
+ 		tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n");
+ 		ret = -EINVAL;
+ 		goto out;
+@@ -1735,15 +1739,15 @@ ieee80211_process_tdls_channel_switch_re
+ 
+ 	/* validate the initiator is set correctly */
+ 	local_initiator =
+-		!memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
++		!memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
+ 	if (local_initiator == sta->sta.tdls_initiator) {
+ 		tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n");
+ 		ret = -EINVAL;
+ 		goto out;
+ 	}
+ 
+-	params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
+-	params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
++	params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time);
++	params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout);
+ 
+ 	params.tmpl_skb =
+ 		ieee80211_tdls_ch_sw_resp_tmpl_get(sta, &params.ch_sw_tm_ie);
+@@ -1763,6 +1767,7 @@ call_drv:
+ out:
+ 	mutex_unlock(&local->sta_mtx);
+ 	dev_kfree_skb_any(params.tmpl_skb);
++	kfree(elems);
+ 	return ret;
+ }
+ 
+@@ -1771,7 +1776,7 @@ ieee80211_process_tdls_channel_switch_re
+ 					  struct sk_buff *skb)
+ {
+ 	struct ieee80211_local *local = sdata->local;
+-	struct ieee802_11_elems elems;
++	struct ieee802_11_elems *elems;
+ 	struct cfg80211_chan_def chandef;
+ 	struct ieee80211_channel *chan;
+ 	enum nl80211_channel_type chan_type;
+@@ -1831,22 +1836,27 @@ ieee80211_process_tdls_channel_switch_re
+ 		return -EINVAL;
+ 	}
+ 
+-	ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
+-			       skb->len - baselen, false, &elems, NULL, NULL);
+-	if (elems.parse_error) {
++	elems = ieee802_11_parse_elems(tf->u.chan_switch_req.variable,
++				       skb->len - baselen, false, NULL, NULL);
++	if (!elems)
++		return -ENOMEM;
++
++	if (elems->parse_error) {
+ 		tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n");
+-		return -EINVAL;
++		ret = -EINVAL;
++		goto free;
+ 	}
+ 
+-	if (!elems.ch_sw_timing || !elems.lnk_id) {
++	if (!elems->ch_sw_timing || !elems->lnk_id) {
+ 		tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n");
+-		return -EINVAL;
++		ret = -EINVAL;
++		goto free;
+ 	}
+ 
+-	if (!elems.sec_chan_offs) {
++	if (!elems->sec_chan_offs) {
+ 		chan_type = NL80211_CHAN_HT20;
+ 	} else {
+-		switch (elems.sec_chan_offs->sec_chan_offs) {
++		switch (elems->sec_chan_offs->sec_chan_offs) {
+ 		case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ 			chan_type = NL80211_CHAN_HT40PLUS;
+ 			break;
+@@ -1865,7 +1875,8 @@ ieee80211_process_tdls_channel_switch_re
+ 	if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef,
+ 					   sdata->wdev.iftype)) {
+ 		tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n");
+-		return -EINVAL;
++		ret = -EINVAL;
++		goto free;
+ 	}
+ 
+ 	mutex_lock(&local->sta_mtx);
+@@ -1881,7 +1892,7 @@ ieee80211_process_tdls_channel_switch_re
+ 
+ 	/* validate the initiator is set correctly */
+ 	local_initiator =
+-		!memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
++		!memcmp(elems->lnk_id->init_sta, sdata->vif.addr, ETH_ALEN);
+ 	if (local_initiator == sta->sta.tdls_initiator) {
+ 		tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n");
+ 		ret = -EINVAL;
+@@ -1889,16 +1900,16 @@ ieee80211_process_tdls_channel_switch_re
+ 	}
+ 
+ 	/* peer should have known better */
+-	if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs &&
+-	    elems.sec_chan_offs->sec_chan_offs) {
++	if (!sta->sta.ht_cap.ht_supported && elems->sec_chan_offs &&
++	    elems->sec_chan_offs->sec_chan_offs) {
+ 		tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n");
+ 		ret = -ENOTSUPP;
+ 		goto out;
+ 	}
+ 
+ 	params.chandef = &chandef;
+-	params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time);
+-	params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout);
++	params.switch_time = le16_to_cpu(elems->ch_sw_timing->switch_time);
++	params.switch_timeout = le16_to_cpu(elems->ch_sw_timing->switch_timeout);
+ 
+ 	params.tmpl_skb =
+ 		ieee80211_tdls_ch_sw_resp_tmpl_get(sta,
+@@ -1917,6 +1928,8 @@ ieee80211_process_tdls_channel_switch_re
+ out:
+ 	mutex_unlock(&local->sta_mtx);
+ 	dev_kfree_skb_any(params.tmpl_skb);
++free:
++	kfree(elems);
+ 	return ret;
+ }
+ 
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -1399,8 +1399,8 @@ _ieee802_11_parse_elems_crc(const u8 *st
+ 
+ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
+ 					    struct ieee802_11_elems *elems,
+-					    u8 *transmitter_bssid,
+-					    u8 *bss_bssid,
++					    const u8 *transmitter_bssid,
++					    const u8 *bss_bssid,
+ 					    u8 *nontransmitted_profile)
+ {
+ 	const struct element *elem, *sub;
+@@ -1465,16 +1465,20 @@ static size_t ieee802_11_find_bssid_prof
+ 	return found ? profile_len : 0;
+ }
+ 
+-void ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+-				struct ieee802_11_elems *elems,
+-				u64 filter, u32 crc, u8 *transmitter_bssid,
+-				u8 *bss_bssid)
++struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
++						    bool action, u64 filter,
++						    u32 crc,
++						    const u8 *transmitter_bssid,
++						    const u8 *bss_bssid)
+ {
++	struct ieee802_11_elems *elems;
+ 	const struct element *non_inherit = NULL;
+ 	u8 *nontransmitted_profile;
+ 	int nontransmitted_profile_len = 0;
+ 
+-	memset(elems, 0, sizeof(*elems));
++	elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
++	if (!elems)
++		return NULL;
+ 	elems->ie_start = start;
+ 	elems->total_len = len;
+ 
+@@ -1521,6 +1525,8 @@ void ieee802_11_parse_elems_crc(const u8
+ 	kfree(nontransmitted_profile);
+ 
+ 	elems->crc = crc;
++
++	return elems;
+ }
+ 
+ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch
new file mode 100644
index 0000000..f4906e8
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/350-mac80211-fix-memory-leaks-with-element-parsing.patch
@@ -0,0 +1,115 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Fri, 1 Oct 2021 21:11:08 +0200
+Subject: [PATCH] mac80211: fix memory leaks with element parsing
+
+commit 8223ac199a3849257e86ec27865dc63f034b1cf1 upstream.
+
+My previous commit 5d24828d05f3 ("mac80211: always allocate
+struct ieee802_11_elems") had a few bugs and leaked the new
+allocated struct in a few error cases, fix that.
+
+Fixes: 5d24828d05f3 ("mac80211: always allocate struct ieee802_11_elems")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Link: https://lore.kernel.org/r/20211001211108.9839928e42e0.Ib81ca187d3d3af7ed1bfeac2e00d08a4637c8025@changeid
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/agg-rx.c
++++ b/net/mac80211/agg-rx.c
+@@ -499,13 +499,14 @@ void ieee80211_process_addba_request(str
+ 		elems = ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
+ 					       ies_len, true, mgmt->bssid, NULL);
+ 		if (!elems || elems->parse_error)
+-			return;
++			goto free;
+ 	}
+ 
+ 	__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
+ 					start_seq_num, ba_policy, tid,
+ 					buf_size, true, false,
+ 					elems ? elems->addba_ext_ie : NULL);
++free:
+ 	kfree(elems);
+ }
+ 
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -1659,11 +1659,11 @@ void ieee80211_ibss_rx_queued_mgmt(struc
+ 				mgmt->u.action.u.chan_switch.variable,
+ 				ies_len, true, mgmt->bssid, NULL);
+ 
+-			if (!elems || elems->parse_error)
+-				break;
+-
+-			ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
+-							rx_status, elems);
++			if (elems && !elems->parse_error)
++				ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt,
++								skb->len,
++								rx_status,
++								elems);
+ 			kfree(elems);
+ 			break;
+ 		}
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -3374,8 +3374,10 @@ static bool ieee80211_assoc_success(stru
+ 			bss_ies = kmemdup(ies, sizeof(*ies) + ies->len,
+ 					  GFP_ATOMIC);
+ 		rcu_read_unlock();
+-		if (!bss_ies)
+-			return false;
++		if (!bss_ies) {
++			ret = false;
++			goto out;
++		}
+ 
+ 		bss_elems = ieee802_11_parse_elems(bss_ies->data, bss_ies->len,
+ 						   false, mgmt->bssid,
+@@ -4358,13 +4360,11 @@ void ieee80211_sta_rx_queued_mgmt(struct
+ 					mgmt->u.action.u.chan_switch.variable,
+ 					ies_len, true, mgmt->bssid, NULL);
+ 
+-			if (!elems || elems->parse_error)
+-				break;
+-
+-			ieee80211_sta_process_chanswitch(sdata,
+-						 rx_status->mactime,
+-						 rx_status->device_timestamp,
+-						 elems, false);
++			if (elems && !elems->parse_error)
++				ieee80211_sta_process_chanswitch(sdata,
++								 rx_status->mactime,
++								 rx_status->device_timestamp,
++								 elems, false);
+ 			kfree(elems);
+ 		} else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
+ 			struct ieee802_11_elems *elems;
+@@ -4384,17 +4384,17 @@ void ieee80211_sta_rx_queued_mgmt(struct
+ 					mgmt->u.action.u.ext_chan_switch.variable,
+ 					ies_len, true, mgmt->bssid, NULL);
+ 
+-			if (!elems || elems->parse_error)
+-				break;
++			if (elems && !elems->parse_error) {
++				/* for the handling code pretend it was an IE */
++				elems->ext_chansw_ie =
++					&mgmt->u.action.u.ext_chan_switch.data;
++
++				ieee80211_sta_process_chanswitch(sdata,
++								 rx_status->mactime,
++								 rx_status->device_timestamp,
++								 elems, false);
++			}
+ 
+-			/* for the handling code pretend this was also an IE */
+-			elems->ext_chansw_ie =
+-				&mgmt->u.action.u.ext_chan_switch.data;
+-
+-			ieee80211_sta_process_chanswitch(sdata,
+-						 rx_status->mactime,
+-						 rx_status->device_timestamp,
+-						 elems, false);
+ 			kfree(elems);
+ 		}
+ 		break;
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch
new file mode 100644
index 0000000..9e1f781
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch
@@ -0,0 +1,41 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 28 Sep 2022 21:56:15 +0200
+Subject: [PATCH] wifi: cfg80211: fix u8 overflow in
+ cfg80211_update_notlisted_nontrans()
+
+commit aebe9f4639b13a1f4e9a6b42cdd2e38c617b442d upstream.
+
+In the copy code of the elements, we do the following calculation
+to reach the end of the MBSSID element:
+
+	/* copy the IEs after MBSSID */
+	cpy_len = mbssid[1] + 2;
+
+This looks fine, however, cpy_len is a u8, the same as mbssid[1],
+so the addition of two can overflow. In this case the subsequent
+memcpy() will overflow the allocated buffer, since it copies 256
+bytes too much due to the way the allocation and memcpy() sizes
+are calculated.
+
+Fix this by using size_t for the cpy_len variable.
+
+This fixes CVE-2022-41674.
+
+Reported-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
+Tested-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
+Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -2238,7 +2238,7 @@ cfg80211_update_notlisted_nontrans(struc
+ 	size_t new_ie_len;
+ 	struct cfg80211_bss_ies *new_ies;
+ 	const struct cfg80211_bss_ies *old;
+-	u8 cpy_len;
++	size_t cpy_len;
+ 
+ 	lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
+ 
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch
new file mode 100644
index 0000000..4c8e05e
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch
@@ -0,0 +1,47 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 28 Sep 2022 22:01:37 +0200
+Subject: [PATCH] wifi: cfg80211/mac80211: reject bad MBSSID elements
+
+commit 8f033d2becc24aa6bfd2a5c104407963560caabc upstream
+
+Per spec, the maximum value for the MaxBSSID ('n') indicator is 8,
+and the minimum is 1 since a multiple BSSID set with just one BSSID
+doesn't make sense (the # of BSSIDs is limited by 2^n).
+
+Limit this in the parsing in both cfg80211 and mac80211, rejecting
+any elements with an invalid value.
+
+This fixes potentially bad shifts in the processing of these inside
+the cfg80211_gen_new_bssid() function later.
+
+I found this during the investigation of CVE-2022-41674 fixed by the
+previous patch.
+
+Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
+Fixes: 78ac51f81532 ("mac80211: support multi-bssid")
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -1413,6 +1413,8 @@ static size_t ieee802_11_find_bssid_prof
+ 	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
+ 		if (elem->datalen < 2)
+ 			continue;
++		if (elem->data[0] < 1 || elem->data[0] > 8)
++			continue;
+ 
+ 		for_each_element(sub, elem->data + 1, elem->datalen - 1) {
+ 			u8 new_bssid[ETH_ALEN];
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -2103,6 +2103,8 @@ static void cfg80211_parse_mbssid_data(s
+ 	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
+ 		if (elem->datalen < 4)
+ 			continue;
++		if (elem->data[0] < 1 || (int)elem->data[0] > 8)
++			continue;
+ 		for_each_element(sub, elem->data + 1, elem->datalen - 1) {
+ 			u8 profile_len;
+ 
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch
new file mode 100644
index 0000000..6e97150
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch
@@ -0,0 +1,94 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 28 Sep 2022 22:07:15 +0200
+Subject: [PATCH] wifi: mac80211: fix MBSSID parsing use-after-free
+
+commit ff05d4b45dd89b922578dac497dcabf57cf771c6
+
+When we parse a multi-BSSID element, we might point some
+element pointers into the allocated nontransmitted_profile.
+However, we free this before returning, causing UAF when the
+relevant pointers in the parsed elements are accessed.
+
+Fix this by not allocating the scratch buffer separately but
+as part of the returned structure instead, that way, there
+are no lifetime issues with it.
+
+The scratch buffer introduction as part of the returned data
+here is taken from MLO feature work done by Ilan.
+
+This fixes CVE-2022-42719.
+
+Fixes: 5023b14cf4df ("mac80211: support profile split between elements")
+Co-developed-by: Ilan Peer <ilan.peer@intel.com>
+Signed-off-by: Ilan Peer <ilan.peer@intel.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1611,6 +1611,14 @@ struct ieee802_11_elems {
+ 
+ 	/* whether a parse error occurred while retrieving these elements */
+ 	bool parse_error;
++
++	/*
++	 * scratch buffer that can be used for various element parsing related
++	 * tasks, e.g., element de-fragmentation etc.
++	 */
++	size_t scratch_len;
++	u8 *scratch_pos;
++	u8 scratch[];
+ };
+ 
+ static inline struct ieee80211_local *hw_to_local(
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -1478,24 +1478,25 @@ struct ieee802_11_elems *ieee802_11_pars
+ 	u8 *nontransmitted_profile;
+ 	int nontransmitted_profile_len = 0;
+ 
+-	elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
++	elems = kzalloc(sizeof(*elems) + len, GFP_ATOMIC);
+ 	if (!elems)
+ 		return NULL;
+ 	elems->ie_start = start;
+ 	elems->total_len = len;
+ 
+-	nontransmitted_profile = kmalloc(len, GFP_ATOMIC);
+-	if (nontransmitted_profile) {
+-		nontransmitted_profile_len =
+-			ieee802_11_find_bssid_profile(start, len, elems,
+-						      transmitter_bssid,
+-						      bss_bssid,
+-						      nontransmitted_profile);
+-		non_inherit =
+-			cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
+-					       nontransmitted_profile,
+-					       nontransmitted_profile_len);
+-	}
++	elems->scratch_len = len;
++	elems->scratch_pos = elems->scratch;
++
++	nontransmitted_profile = elems->scratch_pos;
++	nontransmitted_profile_len =
++		ieee802_11_find_bssid_profile(start, len, elems,
++					      transmitter_bssid,
++					      bss_bssid,
++					      nontransmitted_profile);
++	non_inherit =
++		cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
++				       nontransmitted_profile,
++				       nontransmitted_profile_len);
+ 
+ 	crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
+ 					  crc, non_inherit);
+@@ -1524,8 +1525,6 @@ struct ieee802_11_elems *ieee802_11_pars
+ 	    offsetofend(struct ieee80211_bssid_index, dtim_count))
+ 		elems->dtim_count = elems->bssid_index->dtim_count;
+ 
+-	kfree(nontransmitted_profile);
+-
+ 	elems->crc = crc;
+ 
+ 	return elems;
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch
new file mode 100644
index 0000000..da94840
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch
@@ -0,0 +1,41 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Thu, 29 Sep 2022 21:50:44 +0200
+Subject: [PATCH] wifi: cfg80211: ensure length byte is present before
+ access
+
+commit 567e14e39e8f8c6997a1378bc3be615afca86063 upstream.
+
+When iterating the elements here, ensure the length byte is
+present before checking it to see if the entire element will
+fit into the buffer.
+
+Longer term, we should rewrite this code using the type-safe
+element iteration macros that check all of this.
+
+Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
+Reported-by: Soenke Huster <shuster@seemoo.tu-darmstadt.de>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -304,7 +304,8 @@ static size_t cfg80211_gen_new_ie(const
+ 	tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
+ 	tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
+ 
+-	while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
++	while (tmp_old + 2 - ie <= ielen &&
++	       tmp_old + tmp_old[1] + 2 - ie <= ielen) {
+ 		if (tmp_old[0] == 0) {
+ 			tmp_old++;
+ 			continue;
+@@ -364,7 +365,8 @@ static size_t cfg80211_gen_new_ie(const
+ 	 * copied to new ie, skip ssid, capability, bssid-index ie
+ 	 */
+ 	tmp_new = sub_copy;
+-	while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
++	while (tmp_new + 2 - sub_copy <= subie_len &&
++	       tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
+ 		if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
+ 		      tmp_new[0] == WLAN_EID_SSID)) {
+ 			memcpy(pos, tmp_new, tmp_new[1] + 2);
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch
new file mode 100644
index 0000000..4680e1e
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch
@@ -0,0 +1,87 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Fri, 30 Sep 2022 23:44:23 +0200
+Subject: [PATCH] wifi: cfg80211: fix BSS refcounting bugs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 0b7808818cb9df6680f98996b8e9a439fa7bcc2f upstream.
+
+There are multiple refcounting bugs related to multi-BSSID:
+ - In bss_ref_get(), if the BSS has a hidden_beacon_bss, then
+   the bss pointer is overwritten before checking for the
+   transmitted BSS, which is clearly wrong. Fix this by using
+   the bss_from_pub() macro.
+
+ - In cfg80211_bss_update() we copy the transmitted_bss pointer
+   from tmp into new, but then if we release new, we'll unref
+   it erroneously. We already set the pointer and ref it, but
+   need to NULL it since it was copied from the tmp data.
+
+ - In cfg80211_inform_single_bss_data(), if adding to the non-
+   transmitted list fails, we unlink the BSS and yet still we
+   return it, but this results in returning an entry without
+   a reference. We shouldn't return it anyway if it was broken
+   enough to not get added there.
+
+This fixes CVE-2022-42720.
+
+Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Fixes: a3584f56de1c ("cfg80211: Properly track transmitting and non-transmitting BSS")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cf
+ 	lockdep_assert_held(&rdev->bss_lock);
+ 
+ 	bss->refcount++;
+-	if (bss->pub.hidden_beacon_bss) {
+-		bss = container_of(bss->pub.hidden_beacon_bss,
+-				   struct cfg80211_internal_bss,
+-				   pub);
+-		bss->refcount++;
+-	}
+-	if (bss->pub.transmitted_bss) {
+-		bss = container_of(bss->pub.transmitted_bss,
+-				   struct cfg80211_internal_bss,
+-				   pub);
+-		bss->refcount++;
+-	}
++
++	if (bss->pub.hidden_beacon_bss)
++		bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++;
++
++	if (bss->pub.transmitted_bss)
++		bss_from_pub(bss->pub.transmitted_bss)->refcount++;
+ }
+ 
+ static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
+@@ -1743,6 +1737,8 @@ cfg80211_bss_update(struct cfg80211_regi
+ 		new->refcount = 1;
+ 		INIT_LIST_HEAD(&new->hidden_list);
+ 		INIT_LIST_HEAD(&new->pub.nontrans_list);
++		/* we'll set this later if it was non-NULL */
++		new->pub.transmitted_bss = NULL;
+ 
+ 		if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
+ 			hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
+@@ -1983,10 +1979,15 @@ cfg80211_inform_single_bss_data(struct w
+ 		spin_lock_bh(&rdev->bss_lock);
+ 		if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
+ 					       &res->pub)) {
+-			if (__cfg80211_unlink_bss(rdev, res))
++			if (__cfg80211_unlink_bss(rdev, res)) {
+ 				rdev->bss_generation++;
++				res = NULL;
++			}
+ 		}
+ 		spin_unlock_bh(&rdev->bss_lock);
++
++		if (!res)
++			return NULL;
+ 	}
+ 
+ 	trace_cfg80211_return_bss(&res->pub);
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch
new file mode 100644
index 0000000..db0e51e
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch
@@ -0,0 +1,48 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Sat, 1 Oct 2022 00:01:44 +0200
+Subject: [PATCH] wifi: cfg80211: avoid nontransmitted BSS list
+ corruption
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit bcca852027e5878aec911a347407ecc88d6fff7f upstream.
+
+If a non-transmitted BSS shares enough information (both
+SSID and BSSID!) with another non-transmitted BSS of a
+different AP, then we can find and update it, and then
+try to add it to the non-transmitted BSS list. We do a
+search for it on the transmitted BSS, but if it's not
+there (but belongs to another transmitted BSS), the list
+gets corrupted.
+
+Since this is an erroneous situation, simply fail the
+list insertion in this case and free the non-transmitted
+BSS.
+
+This fixes CVE-2022-42721.
+
+Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -425,6 +425,15 @@ cfg80211_add_nontrans_list(struct cfg802
+ 
+ 	rcu_read_unlock();
+ 
++	/*
++	 * This is a bit weird - it's not on the list, but already on another
++	 * one! The only way that could happen is if there's some BSSID/SSID
++	 * shared by multiple APs in their multi-BSSID profiles, potentially
++	 * with hidden SSID mixed in ... ignore it.
++	 */
++	if (!list_empty(&nontrans_bss->nontrans_list))
++		return -EINVAL;
++
+ 	/* add to the list */
+ 	list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
+ 	return 0;
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch
new file mode 100644
index 0000000..ed834ff
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch
@@ -0,0 +1,31 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 5 Oct 2022 15:10:09 +0200
+Subject: [PATCH] wifi: mac80211_hwsim: avoid mac80211 warning on bad
+ rate
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 1833b6f46d7e2830251a063935ab464256defe22 upstream.
+
+If the tool on the other side (e.g. wmediumd) gets confused
+about the rate, we hit a warning in mac80211. Silence that
+by effectively duplicating the check here and dropping the
+frame silently (in mac80211 it's dropped with the warning).
+
+Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/drivers/net/wireless/mac80211_hwsim.c
++++ b/drivers/net/wireless/mac80211_hwsim.c
+@@ -3760,6 +3760,8 @@ static int hwsim_cloned_frame_received_n
+ 
+ 	rx_status.band = channel->band;
+ 	rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
++	if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates)
++		goto out;
+ 	rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
+ 
+ 	hdr = (void *)skb->data;
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
new file mode 100644
index 0000000..44b8729
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
@@ -0,0 +1,52 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 5 Oct 2022 21:24:10 +0200
+Subject: [PATCH] wifi: mac80211: fix crash in beacon protection for
+ P2P-device
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit b2d03cabe2b2e150ff5a381731ea0355459be09f upstream.
+
+If beacon protection is active but the beacon cannot be
+decrypted or is otherwise malformed, we call the cfg80211
+API to report this to userspace, but that uses a netdev
+pointer, which isn't present for P2P-Device. Fix this to
+call it only conditionally to ensure cfg80211 won't crash
+in the case of P2P-Device.
+
+This fixes CVE-2022-42722.
+
+Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Fixes: 9eaf183af741 ("mac80211: Report beacon protection failures to user space")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1986,10 +1986,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_
+ 
+ 		if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
+ 		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
+-		    NUM_DEFAULT_BEACON_KEYS) {
+-			cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+-						     skb->data,
+-						     skb->len);
++				   NUM_DEFAULT_BEACON_KEYS) {
++			if (rx->sdata->dev)
++				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
++							     skb->data,
++							     skb->len);
+ 			return RX_DROP_MONITOR; /* unexpected BIP keyidx */
+ 		}
+ 
+@@ -2137,7 +2138,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_
+ 	/* either the frame has been decrypted or will be dropped */
+ 	status->flag |= RX_FLAG_DECRYPTED;
+ 
+-	if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
++	if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE &&
++		     rx->sdata->dev))
+ 		cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+ 					     skb->data, skb->len);
+ 
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch
new file mode 100644
index 0000000..c689fac
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch
@@ -0,0 +1,85 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Wed, 5 Oct 2022 23:11:43 +0200
+Subject: [PATCH] wifi: cfg80211: update hidden BSSes to avoid WARN_ON
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit c90b93b5b782891ebfda49d4e5da36632fefd5d1 upstream.
+
+When updating beacon elements in a non-transmitted BSS,
+also update the hidden sub-entries to the same beacon
+elements, so that a future update through other paths
+won't trigger a WARN_ON().
+
+The warning is triggered because the beacon elements in
+the hidden BSSes that are children of the BSS should
+always be the same as in the parent.
+
+Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Tested-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -1609,6 +1609,23 @@ struct cfg80211_non_tx_bss {
+ 	u8 bssid_index;
+ };
+ 
++static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
++					 const struct cfg80211_bss_ies *new_ies,
++					 const struct cfg80211_bss_ies *old_ies)
++{
++	struct cfg80211_internal_bss *bss;
++
++	/* Assign beacon IEs to all sub entries */
++	list_for_each_entry(bss, &known->hidden_list, hidden_list) {
++		const struct cfg80211_bss_ies *ies;
++
++		ies = rcu_access_pointer(bss->pub.beacon_ies);
++		WARN_ON(ies != old_ies);
++
++		rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
++	}
++}
++
+ static bool
+ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
+ 			  struct cfg80211_internal_bss *known,
+@@ -1632,7 +1649,6 @@ cfg80211_update_known_bss(struct cfg8021
+ 			kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
+ 	} else if (rcu_access_pointer(new->pub.beacon_ies)) {
+ 		const struct cfg80211_bss_ies *old;
+-		struct cfg80211_internal_bss *bss;
+ 
+ 		if (known->pub.hidden_beacon_bss &&
+ 		    !list_empty(&known->hidden_list)) {
+@@ -1660,16 +1676,7 @@ cfg80211_update_known_bss(struct cfg8021
+ 		if (old == rcu_access_pointer(known->pub.ies))
+ 			rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
+ 
+-		/* Assign beacon IEs to all sub entries */
+-		list_for_each_entry(bss, &known->hidden_list, hidden_list) {
+-			const struct cfg80211_bss_ies *ies;
+-
+-			ies = rcu_access_pointer(bss->pub.beacon_ies);
+-			WARN_ON(ies != old);
+-
+-			rcu_assign_pointer(bss->pub.beacon_ies,
+-					   new->pub.beacon_ies);
+-		}
++		cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old);
+ 
+ 		if (old)
+ 			kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
+@@ -2319,6 +2326,8 @@ cfg80211_update_notlisted_nontrans(struc
+ 	} else {
+ 		old = rcu_access_pointer(nontrans_bss->beacon_ies);
+ 		rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
++		cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
++					     new_ies, old);
+ 		rcu_assign_pointer(nontrans_bss->ies, new_ies);
+ 		if (old)
+ 			kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
index 0e58b61..50b6b94 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
@@ -29,7 +29,7 @@
 
 --- a/net/mac80211/scan.c
 +++ b/net/mac80211/scan.c
-@@ -461,16 +461,19 @@ static void __ieee80211_scan_completed(s
+@@ -465,16 +465,19 @@ static void __ieee80211_scan_completed(s
  	scan_req = rcu_dereference_protected(local->scan_req,
  					     lockdep_is_held(&local->mtx));
  
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/363-bss-color-collision.patch
similarity index 96%
rename from recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
rename to recipes-kernel/linux-mac80211/files/patches/subsys/363-bss-color-collision.patch
index 1e3486a..edee4b3 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/363-bss-color-collision.patch
@@ -56,7 +56,7 @@
  
 --- a/net/mac80211/rx.c
 +++ b/net/mac80211/rx.c
-@@ -3180,6 +3180,49 @@ static void ieee80211_process_sa_query_r
+@@ -3182,6 +3182,49 @@ static void ieee80211_process_sa_query_r
  	ieee80211_tx_skb(sdata, skb);
  }
  
@@ -106,7 +106,7 @@
  static ieee80211_rx_result debug_noinline
  ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
  {
-@@ -3205,6 +3248,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802
+@@ -3207,6 +3250,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802
  	    !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
  		int sig = 0;
  
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/364-mac80211-add-support-for-restricting-netdev-features.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/364-mac80211-add-support-for-restricting-netdev-features.patch
new file mode 100644
index 0000000..d133ed9
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/364-mac80211-add-support-for-restricting-netdev-features.patch
@@ -0,0 +1,513 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 9 Oct 2022 20:15:46 +0200
+Subject: [PATCH] mac80211: add support for restricting netdev features per vif
+
+This can be used to selectively disable feature flags for checksum offload,
+scatter/gather or GSO by changing vif->netdev_features.
+Removing features from vif->netdev_features does not affect the netdev
+features themselves, but instead fixes up skbs in the tx path so that the
+offloads are not needed in the driver.
+
+Aside from making it easier to deal with vif type based hardware limitations,
+this also makes it possible to optimize performance on hardware without native
+GSO support by declaring GSO support in hw->netdev_features and removing it
+from vif->netdev_features. This allows mac80211 to handle GSO segmentation
+after the sta lookup, but before itxq enqueue, thus reducing the number of
+unnecessary sta lookups, as well as some other per-packet processing.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/fq_impl.h
++++ b/include/net/fq_impl.h
+@@ -200,6 +200,7 @@ static void fq_tin_enqueue(struct fq *fq
+ 			   fq_skb_free_t free_func)
+ {
+ 	struct fq_flow *flow;
++	struct sk_buff *next;
+ 	bool oom;
+ 
+ 	lockdep_assert_held(&fq->lock);
+@@ -214,11 +215,15 @@ static void fq_tin_enqueue(struct fq *fq
+ 	}
+ 
+ 	flow->tin = tin;
+-	flow->backlog += skb->len;
+-	tin->backlog_bytes += skb->len;
+-	tin->backlog_packets++;
+-	fq->memory_usage += skb->truesize;
+-	fq->backlog++;
++	skb_list_walk_safe(skb, skb, next) {
++		skb_mark_not_on_list(skb);
++		flow->backlog += skb->len;
++		tin->backlog_bytes += skb->len;
++		tin->backlog_packets++;
++		fq->memory_usage += skb->truesize;
++		fq->backlog++;
++		__skb_queue_tail(&flow->queue, skb);
++	}
+ 
+ 	if (list_empty(&flow->flowchain)) {
+ 		flow->deficit = fq->quantum;
+@@ -226,7 +231,6 @@ static void fq_tin_enqueue(struct fq *fq
+ 			      &tin->new_flows);
+ 	}
+ 
+-	__skb_queue_tail(&flow->queue, skb);
+ 	oom = (fq->memory_usage > fq->memory_limit);
+ 	while (fq->backlog > fq->limit || oom) {
+ 		flow = fq_find_fattest_flow(fq);
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1685,6 +1685,10 @@ enum ieee80211_offload_flags {
+  *	write-protected by sdata_lock and local->mtx so holding either is fine
+  *	for read access.
+  * @mu_mimo_owner: indicates interface owns MU-MIMO capability
++ * @netdev_features: tx netdev features supported by the hardware for this
++ *	vif. mac80211 initializes this to hw->netdev_features, and the driver
++ *	can mask out specific tx features. mac80211 will handle software fixup
++ *	for masked offloads (GSO, CSUM)
+  * @driver_flags: flags/capabilities the driver has for this interface,
+  *	these need to be set (or cleared) when the interface is added
+  *	or, if supported by the driver, the interface type is changed
+@@ -1736,6 +1740,7 @@ struct ieee80211_vif {
+ 
+ 	struct ieee80211_chanctx_conf __rcu *chanctx_conf;
+ 
++	netdev_features_t netdev_features;
+ 	u32 driver_flags;
+ 	u32 offload_flags;
+ 
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -2209,6 +2209,7 @@ int ieee80211_if_add(struct ieee80211_lo
+ 		ndev->features |= local->hw.netdev_features;
+ 		ndev->hw_features |= ndev->features &
+ 					MAC80211_SUPPORTED_FEATURES_TX;
++		sdata->vif.netdev_features = local->hw.netdev_features;
+ 
+ 		netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
+ 
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1310,7 +1310,11 @@ static struct txq_info *ieee80211_get_tx
+ 
+ static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
+ {
+-	IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
++	struct sk_buff *next;
++	codel_time_t now = codel_get_time();
++
++	skb_list_walk_safe(skb, skb, next)
++		IEEE80211_SKB_CB(skb)->control.enqueue_time = now;
+ }
+ 
+ static u32 codel_skb_len_func(const struct sk_buff *skb)
+@@ -3499,47 +3503,71 @@ ieee80211_xmit_fast_finish(struct ieee80
+ 	return TX_CONTINUE;
+ }
+ 
+-static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
+-				struct sta_info *sta,
+-				struct ieee80211_fast_tx *fast_tx,
+-				struct sk_buff *skb)
++static netdev_features_t
++ieee80211_sdata_netdev_features(struct ieee80211_sub_if_data *sdata)
+ {
+-	struct ieee80211_local *local = sdata->local;
+-	u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+-	int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
+-	int hw_headroom = sdata->local->hw.extra_tx_headroom;
+-	struct ethhdr eth;
+-	struct ieee80211_tx_info *info;
+-	struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
+-	struct ieee80211_tx_data tx;
+-	ieee80211_tx_result r;
+-	struct tid_ampdu_tx *tid_tx = NULL;
+-	u8 tid = IEEE80211_NUM_TIDS;
++	if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
++		return sdata->vif.netdev_features;
+ 
+-	/* control port protocol needs a lot of special handling */
+-	if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
+-		return false;
++	if (!sdata->bss)
++		return 0;
+ 
+-	/* only RFC 1042 SNAP */
+-	if (ethertype < ETH_P_802_3_MIN)
+-		return false;
++	sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
++	return sdata->vif.netdev_features;
++}
+ 
+-	/* don't handle TX status request here either */
+-	if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
+-		return false;
++static struct sk_buff *
++ieee80211_tx_skb_fixup(struct sk_buff *skb, netdev_features_t features)
++{
++	if (skb_is_gso(skb)) {
++		struct sk_buff *segs;
+ 
+-	if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+-		tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+-		tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+-		if (tid_tx) {
+-			if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
+-				return false;
+-			if (tid_tx->timeout)
+-				tid_tx->last_tx = jiffies;
+-		}
++		segs = skb_gso_segment(skb, features);
++		if (!segs)
++			return skb;
++		if (IS_ERR(segs))
++			goto free;
++
++		consume_skb(skb);
++		return segs;
++	}
++
++	if (skb_needs_linearize(skb, features) && __skb_linearize(skb))
++		goto free;
++
++	if (skb->ip_summed == CHECKSUM_PARTIAL) {
++		int ofs = skb_checksum_start_offset(skb);
++
++		if (skb->encapsulation)
++			skb_set_inner_transport_header(skb, ofs);
++		else
++			skb_set_transport_header(skb, ofs);
++
++		if (skb_csum_hwoffload_help(skb, features))
++			goto free;
+ 	}
+ 
+-	/* after this point (skb is modified) we cannot return false */
++	skb_mark_not_on_list(skb);
++	return skb;
++
++free:
++	kfree_skb(skb);
++	return NULL;
++}
++
++static void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
++				  struct sta_info *sta,
++				  struct ieee80211_fast_tx *fast_tx,
++				  struct sk_buff *skb, u8 tid, bool ampdu)
++{
++	struct ieee80211_local *local = sdata->local;
++	struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
++	struct ieee80211_tx_info *info;
++	struct ieee80211_tx_data tx;
++	ieee80211_tx_result r;
++	int hw_headroom = sdata->local->hw.extra_tx_headroom;
++	int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
++	struct ethhdr eth;
+ 
+ 	if (skb_shared(skb)) {
+ 		struct sk_buff *tmp_skb = skb;
+@@ -3548,12 +3576,12 @@ static bool ieee80211_xmit_fast(struct i
+ 		kfree_skb(tmp_skb);
+ 
+ 		if (!skb)
+-			return true;
++			return;
+ 	}
+ 
+ 	if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
+ 	    ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
+-		return true;
++		return;
+ 
+ 	/* will not be crypto-handled beyond what we do here, so use false
+ 	 * as the may-encrypt argument for the resize to not account for
+@@ -3562,10 +3590,8 @@ static bool ieee80211_xmit_fast(struct i
+ 	if (unlikely(ieee80211_skb_resize(sdata, skb,
+ 					  max_t(int, extra_head + hw_headroom -
+ 						     skb_headroom(skb), 0),
+-					  ENCRYPT_NO))) {
+-		kfree_skb(skb);
+-		return true;
+-	}
++					  ENCRYPT_NO)))
++		goto free;
+ 
+ 	memcpy(&eth, skb->data, ETH_HLEN - 2);
+ 	hdr = skb_push(skb, extra_head);
+@@ -3579,7 +3605,7 @@ static bool ieee80211_xmit_fast(struct i
+ 	info->control.vif = &sdata->vif;
+ 	info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
+ 		      IEEE80211_TX_CTL_DONTFRAG |
+-		      (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
++		      (ampdu ? IEEE80211_TX_CTL_AMPDU : 0);
+ 	info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
+ 
+ #ifdef CPTCFG_MAC80211_DEBUGFS
+@@ -3601,16 +3627,14 @@ static bool ieee80211_xmit_fast(struct i
+ 	tx.key = fast_tx->key;
+ 
+ 	if (ieee80211_queue_skb(local, sdata, sta, skb))
+-		return true;
++		return;
+ 
+ 	tx.skb = skb;
+ 	r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
+ 				       fast_tx->key, &tx);
+ 	tx.skb = NULL;
+-	if (r == TX_DROP) {
+-		kfree_skb(skb);
+-		return true;
+-	}
++	if (r == TX_DROP)
++		goto free;
+ 
+ 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ 		sdata = container_of(sdata->bss,
+@@ -3618,6 +3642,55 @@ static bool ieee80211_xmit_fast(struct i
+ 
+ 	__skb_queue_tail(&tx.skbs, skb);
+ 	ieee80211_tx_frags(local, &sdata->vif, sta, &tx.skbs, false);
++	return;
++
++free:
++	kfree_skb(skb);
++}
++
++static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
++				struct sta_info *sta,
++				struct ieee80211_fast_tx *fast_tx,
++				struct sk_buff *skb)
++{
++	u16 ethertype = (skb->data[12] << 8) | skb->data[13];
++	struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
++	struct tid_ampdu_tx *tid_tx = NULL;
++	struct sk_buff *next;
++	u8 tid = IEEE80211_NUM_TIDS;
++
++	/* control port protocol needs a lot of special handling */
++	if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
++		return false;
++
++	/* only RFC 1042 SNAP */
++	if (ethertype < ETH_P_802_3_MIN)
++		return false;
++
++	/* don't handle TX status request here either */
++	if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
++		return false;
++
++	if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
++		tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
++		tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
++		if (tid_tx) {
++			if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
++				return false;
++			if (tid_tx->timeout)
++				tid_tx->last_tx = jiffies;
++		}
++	}
++
++	skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
++	if (!skb)
++		return true;
++
++	skb_list_walk_safe(skb, skb, next) {
++		skb_mark_not_on_list(skb);
++		__ieee80211_xmit_fast(sdata, sta, fast_tx, skb, tid, tid_tx);
++	}
++
+ 	return true;
+ }
+ 
+@@ -4123,31 +4196,14 @@ void __ieee80211_subif_start_xmit(struct
+ 			goto out;
+ 	}
+ 
+-	if (skb_is_gso(skb)) {
+-		struct sk_buff *segs;
+-
+-		segs = skb_gso_segment(skb, 0);
+-		if (IS_ERR(segs)) {
+-			goto out_free;
+-		} else if (segs) {
+-			consume_skb(skb);
+-			skb = segs;
+-		}
+-	} else {
+-		/* we cannot process non-linear frames on this path */
+-		if (skb_linearize(skb))
+-			goto out_free;
+-
+-		/* the frame could be fragmented, software-encrypted, and other
+-		 * things so we cannot really handle checksum offload with it -
+-		 * fix it up in software before we handle anything else.
+-		 */
+-		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-			skb_set_transport_header(skb,
+-						 skb_checksum_start_offset(skb));
+-			if (skb_checksum_help(skb))
+-				goto out_free;
+-		}
++	/* the frame could be fragmented, software-encrypted, and other
++	 * things so we cannot really handle checksum or GSO offload.
++	 * fix it up in software before we handle anything else.
++	 */
++	skb = ieee80211_tx_skb_fixup(skb, 0);
++	if (!skb) {
++		len = 0;
++		goto out;
+ 	}
+ 
+ 	skb_list_walk_safe(skb, skb, next) {
+@@ -4310,9 +4366,11 @@ netdev_tx_t ieee80211_subif_start_xmit(s
+ 	return NETDEV_TX_OK;
+ }
+ 
+-static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
+-			      struct sk_buff *skb, struct sta_info *sta,
+-			      bool txpending)
++
++
++static bool __ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
++				struct sk_buff *skb, struct sta_info *sta,
++				bool txpending)
+ {
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct ieee80211_tx_control control = {};
+@@ -4321,14 +4379,6 @@ static bool ieee80211_tx_8023(struct iee
+ 	unsigned long flags;
+ 	int q = info->hw_queue;
+ 
+-	if (sta)
+-		sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift);
+-
+-	ieee80211_tpt_led_trig_tx(local, skb->len);
+-
+-	if (ieee80211_queue_skb(local, sdata, sta, skb))
+-		return true;
+-
+ 	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ 
+ 	if (local->queue_stop_reasons[q] ||
+@@ -4355,27 +4405,50 @@ static bool ieee80211_tx_8023(struct iee
+ 	return true;
+ }
+ 
++static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
++			      struct sk_buff *skb, struct sta_info *sta,
++			      bool txpending)
++{
++	struct ieee80211_local *local = sdata->local;
++	struct sk_buff *next;
++	bool ret = true;
++
++	if (ieee80211_queue_skb(local, sdata, sta, skb))
++		return true;
++
++	skb_list_walk_safe(skb, skb, next) {
++		skb_mark_not_on_list(skb);
++		if (!__ieee80211_tx_8023(sdata, skb, sta, txpending))
++			ret = false;
++	}
++
++	return ret;
++}
++
+ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
+ 				struct net_device *dev, struct sta_info *sta,
+ 				struct ieee80211_key *key, struct sk_buff *skb)
+ {
+-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++	struct ieee80211_tx_info *info;
+ 	struct ieee80211_local *local = sdata->local;
+ 	struct tid_ampdu_tx *tid_tx;
++	struct sk_buff *seg, *next;
++	unsigned int skbs = 0, len = 0;
++	u16 queue;
+ 	u8 tid;
+ 
+ 	if (local->ops->wake_tx_queue) {
+-		u16 queue = __ieee80211_select_queue(sdata, sta, skb);
++		queue = __ieee80211_select_queue(sdata, sta, skb);
+ 		skb_set_queue_mapping(skb, queue);
+ 		skb_get_hash(skb);
++	} else {
++		queue = skb_get_queue_mapping(skb);
+ 	}
+ 
+ 	if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
+ 	    test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+ 		goto out_free;
+ 
+-	memset(info, 0, sizeof(*info));
+-
+ 	ieee80211_aggr_check(sdata, sta, skb);
+ 
+ 	tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+@@ -4387,22 +4460,20 @@ static void ieee80211_8023_xmit(struct i
+ 			return;
+ 		}
+ 
+-		info->flags |= IEEE80211_TX_CTL_AMPDU;
+ 		if (tid_tx->timeout)
+ 			tid_tx->last_tx = jiffies;
+ 	}
+ 
+-	if (unlikely(skb->sk &&
+-		     skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
+-		info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
+-							     &info->flags, NULL);
++	skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
++	if (!skb)
++		return;
+ 
+-	info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
++	info = IEEE80211_SKB_CB(skb);
++	memset(info, 0, sizeof(*info));
++	if (tid_tx)
++		info->flags |= IEEE80211_TX_CTL_AMPDU;
+ 
+-	dev_sw_netstats_tx_add(dev, 1, skb->len);
+-
+-	sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
+-	sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
++	info->hw_queue = sdata->vif.hw_queue[queue];
+ 
+ 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ 		sdata = container_of(sdata->bss,
+@@ -4414,6 +4485,24 @@ static void ieee80211_8023_xmit(struct i
+ 	if (key)
+ 		info->control.hw_key = &key->conf;
+ 
++	skb_list_walk_safe(skb, seg, next) {
++		skbs++;
++		len += seg->len;
++		if (seg != skb)
++			memcpy(IEEE80211_SKB_CB(seg), info, sizeof(*info));
++	}
++
++	if (unlikely(skb->sk &&
++		     skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
++		info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
++							     &info->flags, NULL);
++
++	dev_sw_netstats_tx_add(dev, skbs, len);
++	sta->tx_stats.packets[queue] += skbs;
++	sta->tx_stats.bytes[queue] += len;
++
++	ieee80211_tpt_led_trig_tx(local, len);
++
+ 	ieee80211_tx_8023(sdata, skb, sta, false);
+ 
+ 	return;
+@@ -4455,6 +4544,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8
+ 		    key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
+ 		goto skip_offload;
+ 
++	sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
+ 	ieee80211_8023_xmit(sdata, dev, sta, key, skb);
+ 	goto out;
+ 
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/916-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on-DFS-channel-concurrently.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/916-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on-DFS-channel-concurrently.patch
new file mode 100644
index 0000000..f5fc0f9
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/916-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on-DFS-channel-concurrently.patch
@@ -0,0 +1,262 @@
+From a58aa02645052470e6bacb9e6c1eb7adfb9fc0d8 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Wed, 5 Oct 2022 19:13:43 +0800
+Subject: [PATCH] mac80211: fix the issue of AP and STA starting on DFS channel
+ concurrently
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ include/net/cfg80211.h       | 21 ++++++++++++++++
+ include/uapi/linux/nl80211.h |  2 +-
+ net/mac80211/cfg.c           | 48 ++++++++++++++++++++++++++++++++++++
+ net/mac80211/chan.c          |  2 +-
+ net/wireless/chan.c          |  6 ++---
+ net/wireless/nl80211.c       |  8 ++++++
+ net/wireless/rdev-ops.h      | 16 ++++++++++++
+ net/wireless/trace.h         | 15 +++++++++++
+ 8 files changed, 113 insertions(+), 5 deletions(-)
+
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+index f594914..0af069d 100644
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -800,6 +800,24 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
+ 		chandef1->center_freq2 == chandef2->center_freq2);
+ }
+ 
++/**
++ * cfg80211_chan_fully_overlap - check if two channel are fully overlapped
++ * @chandef1: first channel definition
++ * @chandef2: second channel definition
++ *
++ * Return: %true if the channels are valid and fully overlapped, %false otherwise.
++ */
++static inline bool
++cfg80211_chan_fully_overlap(const struct cfg80211_chan_def *chandef1,
++			    const struct cfg80211_chan_def *chandef2)
++{
++	return (chandef1->center_freq1 != 0 &&
++		chandef1->center_freq1 == chandef2->center_freq1 &&
++		chandef1->width == chandef2->width &&
++		chandef1->freq1_offset == chandef2->freq1_offset &&
++		chandef1->center_freq2 == chandef2->center_freq2);
++}
++
+ /**
+  * cfg80211_chandef_is_edmg - check if chandef represents an EDMG channel
+  *
+@@ -4401,6 +4419,8 @@ struct cfg80211_ops {
+ 				struct cfg80211_color_change_settings *params);
+ 	int	(*set_radar_background)(struct wiphy *wiphy,
+ 					struct cfg80211_chan_def *chandef);
++	void	(*check_cac_skip)(struct wiphy *wiphy,
++				  struct cfg80211_chan_def *chandef);
+ };
+ 
+ /*
+@@ -5554,6 +5574,7 @@ struct wireless_dev {
+ 	struct work_struct pmsr_free_wk;
+ 
+ 	unsigned long unprot_beacon_reported;
++	bool start_disabled;
+ };
+ 
+ static inline u8 *wdev_address(struct wireless_dev *wdev)
+diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
+index e674aa7..ada8288 100644
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -3129,7 +3129,7 @@ enum nl80211_attrs {
+ 	NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+ 
+ 	/* add attributes here, update the policy in nl80211.c */
+-
++	NL80211_ATTR_START_DISABLED = 999,
+ 	__NL80211_ATTR_AFTER_LAST,
+ 	NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
+ 	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+index bf71594..73fb432 100644
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -4504,6 +4504,53 @@ ieee80211_set_radar_background(struct wiphy *wiphy,
+ 	return local->ops->set_radar_background(&local->hw, chandef);
+ }
+ 
++static void
++ieee80211_check_cac_skip(struct wiphy *wiphy,
++			 struct cfg80211_chan_def *chandef)
++{
++	struct ieee80211_local *local = wiphy_priv(wiphy);
++	struct ieee80211_sub_if_data *s1;
++	struct ieee80211_sub_if_data *s2;
++	struct ieee80211_sub_if_data *sdata_sta;
++	struct ieee80211_if_managed *ifmgd;
++	struct ieee80211_channel *chan;
++	struct wireless_dev *wdev;
++	unsigned int cac_time_ms;
++
++	mutex_lock(&local->mtx);
++	/* Bypass AP's cac if there is a STA associated to the same DFS channel */
++	list_for_each_entry(s1, &local->interfaces, list) {
++		ifmgd = &s1->u.mgd;
++
++		if (s1->vif.type == NL80211_IFTYPE_STATION && ifmgd->associated)
++			sdata_sta = s1;
++		else
++			continue;
++
++		list_for_each_entry(s2, &local->interfaces, list) {
++			wdev = &s2->wdev;
++			chan = wdev->chandef.chan;
++			if (chan) {
++				if (!(chan->flags & IEEE80211_CHAN_RADAR))
++					continue;
++
++				if (wdev->identifier != sdata_sta->wdev.identifier &&
++				    chan->dfs_state == NL80211_DFS_USABLE && wdev->cac_started &&
++				    cfg80211_chan_fully_overlap(&sdata_sta->vif.bss_conf.chandef,
++								&s2->vif.bss_conf.chandef)) {
++					cac_time_ms = wdev->cac_time_ms;
++					wdev->cac_start_time = jiffies -
++							       msecs_to_jiffies(cac_time_ms + 1);
++					cfg80211_cac_event(wdev->netdev, &wdev->chandef,
++							   NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
++					sdata_info(s2, "Skip CAC on the associated STA's chan\n");
++				}
++			}
++		}
++	}
++	mutex_unlock(&local->mtx);
++}
++
+ const struct cfg80211_ops mac80211_config_ops = {
+ 	.add_virtual_intf = ieee80211_add_iface,
+ 	.del_virtual_intf = ieee80211_del_iface,
+@@ -4610,4 +4657,5 @@ const struct cfg80211_ops mac80211_config_ops = {
+ 	.set_sar_specs = ieee80211_set_sar_specs,
+ 	.color_change = ieee80211_color_change,
+ 	.set_radar_background = ieee80211_set_radar_background,
++	.check_cac_skip = ieee80211_check_cac_skip,
+ };
+diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
+index 63e15f5..5e57e4a 100644
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -505,7 +505,7 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
+ 
+ 	rcu_read_lock();
+ 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+-		if (sdata->radar_required) {
++		if (sdata->radar_required && sdata->wdev.cac_started) {
+ 			rcu_read_unlock();
+ 			return true;
+ 		}
+diff --git a/net/wireless/chan.c b/net/wireless/chan.c
+index 5f50ac4..067ed79 100644
+--- a/net/wireless/chan.c
++++ b/net/wireless/chan.c
+@@ -664,13 +664,13 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
+ 	switch (wdev->iftype) {
+ 	case NL80211_IFTYPE_AP:
+ 	case NL80211_IFTYPE_P2P_GO:
+-		active = wdev->beacon_interval != 0;
++		active = wdev->beacon_interval != 0 || wdev->start_disabled;
+ 		break;
+ 	case NL80211_IFTYPE_ADHOC:
+-		active = wdev->ssid_len != 0;
++		active = wdev->ssid_len != 0 || wdev->start_disabled;
+ 		break;
+ 	case NL80211_IFTYPE_MESH_POINT:
+-		active = wdev->mesh_id_len != 0;
++		active = wdev->mesh_id_len != 0 || wdev->start_disabled;
+ 		break;
+ 	case NL80211_IFTYPE_STATION:
+ 	case NL80211_IFTYPE_OCB:
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index a20aba5..8dc928d 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -803,6 +803,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
+ 			NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
+ 	[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
+ 	[NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
++	[NL80211_ATTR_START_DISABLED] = { .type = NLA_FLAG },
+ 	[NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
+ };
+ 
+@@ -5547,6 +5548,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	memset(&params, 0, sizeof(params));
+ 
++	if (info->attrs[NL80211_ATTR_START_DISABLED]) {
++		wdev->start_disabled = nla_get_flag(info->attrs[NL80211_ATTR_START_DISABLED]);
++		err = 0;
++		goto out;
++	}
++
+ 	/* these are required for START_AP */
+ 	if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
+ 	    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
+@@ -9393,6 +9400,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
+ 		wdev->cac_started = true;
+ 		wdev->cac_start_time = jiffies;
+ 		wdev->cac_time_ms = cac_time_ms;
++		err = rdev_check_cac_skip(rdev, &wdev->chandef);
+ 	}
+ unlock:
+ 	wiphy_unlock(wiphy);
+diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
+index 8555468..e7d0064 100644
+--- a/net/wireless/rdev-ops.h
++++ b/net/wireless/rdev-ops.h
+@@ -1398,4 +1398,20 @@ rdev_set_radar_background(struct cfg80211_registered_device *rdev,
+ 	return ret;
+ }
+ 
++static inline int
++rdev_check_cac_skip(struct cfg80211_registered_device *rdev,
++		    struct cfg80211_chan_def *chandef)
++{
++	struct wiphy *wiphy = &rdev->wiphy;
++
++	if (!rdev->ops->check_cac_skip)
++		return -EOPNOTSUPP;
++
++	trace_rdev_check_cac_skip(wiphy, chandef);
++	rdev->ops->check_cac_skip(wiphy, chandef);
++	trace_rdev_return_void(wiphy);
++
++	return 0;
++}
++
+ #endif /* __CFG80211_RDEV_OPS */
+diff --git a/net/wireless/trace.h b/net/wireless/trace.h
+index 97a2937..e3f1c79 100644
+--- a/net/wireless/trace.h
++++ b/net/wireless/trace.h
+@@ -3665,6 +3665,21 @@ TRACE_EVENT(rdev_set_radar_background,
+ 		  WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
+ );
+ 
++TRACE_EVENT(rdev_check_cac_skip,
++	    TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
++
++	    TP_ARGS(wiphy, chandef),
++
++	    TP_STRUCT__entry(WIPHY_ENTRY
++			     CHAN_DEF_ENTRY),
++
++	    TP_fast_assign(WIPHY_ASSIGN;
++			   CHAN_DEF_ASSIGN(chandef)),
++
++	    TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
++		      WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
++);
++
+ #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
+ 
+ #undef TRACE_INCLUDE_PATH
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc b/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
index 8ca4824..10725d1 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
@@ -41,10 +41,25 @@
     file://343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch \
     file://344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch \
     file://345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch \
-    file://350-bss-color-collision.patch \
+    file://346-mac80211-mesh-clean-up-rx_bcn_presp-API.patch \
+    file://347-mac80211-move-CRC-into-struct-ieee802_11_elems.patch \
+    file://348-mac80211-mlme-find-auth-challenge-directly.patch \
+    file://349-mac80211-always-allocate-struct-ieee802_11_elems.patch \
+    file://350-mac80211-fix-memory-leaks-with-element-parsing.patch \
+    file://351-wifi-cfg80211-fix-u8-overflow-in-cfg80211_update_not.patch \
+    file://352-wifi-cfg80211-mac80211-reject-bad-MBSSID-elements.patch \
+    file://353-wifi-mac80211-fix-MBSSID-parsing-use-after-free.patch \
+    file://354-wifi-cfg80211-ensure-length-byte-is-present-before-a.patch \
+    file://355-wifi-cfg80211-fix-BSS-refcounting-bugs.patch \
+    file://356-wifi-cfg80211-avoid-nontransmitted-BSS-list-corrupti.patch \
+    file://357-wifi-mac80211_hwsim-avoid-mac80211-warning-on-bad-ra.patch \
+    file://358-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch \
+    file://359-wifi-cfg80211-update-hidden-BSSes-to-avoid-WARN_ON.patch \
     file://360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch \
     file://361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch \
     file://362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch \
+    file://363-bss-color-collision.patch \
+    file://364-mac80211-add-support-for-restricting-netdev-features.patch \
     file://400-allow-ibss-mixed.patch \
     file://500-mac80211_configure_antenna_gain.patch \
     file://782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch \
@@ -64,4 +79,5 @@
     file://913-mac80211-mtk-remove-timerout-handle-for-ax210-iot-issue.patch \
     file://914-cfg80211-mtk-implement-DFS-status-show-cac-and-nop-skip-command.patch \
     file://915-mac80211-mtk-Set-TWT-Information-Frame-Disabled-bit-as-1.-This-mo.patch \
+    file://916-mac80211-mtk-fix-the-issue-of-AP-and-STA-starting-on-DFS-channel-concurrently.patch \
     "
diff --git a/recipes-kernel/linux-mt76/files/patches/0001-mt76-mt7915-rework-testmode-init-registers.patch b/recipes-kernel/linux-mt76/files/patches/0001-mt76-mt7915-rework-testmode-init-registers.patch
index 873a154..b0689cd 100644
--- a/recipes-kernel/linux-mt76/files/patches/0001-mt76-mt7915-rework-testmode-init-registers.patch
+++ b/recipes-kernel/linux-mt76/files/patches/0001-mt76-mt7915-rework-testmode-init-registers.patch
@@ -1,4 +1,4 @@
-From f45f9c4ab6b8e9508a0fedb65de098c4f1be63c3 Mon Sep 17 00:00:00 2001
+From 567a6f7be24a7f87d550f1cf3e1f1796e1770b2a Mon Sep 17 00:00:00 2001
 From: Shayne Chen <shayne.chen@mediatek.com>
 Date: Mon, 6 Jun 2022 19:46:26 +0800
 Subject: [PATCH 1/3] mt76: mt7915: rework testmode init registers
@@ -11,7 +11,7 @@
  4 files changed, 55 insertions(+), 18 deletions(-)
 
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index be1b8ea..9c2c508 100644
+index be1b8ea7..9c2c5086 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
 @@ -68,6 +68,7 @@ static const u32 mt7986_reg[] = {
@@ -31,7 +31,7 @@
  	[TMAC_ODTR]		= 0x0cc,
  	[TMAC_ATCR]		= 0x00c,
 diff --git a/mt7915/regs.h b/mt7915/regs.h
-index 5180dd9..2e44537 100644
+index 5180dd93..2e445373 100644
 --- a/mt7915/regs.h
 +++ b/mt7915/regs.h
 @@ -32,6 +32,7 @@ enum reg_rev {
@@ -79,7 +79,7 @@
  #define MT_AGG_ACR0(_band)		MT_WF_AGG(_band, __OFFS(AGG_ACR0))
  #define MT_AGG_ACR_CFEND_RATE		GENMASK(13, 0)
 diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index a979460..819fafe 100644
+index a979460f..819fafe4 100644
 --- a/mt7915/testmode.c
 +++ b/mt7915/testmode.c
 @@ -30,7 +30,7 @@ struct reg_band {
@@ -176,7 +176,7 @@
  
  static void
 diff --git a/testmode.c b/testmode.c
-index 0accc71..57cdfdf 100644
+index 0accc71a..57cdfdf6 100644
 --- a/testmode.c
 +++ b/testmode.c
 @@ -447,8 +447,7 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -190,5 +190,5 @@
  	    mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE],
  			   &td->tx_duty_cycle, 0, 99) ||
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/0002-mt76-mt7915-rework-rx-testmode-stats.patch b/recipes-kernel/linux-mt76/files/patches/0002-mt76-mt7915-rework-rx-testmode-stats.patch
index 08f86a3..0691685 100644
--- a/recipes-kernel/linux-mt76/files/patches/0002-mt76-mt7915-rework-rx-testmode-stats.patch
+++ b/recipes-kernel/linux-mt76/files/patches/0002-mt76-mt7915-rework-rx-testmode-stats.patch
@@ -1,4 +1,4 @@
-From 095584941c21d2348ab3c3afe67f4dfa0b6957cd Mon Sep 17 00:00:00 2001
+From 691fcd82d9e3572d2a2973361ee3c4fe9f3789f3 Mon Sep 17 00:00:00 2001
 From: Shayne Chen <shayne.chen@mediatek.com>
 Date: Mon, 3 Jan 2022 17:09:53 +0800
 Subject: [PATCH 2/3] mt76: mt7915: rework rx testmode stats
@@ -15,7 +15,7 @@
  8 files changed, 109 insertions(+), 17 deletions(-)
 
 diff --git a/mac80211.c b/mac80211.c
-index e2a8ef9..7ef853c 100644
+index e2a8ef94..7ef853cb 100644
 --- a/mac80211.c
 +++ b/mac80211.c
 @@ -756,7 +756,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
@@ -29,7 +29,7 @@
  		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
  			phy->test.rx_stats.fcs_error[q]++;
 diff --git a/mt76.h b/mt76.h
-index f9bdf16..aef6006 100644
+index f9bdf16f..aef60066 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -626,6 +626,8 @@ struct mt76_testmode_ops {
@@ -59,7 +59,7 @@
  };
  
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index cf4ce3b..3101721 100644
+index cf4ce3b1..31017218 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -1138,6 +1138,7 @@ enum {
@@ -71,7 +71,7 @@
  	MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab,
  	MCU_EXT_CMD_DPD_PRE_CAL_INFO = 0xac,
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 87cd1bf..ed94980 100644
+index 87cd1bff..ed949802 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -9,6 +9,7 @@
@@ -83,7 +83,7 @@
  	MCU_ATE_CLEAN_TXQUEUE = 0x1c,
  };
 diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index 819fafe..8d99edc 100644
+index 819fafe4..8d99edcb 100644
 --- a/mt7915/testmode.c
 +++ b/mt7915/testmode.c
 @@ -133,6 +133,21 @@ mt7915_tm_clean_hwq(struct mt7915_phy *phy, u8 wcid)
@@ -215,7 +215,7 @@
  
  const struct mt76_testmode_ops mt7915_testmode_ops = {
 diff --git a/mt7915/testmode.h b/mt7915/testmode.h
-index 5573ac3..a1c54c8 100644
+index 5573ac30..a1c54c89 100644
 --- a/mt7915/testmode.h
 +++ b/mt7915/testmode.h
 @@ -33,6 +33,12 @@ struct mt7915_tm_clean_txq {
@@ -266,7 +266,7 @@
 +
  #endif
 diff --git a/testmode.c b/testmode.c
-index 57cdfdf..1d0d5d3 100644
+index 57cdfdf6..1d0d5d30 100644
 --- a/testmode.c
 +++ b/testmode.c
 @@ -559,6 +559,9 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg)
@@ -280,7 +280,7 @@
  		return -EMSGSIZE;
  
 diff --git a/testmode.h b/testmode.h
-index 5e2792d..8961326 100644
+index 5e2792d8..89613266 100644
 --- a/testmode.h
 +++ b/testmode.h
 @@ -101,6 +101,8 @@ enum mt76_testmode_attr {
@@ -301,5 +301,5 @@
  	/* keep last */
  	NUM_MT76_TM_STATS_ATTRS,
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/0003-mt76-mt7915-drop-undefined-action-frame.patch b/recipes-kernel/linux-mt76/files/patches/0003-mt76-mt7915-drop-undefined-action-frame.patch
index c48bc4c..eec1bc6 100644
--- a/recipes-kernel/linux-mt76/files/patches/0003-mt76-mt7915-drop-undefined-action-frame.patch
+++ b/recipes-kernel/linux-mt76/files/patches/0003-mt76-mt7915-drop-undefined-action-frame.patch
@@ -1,4 +1,4 @@
-From 71dc778b26769005bb0396d0a167ad18a7599ad9 Mon Sep 17 00:00:00 2001
+From 88a457bc6d5909735c89102ef970235c2e8f4038 Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Thu, 14 Apr 2022 15:18:02 +0800
 Subject: [PATCH 3/3] mt76: mt7915: drop undefined action frame
@@ -8,10 +8,10 @@
  1 file changed, 6 insertions(+)
 
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index a76c82b..8ef5ddc 100644
+index 66aae55d..d1a20818 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -684,6 +684,8 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+@@ -686,6 +686,8 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
  			  struct mt76_tx_info *tx_info)
  {
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
@@ -20,7 +20,7 @@
  	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
  	struct ieee80211_key_conf *key = info->control.hw_key;
-@@ -714,6 +716,10 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+@@ -716,6 +718,10 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
  	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
  	t->skb = tx_info->skb;
  
@@ -32,5 +32,5 @@
  	if (id < 0)
  		return id;
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch b/recipes-kernel/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
index e75b064..184e824 100644
--- a/recipes-kernel/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
@@ -1,4 +1,4 @@
-From 66c81406b30b24a50be33f5434664191b7cf7ab0 Mon Sep 17 00:00:00 2001
+From df2abf2cef0ea55ed0a3fc805c491934ac65a5c9 Mon Sep 17 00:00:00 2001
 From: Shayne Chen <shayne.chen@mediatek.com>
 Date: Wed, 22 Jun 2022 10:39:47 +0800
 Subject: [PATCH 1001/1009] mt76: mt7915: add mtk internal debug tools for mt76
@@ -22,7 +22,7 @@
  create mode 100644 mt7915/mtk_mcu.c
 
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 3101721..06813f7 100644
+index 31017218..06813f77 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -1104,6 +1104,7 @@ enum {
@@ -47,7 +47,7 @@
  	MCU_EXT_CMD_CAL_CACHE = 0x67,
  	MCU_EXT_CMD_SET_RADAR_TH = 0x7c,
 diff --git a/mt7915/Makefile b/mt7915/Makefile
-index b794ceb..a3474e2 100644
+index b794ceb7..a3474e2f 100644
 --- a/mt7915/Makefile
 +++ b/mt7915/Makefile
 @@ -3,7 +3,7 @@
@@ -61,7 +61,7 @@
  mt7915e-$(CONFIG_MT7986_WMAC) += soc.o
 \ No newline at end of file
 diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
-index b95c81d..fd0c9d1 100644
+index b95c81db..fd0c9d18 100644
 --- a/mt7915/debugfs.c
 +++ b/mt7915/debugfs.c
 @@ -8,6 +8,9 @@
@@ -205,10 +205,10 @@
  
  	if (dev->relay_fwlog)
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 8ef5ddc..2ff90f7 100644
+index d1a20818..88616e1e 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -239,6 +239,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
+@@ -240,6 +240,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
  	__le16 fc = 0;
  	int idx;
  
@@ -219,7 +219,7 @@
  	memset(status, 0, sizeof(*status));
  
  	if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->band_idx) {
-@@ -421,6 +425,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
+@@ -423,6 +427,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
  	}
  
  	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
@@ -230,7 +230,7 @@
  	if (hdr_trans && ieee80211_has_morefrags(fc)) {
  		struct ieee80211_vif *vif;
  		int err;
-@@ -762,6 +770,12 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+@@ -764,6 +772,12 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
  	tx_info->buf[1].skip_unmap = true;
  	tx_info->nbuf = MT_CT_DMA_BUF_NUM;
  
@@ -244,7 +244,7 @@
  }
  
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 0dffe82..7913059 100644
+index 0dffe82f..7913059c 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -62,7 +62,11 @@ static int mt7915_start(struct ieee80211_hw *hw)
@@ -260,7 +260,7 @@
  		goto out;
  
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 2f6d328..c710624 100644
+index 2f6d3287..c710624d 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -195,6 +195,11 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -352,7 +352,7 @@
 +}
 +#endif
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index ed94980..bfb822f 100644
+index ed949802..bfb822fa 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -259,6 +259,10 @@ enum {
@@ -367,7 +367,7 @@
  
  enum mcu_mmps_mode {
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index fe6a6d3..c0dfe10 100644
+index fe6a6d3b..c0dfe105 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -9,6 +9,7 @@
@@ -435,7 +435,7 @@
  #endif
 diff --git a/mt7915/mt7915_debug.h b/mt7915/mt7915_debug.h
 new file mode 100644
-index 0000000..58ba2cd
+index 00000000..ecdc02ab
 --- /dev/null
 +++ b/mt7915/mt7915_debug.h
 @@ -0,0 +1,1350 @@
@@ -1791,7 +1791,7 @@
 +#endif
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
 new file mode 100644
-index 0000000..747a901
+index 00000000..747a9014
 --- /dev/null
 +++ b/mt7915/mtk_debugfs.c
 @@ -0,0 +1,2925 @@
@@ -4722,7 +4722,7 @@
 +#endif
 diff --git a/mt7915/mtk_mcu.c b/mt7915/mtk_mcu.c
 new file mode 100644
-index 0000000..145fe78
+index 00000000..145fe785
 --- /dev/null
 +++ b/mt7915/mtk_mcu.c
 @@ -0,0 +1,51 @@
@@ -4778,7 +4778,7 @@
 +				 sizeof(req), true);
 +}
 diff --git a/tools/fwlog.c b/tools/fwlog.c
-index e5d4a10..3d51d9e 100644
+index e5d4a105..3d51d9ec 100644
 --- a/tools/fwlog.c
 +++ b/tools/fwlog.c
 @@ -26,7 +26,7 @@ static const char *debugfs_path(const char *phyname, const char *file)
@@ -4892,5 +4892,5 @@
  	return ret;
  }
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1002-mt76-mt7915-csi-implement-csi-support.patch b/recipes-kernel/linux-mt76/files/patches/1002-mt76-mt7915-csi-implement-csi-support.patch
index d578e64..e6af65a 100644
--- a/recipes-kernel/linux-mt76/files/patches/1002-mt76-mt7915-csi-implement-csi-support.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1002-mt76-mt7915-csi-implement-csi-support.patch
@@ -1,4 +1,4 @@
-From 0da94e40be885271ff884b581117498f2e4db997 Mon Sep 17 00:00:00 2001
+From a8eebb6485cf276131d9c57f2a20839740900e12 Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Mon, 6 Jun 2022 20:13:02 +0800
 Subject: [PATCH 1002/1009] mt76: mt7915: csi: implement csi support
@@ -17,7 +17,7 @@
  create mode 100644 mt7915/vendor.h
 
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 06813f7..5d7c911 100644
+index 06813f77..5d7c911c 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -979,6 +979,7 @@ enum {
@@ -37,7 +37,7 @@
  
  enum {
 diff --git a/mt7915/Makefile b/mt7915/Makefile
-index a3474e2..e272c82 100644
+index a3474e2f..e272c826 100644
 --- a/mt7915/Makefile
 +++ b/mt7915/Makefile
 @@ -1,9 +1,9 @@
@@ -54,7 +54,7 @@
  mt7915e-$(CONFIG_MT7986_WMAC) += soc.o
 \ No newline at end of file
 diff --git a/mt7915/init.c b/mt7915/init.c
-index 416e5ac..34b5df7 100644
+index 416e5acb..34b5df76 100644
 --- a/mt7915/init.c
 +++ b/mt7915/init.c
 @@ -547,6 +547,12 @@ mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy)
@@ -132,7 +132,7 @@
  	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
  		dev->mt76.led_cdev.brightness_set = mt7915_led_set_brightness;
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index c710624..d9ff5a3 100644
+index c710624d..d9ff5a35 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -32,6 +32,10 @@
@@ -268,7 +268,7 @@
  int mt7915_dbg_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3, bool wait_resp)
  {
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index bfb822f..a27129c 100644
+index bfb822fa..a27129c2 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -480,4 +480,80 @@ enum {
@@ -353,7 +353,7 @@
 +
  #endif
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index c0dfe10..bcfcf6f 100644
+index c0dfe105..bcfcf6f5 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -274,6 +274,20 @@ struct mt7915_phy {
@@ -392,7 +392,7 @@
  int mt7915_dbg_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3, bool wait_resp);
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
 new file mode 100644
-index 0000000..98fd9c2
+index 00000000..98fd9c2d
 --- /dev/null
 +++ b/mt7915/vendor.c
 @@ -0,0 +1,452 @@
@@ -850,7 +850,7 @@
 +}
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
 new file mode 100644
-index 0000000..9d3db2a
+index 00000000..9d3db2a7
 --- /dev/null
 +++ b/mt7915/vendor.h
 @@ -0,0 +1,60 @@
@@ -915,5 +915,5 @@
 +
 +#endif
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1003-mt76-mt7915-air-monitor-support.patch b/recipes-kernel/linux-mt76/files/patches/1003-mt76-mt7915-air-monitor-support.patch
index 9eb1876..1a22431 100644
--- a/recipes-kernel/linux-mt76/files/patches/1003-mt76-mt7915-air-monitor-support.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1003-mt76-mt7915-air-monitor-support.patch
@@ -1,4 +1,4 @@
-From e5b6d9784c5d5866df066f448940046a093aa9e4 Mon Sep 17 00:00:00 2001
+From 77db6e402f1e3d53d433c01a9e2339aba47db48d Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Tue, 11 Jan 2022 12:03:23 +0800
 Subject: [PATCH 1003/1009] mt76: mt7915: air monitor support
@@ -13,7 +13,7 @@
  6 files changed, 440 insertions(+)
 
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 5d7c911..d87ad38 100644
+index 5d7c911c..d87ad382 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -1151,6 +1151,8 @@ enum {
@@ -26,10 +26,10 @@
  };
  
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 2ff90f7..78190af 100644
+index 88616e1e..42c887e2 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -486,6 +486,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
+@@ -488,6 +488,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
  			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
  			qos_ctl = *ieee80211_get_qos_ctl(hdr);
  		}
@@ -41,7 +41,7 @@
  		status->flag |= RX_FLAG_8023;
  	}
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 7913059..35cd7ad 100644
+index 7913059c..35cd7ad5 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -675,6 +675,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -55,7 +55,7 @@
  }
  
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index bcfcf6f..4c3bb62 100644
+index bcfcf6f5..4c3bb62f 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -229,6 +229,35 @@ struct mt7915_hif {
@@ -114,7 +114,7 @@
  
  #ifdef MTK_DEBUG
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 98fd9c2..b94d787 100644
+index 98fd9c2d..b94d787e 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -430,6 +430,353 @@ out:
@@ -491,7 +491,7 @@
  };
  
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 9d3db2a..976817f 100644
+index 9d3db2a7..976817f3 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -4,6 +4,7 @@
@@ -545,5 +545,5 @@
 +
  #endif
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch b/recipes-kernel/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
index e5a31be..83a9101 100644
--- a/recipes-kernel/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
@@ -1,4 +1,4 @@
-From 952b05674331043bc5e904a16b7ec4e5634f5b5f Mon Sep 17 00:00:00 2001
+From 8e92016b1c11dd9d7608f675726d5cb337f8623c Mon Sep 17 00:00:00 2001
 From: MeiChia Chiu <meichia.chiu@mediatek.com>
 Date: Wed, 22 Jun 2022 10:45:53 +0800
 Subject: [PATCH 1004/1009] mt76: mt7915: add support for muru_onoff via
@@ -12,7 +12,7 @@
  4 files changed, 47 insertions(+), 2 deletions(-)
 
 diff --git a/mt7915/init.c b/mt7915/init.c
-index 34b5df7..479b984 100644
+index 34b5df76..479b984f 100644
 --- a/mt7915/init.c
 +++ b/mt7915/init.c
 @@ -582,6 +582,7 @@ static void mt7915_init_work(struct work_struct *work)
@@ -24,7 +24,7 @@
  
  void mt7915_wfsys_reset(struct mt7915_dev *dev)
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index d9ff5a3..4c04760 100644
+index d9ff5a35..4c047606 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -856,13 +856,18 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
@@ -49,7 +49,7 @@
  		muru->mimo_dl.vht_mu_bfee =
  			!!(sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index a27129c..d3cc828 100644
+index a27129c2..d3cc8283 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -556,4 +556,10 @@ struct csi_data {
@@ -64,7 +64,7 @@
 +
  #endif
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 747a901..176937a 100644
+index 747a9014..176937ad 100644
 --- a/mt7915/mtk_debugfs.c
 +++ b/mt7915/mtk_debugfs.c
 @@ -2480,6 +2480,38 @@ static int mt7915_token_txd_read(struct seq_file *s, void *data)
@@ -115,5 +115,5 @@
  			    &fops_fw_debug_module);
  	debugfs_create_file("fw_debug_level", 0600, dir, dev,
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1005-mt76-certification-patches.patch b/recipes-kernel/linux-mt76/files/patches/1005-mt76-certification-patches.patch
index f91650a..00d5fb1 100644
--- a/recipes-kernel/linux-mt76/files/patches/1005-mt76-certification-patches.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1005-mt76-certification-patches.patch
@@ -1,4 +1,4 @@
-From 280df913359a09229adfeb301edd1f64c9f4c464 Mon Sep 17 00:00:00 2001
+From e5d58f825b9f53695880296959dea2cc8beb7176 Mon Sep 17 00:00:00 2001
 From: MeiChia Chiu <meichia.chiu@mediatek.com>
 Date: Mon, 6 Jun 2022 20:15:51 +0800
 Subject: [PATCH 1005/1009] mt76: certification patches
@@ -16,7 +16,7 @@
  9 files changed, 956 insertions(+), 5 deletions(-)
 
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index d87ad38..01035b2 100644
+index d87ad382..01035b28 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -1153,6 +1153,7 @@ enum {
@@ -28,7 +28,7 @@
  };
  
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 78190af..7caa0ec 100644
+index 42c887e2..5609108b 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
 @@ -7,6 +7,7 @@
@@ -39,7 +39,7 @@
  
  #define to_rssi(field, rxv)	((FIELD_GET(field, rxv) - 220) / 2)
  
-@@ -1752,6 +1753,21 @@ static void mt7915_mac_severe_check(struct mt7915_phy *phy)
+@@ -1754,6 +1755,21 @@ static void mt7915_mac_severe_check(struct mt7915_phy *phy)
  	phy->trb_ts = trb;
  }
  
@@ -61,7 +61,7 @@
  void mt7915_mac_sta_rc_work(struct work_struct *work)
  {
  	struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
-@@ -1774,6 +1790,13 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
+@@ -1776,6 +1792,13 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
  		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
  		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
  
@@ -76,7 +76,7 @@
  			       IEEE80211_RC_NSS_CHANGED |
  			       IEEE80211_RC_BW_CHANGED))
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 35cd7ad..abfdc72 100644
+index 35cd7ad5..abfdc729 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -653,6 +653,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -109,7 +109,7 @@
  
  void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 4c04760..8731f7d 100644
+index 4c047606..8731f7d0 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -3574,6 +3574,472 @@ mt7915_mcu_report_csi(struct mt7915_dev *dev, struct sk_buff *skb)
@@ -586,7 +586,7 @@
  
  #ifdef MTK_DEBUG
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index d3cc828..aab1a6a 100644
+index d3cc8283..aab1a6a3 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -396,10 +396,14 @@ enum {
@@ -820,7 +820,7 @@
  
  #endif
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 4c3bb62..93afa3d 100644
+index 4c3bb62f..93afa3d2 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -664,6 +664,19 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
@@ -844,7 +844,7 @@
  int mt7915_mcu_set_csi(struct mt7915_phy *phy, u8 mode,
  			u8 cfg, u8 v1, u32 v2, u8 *mac_addr);
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 176937a..e24b4d7 100644
+index 176937ad..e24b4d78 100644
 --- a/mt7915/mtk_debugfs.c
 +++ b/mt7915/mtk_debugfs.c
 @@ -2486,7 +2486,8 @@ static int mt7915_muru_onoff_get(void *data, u64 *val)
@@ -869,7 +869,7 @@
         }
  
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index b94d787..7456c57 100644
+index b94d787e..7456c577 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -22,6 +22,29 @@ csi_ctrl_policy[NUM_MTK_VENDOR_ATTRS_CSI_CTRL] = {
@@ -1081,7 +1081,7 @@
  };
  
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 976817f..1b08321 100644
+index 976817f3..1b08321c 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -6,6 +6,48 @@
@@ -1134,5 +1134,5 @@
  
  enum mtk_vendor_attr_csi_ctrl {
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1006-mt76-mt7915-add-L0.5-system-error-recovery-support.patch b/recipes-kernel/linux-mt76/files/patches/1006-mt76-mt7915-add-L0.5-system-error-recovery-support.patch
index 8df260a..8ff2c60 100644
--- a/recipes-kernel/linux-mt76/files/patches/1006-mt76-mt7915-add-L0.5-system-error-recovery-support.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1006-mt76-mt7915-add-L0.5-system-error-recovery-support.patch
@@ -1,4 +1,4 @@
-From 8df2b764386b00bbe48eb2f7e0d6829ce36eccda Mon Sep 17 00:00:00 2001
+From 3826960263176ad488830dd85649053ca41193f2 Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Wed, 22 Jun 2022 10:51:59 +0800
 Subject: [PATCH 1006/1009] mt76: mt7915: add L0.5 system error recovery
@@ -18,7 +18,7 @@
  10 files changed, 491 insertions(+), 98 deletions(-)
 
 diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
-index fd0c9d1..f585eb9 100644
+index fd0c9d18..f585eb93 100644
 --- a/mt7915/debugfs.c
 +++ b/mt7915/debugfs.c
 @@ -52,12 +52,17 @@ static ssize_t
@@ -142,7 +142,7 @@
  	kfree(buff);
  	return ret;
 diff --git a/mt7915/dma.c b/mt7915/dma.c
-index edae845..e391886 100644
+index edae8453..e3918860 100644
 --- a/mt7915/dma.c
 +++ b/mt7915/dma.c
 @@ -514,6 +514,54 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
@@ -201,7 +201,7 @@
  {
  	mt7915_dma_disable(dev, true);
 diff --git a/mt7915/init.c b/mt7915/init.c
-index 479b984..d83ba2b 100644
+index 479b984f..d83ba2bc 100644
 --- a/mt7915/init.c
 +++ b/mt7915/init.c
 @@ -262,7 +262,7 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev,
@@ -241,7 +241,7 @@
  
  unreg_thermal:
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 7caa0ec..cac296e 100644
+index 5609108b..e0210c3e 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
 @@ -3,6 +3,7 @@
@@ -252,7 +252,7 @@
  #include "mt7915.h"
  #include "../dma.h"
  #include "mac.h"
-@@ -1329,85 +1330,187 @@ mt7915_update_beacons(struct mt7915_dev *dev)
+@@ -1331,85 +1332,187 @@ mt7915_update_beacons(struct mt7915_dev *dev)
  		mt7915_update_vif_beacon, mphy_ext->hw);
  }
  
@@ -499,7 +499,7 @@
  }
  
  /* system error recovery */
-@@ -1422,6 +1525,36 @@ void mt7915_mac_reset_work(struct work_struct *work)
+@@ -1424,6 +1527,36 @@ void mt7915_mac_reset_work(struct work_struct *work)
  	ext_phy = dev->mt76.phys[MT_BAND1];
  	phy2 = ext_phy ? ext_phy->priv : NULL;
  
@@ -536,7 +536,7 @@
  	if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
  		return;
  
-@@ -1447,7 +1580,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
+@@ -1449,7 +1582,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
  	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
  
  	if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
@@ -545,7 +545,7 @@
  
  		mt7915_tx_token_put(dev);
  		idr_init(&dev->mt76.token);
-@@ -1496,6 +1629,34 @@ void mt7915_mac_reset_work(struct work_struct *work)
+@@ -1498,6 +1631,34 @@ void mt7915_mac_reset_work(struct work_struct *work)
  					     MT7915_WATCHDOG_TIME);
  }
  
@@ -581,7 +581,7 @@
  {
  	struct mt7915_dev *dev = phy->dev;
 diff --git a/mt7915/main.c b/mt7915/main.c
-index abfdc72..98dce0f 100644
+index abfdc729..98dce0f4 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -20,17 +20,13 @@ static bool mt7915_dev_running(struct mt7915_dev *dev)
@@ -631,7 +631,7 @@
  	mutex_lock(&dev->mt76.mutex);
  
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 8731f7d..7984432 100644
+index 8731f7d0..79844323 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -150,19 +150,90 @@ mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
@@ -767,7 +767,7 @@
  {
  	__mt76_mcu_restart(&dev->mt76);
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index aab1a6a..c485064 100644
+index aab1a6a3..c4850644 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -453,8 +453,9 @@ enum {
@@ -782,7 +782,7 @@
  	SER_SET_RECOVER_L3_RX_ABORT,
  	SER_SET_RECOVER_L3_TX_ABORT,
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 9c2c508..2e73bd7 100644
+index 9c2c5086..2e73bd79 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
 @@ -29,6 +29,7 @@ static const u32 mt7915_reg[] = {
@@ -823,7 +823,7 @@
  	}
  }
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 93afa3d..6868813 100644
+index 93afa3d2..6868813a 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -350,6 +350,15 @@ struct mt7915_dev {
@@ -871,7 +871,7 @@
  int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
  			       struct mt7915_vif *mvif,
 diff --git a/mt7915/regs.h b/mt7915/regs.h
-index 2e44537..3f283a8 100644
+index 2e445373..3f283a83 100644
 --- a/mt7915/regs.h
 +++ b/mt7915/regs.h
 @@ -28,6 +28,7 @@ enum reg_rev {
@@ -926,5 +926,5 @@
  #define MT_LED_TOP_BASE			0x18013000
  #define MT_LED_PHYS(_n)			(MT_LED_TOP_BASE + (_n))
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1007-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch b/recipes-kernel/linux-mt76/files/patches/1007-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch
index cee0d14..a473373 100644
--- a/recipes-kernel/linux-mt76/files/patches/1007-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1007-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch
@@ -1,4 +1,4 @@
-From d8a6f77dc9b3c58499375951b17c8f124668dd86 Mon Sep 17 00:00:00 2001
+From eaa7bb6b3e47af84399c5bb3a421ac23a8c0b96d Mon Sep 17 00:00:00 2001
 From: MeiChia Chiu <meichia.chiu@mediatek.com>
 Date: Fri, 27 May 2022 15:51:48 +0800
 Subject: [PATCH 1007/1009] mt76: mt7915:add support for runtime set in-band
@@ -10,7 +10,7 @@
  1 file changed, 2 insertions(+), 3 deletions(-)
 
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 7984432..d36bcd0 100644
+index 79844323..d36bcd0a 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -2022,8 +2022,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
@@ -33,5 +33,5 @@
  	buf = (u8 *)tlv + sizeof(*discov);
  
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1008-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch b/recipes-kernel/linux-mt76/files/patches/1008-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch
index c205a87..0d6a14d 100644
--- a/recipes-kernel/linux-mt76/files/patches/1008-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1008-mt76-mt7915-add-mt76-vendor-muru-onoff-command.patch
@@ -1,4 +1,4 @@
-From 602c89b9ac8e7fec5ab466a28a4457c70da37b53 Mon Sep 17 00:00:00 2001
+From db5bbdab6a3a2e72c8309f06dff31115e51fd874 Mon Sep 17 00:00:00 2001
 From: MeiChia Chiu <meichia.chiu@mediatek.com>
 Date: Wed, 22 Jun 2022 10:53:43 +0800
 Subject: [PATCH 1008/1009] mt76: mt7915: add mt76 vendor muru onoff command
@@ -11,7 +11,7 @@
  4 files changed, 63 insertions(+)
 
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index d36bcd0..bcecc5e 100644
+index d36bcd0a..bcecc5e3 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -3670,6 +3670,13 @@ void mt7915_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
@@ -29,7 +29,7 @@
  }
  
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index c485064..0a77ad0 100644
+index c4850644..0a77ad0d 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -403,6 +403,7 @@ enum {
@@ -41,7 +41,7 @@
  };
  
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 7456c57..c755184 100644
+index 7456c577..c7551848 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -34,6 +34,11 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
@@ -109,7 +109,7 @@
  };
  
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 1b08321..a8e4ebf 100644
+index 1b08321c..a8e4ebf9 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -8,6 +8,7 @@ enum mtk_nl80211_vendor_subcmds {
@@ -139,5 +139,5 @@
  	MTK_VENDOR_ATTR_RFEATURE_CTRL_UNSPEC,
  
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1009-mt76-mt7915-add-fw_version-dump.patch b/recipes-kernel/linux-mt76/files/patches/1009-mt76-mt7915-add-fw_version-dump.patch
index fd99f23..89e3e3e 100644
--- a/recipes-kernel/linux-mt76/files/patches/1009-mt76-mt7915-add-fw_version-dump.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1009-mt76-mt7915-add-fw_version-dump.patch
@@ -1,4 +1,4 @@
-From 3240a8b38a26ca9293db89e3e5bf8f48f5434518 Mon Sep 17 00:00:00 2001
+From 3eaaa3c218dd75d14dea44f903e5d689ac9dd994 Mon Sep 17 00:00:00 2001
 From: Evelyn Tsai <evelyn.tsai@mediatek.com>
 Date: Wed, 17 Aug 2022 13:40:24 +0800
 Subject: [PATCH 1009/1009] mt76: mt7915: add fw_version dump
@@ -10,7 +10,7 @@
  3 files changed, 32 insertions(+)
 
 diff --git a/mt76.h b/mt76.h
-index aef6006..fac1dfb 100644
+index aef60066..fac1dfb7 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -823,6 +823,10 @@ struct mt76_dev {
@@ -25,7 +25,7 @@
  
  struct mt76_power_limits {
 diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index ed6c9eb..be2a2de 100644
+index ed6c9ebb..be2a2de1 100644
 --- a/mt76_connac_mcu.c
 +++ b/mt76_connac_mcu.c
 @@ -2889,6 +2889,9 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
@@ -59,7 +59,7 @@
  		struct mt76_connac2_patch_sec *sec;
  		u32 len, addr, mode;
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index e24b4d7..9de5b0f 100644
+index e24b4d78..9de5b0f6 100644
 --- a/mt7915/mtk_debugfs.c
 +++ b/mt7915/mtk_debugfs.c
 @@ -2721,6 +2721,22 @@ static int mt7915_agginfo_read_band1(struct seq_file *s, void *data)
@@ -96,5 +96,5 @@
  }
  #endif
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1111-mt76-testmode-additional-supports.patch b/recipes-kernel/linux-mt76/files/patches/1111-mt76-testmode-additional-supports.patch
index 0265815..25042b2 100644
--- a/recipes-kernel/linux-mt76/files/patches/1111-mt76-testmode-additional-supports.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1111-mt76-testmode-additional-supports.patch
@@ -1,7 +1,7 @@
-From 7846c2ea51d1b3f037688af0ea1bed306683daf0 Mon Sep 17 00:00:00 2001
+From ef88a8764755afe4db6617a640ee6edd3b47e86d Mon Sep 17 00:00:00 2001
 From: Shayne Chen <shayne.chen@mediatek.com>
 Date: Thu, 21 Apr 2022 15:43:19 +0800
-Subject: [PATCH 1111/1124] mt76: testmode: additional supports
+Subject: [PATCH 1111/1127] mt76: testmode: additional supports
 
 Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
 ---
@@ -27,7 +27,7 @@
  19 files changed, 1961 insertions(+), 146 deletions(-)
 
 diff --git a/dma.c b/dma.c
-index 40cb910..8ea09e6 100644
+index 4b181305..82b4da26 100644
 --- a/dma.c
 +++ b/dma.c
 @@ -426,8 +426,7 @@ free:
@@ -41,7 +41,7 @@
  #endif
  
 diff --git a/mac80211.c b/mac80211.c
-index 7ef853c..454f449 100644
+index 7ef853cb..454f449d 100644
 --- a/mac80211.c
 +++ b/mac80211.c
 @@ -55,6 +55,13 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = {
@@ -71,7 +71,7 @@
  
  static const struct ieee80211_channel mt76_channels_6ghz[] = {
 diff --git a/mt76.h b/mt76.h
-index fac1dfb..c4cdb4b 100644
+index fac1dfb7..c4cdb4ba 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -624,6 +624,21 @@ struct mt76_testmode_ops {
@@ -233,7 +233,7 @@
  static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable)
  {
 diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index be2a2de..01561a5 100644
+index be2a2de1..01561a56 100644
 --- a/mt76_connac_mcu.c
 +++ b/mt76_connac_mcu.c
 @@ -393,6 +393,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
@@ -255,7 +255,7 @@
  		return;
  
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 01035b2..a60965a 100644
+index 01035b28..a60965a2 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -975,6 +975,7 @@ enum {
@@ -275,7 +275,7 @@
  	MCU_EXT_CMD_CSI_CTRL = 0xc2,
  };
 diff --git a/mt7915/init.c b/mt7915/init.c
-index d83ba2b..6833bbf 100644
+index d83ba2bc..6833bbf5 100644
 --- a/mt7915/init.c
 +++ b/mt7915/init.c
 @@ -576,7 +576,7 @@ static void mt7915_init_work(struct work_struct *work)
@@ -288,10 +288,10 @@
  	mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
  	mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index cac296e..d798ec8 100644
+index e0210c3e..100ed7e1 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -565,16 +565,38 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
+@@ -567,16 +567,38 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
  {
  #ifdef CONFIG_NL80211_TESTMODE
  	struct mt76_testmode_data *td = &phy->mt76->test;
@@ -333,7 +333,7 @@
  
  	switch (td->tx_rate_mode) {
  	case MT76_TM_TX_MODE_HT:
-@@ -664,13 +686,14 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
+@@ -666,13 +688,14 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
  	if (mode >= MT_PHY_TYPE_HE_SU)
  		val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf);
  
@@ -352,7 +352,7 @@
  }
  
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 98dce0f..0a5a4b3 100644
+index 98dce0f4..0a5a4b36 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -224,7 +224,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
@@ -365,7 +365,7 @@
  		mvif->mt76.wmm_idx += 2;
  
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index bcecc5e..1b56635 100644
+index bcecc5e3..1b566351 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -434,6 +434,11 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
@@ -406,7 +406,7 @@
  
  	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 0a77ad0..ad85e56 100644
+index 0a77ad0d..ad85e56c 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -8,10 +8,15 @@
@@ -463,7 +463,7 @@
  
  enum {
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 2e73bd7..1eda361 100644
+index 2e73bd79..1eda361f 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
 @@ -85,6 +85,7 @@ static const u32 mt7915_offs[] = {
@@ -483,7 +483,7 @@
  	[AGG_PCR0]		= 0x040,
  	[AGG_ACR0]		= 0x054,
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 6868813..3bfec8f 100644
+index 6868813a..3bfec8fa 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -301,6 +301,9 @@ struct mt7915_phy {
@@ -529,7 +529,7 @@
  static inline u16 mt7915_wtbl_size(struct mt7915_dev *dev)
  {
 diff --git a/mt7915/regs.h b/mt7915/regs.h
-index 3f283a8..8fd2f69 100644
+index 3f283a83..8fd2f69a 100644
 --- a/mt7915/regs.h
 +++ b/mt7915/regs.h
 @@ -47,6 +47,7 @@ enum offs_rev {
@@ -550,7 +550,7 @@
  							  (_n) * 4))
  #define MT_AGG_PCR0(_band, _n)		MT_WF_AGG(_band, (__OFFS(AGG_PCR0) +	\
 diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index 8d99edc..8f250db 100644
+index 8d99edcb..8f250db1 100644
 --- a/mt7915/testmode.c
 +++ b/mt7915/testmode.c
 @@ -9,6 +9,9 @@
@@ -1881,7 +1881,7 @@
 +	.set_eeprom = mt7915_tm_set_eeprom,
  };
 diff --git a/mt7915/testmode.h b/mt7915/testmode.h
-index a1c54c8..01b08e9 100644
+index a1c54c89..01b08e9e 100644
 --- a/mt7915/testmode.h
 +++ b/mt7915/testmode.h
 @@ -4,6 +4,8 @@
@@ -2196,7 +2196,7 @@
 +
  #endif
 diff --git a/testmode.c b/testmode.c
-index 1d0d5d3..7a9ed54 100644
+index 1d0d5d30..7a9ed543 100644
 --- a/testmode.c
 +++ b/testmode.c
 @@ -27,28 +27,16 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
@@ -2663,7 +2663,7 @@
  		a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER);
  		if (!a)
 diff --git a/testmode.h b/testmode.h
-index 8961326..57949f2 100644
+index 89613266..57949f2b 100644
 --- a/testmode.h
 +++ b/testmode.h
 @@ -6,6 +6,8 @@
@@ -2768,7 +2768,7 @@
 +
  #endif
 diff --git a/tools/fields.c b/tools/fields.c
-index e3f6908..6e36ab2 100644
+index e3f69089..6e36ab27 100644
 --- a/tools/fields.c
 +++ b/tools/fields.c
 @@ -10,6 +10,7 @@ static const char * const testmode_state[] = {
@@ -2894,7 +2894,7 @@
  };
  
 diff --git a/tx.c b/tx.c
-index 65e2b7c..8b33186 100644
+index 65e2b7c1..8b33186b 100644
 --- a/tx.c
 +++ b/tx.c
 @@ -245,8 +245,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
@@ -2908,5 +2908,5 @@
  			wake_up(&dev->tx_wait);
  
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1112-mt76-testmode-add-pre-cal-support.patch b/recipes-kernel/linux-mt76/files/patches/1112-mt76-testmode-add-pre-cal-support.patch
index 9ccd494..1310b9b 100644
--- a/recipes-kernel/linux-mt76/files/patches/1112-mt76-testmode-add-pre-cal-support.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1112-mt76-testmode-add-pre-cal-support.patch
@@ -1,7 +1,7 @@
-From a87d889131d6a636ebae5e0a51c90ded201d7e6e Mon Sep 17 00:00:00 2001
+From 809cc2ea59de51435e0c33466ff2f6ab280ff043 Mon Sep 17 00:00:00 2001
 From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Date: Wed, 31 Aug 2022 20:06:52 +0800
-Subject: [PATCH 1112/1124] mt76: testmode: add pre-cal support
+Subject: [PATCH 1112/1127] mt76: testmode: add pre-cal support
 
 Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Change-Id: Ibfbbc3443de994eeb4daa5e364b0a90f5d7d3bcd
@@ -20,7 +20,7 @@
  11 files changed, 562 insertions(+), 13 deletions(-)
 
 diff --git a/eeprom.c b/eeprom.c
-index 25f6776..4c50bfe 100644
+index 25f67760..4c50bfe6 100644
 --- a/eeprom.c
 +++ b/eeprom.c
 @@ -89,8 +89,10 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
@@ -37,7 +37,7 @@
  
  out_put_node:
 diff --git a/mt76.h b/mt76.h
-index c4cdb4b..3ca449f 100644
+index c4cdb4ba..3ca449f7 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -625,6 +625,7 @@ struct mt76_testmode_ops {
@@ -49,7 +49,7 @@
  
  struct mt76_testmode_entry_data {
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index a60965a..b14f931 100644
+index a60965a2..b14f931b 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -971,6 +971,7 @@ enum {
@@ -61,7 +61,7 @@
  	MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13,
  	MCU_EXT_EVENT_THERMAL_PROTECT = 0x22,
 diff --git a/mt7915/eeprom.h b/mt7915/eeprom.h
-index f3e5681..88aaa16 100644
+index f3e56817..88aaa16a 100644
 --- a/mt7915/eeprom.h
 +++ b/mt7915/eeprom.h
 @@ -39,10 +39,18 @@ enum mt7915_eeprom_field {
@@ -114,7 +114,7 @@
  
  #endif
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 1b56635..34ce7d6 100644
+index 1b566351..34ce7d6f 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -438,6 +438,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
@@ -169,7 +169,7 @@
  
  	idx = mt7915_dpd_freq_idx(center_freq, chandef->width);
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 3bfec8f..f3bbdba 100644
+index 3bfec8fa..f3bbdbae 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -379,6 +379,10 @@ struct mt7915_dev {
@@ -192,7 +192,7 @@
  static inline u16 mt7915_wtbl_size(struct mt7915_dev *dev)
  {
 diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index 8f250db..b1ce299 100644
+index 8f250db1..b1ce2991 100644
 --- a/mt7915/testmode.c
 +++ b/mt7915/testmode.c
 @@ -5,6 +5,7 @@
@@ -666,7 +666,7 @@
 +	.dump_precal = mt7915_tm_dump_precal,
  };
 diff --git a/mt7915/testmode.h b/mt7915/testmode.h
-index 01b08e9..d500987 100644
+index 01b08e9e..d500987d 100644
 --- a/mt7915/testmode.h
 +++ b/mt7915/testmode.h
 @@ -81,6 +81,11 @@ struct tm_tx_cont {
@@ -734,7 +734,7 @@
  	TAM_ARB_OP_MODE_NORMAL = 1,
  	TAM_ARB_OP_MODE_TEST,
 diff --git a/testmode.c b/testmode.c
-index 7a9ed54..82b8e98 100644
+index 7a9ed543..82b8e983 100644
 --- a/testmode.c
 +++ b/testmode.c
 @@ -763,6 +763,18 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
@@ -767,7 +767,7 @@
  
  	if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) ||
 diff --git a/testmode.h b/testmode.h
-index 57949f2..e2190e7 100644
+index 57949f2b..e2190e72 100644
 --- a/testmode.h
 +++ b/testmode.h
 @@ -19,6 +19,7 @@
@@ -823,7 +823,7 @@
  
  	/* keep last */
 diff --git a/tools/fields.c b/tools/fields.c
-index 6e36ab2..1be1ffd 100644
+index 6e36ab27..1be1ffd6 100644
 --- a/tools/fields.c
 +++ b/tools/fields.c
 @@ -11,6 +11,14 @@ static const char * const testmode_state[] = {
@@ -842,5 +842,5 @@
  
  static const char * const testmode_tx_mode[] = {
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1113-mt76-testmode-add-iBF-command-mode-support.patch b/recipes-kernel/linux-mt76/files/patches/1113-mt76-testmode-add-iBF-command-mode-support.patch
index 49562c9..cfa19e2 100644
--- a/recipes-kernel/linux-mt76/files/patches/1113-mt76-testmode-add-iBF-command-mode-support.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1113-mt76-testmode-add-iBF-command-mode-support.patch
@@ -1,7 +1,7 @@
-From a5f91f701b6389e793b4c705ddd39631d18cdd80 Mon Sep 17 00:00:00 2001
+From 3c19e3a62e66bcbcc35989d5ddea6a6e38f406af Mon Sep 17 00:00:00 2001
 From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Date: Mon, 12 Sep 2022 18:16:54 +0800
-Subject: [PATCH 1113/1124] mt76: testmode: add iBF command mode support
+Subject: [PATCH 1113/1127] mt76: testmode: add iBF command mode support
 
 Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Change-Id: I7eea1d6412563f889e5774e787e58ce9eba001bd
@@ -13,7 +13,7 @@
  4 files changed, 85 insertions(+), 7 deletions(-)
 
 diff --git a/mt7915/testmode.c b/mt7915/testmode.c
-index b1ce299..f735ed6 100644
+index b1ce2991..f735ed69 100644
 --- a/mt7915/testmode.c
 +++ b/mt7915/testmode.c
 @@ -701,6 +701,7 @@ mt7915_tm_txbf_profile_update(struct mt7915_phy *phy, u16 *val, bool ebf)
@@ -105,7 +105,7 @@
  		mt7915_tm_set_tx_len(phy, tx_time);
  
 diff --git a/testmode.c b/testmode.c
-index 82b8e98..aa874a8 100644
+index 82b8e983..aa874a83 100644
 --- a/testmode.c
 +++ b/testmode.c
 @@ -530,6 +530,42 @@ out:
@@ -164,7 +164,7 @@
  		nla_for_each_nested(cur, tb[MT76_TM_ATTR_TXBF_PARAM], rem) {
  			if (nla_len(cur) != 2 ||
 diff --git a/testmode.h b/testmode.h
-index e2190e7..5d1fe79 100644
+index e2190e72..5d1fe793 100644
 --- a/testmode.h
 +++ b/testmode.h
 @@ -281,8 +281,10 @@ enum mt76_testmode_txbf_act {
@@ -179,7 +179,7 @@
  
  	/* keep last */
 diff --git a/tools/fields.c b/tools/fields.c
-index 1be1ffd..47fc69f 100644
+index 1be1ffd6..47fc69f9 100644
 --- a/tools/fields.c
 +++ b/tools/fields.c
 @@ -32,6 +32,20 @@ static const char * const testmode_tx_mode[] = {
@@ -239,5 +239,5 @@
  
  const struct tm_field msg_field = {
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1114-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch b/recipes-kernel/linux-mt76/files/patches/1114-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
index 94e28d2..06237df 100644
--- a/recipes-kernel/linux-mt76/files/patches/1114-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1114-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
@@ -1,14 +1,14 @@
-From ae8372c6fb4b5344218a8b724ed9caeea1bd4dcc Mon Sep 17 00:00:00 2001
+From 5031592059aaedc2b8d287b191d2d389d672761f Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Sun, 24 Apr 2022 10:07:00 +0800
-Subject: [PATCH 1114/1124] mt76: mt7915: init rssi in WTBL when add station
+Subject: [PATCH 1114/1127] mt76: mt7915: init rssi in WTBL when add station
 
 ---
  mt7915/main.c | 4 ++++
  1 file changed, 4 insertions(+)
 
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 0a5a4b3..fdbf1ee 100644
+index 0a5a4b36..fdbf1eea 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -666,6 +666,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -30,5 +30,5 @@
  	mt7915_vendor_amnt_sta_remove(mvif->phy, sta);
  #endif
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1115-mt76-mt7915-reduce-TWT-SP-sent-to-FW-for-cert.patch b/recipes-kernel/linux-mt76/files/patches/1115-mt76-mt7915-reduce-TWT-SP-sent-to-FW-for-cert.patch
index f808c1e..38827b4 100644
--- a/recipes-kernel/linux-mt76/files/patches/1115-mt76-mt7915-reduce-TWT-SP-sent-to-FW-for-cert.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1115-mt76-mt7915-reduce-TWT-SP-sent-to-FW-for-cert.patch
@@ -1,7 +1,7 @@
-From 1a023afd7dd2ff4820f056de4d60ac019b1f72e7 Mon Sep 17 00:00:00 2001
+From 271c0cad1bc8013bc30a9be9fc24879739d7a87d Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Thu, 4 Aug 2022 14:08:11 +0800
-Subject: [PATCH 1115/1124] mt76: mt7915: reduce TWT SP sent to FW for cert
+Subject: [PATCH 1115/1127] mt76: mt7915: reduce TWT SP sent to FW for cert
 
 Set TWT SP duration to 88 percent to prevent HW sends PPDU over TWT SP.
 
@@ -11,7 +11,7 @@
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 34ce7d6..b6733b1 100644
+index 34ce7d6f..b6733b1c 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -3558,7 +3558,7 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
@@ -24,5 +24,5 @@
  		.start_tsf = cpu_to_le64(flow->tsf),
  		.mantissa = flow->mantissa,
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1116-mt76-airtime-fairness-feature-off-in-mac80211.patch b/recipes-kernel/linux-mt76/files/patches/1116-mt76-airtime-fairness-feature-off-in-mac80211.patch
index 25a32e0..82ebd57 100644
--- a/recipes-kernel/linux-mt76/files/patches/1116-mt76-airtime-fairness-feature-off-in-mac80211.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1116-mt76-airtime-fairness-feature-off-in-mac80211.patch
@@ -1,14 +1,14 @@
-From eb09887134c11a820556064ad6d18c21e06fc6ab Mon Sep 17 00:00:00 2001
+From b5812eb715903b1ee0e0c74e30871444e0fef807 Mon Sep 17 00:00:00 2001
 From: Evelyn Tsai <evelyn.tsai@mediatek.com>
 Date: Fri, 6 May 2022 15:58:42 +0800
-Subject: [PATCH 1116/1124] mt76: airtime fairness feature off in mac80211
+Subject: [PATCH 1116/1127] mt76: airtime fairness feature off in mac80211
 
 ---
  mac80211.c | 1 -
  1 file changed, 1 deletion(-)
 
 diff --git a/mac80211.c b/mac80211.c
-index 454f449..b7c1b13 100644
+index 454f449d..b7c1b13b 100644
 --- a/mac80211.c
 +++ b/mac80211.c
 @@ -429,7 +429,6 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
@@ -20,5 +20,5 @@
  
  	wiphy->available_antennas_tx = phy->antenna_mask;
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1117-mt76-mt7915-add-mt7986-and-mt7916-pre-calibration.patch b/recipes-kernel/linux-mt76/files/patches/1117-mt76-mt7915-add-mt7986-and-mt7916-pre-calibration.patch
index 7598dc0..0f09ca0 100644
--- a/recipes-kernel/linux-mt76/files/patches/1117-mt76-mt7915-add-mt7986-and-mt7916-pre-calibration.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1117-mt76-mt7915-add-mt7986-and-mt7916-pre-calibration.patch
@@ -1,7 +1,7 @@
-From 63804504dd96a01005b6a2b828bcfe76c42d6b2a Mon Sep 17 00:00:00 2001
+From 87a9bde534000908f7154499a808575d77d66da9 Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Fri, 20 May 2022 19:19:25 +0800
-Subject: [PATCH 1117/1124] mt76: mt7915: add mt7986 and mt7916 pre-calibration
+Subject: [PATCH 1117/1127] mt76: mt7915: add mt7986 and mt7916 pre-calibration
 
 Add pre-calibration for mt7986 and mt7916. It has different data size
 with mt7915. Group cal needs 54k and 94k for 2G + 5G and 2G + 6G,
@@ -15,7 +15,7 @@
  3 files changed, 62 insertions(+), 26 deletions(-)
 
 diff --git a/mt7915/eeprom.c b/mt7915/eeprom.c
-index e2482c6..d58a320 100644
+index e2482c65..d58a3201 100644
 --- a/mt7915/eeprom.c
 +++ b/mt7915/eeprom.c
 @@ -9,23 +9,22 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
@@ -50,7 +50,7 @@
  
  static int mt7915_check_eeprom(struct mt7915_dev *dev)
 diff --git a/mt7915/eeprom.h b/mt7915/eeprom.h
-index 88aaa16..fdae347 100644
+index 88aaa16a..fdae347e 100644
 --- a/mt7915/eeprom.h
 +++ b/mt7915/eeprom.h
 @@ -19,6 +19,7 @@ enum mt7915_eeprom_field {
@@ -62,7 +62,7 @@
  	MT_EE_RATE_DELTA_5G =	0x29d,
  	MT_EE_TX0_POWER_2G =	0x2fc,
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index b6733b1..69a266f 100644
+index b6733b1c..69a266f6 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -2928,7 +2928,8 @@ static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
@@ -198,5 +198,5 @@
  
  	return 0;
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1118-mt76-mt7915-add-phy-capability-vendor-command.patch b/recipes-kernel/linux-mt76/files/patches/1118-mt76-mt7915-add-phy-capability-vendor-command.patch
index 53c6a9b..9b489c4 100644
--- a/recipes-kernel/linux-mt76/files/patches/1118-mt76-mt7915-add-phy-capability-vendor-command.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1118-mt76-mt7915-add-phy-capability-vendor-command.patch
@@ -1,7 +1,7 @@
-From 6debaa3030b494e9a0179ad5acacf046f037858a Mon Sep 17 00:00:00 2001
+From 96e6ea270e50b2d2c76998e8f3486c97dae66bb6 Mon Sep 17 00:00:00 2001
 From: Yi-Chia Hsieh <Yi-Chia.Hsieh@mediatek.com>
 Date: Tue, 12 Jul 2022 10:04:35 -0700
-Subject: [PATCH 1118/1124] mt76: mt7915: add phy capability vendor command
+Subject: [PATCH 1118/1127] mt76: mt7915: add phy capability vendor command
 
 ---
  mt7915/mt7915.h |  1 +
@@ -10,7 +10,7 @@
  3 files changed, 78 insertions(+)
 
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index f3bbdba..bd20e7c 100644
+index f3bbdbae..bd20e7c7 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -11,6 +11,7 @@
@@ -22,7 +22,7 @@
  #define MT7916_WTBL_SIZE		544
  #define MT7915_WTBL_RESERVED		(mt7915_wtbl_size(dev) - 1)
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index c755184..77d71e4 100644
+index c7551848..77d71e48 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -50,6 +50,18 @@ rfeature_ctrl_policy[NUM_MTK_VENDOR_ATTRS_RFEATURE_CTRL] = {
@@ -99,7 +99,7 @@
  };
  
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index a8e4ebf..719b851 100644
+index a8e4ebf9..719b851f 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -9,6 +9,7 @@ enum mtk_nl80211_vendor_subcmds {
@@ -140,5 +140,5 @@
 +
  #endif
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1119-mt76-mt7915-add-vendor-subcmd-EDCCA-ctrl.patch b/recipes-kernel/linux-mt76/files/patches/1119-mt76-mt7915-add-vendor-subcmd-EDCCA-ctrl.patch
index 7eb811e..8fd3f28 100644
--- a/recipes-kernel/linux-mt76/files/patches/1119-mt76-mt7915-add-vendor-subcmd-EDCCA-ctrl.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1119-mt76-mt7915-add-vendor-subcmd-EDCCA-ctrl.patch
@@ -1,7 +1,7 @@
-From ef7f1097ad31dc69e3e5d0893ef5713f6af98a44 Mon Sep 17 00:00:00 2001
+From d219c48c59fdf1ec69bd08d3c1fef708c3ab9300 Mon Sep 17 00:00:00 2001
 From: Howard Hsu <howard-yh.hsu@mediatek.com>
 Date: Fri, 24 Jun 2022 11:15:45 +0800
-Subject: [PATCH 1119/1124] mt76: mt7915: add vendor subcmd EDCCA ctrl
+Subject: [PATCH 1119/1127] mt76: mt7915: add vendor subcmd EDCCA ctrl
 
 Change-Id: I92dabf8be9c5a7ecec78f35325bc5645af8d15ab
 ---
@@ -15,7 +15,7 @@
  7 files changed, 138 insertions(+)
 
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index b14f931..6143d8e 100644
+index b14f931b..6143d8e4 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -1157,6 +1157,7 @@ enum {
@@ -27,7 +27,7 @@
  };
  
 diff --git a/mt7915/main.c b/mt7915/main.c
-index fdbf1ee..80f4d9d 100644
+index fdbf1eea..80f4d9dd 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -456,6 +456,9 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
@@ -41,7 +41,7 @@
  		ret = mt7915_set_channel(phy);
  		if (ret)
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 69a266f..8dcc54e 100644
+index 69a266f6..8dcc54eb 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -4272,3 +4272,41 @@ int mt7915_mcu_set_amsdu_algo(struct mt7915_dev *dev, u16 wcid, u8 enable)
@@ -87,7 +87,7 @@
 +	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCCA), &req, sizeof(req), true);
 +}
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index ad85e56..b8a433e 100644
+index ad85e56c..b8a433e5 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -789,4 +789,16 @@ enum {
@@ -108,7 +108,7 @@
 +};
  #endif
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index bd20e7c..1b08686 100644
+index bd20e7c7..1b08686e 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -725,6 +725,8 @@ void mt7915_vendor_amnt_fill_rx(struct mt7915_phy *phy, struct sk_buff *skb);
@@ -121,7 +121,7 @@
  #ifdef MTK_DEBUG
  int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir);
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 77d71e4..5a28a55 100644
+index 77d71e48..5a28a554 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -62,6 +62,17 @@ phy_capa_dump_policy[NUM_MTK_VENDOR_ATTRS_PHY_CAPA_DUMP] = {
@@ -209,7 +209,7 @@
  };
  
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 719b851..83c41bc 100644
+index 719b851f..83c41bc1 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -10,8 +10,27 @@ enum mtk_nl80211_vendor_subcmds {
@@ -241,5 +241,5 @@
  	CAPI_RFEATURE_CHANGED		= BIT(16),
  	CAPI_WIRELESS_CHANGED		= BIT(17),
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1120-mt76-mt7915-implement-bin-file-mode.patch b/recipes-kernel/linux-mt76/files/patches/1120-mt76-mt7915-implement-bin-file-mode.patch
index 73a117a..da1bb74 100644
--- a/recipes-kernel/linux-mt76/files/patches/1120-mt76-mt7915-implement-bin-file-mode.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1120-mt76-mt7915-implement-bin-file-mode.patch
@@ -1,7 +1,7 @@
-From 09763f3753bb13ed2d754440295a459f6bb743c3 Mon Sep 17 00:00:00 2001
+From 6ed6cb4cf561159bcd935f48000abce3652fb682 Mon Sep 17 00:00:00 2001
 From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Date: Thu, 7 Jul 2022 11:09:59 +0800
-Subject: [PATCH 1120/1124] mt76: mt7915: implement bin file mode
+Subject: [PATCH 1120/1127] mt76: mt7915: implement bin file mode
 
 Change-Id: I2a726341541a11cbecdb210b33a8e79aefbd6cf3
 Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -13,7 +13,7 @@
  4 files changed, 71 insertions(+), 11 deletions(-)
 
 diff --git a/eeprom.c b/eeprom.c
-index 4c50bfe..baca86f 100644
+index 4c50bfe6..baca86fd 100644
 --- a/eeprom.c
 +++ b/eeprom.c
 @@ -104,6 +104,24 @@ out_put_node:
@@ -42,7 +42,7 @@
  mt76_eeprom_override(struct mt76_phy *phy)
  {
 diff --git a/mt76.h b/mt76.h
-index 3ca449f..e547f79 100644
+index 3ca449f7..e547f79e 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -1001,6 +1001,7 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
@@ -54,7 +54,7 @@
  struct mt76_queue *
  mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
 diff --git a/mt7915/eeprom.c b/mt7915/eeprom.c
-index d58a320..632ecc7 100644
+index d58a3201..632ecc7b 100644
 --- a/mt7915/eeprom.c
 +++ b/mt7915/eeprom.c
 @@ -46,26 +46,36 @@ static char *mt7915_eeprom_name(struct mt7915_dev *dev)
@@ -148,7 +148,7 @@
  		if (ret)
  			return ret;
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 1b08686..5fa1dfa 100644
+index 1b08686e..5fa1dfac 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -51,6 +51,15 @@
@@ -176,5 +176,5 @@
  	bool ibf;
  
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1121-mt76-mt7915-initialize-wcid.patch b/recipes-kernel/linux-mt76/files/patches/1121-mt76-mt7915-initialize-wcid.patch
index f5ed0a0..49f0d06 100644
--- a/recipes-kernel/linux-mt76/files/patches/1121-mt76-mt7915-initialize-wcid.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1121-mt76-mt7915-initialize-wcid.patch
@@ -1,7 +1,7 @@
-From bf5186ab642f733c312f6971d93934af4ec0f406 Mon Sep 17 00:00:00 2001
+From 5f1203708a71e815d3d3f40ca18005d1667453cb Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Tue, 12 Jul 2022 13:56:07 +0800
-Subject: [PATCH 1121/1124] mt76 mt7915 initialize wcid
+Subject: [PATCH 1121/1127] mt76 mt7915 initialize wcid
 
 Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
 ---
@@ -9,10 +9,10 @@
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index d798ec8..961b7af 100644
+index 100ed7e1..27f9419a 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -967,7 +967,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
+@@ -969,7 +969,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
  		info = le32_to_cpu(*cur_info);
  		if (info & MT_TX_FREE_PAIR) {
  			struct mt7915_sta *msta;
@@ -22,5 +22,5 @@
  
  			idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1122-mt76-HEMU-Add-dump-support.patch b/recipes-kernel/linux-mt76/files/patches/1122-mt76-HEMU-Add-dump-support.patch
index 286936e..2c124c2 100644
--- a/recipes-kernel/linux-mt76/files/patches/1122-mt76-HEMU-Add-dump-support.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1122-mt76-HEMU-Add-dump-support.patch
@@ -1,7 +1,7 @@
-From a56e9413d6604dcec4fe5c21f240ad8d3e82eb7b Mon Sep 17 00:00:00 2001
+From e3d3c941dcf1d99d78e57d72989cf2f98f9f5b6b Mon Sep 17 00:00:00 2001
 From: TomLiu <tomml.liu@mediatek.com>
 Date: Thu, 11 Aug 2022 18:09:45 -0700
-Subject: [PATCH 1122/1124] mt76: HEMU: Add dump support
+Subject: [PATCH 1122/1127] mt76: HEMU: Add dump support
 
 Change-Id: I521214f3feb6f0d528a9f550255050ffd1ec96d2
 ---
@@ -10,7 +10,7 @@
  2 files changed, 27 insertions(+)
 
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 5a28a55..7acb330 100644
+index 5a28a554..7acb3304 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -37,6 +37,7 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
@@ -61,7 +61,7 @@
  		.maxattr = MTK_VENDOR_ATTR_HEMU_CTRL_MAX,
  	},
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 83c41bc..57f52f3 100644
+index 83c41bc1..57f52f3a 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -58,6 +58,7 @@ enum mtk_vendor_attr_hemu_ctrl {
@@ -73,5 +73,5 @@
  	/* keep last */
  	NUM_MTK_VENDOR_ATTRS_HEMU_CTRL,
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1123-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch b/recipes-kernel/linux-mt76/files/patches/1123-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch
index c5814bd..74c02b6 100644
--- a/recipes-kernel/linux-mt76/files/patches/1123-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1123-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch
@@ -1,22 +1,22 @@
-From c2a099c2d4c02f67232cf98ee7d4e4b241b6befc Mon Sep 17 00:00:00 2001
+From 513897014f6bafe1f38bcfa48d0bb43ed30d4d82 Mon Sep 17 00:00:00 2001
 From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Date: Tue, 30 Aug 2022 15:29:38 +0800
-Subject: [PATCH 1123/1124] mt76: mt7915: add vendor subcmd three wire (PTA)
+Subject: [PATCH 1123/1127] mt76: mt7915: add vendor subcmd three wire (PTA)
  ctrl
 
 Change-Id: Ie092d63af9a1e06bef36fc5a5bac40fdab73dba5
 Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 ---
  mt76_connac_mcu.h |  2 +-
- mt7915/mcu.c      | 51 ++++++++++++++++++++++-------------------------
+ mt7915/mcu.c      | 50 ++++++++++++++++++++++-------------------------
  mt7915/mcu.h      | 29 +++++++++++++++++++++++++++
  mt7915/mt7915.h   |  1 +
- mt7915/vendor.c   | 42 +++++++++++++++++++++++++++++++++++++-
- mt7915/vendor.h   | 12 +++++++++++
- 6 files changed, 108 insertions(+), 29 deletions(-)
+ mt7915/vendor.c   | 42 ++++++++++++++++++++++++++++++++++++++-
+ mt7915/vendor.h   | 12 ++++++++++++
+ 6 files changed, 107 insertions(+), 29 deletions(-)
 
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 6143d8e..27a3624 100644
+index 6143d8e4..27a36241 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -1156,7 +1156,7 @@ enum {
@@ -29,10 +29,10 @@
  	MCU_EXT_CMD_CSI_CTRL = 0xc2,
  };
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 8dcc54e..477a41c 100644
+index 8dcc54eb..d67495c4 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
-@@ -4019,37 +4019,34 @@ void mt7915_mcu_set_dynalgo(struct mt7915_phy *phy, u8 enable)
+@@ -4019,37 +4019,33 @@ void mt7915_mcu_set_dynalgo(struct mt7915_phy *phy, u8 enable)
  			&req, sizeof(req), false);
  }
  
@@ -68,7 +68,6 @@
 +		.dbdc_idx = phy != &dev->phy,
 +		.tlv_num = cpu_to_le32(1),
  	};
-+	struct sk_buff *skb;
 +	int tlv_len;
 +
 +	switch (cfg_info) {
@@ -95,7 +94,7 @@
  
  void mt7915_mcu_set_bypass_smthint(struct mt7915_phy *phy, u8 val)
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index b8a433e..9d0fac4 100644
+index b8a433e5..9d0fac47 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -576,6 +576,35 @@ struct csi_data {
@@ -135,7 +134,7 @@
  #define OFDMA_DL                       BIT(0)
  #define OFDMA_UL                       BIT(1)
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 5fa1dfa..f403820 100644
+index 5fa1dfac..f4038207 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -727,6 +727,7 @@ void mt7915_mcu_set_mimo(struct mt7915_phy *phy, u8 direction);
@@ -147,7 +146,7 @@
  void mt7915_vendor_register(struct mt7915_phy *phy);
  int mt7915_mcu_set_csi(struct mt7915_phy *phy, u8 mode,
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 7acb330..7f67c0d 100644
+index 7acb3304..7f67c0d3 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -40,6 +40,11 @@ hemu_ctrl_policy[NUM_MTK_VENDOR_ATTRS_HEMU_CTRL] = {
@@ -221,7 +220,7 @@
  };
  
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 57f52f3..e0c5fd9 100644
+index 57f52f3a..e0c5fd94 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -11,6 +11,7 @@ enum mtk_nl80211_vendor_subcmds {
@@ -251,5 +250,5 @@
  enum mtk_capi_control_changed {
  	CAPI_RFEATURE_CHANGED		= BIT(16),
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1124-mt76-add-ibf-control-vendor-cmd.patch b/recipes-kernel/linux-mt76/files/patches/1124-mt76-add-ibf-control-vendor-cmd.patch
index 3532752..1bb1bcc 100644
--- a/recipes-kernel/linux-mt76/files/patches/1124-mt76-add-ibf-control-vendor-cmd.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1124-mt76-add-ibf-control-vendor-cmd.patch
@@ -1,7 +1,7 @@
-From 5c25234839bdbe57851bc0ea0d7946fac8458af3 Mon Sep 17 00:00:00 2001
+From 8bf75c1a4afd5a2f0abd5ccda8a174b80b0fbd07 Mon Sep 17 00:00:00 2001
 From: mtk27835 <shurong.wen@mediatek.com>
 Date: Wed, 7 Sep 2022 14:01:29 -0700
-Subject: [PATCH 1124/1124] mt76: add ibf control vendor cmd
+Subject: [PATCH 1124/1127] mt76: add ibf control vendor cmd
 
 Signed-off-by: mtk27835 <shurong.wen@mediatek.com>
 ---
@@ -10,7 +10,7 @@
  2 files changed, 94 insertions(+), 1 deletion(-)
 
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index 7f67c0d..cbbb084 100644
+index 7f67c0d3..cbbb0843 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -78,6 +78,16 @@ edcca_ctrl_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL] = {
@@ -105,7 +105,7 @@
  };
  
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index e0c5fd9..5aac559 100644
+index e0c5fd94..5aac5595 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -11,7 +11,8 @@ enum mtk_nl80211_vendor_subcmds {
@@ -146,5 +146,5 @@
 +
  #endif
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1125-mt76-add-ampdu-amsdu-control.patch b/recipes-kernel/linux-mt76/files/patches/1125-mt76-mt7915-add-AMPDU-AMSDU-OnOff-ctonrol.patch
similarity index 91%
rename from recipes-kernel/linux-mt76/files/patches/1125-mt76-add-ampdu-amsdu-control.patch
rename to recipes-kernel/linux-mt76/files/patches/1125-mt76-mt7915-add-AMPDU-AMSDU-OnOff-ctonrol.patch
index 15e938d..ad78deb 100644
--- a/recipes-kernel/linux-mt76/files/patches/1125-mt76-add-ampdu-amsdu-control.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1125-mt76-mt7915-add-AMPDU-AMSDU-OnOff-ctonrol.patch
@@ -1,8 +1,9 @@
-From f15366ef845f70c3557e6ebcc4c72ee154e7cfc1 Mon Sep 17 00:00:00 2001
+From 73ed020063abbe785ad02d2fdab8dc6fdcec07a3 Mon Sep 17 00:00:00 2001
 From: TomLiu <tomml.liu@mediatek.com>
 Date: Wed, 21 Sep 2022 13:55:15 -0700
-Subject: [PATCH][MAC80211][mt76][add AMPDU/AMSDU OnOff ctonrol]
+Subject: [PATCH 1125/1127] mt76: mt7915: add AMPDU/AMSDU OnOff ctonrol
 
+Change-Id: I6030b3a420e96b02e83b0c7a3c3626a3b23c97e3
 ---
  mt7915/mac.c    | 28 ++++++++++++++++++++++++++++
  mt7915/mt7915.h |  2 ++
@@ -11,10 +12,10 @@
  4 files changed, 83 insertions(+)
 
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 516717c..6ad32b1 100644
+index 27f9419a..3896c3d5 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -2064,6 +2064,34 @@ static void mt7915_mac_severe_check(struct mt7915_phy *phy)
+@@ -1939,6 +1939,34 @@ static void mt7915_mac_severe_check(struct mt7915_phy *phy)
  	phy->trb_ts = trb;
  }
  
@@ -50,11 +51,11 @@
  void mt7915_capi_sta_rc_work(void *data, struct ieee80211_sta *sta)
  {
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 3029315..bac7fcb 100644
+index f4038207..d5e0c3e9 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
-@@ -726,6 +726,8 @@ void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- #endif
+@@ -715,6 +715,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
+ 			 bool pci, int *irq);
  
  #ifdef CONFIG_MTK_VENDOR
 +void mt7915_set_wireless_ampdu(struct ieee80211_hw *hw, u8 en);
@@ -63,7 +64,7 @@
  void mt7915_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
  void mt7915_mcu_set_rfeature_starec(void *data, struct mt7915_dev *dev,
 diff --git a/mt7915/vendor.c b/mt7915/vendor.c
-index cbbb084..d73fdd4 100644
+index cbbb0843..d73fdd4c 100644
 --- a/mt7915/vendor.c
 +++ b/mt7915/vendor.c
 @@ -30,10 +30,18 @@ wireless_ctrl_policy[NUM_MTK_VENDOR_ATTRS_WIRELESS_CTRL] = {
@@ -136,7 +137,7 @@
  		.maxattr = MTK_VENDOR_ATTR_WIRELESS_CTRL_MAX,
  	},
 diff --git a/mt7915/vendor.h b/mt7915/vendor.h
-index 5aac559..53abb10 100644
+index 5aac5595..53abb100 100644
 --- a/mt7915/vendor.h
 +++ b/mt7915/vendor.h
 @@ -58,6 +58,8 @@ enum mtk_vendor_attr_wireless_ctrl {
@@ -168,5 +169,5 @@
  	MTK_VENDOR_ATTR_HEMU_CTRL_UNSPEC,
  
 -- 
-2.32.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1126-mt76-mt7915-add-E3-re-bonding-for-low-yield-rate-iss.patch b/recipes-kernel/linux-mt76/files/patches/1126-mt76-mt7915-add-E3-re-bonding-for-low-yield-rate-iss.patch
new file mode 100644
index 0000000..9d5aeaa
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/1126-mt76-mt7915-add-E3-re-bonding-for-low-yield-rate-iss.patch
@@ -0,0 +1,120 @@
+From 6a0356a60feb88001aa785b3ae6fe9a26fe9e25e Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Thu, 13 Oct 2022 13:22:05 +0800
+Subject: [PATCH 1126/1127] mt76: mt7915: add E3 re-bonding for low yield rate
+ issue
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ mt7915/eeprom.c | 27 ++++++++++++++++++++++++++-
+ mt7915/mcu.c    | 13 ++++++++++---
+ mt7915/mt7915.h |  3 ++-
+ 3 files changed, 38 insertions(+), 5 deletions(-)
+
+diff --git a/mt7915/eeprom.c b/mt7915/eeprom.c
+index 632ecc7b..34a4a624 100644
+--- a/mt7915/eeprom.c
++++ b/mt7915/eeprom.c
+@@ -133,7 +133,7 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
+ 					 MT7915_EEPROM_BLOCK_SIZE);
+ 		for (i = 0; i < block_num; i++)
+ 			mt7915_mcu_get_eeprom(dev,
+-					      i * MT7915_EEPROM_BLOCK_SIZE);
++					      i * MT7915_EEPROM_BLOCK_SIZE, NULL);
+ 	}
+ 
+ 	return mt7915_check_eeprom(dev);
+@@ -230,6 +230,29 @@ void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev,
+ 	dev->chainshift = hweight8(dev->mphy.chainmask);
+ }
+ 
++void mt7915_eeprom_rebonding(struct mt7915_dev *dev)
++{
++#define MT7976_ADIE_MASK			BIT(1)
++#define MT7986_ADIE1_EFFUSE_OFFSET		0x1000
++#define MT7986_ADIE1_MT7976C_OFFSET		0x270
++#define MT7986_ADIE1_E3_OFFSET			0x271
++	u32 adie_offset, sku = mt7915_check_adie(dev, true);
++	u8 read_buf, *eeprom = dev->mt76.eeprom.data;
++
++	if (!(sku & MT7976_ADIE_MASK))
++		return;
++
++	adie_offset = (sku == MT7976_DUAL_ADIE) ? MT7986_ADIE1_EFFUSE_OFFSET : 0;
++
++	/* 7976 A-Die, To identify MT7976C */
++	mt7915_mcu_get_eeprom(dev, MT7986_ADIE1_MT7976C_OFFSET + adie_offset, &read_buf);
++	eeprom[MT7986_ADIE1_MT7976C_OFFSET] = read_buf;
++
++	/* E3 re-binding */
++	mt7915_mcu_get_eeprom(dev, MT7986_ADIE1_E3_OFFSET + adie_offset, &read_buf);
++	eeprom[MT7986_ADIE1_E3_OFFSET] = read_buf;
++}
++
+ int mt7915_eeprom_init(struct mt7915_dev *dev)
+ {
+ 	int ret;
+@@ -263,6 +286,8 @@ int mt7915_eeprom_init(struct mt7915_dev *dev)
+ 			return ret;
+ 	}
+ 
++	mt7915_eeprom_rebonding(dev);
++
+ 	ret = mt7915_eeprom_load_precal(dev);
+ 	if (ret)
+ 		return ret;
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index d67495c4..4438e748 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -2849,7 +2849,7 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev, bool flash_mode)
+ 				 &req, sizeof(req), true);
+ }
+ 
+-int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
++int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 *read_buf)
+ {
+ 	struct mt7915_mcu_eeprom_info req = {
+ 		.addr = cpu_to_le32(round_down(offset,
+@@ -2866,8 +2866,15 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
+ 		return ret;
+ 
+ 	res = (struct mt7915_mcu_eeprom_info *)skb->data;
+-	buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
+-	memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE);
++
++	if (read_buf) {
++		u32 offs = offset % MT7915_EEPROM_BLOCK_SIZE;
++		*read_buf = res->data[offs];
++	} else {
++		buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
++		memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE);
++	}
++
+ 	dev_kfree_skb(skb);
+ 
+ 	return 0;
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index d5e0c3e9..b5784d92 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -543,6 +543,7 @@ u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
+ 
+ int mt7915_register_device(struct mt7915_dev *dev);
+ void mt7915_unregister_device(struct mt7915_dev *dev);
++void mt7915_eeprom_rebonding(struct mt7915_dev *dev);
+ int mt7915_eeprom_init(struct mt7915_dev *dev);
+ void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev,
+ 				struct mt7915_phy *phy);
+@@ -597,7 +598,7 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
+ 				   struct ieee80211_sta *sta,
+ 				   void *data, u32 field);
+ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev, bool flash_mode);
+-int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset);
++int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 *read_buf);
+ int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num);
+ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
+ 		       bool hdr_trans);
+-- 
+2.25.1
+
diff --git a/recipes-kernel/linux-mt76/files/patches/1127-mt76-support-on-off-SW-ACI-through-debugfs.patch b/recipes-kernel/linux-mt76/files/patches/1127-mt76-support-on-off-SW-ACI-through-debugfs.patch
new file mode 100644
index 0000000..8ec0a45
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/1127-mt76-support-on-off-SW-ACI-through-debugfs.patch
@@ -0,0 +1,66 @@
+From eb6849812919d13e38cb8253632e96edec6a582a Mon Sep 17 00:00:00 2001
+From: Evelyn Tsai <evelyn.tsai@mediatek.com>
+Date: Fri, 14 Oct 2022 11:15:13 +0800
+Subject: [PATCH 1127/1127] mt76: support on off SW ACI through debugfs
+
+Signed-off-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
+Change-Id: I8a9c277c41d1ba76f9737d8af6f42e5e8f00ba64
+---
+ mt76_connac_mcu.h    |  1 +
+ mt7915/mtk_debugfs.c | 21 +++++++++++++++++++++
+ 2 files changed, 22 insertions(+)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 27a36241..c7e28e3e 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1158,6 +1158,7 @@ enum {
+ 	MCU_EXT_CMD_RX_STAT_USER_CTRL = 0xb3,
+ 	MCU_EXT_CMD_SET_CFG = 0xb7,
+ 	MCU_EXT_CMD_EDCCA = 0xba,
++	MCU_EXT_CMD_SWLNA_ACI_CTRL = 0xc0,
+ 	MCU_EXT_CMD_CSI_CTRL = 0xc2,
+ };
+ 
+diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
+index 9de5b0f6..c5e04728 100644
+--- a/mt7915/mtk_debugfs.c
++++ b/mt7915/mtk_debugfs.c
+@@ -2893,6 +2893,25 @@ mt7915_wa_debug(void *data, u64 val)
+ DEFINE_DEBUGFS_ATTRIBUTE(fops_wa_debug, NULL, mt7915_wa_debug,
+ 			 "0x%llx\n");
+ 
++static int
++mt7915_sw_aci_set(void *data, u64 val)
++{
++#define SWLNA_ENABLE 6
++	struct mt7915_dev *dev = data;
++	struct {
++		u32 subcmd;
++		u8 enable;
++	} req = {
++		.subcmd = SWLNA_ENABLE,
++		.enable = (u8) val,
++	};
++	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SWLNA_ACI_CTRL), &req, sizeof(req), NULL);
++}
++
++
++DEFINE_DEBUGFS_ATTRIBUTE(fops_sw_aci, NULL,
++			 mt7915_sw_aci_set, "%llx\n");
++
+ int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir)
+ {
+ 	struct mt7915_dev *dev = phy->dev;
+@@ -2973,6 +2992,8 @@ int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir)
+ 	debugfs_create_devm_seqfile(dev->mt76.dev, "fw_version", dir,
+ 				    mt7915_dump_version);
+ 
++	debugfs_create_file("sw_aci", 0600, dir, dev,
++			    &fops_sw_aci);
+ 	return 0;
+ }
+ #endif
+-- 
+2.25.1
+
diff --git a/recipes-kernel/linux-mt76/files/patches/3001-mt76-add-wed-tx-support.patch b/recipes-kernel/linux-mt76/files/patches/3001-mt76-add-wed-tx-support.patch
index 9339794..038f10c 100644
--- a/recipes-kernel/linux-mt76/files/patches/3001-mt76-add-wed-tx-support.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3001-mt76-add-wed-tx-support.patch
@@ -1,7 +1,7 @@
-From 76d6af5ef0539cfa09fadf9e7dd60c015428d12d Mon Sep 17 00:00:00 2001
+From a96024fdb9633ad7a309bc13800cf730fd00f7dc Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Sun, 12 Jun 2022 16:38:45 +0800
-Subject: [PATCH] mt76 add wed tx support
+Subject: [PATCH 3001/3011] mt76 add wed tx support
 
 Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
 ---
@@ -24,7 +24,7 @@
  struct mt76_connac_fw_txp {
  	__le16 flags;
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 961b7afc..65e47f95 100644
+index 3896c3d5..98925ed5 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
 @@ -828,9 +828,9 @@ u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
@@ -86,7 +86,7 @@
  
  	ctx->dev = NULL;
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 1eda361f..0b37f1b3 100644
+index 1eda361f..5819281c 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
 @@ -10,7 +10,7 @@
@@ -148,5 +148,5 @@
  	ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32));
  	if (ret)
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3002-mt76-mt7915-add-wed-tx-wds-support-on-mt7986.patch b/recipes-kernel/linux-mt76/files/patches/3002-mt76-mt7915-add-wed-tx-wds-support-on-mt7986.patch
index 8addd3c..fd4d484 100644
--- a/recipes-kernel/linux-mt76/files/patches/3002-mt76-mt7915-add-wed-tx-wds-support-on-mt7986.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3002-mt76-mt7915-add-wed-tx-wds-support-on-mt7986.patch
@@ -1,7 +1,7 @@
-From 2e99c7444625c73a247c0be7b3c1b60fb5de72ce Mon Sep 17 00:00:00 2001
+From 1672984d38b180a4e7cd64cc262a7a30cf39a329 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Sat, 10 Sep 2022 17:09:21 +0800
-Subject: [PATCH 3002/3010] mt76: mt7915: add-wed-tx-wds-support-on-mt7986
+Subject: [PATCH 3002/3011] mt76: mt7915: add-wed-tx-wds-support-on-mt7986
 
 Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
 ---
@@ -16,7 +16,7 @@
  8 files changed, 76 insertions(+), 5 deletions(-)
 
 diff --git a/mac80211.c b/mac80211.c
-index b7c1b13..7571e83 100644
+index b7c1b13b..1e13b654 100644
 --- a/mac80211.c
 +++ b/mac80211.c
 @@ -1364,7 +1364,10 @@ void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
@@ -32,7 +32,7 @@
  }
  EXPORT_SYMBOL_GPL(__mt76_sta_remove);
 diff --git a/mt76.h b/mt76.h
-index e547f79..335f0b1 100644
+index e547f79e..335f0b10 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -454,6 +454,7 @@ struct mt76_driver_ops {
@@ -52,7 +52,7 @@
  
  	u64 vif_mask;
 diff --git a/mt7915/init.c b/mt7915/init.c
-index 6833bbf..8055c6e 100644
+index 6833bbf5..8055c6ea 100644
 --- a/mt7915/init.c
 +++ b/mt7915/init.c
 @@ -695,6 +695,15 @@ mt7915_init_hardware(struct mt7915_dev *dev, struct mt7915_phy *phy2)
@@ -72,7 +72,7 @@
  	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
  	if (idx)
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 4e91527..74c9777 100644
+index 4e915279..62b9658b 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -658,6 +658,24 @@ mt7915_channel_switch_beacon(struct ieee80211_hw *hw,
@@ -150,7 +150,7 @@
  
  	ctx->dev = NULL;
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 477a41c..1d5cb2b 100644
+index bd7b81e6..4aa859e5 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -2350,6 +2350,7 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
@@ -180,7 +180,7 @@
  	ret = mt7915_mcu_set_mwds(dev, 1);
  	if (ret)
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 9d0fac4..1f56db6 100644
+index 9d0fac47..1f56db6b 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -268,6 +268,7 @@ enum {
@@ -192,7 +192,7 @@
  
  enum mcu_mmps_mode {
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 1eda361..6f0f262 100644
+index 5819281c..84a47c94 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
 @@ -596,6 +596,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
@@ -213,7 +213,7 @@
  	struct mt7915_dev *dev;
  	struct mt76_dev *mdev;
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index f403820..b06e7a9 100644
+index b5784d92..5a2d15ff 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -18,6 +18,9 @@
@@ -226,7 +226,7 @@
  #define MT7915_WATCHDOG_TIME		(HZ / 10)
  #define MT7915_RESET_TIMEOUT		(30 * HZ)
  
-@@ -695,6 +698,7 @@ void mt7915_tx_token_put(struct mt7915_dev *dev);
+@@ -696,6 +699,7 @@ void mt7915_tx_token_put(struct mt7915_dev *dev);
  void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
  			 struct sk_buff *skb);
  bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len);
@@ -235,5 +235,5 @@
  void mt7915_stats_work(struct work_struct *work);
  int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force);
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3003-mt76-add-wed-rx-support.patch b/recipes-kernel/linux-mt76/files/patches/3003-mt76-add-wed-rx-support.patch
index b6ae918..795bc23 100644
--- a/recipes-kernel/linux-mt76/files/patches/3003-mt76-add-wed-rx-support.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3003-mt76-add-wed-rx-support.patch
@@ -1,7 +1,7 @@
-From 9c57070620b011bc01d24aac8d387e6fa37bcde7 Mon Sep 17 00:00:00 2001
+From 6a8ab8991772977d92928b560b6b881132728508 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Tue, 5 Jul 2022 19:42:55 +0800
-Subject: [PATCH] mt76 add wed rx support
+Subject: [PATCH 3003/3011] mt76 add wed rx support
 
 Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
 ---
@@ -28,7 +28,7 @@
  20 files changed, 448 insertions(+), 67 deletions(-)
 
 diff --git a/dma.c b/dma.c
-index 8ea09e6e..3317d2b9 100644
+index 82b4da26..a8739eb4 100644
 --- a/dma.c
 +++ b/dma.c
 @@ -98,6 +98,63 @@ mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)
@@ -441,7 +441,7 @@
  			continue;
  		}
  
-@@ -708,7 +865,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+@@ -705,7 +862,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
  			continue;
  		}
  
@@ -450,7 +450,7 @@
  		continue;
  
  free_frag:
-@@ -785,7 +942,7 @@ EXPORT_SYMBOL_GPL(mt76_dma_attach);
+@@ -782,7 +939,7 @@ EXPORT_SYMBOL_GPL(mt76_dma_attach);
  
  void mt76_dma_cleanup(struct mt76_dev *dev)
  {
@@ -459,7 +459,7 @@
  
  	mt76_worker_disable(&dev->tx_worker);
  	netif_napi_del(&dev->tx_napi);
-@@ -806,12 +963,17 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
+@@ -803,12 +960,17 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
  
  	mt76_for_each_q_rx(dev, i) {
  		netif_napi_del(&dev->napi[i]);
@@ -500,7 +500,7 @@
  #define MT_RX_INFO_LEN			4
  #define MT_FCE_INFO_LEN			4
 diff --git a/mac80211.c b/mac80211.c
-index 7571e832..d0bd215a 100644
+index 1e13b654..3e276357 100644
 --- a/mac80211.c
 +++ b/mac80211.c
 @@ -603,11 +603,14 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
@@ -655,10 +655,10 @@
  void mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
  int mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 diff --git a/mt7615/mac.c b/mt7615/mac.c
-index d6aae60c..4774eaab 100644
+index 2ce1705c..59125b4d 100644
 --- a/mt7615/mac.c
 +++ b/mt7615/mac.c
-@@ -1651,7 +1651,7 @@ bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len)
+@@ -1653,7 +1653,7 @@ bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len)
  EXPORT_SYMBOL_GPL(mt7615_rx_check);
  
  void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
@@ -811,7 +811,7 @@
  		ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1],
  				       MT_RXQ_ID(MT_RXQ_BAND1),
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 65e47f95..06268e06 100644
+index 98925ed5..1ef7cb45 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
 @@ -217,7 +217,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
@@ -823,7 +823,7 @@
  {
  	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
  	struct mt76_phy *mphy = &dev->mt76.phy;
-@@ -494,6 +494,27 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
+@@ -496,6 +496,27 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
  #endif
  	} else {
  		status->flag |= RX_FLAG_8023;
@@ -851,7 +851,7 @@
  	}
  
  	if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
-@@ -831,6 +852,80 @@ u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
+@@ -833,6 +854,80 @@ u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
  	return MT_TXD_TXP_BUF_SIZE;
  }
  
@@ -932,7 +932,7 @@
  static void
  mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
  {
-@@ -1115,7 +1210,7 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
+@@ -1117,7 +1212,7 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
  }
  
  void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
@@ -941,7 +941,7 @@
  {
  	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
  	__le32 *rxd = (__le32 *)skb->data;
-@@ -1149,7 +1244,7 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+@@ -1151,7 +1246,7 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
  		dev_kfree_skb(skb);
  		break;
  	case PKT_TYPE_NORMAL:
@@ -951,7 +951,7 @@
  			return;
  		}
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 1d5cb2b3..a405bfde 100644
+index 4aa859e5..6603effd 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -1724,6 +1724,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
@@ -972,7 +972,7 @@
  				     MCU_EXT_CMD(STA_REC_UPDATE), true);
  }
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index c197e5eb..b98458e5 100644
+index 84a47c94..45520c74 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
 @@ -29,6 +29,7 @@ static const u32 mt7915_reg[] = {
@@ -1064,7 +1064,7 @@
  		return 0;
  
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index b06e7a90..d96709b1 100644
+index 5a2d15ff..e2127e02 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -81,6 +81,7 @@
@@ -1085,8 +1085,8 @@
 +void mt7915_wed_release_rx_buf(struct mtk_wed_device *wed);
  int mt7915_register_device(struct mt7915_dev *dev);
  void mt7915_unregister_device(struct mt7915_dev *dev);
- int mt7915_eeprom_init(struct mt7915_dev *dev);
-@@ -696,7 +699,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ void mt7915_eeprom_rebonding(struct mt7915_dev *dev);
+@@ -697,7 +700,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
  			  struct mt76_tx_info *tx_info);
  void mt7915_tx_token_put(struct mt7915_dev *dev);
  void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
@@ -1130,10 +1130,10 @@
  #define MT_INT_SOURCE_CSR		__REG(INT_SOURCE_CSR)
  #define MT_INT_MASK_CSR			__REG(INT_MASK_CSR)
 diff --git a/mt7921/mac.c b/mt7921/mac.c
-index dbdf4a77..c93cd5c4 100644
+index 1abf7d9b..2ad7b33a 100644
 --- a/mt7921/mac.c
 +++ b/mt7921/mac.c
-@@ -690,7 +690,7 @@ bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len)
+@@ -692,7 +692,7 @@ bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len)
  EXPORT_SYMBOL_GPL(mt7921_rx_check);
  
  void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
@@ -1198,5 +1198,5 @@
 +}
 +EXPORT_SYMBOL_GPL(mt76_rx_token_release);
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3004-mt76-add-fill-receive-path-to-report-wed-idx.patch b/recipes-kernel/linux-mt76/files/patches/3004-mt76-add-fill-receive-path-to-report-wed-idx.patch
index 163076d..4212bca 100644
--- a/recipes-kernel/linux-mt76/files/patches/3004-mt76-add-fill-receive-path-to-report-wed-idx.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3004-mt76-add-fill-receive-path-to-report-wed-idx.patch
@@ -1,7 +1,7 @@
-From ce92956ffffb916d8dd7ec6c5bb63c94e153678d Mon Sep 17 00:00:00 2001
+From 9f6f4b064b75c34530c28b8f9027ea499af76409 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Thu, 19 May 2022 13:44:42 +0800
-Subject: [PATCH 3004/3010] mt76: add fill receive path to report wed idx
+Subject: [PATCH 3004/3011] mt76: add fill receive path to report wed idx
 
 Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
 ---
@@ -9,10 +9,10 @@
  1 file changed, 19 insertions(+)
 
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 74c9777..d5360ce 100644
+index 62b9658b..5e37c4c8 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
-@@ -1511,6 +1511,24 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
+@@ -1512,6 +1512,24 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
  
  	return 0;
  }
@@ -37,7 +37,7 @@
  #endif
  
  const struct ieee80211_ops mt7915_ops = {
-@@ -1562,5 +1580,6 @@ const struct ieee80211_ops mt7915_ops = {
+@@ -1563,5 +1581,6 @@ const struct ieee80211_ops mt7915_ops = {
  	.set_radar_background = mt7915_set_radar_background,
  #ifdef CONFIG_NET_MEDIATEK_SOC_WED
  	.net_fill_forward_path = mt7915_net_fill_forward_path,
@@ -45,5 +45,5 @@
  #endif
  };
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3005-mt76-add-ser-spport-when-wed-on.patch b/recipes-kernel/linux-mt76/files/patches/3005-mt76-add-ser-spport-when-wed-on.patch
index 9118c67..1db7b07 100644
--- a/recipes-kernel/linux-mt76/files/patches/3005-mt76-add-ser-spport-when-wed-on.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3005-mt76-add-ser-spport-when-wed-on.patch
@@ -1,7 +1,7 @@
-From 067df4201faff9efe5d8574ce98172262bec25e1 Mon Sep 17 00:00:00 2001
+From 47a51d19218454afda6bac509c8c7633e9f61330 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Thu, 28 Jul 2022 11:16:15 +0800
-Subject: [PATCH 3005/3010] mt76 add ser spport when wed on
+Subject: [PATCH 3005/3011] mt76 add ser spport when wed on
 
 Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
 ---
@@ -15,7 +15,7 @@
  7 files changed, 76 insertions(+), 15 deletions(-)
 
 diff --git a/dma.c b/dma.c
-index 3317d2b..fa56ccf 100644
+index a8739eb4..d63b02f5 100644
 --- a/dma.c
 +++ b/dma.c
 @@ -169,7 +169,7 @@ mt76_free_pending_txwi(struct mt76_dev *dev)
@@ -109,7 +109,7 @@
  	if (!q->rx_head)
  		return;
 diff --git a/dma.h b/dma.h
-index 90370d1..083cbca 100644
+index 90370d12..083cbca4 100644
 --- a/dma.h
 +++ b/dma.h
 @@ -58,5 +58,5 @@ enum mt76_mcu_evt_type {
@@ -120,7 +120,7 @@
 +int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset);
  #endif
 diff --git a/mt76.h b/mt76.h
-index 959fb24..3530d21 100644
+index 959fb240..3530d213 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -1365,6 +1365,7 @@ mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb)
@@ -132,7 +132,7 @@
  		      struct napi_struct *napi);
  void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
 diff --git a/mt7915/dma.c b/mt7915/dma.c
-index 702d629..96cad2b 100644
+index 702d629a..96cad2b5 100644
 --- a/mt7915/dma.c
 +++ b/mt7915/dma.c
 @@ -532,6 +532,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
@@ -203,10 +203,10 @@
  }
  
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 06268e0..544d166 100644
+index 1ef7cb45..e78f30fc 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -916,6 +916,8 @@ void mt7915_wed_release_rx_buf(struct mtk_wed_device *wed)
+@@ -918,6 +918,8 @@ void mt7915_wed_release_rx_buf(struct mtk_wed_device *wed)
  		mt76_put_rxwi(&dev->mt76, rxwi);
  	}
  
@@ -215,7 +215,7 @@
  	if (wed->rx_page.va)
  		return;
  
-@@ -926,6 +928,18 @@ void mt7915_wed_release_rx_buf(struct mtk_wed_device *wed)
+@@ -928,6 +930,18 @@ void mt7915_wed_release_rx_buf(struct mtk_wed_device *wed)
  	return;
  }
  
@@ -234,7 +234,7 @@
  static void
  mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
  {
-@@ -1679,6 +1693,12 @@ void mt7915_mac_reset_work(struct work_struct *work)
+@@ -1681,6 +1695,12 @@ void mt7915_mac_reset_work(struct work_struct *work)
  	if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
  		return;
  
@@ -248,10 +248,10 @@
  	if (ext_phy)
  		ieee80211_stop_queues(ext_phy->hw);
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index edf99d2..11c7e94 100644
+index 45520c74..6a1877d4 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
-@@ -609,6 +609,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
+@@ -616,6 +616,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
  	wed->wlan.init_rx_buf = mt7915_wed_init_rx_buf;
  	wed->wlan.release_rx_buf = mt7915_wed_release_rx_buf;
  
@@ -261,7 +261,7 @@
  	if (mtk_wed_device_attach(wed))
  		return 0;
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index d96709b..1a32e82 100644
+index e2127e02..3a81261b 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -547,6 +547,7 @@ u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
@@ -271,7 +271,7 @@
 +void mt7915_wed_trigger_ser(struct mtk_wed_device *wed);
  int mt7915_register_device(struct mt7915_dev *dev);
  void mt7915_unregister_device(struct mt7915_dev *dev);
- int mt7915_eeprom_init(struct mt7915_dev *dev);
+ void mt7915_eeprom_rebonding(struct mt7915_dev *dev);
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3006-mt76-mt7915-add-statistic-for-H-W-Rx-Path.patch b/recipes-kernel/linux-mt76/files/patches/3006-mt76-mt7915-add-statistic-for-H-W-Rx-Path.patch
index 4de3b94..d92030c 100644
--- a/recipes-kernel/linux-mt76/files/patches/3006-mt76-mt7915-add-statistic-for-H-W-Rx-Path.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3006-mt76-mt7915-add-statistic-for-H-W-Rx-Path.patch
@@ -1,7 +1,7 @@
-From 74a76d638bf234a888a94a607aadeb0fda232abd Mon Sep 17 00:00:00 2001
+From 3c7f7b7883ce2dd0f185488d1f67d689330213d4 Mon Sep 17 00:00:00 2001
 From: Yi-Chia Hsieh <Yi-Chia.Hsieh@mediatek.com>
 Date: Fri, 5 Aug 2022 13:58:11 -0700
-Subject: [PATCH 3006/3010] mt76: mt7915: add statistic for H/W Rx Path
+Subject: [PATCH 3006/3011] mt76: mt7915: add statistic for H/W Rx Path
 
 Change-Id: Id94d663f08e91c83d296bd57e5e9b65a505ae1c7
 ---
@@ -16,7 +16,7 @@
  8 files changed, 107 insertions(+), 1 deletion(-)
 
 diff --git a/mt76.h b/mt76.h
-index 3530d21..47a9213 100644
+index 3530d213..47a92132 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -278,6 +278,10 @@ struct mt76_sta_stats {
@@ -31,7 +31,7 @@
  
  enum mt76_wcid_flags {
 diff --git a/mt76_connac.h b/mt76_connac.h
-index 9a46887..7ecc725 100644
+index 9a468878..7ecc7253 100644
 --- a/mt76_connac.h
 +++ b/mt76_connac.h
 @@ -224,6 +224,11 @@ static inline bool is_mt76_fw_txp(struct mt76_dev *dev)
@@ -47,7 +47,7 @@
  {
  	static const u8 width_to_bw[] = {
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 27a3624..475c391 100644
+index 27a36241..475c3910 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -1211,6 +1211,41 @@ enum {
@@ -93,10 +93,10 @@
  	PATCH_SEM_RELEASE,
  	PATCH_SEM_GET
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 544d166..bfc6c52 100644
+index e78f30fc..7fb161db 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -940,6 +940,31 @@ void mt7915_wed_trigger_ser(struct mtk_wed_device *wed)
+@@ -942,6 +942,31 @@ void mt7915_wed_trigger_ser(struct mtk_wed_device *wed)
  	return;
  }
  
@@ -129,7 +129,7 @@
  mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
  {
 diff --git a/mt7915/main.c b/mt7915/main.c
-index d5360ce..3e8142e 100644
+index 5e37c4c8..01d64b2f 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -1050,7 +1050,8 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
@@ -156,7 +156,7 @@
  }
  
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index a405bfd..48305b4 100644
+index 6603effd..87e02de7 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -293,6 +293,27 @@ int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
@@ -188,7 +188,7 @@
  mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
  {
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 11c7e94..1f794df 100644
+index 6a1877d4..cd8326b0 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
 @@ -9,6 +9,7 @@
@@ -197,9 +197,9 @@
  #include "../trace.h"
 +#include "../mt76_connac_mcu.h"
  
- static bool wed_enable;
+ static bool wed_enable = true;
  module_param(wed_enable, bool, 0644);
-@@ -611,6 +612,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
+@@ -618,6 +619,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
  
  	wed->wlan.ser_trigger = mt7915_wed_trigger_ser;
  
@@ -208,7 +208,7 @@
  	dev->mt76.rx_token_size = wed->wlan.rx_pkt;
  	if (mtk_wed_device_attach(wed))
  		return 0;
-@@ -622,6 +625,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
+@@ -630,6 +633,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
  	if (ret)
  		return ret;
  
@@ -219,7 +219,7 @@
  #else
  	return 0;
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 1a32e82..c2a7f35 100644
+index 3a81261b..b1fbbae9 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -548,6 +548,8 @@ u32 mt7915_wed_init_rx_buf(struct mtk_wed_device *wed,
@@ -230,8 +230,8 @@
 +				struct wo_cmd_rxcnt_t *rxcnt);
  int mt7915_register_device(struct mt7915_dev *dev);
  void mt7915_unregister_device(struct mt7915_dev *dev);
- int mt7915_eeprom_init(struct mt7915_dev *dev);
-@@ -632,6 +634,7 @@ int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
+ void mt7915_eeprom_rebonding(struct mt7915_dev *dev);
+@@ -633,6 +635,7 @@ int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
  				     struct cfg80211_chan_def *chandef);
  int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set);
  int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
@@ -240,5 +240,5 @@
  int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level);
  void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb);
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3007-mt76-mt7915-enable-red-per-band-token-drop-for-HW-Pa.patch b/recipes-kernel/linux-mt76/files/patches/3007-mt76-mt7915-enable-red-per-band-token-drop-for-HW-Pa.patch
index dee6d8c..805db7c 100644
--- a/recipes-kernel/linux-mt76/files/patches/3007-mt76-mt7915-enable-red-per-band-token-drop-for-HW-Pa.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3007-mt76-mt7915-enable-red-per-band-token-drop-for-HW-Pa.patch
@@ -1,7 +1,7 @@
-From 95895d15a31f5fef5133f1dafef38cd6b39700ea Mon Sep 17 00:00:00 2001
+From ad97dee36cde2face7aa7b19470e040b8681e7c8 Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Fri, 2 Sep 2022 14:40:40 +0800
-Subject: [PATCH 3007/3010] mt76: mt7915: enable red per-band token drop for HW
+Subject: [PATCH 3007/3011] mt76: mt7915: enable red per-band token drop for HW
  Path
 
 Limit the number of token used by each band. If a band uses too many token,
@@ -16,7 +16,7 @@
  3 files changed, 45 insertions(+), 11 deletions(-)
 
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 48305b4..a3600c7 100644
+index 87e02de7..7fc24e67 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -2412,8 +2412,13 @@ int mt7915_run_firmware(struct mt7915_dev *dev)
@@ -47,7 +47,7 @@
  }
  
  int mt7915_mcu_init(struct mt7915_dev *dev)
-@@ -4232,6 +4232,35 @@ int mt7915_dbg_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a
+@@ -4239,6 +4239,35 @@ int mt7915_dbg_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a
  
  	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), wait_resp);
  }
@@ -83,7 +83,7 @@
  
  int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled)
  {
-@@ -4242,17 +4271,21 @@ int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled)
+@@ -4249,17 +4278,21 @@ int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled)
  	u32 red_type = enabled > 0 ? RED_BY_WA_ENABLE : RED_DISABLE;
  	__le32 req = cpu_to_le32(red_type);
  
@@ -110,7 +110,7 @@
  int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
  {
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 1f56db6..9181e96 100644
+index 1f56db6b..9181e961 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -269,6 +269,7 @@ enum {
@@ -122,10 +122,10 @@
  
  enum mcu_mmps_mode {
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index c2a7f35..14dfc34 100644
+index b1fbbae9..ac3f4763 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
-@@ -749,11 +749,11 @@ int mt7915_vendor_amnt_sta_remove(struct mt7915_phy *phy,
+@@ -752,11 +752,11 @@ int mt7915_vendor_amnt_sta_remove(struct mt7915_phy *phy,
  #endif
  int mt7915_mcu_set_edcca(struct mt7915_phy *phy, int mode, u8 *value,
  			 s8 compensation);
@@ -139,5 +139,5 @@
  int mt7915_mcu_set_txpower_level(struct mt7915_phy *phy, u8 drop_level);
  void mt7915_packet_log_to_host(struct mt7915_dev *dev, const void *data, int len, int type, int des_len);
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3008-mt76-mt7915-update-mt7916-trinfo-when-hw-path-enable.patch b/recipes-kernel/linux-mt76/files/patches/3008-mt76-mt7915-update-mt7916-trinfo-when-hw-path-enable.patch
index 997a28f..8b511a9 100644
--- a/recipes-kernel/linux-mt76/files/patches/3008-mt76-mt7915-update-mt7916-trinfo-when-hw-path-enable.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3008-mt76-mt7915-update-mt7916-trinfo-when-hw-path-enable.patch
@@ -1,7 +1,7 @@
-From 7b58f758461fd34ce64e75a8310787a347fd2ee5 Mon Sep 17 00:00:00 2001
+From 9082a5d0fef0f16f1d34285898b9c5090ab21a03 Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Thu, 22 Sep 2022 09:54:53 +0800
-Subject: [PATCH 3008/3010] mt76: mt7915: update mt7916 trinfo when hw path
+Subject: [PATCH 3008/3011] mt76: mt7915: update mt7916 trinfo when hw path
  enable
 
 ---
@@ -10,7 +10,7 @@
  2 files changed, 23 insertions(+), 3 deletions(-)
 
 diff --git a/mt7915/mt7915_debug.h b/mt7915/mt7915_debug.h
-index 58ba2cd..50b588b 100644
+index ecdc02ab..0a1ee808 100644
 --- a/mt7915/mt7915_debug.h
 +++ b/mt7915/mt7915_debug.h
 @@ -133,6 +133,8 @@ enum dbg_reg_rev {
@@ -57,7 +57,7 @@
  #define MT_DBG_INT_SOURCE_CSR			__DBG_REG(dev, DBG_INT_SOURCE_CSR)
  #define MT_DBG_INT_MASK_CSR			__DBG_REG(dev, DBG_INT_MASK_CSR)
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 9de5b0f..5f09f0a 100644
+index 9de5b0f6..5f09f0aa 100644
 --- a/mt7915/mtk_debugfs.c
 +++ b/mt7915/mtk_debugfs.c
 @@ -855,12 +855,22 @@ mt7986_show_host_dma_info(struct seq_file *s, struct mt7915_dev *dev)
@@ -87,5 +87,5 @@
  	dump_dma_rx_ring_info(s, dev, "R4:Data0(MAC2H)", MT_DBG_RX_DATA_RING_CTRL(0));
  	dump_dma_rx_ring_info(s, dev, "R5:Data1(MAC2H)", MT_DBG_RX_DATA_RING_CTRL(1));
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3009-mt76-mt7915-find-rx-token-by-physical-address.patch b/recipes-kernel/linux-mt76/files/patches/3009-mt76-mt7915-find-rx-token-by-physical-address.patch
index a252398..09b05b8 100644
--- a/recipes-kernel/linux-mt76/files/patches/3009-mt76-mt7915-find-rx-token-by-physical-address.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3009-mt76-mt7915-find-rx-token-by-physical-address.patch
@@ -1,7 +1,7 @@
-From 82335286ec2a9d33c9638c30e7638035f431e116 Mon Sep 17 00:00:00 2001
+From 8798ce118731d2446d8d1b1c4ab0f1062fc08ea7 Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Tue, 27 Sep 2022 16:34:26 +0800
-Subject: [PATCH 3009/3010] mt76: mt7915: find rx token by physical address
+Subject: [PATCH 3009/3011] mt76: mt7915: find rx token by physical address
 
 The token id in RxDMAD may be incorrect when it is not the last frame due to
 WED HW bug. Lookup correct token id by physical address in sdp0.
@@ -12,7 +12,7 @@
  1 file changed, 18 insertions(+), 1 deletion(-)
 
 diff --git a/dma.c b/dma.c
-index fa56ccf..c551369 100644
+index d63b02f5..a7a4538a 100644
 --- a/dma.c
 +++ b/dma.c
 @@ -380,11 +380,28 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
@@ -46,5 +46,5 @@
  		if (!r)
  			return NULL;
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/3010-mt76-mt7915-drop-scatter-and-gather-frame.patch b/recipes-kernel/linux-mt76/files/patches/3010-mt76-mt7915-drop-scatter-and-gather-frame.patch
index dbc898d..e516e83 100644
--- a/recipes-kernel/linux-mt76/files/patches/3010-mt76-mt7915-drop-scatter-and-gather-frame.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3010-mt76-mt7915-drop-scatter-and-gather-frame.patch
@@ -1,7 +1,7 @@
-From fbbc214ee09aae422c5a8f89dd88c8adeecb7356 Mon Sep 17 00:00:00 2001
+From a71f60174d354cd7d4bf82ade7534c1578a8fd17 Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Wed, 28 Sep 2022 18:52:54 +0800
-Subject: [PATCH 3010/3010] mt76: mt7915: drop scatter and gather frame
+Subject: [PATCH 3010/3011] mt76: mt7915: drop scatter and gather frame
 
 The scatter and gather frame may be incorrect because WED and WO may
 send frames to host driver interleaved.
@@ -14,7 +14,7 @@
  3 files changed, 11 insertions(+)
 
 diff --git a/dma.c b/dma.c
-index c551369..f893c78 100644
+index a7a4538a..c106ae42 100644
 --- a/dma.c
 +++ b/dma.c
 @@ -419,6 +419,15 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
@@ -34,7 +34,7 @@
  		buf_addr = e->dma_addr[0];
  		e->buf = NULL;
 diff --git a/dma.h b/dma.h
-index 083cbca..221fcc8 100644
+index 083cbca4..221fcc8e 100644
 --- a/dma.h
 +++ b/dma.h
 @@ -21,6 +21,7 @@
@@ -46,7 +46,7 @@
  #define MT_DMA_PPE_CPU_REASON		GENMASK(15, 11)
  #define MT_DMA_PPE_ENTRY		GENMASK(30, 16)
 diff --git a/mt76.h b/mt76.h
-index 47a9213..1af188e 100644
+index 47a92132..1af188e1 100644
 --- a/mt76.h
 +++ b/mt76.h
 @@ -32,6 +32,7 @@
@@ -58,5 +58,5 @@
  #define __MT_WED_Q(_type, _n)	(MT_QFLAG_WED | \
  				 FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/patches.inc b/recipes-kernel/linux-mt76/files/patches/patches.inc
index d9a0e57..f771e06 100644
--- a/recipes-kernel/linux-mt76/files/patches/patches.inc
+++ b/recipes-kernel/linux-mt76/files/patches/patches.inc
@@ -27,7 +27,9 @@
     file://1122-mt76-HEMU-Add-dump-support.patch \
     file://1123-mt76-mt7915-add-vendor-subcmd-three-wire-PTA-ctrl.patch \
     file://1124-mt76-add-ibf-control-vendor-cmd.patch \
-    file://1125-mt76-add-ampdu-amsdu-control.patch \
+    file://1125-mt76-mt7915-add-AMPDU-AMSDU-OnOff-ctonrol.patch \
+    file://1126-mt76-mt7915-add-E3-re-bonding-for-low-yield-rate-iss.patch \
+    file://1127-mt76-support-on-off-SW-ACI-through-debugfs.patch \
     file://3001-mt76-add-wed-tx-support.patch \
     file://3002-mt76-mt7915-add-wed-tx-wds-support-on-mt7986.patch \
     file://3003-mt76-add-wed-rx-support.patch \
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7915_rom_patch.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7915_rom_patch.bin
index 7cca92e..aba89e9 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7915_rom_patch.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7915_rom_patch.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7915_wa.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7915_wa.bin
index f87d182..9c620cf 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7915_wa.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7915_wa.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7915_wm.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7915_wm.bin
index 777bfac..417b7e6 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7915_wm.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7915_wm.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7916_rom_patch.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7916_rom_patch.bin
index a7c3de2..e98a766 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7916_rom_patch.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7916_rom_patch.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7916_wa.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7916_wa.bin
index 3f61a50..bc0e31b 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7916_wa.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7916_wa.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7916_wm.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7916_wm.bin
index f7f7616..87c0f6f 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7916_wm.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7916_wm.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_rom_patch.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_rom_patch.bin
index 37c1106..e2ab607 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_rom_patch.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_rom_patch.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_rom_patch_mt7975.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_rom_patch_mt7975.bin
index 6e9aa8d..409fbf6 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_rom_patch_mt7975.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_rom_patch_mt7975.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wa.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wa.bin
index 3e0f5f8..a8a813f 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wa.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wa.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wm.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wm.bin
index 67e905f..2d71ab7 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wm.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wm.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wm_mt7975.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wm_mt7975.bin
index f2911f9..9566b18 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wm_mt7975.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wm_mt7975.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wo_0.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wo_0.bin
index 12c4cf3..a2dfb96 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wo_0.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wo_0.bin
Binary files differ
diff --git a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wo_1.bin b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wo_1.bin
index c5f4fb7..f7bbf39 100644
--- a/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wo_1.bin
+++ b/recipes-kernel/linux-mt76/files/src/firmware/mt7986_wo_1.bin
Binary files differ
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988-clkitg.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988-clkitg.dtsi
new file mode 100644
index 0000000..48ed6c0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988-clkitg.dtsi
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&clkitg {
+	bring-up {
+		compatible = "mediatek,clk-bring-up";
+		clocks =
+			<&apmixedsys CK_APMIXED_NETSYSPLL>,
+			<&apmixedsys CK_APMIXED_MPLL>,
+			<&apmixedsys CK_APMIXED_MMPLL>,
+			<&apmixedsys CK_APMIXED_APLL2>,
+			<&apmixedsys CK_APMIXED_NET1PLL>,
+			<&apmixedsys CK_APMIXED_NET2PLL>,
+			<&apmixedsys CK_APMIXED_WEDMCUPLL>,
+			<&apmixedsys CK_APMIXED_SGMPLL>,
+			<&apmixedsys CK_APMIXED_ARM_B>,
+			<&apmixedsys CK_APMIXED_CCIPLL2_B>,
+			<&apmixedsys CK_APMIXED_USXGMIIPLL>,
+			<&apmixedsys CK_APMIXED_MSDCPLL>,
+			<&topckgen CK_TOP_CB_CKSQ_40M>,
+			<&topckgen CK_TOP_CB_M_416M>,
+			<&topckgen CK_TOP_CB_M_D2>,
+			<&topckgen CK_TOP_M_D3_D2>,
+			<&topckgen CK_TOP_CB_M_D4>,
+			<&topckgen CK_TOP_CB_M_D8>,
+			<&topckgen CK_TOP_M_D8_D2>,
+			<&topckgen CK_TOP_CB_MM_720M>,
+			<&topckgen CK_TOP_CB_MM_D2>,
+			<&topckgen CK_TOP_CB_MM_D3_D5>,
+			<&topckgen CK_TOP_CB_MM_D4>,
+			<&topckgen CK_TOP_MM_D6_D2>,
+			<&topckgen CK_TOP_CB_MM_D8>,
+			<&topckgen CK_TOP_CB_APLL2_196M>,
+			<&topckgen CK_TOP_CB_APLL2_D4>,
+			<&topckgen CK_TOP_CB_NET1_D4>,
+			<&topckgen CK_TOP_CB_NET1_D5>,
+			<&topckgen CK_TOP_NET1_D5_D2>,
+			<&topckgen CK_TOP_NET1_D5_D4>,
+			<&topckgen CK_TOP_CB_NET1_D8>,
+			<&topckgen CK_TOP_NET1_D8_D2>,
+			<&topckgen CK_TOP_NET1_D8_D4>,
+			<&topckgen CK_TOP_NET1_D8_D8>,
+			<&topckgen CK_TOP_NET1_D8_D16>,
+			<&topckgen CK_TOP_CB_NET2_800M>,
+			<&topckgen CK_TOP_CB_NET2_D2>,
+			<&topckgen CK_TOP_CB_NET2_D4>,
+			<&topckgen CK_TOP_NET2_D4_D4>,
+			<&topckgen CK_TOP_NET2_D4_D8>,
+			<&topckgen CK_TOP_CB_NET2_D6>,
+			<&topckgen CK_TOP_CB_NET2_D8>,
+			<&topckgen CK_TOP_CB_WEDMCU_208M>,
+			<&topckgen CK_TOP_CB_SGM_325M>,
+			<&topckgen CK_TOP_CB_NETSYS_850M>,
+			<&topckgen CK_TOP_CB_MSDC_400M>,
+			<&topckgen CK_TOP_CKSQ_40M_D2>,
+			<&topckgen CK_TOP_CB_RTC_32K>,
+			<&topckgen CK_TOP_CB_RTC_32P7K>,
+			<&topckgen CK_TOP_INFRA_F32K>,
+			<&topckgen CK_TOP_CKSQ_SRC>,
+			<&topckgen CK_TOP_NETSYS_2X>,
+			<&topckgen CK_TOP_NETSYS_GSW>,
+			<&topckgen CK_TOP_NETSYS_WED_MCU>,
+			<&topckgen CK_TOP_EIP197>,
+			<&topckgen CK_TOP_EMMC_250M>,
+			<&topckgen CK_TOP_EMMC_400M>,
+			<&topckgen CK_TOP_SPI>,
+			<&topckgen CK_TOP_SPIM_MST>,
+			<&topckgen CK_TOP_NFI1X>,
+			<&topckgen CK_TOP_SPINFI_BCK>,
+			<&topckgen CK_TOP_I2C_BCK>,
+			<&topckgen CK_TOP_USB_SYS>,
+			<&topckgen CK_TOP_USB_SYS_P1>,
+			<&topckgen CK_TOP_USB_XHCI>,
+			<&topckgen CK_TOP_USB_XHCI_P1>,
+			<&topckgen CK_TOP_USB_FRMCNT>,
+			<&topckgen CK_TOP_USB_FRMCNT_P1>,
+			<&topckgen CK_TOP_AUD>,
+			<&topckgen CK_TOP_A1SYS>,
+			<&topckgen CK_TOP_AUD_L>,
+			<&topckgen CK_TOP_A_TUNER>,
+			<&topckgen CK_TOP_SYSAXI>,
+			<&topckgen CK_TOP_INFRA_F26M>,
+			<&topckgen CK_TOP_USB_REF>,
+			<&topckgen CK_TOP_USB_CK_P1>,
+			<&topckgen CK_TOP_AUD_I2S_M>,
+			<&topckgen CK_TOP_NETSYS_SEL>,
+			<&topckgen CK_TOP_NETSYS_500M_SEL>,
+			<&topckgen CK_TOP_NETSYS_2X_SEL>,
+			<&topckgen CK_TOP_NETSYS_GSW_SEL>,
+			<&topckgen CK_TOP_ETH_GMII_SEL>,
+			<&topckgen CK_TOP_NETSYS_MCU_SEL>,
+			<&topckgen CK_TOP_NETSYS_PAO_2X_SEL>,
+			<&topckgen CK_TOP_EIP197_SEL>,
+			<&topckgen CK_TOP_AXI_INFRA_SEL>,
+			<&topckgen CK_TOP_UART_SEL>,
+			<&topckgen CK_TOP_EMMC_250M_SEL>,
+			<&topckgen CK_TOP_EMMC_400M_SEL>,
+			<&topckgen CK_TOP_SPI_SEL>,
+			<&topckgen CK_TOP_SPIM_MST_SEL>,
+			<&topckgen CK_TOP_NFI1X_SEL>,
+			<&topckgen CK_TOP_SPINFI_SEL>,
+			<&topckgen CK_TOP_PWM_SEL>,
+			<&topckgen CK_TOP_I2C_SEL>,
+			<&topckgen CK_TOP_PCIE_MBIST_250M_SEL>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&topckgen CK_TOP_USB_SYS_SEL>,
+			<&topckgen CK_TOP_USB_SYS_P1_SEL>,
+			<&topckgen CK_TOP_USB_XHCI_SEL>,
+			<&topckgen CK_TOP_USB_XHCI_P1_SEL>,
+			<&topckgen CK_TOP_USB_FRMCNT_SEL>,
+			<&topckgen CK_TOP_USB_FRMCNT_P1_SEL>,
+			<&topckgen CK_TOP_AUD_SEL>,
+			<&topckgen CK_TOP_A1SYS_SEL>,
+			<&topckgen CK_TOP_AUD_L_SEL>,
+			<&topckgen CK_TOP_A_TUNER_SEL>,
+			<&topckgen CK_TOP_SSPXTP_SEL>,
+			<&topckgen CK_TOP_USB_PHY_SEL>,
+			<&topckgen CK_TOP_USXGMII_SBUS_0_SEL>,
+			<&topckgen CK_TOP_USXGMII_SBUS_1_SEL>,
+			<&topckgen CK_TOP_SGM_0_SEL>,
+			<&topckgen CK_TOP_SGM_SBUS_0_SEL>,
+			<&topckgen CK_TOP_SGM_1_SEL>,
+			<&topckgen CK_TOP_SGM_SBUS_1_SEL>,
+			<&topckgen CK_TOP_XFI_PHY_0_XTAL_SEL>,
+			<&topckgen CK_TOP_XFI_PHY_1_XTAL_SEL>,
+			<&topckgen CK_TOP_SYSAXI_SEL>,
+			<&topckgen CK_TOP_SYSAPB_SEL>,
+			<&topckgen CK_TOP_ETH_REFCK_50M_SEL>,
+			<&topckgen CK_TOP_ETH_SYS_200M_SEL>,
+			<&topckgen CK_TOP_ETH_SYS_SEL>,
+			<&topckgen CK_TOP_ETH_XGMII_SEL>,
+			<&topckgen CK_TOP_BUS_TOPS_SEL>,
+			<&topckgen CK_TOP_NPU_TOPS_SEL>,
+			<&topckgen CK_TOP_DRAMC_SEL>,
+			<&topckgen CK_TOP_DRAMC_MD32_SEL>,
+			<&topckgen CK_TOP_INFRA_F26M_SEL>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&topckgen CK_TOP_DA_XTP_GLB_P0_SEL>,
+			<&topckgen CK_TOP_DA_XTP_GLB_P1_SEL>,
+			<&topckgen CK_TOP_DA_XTP_GLB_P2_SEL>,
+			<&topckgen CK_TOP_DA_XTP_GLB_P3_SEL>,
+			<&topckgen CK_TOP_CKM_SEL>,
+			<&topckgen CK_TOP_DA_SELM_XTAL_SEL>,
+			<&topckgen CK_TOP_PEXTP_SEL>,
+			<&topckgen CK_TOP_TOPS_P2_26M_SEL>,
+			<&topckgen CK_TOP_MCUSYS_BACKUP_625M_SEL>,
+			<&topckgen CK_TOP_NETSYS_SYNC_250M_SEL>,
+			<&topckgen CK_TOP_MACSEC_SEL>,
+			<&topckgen CK_TOP_NETSYS_TOPS_400M_SEL>,
+			<&topckgen CK_TOP_NETSYS_PPEFB_250M_SEL>,
+			<&topckgen CK_TOP_NETSYS_WARP_SEL>,
+			<&topckgen CK_TOP_ETH_MII_SEL>,
+			<&topckgen CK_TOP_CK_NPU_SEL_CM_TOPS_SEL>,
+			<&infracfg CK_INFRA_CK_F26M>,
+			<&infracfg CK_INFRA_PWM_O>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&infracfg CK_INFRA_133M_HCK>,
+			<&infracfg CK_INFRA_133M_PHCK>,
+			<&infracfg CK_INFRA_66M_PHCK>,
+			<&infracfg CK_INFRA_FAUD_L_O>,
+			<&infracfg CK_INFRA_FAUD_AUD_O>,
+			<&infracfg CK_INFRA_FAUD_EG2_O>,
+			<&infracfg CK_INFRA_I2C_O>,
+			<&infracfg CK_INFRA_UART_O0>,
+			<&infracfg CK_INFRA_UART_O1>,
+			<&infracfg CK_INFRA_UART_O2>,
+			<&infracfg CK_INFRA_NFI_O>,
+			<&infracfg CK_INFRA_SPINFI_O>,
+			<&infracfg CK_INFRA_SPI0_O>,
+			<&infracfg CK_INFRA_SPI1_O>,
+			<&infracfg CK_INFRA_LB_MUX_FRTC>,
+			<&infracfg CK_INFRA_FRTC>,
+			<&infracfg CK_INFRA_FMSDC400_O>,
+			<&infracfg CK_INFRA_FMSDC2_HCK_OCC>,
+			<&infracfg CK_INFRA_PERI_133M>,
+			<&infracfg CK_INFRA_USB_O>,
+			<&infracfg CK_INFRA_USB_O_P1>,
+			<&infracfg CK_INFRA_USB_FRMCNT_O>,
+			<&infracfg CK_INFRA_USB_FRMCNT_O_P1>,
+			<&infracfg CK_INFRA_USB_XHCI_O>,
+			<&infracfg CK_INFRA_USB_XHCI_O_P1>,
+			<&infracfg CK_INFRA_USB_PIPE_O>,
+			<&infracfg CK_INFRA_USB_PIPE_O_P1>,
+			<&infracfg CK_INFRA_USB_UTMI_O>,
+			<&infracfg CK_INFRA_USB_UTMI_O_P1>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&infracfg CK_INFRA_F26M_O0>,
+			<&infracfg CK_INFRA_F26M_O1>,
+			<&infracfg CK_INFRA_133M_MCK>,
+			<&infracfg CK_INFRA_66M_MCK>,
+			<&infracfg CK_INFRA_PERI_66M_O>,
+			<&infracfg CK_INFRA_USB_SYS_O>,
+			<&infracfg CK_INFRA_USB_SYS_O_P1>,
+			<&infracfg_ao CK_INFRA_66M_GPT_BCK>,
+			<&infracfg_ao CK_INFRA_66M_PWM_HCK>,
+			<&infracfg_ao CK_INFRA_66M_PWM_BCK>,
+			<&infracfg_ao CK_INFRA_66M_PWM_CK1>,
+			<&infracfg_ao CK_INFRA_66M_PWM_CK2>,
+			<&infracfg_ao CK_INFRA_66M_PWM_CK3>,
+			<&infracfg_ao CK_INFRA_66M_PWM_CK4>,
+			<&infracfg_ao CK_INFRA_66M_PWM_CK5>,
+			<&infracfg_ao CK_INFRA_66M_PWM_CK6>,
+			<&infracfg_ao CK_INFRA_66M_PWM_CK7>,
+			<&infracfg_ao CK_INFRA_66M_PWM_CK8>,
+			<&infracfg_ao CK_INFRA_133M_CQDMA_BCK>,
+			<&infracfg_ao CK_INFRA_66M_AUD_SLV_BCK>,
+			<&infracfg_ao CK_INFRA_AUD_26M>,
+			<&infracfg_ao CK_INFRA_AUD_L>,
+			<&infracfg_ao CK_INFRA_AUD_AUD>,
+			<&infracfg_ao CK_INFRA_AUD_EG2>,
+			<&infracfg_ao CK_INFRA_DRAMC_F26M>,
+			<&infracfg_ao CK_INFRA_133M_DBG_ACKM>,
+			<&infracfg_ao CK_INFRA_66M_AP_DMA_BCK>,
+			<&infracfg_ao CK_INFRA_66M_SEJ_BCK>,
+			<&infracfg_ao CK_INFRA_PRE_CK_SEJ_F13M>,
+			<&infracfg_ao CK_INFRA_66M_TRNG>,
+			<&infracfg_ao CK_INFRA_26M_THERM_SYSTEM>,
+			<&infracfg_ao CK_INFRA_I2C_BCK>,
+			<&infracfg_ao CK_INFRA_66M_UART0_PCK>,
+			<&infracfg_ao CK_INFRA_66M_UART1_PCK>,
+			<&infracfg_ao CK_INFRA_66M_UART2_PCK>,
+			<&infracfg_ao CK_INFRA_52M_UART0_CK>,
+			<&infracfg_ao CK_INFRA_52M_UART1_CK>,
+			<&infracfg_ao CK_INFRA_52M_UART2_CK>,
+			<&infracfg_ao CK_INFRA_NFI>,
+			<&infracfg_ao CK_INFRA_SPINFI>,
+			<&infracfg_ao CK_INFRA_66M_NFI_HCK>,
+			<&infracfg_ao CK_INFRA_104M_SPI0>,
+			<&infracfg_ao CK_INFRA_104M_SPI1>,
+			<&infracfg_ao CK_INFRA_104M_SPI2_BCK>,
+			<&infracfg_ao CK_INFRA_66M_SPI0_HCK>,
+			<&infracfg_ao CK_INFRA_66M_SPI1_HCK>,
+			<&infracfg_ao CK_INFRA_66M_SPI2_HCK>,
+			<&infracfg_ao CK_INFRA_66M_FLASHIF_AXI>,
+			<&infracfg_ao CK_INFRA_RTC>,
+			<&infracfg_ao CK_INFRA_26M_ADC_BCK>,
+			<&infracfg_ao CK_INFRA_RC_ADC>,
+			<&infracfg_ao CK_INFRA_MSDC400>,
+			<&infracfg_ao CK_INFRA_MSDC2_HCK>,
+			<&infracfg_ao CK_INFRA_133M_MSDC_0_HCK>,
+			<&infracfg_ao CK_INFRA_66M_MSDC_0_HCK>,
+			<&infracfg_ao CK_INFRA_133M_CPUM_BCK>,
+			<&infracfg_ao CK_INFRA_BIST2FPC>,
+			<&infracfg_ao CK_INFRA_I2C_X16W_MCK_CK_P1>,
+			<&infracfg_ao CK_INFRA_I2C_X16W_PCK_CK_P1>,
+			<&infracfg_ao CK_INFRA_133M_USB_HCK>,
+			<&infracfg_ao CK_INFRA_133M_USB_HCK_CK_P1>,
+			<&infracfg_ao CK_INFRA_66M_USB_HCK>,
+			<&infracfg_ao CK_INFRA_66M_USB_HCK_CK_P1>,
+			<&infracfg_ao CK_INFRA_USB_SYS>,
+			<&infracfg_ao CK_INFRA_USB_SYS_CK_P1>,
+			<&infracfg_ao CK_INFRA_USB_REF>,
+			<&infracfg_ao CK_INFRA_USB_CK_P1>,
+			<&infracfg_ao CK_INFRA_USB_FRMCNT>,
+			<&infracfg_ao CK_INFRA_USB_FRMCNT_CK_P1>,
+			<&infracfg_ao CK_INFRA_USB_PIPE>,
+			<&infracfg_ao CK_INFRA_USB_PIPE_CK_P1>,
+			<&infracfg_ao CK_INFRA_USB_UTMI>,
+			<&infracfg_ao CK_INFRA_USB_UTMI_CK_P1>,
+			<&infracfg_ao CK_INFRA_USB_XHCI>,
+			<&infracfg_ao CK_INFRA_USB_XHCI_CK_P1>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&infracfg_ao CK_INFRA_MUX_UART0_SEL>,
+			<&infracfg_ao CK_INFRA_MUX_UART1_SEL>,
+			<&infracfg_ao CK_INFRA_MUX_UART2_SEL>,
+			<&infracfg_ao CK_INFRA_MUX_SPI0_SEL>,
+			<&infracfg_ao CK_INFRA_MUX_SPI1_SEL>,
+			<&infracfg_ao CK_INFRA_MUX_SPI2_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_CK1_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_CK2_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_CK3_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_CK4_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_CK5_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_CK6_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_CK7_SEL>,
+			<&infracfg_ao CK_INFRA_PWM_CK8_SEL>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&system_clk>,
+			<&ethsys CK_ETHDMA_XGP1_EN>,
+			<&ethsys CK_ETHDMA_XGP2_EN>,
+			<&ethsys CK_ETHDMA_XGP3_EN>,
+			<&ethsys CK_ETHDMA_FE_EN>,
+			<&ethsys CK_ETHDMA_GP2_EN>,
+			<&ethsys CK_ETHDMA_GP1_EN>,
+			<&ethsys CK_ETHDMA_GP3_EN>,
+			<&ethsys CK_ETHDMA_ESW_EN>,
+			<&ethsys CK_ETHDMA_CRYPT0_EN>,
+			<&ethwarp CK_ETHWARP_WOCPU2_EN>,
+			<&ethwarp CK_ETHWARP_WOCPU1_EN>,
+			<&ethwarp CK_ETHWARP_WOCPU0_EN>,
+			<&sgmiisys0 CK_SGM0_TX_EN>,
+			<&sgmiisys0 CK_SGM0_RX_EN>,
+			<&sgmiisys1 CK_SGM1_TX_EN>,
+			<&sgmiisys1 CK_SGM1_RX_EN>,
+			<&mcusys CK_MCU_BUS_DIV_SEL>,
+			<&mcusys CK_MCU_ARM_DIV_SEL>;
+
+		clock-names = "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+			      "10", "11", "12", "13", "14", "15", "16", "17",
+			      "18", "19", "20", "21", "22", "23", "24", "25",
+			      "26", "27", "28", "29", "30", "31", "32", "33",
+			      "34", "35", "36", "37", "38", "39", "40", "41",
+			      "42", "43", "44", "45", "46", "47", "48", "49",
+			      "50", "51", "52", "53", "54", "55", "56", "57",
+			      "58", "59", "60", "61", "62", "63", "64", "65",
+			      "66", "67", "68", "69", "70", "71", "72", "73",
+			      "74", "75", "76", "77", "78", "79", "80", "81",
+			      "82", "83", "84", "85", "86", "87", "88", "89",
+			      "90", "91", "92", "93", "94", "95", "96", "97",
+			      "98", "99", "100", "101", "102", "103", "104",
+			      "105", "106", "107", "108", "109", "110", "111",
+			      "112", "113", "114", "115", "116", "117", "118",
+			      "119", "120", "121", "122", "123", "124", "125",
+			      "126", "127", "128", "129", "130", "131", "132",
+			      "133", "134", "135", "136", "137", "138", "139",
+			      "140", "141", "142", "143", "144", "145", "146",
+			      "147", "148", "149", "150", "151", "152", "153",
+			      "154", "155", "156", "157", "158", "159", "160",
+			      "161", "162", "163", "164", "165", "166", "167",
+			      "168", "169", "170", "171", "172", "173", "174",
+			      "175", "176", "177", "178", "179", "180", "181",
+			      "182", "183", "184", "185", "186", "187", "188",
+			      "189", "190", "191", "192", "193", "194", "195",
+			      "196", "197", "198", "199", "200", "201", "202",
+			      "203", "204", "205", "206", "207", "208", "209",
+			      "210", "211", "212", "213", "214", "215", "216",
+			      "217", "218", "219", "220", "221", "222", "223",
+			      "224", "225", "226", "227", "228", "229", "230",
+			      "231", "232", "233", "234", "235", "236", "237",
+			      "238", "239", "240", "241", "242", "243", "244",
+			      "245", "246", "247", "248", "249", "250", "251",
+			      "252", "253", "254", "255", "256", "257", "258",
+			      "259", "260", "261", "262", "263", "264", "265",
+			      "266", "267", "268", "269", "270", "271", "272",
+			      "273", "274", "275", "276", "277", "278", "279",
+			      "280", "281", "282", "283", "284", "285", "286",
+			      "287", "288", "289", "290", "291", "292", "293",
+			      "294", "295", "296", "297", "298", "299", "300",
+			      "301", "302", "303", "304", "305", "306", "307",
+			      "308", "309", "310", "311", "312", "313", "314",
+			      "315", "316", "317", "318", "319", "320", "321",
+			      "322", "323";
+	};
+};
+
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
new file mode 100644
index 0000000..16b872e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
@@ -0,0 +1,1096 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/reset/ti-syscon.h>
+#include <dt-bindings/clock/mt7988-clk.h>
+#include <dt-bindings/pinctrl/mt65xx.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/regulator/richtek,rt5190a-regulator.h>
+#include <dt-bindings/power/mt7988-power.h>
+
+/ {
+	compatible = "mediatek,mt7988-rfb";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a73";
+			enable-method = "psci";
+			reg = <0x0>;
+			clocks = <&mcusys CK_MCU_ARM_DIV_SEL>,
+				 <&topckgen CK_TOP_CB_NET1_D4>,
+				 <&apmixedsys CK_APMIXED_ARM_B>,
+				 <&mcusys CK_MCU_BUS_DIV_SEL>,
+				 <&apmixedsys CK_APMIXED_CCIPLL2_B>;
+			clock-names = "cpu", "intermediate", "armpll", "cci",
+				      "ccipll";
+			operating-points-v2 = <&cluster0_opp>;
+			nvmem-cells = <&cpufreq_calibration>;
+			nvmem-cell-names = "calibration-data";
+		};
+
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a73";
+			enable-method = "psci";
+			reg = <0x1>;
+			clocks = <&mcusys CK_MCU_ARM_DIV_SEL>,
+				 <&topckgen CK_TOP_CB_NET1_D4>,
+				 <&apmixedsys CK_APMIXED_ARM_B>,
+				 <&mcusys CK_MCU_BUS_DIV_SEL>,
+				 <&apmixedsys CK_APMIXED_CCIPLL2_B>;
+			clock-names = "cpu", "intermediate", "armpll", "cci",
+				      "ccipll";
+			operating-points-v2 = <&cluster0_opp>;
+			nvmem-cells = <&cpufreq_calibration>;
+			nvmem-cell-names = "calibration-data";
+		};
+
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a73";
+			enable-method = "psci";
+			reg = <0x2>;
+			clocks = <&mcusys CK_MCU_ARM_DIV_SEL>,
+				 <&topckgen CK_TOP_CB_NET1_D4>,
+				 <&apmixedsys CK_APMIXED_ARM_B>,
+				 <&mcusys CK_MCU_BUS_DIV_SEL>,
+				 <&apmixedsys CK_APMIXED_CCIPLL2_B>;
+			clock-names = "cpu", "intermediate", "armpll", "cci",
+				      "ccipll";
+			operating-points-v2 = <&cluster0_opp>;
+			nvmem-cells = <&cpufreq_calibration>;
+			nvmem-cell-names = "calibration-data";
+		};
+
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a73";
+			enable-method = "psci";
+			reg = <0x3>;
+			clocks = <&mcusys CK_MCU_ARM_DIV_SEL>,
+				 <&topckgen CK_TOP_CB_NET1_D4>,
+				 <&apmixedsys CK_APMIXED_ARM_B>,
+				 <&mcusys CK_MCU_BUS_DIV_SEL>,
+				 <&apmixedsys CK_APMIXED_CCIPLL2_B>;
+			clock-names = "cpu", "intermediate", "armpll", "cci",
+				      "ccipll";
+			operating-points-v2 = <&cluster0_opp>;
+			nvmem-cells = <&cpufreq_calibration>;
+			nvmem-cell-names = "calibration-data";
+		};
+
+		cluster0_opp: opp_table0 {
+			compatible = "operating-points-v2";
+			opp-shared;
+			opp00 {
+				opp-hz = /bits/ 64 <800000000>;
+				opp-microvolt = <850000>;
+			};
+			opp01 {
+				opp-hz = /bits/ 64 <1100000000>;
+				opp-microvolt = <850000>;
+			};
+			opp02 {
+				opp-hz = /bits/ 64 <1500000000>;
+				opp-microvolt = <850000>;
+			};
+			opp03 {
+				opp-hz = /bits/ 64 <1800000000>;
+				opp-microvolt = <900000>;
+			};
+		};
+	};
+
+	thermal-zones {
+		cpu_thermal: cpu-thermal {
+			polling-delay-passive = <1000>;
+			polling-delay = <1000>;
+			thermal-sensors = <&lvts 0>;
+			trips {
+				cpu_trip_crit: crit {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+
+				cpu_trip_hot: hot {
+					temperature = <120000>;
+					hysteresis = <2000>;
+					type = "hot";
+				};
+
+				cpu_trip_active_high: active-high {
+					temperature = <115000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+
+				cpu_trip_active_low: active-low {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "active";
+				};
+
+				cpu_trip_passive: passive {
+					temperature = <40000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+			};
+
+			cooling-maps {
+				cpu-active-high {
+				/* active: set fan to cooling level 2 */
+					cooling-device = <&fan 2 2>;
+					trip = <&cpu_trip_active_high>;
+				};
+
+				cpu-active-low {
+				/* active: set fan to cooling level 1 */
+					cooling-device = <&fan 1 1>;
+					trip = <&cpu_trip_active_low>;
+				};
+
+				cpu-passive {
+				/* passive: set fan to cooling level 0 */
+					cooling-device = <&fan 0 0>;
+					trip = <&cpu_trip_passive>;
+				};
+			};
+
+		};
+	};
+
+	mmc0: mmc@11230000 {
+		compatible = "mediatek,mt7986-mmc";
+		reg = <0 0x11230000 0 0x1000>,
+		      <0 0x11D60000 0 0x1000>;
+		interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&infracfg_ao CK_INFRA_MSDC400>,
+			 <&infracfg_ao CK_INFRA_MSDC2_HCK>,
+			 <&infracfg_ao CK_INFRA_133M_MSDC_0_HCK>,
+			 <&infracfg_ao CK_INFRA_66M_MSDC_0_HCK>;
+		clock-names = "source", "hclk", "ahb_cg", "axi_cg";
+		status = "disabled";
+	};
+
+	wed: wed@15010000 {
+		compatible = "mediatek,wed";
+		wed_num = <3>;
+		/* add this property for wed get the pci slot number. */
+		pci_slot_map = <0>, <1>, <2>;
+		reg = <0 0x15010000 0 0x2000>,
+		      <0 0x15012000 0 0x2000>,
+		      <0 0x15014000 0 0x2000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wed2: wed2@15012000 {
+		compatible = "mediatek,wed2";
+		wed_num = <3>;
+		/* add this property for wed get the pci slot number. */
+		reg = <0 0x15010000 0 0x2000>,
+		      <0 0x15012000 0 0x2000>,
+		      <0 0x15014000 0 0x2000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wed3: wed3@15014000 {
+		compatible = "mediatek,wed3";
+		wed_num = <3>;
+		/* add this property for wed get the pci slot number. */
+		reg = <0 0x15010000 0 0x2000>,
+		      <0 0x15012000 0 0x2000>,
+		      <0 0x15014000 0 0x2000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wdma: wdma@15104800 {
+		compatible = "mediatek,wed-wdma";
+		reg = <0 0x15104800 0 0x400>,
+		      <0 0x15104c00 0 0x400>,
+		      <0 0x15105000 0 0x400>;
+	};
+
+	ap2woccif: ap2woccif@151A5000 {
+		compatible = "mediatek,ap2woccif";
+		reg = <0 0x151A5000 0 0x1000>,
+		      <0 0x152A5000 0 0x1000>,
+		      <0 0x153A5000 0 0x1000>;
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 211 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 212 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	wocpu0_ilm: wocpu0_ilm@151E0000 {
+		compatible = "mediatek,wocpu0_ilm";
+		reg = <0 0x151E0000 0 0x8000>;
+	};
+
+	wocpu1_ilm: wocpu1_ilm@152E0000 {
+		compatible = "mediatek,wocpu1_ilm";
+		reg = <0 0x152E0000 0 0x8000>;
+	};
+
+	wocpu2_ilm: wocpu2_ilm@153E0000 {
+		compatible = "mediatek,wocpu2_ilm";
+		reg = <0 0x153E0000 0 0x8000>;
+	};
+
+	wocpu_dlm: wocpu_dlm@151E8000 {
+		compatible = "mediatek,wocpu_dlm";
+		reg = <0 0x151E8000 0 0x2000>,
+		      <0 0x152E8000 0 0x2000>,
+		      <0 0x153E8000 0 0x2000>;
+
+		resets = <&ethsysrst 0>;
+		reset-names = "wocpu_rst";
+	};
+
+	cpu_boot: wocpu_boot@15194000 {
+		compatible = "mediatek,wocpu_boot";
+		reg = <0 0x15194000 0 0x1000>,
+		      <0 0x15294000 0 0x1000>,
+		      <0 0x15394000 0 0x1000>;
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		/* 192 KiB reserved for ARM Trusted Firmware (BL31) */
+		secmon_reserved: secmon@43000000 {
+			reg = <0 0x43000000 0 0x30000>;
+			no-map;
+		};
+
+		wmcpu_emi: wmcpu-reserved@47CC0000 {
+			compatible = "mediatek,wmcpu-reserved";
+			no-map;
+			reg = <0 0x47CC0000 0 0x00100000>;
+		};
+
+		wocpu0_emi: wocpu0_emi@4F600000 {
+			compatible = "mediatek,wocpu0_emi";
+			no-map;
+			reg = <0 0x4F600000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu1_emi: wocpu1_emi@4F640000 {
+			compatible = "mediatek,wocpu1_emi";
+			no-map;
+			reg = <0 0x4F640000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu2_emi: wocpu2_emi@4F680000 {
+			compatible = "mediatek,wocpu2_emi";
+			no-map;
+			reg = <0 0x4F680000 0 0x40000>;
+			shared = <0>;
+		};
+
+		wocpu_data: wocpu_data@4F700000 {
+			compatible = "mediatek,wocpu_data";
+			no-map;
+			reg = <0 0x4F700000 0 0x800000>;
+			shared = <1>;
+		};
+	};
+
+	psci {
+		compatible  = "arm,psci-0.2";
+		method      = "smc";
+	};
+
+	system_clk: dummy_system_clk {
+		compatible = "fixed-clock";
+		clock-frequency = <40000000>;
+		#clock-cells = <0>;
+	};
+
+	uart_clk: dummy_uart_clk {
+		compatible = "fixed-clock";
+		clock-frequency = <40000000>;
+		#clock-cells = <0>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+
+	};
+
+	tops: tops@09100000 {
+		compatible = "mediatek,tops";
+		reg = <0 0x09100000 0 0x01000000>;
+		reg-names = "tops-base";
+		clocks = <&topckgen CK_TOP_BUS_TOPS_SEL>,
+			 <&topckgen CK_TOP_TOPS_P2_26M_SEL>,
+			 <&topckgen CK_TOP_NETSYS_TOPS_400M_SEL>,
+			 <&topckgen CK_TOP_NPU_TOPS_SEL>,
+			 <&topckgen CK_TOP_CK_NPU_SEL_CM_TOPS_SEL>;
+		clock-names = "bus", "sram", "xdma", "offload", "mgmt";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "tdma-tx-pause", "mbox";
+		topmisc = <&topmisc>;
+		fe_mem = <&eth>;
+		topckgen = <&topckgen>;
+	};
+	hpdma1: hpdma@09106000 {
+		compatible = "mediatek,hpdma-top";
+		reg = <0 0x09106000 0 0x1000>;
+		reg-names = "base";
+	};
+	hpdma2: hpdma@09606000 {
+		compatible = "mediatek,hpdma-sub";
+		reg = <0 0x09606000 0 0x1000>;
+		reg-names = "base";
+	};
+
+	watchdog: watchdog@1001c000 {
+		compatible = "mediatek,mt7622-wdt",
+			     "mediatek,mt6589-wdt",
+			     "syscon";
+		reg = <0 0x1001c000 0 0x1000>;
+		interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		#reset-cells = <1>;
+	};
+
+	phyfw: phy-firmware@f000000 {
+		compatible = "mediatek,2p5gphy-fw";
+		reg = <0 0x0f000000 0 0x8000>,
+		      <0 0x0f100000 0 0x20000>,
+		      <0 0x0f0f0000 0 0x200>;
+	};
+
+	gic: interrupt-controller@c000000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-parent = <&gic>;
+		interrupt-controller;
+		reg = <0 0x0c000000 0 0x40000>,  /* GICD */
+		      <0 0x0c080000 0 0x200000>; /* GICR */
+
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	trng: trng@1020f000 {
+		compatible = "mediatek,mt7988-rng";
+	};
+
+	uart0: serial@11000000 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11000000 0 0x100>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart1: serial@11000100 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11000100 0 0x100>;
+		interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	uart2: serial@11000200 {
+		compatible = "mediatek,mt7986-uart",
+			     "mediatek,mt6577-uart";
+		reg = <0 0x11000200 0 0x100>;
+		interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&uart_clk>;
+		status = "disabled";
+	};
+
+	i2c0: i2c@11003000 {
+		compatible = "mediatek,mt7988-i2c",
+			"mediatek,mt7981-i2c";
+		reg = <0 0x11003000 0 0x1000>,
+		      <0 0x10217080 0 0x80>;
+		interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+		clock-div = <1>;
+		clocks = <&system_clk>,
+			 <&system_clk>;
+		clock-names = "main", "dma";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c1: i2c@11004000 {
+		compatible = "mediatek,mt7988-i2c",
+			"mediatek,mt7981-i2c";
+		reg = <0 0x11004000 0 0x1000>,
+		      <0 0x10217100 0 0x80>;
+		interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+		clock-div = <1>;
+		clocks = <&system_clk>,
+			 <&system_clk>;
+		clock-names = "main", "dma";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c2: i2c@11005000 {
+		compatible = "mediatek,mt7988-i2c",
+			"mediatek,mt7981-i2c";
+		reg = <0 0x11005000 0 0x1000>,
+		      <0 0x10217180 0 0x80>;
+		interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+		clock-div = <1>;
+		clocks = <&system_clk>,
+			 <&system_clk>;
+		clock-names = "main", "dma";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	pwm: pwm@10048000 {
+		compatible = "mediatek,mt7988-pwm";
+		reg = <0 0x10048000 0 0x1000>;
+		#pwm-cells = <2>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "top", "main", "pwm1", "pwm2", "pwm3",
+			      "pwm4","pwm5","pwm6","pwm7","pwm8";
+		status = "disabled";
+	};
+
+	fan: pwm-fan {
+		compatible = "pwm-fan";
+		/* cooling level (0, 1, 2) : (0% duty, 50% duty, 100% duty) */
+		cooling-levels = <0 128 255>;
+		#cooling-cells = <2>;
+		#thermal-sensor-cells = <1>;
+		status = "disabled";
+	};
+
+	lvts: lvts@1100a000 {
+		compatible = "mediatek,mt7988-lvts";
+		#thermal-sensor-cells = <1>;
+		reg = <0 0x1100a000 0 0x1000>;
+		clocks = <&system_clk>;
+		clock-names = "lvts_clk";
+		nvmem-cells = <&lvts_calibration>;
+		nvmem-cell-names = "e_data1";
+	};
+
+	crypto: crypto@15600000 {
+		compatible = "inside-secure,safexcel-eip197b";
+		reg = <0 0x15600000 0 0x180000>;
+		interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "ring0", "ring1", "ring2", "ring3";
+		status = "okay";
+	};
+
+	pcie0: pcie@11300000 {
+		compatible = "mediatek,mt7988-pcie",
+			     "mediatek,mt7986-pcie";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		reg = <0 0x11300000 0 0x2000>;
+		reg-names = "pcie-mac";
+		linux,pci-domain = <0>;
+		interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x81000000 0x00 0x30000000 0x00
+			  0x30000000 0x00 0x00200000>,
+			 <0x82000000 0x00 0x30200000 0x00
+			  0x30200000 0x00 0x07e00000>;
+		status = "disabled";
+
+		clocks = <&topckgen CK_TOP_PEXTP_P0_SEL>,
+			 <&infracfg_ao CK_INFRA_PCIE_GFMUX_TL_P0>,
+			 <&infracfg_ao CK_INFRA_PCIE_PIPE_P0>,
+			 <&infracfg_ao CK_INFRA_133M_PCIE_CK_P0>,
+			 <&infracfg_ao CK_INFRA_PCIE_PERI_26M_CK_P0>;
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0x7>;
+		interrupt-map = <0 0 0 1 &pcie_intc0 0>,
+				<0 0 0 2 &pcie_intc0 1>,
+				<0 0 0 3 &pcie_intc0 2>,
+				<0 0 0 4 &pcie_intc0 3>;
+		pcie_intc0: interrupt-controller {
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+		};
+	};
+
+	pcie1: pcie@11310000 {
+		compatible = "mediatek,mt7988-pcie",
+			     "mediatek,mt7986-pcie";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		reg = <0 0x11310000 0 0x2000>;
+		reg-names = "pcie-mac";
+		linux,pci-domain = <1>;
+		interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x81000000 0x00 0x38000000 0x00
+			  0x38000000 0x00 0x00200000>,
+			 <0x82000000 0x00 0x38200000 0x00
+			  0x38200000 0x00 0x07e00000>;
+		status = "disabled";
+
+		clocks = <&topckgen CK_TOP_PEXTP_P1_SEL>,
+			 <&infracfg_ao CK_INFRA_PCIE_GFMUX_TL_P1>,
+			 <&infracfg_ao CK_INFRA_PCIE_PIPE_P1>,
+			 <&infracfg_ao CK_INFRA_133M_PCIE_CK_P1>,
+			 <&infracfg_ao CK_INFRA_PCIE_PERI_26M_CK_P1>;
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0x7>;
+		interrupt-map = <0 0 0 1 &pcie_intc1 0>,
+				<0 0 0 2 &pcie_intc1 1>,
+				<0 0 0 3 &pcie_intc1 2>,
+				<0 0 0 4 &pcie_intc1 3>;
+		pcie_intc1: interrupt-controller {
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+		};
+	};
+
+	pcie2: pcie@11280000 {
+		compatible = "mediatek,mt7988-pcie",
+			     "mediatek,mt7986-pcie";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		reg = <0 0x11280000 0 0x2000>;
+		reg-names = "pcie-mac";
+		linux,pci-domain = <3>;
+		interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x81000000 0x00 0x20000000 0x00
+			  0x20000000 0x00 0x00200000>,
+			 <0x82000000 0x00 0x20200000 0x00
+			  0x20200000 0x00 0x07e00000>;
+		status = "disabled";
+
+		clocks = <&topckgen CK_TOP_PEXTP_P2_SEL>,
+			 <&infracfg_ao CK_INFRA_PCIE_GFMUX_TL_P2>,
+			 <&infracfg_ao CK_INFRA_PCIE_PIPE_P2>,
+			 <&infracfg_ao CK_INFRA_133M_PCIE_CK_P2>,
+			 <&infracfg_ao CK_INFRA_PCIE_PERI_26M_CK_P2>,
+			 <&infracfg_ao CK_INFRA_PCIE_PERI_26M_CK_P3>;
+
+		phys = <&xphyu3port0 PHY_TYPE_PCIE>;
+		phy-names = "pcie-phy";
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0x7>;
+		interrupt-map = <0 0 0 1 &pcie_intc2 0>,
+				<0 0 0 2 &pcie_intc2 1>,
+				<0 0 0 3 &pcie_intc2 2>,
+				<0 0 0 4 &pcie_intc2 3>;
+		pcie_intc2: interrupt-controller {
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+		};
+	};
+
+	pcie3: pcie@11290000 {
+		compatible = "mediatek,mt7988-pcie",
+			     "mediatek,mt7986-pcie";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		reg = <0 0x11290000 0 0x2000>;
+		reg-names = "pcie-mac";
+		linux,pci-domain = <2>;
+		interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+		bus-range = <0x00 0xff>;
+		ranges = <0x81000000 0x00 0x28000000 0x00
+			  0x28000000 0x00 0x00200000>,
+			 <0x82000000 0x00 0x28200000 0x00
+			  0x28200000 0x00 0x07e00000>;
+		status = "disabled";
+
+		clocks = <&topckgen CK_TOP_PEXTP_P3_SEL>,
+			 <&infracfg_ao CK_INFRA_PCIE_GFMUX_TL_P3>,
+			 <&infracfg_ao CK_INFRA_PCIE_PIPE_P3>,
+			 <&infracfg_ao CK_INFRA_133M_PCIE_CK_P3>,
+			 <&infracfg_ao CK_INFRA_PCIE_PERI_26M_CK_P3>;
+
+		#interrupt-cells = <1>;
+		interrupt-map-mask = <0 0 0 0x7>;
+		interrupt-map = <0 0 0 1 &pcie_intc3 0>,
+				<0 0 0 2 &pcie_intc3 1>,
+				<0 0 0 3 &pcie_intc3 2>,
+				<0 0 0 4 &pcie_intc3 3>;
+		pcie_intc3: interrupt-controller {
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+		};
+	};
+
+	pio: pinctrl@1001f000 {
+		compatible = "mediatek,mt7988-pinctrl";
+		reg = <0 0x1001f000 0 0x1000>,
+		      <0 0x11c10000 0 0x1000>,
+		      <0 0x11d00000 0 0x1000>,
+		      <0 0x11d20000 0 0x1000>,
+		      <0 0x11e00000 0 0x1000>,
+		      <0 0x11f00000 0 0x1000>,
+		      <0 0x1000b000 0 0x1000>;
+		reg-names = "gpio_base", "iocfg_tr_base", "iocfg_br_base",
+			    "iocfg_rb_base", "iocfg_lb_base", "iocfg_tl_base",
+			    "eint";
+		gpio-controller;
+		#gpio-cells = <2>;
+		gpio-ranges = <&pio 0 0 83>;
+		interrupt-controller;
+		interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <2>;
+	};
+
+	ethsys: syscon@15000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "mediatek,mt7988-ethsys",
+			     "syscon";
+		reg = <0 0x15000000 0 0x1000>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+
+		ethsysrst: reset-controller {
+			compatible = "ti,syscon-reset";
+			#reset-cells = <1>;
+			ti,reset-bits =
+				<0x34 4 0x34 4 0x34 4
+				 (ASSERT_SET | DEASSERT_CLEAR | STATUS_SET)>;
+		};
+	};
+
+	ethwarp: syscon@15031000 {
+		compatible = "mediatek,mt7988-ethwarp", "syscon";
+		reg = <0 0x15031000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	switch0: switch0@15020000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "mediatek,mt7988-switch", "syscon";
+		reg = <0 0x15020000 0 0x8000>;
+	};
+
+	eth: ethernet@15100000 {
+		compatible = "mediatek,mt7988-eth";
+		reg = <0 0x15100000 0 0x80000>,
+		      <0 0x15400000 0 0x380000>;
+		interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "fe", "gp2", "gp1", "wocpu1", "wocpu0",
+			      "sgmii_tx250m", "sgmii_rx250m",
+			      "sgmii_cdr_ref", "sgmii_cdr_fb",
+			      "sgmii2_tx250m", "sgmii2_rx250m",
+			      "sgmii2_cdr_ref", "sgmii2_cdr_fb";
+		mediatek,ethsys = <&ethsys>;
+		mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+		mediatek,usxgmiisys = <&usxgmiisys0>, <&usxgmiisys1>;
+		mediatek,xfi_pextp = <&xfi_pextp0>, <&xfi_pextp1>;
+		mediatek,xfi_pll = <&xfi_pll>;
+		mediatek,infracfg = <&topmisc>;
+		mediatek,toprgu = <&watchdog>;
+		#reset-cells = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	hnat: hnat@15000000 {
+		compatible = "mediatek,mtk-hnat_v5";
+		reg = <0 0x15100000 0 0x80000>;
+		resets = <&ethsys 0>;
+		reset-names = "mtketh";
+		status = "disabled";
+	};
+
+	sgmiisys0: syscon@10060000 {
+		compatible = "mediatek,mt7988-sgmiisys",
+			     "mediatek,mt7988-sgmiisys_0",
+			     "syscon";
+		reg = <0 0x10060000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	sgmiisys1: syscon@10070000 {
+		compatible = "mediatek,mt7988-sgmiisys",
+			     "mediatek,mt7988-sgmiisys_1",
+			     "syscon";
+		reg = <0 0x10070000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	usxgmiisys0: usxgmiisys@10080000 {
+		compatible = "mediatek,mt7988-usxgmiisys",
+			     "mediatek,mt7988-usxgmiisys_0",
+			     "syscon";
+		reg = <0 0x10080000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	usxgmiisys1: usxgmiisys@10081000 {
+		compatible = "mediatek,mt7988-usxgmiisys",
+			     "mediatek,mt7988-usxgmiisys_1",
+			     "syscon";
+		reg = <0 0x10081000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	xfi_pextp0: xfi_pextp@11f20000 {
+		compatible = "mediatek,mt7988-xfi_pextp",
+			     "mediatek,mt7988-xfi_pextp_0",
+			     "syscon";
+		reg = <0 0x11f20000 0 0x10000>;
+		#clock-cells = <1>;
+	};
+
+	xfi_pextp1: xfi_pextp@11f30000 {
+		compatible = "mediatek,mt7988-xfi_pextp",
+			     "mediatek,mt7988-xfi_pextp_1",
+			     "syscon";
+		reg = <0 0x11f30000 0 0x10000>;
+		#clock-cells = <1>;
+	};
+
+	xfi_pll: xfi_pll@11f40000 {
+		compatible = "mediatek,mt7988-xfi_pll", "syscon";
+		reg = <0 0x11f40000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topmisc: topmisc@11d10000 {
+		compatible = "mediatek,mt7988-topmisc", "syscon",
+			     "mediatek,mt7988-power-controller";
+		reg = <0 0x11d10000 0 0x10000>;
+		#clock-cells = <1>;
+		#power-domain-cells = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		/* power domain of the SoC */
+		tops0@MT7988_POWER_DOMAIN_TOPS0 {
+			reg = <MT7988_POWER_DOMAIN_TOPS0>;
+			#power-domain-cells = <0>;
+		};
+		tops1@MT7988_POWER_DOMAIN_TOPS1 {
+			reg = <MT7988_POWER_DOMAIN_TOPS1>;
+			#power-domain-cells = <0>;
+		};
+		eth2p5@MT7988_POWER_DOMAIN_ETH2P5 {
+			reg = <MT7988_POWER_DOMAIN_ETH2P5>;
+			#power-domain-cells = <0>;
+		};
+	};
+
+	snand: snfi@11001000 {
+		compatible = "mediatek,mt7986-snand";
+		reg = <0 0x11001000 0 0x1000>, <0 0x11002000 0 0x1000>;
+		reg-names = "nfi", "ecc";
+		interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "nfi_clk", "pad_clk", "ecc_clk", "nfi_hclk";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	wbsys: wbsys@18000000 {
+		compatible = "mediatek,wbsys";
+		reg = <0 0x18000000 0  0x1000000>;
+		linux,pci-domain = <4>;
+		interrupts = <GIC_SPI 213 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
+		chip_id = <0x7981>;
+	};
+
+	wed_pcie: wed_pcie@10003000 {
+		compatible = "mediatek,wed_pcie";
+		reg = <0 0x10003000 0 0x10>;
+	};
+
+	spi0: spi@11007000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x11007000 0 0x100>;
+		interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_104M_SPI0>,
+			 <&infracfg_ao CK_INFRA_66M_SPI0_HCK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi1: spi@11008000 {
+		compatible = "mediatek,ipm-spi-single";
+		reg = <0 0x11008000 0 0x100>;
+		interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_104M_SPI1>,
+			 <&infracfg_ao CK_INFRA_66M_SPI1_HCK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	spi2: spi@11009000 {
+		compatible = "mediatek,ipm-spi-quad";
+		reg = <0 0x11009000 0 0x100>;
+		interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&topckgen CK_TOP_CB_M_D2>,
+			 <&topckgen CK_TOP_SPI_SEL>,
+			 <&infracfg_ao CK_INFRA_104M_SPI2_BCK>,
+			 <&infracfg_ao CK_INFRA_66M_SPI2_HCK>;
+		clock-names = "parent-clk", "sel-clk", "spi-clk", "spi-hclk";
+		status = "disabled";
+	};
+
+	consys: consys@10000000 {
+		compatible = "mediatek,mt7981-consys";
+		reg = <0 0x10000000 0 0x8600000>;
+		memory-region = <&wmcpu_emi>;
+	};
+
+	xhci0: xhci@11190000 {
+		compatible = "mediatek,mt7988-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11190000 0 0x2e00>,
+		      <0 0x11193e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&xphyu2port0 PHY_TYPE_USB2>,
+		       <&xphyu3port0 PHY_TYPE_USB3>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		status = "okay";
+	};
+
+	usbxphy: usb-phy@11e10000 {
+		compatible = "mediatek,mt7988",
+			     "mediatek,xsphy";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		xphyu2port0: usb-phy@11e10000 {
+			reg = <0 0x11e10000 0 0x400>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		xphyu3port0: usb-phy@11e13000 {
+			reg = <0 0x11e13400 0 0x500>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			mediatek,syscon-type = <&topmisc 0x218 0>;
+			status = "okay";
+		};
+	};
+
+	xhci1: xhci@11200000 {
+		compatible = "mediatek,mt7988-xhci",
+			     "mediatek,mtk-xhci";
+		reg = <0 0x11200000 0 0x2e00>,
+		      <0 0x11203e00 0 0x0100>;
+		reg-names = "mac", "ippc";
+		interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&tphyu2port0 PHY_TYPE_USB2>,
+		       <&tphyu3port0 PHY_TYPE_USB3>;
+		clocks = <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>,
+			 <&system_clk>;
+		clock-names = "sys_ck",
+			      "xhci_ck",
+			      "ref_ck",
+			      "mcu_ck",
+			      "dma_ck";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		status = "okay";
+	};
+
+	usbtphy: usb-phy@11c50000 {
+		compatible = "mediatek,mt7988",
+			     "mediatek,generic-tphy-v2";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "okay";
+
+		tphyu2port0: usb-phy@11c50000 {
+			reg = <0 0x11c50000 0 0x700>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+
+		tphyu3port0: usb-phy@11c50700 {
+			reg = <0 0x11c50700 0 0x900>;
+			clocks = <&system_clk>;
+			clock-names = "ref";
+			#phy-cells = <1>;
+			status = "okay";
+		};
+	};
+
+	clk40m: oscillator@0 {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <40000000>;
+		clock-output-names = "clkxtal";
+	};
+
+	infracfg_ao: infracfg_ao@10001000 {
+		compatible = "mediatek,mt7988-infracfg_ao", "syscon";
+		reg = <0 0x10001000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	infracfg: infracfg@10209000 {
+		compatible = "mediatek,mt7988-infracfg", "syscon";
+		reg = <0 0x10209000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	topckgen: topckgen@1001B000 {
+		compatible = "mediatek,mt7988-topckgen", "syscon";
+		reg = <0 0x1001B000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	apmixedsys: apmixedsys@1001E000 {
+		compatible = "mediatek,mt7988-apmixedsys", "syscon";
+		reg = <0 0x1001E000 0 0x1000>;
+		#clock-cells = <1>;
+	};
+
+	mcusys: mcusys@100E0000 {
+	compatible = "mediatek,mt7988-mcusys", "syscon";
+	reg = <0 0x100E0000 0 0x1000>;
+	#clock-cells = <1>;
+	};
+
+	clkitg: clkitg {
+		compatible = "simple-bus";
+	};
+
+	efuse: efuse@11f50000 {
+		compatible = "mediatek,efuse";
+		reg = <0 0x11f50000 0 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lvts_calibration: calib@918 {
+			reg = <0x918 0x28>;
+		};
+		phy_calibration_p0: calib@940 {
+			reg = <0x940 0x10>;
+		};
+		phy_calibration_p1: calib@954 {
+			reg = <0x954 0x10>;
+		};
+		phy_calibration_p2: calib@968 {
+			reg = <0x968 0x10>;
+		};
+		phy_calibration_p3: calib@97c {
+			reg = <0x97c 0x10>;
+		};
+		cpufreq_calibration: calib@278 {
+			reg = <0x278 0x1>;
+		};
+	};
+};
+
+#include "mt7988-clkitg.dtsi"
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-emmc.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-emmc.dts
new file mode 100644
index 0000000..21eab01
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-emmc.dts
@@ -0,0 +1,271 @@
+// 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 MT7988A DSA 10G eMMC RFB";
+	compatible = "mediatek,mt7988a-dsa-10g-emmc",
+		     /* Reserve this for DVFS if creating new dts */
+		     "mediatek,mt7988";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+			    earlycon=uart8250,mmio32,0x11000000 \
+			    root=PARTLABEL=rootfs rootwait \
+			    rootfstype=squashfs,f2fs pci=pcie_bus_perf";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	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>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	status = "okay";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	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";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	mmc0_pins_default: mmc0-pins-default {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_51";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		phy0: ethernet-phy@0 {
+			reg = <0>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 71 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 72 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7988";
+			reg = <31>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "10gbase-kr";
+
+					fixed-link {
+						speed = <10000>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <8>;
+	max-frequency = <200000000>;
+	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
+	hs400-ds-delay = <0x12814>;
+	vqmmc-supply = <&reg_1p8v>;
+	vmmc-supply = <&reg_3p3v>;
+	non-removable;
+	no-sd;
+	no-sdio;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sd.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sd.dts
new file mode 100644
index 0000000..bc2d427
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-sd.dts
@@ -0,0 +1,258 @@
+// 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 MT7988A DSA 10G SD RFB";
+	compatible = "mediatek,mt7988a-dsa-10g-sd",
+		     /* Reserve this for DVFS if creating new dts */
+		     "mediatek,mt7988";
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+			    earlycon=uart8250,mmio32,0x11000000 \
+			    root=PARTLABEL=rootfs rootwait \
+			    rootfstype=squashfs,f2fs pci=pcie_bus_perf";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	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>;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	status = "okay";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	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";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	mmc0_pins_default: mmc0-pins-default {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+
+	mmc0_pins_uhs: mmc0-pins-uhs {
+		mux {
+			function = "flash";
+			groups = "emmc_45";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		phy0: ethernet-phy@0 {
+			reg = <0>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 71 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 72 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7988";
+			reg = <31>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "10gbase-kr";
+
+					fixed-link {
+						speed = <10000>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
+
+&mmc0 {
+	pinctrl-names = "default", "state_uhs";
+	pinctrl-0 = <&mmc0_pins_default>;
+	pinctrl-1 = <&mmc0_pins_uhs>;
+	bus-width = <4>;
+	max-frequency = <52000000>;
+	cap-sd-highspeed;
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_3p3v>;
+	no-mmc;
+	no-sdio;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-snfi-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-snfi-nand.dts
new file mode 100644
index 0000000..15d38ec
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-snfi-nand.dts
@@ -0,0 +1,279 @@
+// 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 MT7988A DSA 10G SNFI-NAND RFB";
+	compatible = "mediatek,mt7988a-dsa-10g-snfi-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";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	nmbm_snfi {
+		compatible = "generic,nmbm";
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		lower-mtd-device = <&snand>;
+		forced-create;
+		empty-page-ecc-protected;
+
+		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 0x4000000>;
+			};
+		};
+	};
+
+	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>;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	status = "okay";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	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";
+		};
+	};
+
+	snfi_pins: snfi-pins {
+		mux {
+			function = "flash";
+			groups = "snfi";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&snand {
+	pinctrl-names = "default";
+	/* pin shared with spic */
+	pinctrl-0 = <&snfi_pins>;
+	status = "okay";
+	mediatek,quad-spi;
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		phy0: ethernet-phy@0 {
+			reg = <0>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 71 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 72 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7988";
+			reg = <31>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "10gbase-kr";
+
+					fixed-link {
+						speed = <10000>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
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
new file mode 100644
index 0000000..6a289ff
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts
@@ -0,0 +1,292 @@
+// 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 MT7988A DSA 10G SPIM-NAND RFB";
+	compatible = "mediatek,mt7988a-dsa-10g-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";
+	};
+
+	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 0x4000000>;
+			};
+		};
+	};
+
+	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>;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	status = "okay";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	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_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		phy0: ethernet-phy@0 {
+			reg = <0>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 71 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 72 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7988";
+			reg = <31>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "10gbase-kr";
+
+					fixed-link {
+						speed = <10000>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
new file mode 100644
index 0000000..4edf1f0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nor.dts
@@ -0,0 +1,276 @@
+// 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 MT7988A DSA 10G SPIM-NOR RFB";
+	compatible = "mediatek,mt7988a-dsa-10g-spim-nor",
+		     /* 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";
+	};
+
+	memory {
+		reg = <0 0x40000000 0 0x10000000>;
+	};
+
+	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>;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	status = "okay";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&spi2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2_flash_pins>;
+	status = "okay";
+	spi_nor@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		spi-cal-enable;
+		spi-cal-mode = "read-data";
+		spi-cal-datalen = <7>;
+		spi-cal-data = /bits/ 8 <
+			0x53 0x46 0x5F 0x42 0x4F 0x4F 0x54>; /* SF_BOOT */
+		spi-cal-addrlen = <1>;
+		spi-cal-addr = /bits/ 32 <0x0>;
+		reg = <0>;
+		spi-max-frequency = <52000000>;
+
+		partition@00000 {
+			label = "BL2";
+			reg = <0x00000 0x0040000>;
+		};
+		partition@40000 {
+			label = "u-boot-env";
+			reg = <0x40000 0x0010000>;
+		};
+		factory: partition@50000 {
+			label = "Factory";
+			reg = <0x50000 0x00B0000>;
+		};
+		partition@100000 {
+			label = "FIP";
+			reg = <0x100000 0x0080000>;
+		};
+		partition@180000 {
+			label = "firmware";
+			reg = <0x180000 0xE00000>;
+		};
+	};
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	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";
+		};
+	};
+
+	spic_pins: spi1-pins {
+		mux {
+			function = "spi";
+			groups = "spi1_1";
+		};
+	};
+
+	spi2_flash_pins: spi2-pins {
+		mux {
+			function = "spi";
+			groups = "spi2", "spi2_wp_hold";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		phy0: ethernet-phy@0 {
+			reg = <0>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 71 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 72 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7988";
+			reg = <31>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "10gbase-kr";
+
+					fixed-link {
+						speed = <10000>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
+
+&wed {
+	dy_txbm_enable = "true";
+	dy_txbm_budge = <8>;
+	txbm_init_sz = <10>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts
new file mode 100644
index 0000000..ed60643
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-e2p5g-spim-nand.dts
@@ -0,0 +1,365 @@
+// 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 MT7988 DSA external-2.5G SPIM-NAND RFB";
+	compatible = "mediatek,mt7988a-dsa-e2p5g-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";
+	};
+
+	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 0x4000000>;
+			};
+		};
+	};
+
+	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>;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	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";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	i2c0_pins: i2c0-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c0_1";
+		};
+	};
+
+	i2c1_pins: i2c1-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c1_0";
+		};
+	};
+
+	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_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "2500base-x";
+		phy-handle = <&phy13>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "2500base-x";
+		phy-handle = <&phy5>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		phy5: phy@5 {
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reg = <5>;
+			reset-gpios = <&pio 0 1>;
+			reset-assert-us = <600>;
+			reset-deassert-us = <20000>;
+		};
+
+		phy13: phy@13 {
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reg = <13>;
+			reset-gpios = <&pio 1 1>;
+			reset-assert-us = <600>;
+			reset-deassert-us = <20000>;
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7988";
+			reg = <31>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "10gbase-kr";
+
+					fixed-link {
+						speed = <10000>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
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
new file mode 100644
index 0000000..d07634b
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-dsa-i2p5g-spim-nand.dts
@@ -0,0 +1,282 @@
+// 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 MT7988 DSA internal-2.5G SPIM-NAND RFB";
+	compatible = "mediatek,mt7988a-dsa-i2p5g-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";
+	};
+
+	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 0x4000000>;
+			};
+		};
+	};
+
+	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>;
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	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_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&usxgmiisys1 {
+	internal_2500;
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		phy0: ethernet-phy@0 {
+			reg = <15>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			phy-mode = "10gbase-kr";
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+		};
+
+		switch@0 {
+			compatible = "mediatek,mt7988";
+			reg = <31>;
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port@0 {
+					reg = <0>;
+					label = "lan0";
+				};
+
+				port@1 {
+					reg = <1>;
+					label = "lan1";
+				};
+
+				port@2 {
+					reg = <2>;
+					label = "lan2";
+				};
+
+				port@3 {
+					reg = <3>;
+					label = "lan3";
+				};
+
+				port@6 {
+					reg = <6>;
+					label = "cpu";
+					ethernet = <&gmac0>;
+					phy-mode = "10gbase-kr";
+
+					fixed-link {
+						speed = <10000>;
+						full-duplex;
+						pause;
+					};
+				};
+			};
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "lan";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-sfp-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-sfp-spim-nand.dts
new file mode 100644
index 0000000..4335fcf
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-sfp-spim-nand.dts
@@ -0,0 +1,405 @@
+// 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 MT7988 GSW 10G SFP SPIM-NAND RFB";
+	compatible = "mediatek,mt7988a-gsw-10g-sfp-spim-snand",
+		     /* Reserve this for DVFS if creating new dts */
+		     "mediatek,mt7988";
+
+	chosen {
+		bootargs = "console=ttyS0,115200n1 loglevel=8  \
+			    earlycon=uart8250,mmio32,0x11000000";
+	};
+
+	gsw: gsw@0 {
+		compatible = "mediatek,mt753x";
+		mediatek,sysctrl = <&ethwarp>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	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 0x4000000>;
+			};
+		};
+	};
+
+	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>;
+	};
+
+	sfp_esp0: sfp@0 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c2>;
+		tx-disable-gpios = <&pio 29 0>;
+	};
+
+	sfp_esp1: sfp@1 {
+		compatible = "sff,sfp";
+		i2c-bus = <&i2c1>;
+		tx-disable-gpios = <&pio 36 0>;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	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";
+};
+
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+	status = "okay";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	i2c0_pins: i2c0-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c0_1";
+		};
+	};
+
+	i2c1_pins: i2c1-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c1_sfp";
+		};
+	};
+
+	i2c2_pins: i2c2-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c2_0";
+		};
+	};
+
+	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_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		managed = "in-band-status";
+		sfp = <&sfp_esp1>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		managed = "in-band-status";
+		sfp = <&sfp_esp0>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
+
+&gsw {
+	mediatek,mdio = <&mdio>;
+	mediatek,portmap = "llllw";
+	mediatek,mdio_master_pinmux = <1>;
+	interrupt-parent = <&gic>;
+	interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port6: port@6 {
+		compatible = "mediatek,mt753x-port";
+		mediatek,ssc-on;
+		phy-mode = "10gbase-kr";
+		reg = <6>;
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+
+	mdio1: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		gsw_phy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <0>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p0>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy1: ethernet-phy@1 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <1>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p1>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy2: ethernet-phy@2 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <2>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p2>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy3: ethernet-phy@3 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <3>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p3>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand-4pcie.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand-4pcie.dts
new file mode 100644
index 0000000..86221c2
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand-4pcie.dts
@@ -0,0 +1,398 @@
+// 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 MT7988 GSW 10G SPIM-NAND 4PCIe RFB";
+	compatible = "mediatek,mt7988a-gsw-10g-spim-snand-4pcie",
+		     /* 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";
+	};
+
+	gsw: gsw@0 {
+		compatible = "mediatek,mt753x";
+		mediatek,sysctrl = <&ethwarp>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	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 0x4000000>;
+			};
+		};
+	};
+
+	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>;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	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";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "okay";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	i2c0_pins: i2c0-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c0_1";
+		};
+	};
+
+	i2c1_pins: i2c1-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c1_0";
+		};
+	};
+
+	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_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&xhci0 {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		phy0: ethernet-phy@0 {
+			reg = <0>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 71 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 72 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
+
+&gsw {
+	mediatek,mdio = <&mdio>;
+	mediatek,portmap = "llllw";
+	mediatek,mdio_master_pinmux = <1>;
+	interrupt-parent = <&gic>;
+	interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port6: port@6 {
+		compatible = "mediatek,mt753x-port";
+		mediatek,ssc-on;
+		phy-mode = "10gbase-kr";
+		reg = <6>;
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+
+	mdio1: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		gsw_phy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <0>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p0>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy1: ethernet-phy@1 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <1>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p1>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy2: ethernet-phy@2 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <2>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p2>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy3: ethernet-phy@3 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <3>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p3>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand.dts b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand.dts
new file mode 100644
index 0000000..ef4cd4d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988a-gsw-10g-spim-nand.dts
@@ -0,0 +1,395 @@
+// 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 MT7988 GSW 10G SPIM-NAND RFB";
+	compatible = "mediatek,mt7988a-gsw-10g-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";
+	};
+
+	gsw: gsw@0 {
+		compatible = "mediatek,mt753x";
+		mediatek,sysctrl = <&ethwarp>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	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 0x4000000>;
+			};
+		};
+	};
+
+	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>;
+	};
+};
+
+&fan {
+	pwms = <&pwm 0 50000 0>;
+	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";
+};
+
+&pwm {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&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-buswidth = <4>;
+		spi-rx-buswidth = <4>;
+	};
+};
+
+&spi1 {
+	pinctrl-names = "default";
+	/* pin shared with snfi */
+	pinctrl-0 = <&spic_pins>;
+	status = "disabled";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_pins>;
+	status = "okay";
+};
+
+&pcie1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_pins>;
+	status = "okay";
+};
+
+&pcie2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_pins>;
+	status = "disabled";
+};
+
+&pcie3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_pins>;
+	status = "okay";
+};
+
+&pio {
+	i2c0_pins: i2c0-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c0_1";
+		};
+	};
+
+	i2c1_pins: i2c1-pins-g0 {
+		mux {
+			function = "i2c";
+			groups = "i2c1_0";
+		};
+	};
+
+	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_1";
+		};
+	};
+};
+
+&watchdog {
+	status = "disabled";
+};
+
+&eth {
+	status = "okay";
+
+	gmac0: mac@0 {
+		compatible = "mediatek,eth-mac";
+		reg = <0>;
+		phy-mode = "10gbase-kr";
+
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+			pause;
+		};
+	};
+
+	gmac1: mac@1 {
+		compatible = "mediatek,eth-mac";
+		reg = <1>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy0>;
+	};
+
+	gmac2: mac@2 {
+		compatible = "mediatek,eth-mac";
+		reg = <2>;
+		phy-mode = "10gbase-kr";
+		phy-handle = <&phy1>;
+	};
+
+	mdio: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		phy0: ethernet-phy@0 {
+			reg = <0>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 71 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+
+		phy1: ethernet-phy@8 {
+			reg = <8>;
+			compatible = "ethernet-phy-ieee802.3-c45";
+			reset-gpios = <&pio 72 1>;
+			reset-assert-us = <1000000>;
+			reset-deassert-us = <1000000>;
+		};
+	};
+};
+
+&hnat {
+	mtketh-wan = "eth1";
+	mtketh-lan = "eth0";
+	mtketh-lan2 = "eth2";
+	mtketh-max-gmac = <3>;
+	status = "okay";
+};
+
+&gsw {
+	mediatek,mdio = <&mdio>;
+	mediatek,portmap = "llllw";
+	mediatek,mdio_master_pinmux = <1>;
+	interrupt-parent = <&gic>;
+	interrupts = <GIC_SPI 209 IRQ_TYPE_LEVEL_HIGH>;
+	status = "okay";
+
+	port6: port@6 {
+		compatible = "mediatek,mt753x-port";
+		mediatek,ssc-on;
+		phy-mode = "10gbase-kr";
+		reg = <6>;
+		fixed-link {
+			speed = <2500>;
+			full-duplex;
+		};
+	};
+
+	mdio1: mdio-bus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		gsw_phy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <0>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p0>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy1: ethernet-phy@1 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <1>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p1>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy2: ethernet-phy@2 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <2>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p2>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+
+		gsw_phy3: ethernet-phy@3 {
+			compatible = "ethernet-phy-id03a2.9481";
+			reg = <3>;
+			phy-mode = "gmii";
+			rext = "efuse";
+			tx_r50 = "efuse";
+			nvmem-cells = <&phy_calibration_p3>;
+			nvmem-cell-names = "phy-cal-data";
+		};
+	};
+};
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c
index ad1f092..637e2c5 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-bringup.c
@@ -31,7 +31,7 @@
 
 static int bring_up_probe(struct platform_device *pdev)
 {
-	const int NR_CLKS = 300;
+	const int NR_CLKS = 400;
 	char clk_name_buf[16];
 	struct clk *clk;
 	int i, r;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7988.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7988.c
new file mode 100644
index 0000000..b0cefe9
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/clk/mediatek/clk-mt7988.c
@@ -0,0 +1,1195 @@
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include "clk-mux.h"
+
+#include <dt-bindings/clock/mt7988-clk.h>
+
+static DEFINE_SPINLOCK(mt7988_clk_lock);
+
+static const struct mtk_fixed_factor top_divs[] __initconst = {
+	FACTOR(CK_TOP_CB_CKSQ_40M, "cb_cksq_40m", "clkxtal", 1, 1),
+	FACTOR(CK_TOP_CB_M_416M, "cb_m_416m", "mpll", 1, 1),
+	FACTOR(CK_TOP_CB_M_D2, "cb_m_d2", "mpll", 1, 2),
+	FACTOR(CK_TOP_M_D3_D2, "m_d3_d2", "mpll", 1, 2),
+	FACTOR(CK_TOP_CB_M_D4, "cb_m_d4", "mpll", 1, 4),
+	FACTOR(CK_TOP_CB_M_D8, "cb_m_d8", "mpll", 1, 8),
+	FACTOR(CK_TOP_M_D8_D2, "m_d8_d2", "mpll", 1, 16),
+	FACTOR(CK_TOP_CB_MM_720M, "cb_mm_720m", "mmpll", 1, 1),
+	FACTOR(CK_TOP_CB_MM_D2, "cb_mm_d2", "mmpll", 1, 2),
+	FACTOR(CK_TOP_CB_MM_D3_D5, "cb_mm_d3_d5", "mmpll", 1, 15),
+	FACTOR(CK_TOP_CB_MM_D4, "cb_mm_d4", "mmpll", 1, 4),
+	FACTOR(CK_TOP_MM_D6_D2, "mm_d6_d2", "mmpll", 1, 12),
+	FACTOR(CK_TOP_CB_MM_D8, "cb_mm_d8", "mmpll", 1, 8),
+	FACTOR(CK_TOP_CB_APLL2_196M, "cb_apll2_196m", "apll2", 1, 1),
+	FACTOR(CK_TOP_CB_APLL2_D4, "cb_apll2_d4", "apll2", 1, 4),
+	FACTOR(CK_TOP_CB_NET1_D4, "cb_net1_d4", "net1pll", 1, 4),
+	FACTOR(CK_TOP_CB_NET1_D5, "cb_net1_d5", "net1pll", 1, 5),
+	FACTOR(CK_TOP_NET1_D5_D2, "net1_d5_d2", "net1pll", 1, 10),
+	FACTOR(CK_TOP_NET1_D5_D4, "net1_d5_d4", "net1pll", 1, 20),
+	FACTOR(CK_TOP_CB_NET1_D8, "cb_net1_d8", "net1pll", 1, 8),
+	FACTOR(CK_TOP_NET1_D8_D2, "net1_d8_d2", "net1pll", 1, 16),
+	FACTOR(CK_TOP_NET1_D8_D4, "net1_d8_d4", "net1pll", 1, 32),
+	FACTOR(CK_TOP_NET1_D8_D8, "net1_d8_d8", "net1pll", 1, 64),
+	FACTOR(CK_TOP_NET1_D8_D16, "net1_d8_d16", "net1pll", 1, 128),
+	FACTOR(CK_TOP_CB_NET2_800M, "cb_net2_800m", "net2pll", 1, 1),
+	FACTOR(CK_TOP_CB_NET2_D2, "cb_net2_d2", "net2pll", 1, 2),
+	FACTOR(CK_TOP_CB_NET2_D4, "cb_net2_d4", "net2pll", 1, 4),
+	FACTOR(CK_TOP_NET2_D4_D4, "net2_d4_d4", "net2pll", 1, 16),
+	FACTOR(CK_TOP_NET2_D4_D8, "net2_d4_d8", "net2pll", 1, 32),
+	FACTOR(CK_TOP_CB_NET2_D6, "cb_net2_d6", "net2pll", 1, 6),
+	FACTOR(CK_TOP_CB_NET2_D8, "cb_net2_d8", "net2pll", 1, 8),
+	FACTOR(CK_TOP_CB_WEDMCU_208M, "cb_wedmcu_208m", "wedmcupll", 1, 1),
+	FACTOR(CK_TOP_CB_SGM_325M, "cb_sgm_325m", "sgmpll", 1, 1),
+	FACTOR(CK_TOP_CB_NETSYS_850M, "cb_netsys_850m", "netsyspll", 1, 1),
+	FACTOR(CK_TOP_CB_MSDC_400M, "cb_msdc_400m", "msdcpll", 1, 1),
+	FACTOR(CK_TOP_CKSQ_40M_D2, "cksq_40m_d2", "cb_cksq_40m", 1, 2),
+	FACTOR(CK_TOP_CB_RTC_32K, "cb_rtc_32k", "cb_cksq_40m", 1, 1250),
+	FACTOR(CK_TOP_CB_RTC_32P7K, "cb_rtc_32p7k", "cb_cksq_40m", 1, 1220),
+	FACTOR(CK_TOP_INFRA_F32K, "csw_infra_f32k", "cb_rtc_32p7k", 1, 1),
+	FACTOR(CK_TOP_CKSQ_SRC, "cksq_src", "clkxtal", 1, 1),
+	FACTOR(CK_TOP_NETSYS_2X, "netsys_2x", "netsys_2x_sel", 1, 1),
+	FACTOR(CK_TOP_NETSYS_GSW, "netsys_gsw", "netsys_gsw_sel", 1, 1),
+	FACTOR(CK_TOP_NETSYS_WED_MCU, "netsys_wed_mcu", "netsys_mcu_sel", 1, 1),
+	FACTOR(CK_TOP_EIP197, "eip197", "eip197_sel", 1, 1),
+	FACTOR(CK_TOP_EMMC_250M, "emmc_250m", "emmc_250m_sel", 1, 1),
+	FACTOR(CK_TOP_EMMC_400M, "emmc_400m", "emmc_400m_sel", 1, 1),
+	FACTOR(CK_TOP_SPI, "spi", "spi_sel", 1, 1),
+	FACTOR(CK_TOP_SPIM_MST, "spim_mst", "spim_mst_sel", 1, 1),
+	FACTOR(CK_TOP_NFI1X, "nfi1x", "nfi1x_sel", 1, 1),
+	FACTOR(CK_TOP_SPINFI_BCK, "spinfi_bck", "spinfi_sel", 1, 1),
+	FACTOR(CK_TOP_I2C_BCK, "i2c_bck", "i2c_sel", 1, 1),
+	FACTOR(CK_TOP_USB_SYS, "usb_sys", "usb_sys_sel", 1, 1),
+	FACTOR(CK_TOP_USB_SYS_P1, "usb_sys_p1", "usb_sys_p1_sel", 1, 1),
+	FACTOR(CK_TOP_USB_XHCI, "usb_xhci", "usb_xhci_sel", 1, 1),
+	FACTOR(CK_TOP_USB_XHCI_P1, "usb_xhci_p1", "usb_xhci_p1_sel", 1, 1),
+	FACTOR(CK_TOP_USB_FRMCNT, "usb_frmcnt", "usb_frmcnt_sel", 1, 1),
+	FACTOR(CK_TOP_USB_FRMCNT_P1, "usb_frmcnt_p1", "usb_frmcnt_p1_sel", 1,
+	       1),
+	FACTOR(CK_TOP_AUD, "aud", "aud_sel", 1, 1),
+	FACTOR(CK_TOP_A1SYS, "a1sys", "a1sys_sel", 1, 1),
+	FACTOR(CK_TOP_AUD_L, "aud_l", "aud_l_sel", 1, 1),
+	FACTOR(CK_TOP_A_TUNER, "a_tuner", "a_tuner_sel", 1, 1),
+	FACTOR(CK_TOP_SYSAXI, "sysaxi", "sysaxi_sel", 1, 1),
+	FACTOR(CK_TOP_INFRA_F26M, "csw_infra_f26m", "csw_infra_f26m_sel", 1, 1),
+	FACTOR(CK_TOP_USB_REF, "usb_ref", "cksq_src", 1, 1),
+	FACTOR(CK_TOP_USB_CK_P1, "usb_ck_p1", "cksq_src", 1, 1),
+};
+
+static const struct mtk_fixed_factor infra_divs[] __initconst = {
+	FACTOR(CK_INFRA_CK_F26M, "infra_ck_f26m", "csw_infra_f26m_sel", 1, 1),
+	FACTOR(CK_INFRA_PWM_O, "infra_pwm_o", "pwm_sel", 1, 1),
+	FACTOR(CK_INFRA_PCIE_OCC_P0, "infra_pcie_ck_occ_p0", "pextp_tl_ck_sel",
+	       1, 1),
+	FACTOR(CK_INFRA_PCIE_OCC_P1, "infra_pcie_ck_occ_p1",
+	       "pextp_tl_ck_p1_sel", 1, 1),
+	FACTOR(CK_INFRA_PCIE_OCC_P2, "infra_pcie_ck_occ_p2",
+	       "pextp_tl_ck_p2_sel", 1, 1),
+	FACTOR(CK_INFRA_PCIE_OCC_P3, "infra_pcie_ck_occ_p3",
+	       "pextp_tl_ck_p3_sel", 1, 1),
+	FACTOR(CK_INFRA_133M_HCK, "infra_133m_hck", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_133M_PHCK, "infra_133m_phck", "infra_133m_hck", 1, 1),
+	FACTOR(CK_INFRA_66M_PHCK, "infra_66m_phck", "infra_133m_hck", 1, 1),
+	FACTOR(CK_INFRA_FAUD_L_O, "infra_faud_l_o", "aud_l", 1, 1),
+	FACTOR(CK_INFRA_FAUD_AUD_O, "infra_faud_aud_o", "a1sys", 1, 1),
+	FACTOR(CK_INFRA_FAUD_EG2_O, "infra_faud_eg2_o", "a_tuner", 1, 1),
+	FACTOR(CK_INFRA_I2C_O, "infra_i2c_o", "i2c_bck", 1, 1),
+	FACTOR(CK_INFRA_UART_O0, "infra_uart_o0", "uart_sel", 1, 1),
+	FACTOR(CK_INFRA_UART_O1, "infra_uart_o1", "uart_sel", 1, 1),
+	FACTOR(CK_INFRA_UART_O2, "infra_uart_o2", "uart_sel", 1, 1),
+	FACTOR(CK_INFRA_NFI_O, "infra_nfi_o", "nfi1x", 1, 1),
+	FACTOR(CK_INFRA_SPINFI_O, "infra_spinfi_o", "spinfi_bck", 1, 1),
+	FACTOR(CK_INFRA_SPI0_O, "infra_spi0_o", "spi", 1, 1),
+	FACTOR(CK_INFRA_SPI1_O, "infra_spi1_o", "spim_mst", 1, 1),
+	FACTOR(CK_INFRA_LB_MUX_FRTC, "infra_lb_mux_frtc", "infra_frtc", 1, 1),
+	FACTOR(CK_INFRA_FRTC, "infra_frtc", "cb_rtc_32k", 1, 1),
+	FACTOR(CK_INFRA_FMSDC400_O, "infra_fmsdc400_o", "emmc_400m", 1, 1),
+	FACTOR(CK_INFRA_FMSDC2_HCK_OCC, "infra_fmsdc2_hck_occ", "emmc_250m", 1,
+	       1),
+	FACTOR(CK_INFRA_PERI_133M, "infra_peri_133m", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_USB_O, "infra_usb_o", "usb_ref", 1, 1),
+	FACTOR(CK_INFRA_USB_O_P1, "infra_usb_o_p1", "usb_ck_p1", 1, 1),
+	FACTOR(CK_INFRA_USB_FRMCNT_O, "infra_usb_frmcnt_o", "usb_frmcnt", 1, 1),
+	FACTOR(CK_INFRA_USB_FRMCNT_O_P1, "infra_usb_frmcnt_o_p1",
+	       "usb_frmcnt_p1", 1, 1),
+	FACTOR(CK_INFRA_USB_XHCI_O, "infra_usb_xhci_o", "usb_xhci", 1, 1),
+	FACTOR(CK_INFRA_USB_XHCI_O_P1, "infra_usb_xhci_o_p1", "usb_xhci_p1", 1,
+	       1),
+	FACTOR(CK_INFRA_USB_PIPE_O, "infra_usb_pipe_o", "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_USB_PIPE_O_P1, "infra_usb_pipe_o_p1", "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_USB_UTMI_O, "infra_usb_utmi_o", "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_USB_UTMI_O_P1, "infra_usb_utmi_o_p1", "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_PCIE_PIPE_OCC_P0, "infra_pcie_pipe_ck_occ_p0",
+	       "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_PCIE_PIPE_OCC_P1, "infra_pcie_pipe_ck_occ_p1",
+	       "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_PCIE_PIPE_OCC_P2, "infra_pcie_pipe_ck_occ_p2",
+	       "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_PCIE_PIPE_OCC_P3, "infra_pcie_pipe_ck_occ_p3",
+	       "clkxtal", 1, 1),
+	FACTOR(CK_INFRA_F26M_O0, "infra_f26m_o0", "csw_infra_f26m", 1, 1),
+	FACTOR(CK_INFRA_F26M_O1, "infra_f26m_o1", "csw_infra_f26m", 1, 1),
+	FACTOR(CK_INFRA_133M_MCK, "infra_133m_mck", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_66M_MCK, "infra_66m_mck", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_PERI_66M_O, "infra_peri_66m_o", "sysaxi", 1, 1),
+	FACTOR(CK_INFRA_USB_SYS_O, "infra_usb_sys_o", "usb_sys", 1, 1),
+	FACTOR(CK_INFRA_USB_SYS_O_P1, "infra_usb_sys_o_p1", "usb_sys_p1", 1, 1),
+};
+
+static const char *const mcu_bus_div_parents[] = { "cb_cksq_40m", "ccipll2_b",
+						   "cb_net1_d4" };
+
+static const char *const mcu_arm_div_parents[] = { "cb_cksq_40m", "arm_b",
+						   "cb_net1_d4" };
+
+static struct mtk_composite mcu_muxes[] = {
+	/* bus_pll_divider_cfg */
+	MUX_GATE_FLAGS(CK_MCU_BUS_DIV_SEL, "mcu_bus_div_sel",
+		       mcu_bus_div_parents, 0x7C0, 9, 2, -1, CLK_IS_CRITICAL),
+	/* mp2_pll_divider_cfg */
+	MUX_GATE_FLAGS(CK_MCU_ARM_DIV_SEL, "mcu_arm_div_sel",
+		       mcu_arm_div_parents, 0x7A8, 9, 2, -1, CLK_IS_CRITICAL),
+};
+
+static const char *const netsys_parents[] = { "cb_cksq_40m", "cb_net2_d2",
+					      "cb_mm_d2" };
+
+static const char *const netsys_500m_parents[] = { "cb_cksq_40m", "cb_net1_d5",
+						   "net1_d5_d2" };
+
+static const char *const netsys_2x_parents[] = { "cb_cksq_40m", "cb_net2_800m",
+						 "cb_mm_720m" };
+
+static const char *const netsys_gsw_parents[] = { "cb_cksq_40m", "cb_net1_d4",
+						  "cb_net1_d5" };
+
+static const char *const eth_gmii_parents[] = { "cb_cksq_40m", "net1_d5_d4" };
+
+static const char *const netsys_mcu_parents[] = { "cb_cksq_40m", "cb_net2_800m",
+						  "cb_mm_720m",	 "cb_net1_d4",
+						  "cb_net1_d5",	 "cb_m_416m" };
+
+static const char *const eip197_parents[] = { "cb_cksq_40m",  "cb_netsys_850m",
+					      "cb_net2_800m", "cb_mm_720m",
+					      "cb_net1_d4",   "cb_net1_d5" };
+
+static const char *const axi_infra_parents[] = { "cb_cksq_40m", "net1_d8_d2" };
+
+static const char *const uart_parents[] = { "cb_cksq_40m", "cb_m_d8",
+					    "m_d8_d2" };
+
+static const char *const emmc_250m_parents[] = { "cb_cksq_40m", "net1_d5_d2",
+						 "cb_mm_d4" };
+
+static const char *const emmc_400m_parents[] = { "cb_cksq_40m", "cb_msdc_400m",
+						 "cb_mm_d2",	"cb_m_d2",
+						 "cb_mm_d4",	"net1_d8_d2" };
+
+static const char *const spi_parents[] = { "cb_cksq_40m", "cb_m_d2",
+					   "cb_mm_d4",	  "net1_d8_d2",
+					   "cb_net2_d6",  "net1_d5_d4",
+					   "cb_m_d4",	  "net1_d8_d4" };
+
+static const char *const nfi1x_parents[] = { "cb_cksq_40m", "cb_mm_d4",
+					     "net1_d8_d2",  "cb_net2_d6",
+					     "cb_m_d4",	    "cb_mm_d8",
+					     "net1_d8_d4",  "cb_m_d8" };
+
+static const char *const spinfi_parents[] = { "cksq_40m_d2", "cb_cksq_40m",
+					      "net1_d5_d4",  "cb_m_d4",
+					      "cb_mm_d8",    "net1_d8_d4",
+					      "mm_d6_d2",    "cb_m_d8" };
+
+static const char *const pwm_parents[] = { "cb_cksq_40m", "net1_d8_d2",
+					   "net1_d5_d4",  "cb_m_d4",
+					   "m_d8_d2",	  "cb_rtc_32k" };
+
+static const char *const i2c_parents[] = { "cb_cksq_40m", "net1_d5_d4",
+					   "cb_m_d4", "net1_d8_d4" };
+
+static const char *const pcie_mbist_250m_parents[] = { "cb_cksq_40m",
+						       "net1_d5_d2" };
+
+static const char *const pextp_tl_ck_parents[] = { "cb_cksq_40m", "cb_net2_d6",
+						   "cb_mm_d8", "m_d8_d2",
+						   "cb_rtc_32k" };
+
+static const char *const usb_frmcnt_parents[] = { "cb_cksq_40m",
+						  "cb_mm_d3_d5" };
+
+static const char *const aud_parents[] = { "cb_cksq_40m", "cb_apll2_196m" };
+
+static const char *const a1sys_parents[] = { "cb_cksq_40m", "cb_apll2_d4" };
+
+static const char *const aud_l_parents[] = { "cb_cksq_40m", "cb_apll2_196m",
+					     "m_d8_d2" };
+
+static const char *const sspxtp_parents[] = { "cksq_40m_d2", "m_d8_d2" };
+
+static const char *const usxgmii_sbus_0_parents[] = { "cb_cksq_40m",
+						      "net1_d8_d4" };
+
+static const char *const sgm_0_parents[] = { "cb_cksq_40m", "cb_sgm_325m" };
+
+static const char *const sysapb_parents[] = { "cb_cksq_40m", "m_d3_d2" };
+
+static const char *const eth_refck_50m_parents[] = { "cb_cksq_40m",
+						     "net2_d4_d4" };
+
+static const char *const eth_sys_200m_parents[] = { "cb_cksq_40m",
+						    "cb_net2_d4" };
+
+static const char *const eth_xgmii_parents[] = { "cksq_40m_d2", "net1_d8_d8",
+						 "net1_d8_d16" };
+
+static const char *const bus_tops_parents[] = { "cb_cksq_40m", "cb_net1_d5",
+						"cb_net2_d2" };
+
+static const char *const npu_tops_parents[] = { "cb_cksq_40m", "cb_net2_800m" };
+
+static const char *const dramc_md32_parents[] = { "cb_cksq_40m", "cb_m_d2",
+						  "cb_wedmcu_208m" };
+
+static const char *const da_xtp_glb_p0_parents[] = { "cb_cksq_40m",
+						     "cb_net2_d8" };
+
+static const char *const mcusys_backup_625m_parents[] = { "cb_cksq_40m",
+							  "cb_net1_d4" };
+
+static const char *const macsec_parents[] = { "cb_cksq_40m", "cb_sgm_325m",
+					      "cb_net1_d8" };
+
+static const char *const netsys_tops_400m_parents[] = { "cb_cksq_40m",
+							"cb_net2_d2" };
+
+static const char *const eth_mii_parents[] = { "cksq_40m_d2", "net2_d4_d8" };
+
+static struct mtk_mux top_muxes[] = {
+	/* CLK_CFG_0 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents,
+			     0x000, 0x004, 0x008, 0, 2, 7, 0x1C0, 0),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_500M_SEL, "netsys_500m_sel",
+			     netsys_500m_parents, 0x000, 0x004, 0x008, 8, 2, 15,
+			     0x1C0, 1),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_2X_SEL, "netsys_2x_sel",
+			     netsys_2x_parents, 0x000, 0x004, 0x008, 16, 2, 23,
+			     0x1C0, 2),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_GSW_SEL, "netsys_gsw_sel",
+			     netsys_gsw_parents, 0x000, 0x004, 0x008, 24, 2, 31,
+			     0x1C0, 3),
+	/* CLK_CFG_1 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_GMII_SEL, "eth_gmii_sel",
+			     eth_gmii_parents, 0x010, 0x014, 0x018, 0, 1, 7,
+			     0x1C0, 4),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel",
+			     netsys_mcu_parents, 0x010, 0x014, 0x018, 8, 3, 15,
+			     0x1C0, 5),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_PAO_2X_SEL, "netsys_pao_2x_sel",
+			     netsys_mcu_parents, 0x010, 0x014, 0x018, 16, 3, 23,
+			     0x1C0, 6),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_EIP197_SEL, "eip197_sel", eip197_parents,
+			     0x010, 0x014, 0x018, 24, 3, 31, 0x1C0, 7),
+	/* CLK_CFG_2 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_AXI_INFRA_SEL, "axi_infra_sel",
+			     axi_infra_parents, 0x020, 0x024, 0x028, 0, 1, 7,
+			     0x1C0, 8),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_UART_SEL, "uart_sel", uart_parents, 0x020,
+			     0x024, 0x028, 8, 2, 15, 0x1C0, 9),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_250M_SEL, "emmc_250m_sel",
+			     emmc_250m_parents, 0x020, 0x024, 0x028, 16, 2, 23,
+			     0x1C0, 10),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_EMMC_400M_SEL, "emmc_400m_sel",
+			     emmc_400m_parents, 0x020, 0x024, 0x028, 24, 3, 31,
+			     0x1C0, 11),
+	/* CLK_CFG_3 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x030,
+			     0x034, 0x038, 0, 3, 7, 0x1C0, 12),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents,
+			     0x030, 0x034, 0x038, 8, 3, 15, 0x1C0, 13),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents,
+			     0x030, 0x034, 0x038, 16, 3, 23, 0x1C0, 14),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents,
+			     0x030, 0x034, 0x038, 24, 3, 31, 0x1C0, 15),
+	/* CLK_CFG_4 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x040,
+			     0x044, 0x048, 0, 3, 7, 0x1C0, 16),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x040,
+			     0x044, 0x048, 8, 2, 15, 0x1C0, 17),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PCIE_MBIST_250M_SEL, "pcie_mbist_250m_sel",
+			     pcie_mbist_250m_parents, 0x040, 0x044, 0x048, 16,
+			     1, 23, 0x1C0, 18),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_SEL, "pextp_tl_ck_sel",
+			     pextp_tl_ck_parents, 0x040, 0x044, 0x048, 24, 3,
+			     31, 0x1C0, 19),
+	/* CLK_CFG_5 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_P1_SEL, "pextp_tl_ck_p1_sel",
+			     pextp_tl_ck_parents, 0x050, 0x054, 0x058, 0, 3, 7,
+			     0x1C0, 20),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_P2_SEL, "pextp_tl_ck_p2_sel",
+			     pextp_tl_ck_parents, 0x050, 0x054, 0x058, 8, 3, 15,
+			     0x1C0, 21),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_TL_P3_SEL, "pextp_tl_ck_p3_sel",
+			     pextp_tl_ck_parents, 0x050, 0x054, 0x058, 16, 3,
+			     23, 0x1C0, 22),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_SYS_SEL, "usb_sys_sel",
+			     eth_gmii_parents, 0x050, 0x054, 0x058, 24, 1, 31,
+			     0x1C0, 23),
+	/* CLK_CFG_6 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_SYS_P1_SEL, "usb_sys_p1_sel",
+			     eth_gmii_parents, 0x060, 0x064, 0x068, 0, 1, 7,
+			     0x1C0, 24),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_XHCI_SEL, "usb_xhci_sel",
+			     eth_gmii_parents, 0x060, 0x064, 0x068, 8, 1, 15,
+			     0x1C0, 25),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_XHCI_P1_SEL, "usb_xhci_p1_sel",
+			     eth_gmii_parents, 0x060, 0x064, 0x068, 16, 1, 23,
+			     0x1C0, 26),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel",
+			     usb_frmcnt_parents, 0x060, 0x064, 0x068, 24, 1, 31,
+			     0x1C0, 27),
+	/* CLK_CFG_7 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_FRMCNT_P1_SEL, "usb_frmcnt_p1_sel",
+			     usb_frmcnt_parents, 0x070, 0x074, 0x078, 0, 1, 7,
+			     0x1C0, 28),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x070,
+			     0x074, 0x078, 8, 1, 15, 0x1C0, 29),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents,
+			     0x070, 0x074, 0x078, 16, 1, 23, 0x1C0, 30),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents,
+			     0x070, 0x074, 0x078, 24, 2, 31, 0x1C4, 0),
+	/* CLK_CFG_8 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_A_TUNER_SEL, "a_tuner_sel", a1sys_parents,
+			     0x080, 0x084, 0x088, 0, 1, 7, 0x1C4, 1),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SSPXTP_SEL, "sspxtp_sel", sspxtp_parents,
+			     0x080, 0x084, 0x088, 8, 1, 15, 0x1C4, 2),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USB_PHY_SEL, "usb_phy_sel", sspxtp_parents,
+			     0x080, 0x084, 0x088, 16, 1, 23, 0x1C4, 3),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USXGMII_SBUS_0_SEL, "usxgmii_sbus_0_sel",
+			     usxgmii_sbus_0_parents, 0x080, 0x084, 0x088, 24, 1,
+			     31, 0x1C4, 4),
+	/* CLK_CFG_9 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_USXGMII_SBUS_1_SEL, "usxgmii_sbus_1_sel",
+			     usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, 0, 1,
+			     7, 0x1C4, 5),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_0_SEL, "sgm_0_sel", sgm_0_parents,
+			     0x090, 0x094, 0x098, 8, 1, 15, 0x1C4, 6),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_SBUS_0_SEL, "sgm_sbus_0_sel",
+			     usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, 16, 1,
+			     23, 0x1C4, 7),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_1_SEL, "sgm_1_sel", sgm_0_parents,
+			     0x090, 0x094, 0x098, 24, 1, 31, 0x1C4, 8),
+	/* CLK_CFG_10 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SGM_SBUS_1_SEL, "sgm_sbus_1_sel",
+			     usxgmii_sbus_0_parents, 0x0A0, 0x0A4, 0x0A8, 0, 1,
+			     7, 0x1C4, 9),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_XFI_PHY_0_XTAL_SEL, "xfi_phy_0_xtal_sel",
+			     sspxtp_parents, 0x0A0, 0x0A4, 0x0A8, 8, 1, 15,
+			     0x1C4, 10),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_XFI_PHY_1_XTAL_SEL, "xfi_phy_1_xtal_sel",
+			     sspxtp_parents, 0x0A0, 0x0A4, 0x0A8, 16, 1, 23,
+			     0x1C4, 11),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SYSAXI_SEL, "sysaxi_sel", axi_infra_parents,
+			     0x0A0, 0x0A4, 0x0A8, 24, 1, 31, 0x1C4, 12),
+	/* CLK_CFG_11 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents,
+			     0x0B0, 0x0B4, 0x0B8, 0, 1, 7, 0x1C4, 13),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_REFCK_50M_SEL, "eth_refck_50m_sel",
+			     eth_refck_50m_parents, 0x0B0, 0x0B4, 0x0B8, 8, 1,
+			     15, 0x1C4, 14),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_SYS_200M_SEL, "eth_sys_200m_sel",
+			     eth_sys_200m_parents, 0x0B0, 0x0B4, 0x0B8, 16, 1,
+			     23, 0x1C4, 15),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_SYS_SEL, "eth_sys_sel",
+			     pcie_mbist_250m_parents, 0x0B0, 0x0B4, 0x0B8, 24,
+			     1, 31, 0x1C4, 16),
+	/* CLK_CFG_12 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_XGMII_SEL, "eth_xgmii_sel",
+			     eth_xgmii_parents, 0x0C0, 0x0C4, 0x0C8, 0, 2, 7,
+			     0x1C4, 17),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_BUS_TOPS_SEL, "bus_tops_sel",
+			     bus_tops_parents, 0x0C0, 0x0C4, 0x0C8, 8, 2, 15,
+			     0x1C4, 18),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NPU_TOPS_SEL, "npu_tops_sel",
+			     npu_tops_parents, 0x0C0, 0x0C4, 0x0C8, 16, 1, 23,
+			     0x1C4, 19),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DRAMC_SEL, "dramc_sel", sspxtp_parents,
+			     0x0C0, 0x0C4, 0x0C8, 24, 1, 31, 0x1C4, 20),
+	/* CLK_CFG_13 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel",
+			     dramc_md32_parents, 0x0D0, 0x0D4, 0x0D8, 0, 2, 7,
+			     0x1C4, 21),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_INFRA_F26M_SEL, "csw_infra_f26m_sel",
+			     sspxtp_parents, 0x0D0, 0x0D4, 0x0D8, 8, 1, 15,
+			     0x1C4, 22),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_P0_SEL, "pextp_p0_sel",
+			     sspxtp_parents, 0x0D0, 0x0D4, 0x0D8, 16, 1, 23,
+			     0x1C4, 23),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_P1_SEL, "pextp_p1_sel",
+			     sspxtp_parents, 0x0D0, 0x0D4, 0x0D8, 24, 1, 31,
+			     0x1C4, 24),
+	/* CLK_CFG_14 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_P2_SEL, "pextp_p2_sel",
+			     sspxtp_parents, 0x0E0, 0x0E4, 0x0E8, 0, 1, 7,
+			     0x1C4, 25),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_P3_SEL, "pextp_p3_sel",
+			     sspxtp_parents, 0x0E0, 0x0E4, 0x0E8, 8, 1, 15,
+			     0x1C4, 26),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P0_SEL, "da_xtp_glb_p0_sel",
+			     da_xtp_glb_p0_parents, 0x0E0, 0x0E4, 0x0E8, 16, 1,
+			     23, 0x1C4, 27),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P1_SEL, "da_xtp_glb_p1_sel",
+			     da_xtp_glb_p0_parents, 0x0E0, 0x0E4, 0x0E8, 24, 1,
+			     31, 0x1C4, 28),
+	/* CLK_CFG_15 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P2_SEL, "da_xtp_glb_p2_sel",
+			     da_xtp_glb_p0_parents, 0x0F0, 0x0F4, 0x0F8, 0, 1,
+			     7, 0x1C4, 29),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_XTP_GLB_P3_SEL, "da_xtp_glb_p3_sel",
+			     da_xtp_glb_p0_parents, 0x0F0, 0x0F4, 0x0F8, 8, 1,
+			     15, 0x1C4, 30),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_CKM_SEL, "ckm_sel", sspxtp_parents, 0x0F0,
+			     0x0F4, 0x0F8, 16, 1, 23, 0x1C8, 0),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_DA_SELM_XTAL_SEL, "da_selm_xtal_sel",
+			     sspxtp_parents, 0x0F0, 0x0F4, 0x0F8, 24, 1, 31,
+			     0x1C8, 1),
+	/* CLK_CFG_16 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_PEXTP_SEL, "pextp_sel", sspxtp_parents,
+			     0x0100, 0x104, 0x108, 0, 1, 7, 0x1C8, 2),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_TOPS_P2_26M_SEL, "tops_p2_26m_sel",
+			     sspxtp_parents, 0x0100, 0x104, 0x108, 8, 1, 15,
+			     0x1C8, 3),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_MCUSYS_BACKUP_625M_SEL,
+			     "mcusys_backup_625m_sel",
+			     mcusys_backup_625m_parents, 0x0100, 0x104, 0x108,
+			     16, 1, 23, 0x1C8, 4),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_SYNC_250M_SEL,
+			     "netsys_sync_250m_sel", pcie_mbist_250m_parents,
+			     0x0100, 0x104, 0x108, 24, 1, 31, 0x1C8, 5),
+	/* CLK_CFG_17 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_MACSEC_SEL, "macsec_sel", macsec_parents,
+			     0x0110, 0x114, 0x118, 0, 2, 7, 0x1C8, 6),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_TOPS_400M_SEL,
+			     "netsys_tops_400m_sel", netsys_tops_400m_parents,
+			     0x0110, 0x114, 0x118, 8, 1, 15, 0x1C8, 7),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_PPEFB_250M_SEL,
+			     "netsys_ppefb_250m_sel", pcie_mbist_250m_parents,
+			     0x0110, 0x114, 0x118, 16, 1, 23, 0x1C8, 8),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_NETSYS_WARP_SEL, "netsys_warp_sel",
+			     netsys_parents, 0x0110, 0x114, 0x118, 24, 2, 31,
+			     0x1C8, 9),
+	/* CLK_CFG_18 */
+	MUX_GATE_CLR_SET_UPD(CK_TOP_ETH_MII_SEL, "eth_mii_sel", eth_mii_parents,
+			     0x0120, 0x124, 0x128, 0, 1, 7, 0x1C8, 10),
+	MUX_GATE_CLR_SET_UPD(CK_TOP_CK_NPU_SEL_CM_TOPS_SEL,
+			     "ck_npu_sel_cm_tops_sel", netsys_2x_parents,
+			     0x0120, 0x124, 0x128, 8, 2, 15, 0x1C8, 11),
+};
+
+static const char *const infra_mux_uart0_parents[] __initconst = {
+	"infra_ck_f26m", "infra_uart_o0"
+};
+
+static const char *const infra_mux_uart1_parents[] __initconst = {
+	"infra_ck_f26m", "infra_uart_o1"
+};
+
+static const char *const infra_mux_uart2_parents[] __initconst = {
+	"infra_ck_f26m", "infra_uart_o2"
+};
+
+static const char *const infra_mux_spi0_parents[] __initconst = {
+	"infra_i2c_o", "infra_spi0_o"
+};
+
+static const char *const infra_mux_spi1_parents[] __initconst = {
+	"infra_i2c_o", "infra_spi1_o"
+};
+
+static const char *const infra_pwm_bck_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_66m_mck", "infra_pwm_o"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p0_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_ck_f26m",
+	"infra_pcie_ck_occ_p0"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p1_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_ck_f26m",
+	"infra_pcie_ck_occ_p1"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p2_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_ck_f26m",
+	"infra_pcie_ck_occ_p2"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p3_parents[] __initconst = {
+	"csw_infra_f32k", "infra_ck_f26m", "infra_ck_f26m",
+	"infra_pcie_ck_occ_p3"
+};
+
+static const struct mtk_mux infra_muxes[] = {
+	/* MODULE_CLK_SEL_0 */
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
+			     infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
+			     infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
+			     infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel",
+			     infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 4,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel",
+			     infra_mux_spi1_parents, 0x0018, 0x0010, 0x0014, 5,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel",
+			     infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 6,
+			     1, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_SEL, "infra_pwm_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 14,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 16,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 18,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 20,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 22,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 24,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 26,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 28,
+			     2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel",
+			     infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 30,
+			     2, -1, -1, -1),
+	/* MODULE_CLK_SEL_1 */
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P0_SEL,
+			     "infra_pcie_gfmux_tl_o_p0_sel",
+			     infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028,
+			     0x0020, 0x0024, 0, 2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P1_SEL,
+			     "infra_pcie_gfmux_tl_o_p1_sel",
+			     infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028,
+			     0x0020, 0x0024, 2, 2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P2_SEL,
+			     "infra_pcie_gfmux_tl_o_p2_sel",
+			     infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028,
+			     0x0020, 0x0024, 4, 2, -1, -1, -1),
+	MUX_GATE_CLR_SET_UPD(CK_INFRA_PCIE_GFMUX_TL_O_P3_SEL,
+			     "infra_pcie_gfmux_tl_o_p3_sel",
+			     infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028,
+			     0x0020, 0x0024, 6, 2, -1, -1, -1),
+};
+
+static struct mtk_composite top_aud_divs[] = {
+	DIV_GATE(CK_TOP_AUD_I2S_M, "aud_i2s_m", "aud",
+		0x0420, 0, 0x0420, 8, 8),
+};
+
+static const struct mtk_gate_regs infra0_cg_regs = {
+	.set_ofs = 0x10,
+	.clr_ofs = 0x14,
+	.sta_ofs = 0x18,
+};
+
+static const struct mtk_gate_regs infra1_cg_regs = {
+	.set_ofs = 0x40,
+	.clr_ofs = 0x44,
+	.sta_ofs = 0x48,
+};
+
+static const struct mtk_gate_regs infra2_cg_regs = {
+	.set_ofs = 0x50,
+	.clr_ofs = 0x54,
+	.sta_ofs = 0x58,
+};
+
+static const struct mtk_gate_regs infra3_cg_regs = {
+	.set_ofs = 0x60,
+	.clr_ofs = 0x64,
+	.sta_ofs = 0x68,
+};
+
+#define GATE_INFRA0(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &infra0_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_setclr,                               \
+	}
+
+#define GATE_INFRA1(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &infra1_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_setclr,                               \
+	}
+
+#define GATE_INFRA2(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &infra2_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_setclr,                               \
+	}
+
+#define GATE_INFRA3(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &infra3_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_setclr,                               \
+	}
+
+static const struct mtk_gate infra_clks[] __initconst = {
+	/* INFRA0 */
+	GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P0,
+		    "infra_pcie_peri_ck_26m_ck_p0", "infra_f26m_o0", 7),
+	GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P1,
+		    "infra_pcie_peri_ck_26m_ck_p1", "infra_f26m_o0", 8),
+	GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P2,
+		    "infra_pcie_peri_ck_26m_ck_p2", "infra_f26m_o0", 9),
+	GATE_INFRA0(CK_INFRA_PCIE_PERI_26M_CK_P3,
+		    "infra_pcie_peri_ck_26m_ck_p3", "infra_f26m_o0", 10),
+	/* INFRA1 */
+	GATE_INFRA1(CK_INFRA_66M_GPT_BCK, "infra_hf_66m_gpt_bck",
+		    "infra_66m_mck", 0),
+	GATE_INFRA1(CK_INFRA_66M_PWM_HCK, "infra_hf_66m_pwm_hck",
+		    "infra_66m_mck", 1),
+	GATE_INFRA1(CK_INFRA_66M_PWM_BCK, "infra_hf_66m_pwm_bck",
+		    "infra_pwm_sel", 2),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK1, "infra_hf_66m_pwm_ck1",
+		    "infra_pwm_ck1_sel", 3),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK2, "infra_hf_66m_pwm_ck2",
+		    "infra_pwm_ck2_sel", 4),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK3, "infra_hf_66m_pwm_ck3",
+		    "infra_pwm_ck3_sel", 5),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK4, "infra_hf_66m_pwm_ck4",
+		    "infra_pwm_ck4_sel", 6),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK5, "infra_hf_66m_pwm_ck5",
+		    "infra_pwm_ck5_sel", 7),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK6, "infra_hf_66m_pwm_ck6",
+		    "infra_pwm_ck6_sel", 8),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK7, "infra_hf_66m_pwm_ck7",
+		    "infra_pwm_ck7_sel", 9),
+	GATE_INFRA1(CK_INFRA_66M_PWM_CK8, "infra_hf_66m_pwm_ck8",
+		    "infra_pwm_ck8_sel", 10),
+	GATE_INFRA1(CK_INFRA_133M_CQDMA_BCK, "infra_hf_133m_cqdma_bck",
+		    "infra_133m_mck", 12),
+	GATE_INFRA1(CK_INFRA_66M_AUD_SLV_BCK, "infra_66m_aud_slv_bck",
+		    "infra_66m_phck", 13),
+	GATE_INFRA1(CK_INFRA_AUD_26M, "infra_f_faud_26m", "infra_ck_f26m", 14),
+	GATE_INFRA1(CK_INFRA_AUD_L, "infra_f_faud_l", "infra_faud_l_o", 15),
+	GATE_INFRA1(CK_INFRA_AUD_AUD, "infra_f_aud_aud", "infra_faud_aud_o",
+		    16),
+	GATE_INFRA1(CK_INFRA_AUD_EG2, "infra_f_faud_eg2", "infra_faud_eg2_o",
+		    18),
+	GATE_INFRA1(CK_INFRA_DRAMC_F26M, "infra_dramc_f26m", "infra_ck_f26m",
+		    19),
+	GATE_INFRA1(CK_INFRA_133M_DBG_ACKM, "infra_hf_133m_dbg_ackm",
+		    "infra_133m_mck", 20),
+	GATE_INFRA1(CK_INFRA_66M_AP_DMA_BCK, "infra_66m_ap_dma_bck",
+		    "infra_66m_mck", 21),
+	GATE_INFRA1(CK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck",
+		    "infra_66m_mck", 29),
+	GATE_INFRA1(CK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m",
+		    "infra_ck_f26m", 30),
+	GATE_INFRA1(CK_INFRA_66M_TRNG, "infra_hf_66m_trng", "infra_peri_66m_o",
+		    31),
+	/* INFRA2 */
+	GATE_INFRA2(CK_INFRA_26M_THERM_SYSTEM, "infra_hf_26m_therm_system",
+		    "infra_ck_f26m", 0),
+	GATE_INFRA2(CK_INFRA_I2C_BCK, "infra_i2c_bck", "infra_i2c_o", 1),
+	GATE_INFRA2(CK_INFRA_66M_UART0_PCK, "infra_hf_66m_uart0_pck",
+		    "infra_66m_mck", 3),
+	GATE_INFRA2(CK_INFRA_66M_UART1_PCK, "infra_hf_66m_uart1_pck",
+		    "infra_66m_mck", 4),
+	GATE_INFRA2(CK_INFRA_66M_UART2_PCK, "infra_hf_66m_uart2_pck",
+		    "infra_66m_mck", 5),
+	GATE_INFRA2(CK_INFRA_52M_UART0_CK, "infra_f_52m_uart0",
+		    "infra_mux_uart0_sel", 3),
+	GATE_INFRA2(CK_INFRA_52M_UART1_CK, "infra_f_52m_uart1",
+		    "infra_mux_uart1_sel", 4),
+	GATE_INFRA2(CK_INFRA_52M_UART2_CK, "infra_f_52m_uart2",
+		    "infra_mux_uart2_sel", 5),
+	GATE_INFRA2(CK_INFRA_NFI, "infra_f_fnfi", "infra_nfi_o", 9),
+	GATE_INFRA2(CK_INFRA_SPINFI, "infra_f_fspinfi", "infra_spinfi_o", 10),
+	GATE_INFRA2(CK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck",
+		    "infra_66m_mck", 11),
+	GATE_INFRA2(CK_INFRA_104M_SPI0, "infra_hf_104m_spi0",
+		    "infra_mux_spi0_sel", 12),
+	GATE_INFRA2(CK_INFRA_104M_SPI1, "infra_hf_104m_spi1",
+		    "infra_mux_spi1_sel", 13),
+	GATE_INFRA2(CK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck",
+		    "infra_mux_spi2_sel", 14),
+	GATE_INFRA2(CK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck",
+		    "infra_66m_mck", 15),
+	GATE_INFRA2(CK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck",
+		    "infra_66m_mck", 16),
+	GATE_INFRA2(CK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck",
+		    "infra_66m_mck", 17),
+	GATE_INFRA2(CK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi",
+		    "infra_66m_mck", 18),
+	GATE_INFRA2(CK_INFRA_RTC, "infra_f_frtc", "infra_lb_mux_frtc", 19),
+	GATE_INFRA2(CK_INFRA_26M_ADC_BCK, "infra_f_26m_adc_bck",
+		    "infra_f26m_o1", 20),
+	GATE_INFRA2(CK_INFRA_RC_ADC, "infra_f_frc_adc", "infra_f_26m_adc_bck",
+		    21),
+	GATE_INFRA2(CK_INFRA_MSDC400, "infra_f_fmsdc400", "infra_fmsdc400_o",
+		    22),
+	GATE_INFRA2(CK_INFRA_MSDC2_HCK, "infra_f_fmsdc2_hck",
+		    "infra_fmsdc2_hck_occ", 23),
+	GATE_INFRA2(CK_INFRA_133M_MSDC_0_HCK, "infra_hf_133m_msdc_0_hck",
+		    "infra_peri_133m", 24),
+	GATE_INFRA2(CK_INFRA_66M_MSDC_0_HCK, "infra_66m_msdc_0_hck",
+		    "infra_66m_phck", 25),
+	GATE_INFRA2(CK_INFRA_133M_CPUM_BCK, "infra_hf_133m_cpum_bck",
+		    "infra_133m_mck", 26),
+	GATE_INFRA2(CK_INFRA_BIST2FPC, "infra_hf_fbist2fpc", "infra_nfi_o", 27),
+	GATE_INFRA2(CK_INFRA_I2C_X16W_MCK_CK_P1, "infra_hf_i2c_x16w_mck_ck_p1",
+		    "infra_133m_mck", 29),
+	GATE_INFRA2(CK_INFRA_I2C_X16W_PCK_CK_P1, "infra_hf_i2c_x16w_pck_ck_p1",
+		    "infra_66m_phck", 31),
+	/* INFRA3 */
+	GATE_INFRA3(CK_INFRA_133M_USB_HCK, "infra_133m_usb_hck",
+		    "infra_133m_phck", 0),
+	GATE_INFRA3(CK_INFRA_133M_USB_HCK_CK_P1, "infra_133m_usb_hck_ck_p1",
+		    "infra_133m_phck", 1),
+	GATE_INFRA3(CK_INFRA_66M_USB_HCK, "infra_66m_usb_hck", "infra_66m_phck",
+		    2),
+	GATE_INFRA3(CK_INFRA_66M_USB_HCK_CK_P1, "infra_66m_usb_hck_ck_p1",
+		    "infra_66m_phck", 3),
+	GATE_INFRA3(CK_INFRA_USB_SYS, "infra_usb_sys", "infra_usb_sys_o", 4),
+	GATE_INFRA3(CK_INFRA_USB_SYS_CK_P1, "infra_usb_sys_ck_p1",
+		    "infra_usb_sys_o_p1", 5),
+	GATE_INFRA3(CK_INFRA_USB_REF, "infra_usb_ref", "infra_usb_o", 6),
+	GATE_INFRA3(CK_INFRA_USB_CK_P1, "infra_usb_ck_p1", "infra_usb_o_p1", 7),
+	GATE_INFRA3(CK_INFRA_USB_FRMCNT, "infra_usb_frmcnt",
+		    "infra_usb_frmcnt_o", 8),
+	GATE_INFRA3(CK_INFRA_USB_FRMCNT_CK_P1, "infra_usb_frmcnt_ck_p1",
+		    "infra_usb_frmcnt_o_p1", 9),
+	GATE_INFRA3(CK_INFRA_USB_PIPE, "infra_usb_pipe", "infra_usb_pipe_o",
+		    10),
+	GATE_INFRA3(CK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1",
+		    "infra_usb_pipe_o_p1", 11),
+	GATE_INFRA3(CK_INFRA_USB_UTMI, "infra_usb_utmi", "infra_usb_utmi_o",
+		    12),
+	GATE_INFRA3(CK_INFRA_USB_UTMI_CK_P1, "infra_usb_utmi_ck_p1",
+		    "infra_usb_utmi_o_p1", 13),
+	GATE_INFRA3(CK_INFRA_USB_XHCI, "infra_usb_xhci", "infra_usb_xhci_o",
+		    14),
+	GATE_INFRA3(CK_INFRA_USB_XHCI_CK_P1, "infra_usb_xhci_ck_p1",
+		    "infra_usb_xhci_o_p1", 15),
+	GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P0, "infra_pcie_gfmux_tl_ck_p0",
+		    "infra_pcie_gfmux_tl_o_p0_sel", 20),
+	GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P1, "infra_pcie_gfmux_tl_ck_p1",
+		    "infra_pcie_gfmux_tl_o_p1_sel", 21),
+	GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P2, "infra_pcie_gfmux_tl_ck_p2",
+		    "infra_pcie_gfmux_tl_o_p2_sel", 22),
+	GATE_INFRA3(CK_INFRA_PCIE_GFMUX_TL_P3, "infra_pcie_gfmux_tl_ck_p3",
+		    "infra_pcie_gfmux_tl_o_p3_sel", 23),
+	GATE_INFRA3(CK_INFRA_PCIE_PIPE_P0, "infra_pcie_pipe_ck_p0",
+		    "infra_pcie_pipe_ck_occ_p0", 24),
+	GATE_INFRA3(CK_INFRA_PCIE_PIPE_P1, "infra_pcie_pipe_ck_p1",
+		    "infra_pcie_pipe_ck_occ_p1", 25),
+	GATE_INFRA3(CK_INFRA_PCIE_PIPE_P2, "infra_pcie_pipe_ck_p2",
+		    "infra_pcie_pipe_ck_occ_p2", 26),
+	GATE_INFRA3(CK_INFRA_PCIE_PIPE_P3, "infra_pcie_pipe_ck_p3",
+		    "infra_pcie_pipe_ck_occ_p3", 27),
+	GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P0, "infra_133m_pcie_ck_p0",
+		    "infra_133m_phck", 28),
+	GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P1, "infra_133m_pcie_ck_p1",
+		    "infra_133m_phck", 29),
+	GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P2, "infra_133m_pcie_ck_p2",
+		    "infra_133m_phck", 30),
+	GATE_INFRA3(CK_INFRA_133M_PCIE_CK_P3, "infra_133m_pcie_ck_p3",
+		    "infra_133m_phck", 31),
+};
+
+static const struct mtk_gate_regs sgmii0_cg_regs = {
+	.set_ofs = 0xE4,
+	.clr_ofs = 0xE4,
+	.sta_ofs = 0xE4,
+};
+
+#define GATE_SGMII0(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &sgmii0_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_no_setclr_inv,                        \
+	}
+
+static const struct mtk_gate sgmii0_clks[] __initconst = {
+	GATE_SGMII0(CK_SGM0_TX_EN, "sgm0_tx_en", "clkxtal", 2),
+	GATE_SGMII0(CK_SGM0_RX_EN, "sgm0_rx_en", "clkxtal", 3),
+};
+
+static const struct mtk_gate_regs sgmii1_cg_regs = {
+	.set_ofs = 0xE4,
+	.clr_ofs = 0xE4,
+	.sta_ofs = 0xE4,
+};
+
+#define GATE_SGMII1(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &sgmii1_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_no_setclr_inv,                        \
+	}
+
+static const struct mtk_gate sgmii1_clks[] __initconst = {
+	GATE_SGMII1(CK_SGM1_TX_EN, "sgm1_tx_en", "clkxtal", 2),
+	GATE_SGMII1(CK_SGM1_RX_EN, "sgm1_rx_en", "clkxtal", 3),
+};
+
+static const struct mtk_gate_regs ethdma_cg_regs = {
+	.set_ofs = 0x30,
+	.clr_ofs = 0x30,
+	.sta_ofs = 0x30,
+};
+
+#define GATE_ETHDMA(_id, _name, _parent, _shift)                               \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &ethdma_cg_regs, .shift = _shift,                      \
+		.ops = &mtk_clk_gate_ops_no_setclr_inv,                        \
+	}
+
+static const struct mtk_gate ethdma_clks[] __initconst = {
+	GATE_ETHDMA(CK_ETHDMA_XGP1_EN, "ethdma_xgp1_en", "clkxtal", 0),
+	GATE_ETHDMA(CK_ETHDMA_XGP2_EN, "ethdma_xgp2_en", "clkxtal", 1),
+	GATE_ETHDMA(CK_ETHDMA_XGP3_EN, "ethdma_xgp3_en", "clkxtal", 2),
+	GATE_ETHDMA(CK_ETHDMA_FE_EN, "ethdma_fe_en", "netsys_2x", 6),
+	GATE_ETHDMA(CK_ETHDMA_GP2_EN, "ethdma_gp2_en", "clkxtal", 7),
+	GATE_ETHDMA(CK_ETHDMA_GP1_EN, "ethdma_gp1_en", "clkxtal", 8),
+	GATE_ETHDMA(CK_ETHDMA_GP3_EN, "ethdma_gp3_en", "clkxtal", 10),
+	GATE_ETHDMA(CK_ETHDMA_ESW_EN, "ethdma_esw_en", "netsys_gsw", 16),
+	GATE_ETHDMA(CK_ETHDMA_CRYPT0_EN, "ethdma_crypt0_en", "eip197", 29),
+};
+
+static const struct mtk_gate_regs ethwarp_cg_regs = {
+	.set_ofs = 0x14,
+	.clr_ofs = 0x14,
+	.sta_ofs = 0x14,
+};
+
+#define GATE_ETHWARP(_id, _name, _parent, _shift)                              \
+	{                                                                      \
+		.id = _id, .name = _name, .parent_name = _parent,              \
+		.regs = &ethwarp_cg_regs, .shift = _shift,                     \
+		.ops = &mtk_clk_gate_ops_no_setclr_inv,                        \
+	}
+
+static const struct mtk_gate ethwarp_clks[] __initconst = {
+	GATE_ETHWARP(CK_ETHWARP_WOCPU2_EN, "ethwarp_wocpu2_en",
+		     "netsys_wed_mcu", 13),
+	GATE_ETHWARP(CK_ETHWARP_WOCPU1_EN, "ethwarp_wocpu1_en",
+		     "netsys_wed_mcu", 14),
+	GATE_ETHWARP(CK_ETHWARP_WOCPU0_EN, "ethwarp_wocpu0_en",
+		     "netsys_wed_mcu", 15),
+};
+
+#define MT7988_PLL_FMAX	     (2500UL * MHZ)
+#define MT7988_PCW_CHG_SHIFT 2
+
+#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask,     \
+	      _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg,         \
+	      _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, _div_table,   \
+	      _parent_name)                                                    \
+	{                                                                      \
+		.id = _id, .name = _name, .reg = _reg, .pwr_reg = _pwr_reg,    \
+		.en_mask = _en_mask, .flags = _flags,                          \
+		.rst_bar_mask = BIT(_rst_bar_mask), .fmax = MT7988_PLL_FMAX,   \
+		.pcwbits = _pcwbits, .pd_reg = _pd_reg, .pd_shift = _pd_shift, \
+		.tuner_reg = _tuner_reg, .tuner_en_reg = _tuner_en_reg,        \
+		.tuner_en_bit = _tuner_en_bit, .pcw_reg = _pcw_reg,            \
+		.pcw_shift = _pcw_shift, .pcw_chg_reg = _pcw_chg_reg,          \
+		.pcw_chg_shift = MT7988_PCW_CHG_SHIFT,                         \
+		.div_table = _div_table, .parent_name = _parent_name,          \
+	}
+
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask,       \
+	    _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg,           \
+	    _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, _parent_name)   \
+	PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask,     \
+	      _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg,         \
+	      _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, NULL,         \
+	      _parent_name)
+
+static const struct mtk_pll_data plls[] = {
+	PLL(CK_APMIXED_NETSYSPLL, "netsyspll", 0x0104, 0x0110, 0x00000001, 0, 0,
+	    32, 0x0104, 4, 0, 0, 0, 0x0108, 0, 0x0104, "clkxtal"),
+	PLL(CK_APMIXED_MPLL, "mpll", 0x0114, 0x0120, 0xff000001, HAVE_RST_BAR,
+	    23, 32, 0x0114, 4, 0, 0, 0, 0x0118, 0, 0x0114, "clkxtal"),
+	PLL(CK_APMIXED_MMPLL, "mmpll", 0x0124, 0x0130, 0xff000001, HAVE_RST_BAR,
+	    23, 32, 0x0124, 4, 0, 0, 0, 0x0128, 0, 0x0124, "clkxtal"),
+	PLL(CK_APMIXED_APLL2, "apll2", 0x0134, 0x0140, 0x00000001, 0, 0, 32,
+	    0x0134, 4, 0x0704, 0x0700, 1, 0x0138, 0, 0x0134, "clkxtal"),
+	PLL(CK_APMIXED_NET1PLL, "net1pll", 0x0144, 0x0150, 0xff000001,
+	    HAVE_RST_BAR, 23, 32, 0x0144, 4, 0, 0, 0, 0x0148, 0, 0x0144,
+	    "clkxtal"),
+	PLL(CK_APMIXED_NET2PLL, "net2pll", 0x0154, 0x0160, 0xff000001,
+	    HAVE_RST_BAR, 23, 32, 0x0154, 4, 0, 0, 0, 0x0158, 0, 0x0154,
+	    "clkxtal"),
+	PLL(CK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0164, 0x0170, 0x00000001, 0, 0,
+	    32, 0x0164, 4, 0, 0, 0, 0x0168, 0, 0x0164, "clkxtal"),
+	PLL(CK_APMIXED_SGMPLL, "sgmpll", 0x0174, 0x0180, 0x00000001, 0, 0, 32,
+	    0x0174, 4, 0, 0, 0, 0x0178, 0, 0x0174, "clkxtal"),
+	PLL(CK_APMIXED_ARM_B, "arm_b", 0x0204, 0x0210, 0xff000001, HAVE_RST_BAR,
+	    23, 32, 0x0204, 4, 0, 0, 0, 0x0208, 0, 0x0204, "clkxtal"),
+	PLL(CK_APMIXED_CCIPLL2_B, "ccipll2_b", 0x0214, 0x0220, 0xff000001,
+	    HAVE_RST_BAR, 23, 32, 0x0214, 4, 0, 0, 0, 0x0218, 0, 0x0214,
+	    "clkxtal"),
+	PLL(CK_APMIXED_USXGMIIPLL, "usxgmiipll", 0x0304, 0x0310, 0xff000001,
+	    HAVE_RST_BAR, 23, 32, 0x0304, 4, 0, 0, 0, 0x0308, 0, 0x0304,
+	    "clkxtal"),
+	PLL(CK_APMIXED_MSDCPLL, "msdcpll", 0x0314, 0x0320, 0x00000001, 0, 0, 32,
+	    0x0314, 4, 0, 0, 0, 0x0318, 0, 0x0314, "clkxtal"),
+};
+
+static struct clk_onecell_data *mt7988_top_clk_data __initdata;
+static struct clk_onecell_data *mt7988_pll_clk_data __initdata;
+
+static void __init mtk_clk_enable_critical(void)
+{
+	if (!mt7988_top_clk_data || !mt7988_pll_clk_data)
+		return;
+
+	clk_prepare_enable(mt7988_pll_clk_data->clks[CK_APMIXED_ARM_B]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_SYSAXI_SEL]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_SYSAPB_SEL]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_DRAMC_SEL]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_DRAMC_MD32_SEL]);
+	clk_prepare_enable(mt7988_top_clk_data->clks[CK_TOP_INFRA_F26M_SEL]);
+}
+
+static void __init mtk_infracfg_init(struct device_node *node)
+{
+	int r;
+
+	mt7988_top_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
+
+	mtk_clk_register_factors(infra_divs, ARRAY_SIZE(infra_divs),
+				 mt7988_top_clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get,
+				mt7988_top_clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+
+	mtk_clk_enable_critical();
+}
+CLK_OF_DECLARE(mtk_infracfg, "mediatek,mt7988-infracfg", mtk_infracfg_init);
+
+static void __init mtk_topckgen_init(struct device_node *node)
+{
+	int r;
+	void __iomem *base;
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("%s(): ioremap failed\n", __func__);
+		return;
+	}
+
+	mt7988_top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
+
+	mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs),
+				 mt7988_top_clk_data);
+	mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node,
+			       &mt7988_clk_lock, mt7988_top_clk_data);
+	mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs),
+		base, &mt7988_clk_lock, mt7988_top_clk_data);
+	r = of_clk_add_provider(node, of_clk_src_onecell_get,
+				mt7988_top_clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+
+	mtk_clk_enable_critical();
+}
+CLK_OF_DECLARE(mtk_topckgen, "mediatek,mt7988-topckgen", mtk_topckgen_init);
+
+static void __init mtk_infracfg_ao_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+	void __iomem *base;
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("%s(): ioremap failed\n", __func__);
+		return;
+	}
+
+	clk_data = mtk_alloc_clk_data(CLK_INFRA_AO_NR_CLK);
+
+	mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node,
+			       &mt7988_clk_lock, clk_data);
+	mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_infracfg_ao, "mediatek,mt7988-infracfg_ao",
+	       mtk_infracfg_ao_init);
+
+static void __init mtk_apmixedsys_init(struct device_node *node)
+{
+	int r;
+
+	mt7988_pll_clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
+
+	mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls),
+			      mt7988_pll_clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get,
+				mt7988_pll_clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+
+	mtk_clk_enable_critical();
+}
+CLK_OF_DECLARE(mtk_apmixedsys, "mediatek,mt7988-apmixedsys",
+	       mtk_apmixedsys_init);
+
+static void __init mtk_mcusys_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+	void __iomem *base;
+
+	base = of_iomap(node, 0);
+	if (!base) {
+		pr_err("%s(): ioremap failed\n", __func__);
+		return;
+	}
+
+	clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK);
+	mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base,
+				    &mt7988_clk_lock, clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_mcusys, "mediatek,mt7988-mcusys", mtk_mcusys_init);
+
+static void __init mtk_sgmiisys_0_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+
+	clk_data = mtk_alloc_clk_data(CLK_SGMII0_NR_CLK);
+
+	mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_sgmiisys_0, "mediatek,mt7988-sgmiisys_0",
+	       mtk_sgmiisys_0_init);
+
+static void __init mtk_sgmiisys_1_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+
+	clk_data = mtk_alloc_clk_data(CLK_SGMII1_NR_CLK);
+
+	mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_sgmiisys_1, "mediatek,mt7988-sgmiisys_1",
+	       mtk_sgmiisys_1_init);
+
+static void __init mtk_ethdma_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+
+	clk_data = mtk_alloc_clk_data(CLK_ETHDMA_NR_CLK);
+
+	mtk_clk_register_gates(node, ethdma_clks, ARRAY_SIZE(ethdma_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_ethdma, "mediatek,mt7988-ethsys", mtk_ethdma_init);
+
+static void __init mtk_ethwarp_init(struct device_node *node)
+{
+	struct clk_onecell_data *clk_data;
+	int r;
+
+	clk_data = mtk_alloc_clk_data(CLK_ETHWARP_NR_CLK);
+
+	mtk_clk_register_gates(node, ethwarp_clks, ARRAY_SIZE(ethwarp_clks),
+			       clk_data);
+
+	r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+
+	if (r)
+		pr_err("%s(): could not register clock provider: %d\n",
+		       __func__, r);
+}
+CLK_OF_DECLARE(mtk_ethwarp, "mediatek,mt7988-ethwarp", mtk_ethwarp_init);
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 5806723..37b6c68 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -709,6 +709,8 @@
 		phylink_set(mask, 1000baseT_Half);
 		phylink_set(mask, 1000baseT_Full);
 		phylink_set(mask, 1000baseX_Full);
+		phylink_set(mask, 2500baseT_Full);
+		phylink_set(mask, 5000baseT_Full);
 		break;
 	case PHY_INTERFACE_MODE_TRGMII:
 		phylink_set(mask, 1000baseT_Full);
@@ -3338,9 +3340,16 @@
 		MTK_FE_INT_RFIFO_OV | MTK_FE_INT_RFIFO_UF, MTK_FE_INT_ENABLE);
 
 	if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) {
+		/* PSE dummy page mechanism */
+		mtk_w32(eth, PSE_DUMMY_WORK_GDM(1) | PSE_DUMMY_WORK_GDM(2) |
+			PSE_DUMMY_WORK_GDM(3) | DUMMY_PAGE_THR, PSE_DUMY_REQ);
+
 		/* PSE should not drop port1, port8 and port9 packets */
 		mtk_w32(eth, 0x00000302, PSE_NO_DROP_CFG);
 
+		/* PSE should drop p8 and p9 packets when WDMA Rx ring full*/
+		mtk_w32(eth, 0x00000300, PSE_PPE0_DROP);
+
 		/* GDM and CDM Threshold */
 		mtk_w32(eth, 0x00000707, MTK_CDMW0_THRES);
 		mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES);
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 8827a36..39543c7 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -146,6 +146,11 @@
 #define PSE_NO_DROP_CFG		0x108
 #define PSE_PPE0_DROP		0x110
 
+/* PSE Last FreeQ Page Request Control */
+#define PSE_DUMY_REQ		0x10C
+#define PSE_DUMMY_WORK_GDM(x)	BIT(16 + (x))
+#define DUMMY_PAGE_THR		0x151
+
 /* PSE Input Queue Reservation Register*/
 #define PSE_IQ_REV(x)		(0x140 + ((x - 1) * 0x4))
 
@@ -1218,55 +1223,55 @@
 };
 
 /* Supported hardware group on SoCs */
-#define MTK_RGMII		BIT(MTK_RGMII_BIT)
-#define MTK_TRGMII		BIT(MTK_TRGMII_BIT)
-#define MTK_SGMII		BIT(MTK_SGMII_BIT)
-#define MTK_USXGMII		BIT(MTK_USXGMII_BIT)
-#define MTK_ESW			BIT(MTK_ESW_BIT)
-#define MTK_GEPHY		BIT(MTK_GEPHY_BIT)
-#define MTK_MUX			BIT(MTK_MUX_BIT)
-#define MTK_INFRA		BIT(MTK_INFRA_BIT)
-#define MTK_SHARED_SGMII	BIT(MTK_SHARED_SGMII_BIT)
-#define MTK_HWLRO		BIT(MTK_HWLRO_BIT)
-#define MTK_RSS			BIT(MTK_RSS_BIT)
-#define MTK_SHARED_INT		BIT(MTK_SHARED_INT_BIT)
-#define MTK_TRGMII_MT7621_CLK	BIT(MTK_TRGMII_MT7621_CLK_BIT)
-#define MTK_QDMA		BIT(MTK_QDMA_BIT)
-#define MTK_NETSYS_V1		BIT(MTK_NETSYS_V1_BIT)
-#define MTK_NETSYS_V2		BIT(MTK_NETSYS_V2_BIT)
-#define MTK_NETSYS_V3		BIT(MTK_NETSYS_V3_BIT)
-#define MTK_SOC_MT7628		BIT(MTK_SOC_MT7628_BIT)
-#define MTK_RSTCTRL_PPE1	BIT(MTK_RSTCTRL_PPE1_BIT)
-#define MTK_U3_COPHY_V2		BIT(MTK_U3_COPHY_V2_BIT)
-#define MTK_8GB_ADDRESSING	BIT(MTK_8GB_ADDRESSING_BIT)
+#define MTK_RGMII		BIT_ULL(MTK_RGMII_BIT)
+#define MTK_TRGMII		BIT_ULL(MTK_TRGMII_BIT)
+#define MTK_SGMII		BIT_ULL(MTK_SGMII_BIT)
+#define MTK_USXGMII		BIT_ULL(MTK_USXGMII_BIT)
+#define MTK_ESW			BIT_ULL(MTK_ESW_BIT)
+#define MTK_GEPHY		BIT_ULL(MTK_GEPHY_BIT)
+#define MTK_MUX			BIT_ULL(MTK_MUX_BIT)
+#define MTK_INFRA		BIT_ULL(MTK_INFRA_BIT)
+#define MTK_SHARED_SGMII	BIT_ULL(MTK_SHARED_SGMII_BIT)
+#define MTK_HWLRO		BIT_ULL(MTK_HWLRO_BIT)
+#define MTK_RSS			BIT_ULL(MTK_RSS_BIT)
+#define MTK_SHARED_INT		BIT_ULL(MTK_SHARED_INT_BIT)
+#define MTK_TRGMII_MT7621_CLK	BIT_ULL(MTK_TRGMII_MT7621_CLK_BIT)
+#define MTK_QDMA		BIT_ULL(MTK_QDMA_BIT)
+#define MTK_NETSYS_V1		BIT_ULL(MTK_NETSYS_V1_BIT)
+#define MTK_NETSYS_V2		BIT_ULL(MTK_NETSYS_V2_BIT)
+#define MTK_NETSYS_V3		BIT_ULL(MTK_NETSYS_V3_BIT)
+#define MTK_SOC_MT7628		BIT_ULL(MTK_SOC_MT7628_BIT)
+#define MTK_RSTCTRL_PPE1	BIT_ULL(MTK_RSTCTRL_PPE1_BIT)
+#define MTK_U3_COPHY_V2		BIT_ULL(MTK_U3_COPHY_V2_BIT)
+#define MTK_8GB_ADDRESSING	BIT_ULL(MTK_8GB_ADDRESSING_BIT)
 
 #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW		\
-	BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
+	BIT_ULL(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT)
 #define MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY	\
-	BIT(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT)
+	BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT)
 #define MTK_ETH_MUX_U3_GMAC2_TO_QPHY		\
-	BIT(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT)
+	BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT)
 #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII	\
-	BIT(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT)
+	BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT)
 #define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII	\
-	BIT(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT)
+	BIT_ULL(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT)
 #define MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII	\
-	BIT(MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT)
+	BIT_ULL(MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT)
 #define MTK_ETH_MUX_GMAC123_TO_USXGMII	\
-	BIT(MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT)
+	BIT_ULL(MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT)
 
 /* Supported path present on SoCs */
-#define MTK_ETH_PATH_GMAC1_RGMII	BIT(MTK_ETH_PATH_GMAC1_RGMII_BIT)
-#define MTK_ETH_PATH_GMAC1_TRGMII	BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
-#define MTK_ETH_PATH_GMAC1_SGMII	BIT(MTK_ETH_PATH_GMAC1_SGMII_BIT)
-#define MTK_ETH_PATH_GMAC2_RGMII	BIT(MTK_ETH_PATH_GMAC2_RGMII_BIT)
-#define MTK_ETH_PATH_GMAC2_SGMII	BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
-#define MTK_ETH_PATH_GMAC2_GEPHY	BIT(MTK_ETH_PATH_GMAC2_GEPHY_BIT)
-#define MTK_ETH_PATH_GMAC3_SGMII	BIT(MTK_ETH_PATH_GMAC3_SGMII_BIT)
-#define MTK_ETH_PATH_GDM1_ESW		BIT(MTK_ETH_PATH_GDM1_ESW_BIT)
-#define MTK_ETH_PATH_GMAC1_USXGMII	BIT(MTK_ETH_PATH_GMAC1_USXGMII_BIT)
-#define MTK_ETH_PATH_GMAC2_USXGMII	BIT(MTK_ETH_PATH_GMAC2_USXGMII_BIT)
-#define MTK_ETH_PATH_GMAC3_USXGMII	BIT(MTK_ETH_PATH_GMAC3_USXGMII_BIT)
+#define MTK_ETH_PATH_GMAC1_RGMII	BIT_ULL(MTK_ETH_PATH_GMAC1_RGMII_BIT)
+#define MTK_ETH_PATH_GMAC1_TRGMII	BIT_ULL(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
+#define MTK_ETH_PATH_GMAC1_SGMII	BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_RGMII	BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_SGMII	BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_GEPHY	BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT)
+#define MTK_ETH_PATH_GMAC3_SGMII	BIT_ULL(MTK_ETH_PATH_GMAC3_SGMII_BIT)
+#define MTK_ETH_PATH_GDM1_ESW		BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT)
+#define MTK_ETH_PATH_GMAC1_USXGMII	BIT_ULL(MTK_ETH_PATH_GMAC1_USXGMII_BIT)
+#define MTK_ETH_PATH_GMAC2_USXGMII	BIT_ULL(MTK_ETH_PATH_GMAC2_USXGMII_BIT)
+#define MTK_ETH_PATH_GMAC3_USXGMII	BIT_ULL(MTK_ETH_PATH_GMAC3_USXGMII_BIT)
 
 #define MTK_GMAC1_RGMII		(MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII)
 #define MTK_GMAC1_TRGMII	(MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
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
new file mode 100644
index 0000000..251a412
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-2p5ge.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0+
+#include <linux/bitfield.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+
+#define MEDAITEK_2P5GE_PHY_DMB_FW "mediatek-2p5ge-phy-dmb.bin"
+#define MEDIATEK_2P5GE_PHY_PMB_FW "mediatek-2p5ge-phy-pmb.bin"
+
+#define MD32_EN_CFG	0x18
+#define   MD32_EN	BIT(0)
+
+static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev)
+{
+	int ret;
+	int i;
+	const struct firmware *fw;
+	struct device *dev = &phydev->mdio.dev;
+	struct device_node *np;
+	void __iomem *dmb_addr;
+	void __iomem *pmb_addr;
+	void __iomem *mcucsr_base;
+	u16 reg;
+
+	np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw");
+	if (!np)
+		return -ENOENT;
+
+	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, 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);
+
+	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);
+
+	reg = readw(mcucsr_base + MD32_EN_CFG);
+	writew(reg | MD32_EN, mcucsr_base + MD32_EN_CFG);
+	dev_info(dev, "Firmware loading/trigger ok.\n");
+
+	return 0;
+}
+
+static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = genphy_read_abilities(phydev);
+	if (ret)
+		return ret;
+
+	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+			 phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+			 phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+			 phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+			 phydev->supported);
+	linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
+
+	return 0;
+}
+
+static struct phy_driver mtk_gephy_driver[] = {
+	{
+		PHY_ID_MATCH_EXACT(0x00339c11),
+		.name		= "MediaTek MT798x 2.5GbE PHY",
+		.config_init	= mt798x_2p5ge_phy_config_init,
+		.config_aneg    = genphy_c45_config_aneg,
+		.get_features	= mt798x_2p5ge_phy_get_features,
+		//.config_intr	= genphy_no_config_intr,
+		//.handle_interrupt = genphy_no_ack_interrupt,
+		//.suspend	= genphy_suspend,
+		//.resume		= genphy_resume,
+	},
+};
+
+module_phy_driver(mtk_gephy_driver);
+
+static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = {
+	{ PHY_ID_MATCH_VENDOR(0x00339c00) },
+	{ }
+};
+
+MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver");
+MODULE_AUTHOR("SkyLake Huang <SkyLake.Huang@mediatek.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
index 27d13b9..0eefd36 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
@@ -893,19 +893,7 @@
 
 	/* Disable TX power saving */
 	phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
-			MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3);
-
-	/* Slave mode finetune*/
-	phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-	__phy_write(phydev, 0x12, 0x0);
-	__phy_write(phydev, 0x11, 0x700);
-	__phy_write(phydev, 0x10, 0x9686);
-
-	__phy_write(phydev, 0x12, 0x0);
-	__phy_write(phydev, 0x11, 0x64);
-	__phy_write(phydev, 0x10, 0x8f82);
-	phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-
+			MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
 }
 
 static int mt798x_phy_calibration(struct phy_device *phydev)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/Makefile
old mode 100755
new mode 100644
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7530.c
old mode 100755
new mode 100644
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
index 7253042..74b27d6 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
@@ -7,6 +7,10 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/hrtimer.h>
+#include <linux/of_platform.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of_address.h>
 
 #include "mt753x.h"
 #include "mt753x_regs.h"
@@ -682,6 +686,24 @@
 	return -ENODEV;
 }
 
+static int mt7988_sw_detect(struct gsw_mt753x *gsw, struct chip_rev *crev)
+{
+	const char *model;
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "mediatek,mt7988-switch");
+	if (!np)
+		return -ENODEV;
+
+	of_node_put(np);
+
+	crev->rev = 0;
+	crev->name = "MT7988";
+	gsw->direct_access = true;
+
+	return 0;
+}
+
 static void pinmux_set_mux_7531(struct gsw_mt753x *gsw, u32 pin, u32 mode)
 {
 	u32 val;
@@ -810,7 +832,8 @@
 	u32 val;
 
 	for (i = 0; i < MT753X_NUM_PHYS; i++) {
-		mt7531_phy_100m_eye_diag_setting(gsw, i);
+		if (!gsw->direct_access)
+			mt7531_phy_100m_eye_diag_setting(gsw, i);
 
 		/* Enable HW auto downshift */
 		gsw->mii_write(gsw, i, 0x1f, 0x1);
@@ -834,10 +857,14 @@
 		val |= PHY_LINKDOWN_POWER_SAVING_EN;
 		gsw->mii_write(gsw, i, PHY_EXT_REG_17, val);
 
-		val = gsw->mmd_read(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6);
-		val &= ~PHY_POWER_SAVING_M;
-		val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
-		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6, val);
+		if (!gsw->direct_access) {
+			val = gsw->mmd_read(gsw, i, PHY_DEV1E,
+					    PHY_DEV1E_REG_0C6);
+			val &= ~PHY_POWER_SAVING_M;
+			val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
+			gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_0C6,
+				       val);
+		}
 
 		/* Timing Recovery for GbE slave mode */
 		mt753x_tr_write(gsw, i, PMA_CH, PMA_NOD, PMA_01, 0x6fb90a);
@@ -871,7 +898,8 @@
 	gsw->mmd_write(gsw, port, PHY_DEV1F, TXVLD_DA_273, 0x3000);
 
 	/* Adjust RX Echo path filter */
-	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_0FE, 0x2);
+	if (!gsw->direct_access)
+		gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_0FE, 0x2);
 
 	/* Adjust RX HVGA bias current */
 	gsw->mmd_write(gsw, port, PHY_DEV1E, PHY_DEV1E_REG_41, 0x3333);
@@ -952,7 +980,8 @@
 	gsw->mmd_read = mt753x_mmd_read;
 	gsw->mmd_write = mt753x_mmd_write;
 
-	gsw->hw_phy_cal = of_property_read_bool(gsw->dev->of_node, "mediatek,hw_phy_cal");
+	gsw->hw_phy_cal = of_property_read_bool(gsw->dev->of_node,
+						"mediatek,hw_phy_cal");
 
 	for (i = 0; i < MT753X_NUM_PHYS; i++) {
 		val = gsw->mii_read(gsw, i, MII_BMCR);
@@ -966,7 +995,7 @@
 
 	/* Switch soft reset */
 	mt753x_reg_write(gsw, SYS_CTRL, SW_SYS_RST | SW_REG_RST);
-	usleep_range(10, 20);
+	udelay(20);
 
 	/* Enable MDC input Schmitt Trigger */
 	val = mt753x_reg_read(gsw, SMT0_IOLB);
@@ -976,6 +1005,7 @@
 	mt7531_set_gpio_pinmux(gsw);
 
 	mt7531_core_pll_setup(gsw);
+
 	mt7531_mac_port_setup(gsw, 5, &gsw->port5_cfg);
 	mt7531_mac_port_setup(gsw, 6, &gsw->port6_cfg);
 
@@ -999,6 +1029,89 @@
 	return 0;
 }
 
+static int mt7988_sw_init(struct gsw_mt753x *gsw)
+{
+	struct device_node *switch_node = NULL;
+	struct platform_device *pdev;
+	int i;
+	u32 val;
+	u32 pmcr;
+	u32 speed;
+
+	switch_node = of_find_node_by_name(NULL, "switch0");
+	if (switch_node == NULL) {
+		dev_err(&pdev->dev, "switch node invaild\n");
+		return -ENOENT;
+	}
+
+	gsw->base = of_iomap(switch_node, 0);
+	if (IS_ERR(gsw->base)) {
+		dev_err(&pdev->dev, "switch ioremap failed\n");
+		return -EIO;
+	}
+
+	pdev = container_of(gsw->dev, struct platform_device, dev);
+	gsw->sysctrl_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							"mediatek,sysctrl");
+	if (IS_ERR(gsw->sysctrl_base)) {
+		dev_err(&pdev->dev, "no sysctl regmap found\n");
+		return -ENODEV;
+	}
+
+	/* reset control */
+	regmap_write(gsw->sysctrl_base, ETH_RESET, 0x200);
+	udelay(20);
+	regmap_write(gsw->sysctrl_base, ETH_RESET, 0);
+	udelay(20);
+
+	gsw->phy_base = (gsw->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
+
+	gsw->mii_read = mt753x_mii_read;
+	gsw->mii_write = mt753x_mii_write;
+	gsw->mmd_read = mt753x_mmd_read;
+	gsw->mmd_write = mt753x_mmd_write;
+
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		val = gsw->mii_read(gsw, i, MII_BMCR);
+		val |= BMCR_ISOLATE;
+		gsw->mii_write(gsw, i, MII_BMCR, val);
+	}
+
+	speed = MAC_SPD_1000;
+	pmcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+		MAC_MODE | MAC_TX_EN | MAC_RX_EN | BKOFF_EN |
+		BACKPR_EN | FORCE_MODE_LNK | FORCE_LINK | FORCE_MODE_SPD |
+		FORCE_MODE_DPX | FORCE_MODE_RX_FC | FORCE_MODE_TX_FC |
+		FORCE_RX_FC | FORCE_TX_FC | (speed << FORCE_SPD_S) | FORCE_DPX;
+
+	mt753x_reg_write(gsw, PMCR(6), pmcr);
+
+	/* Global mac control settings */
+	mt753x_reg_write(gsw, GMACCR,
+			 (15 << MTCC_LMT_S) | (15 << MAX_RX_JUMBO_S) |
+			 RX_PKT_LEN_MAX_JUMBO);
+
+	/* Enable Collision Poll */
+	val = mt753x_reg_read(gsw, CPGC_CTRL);
+	val |= COL_CLK_EN;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+	val |= COL_RST_N;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+	val |= COL_EN;
+	mt753x_reg_write(gsw, CPGC_CTRL, val);
+
+	/* Disable AFIFO reset for extra short IPG */
+	mt7531_afifo_reset(gsw, 0);
+
+	/* PHY force slave 1G*/
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		gsw->mii_write(gsw, i, MII_CTRL1000, 0x1200);
+		gsw->mii_write(gsw, i, MII_BMCR, 0x140);
+	}
+
+	return 0;
+}
+
 static int mt7531_sw_post_init(struct gsw_mt753x *gsw)
 {
 	int i;
@@ -1016,7 +1129,8 @@
 	val |= POWER_ON_OFF;
 	gsw->mmd_write(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403, val);
 
-	mt7531_phy_pll_setup(gsw);
+	if (!gsw->direct_access)
+		mt7531_phy_pll_setup(gsw);
 
 	/* Enable Internal PHYs before phy setting */
 	val = gsw->mmd_read(gsw, 0, PHY_DEV1F, PHY_DEV1F_REG_403);
@@ -1041,7 +1155,14 @@
 	for (i = 0; i < MT753X_NUM_PHYS; i++)
 		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_141, 0x0);
 
-	mt7531_internal_phy_calibration(gsw);
+	if (!gsw->direct_access)
+		mt7531_internal_phy_calibration(gsw);
+
+	/* PHY force slave disable, restart AN*/
+	for (i = 0; i < MT753X_NUM_PHYS; i++) {
+		gsw->mii_write(gsw, i, MII_CTRL1000, 0x200);
+		gsw->mii_write(gsw, i, MII_BMCR, 0x1240);
+	}
 
 	return 0;
 }
@@ -1053,6 +1174,13 @@
 	.post_init = mt7531_sw_post_init
 };
 
+struct mt753x_sw_id mt7988_id = {
+	.model = MT7988,
+	.detect = mt7988_sw_detect,
+	.init = mt7988_sw_init,
+	.post_init = mt7531_sw_post_init
+};
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Zhanguo Ju <zhanguo.ju@mediatek.com>");
 MODULE_DESCRIPTION("Driver for MediaTek MT753x Gigabit Switch");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h
index 52c8a49..2167722 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.h
@@ -2,12 +2,10 @@
 /*
  * Copyright (c) 2018 MediaTek Inc.
  */
-
 #ifndef _MT7531_H_
 #define _MT7531_H_
-
 #include "mt753x.h"
-
 extern struct mt753x_sw_id mt7531_id;
-
+extern struct mt753x_sw_id mt7988_id;
 #endif /* _MT7531_H_ */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h
old mode 100755
new mode 100644
index 732bda1..344d2b0
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x.h
@@ -13,6 +13,7 @@
 #include <linux/of_mdio.h>
 #include <linux/workqueue.h>
 #include <linux/gpio/consumer.h>
+#include <linux/phy.h>
 
 #ifdef CONFIG_SWCONFIG
 #include <linux/switch.h>
@@ -30,12 +31,13 @@
 
 enum mt753x_model {
 	MT7530 = 0x7530,
-	MT7531 = 0x7531
+	MT7531 = 0x7531,
+	MT7988 = 0x7988,
 };
 
 struct mt753x_port_cfg {
 	struct device_node *np;
-	int phy_mode;
+	phy_interface_t phy_mode;
 	u32 enabled: 1;
 	u32 force_link: 1;
 	u32 speed: 2;
@@ -60,6 +62,10 @@
 	u32 smi_addr;
 	u32 phy_base;
 	int direct_phy_access;
+	bool direct_access;
+
+	void __iomem *base;
+	struct regmap *sysctrl_base;
 
 	enum mt753x_model model;
 	const char *name;
@@ -70,7 +76,7 @@
 	bool hw_phy_cal;
 	bool phy_status_poll;
 	struct mt753x_phy phys[MT753X_NUM_PHYS];
-//	int phy_irqs[PHY_MAX_ADDR]; //FIXME 
+//	int phy_irqs[PHY_MAX_ADDR]; //FIXME
 
 	int phy_link_sts;
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c
old mode 100755
new mode 100644
index 3639df1..c57a5a2
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_mdio.c
@@ -33,19 +33,24 @@
 static struct mt753x_sw_id *mt753x_sw_ids[] = {
 	&mt7530_id,
 	&mt7531_id,
+	&mt7988_id,
 };
 
 u32 mt753x_reg_read(struct gsw_mt753x *gsw, u32 reg)
 {
 	u32 high, low;
 
-	mutex_lock(&gsw->host_bus->mdio_lock);
+	if (gsw->direct_access)
+		return __raw_readl(gsw->base + reg);
 
+	mutex_lock(&gsw->host_bus->mdio_lock);
 	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f,
-		(reg & MT753X_REG_PAGE_ADDR_M) >> MT753X_REG_PAGE_ADDR_S);
+			     (reg & MT753X_REG_PAGE_ADDR_M) >>
+				     MT753X_REG_PAGE_ADDR_S);
 
 	low = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr,
-		(reg & MT753X_REG_ADDR_M) >> MT753X_REG_ADDR_S);
+				  (reg & MT753X_REG_ADDR_M) >>
+					  MT753X_REG_ADDR_S);
 
 	high = gsw->host_bus->read(gsw->host_bus, gsw->smi_addr, 0x10);
 
@@ -56,17 +61,24 @@
 
 void mt753x_reg_write(struct gsw_mt753x *gsw, u32 reg, u32 val)
 {
-	mutex_lock(&gsw->host_bus->mdio_lock);
-
-	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f,
-		(reg & MT753X_REG_PAGE_ADDR_M) >> MT753X_REG_PAGE_ADDR_S);
+	if (gsw->direct_access) {
+		__raw_writel(val, gsw->base + reg);
+	} else {
+		mutex_lock(&gsw->host_bus->mdio_lock);
+		gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x1f,
+				     (reg & MT753X_REG_PAGE_ADDR_M) >>
+					     MT753X_REG_PAGE_ADDR_S);
 
-	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr,
-		(reg & MT753X_REG_ADDR_M) >> MT753X_REG_ADDR_S, val & 0xffff);
+		gsw->host_bus->write(gsw->host_bus, gsw->smi_addr,
+				     (reg & MT753X_REG_ADDR_M) >>
+					     MT753X_REG_ADDR_S,
+				     val & 0xffff);
 
-	gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10, val >> 16);
+		gsw->host_bus->write(gsw->host_bus, gsw->smi_addr, 0x10,
+				     val >> 16);
 
-	mutex_unlock(&gsw->host_bus->mdio_lock);
+		mutex_unlock(&gsw->host_bus->mdio_lock);
+	}
 }
 
 /* Indirect MDIO clause 22/45 access */
@@ -89,8 +101,7 @@
 			return -ETIMEDOUT;
 	}
 
-	val = (st << MDIO_ST_S) |
-	      ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
+	val = (st << MDIO_ST_S) | ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
 	      ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
 	      ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
 
@@ -182,19 +193,19 @@
 
 	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
 		      (MMD_ADDR << MMD_CMD_S) |
-		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
 		      MDIO_CMD_WRITE, MDIO_ST_C22);
 
-	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg,
-		      MDIO_CMD_WRITE, MDIO_ST_C22);
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg, MDIO_CMD_WRITE,
+		      MDIO_ST_C22);
 
 	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
 		      (MMD_DATA << MMD_CMD_S) |
-		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
 		      MDIO_CMD_WRITE, MDIO_ST_C22);
 
-	val = mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, 0,
-			    MDIO_CMD_READ, MDIO_ST_C22);
+	val = mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, 0, MDIO_CMD_READ,
+			    MDIO_ST_C22);
 
 	mutex_unlock(&gsw->mii_lock);
 
@@ -211,19 +222,19 @@
 
 	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
 		      (MMD_ADDR << MMD_CMD_S) |
-		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
 		      MDIO_CMD_WRITE, MDIO_ST_C22);
 
-	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg,
-		      MDIO_CMD_WRITE, MDIO_ST_C22);
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, reg, MDIO_CMD_WRITE,
+		      MDIO_ST_C22);
 
 	mt753x_mii_rw(gsw, addr, MII_MMD_ACC_CTL_REG,
 		      (MMD_DATA << MMD_CMD_S) |
-		      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
+			      ((devad << MMD_DEVAD_S) & MMD_DEVAD_M),
 		      MDIO_CMD_WRITE, MDIO_ST_C22);
 
-	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, val,
-		      MDIO_CMD_WRITE, MDIO_ST_C22);
+	mt753x_mii_rw(gsw, addr, MII_MMD_ADDR_DATA_REG, val, MDIO_CMD_WRITE,
+		      MDIO_ST_C22);
 
 	mutex_unlock(&gsw->mii_lock);
 }
@@ -239,6 +250,7 @@
 	struct device_node *fixed_link_node;
 	struct mt753x_port_cfg *port_cfg;
 	u32 port;
+	int ret;
 
 	for_each_child_of_node(gsw->dev->of_node, port_np) {
 		if (!of_device_is_compatible(port_np, "mediatek,mt753x-port"))
@@ -269,8 +281,8 @@
 
 		port_cfg->np = port_np;
 
-		port_cfg->phy_mode = of_get_phy_mode(port_np);
-		if (port_cfg->phy_mode < 0) {
+		ret = of_get_phy_mode(port_cfg->np);
+		if (ret < 0) {
 			dev_info(gsw->dev, "incorrect phy-mode %d\n", port);
 			continue;
 		}
@@ -303,6 +315,7 @@
 			case 2500:
 				port_cfg->speed = MAC_SPD_2500;
 				break;
+
 			default:
 				dev_info(gsw->dev, "incorrect speed %d\n",
 					 speed);
@@ -310,10 +323,10 @@
 			}
 		}
 
-		port_cfg->ssc_on = of_property_read_bool(port_cfg->np,
-							 "mediatek,ssc-on");
-		port_cfg->stag_on = of_property_read_bool(port_cfg->np,
-							  "mediatek,stag-on");
+		port_cfg->ssc_on =
+			of_property_read_bool(port_cfg->np, "mediatek,ssc-on");
+		port_cfg->stag_on =
+			of_property_read_bool(port_cfg->np, "mediatek,stag-on");
 		port_cfg->enabled = 1;
 	}
 }
@@ -438,7 +451,6 @@
 	mutex_unlock(&mt753x_devs_lock);
 }
 
-
 struct gsw_mt753x *mt753x_get_gsw(u32 id)
 {
 	struct gsw_mt753x *dev;
@@ -505,8 +517,8 @@
 
 	gsw->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
 	if (gsw->reset_pin < 0) {
-		dev_err(gsw->dev, "Missing reset pin of switch\n");
-		return ret;
+		dev_info(gsw->dev, "No reset pin of switch\n");
+		return 0;
 	}
 
 	ret = devm_gpio_request(gsw->dev, gsw->reset_pin, "mt753x-reset");
@@ -523,7 +535,7 @@
 
 	return 0;
 }
-#if 1 //XDXDXDXD
+
 static int mt753x_mdio_read(struct mii_bus *bus, int addr, int reg)
 {
 	struct gsw_mt753x *gsw = bus->priv;
@@ -540,8 +552,7 @@
 	return 0;
 }
 
-static const struct net_device_ops mt753x_dummy_netdev_ops = {
-};
+static const struct net_device_ops mt753x_dummy_netdev_ops = {};
 
 static void mt753x_phy_link_handler(struct net_device *dev)
 {
@@ -552,8 +563,8 @@
 
 	if (phydev->link) {
 		dev_info(gsw->dev,
-			 "Port %d Link is Up - %s/%s - flow control %s\n",
-			 port, phy_speed_to_str(phydev->speed),
+			 "Port %d Link is Up - %s/%s - flow control %s\n", port,
+			 phy_speed_to_str(phydev->speed),
 			 (phydev->duplex == DUPLEX_FULL) ? "Full" : "Half",
 			 phydev->pause ? "rx/tx" : "off");
 	} else {
@@ -566,7 +577,8 @@
 {
 	struct device_node *phy_np;
 	struct mt753x_phy *phy;
-	int phy_mode;
+	phy_interface_t iface;
+	int ret;
 	u32 phyad;
 
 	if (!mii_np)
@@ -579,10 +591,10 @@
 		if (phyad >= MT753X_NUM_PHYS)
 			continue;
 
-		phy_mode = of_get_phy_mode(phy_np);
-		if (phy_mode < 0) {
+		ret = of_get_phy_mode(phy_np);
+		if (ret < 0) {
 			dev_info(gsw->dev, "incorrect phy-mode %d for PHY %d\n",
-				 phy_mode, phyad);
+				 iface, phyad);
 			continue;
 		}
 
@@ -593,7 +605,7 @@
 		phy->netdev.netdev_ops = &mt753x_dummy_netdev_ops;
 
 		phy->phydev = of_phy_connect(&phy->netdev, phy_np,
-					mt753x_phy_link_handler, 0, phy_mode);
+					     mt753x_phy_link_handler, 0, iface);
 		if (!phy->phydev) {
 			dev_info(gsw->dev, "could not connect to PHY %d\n",
 				 phyad);
@@ -640,7 +652,7 @@
 	gsw->gphy_bus->priv = gsw;
 	gsw->gphy_bus->parent = gsw->dev;
 	gsw->gphy_bus->phy_mask = BIT(MT753X_NUM_PHYS) - 1;
-//	gsw->gphy_bus->irq = gsw->phy_irqs;
+	//	gsw->gphy_bus->irq = gsw->phy_irqs;
 
 	for (i = 0; i < PHY_MAX_ADDR; i++)
 		gsw->gphy_bus->irq[i] = PHY_POLL;
@@ -655,7 +667,6 @@
 	ret = of_mdiobus_register(gsw->gphy_bus, mii_np);
 
 	if (ret) {
-		devm_mdiobus_free(gsw->dev, gsw->gphy_bus);
 		gsw->gphy_bus = NULL;
 	} else {
 		if (gsw->phy_status_poll)
@@ -668,7 +679,6 @@
 
 	return ret;
 }
-#endif
 
 static irqreturn_t mt753x_irq_handler(int irq, void *dev)
 {
@@ -710,8 +720,10 @@
 	mutex_init(&gsw->mii_lock);
 
 	/* Switch hard reset */
-	if (mt753x_hw_reset(gsw))
+	if (mt753x_hw_reset(gsw)) {
+		dev_info(&pdev->dev, "reset switch fail.\n");
 		goto fail;
+	}
 
 	/* Fetch the SMI address dirst */
 	if (of_property_read_u32(np, "mediatek,smi-addr", &gsw->smi_addr))
@@ -768,8 +780,8 @@
 
 	platform_set_drvdata(pdev, gsw);
 
-	gsw->phy_status_poll = of_property_read_bool(gsw->dev->of_node,
-						     "mediatek,phy-poll");
+	gsw->phy_status_poll =
+		of_property_read_bool(gsw->dev->of_node, "mediatek,phy-poll");
 
 	mt753x_add_gsw(gsw);
 #if 1 //XDXD
@@ -825,7 +837,7 @@
 
 static const struct of_device_id mt753x_ids[] = {
 	{ .compatible = "mediatek,mt753x" },
-	{ },
+	{},
 };
 
 MODULE_DEVICE_TABLE(of, mt753x_ids);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.c
old mode 100755
new mode 100644
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h
old mode 100755
new mode 100644
index 7a2a992..e36b6f3
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_nl.h
@@ -38,7 +38,6 @@
 #ifdef __KERNEL__
 int mt753x_nl_init(void);
 void mt753x_nl_exit(void);
-
 #endif /* __KERNEL__ */
 
 #endif /* _MT753X_NL_H_ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h
old mode 100755
new mode 100644
index 1784873..733da63
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_regs.h
@@ -9,6 +9,9 @@
 
 #include <linux/bitops.h>
 
+/* ethernet wrap register */
+#define ETH_RESET		0x8
+
 /* Values of Egress TAG Control */
 #define ETAG_CTRL_UNTAG			0
 #define ETAG_CTRL_TAG			2
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt753x_swconfig.c
old mode 100755
new mode 100644
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c
new file mode 100644
index 0000000..3be91dd
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/pinctrl/mediatek/pinctrl-mt7988.c
@@ -0,0 +1,1467 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The MT7988 driver based on Linux generic pinctrl binding.
+ *
+ * Copyright (C) 2020 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#include "pinctrl-moore.h"
+
+enum MT7988_PINCTRL_REG_PAGE {
+	GPIO_BASE,
+	IOCFG_TR_BASE,
+	IOCFG_BR_BASE,
+	IOCFG_RB_BASE,
+	IOCFG_LB_BASE,
+	IOCFG_TL_BASE,
+};
+
+#define MT7988_PIN(_number, _name) MTK_PIN(_number, _name, 0, _number, DRV_GRP4)
+
+#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,     \
+		       _x_bits)                                                \
+	PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,     \
+		       _x_bits, 32, 0)
+
+#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,    \
+			_x_bits)                                               \
+	PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit,     \
+		       _x_bits, 32, 1)
+
+static const struct mtk_pin_field_calc mt7988_pin_mode_range[] = {
+	PIN_FIELD(0, 83, 0x300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_dir_range[] = {
+	PIN_FIELD(0, 83, 0x0, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_di_range[] = {
+	PIN_FIELD(0, 83, 0x200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_do_range[] = {
+	PIN_FIELD(0, 83, 0x100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_ies_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x30, 0x10, 13, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0x30, 0x10, 14, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x30, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0x30, 0x10, 12, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0x30, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 6, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(10, 10, 4, 0x30, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0x40, 0x10, 21, 1),
+	PIN_FIELD_BASE(13, 13, 1, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(14, 14, 1, 0x40, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(15, 15, 5, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(16, 16, 5, 0x30, 0x10, 8, 1),
+	PIN_FIELD_BASE(17, 17, 5, 0x30, 0x10, 3, 1),
+	PIN_FIELD_BASE(18, 18, 5, 0x30, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x30, 0x10, 7, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0x30, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x50, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0x50, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0x50, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0x50, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0x50, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0x50, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0x50, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0x50, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0x50, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0x50, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0x50, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0x50, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x50, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x50, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x50, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x50, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x50, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0x50, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0x50, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0x50, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0x50, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0x50, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0x50, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0x50, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x40, 0x10, 14, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x40, 0x10, 15, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x40, 0x10, 13, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(63, 63, 1, 0x40, 0x10, 20, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0x40, 0x10, 8, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0x40, 0x10, 9, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0x40, 0x10, 10, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0x40, 0x10, 11, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0x40, 0x10, 12, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0x30, 0x10, 5, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0x30, 0x10, 6, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x30, 0x10, 10, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0x30, 0x10, 1, 1),
+	PIN_FIELD_BASE(75, 75, 4, 0x30, 0x10, 11, 1),
+	PIN_FIELD_BASE(76, 76, 4, 0x30, 0x10, 9, 1),
+	PIN_FIELD_BASE(77, 77, 4, 0x30, 0x10, 2, 1),
+	PIN_FIELD_BASE(78, 78, 4, 0x30, 0x10, 0, 1),
+	PIN_FIELD_BASE(79, 79, 4, 0x30, 0x10, 12, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x40, 0x10, 18, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0x40, 0x10, 19, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0x40, 0x10, 16, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0x40, 0x10, 17, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_smt_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0xc0, 0x10, 13, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0xc0, 0x10, 14, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0xc0, 0x10, 11, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0xc0, 0x10, 12, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0xc0, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0xc0, 0x10, 9, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0xc0, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(7, 7, 4, 0xb0, 0x10, 8, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0xb0, 0x10, 6, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0xb0, 0x10, 5, 1),
+	PIN_FIELD_BASE(10, 10, 4, 0xb0, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0xe0, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0xe0, 0x10, 21, 1),
+	PIN_FIELD_BASE(13, 13, 1, 0xe0, 0x10, 1, 1),
+	PIN_FIELD_BASE(14, 14, 1, 0xe0, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(15, 15, 5, 0xc0, 0x10, 7, 1),
+	PIN_FIELD_BASE(16, 16, 5, 0xc0, 0x10, 8, 1),
+	PIN_FIELD_BASE(17, 17, 5, 0xc0, 0x10, 3, 1),
+	PIN_FIELD_BASE(18, 18, 5, 0xc0, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0xb0, 0x10, 7, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0xb0, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x140, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0x140, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0x140, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0x140, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0x140, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0x140, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0x140, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0x140, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0x140, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0x140, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0x140, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0x140, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x150, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x140, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x140, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x140, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x150, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x140, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x140, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0x140, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0x140, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0x140, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0x140, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0x140, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0x140, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0x140, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0x140, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0x140, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0x140, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0x140, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0x140, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0x140, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0x140, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0x140, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0xe0, 0x10, 14, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0xe0, 0x10, 15, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0xe0, 0x10, 13, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0xe0, 0x10, 4, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0xe0, 0x10, 5, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0xe0, 0x10, 6, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0xe0, 0x10, 3, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0xe0, 0x10, 7, 1),
+	PIN_FIELD_BASE(63, 63, 1, 0xe0, 0x10, 20, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0xe0, 0x10, 8, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0xe0, 0x10, 9, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0xe0, 0x10, 10, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0xe0, 0x10, 11, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0xe0, 0x10, 12, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0xc0, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0xc0, 0x10, 2, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0xc0, 0x10, 5, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0xc0, 0x10, 6, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0xb0, 0x10, 10, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0xb0, 0x10, 1, 1),
+	PIN_FIELD_BASE(75, 75, 4, 0xb0, 0x10, 11, 1),
+	PIN_FIELD_BASE(76, 76, 4, 0xb0, 0x10, 9, 1),
+	PIN_FIELD_BASE(77, 77, 4, 0xb0, 0x10, 2, 1),
+	PIN_FIELD_BASE(78, 78, 4, 0xb0, 0x10, 0, 1),
+	PIN_FIELD_BASE(79, 79, 4, 0xb0, 0x10, 12, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0xe0, 0x10, 18, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0xe0, 0x10, 19, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0xe0, 0x10, 16, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0xe0, 0x10, 17, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_pu_range[] = {
+	PIN_FIELD_BASE(7, 7, 4, 0x60, 0x10, 5, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x60, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(10, 10, 4, 0x60, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(13, 13, 1, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(14, 14, 1, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(63, 63, 1, 0x70, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(75, 75, 4, 0x60, 0x10, 7, 1),
+	PIN_FIELD_BASE(76, 76, 4, 0x60, 0x10, 6, 1),
+	PIN_FIELD_BASE(77, 77, 4, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(78, 78, 4, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(79, 79, 4, 0x60, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_pd_range[] = {
+	PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(9, 9, 4, 0x40, 0x10, 3, 1),
+	PIN_FIELD_BASE(10, 10, 4, 0x40, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(13, 13, 1, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(14, 14, 1, 0x50, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(15, 15, 5, 0x40, 0x10, 4, 1),
+	PIN_FIELD_BASE(16, 16, 5, 0x40, 0x10, 5, 1),
+	PIN_FIELD_BASE(17, 17, 5, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(18, 18, 5, 0x40, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(63, 63, 1, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(71, 71, 5, 0x40, 0x10, 2, 1),
+	PIN_FIELD_BASE(72, 72, 5, 0x40, 0x10, 3, 1),
+
+	PIN_FIELD_BASE(75, 75, 4, 0x40, 0x10, 7, 1),
+	PIN_FIELD_BASE(76, 76, 4, 0x40, 0x10, 6, 1),
+	PIN_FIELD_BASE(77, 77, 4, 0x40, 0x10, 1, 1),
+	PIN_FIELD_BASE(78, 78, 4, 0x40, 0x10, 0, 1),
+	PIN_FIELD_BASE(79, 79, 4, 0x40, 0x10, 8, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_drv_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(1, 1, 5, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(3, 3, 5, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(4, 4, 5, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(5, 5, 5, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(6, 6, 5, 0x00, 0x10, 12, 3),
+
+	PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 28, 3),
+	PIN_FIELD_BASE(9, 9, 4, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(10, 10, 4, 0x00, 0x10, 9, 3),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(12, 12, 1, 0x20, 0x10, 3, 3),
+	PIN_FIELD_BASE(13, 13, 1, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(14, 14, 1, 0x00, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(20, 20, 4, 0x00, 0x10, 12, 3),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x10, 0x10, 21, 3),
+	PIN_FIELD_BASE(22, 22, 3, 0x20, 0x10, 9, 3),
+	PIN_FIELD_BASE(23, 23, 3, 0x20, 0x10, 0, 3),
+	PIN_FIELD_BASE(24, 24, 3, 0x10, 0x10, 27, 3),
+	PIN_FIELD_BASE(25, 25, 3, 0x20, 0x10, 3, 3),
+	PIN_FIELD_BASE(26, 26, 3, 0x20, 0x10, 6, 3),
+	PIN_FIELD_BASE(27, 27, 3, 0x10, 0x10, 24, 3),
+	PIN_FIELD_BASE(28, 28, 3, 0x20, 0x10, 15, 3),
+	PIN_FIELD_BASE(29, 29, 3, 0x20, 0x10, 18, 3),
+	PIN_FIELD_BASE(30, 30, 3, 0x20, 0x10, 21, 3),
+	PIN_FIELD_BASE(31, 31, 3, 0x20, 0x10, 12, 3),
+	PIN_FIELD_BASE(32, 32, 3, 0x20, 0x10, 24, 3),
+	PIN_FIELD_BASE(33, 33, 3, 0x30, 0x10, 6, 3),
+	PIN_FIELD_BASE(34, 34, 3, 0x30, 0x10, 3, 3),
+	PIN_FIELD_BASE(35, 35, 3, 0x20, 0x10, 27, 3),
+	PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 0, 3),
+	PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 9, 3),
+	PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(40, 40, 3, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(41, 41, 3, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(42, 42, 3, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(43, 43, 3, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(44, 44, 3, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(45, 45, 3, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(46, 46, 3, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(47, 47, 3, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(48, 48, 3, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(49, 49, 3, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(50, 50, 3, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(51, 51, 3, 0x10, 0x10, 6, 3),
+	PIN_FIELD_BASE(52, 52, 3, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(53, 53, 3, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(54, 54, 3, 0x10, 0x10, 18, 3),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x10, 0x10, 12, 3),
+	PIN_FIELD_BASE(56, 56, 1, 0x10, 0x10, 15, 3),
+	PIN_FIELD_BASE(57, 57, 1, 0x10, 0x10, 9, 3),
+	PIN_FIELD_BASE(58, 58, 1, 0x00, 0x10, 12, 3),
+	PIN_FIELD_BASE(59, 59, 1, 0x00, 0x10, 15, 3),
+	PIN_FIELD_BASE(60, 60, 1, 0x00, 0x10, 18, 3),
+	PIN_FIELD_BASE(61, 61, 1, 0x00, 0x10, 9, 3),
+	PIN_FIELD_BASE(62, 62, 1, 0x00, 0x10, 21, 3),
+	PIN_FIELD_BASE(63, 63, 1, 0x20, 0x10, 0, 3),
+	PIN_FIELD_BASE(64, 64, 1, 0x00, 0x10, 24, 3),
+	PIN_FIELD_BASE(65, 65, 1, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(66, 66, 1, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(67, 67, 1, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(68, 68, 1, 0x10, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(70, 70, 5, 0x00, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x10, 0x10, 0, 3),
+	PIN_FIELD_BASE(74, 74, 4, 0x00, 0x10, 3, 3),
+	PIN_FIELD_BASE(75, 75, 4, 0x10, 0x10, 3, 3),
+	PIN_FIELD_BASE(76, 76, 4, 0x00, 0x10, 27, 3),
+	PIN_FIELD_BASE(77, 77, 4, 0x00, 0x10, 6, 3),
+	PIN_FIELD_BASE(78, 78, 4, 0x00, 0x10, 0, 3),
+	PIN_FIELD_BASE(79, 79, 4, 0x10, 0x10, 6, 3),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x10, 0x10, 24, 3),
+	PIN_FIELD_BASE(81, 81, 1, 0x10, 0x10, 27, 3),
+	PIN_FIELD_BASE(82, 82, 1, 0x10, 0x10, 18, 3),
+	PIN_FIELD_BASE(83, 83, 1, 0x10, 0x10, 21, 3),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_pupd_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x50, 0x10, 7, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0x50, 0x10, 8, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x50, 0x10, 5, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0x50, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0x50, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0x50, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0x60, 0x10, 18, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x50, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0x50, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x70, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0x70, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0x70, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0x70, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0x70, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0x70, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0x70, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0x70, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0x70, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0x70, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0x70, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0x70, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x70, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x70, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x70, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x70, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x70, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0x70, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0x70, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0x70, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0x70, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0x70, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0x70, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0x70, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0x70, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0x70, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0x70, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0x70, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0x70, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x60, 0x10, 12, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x60, 0x10, 13, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x60, 0x10, 11, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x60, 0x10, 2, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x60, 0x10, 4, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0x60, 0x10, 5, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0x60, 0x10, 6, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0x60, 0x10, 7, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0x60, 0x10, 8, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0x60, 0x10, 9, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0x60, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x50, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x50, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x50, 0x10, 3, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0x50, 0x10, 0, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x60, 0x10, 16, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0x60, 0x10, 17, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0x60, 0x10, 14, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0x60, 0x10, 15, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_r0_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x60, 0x10, 7, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0x60, 0x10, 8, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x60, 0x10, 5, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0x60, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0x60, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0x60, 0x10, 3, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0x60, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x80, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0x80, 0x10, 18, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x70, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0x70, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0x90, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0x90, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0x90, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0x90, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0x90, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0x90, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0x90, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0x90, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0x90, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0x90, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0x90, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0x90, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0xa0, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0x90, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0x90, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0x90, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0xa0, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0x90, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0x90, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0x90, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0x90, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0x90, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0x90, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0x90, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0x90, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0x90, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0x90, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x80, 0x10, 12, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x80, 0x10, 13, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x80, 0x10, 11, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x80, 0x10, 3, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x80, 0x10, 4, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x80, 0x10, 1, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0x80, 0x10, 5, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0x80, 0x10, 6, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0x80, 0x10, 7, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0x80, 0x10, 8, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0x80, 0x10, 9, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0x80, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x60, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x60, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0x70, 0x10, 0, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x80, 0x10, 16, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0x80, 0x10, 17, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0x80, 0x10, 14, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0x80, 0x10, 15, 1),
+};
+
+static const struct mtk_pin_field_calc mt7988_pin_r1_range[] = {
+	PIN_FIELD_BASE(0, 0, 5, 0x70, 0x10, 7, 1),
+	PIN_FIELD_BASE(1, 1, 5, 0x70, 0x10, 8, 1),
+	PIN_FIELD_BASE(2, 2, 5, 0x70, 0x10, 5, 1),
+	PIN_FIELD_BASE(3, 3, 5, 0x70, 0x10, 6, 1),
+	PIN_FIELD_BASE(4, 4, 5, 0x70, 0x10, 0, 1),
+	PIN_FIELD_BASE(5, 5, 5, 0x70, 0x10, 3, 1),
+	PIN_FIELD_BASE(6, 6, 5, 0x70, 0x10, 4, 1),
+
+	PIN_FIELD_BASE(11, 11, 1, 0x90, 0x10, 0, 1),
+	PIN_FIELD_BASE(12, 12, 1, 0x90, 0x10, 18, 1),
+
+	PIN_FIELD_BASE(19, 19, 4, 0x80, 0x10, 2, 1),
+	PIN_FIELD_BASE(20, 20, 4, 0x80, 0x10, 1, 1),
+
+	PIN_FIELD_BASE(21, 21, 3, 0xb0, 0x10, 17, 1),
+	PIN_FIELD_BASE(22, 22, 3, 0xb0, 0x10, 23, 1),
+	PIN_FIELD_BASE(23, 23, 3, 0xb0, 0x10, 20, 1),
+	PIN_FIELD_BASE(24, 24, 3, 0xb0, 0x10, 19, 1),
+	PIN_FIELD_BASE(25, 25, 3, 0xb0, 0x10, 21, 1),
+	PIN_FIELD_BASE(26, 26, 3, 0xb0, 0x10, 22, 1),
+	PIN_FIELD_BASE(27, 27, 3, 0xb0, 0x10, 18, 1),
+	PIN_FIELD_BASE(28, 28, 3, 0xb0, 0x10, 25, 1),
+	PIN_FIELD_BASE(29, 29, 3, 0xb0, 0x10, 26, 1),
+	PIN_FIELD_BASE(30, 30, 3, 0xb0, 0x10, 27, 1),
+	PIN_FIELD_BASE(31, 31, 3, 0xb0, 0x10, 24, 1),
+	PIN_FIELD_BASE(32, 32, 3, 0xb0, 0x10, 28, 1),
+	PIN_FIELD_BASE(33, 33, 3, 0xc0, 0x10, 0, 1),
+	PIN_FIELD_BASE(34, 34, 3, 0xb0, 0x10, 31, 1),
+	PIN_FIELD_BASE(35, 35, 3, 0xb0, 0x10, 29, 1),
+	PIN_FIELD_BASE(36, 36, 3, 0xb0, 0x10, 30, 1),
+	PIN_FIELD_BASE(37, 37, 3, 0xc0, 0x10, 1, 1),
+	PIN_FIELD_BASE(38, 38, 3, 0xb0, 0x10, 11, 1),
+	PIN_FIELD_BASE(39, 39, 3, 0xb0, 0x10, 10, 1),
+	PIN_FIELD_BASE(40, 40, 3, 0xb0, 0x10, 0, 1),
+	PIN_FIELD_BASE(41, 41, 3, 0xb0, 0x10, 1, 1),
+	PIN_FIELD_BASE(42, 42, 3, 0xb0, 0x10, 9, 1),
+	PIN_FIELD_BASE(43, 43, 3, 0xb0, 0x10, 8, 1),
+	PIN_FIELD_BASE(44, 44, 3, 0xb0, 0x10, 7, 1),
+	PIN_FIELD_BASE(45, 45, 3, 0xb0, 0x10, 6, 1),
+	PIN_FIELD_BASE(46, 46, 3, 0xb0, 0x10, 5, 1),
+	PIN_FIELD_BASE(47, 47, 3, 0xb0, 0x10, 4, 1),
+	PIN_FIELD_BASE(48, 48, 3, 0xb0, 0x10, 3, 1),
+	PIN_FIELD_BASE(49, 49, 3, 0xb0, 0x10, 2, 1),
+	PIN_FIELD_BASE(50, 50, 3, 0xb0, 0x10, 15, 1),
+	PIN_FIELD_BASE(51, 51, 3, 0xb0, 0x10, 12, 1),
+	PIN_FIELD_BASE(52, 52, 3, 0xb0, 0x10, 13, 1),
+	PIN_FIELD_BASE(53, 53, 3, 0xb0, 0x10, 14, 1),
+	PIN_FIELD_BASE(54, 54, 3, 0xb0, 0x10, 16, 1),
+
+	PIN_FIELD_BASE(55, 55, 1, 0x90, 0x10, 12, 1),
+	PIN_FIELD_BASE(56, 56, 1, 0x90, 0x10, 13, 1),
+	PIN_FIELD_BASE(57, 57, 1, 0x90, 0x10, 11, 1),
+	PIN_FIELD_BASE(58, 58, 1, 0x90, 0x10, 2, 1),
+	PIN_FIELD_BASE(59, 59, 1, 0x90, 0x10, 3, 1),
+	PIN_FIELD_BASE(60, 60, 1, 0x90, 0x10, 4, 1),
+	PIN_FIELD_BASE(61, 61, 1, 0x90, 0x10, 1, 1),
+	PIN_FIELD_BASE(62, 62, 1, 0x90, 0x10, 5, 1),
+	PIN_FIELD_BASE(64, 64, 1, 0x90, 0x10, 6, 1),
+	PIN_FIELD_BASE(65, 65, 1, 0x90, 0x10, 7, 1),
+	PIN_FIELD_BASE(66, 66, 1, 0x90, 0x10, 8, 1),
+	PIN_FIELD_BASE(67, 67, 1, 0x90, 0x10, 9, 1),
+	PIN_FIELD_BASE(68, 68, 1, 0x90, 0x10, 10, 1),
+
+	PIN_FIELD_BASE(69, 69, 5, 0x70, 0x10, 1, 1),
+	PIN_FIELD_BASE(70, 70, 5, 0x70, 0x10, 2, 1),
+
+	PIN_FIELD_BASE(73, 73, 4, 0x80, 0x10, 3, 1),
+	PIN_FIELD_BASE(74, 74, 4, 0x80, 0x10, 0, 1),
+
+	PIN_FIELD_BASE(80, 80, 1, 0x90, 0x10, 16, 1),
+	PIN_FIELD_BASE(81, 81, 1, 0x90, 0x10, 17, 1),
+	PIN_FIELD_BASE(82, 82, 1, 0x90, 0x10, 14, 1),
+	PIN_FIELD_BASE(83, 83, 1, 0x90, 0x10, 15, 1),
+};
+
+static const struct mtk_pin_reg_calc mt7988_reg_cals[] = {
+	[PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7988_pin_mode_range),
+	[PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7988_pin_dir_range),
+	[PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7988_pin_di_range),
+	[PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7988_pin_do_range),
+	[PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7988_pin_smt_range),
+	[PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7988_pin_ies_range),
+	[PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7988_pin_pu_range),
+	[PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7988_pin_pd_range),
+	[PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7988_pin_drv_range),
+	[PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7988_pin_pupd_range),
+	[PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7988_pin_r0_range),
+	[PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7988_pin_r1_range),
+};
+
+static const struct mtk_pin_desc mt7988_pins[] = {
+	MT7988_PIN(0, "UART2_RXD"),
+	MT7988_PIN(1, "UART2_TXD"),
+	MT7988_PIN(2, "UART2_CTS"),
+	MT7988_PIN(3, "UART2_RTS"),
+	MT7988_PIN(4, "GPIO_A"),
+	MT7988_PIN(5, "SMI_0_MDC"),
+	MT7988_PIN(6, "SMI_0_MDIO"),
+	MT7988_PIN(7, "PCIE30_2L_0_WAKE_N"),
+	MT7988_PIN(8, "PCIE30_2L_0_CLKREQ_N"),
+	MT7988_PIN(9, "PCIE30_1L_1_WAKE_N"),
+	MT7988_PIN(10, "PCIE30_1L_1_CLKREQ_N"),
+	MT7988_PIN(11, "GPIO_P"),
+	MT7988_PIN(12, "WATCHDOG"),
+	MT7988_PIN(13, "GPIO_RESET"),
+	MT7988_PIN(14, "GPIO_WPS"),
+	MT7988_PIN(15, "PMIC_I2C_SCL"),
+	MT7988_PIN(16, "PMIC_I2C_SDA"),
+	MT7988_PIN(17, "I2C_1_SCL"),
+	MT7988_PIN(18, "I2C_1_SDA"),
+	MT7988_PIN(19, "PCIE30_2L_0_PRESET_N"),
+	MT7988_PIN(20, "PCIE30_1L_1_PRESET_N"),
+	MT7988_PIN(21, "PWMD1"),
+	MT7988_PIN(22, "SPI0_WP"),
+	MT7988_PIN(23, "SPI0_HOLD"),
+	MT7988_PIN(24, "SPI0_CSB"),
+	MT7988_PIN(25, "SPI0_MISO"),
+	MT7988_PIN(26, "SPI0_MOSI"),
+	MT7988_PIN(27, "SPI0_CLK"),
+	MT7988_PIN(28, "SPI1_CSB"),
+	MT7988_PIN(29, "SPI1_MISO"),
+	MT7988_PIN(30, "SPI1_MOSI"),
+	MT7988_PIN(31, "SPI1_CLK"),
+	MT7988_PIN(32, "SPI2_CLK"),
+	MT7988_PIN(33, "SPI2_MOSI"),
+	MT7988_PIN(34, "SPI2_MISO"),
+	MT7988_PIN(35, "SPI2_CSB"),
+	MT7988_PIN(36, "SPI2_HOLD"),
+	MT7988_PIN(37, "SPI2_WP"),
+	MT7988_PIN(38, "EMMC_RSTB"),
+	MT7988_PIN(39, "EMMC_DSL"),
+	MT7988_PIN(40, "EMMC_CK"),
+	MT7988_PIN(41, "EMMC_CMD"),
+	MT7988_PIN(42, "EMMC_DATA_7"),
+	MT7988_PIN(43, "EMMC_DATA_6"),
+	MT7988_PIN(44, "EMMC_DATA_5"),
+	MT7988_PIN(45, "EMMC_DATA_4"),
+	MT7988_PIN(46, "EMMC_DATA_3"),
+	MT7988_PIN(47, "EMMC_DATA_2"),
+	MT7988_PIN(48, "EMMC_DATA_1"),
+	MT7988_PIN(49, "EMMC_DATA_0"),
+	MT7988_PIN(50, "PCM_FS_I2S_LRCK"),
+	MT7988_PIN(51, "PCM_CLK_I2S_BCLK"),
+	MT7988_PIN(52, "PCM_DRX_I2S_DIN"),
+	MT7988_PIN(53, "PCM_DTX_I2S_DOUT"),
+	MT7988_PIN(54, "PCM_MCK_I2S_MCLK"),
+	MT7988_PIN(55, "UART0_RXD"),
+	MT7988_PIN(56, "UART0_TXD"),
+	MT7988_PIN(57, "PWMD0"),
+	MT7988_PIN(58, "JTAG_JTDI"),
+	MT7988_PIN(59, "JTAG_JTDO"),
+	MT7988_PIN(60, "JTAG_JTMS"),
+	MT7988_PIN(61, "JTAG_JTCLK"),
+	MT7988_PIN(62, "JTAG_JTRST_N"),
+	MT7988_PIN(63, "USB_DRV_VBUS_P1"),
+	MT7988_PIN(64, "LED_A"),
+	MT7988_PIN(65, "LED_B"),
+	MT7988_PIN(66, "LED_C"),
+	MT7988_PIN(67, "LED_D"),
+	MT7988_PIN(68, "LED_E"),
+	MT7988_PIN(69, "GPIO_B"),
+	MT7988_PIN(70, "GPIO_C"),
+	MT7988_PIN(71, "I2C_2_SCL"),
+	MT7988_PIN(72, "I2C_2_SDA"),
+	MT7988_PIN(73, "PCIE30_2L_1_PRESET_N"),
+	MT7988_PIN(74, "PCIE30_1L_0_PRESET_N"),
+	MT7988_PIN(75, "PCIE30_2L_1_WAKE_N"),
+	MT7988_PIN(76, "PCIE30_2L_1_CLKREQ_N"),
+	MT7988_PIN(77, "PCIE30_1L_0_WAKE_N"),
+	MT7988_PIN(78, "PCIE30_1L_0_CLKREQ_N"),
+	MT7988_PIN(79, "USB_DRV_VBUS_P0"),
+	MT7988_PIN(80, "UART1_RXD"),
+	MT7988_PIN(81, "UART1_TXD"),
+	MT7988_PIN(82, "UART1_CTS"),
+	MT7988_PIN(83, "UART1_RTS"),
+};
+
+/* jtag */
+static int mt7988_tops_jtag0_0_pins[] = { 0, 1, 2, 3, 4 };
+static int mt7988_tops_jtag0_0_funcs[] = { 2, 2, 2, 2, 2 };
+
+static int mt7988_wo0_jtag_pins[] = { 50, 51, 52, 53, 54 };
+static int mt7988_wo0_jtag_funcs[] = { 3, 3, 3, 3, 3 };
+
+static int mt7988_wo1_jtag_pins[] = { 50, 51, 52, 53, 54 };
+static int mt7988_wo1_jtag_funcs[] = { 4, 4, 4, 4, 4 };
+
+static int mt7988_wo2_jtag_pins[] = { 50, 51, 52, 53, 54 };
+static int mt7988_wo2_jtag_funcs[] = { 5, 5, 5, 5, 5 };
+
+static int mt7988_jtag_pins[] = { 58, 59, 60, 61, 62 };
+static int mt7988_jtag_funcs[] = { 1, 1, 1, 1, 1 };
+
+static int mt7988_tops_jtag0_1_pins[] = { 58, 59, 60, 61, 62 };
+static int mt7988_tops_jtag0_1_funcs[] = { 4, 4, 4, 4, 4 };
+
+/* int_usxgmii */
+static int mt7988_int_usxgmii_pins[] = { 2, 3 };
+static int mt7988_int_usxgmii_funcs[] = { 3, 3 };
+
+/* pwm */
+static int mt7988_pwm7_0_pins[] = { 4 };
+static int mt7988_pwm7_0_funcs[] = { 3 };
+
+static int mt7988_pwm1_pins[] = { 21 };
+static int mt7988_pwm1_funcs[] = { 1 };
+
+static int mt7988_pwm0_pins[] = { 57 };
+static int mt7988_pwm0_funcs[] = { 1 };
+
+static int mt7988_pwm2_pins[] = { 58 };
+static int mt7988_pwm2_funcs[] = { 5 };
+
+static int mt7988_pwm3_pins[] = { 59 };
+static int mt7988_pwm3_funcs[] = { 5 };
+
+static int mt7988_pwm4_pins[] = { 60 };
+static int mt7988_pwm4_funcs[] = { 5 };
+
+static int mt7988_pwm5_pins[] = { 61 };
+static int mt7988_pwm5_funcs[] = { 5 };
+
+static int mt7988_pwm6_0_pins[] = { 62 };
+static int mt7988_pwm6_0_funcs[] = { 5 };
+
+static int mt7988_pwm6_1_pins[] = { 69 };
+static int mt7988_pwm6_1_funcs[] = { 3 };
+
+static int mt7988_pwm7_pins[] = { 70 };
+static int mt7988_pwm7_funcs[] = { 3 };
+
+static int mt7988_pwm2_1_pins[] = { 80 };
+static int mt7988_pwm2_1_funcs[] = { 2 };
+
+static int mt7988_pwm3_1_pins[] = { 81 };
+static int mt7988_pwm3_1_funcs[] = { 2 };
+
+static int mt7988_pwm4_1_pins[] = { 82 };
+static int mt7988_pwm4_1_funcs[] = { 2 };
+
+static int mt7988_pwm5_1_pins[] = { 83 };
+static int mt7988_pwm5_1_funcs[] = { 2 };
+
+/* dfd */
+static int mt7988_dfd_pins[] = { 0, 1, 2, 3, 4 };
+static int mt7988_dfd_funcs[] = { 4, 4, 4, 4, 4 };
+
+/* i2c */
+static int mt7988_xfi_phy0_i2c0_pins[] = { 0, 1 };
+static int mt7988_xfi_phy0_i2c0_funcs[] = { 5, 5 };
+
+static int mt7988_xfi_phy1_i2c0_pins[] = { 0, 1 };
+static int mt7988_xfi_phy1_i2c0_funcs[] = { 6, 6 };
+
+static int mt7988_xfi_phy_pll_i2c0_pins[] = { 3, 4 };
+static int mt7988_xfi_phy_pll_i2c0_funcs[] = { 5, 5 };
+
+static int mt7988_xfi_phy_pll_i2c1_pins[] = { 3, 4 };
+static int mt7988_xfi_phy_pll_i2c1_funcs[] = { 6, 6 };
+
+static int mt7988_i2c0_0_pins[] = { 5, 6 };
+static int mt7988_i2c0_0_funcs[] = { 2, 2 };
+
+static int mt7988_i2c1_sfp_pins[] = { 5, 6 };
+static int mt7988_i2c1_sfp_funcs[] = { 4, 4 };
+
+static int mt7988_xfi_pextp_phy0_i2c_pins[] = { 5, 6 };
+static int mt7988_xfi_pextp_phy0_i2c_funcs[] = { 5, 5 };
+
+static int mt7988_xfi_pextp_phy1_i2c_pins[] = { 5, 6 };
+static int mt7988_xfi_pextp_phy1_i2c_funcs[] = { 6, 6 };
+
+static int mt7988_i2c0_1_pins[] = { 15, 16 };
+static int mt7988_i2c0_1_funcs[] = { 1, 1 };
+
+static int mt7988_u30_phy_i2c0_pins[] = { 15, 16 };
+static int mt7988_u30_phy_i2c0_funcs[] = { 2, 2 };
+
+static int mt7988_u32_phy_i2c0_pins[] = { 15, 16 };
+static int mt7988_u32_phy_i2c0_funcs[] = { 3, 3 };
+
+static int mt7988_xfi_phy0_i2c1_pins[] = { 15, 16 };
+static int mt7988_xfi_phy0_i2c1_funcs[] = { 5, 5 };
+
+static int mt7988_xfi_phy1_i2c1_pins[] = { 15, 16 };
+static int mt7988_xfi_phy1_i2c1_funcs[] = { 6, 6 };
+
+static int mt7988_xfi_phy_pll_i2c2_pins[] = { 15, 16 };
+static int mt7988_xfi_phy_pll_i2c2_funcs[] = { 7, 7 };
+
+static int mt7988_i2c1_0_pins[] = { 17, 18 };
+static int mt7988_i2c1_0_funcs[] = { 1, 1 };
+
+static int mt7988_u30_phy_i2c1_pins[] = { 17, 18 };
+static int mt7988_u30_phy_i2c1_funcs[] = { 2, 2 };
+
+static int mt7988_u32_phy_i2c1_pins[] = { 17, 18 };
+static int mt7988_u32_phy_i2c1_funcs[] = { 3, 3 };
+
+static int mt7988_xfi_phy_pll_i2c3_pins[] = { 17, 18 };
+static int mt7988_xfi_phy_pll_i2c3_funcs[] = { 4, 4 };
+
+static int mt7988_sgmii0_i2c_pins[] = { 17, 18 };
+static int mt7988_sgmii0_i2c_funcs[] = { 5, 5 };
+
+static int mt7988_sgmii1_i2c_pins[] = { 17, 18 };
+static int mt7988_sgmii1_i2c_funcs[] = { 6, 6 };
+
+static int mt7988_i2c1_2_pins[] = { 69, 70 };
+static int mt7988_i2c1_2_funcs[] = { 2, 2 };
+
+static int mt7988_i2c2_0_pins[] = { 69, 70 };
+static int mt7988_i2c2_0_funcs[] = { 4, 4 };
+
+static int mt7988_i2c2_1_pins[] = { 70, 71 };
+static int mt7988_i2c2_1_funcs[] = { 1, 1 };
+
+/* eth */
+static int mt7988_mdc_mdio0_pins[] = { 5, 6 };
+static int mt7988_mdc_mdio0_funcs[] = { 1, 1 };
+
+static int mt7988_2p5g_ext_mdio_pins[] = { 28, 29 };
+static int mt7988_2p5g_ext_mdio_funcs[] = { 6, 6 };
+
+static int mt7988_gbe_ext_mdio_pins[] = { 30, 31 };
+static int mt7988_gbe_ext_mdio_funcs[] = { 6, 6 };
+
+static int mt7988_mdc_mdio1_pins[] = { 69, 70 };
+static int mt7988_mdc_mdio1_funcs[] = { 1, 1 };
+
+/* pcie */
+static int mt7988_pcie_wake_n0_0_pins[] = { 7 };
+static int mt7988_pcie_wake_n0_0_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n0_0_pins[] = { 8 };
+static int mt7988_pcie_clk_req_n0_0_funcs[] = { 1 };
+
+static int mt7988_pcie_wake_n3_0_pins[] = { 9 };
+static int mt7988_pcie_wake_n3_0_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n3_pins[] = { 10 };
+static int mt7988_pcie_clk_req_n3_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n0_1_pins[] = { 10 };
+static int mt7988_pcie_clk_req_n0_1_funcs[] = { 2 };
+
+static int mt7988_pcie_p0_phy_i2c_pins[] = { 7, 8 };
+static int mt7988_pcie_p0_phy_i2c_funcs[] = { 3, 3 };
+
+static int mt7988_pcie_p1_phy_i2c_pins[] = { 7, 8 };
+static int mt7988_pcie_p1_phy_i2c_funcs[] = { 4, 4 };
+
+static int mt7988_pcie_p3_phy_i2c_pins[] = { 9, 10 };
+static int mt7988_pcie_p3_phy_i2c_funcs[] = { 4, 4 };
+
+static int mt7988_pcie_p2_phy_i2c_pins[] = { 7, 8 };
+static int mt7988_pcie_p2_phy_i2c_funcs[] = { 5, 5 };
+
+static int mt7988_ckm_phy_i2c_pins[] = { 9, 10 };
+static int mt7988_ckm_phy_i2c_funcs[] = { 5, 5 };
+
+static int mt7988_pcie_wake_n0_1_pins[] = { 13 };
+static int mt7988_pcie_wake_n0_1_funcs[] = { 2 };
+
+static int mt7988_pcie_wake_n3_1_pins[] = { 14 };
+static int mt7988_pcie_wake_n3_1_funcs[] = { 2 };
+
+static int mt7988_pcie_2l_0_pereset_pins[] = { 19 };
+static int mt7988_pcie_2l_0_pereset_funcs[] = { 1 };
+
+static int mt7988_pcie_1l_1_pereset_pins[] = { 20 };
+static int mt7988_pcie_1l_1_pereset_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n2_1_pins[] = { 63 };
+static int mt7988_pcie_clk_req_n2_1_funcs[] = { 2 };
+
+static int mt7988_pcie_2l_1_pereset_pins[] = { 73 };
+static int mt7988_pcie_2l_1_pereset_funcs[] = { 1 };
+
+static int mt7988_pcie_1l_0_pereset_pins[] = { 74 };
+static int mt7988_pcie_1l_0_pereset_funcs[] = { 1 };
+
+static int mt7988_pcie_wake_n1_0_pins[] = { 75 };
+static int mt7988_pcie_wake_n1_0_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n1_pins[] = { 76 };
+static int mt7988_pcie_clk_req_n1_funcs[] = { 1 };
+
+static int mt7988_pcie_wake_n2_0_pins[] = { 77 };
+static int mt7988_pcie_wake_n2_0_funcs[] = { 1 };
+
+static int mt7988_pcie_clk_req_n2_0_pins[] = { 78 };
+static int mt7988_pcie_clk_req_n2_0_funcs[] = { 1 };
+
+static int mt7988_pcie_wake_n2_1_pins[] = { 79 };
+static int mt7988_pcie_wake_n2_1_funcs[] = { 2 };
+
+/* pmic */
+static int mt7988_pmic_pins[] = { 11 };
+static int mt7988_pmic_funcs[] = { 1 };
+
+/* watchdog */
+static int mt7988_watchdog_pins[] = { 12 };
+static int mt7988_watchdog_funcs[] = { 1 };
+
+/* spi */
+static int mt7988_spi0_wp_hold_pins[] = { 22, 23 };
+static int mt7988_spi0_wp_hold_funcs[] = { 1, 1 };
+
+static int mt7988_spi0_pins[] = { 24, 25, 26, 27 };
+static int mt7988_spi0_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_spi1_pins[] = { 28, 29, 30, 31 };
+static int mt7988_spi1_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_spi2_pins[] = { 32, 33, 34, 35 };
+static int mt7988_spi2_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_spi2_wp_hold_pins[] = { 36, 37 };
+static int mt7988_spi2_wp_hold_funcs[] = { 1, 1 };
+
+/* flash */
+static int mt7988_snfi_pins[] = { 22, 23, 24, 25, 26, 27 };
+static int mt7988_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 };
+
+static int mt7988_emmc_45_pins[] = {
+	21, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37
+};
+static int mt7988_emmc_45_funcs[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
+
+static int mt7988_emmc_51_pins[] = { 38, 39, 40, 41, 42, 43,
+				     44, 45, 46, 47, 48, 49 };
+static int mt7988_emmc_51_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+/* uart */
+static int mt7988_uart2_pins[] = { 0, 1, 2, 3 };
+static int mt7988_uart2_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_tops_uart0_0_pins[] = { 22, 23 };
+static int mt7988_tops_uart0_0_funcs[] = { 3, 3 };
+
+static int mt7988_uart2_0_pins[] = { 28, 29, 30, 31 };
+static int mt7988_uart2_0_funcs[] = { 2, 2, 2, 2 };
+
+static int mt7988_uart1_0_pins[] = { 32, 33, 34, 35 };
+static int mt7988_uart1_0_funcs[] = { 2, 2, 2, 2 };
+
+static int mt7988_uart2_1_pins[] = { 32, 33, 34, 35 };
+static int mt7988_uart2_1_funcs[] = { 3, 3, 3, 3 };
+
+static int mt7988_net_wo0_uart_txd_0_pins[] = { 28 };
+static int mt7988_net_wo0_uart_txd_0_funcs[] = { 3 };
+
+static int mt7988_net_wo1_uart_txd_0_pins[] = { 29 };
+static int mt7988_net_wo1_uart_txd_0_funcs[] = { 3 };
+
+static int mt7988_net_wo2_uart_txd_0_pins[] = { 30 };
+static int mt7988_net_wo2_uart_txd_0_funcs[] = { 3 };
+
+static int mt7988_tops_uart1_0_pins[] = { 28, 29 };
+static int mt7988_tops_uart1_0_funcs[] = { 4, 4 };
+
+static int mt7988_tops_uart0_1_pins[] = { 30, 31 };
+static int mt7988_tops_uart0_1_funcs[] = { 4, 4 };
+
+static int mt7988_tops_uart1_1_pins[] = { 36, 37 };
+static int mt7988_tops_uart1_1_funcs[] = { 3, 3 };
+
+static int mt7988_uart0_pins[] = { 55, 56 };
+static int mt7988_uart0_funcs[] = { 1, 1 };
+
+static int mt7988_tops_uart0_2_pins[] = { 55, 56 };
+static int mt7988_tops_uart0_2_funcs[] = { 2, 2 };
+
+static int mt7988_uart2_2_pins[] = { 50, 51, 52, 53 };
+static int mt7988_uart2_2_funcs[] = { 2, 2, 2, 2 };
+
+static int mt7988_uart1_1_pins[] = { 58, 59, 60, 61 };
+static int mt7988_uart1_1_funcs[] = { 2, 2, 2, 2 };
+
+static int mt7988_uart2_3_pins[] = { 58, 59, 60, 61 };
+static int mt7988_uart2_3_funcs[] = { 3, 3, 3, 3 };
+
+static int mt7988_uart1_2_pins[] = { 80, 81, 82, 83 };
+static int mt7988_uart1_2_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_tops_uart1_2_pins[] = { 80, 81 };
+static int mt7988_tops_uart1_2_funcs[] = {
+	4,
+	4,
+};
+
+static int mt7988_net_wo0_uart_txd_1_pins[] = { 80 };
+static int mt7988_net_wo0_uart_txd_1_funcs[] = { 3 };
+
+static int mt7988_net_wo1_uart_txd_1_pins[] = { 81 };
+static int mt7988_net_wo1_uart_txd_1_funcs[] = { 3 };
+
+static int mt7988_net_wo2_uart_txd_1_pins[] = { 82 };
+static int mt7988_net_wo2_uart_txd_1_funcs[] = { 3 };
+
+/* udi */
+static int mt7988_udi_pins[] = { 32, 33, 34, 35, 36 };
+static int mt7988_udi_funcs[] = { 4, 4, 4, 4, 4 };
+
+/* pcm */
+static int mt7988_pcm_pins[] = { 50, 51, 52, 53, 54 };
+static int mt7988_pcm_funcs[] = { 1, 1, 1, 1, 1 };
+
+/* led */
+static int mt7988_gbe_led1_pins[] = { 58, 59, 60, 61 };
+static int mt7988_gbe_led1_funcs[] = { 6, 6, 6, 6 };
+
+static int mt7988_2p5gbe_led1_pins[] = { 62 };
+static int mt7988_2p5gbe_led1_funcs[] = { 6 };
+
+static int mt7988_gbe_led0_pins[] = { 64, 65, 66, 67 };
+static int mt7988_gbe_led0_funcs[] = { 1, 1, 1, 1 };
+
+static int mt7988_2p5gbe_led0_pins[] = { 68 };
+static int mt7988_2p5gbe_led0_funcs[] = { 1 };
+
+/* usb */
+static int mt7988_drv_vbus_p1_pins[] = { 63 };
+static int mt7988_drv_vbus_p1_funcs[] = { 1 };
+
+static int mt7988_drv_vbus_pins[] = { 79 };
+static int mt7988_drv_vbus_funcs[] = { 1 };
+
+static const struct group_desc mt7988_groups[] = {
+	/*  @GPIO(0,1,2,3): uart2 */
+	PINCTRL_PIN_GROUP("uart2", mt7988_uart2),
+	/*  @GPIO(0,1,2,3,4): tops_jtag0_0 */
+	PINCTRL_PIN_GROUP("tops_jtag0_0", mt7988_tops_jtag0_0),
+	/*  @GPIO(2,3): int_usxgmii */
+	PINCTRL_PIN_GROUP("int_usxgmii", mt7988_int_usxgmii),
+	/*  @GPIO(4): pwm7_0 */
+	PINCTRL_PIN_GROUP("pwm7_0", mt7988_pwm7_0),
+	/*  @GPIO(0,1,2,3,4): dfd */
+	PINCTRL_PIN_GROUP("dfd", mt7988_dfd),
+	/*  @GPIO(0,1): xfi_phy0_i2c0 */
+	PINCTRL_PIN_GROUP("xfi_phy0_i2c0", mt7988_xfi_phy0_i2c0),
+	/*  @GPIO(0,1): xfi_phy1_i2c0 */
+	PINCTRL_PIN_GROUP("xfi_phy1_i2c0", mt7988_xfi_phy1_i2c0),
+	/*  @GPIO(3,4): xfi_phy_pll_i2c0 */
+	PINCTRL_PIN_GROUP("xfi_phy_pll_i2c0", mt7988_xfi_phy_pll_i2c0),
+	/*  @GPIO(3,4): xfi_phy_pll_i2c1 */
+	PINCTRL_PIN_GROUP("xfi_phy_pll_i2c1", mt7988_xfi_phy_pll_i2c1),
+	/*  @GPIO(5,6) i2c0_0 */
+	PINCTRL_PIN_GROUP("i2c0_0", mt7988_i2c0_0),
+	/*  @GPIO(5,6) i2c1_sfp */
+	PINCTRL_PIN_GROUP("i2c1_sfp", mt7988_i2c1_sfp),
+	/*  @GPIO(5,6) xfi_pextp_phy0_i2c */
+	PINCTRL_PIN_GROUP("xfi_pextp_phy0_i2c", mt7988_xfi_pextp_phy0_i2c),
+	/*  @GPIO(5,6) xfi_pextp_phy1_i2c */
+	PINCTRL_PIN_GROUP("xfi_pextp_phy1_i2c", mt7988_xfi_pextp_phy1_i2c),
+	/*  @GPIO(5,6) mdc_mdio0 */
+	PINCTRL_PIN_GROUP("mdc_mdio0", mt7988_mdc_mdio0),
+	/*  @GPIO(7): pcie_wake_n0_0 */
+	PINCTRL_PIN_GROUP("pcie_wake_n0_0", mt7988_pcie_wake_n0_0),
+	/*  @GPIO(8): pcie_clk_req_n0_0 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n0_0", mt7988_pcie_clk_req_n0_0),
+	/*  @GPIO(9): pcie_wake_n3_0 */
+	PINCTRL_PIN_GROUP("pcie_wake_n3_0", mt7988_pcie_wake_n3_0),
+	/*  @GPIO(10): pcie_clk_req_n3 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n3", mt7988_pcie_clk_req_n3),
+	/*  @GPIO(10): pcie_clk_req_n0_1 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n0_1", mt7988_pcie_clk_req_n0_1),
+	/*  @GPIO(7,8) pcie_p0_phy_i2c */
+	PINCTRL_PIN_GROUP("pcie_p0_phy_i2c", mt7988_pcie_p0_phy_i2c),
+	/*  @GPIO(7,8) pcie_p1_phy_i2c */
+	PINCTRL_PIN_GROUP("pcie_p1_phy_i2c", mt7988_pcie_p1_phy_i2c),
+	/*  @GPIO(7,8) pcie_p2_phy_i2c */
+	PINCTRL_PIN_GROUP("pcie_p2_phy_i2c", mt7988_pcie_p2_phy_i2c),
+	/*  @GPIO(9,10) pcie_p3_phy_i2c */
+	PINCTRL_PIN_GROUP("pcie_p3_phy_i2c", mt7988_pcie_p3_phy_i2c),
+	/*  @GPIO(9,10) ckm_phy_i2c */
+	PINCTRL_PIN_GROUP("ckm_phy_i2c", mt7988_ckm_phy_i2c),
+	/*  @GPIO(11): pmic */
+	PINCTRL_PIN_GROUP("pcie_pmic", mt7988_pmic),
+	/*  @GPIO(12): watchdog */
+	PINCTRL_PIN_GROUP("watchdog", mt7988_watchdog),
+	/*  @GPIO(13): pcie_wake_n0_1 */
+	PINCTRL_PIN_GROUP("pcie_wake_n0_1", mt7988_pcie_wake_n0_1),
+	/*  @GPIO(14): pcie_wake_n3_1 */
+	PINCTRL_PIN_GROUP("pcie_wake_n3_1", mt7988_pcie_wake_n3_1),
+	/*  @GPIO(15,16) i2c0_1 */
+	PINCTRL_PIN_GROUP("i2c0_1", mt7988_i2c0_1),
+	/*  @GPIO(15,16) u30_phy_i2c0 */
+	PINCTRL_PIN_GROUP("u30_phy_i2c0", mt7988_u30_phy_i2c0),
+	/*  @GPIO(15,16) u32_phy_i2c0 */
+	PINCTRL_PIN_GROUP("u32_phy_i2c0", mt7988_u32_phy_i2c0),
+	/*  @GPIO(15,16) xfi_phy0_i2c1 */
+	PINCTRL_PIN_GROUP("xfi_phy0_i2c1", mt7988_xfi_phy0_i2c1),
+	/*  @GPIO(15,16) xfi_phy1_i2c1 */
+	PINCTRL_PIN_GROUP("xfi_phy1_i2c1", mt7988_xfi_phy1_i2c1),
+	/*  @GPIO(15,16) xfi_phy_pll_i2c2 */
+	PINCTRL_PIN_GROUP("xfi_phy_pll_i2c2", mt7988_xfi_phy_pll_i2c2),
+	/*  @GPIO(17,18) i2c1_0 */
+	PINCTRL_PIN_GROUP("i2c1_0", mt7988_i2c1_0),
+	/*  @GPIO(17,18) u30_phy_i2c1 */
+	PINCTRL_PIN_GROUP("u30_phy_i2c1", mt7988_u30_phy_i2c1),
+	/*  @GPIO(17,18) u32_phy_i2c1 */
+	PINCTRL_PIN_GROUP("u32_phy_i2c1", mt7988_u32_phy_i2c1),
+	/*  @GPIO(17,18) xfi_phy_pll_i2c3 */
+	PINCTRL_PIN_GROUP("xfi_phy_pll_i2c3", mt7988_xfi_phy_pll_i2c3),
+	/*  @GPIO(17,18) sgmii0_i2c */
+	PINCTRL_PIN_GROUP("sgmii0_i2c", mt7988_sgmii0_i2c),
+	/*  @GPIO(17,18) sgmii1_i2c */
+	PINCTRL_PIN_GROUP("sgmii1_i2c", mt7988_sgmii1_i2c),
+	/*  @GPIO(19): pcie_2l_0_pereset */
+	PINCTRL_PIN_GROUP("pcie_2l_0_pereset", mt7988_pcie_2l_0_pereset),
+	/*  @GPIO(20): pcie_1l_1_pereset */
+	PINCTRL_PIN_GROUP("pcie_1l_1_pereset", mt7988_pcie_1l_1_pereset),
+	/*  @GPIO(21): pwm1 */
+	PINCTRL_PIN_GROUP("pwm1", mt7988_pwm1),
+	/*  @GPIO(22,23) spi0_wp_hold */
+	PINCTRL_PIN_GROUP("spi0_wp_hold", mt7988_spi0_wp_hold),
+	/*  @GPIO(24,25,26,27) spi0 */
+	PINCTRL_PIN_GROUP("spi0", mt7988_spi0),
+	/*  @GPIO(28,29,30,31) spi1 */
+	PINCTRL_PIN_GROUP("spi1", mt7988_spi1),
+	/*  @GPIO(32,33,34,35) spi2 */
+	PINCTRL_PIN_GROUP("spi2", mt7988_spi2),
+	/*  @GPIO(36,37) spi2_wp_hold */
+	PINCTRL_PIN_GROUP("spi2_wp_hold", mt7988_spi2_wp_hold),
+	/*  @GPIO(22,23,24,25,26,27) snfi */
+	PINCTRL_PIN_GROUP("snfi", mt7988_snfi),
+	/*  @GPIO(22,23) tops_uart0_0 */
+	PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart0_0),
+	/*  @GPIO(28,29,30,31) uart2_0 */
+	PINCTRL_PIN_GROUP("uart2_0", mt7988_uart2_0),
+	/*  @GPIO(32,33,34,35) uart1_0 */
+	PINCTRL_PIN_GROUP("uart1_0", mt7988_uart1_0),
+	/*  @GPIO(32,33,34,35) uart2_1 */
+	PINCTRL_PIN_GROUP("uart2_1", mt7988_uart2_1),
+	/*  @GPIO(28) net_wo0_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0),
+	/*  @GPIO(29) net_wo1_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0),
+	/*  @GPIO(30) net_wo2_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0),
+	/*  @GPIO(28,29) tops_uart1_0 */
+	PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart1_0),
+	/*  @GPIO(30,31) tops_uart0_1 */
+	PINCTRL_PIN_GROUP("tops_uart0_1", mt7988_tops_uart0_1),
+	/*  @GPIO(36,37) tops_uart1_1 */
+	PINCTRL_PIN_GROUP("tops_uart1_1", mt7988_tops_uart1_1),
+	/*  @GPIO(32,33,34,35,36) udi */
+	PINCTRL_PIN_GROUP("udi", mt7988_udi),
+	/*  @GPIO(21,28,29,30,31,32,33,34,35,36,37) emmc_45 */
+	PINCTRL_PIN_GROUP("emmc_45", mt7988_emmc_45),
+	/*  @GPIO(38,39,40,41,42,43,44,45,46,47,48,49) emmc_51 */
+	PINCTRL_PIN_GROUP("emmc_51", mt7988_emmc_51),
+	/*  @GPIO(28,29) 2p5g_ext_mdio */
+	PINCTRL_PIN_GROUP("2p5g_ext_mdio", mt7988_2p5g_ext_mdio),
+	/*  @GPIO(30,31) gbe_ext_mdio */
+	PINCTRL_PIN_GROUP("gbe_ext_mdio", mt7988_gbe_ext_mdio),
+	/*  @GPIO(50,51,52,53,54) pcm */
+	PINCTRL_PIN_GROUP("pcm", mt7988_pcm),
+	/*  @GPIO(55,56) uart0 */
+	PINCTRL_PIN_GROUP("uart0", mt7988_uart0),
+	/*  @GPIO(55,56) tops_uart0_2 */
+	PINCTRL_PIN_GROUP("tops_uart0_2", mt7988_tops_uart0_2),
+	/*  @GPIO(50,51,52,53) uart2_2 */
+	PINCTRL_PIN_GROUP("uart2_2", mt7988_uart2_2),
+	/*  @GPIO(50,51,52,53,54) wo0_jtag */
+	PINCTRL_PIN_GROUP("wo0_jtag", mt7988_wo0_jtag),
+	/*  @GPIO(50,51,52,53,54) wo1-wo1_jtag */
+	PINCTRL_PIN_GROUP("wo1_jtag", mt7988_wo1_jtag),
+	/*  @GPIO(50,51,52,53,54) wo2_jtag */
+	PINCTRL_PIN_GROUP("wo2_jtag", mt7988_wo2_jtag),
+	/*  @GPIO(57) pwm0 */
+	PINCTRL_PIN_GROUP("pwm0", mt7988_pwm0),
+	/*  @GPIO(58,59,60,61,62) jtag */
+	PINCTRL_PIN_GROUP("jtag", mt7988_jtag),
+	/*  @GPIO(58,59,60,61,62) tops_jtag0_1 */
+	PINCTRL_PIN_GROUP("tops_jtag0_1", mt7988_tops_jtag0_1),
+	/*  @GPIO(58,59,60,61) uart2_3 */
+	PINCTRL_PIN_GROUP("uart2_3", mt7988_uart2_3),
+	/*  @GPIO(58,59,60,61) uart1_1 */
+	PINCTRL_PIN_GROUP("uart1_1", mt7988_uart1_1),
+	/*  @GPIO(58) pwm2 */
+	PINCTRL_PIN_GROUP("pwm2", mt7988_pwm2),
+	/*  @GPIO(59) pwm3 */
+	PINCTRL_PIN_GROUP("pwm3", mt7988_pwm3),
+	/*  @GPIO(60) pwm4 */
+	PINCTRL_PIN_GROUP("pwm4", mt7988_pwm4),
+	/*  @GPIO(61) pwm5 */
+	PINCTRL_PIN_GROUP("pwm5", mt7988_pwm5),
+	/*  @GPIO(62) pwm6_0 */
+	PINCTRL_PIN_GROUP("pwm6_0", mt7988_pwm6_0),
+	/*  @GPIO(58,59,60,61) gbe_led1 */
+	PINCTRL_PIN_GROUP("gbe_led1", mt7988_gbe_led1),
+	/*  @GPIO(62) 2p5gbe_led1 */
+	PINCTRL_PIN_GROUP("2p5gbe_led1", mt7988_2p5gbe_led1),
+	/*  @GPIO(64,65,66,67) gbe_led0 */
+	PINCTRL_PIN_GROUP("gbe_led0", mt7988_gbe_led0),
+	/*  @GPIO(68) 2p5gbe_led0 */
+	PINCTRL_PIN_GROUP("2p5gbe_led0", mt7988_2p5gbe_led0),
+	/*  @GPIO(63) drv_vbus_p1 */
+	PINCTRL_PIN_GROUP("drv_vbus_p1", mt7988_drv_vbus_p1),
+	/*  @GPIO(63) pcie_clk_req_n2_1 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n2_1", mt7988_pcie_clk_req_n2_1),
+	/*  @GPIO(69, 70) mdc_mdio1 */
+	PINCTRL_PIN_GROUP("mdc_mdio1", mt7988_mdc_mdio1),
+	/*  @GPIO(69, 70) i2c1_2 */
+	PINCTRL_PIN_GROUP("i2c1_2", mt7988_i2c1_2),
+	/*  @GPIO(69) pwm6_1 */
+	PINCTRL_PIN_GROUP("pwm6_1", mt7988_pwm6_1),
+	/*  @GPIO(70) pwm7 */
+	PINCTRL_PIN_GROUP("pwm7", mt7988_pwm7),
+	/*  @GPIO(69,70) i2c2_0 */
+	PINCTRL_PIN_GROUP("i2c2_0", mt7988_i2c2_0),
+	/*  @GPIO(71,72) i2c2_1 */
+	PINCTRL_PIN_GROUP("i2c2_1", mt7988_i2c2_1),
+	/*  @GPIO(73) pcie_2l_1_pereset */
+	PINCTRL_PIN_GROUP("pcie_2l_1_pereset", mt7988_pcie_2l_1_pereset),
+	/*  @GPIO(74) pcie_1l_0_pereset */
+	PINCTRL_PIN_GROUP("pcie_1l_0_pereset", mt7988_pcie_1l_0_pereset),
+	/*  @GPIO(75) pcie_wake_n1_0 */
+	PINCTRL_PIN_GROUP("pcie_wake_n1_0", mt7988_pcie_wake_n1_0),
+	/*  @GPIO(76) pcie_clk_req_n1 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n1", mt7988_pcie_clk_req_n1),
+	/*  @GPIO(77) pcie_wake_n2_0 */
+	PINCTRL_PIN_GROUP("pcie_wake_n2_0", mt7988_pcie_wake_n2_0),
+	/*  @GPIO(78) pcie_clk_req_n2_0 */
+	PINCTRL_PIN_GROUP("pcie_clk_req_n2_0", mt7988_pcie_clk_req_n2_0),
+	/*  @GPIO(79) drv_vbus */
+	PINCTRL_PIN_GROUP("drv_vbus", mt7988_drv_vbus),
+	/*  @GPIO(79) pcie_wake_n2_1 */
+	PINCTRL_PIN_GROUP("pcie_wake_n2_1", mt7988_pcie_wake_n2_1),
+	/*  @GPIO(80,81,82,83) uart1_2 */
+	PINCTRL_PIN_GROUP("uart1_2", mt7988_uart1_2),
+	/*  @GPIO(80) pwm2_1 */
+	PINCTRL_PIN_GROUP("pwm2_1", mt7988_pwm2_1),
+	/*  @GPIO(81) pwm3_1 */
+	PINCTRL_PIN_GROUP("pwm3_1", mt7988_pwm3_1),
+	/*  @GPIO(82) pwm4_1 */
+	PINCTRL_PIN_GROUP("pwm4_1", mt7988_pwm4_1),
+	/*  @GPIO(83) pwm5_1 */
+	PINCTRL_PIN_GROUP("pwm5_1", mt7988_pwm5_1),
+	/*  @GPIO(80) net_wo0_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0),
+	/*  @GPIO(81) net_wo1_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0),
+	/*  @GPIO(82) net_wo2_uart_txd_0 */
+	PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0),
+	/*  @GPIO(80,81) tops_uart1_2 */
+	PINCTRL_PIN_GROUP("tops_uart1_2", mt7988_tops_uart1_2),
+	/*  @GPIO(80) net_wo0_uart_txd_1 */
+	PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7988_net_wo0_uart_txd_1),
+	/*  @GPIO(81) net_wo1_uart_txd_1 */
+	PINCTRL_PIN_GROUP("net_wo1_uart_txd_1", mt7988_net_wo1_uart_txd_1),
+	/*  @GPIO(82) net_wo2_uart_txd_1 */
+	PINCTRL_PIN_GROUP("net_wo2_uart_txd_1", mt7988_net_wo2_uart_txd_1),
+};
+
+/* Joint those groups owning the same capability in user point of view which
+ * allows that people tend to use through the device tree.
+ */
+static const char * const mt7988_jtag_groups[] = {
+	"tops_jtag0_0", "wo0_jtag", "wo1_jtag",
+	"wo2_jtag",	"jtag",	    "tops_jtag0_1",
+};
+static const char * const mt7988_int_usxgmii_groups[] = {
+	"int_usxgmii",
+};
+static const char * const mt7988_pwm_groups[] = {
+	"pwm7_0", "pwm1",   "pwm0", "pwm2",   "pwm3",	"pwm4",	  "pwm5",
+	"pwm6_0", "pwm6_1", "pwm7", "pwm2_1", "pwm3_1", "pwm4_1", "pwm5_1"
+};
+static const char * const mt7988_dfd_groups[] = {
+	"dfd",
+};
+static const char * const mt7988_i2c_groups[] = {
+	"xfi_phy0_i2c0",
+	"xfi_phy1_i2c0",
+	"xfi_phy_pll_i2c0",
+	"xfi_phy_pll_i2c1",
+	"i2c0_0",
+	"i2c1_sfp",
+	"xfi_pextp_phy0_i2c",
+	"xfi_pextp_phy1_i2c",
+	"i2c0_1",
+	"u30_phy_i2c0",
+	"u32_phy_i2c0",
+	"xfi_phy0_i2c1",
+	"xfi_phy1_i2c1",
+	"xfi_phy_pll_i2c2",
+	"i2c1_0",
+	"u30_phy_i2c1",
+	"u32_phy_i2c1",
+	"xfi_phy_pll_i2c3",
+	"sgmii0_i2c",
+	"sgmii1_i2c",
+	"i2c1_2",
+	"i2c2_0",
+	"i2c2_1",
+};
+static const char * const mt7988_ethernet_groups[] = {
+	"mdc_mdio0",
+	"2p5g_ext_mdio",
+	"gbe_ext_mdio",
+	"mdc_mdio1",
+};
+static const char * const mt7988_pcie_groups[] = {
+	"pcie_wake_n0_0",    "pcie_clk_req_n0_0", "pcie_wake_n3_0",
+	"pcie_clk_req_n3",   "pcie_p0_phy_i2c",	  "pcie_p1_phy_i2c",
+	"pcie_p3_phy_i2c",   "pcie_p2_phy_i2c",	  "ckm_phy_i2c",
+	"pcie_wake_n0_1",    "pcie_wake_n3_1",	  "pcie_2l_0_pereset",
+	"pcie_1l_1_pereset", "pcie_clk_req_n2_1", "pcie_2l_1_pereset",
+	"pcie_1l_0_pereset", "pcie_wake_n1_0",	  "pcie_clk_req_n1",
+	"pcie_wake_n2_0",    "pcie_clk_req_n2_0", "pcie_wake_n2_1",
+	"pcie_clk_req_n0_1"
+};
+static const char * const mt7988_pmic_groups[] = {
+	"pmic",
+};
+static const char * const mt7988_wdt_groups[] = {
+	"watchdog",
+};
+static const char * const mt7988_spi_groups[] = {
+	"spi0", "spi0_wp_hold", "spi1", "spi2", "spi2_wp_hold",
+};
+static const char * const mt7988_flash_groups[] = { "emmc_45", "snfi",
+						    "emmc_51" };
+static const char * const mt7988_uart_groups[] = {
+	"uart2",
+	"tops_uart0_0",
+	"uart2_0",
+	"uart1_0",
+	"uart2_1",
+	"net_wo0_uart_txd_0",
+	"net_wo1_uart_txd_0",
+	"net_wo2_uart_txd_0",
+	"tops_uart1_0",
+	"ops_uart0_1",
+	"ops_uart1_1",
+	"uart0",
+	"tops_uart0_2",
+	"uart1_1",
+	"uart2_3",
+	"uart1_2",
+	"tops_uart1_2",
+	"net_wo0_uart_txd_1",
+	"net_wo1_uart_txd_1",
+	"net_wo2_uart_txd_1",
+};
+static const char * const mt7988_udi_groups[] = {
+	"udi",
+};
+static const char * const mt7988_pcm_groups[] = {
+	"pcm",
+};
+static const char * const mt7988_led_groups[] = {
+	"gbe_led1",    "2p5gbe_led1", "gbe_led0",
+	"2p5gbe_led0", "wf5g_led0",   "wf5g_led1",
+};
+static const char * const mt7988_usb_groups[] = {
+	"drv_vbus",
+	"drv_vbus_p1",
+};
+
+static const struct function_desc mt7988_functions[] = {
+	{ "jtag", mt7988_jtag_groups, ARRAY_SIZE(mt7988_jtag_groups) },
+	{ "int_usxgmii", mt7988_int_usxgmii_groups,
+	  ARRAY_SIZE(mt7988_int_usxgmii_groups) },
+	{ "pwm", mt7988_pwm_groups, ARRAY_SIZE(mt7988_pwm_groups) },
+	{ "dfd", mt7988_dfd_groups, ARRAY_SIZE(mt7988_dfd_groups) },
+	{ "i2c", mt7988_i2c_groups, ARRAY_SIZE(mt7988_i2c_groups) },
+	{ "eth", mt7988_ethernet_groups, ARRAY_SIZE(mt7988_ethernet_groups) },
+	{ "pcie", mt7988_pcie_groups, ARRAY_SIZE(mt7988_pcie_groups) },
+	{ "pmic", mt7988_pmic_groups, ARRAY_SIZE(mt7988_pmic_groups) },
+	{ "watchdog", mt7988_wdt_groups, ARRAY_SIZE(mt7988_wdt_groups) },
+	{ "spi", mt7988_spi_groups, ARRAY_SIZE(mt7988_spi_groups) },
+	{ "flash", mt7988_flash_groups, ARRAY_SIZE(mt7988_flash_groups) },
+	{ "uart", mt7988_uart_groups, ARRAY_SIZE(mt7988_uart_groups) },
+	{ "udi", mt7988_udi_groups, ARRAY_SIZE(mt7988_udi_groups) },
+	{ "pcm", mt7988_pcm_groups, ARRAY_SIZE(mt7988_pcm_groups) },
+	{ "usb", mt7988_usb_groups, ARRAY_SIZE(mt7988_usb_groups) },
+	{ "led", mt7988_led_groups, ARRAY_SIZE(mt7988_led_groups) },
+};
+
+static const struct mtk_eint_hw mt7988_eint_hw = {
+	.port_mask = 7,
+	.ports = 7,
+	.ap_num = ARRAY_SIZE(mt7988_pins),
+	.db_cnt = 16,
+};
+
+static const char * const mt7988_pinctrl_register_base_names[] = {
+	"gpio_base",	 "iocfg_tr_base", "iocfg_br_base",
+	"iocfg_rb_base", "iocfg_lb_base", "iocfg_tl_base",
+};
+
+static struct mtk_pin_soc mt7988_data = {
+	.reg_cal = mt7988_reg_cals,
+	.pins = mt7988_pins,
+	.npins = ARRAY_SIZE(mt7988_pins),
+	.grps = mt7988_groups,
+	.ngrps = ARRAY_SIZE(mt7988_groups),
+	.funcs = mt7988_functions,
+	.nfuncs = ARRAY_SIZE(mt7988_functions),
+	.eint_hw = &mt7988_eint_hw,
+	.gpio_m = 0,
+	.ies_present = false,
+	.base_names = mt7988_pinctrl_register_base_names,
+	.nbase_names = ARRAY_SIZE(mt7988_pinctrl_register_base_names),
+	.bias_disable_set = mtk_pinconf_bias_disable_set,
+	.bias_disable_get = mtk_pinconf_bias_disable_get,
+	.bias_set = mtk_pinconf_bias_set,
+	.bias_get = mtk_pinconf_bias_get,
+	.drive_set = mtk_pinconf_drive_set_rev1,
+	.drive_get = mtk_pinconf_drive_get_rev1,
+	.adv_pull_get = mtk_pinconf_adv_pull_get,
+	.adv_pull_set = mtk_pinconf_adv_pull_set,
+};
+
+static const struct of_device_id mt7988_pinctrl_of_match[] = {
+	{
+		.compatible = "mediatek,mt7988-pinctrl",
+	},
+	{}
+};
+
+static int mt7988_pinctrl_probe(struct platform_device *pdev)
+{
+	return mtk_moore_pinctrl_probe(pdev, &mt7988_data);
+}
+
+static struct platform_driver mt7988_pinctrl_driver = {
+	.driver = {
+		.name = "mt7988-pinctrl",
+		.of_match_table = mt7988_pinctrl_of_match,
+	},
+	.probe = mt7988_pinctrl_probe,
+};
+
+static int __init mt7988_pinctrl_init(void)
+{
+	return platform_driver_register(&mt7988_pinctrl_driver);
+}
+arch_initcall(mt7988_pinctrl_init);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/regulator/rt5190a-regulator.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/regulator/rt5190a-regulator.c
new file mode 100644
index 0000000..c616a46
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/regulator/rt5190a-regulator.c
@@ -0,0 +1,557 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <dt-bindings/regulator/richtek,rt5190a-regulator.h>
+#include <linux/bits.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#define RT5190A_REG_MANUFACTURE 0x00
+#define RT5190A_REG_BUCK2VSEL	0x04
+#define RT5190A_REG_BUCK3VSEL	0x05
+#define RT5190A_REG_DCDCCNTL	0x06
+#define RT5190A_REG_ENABLE	0x07
+#define RT5190A_REG_DISCHARGE	0x09
+#define RT5190A_REG_PROTMODE	0x0A
+#define RT5190A_REG_MUTECNTL	0x0B
+#define RT5190A_REG_PGSTAT	0x0F
+#define RT5190A_REG_OVINT	0x10
+#define RT5190A_REG_HOTDIEMASK	0x17
+
+#define RT5190A_VSEL_MASK	   GENMASK(6, 0)
+#define RT5190A_RID_BITMASK(rid)   BIT(rid + 1)
+#define RT5190A_BUCK1_DISCHG_MASK  GENMASK(1, 0)
+#define RT5190A_BUCK1_DISCHG_ONVAL 0x01
+#define RT5190A_OVERVOLT_MASK	   GENMASK(7, 0)
+#define RT5190A_UNDERVOLT_MASK	   GENMASK(15, 8)
+#define RT5190A_CH234OT_MASK	   BIT(29)
+#define RT5190A_CHIPOT_MASK	   BIT(28)
+
+#define RT5190A_BUCK23_MINUV   600000
+#define RT5190A_BUCK23_MAXUV   1400000
+#define RT5190A_BUCK23_STEPUV  10000
+#define RT5190A_BUCK23_STEPNUM ((1400000 - 600000) / 10000 + 1)
+
+enum {
+	RT5190A_IDX_BUCK1 = 0,
+	RT5190A_IDX_BUCK2,
+	RT5190A_IDX_BUCK3,
+	RT5190A_IDX_BUCK4,
+	RT5190A_IDX_LDO,
+	RT5190A_MAX_IDX
+};
+
+struct rt5190a_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct regulator_desc rdesc[RT5190A_MAX_IDX];
+	struct regulator_dev *rdev[RT5190A_MAX_IDX];
+};
+
+static int rt5190a_get_error_flags(struct regulator_dev *rdev,
+				   unsigned int *flags)
+{
+	struct regmap *regmap = rdev_get_regmap(rdev);
+	int rid = rdev_get_id(rdev);
+	unsigned int pgood_stat;
+	int ret;
+
+	ret = regmap_read(regmap, RT5190A_REG_PGSTAT, &pgood_stat);
+	if (ret)
+		return ret;
+
+	if (!(pgood_stat & RT5190A_RID_BITMASK(rid)))
+		*flags = REGULATOR_ERROR_FAIL;
+	else
+		*flags = 0;
+
+	return 0;
+}
+
+static int rt5190a_fixed_buck_set_mode(struct regulator_dev *rdev,
+				       unsigned int mode)
+{
+	struct regmap *regmap = rdev_get_regmap(rdev);
+	int rid = rdev_get_id(rdev);
+	unsigned int mask = RT5190A_RID_BITMASK(rid), val;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		val = mask;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_update_bits(regmap, RT5190A_REG_DCDCCNTL, mask, val);
+}
+
+static unsigned int rt5190a_fixed_buck_get_mode(struct regulator_dev *rdev)
+{
+	struct regmap *regmap = rdev_get_regmap(rdev);
+	int rid = rdev_get_id(rdev);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(regmap, RT5190A_REG_DCDCCNTL, &val);
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to get mode [%d]\n", ret);
+		return ret;
+	}
+
+	if (val & RT5190A_RID_BITMASK(rid))
+		return REGULATOR_MODE_FAST;
+
+	return REGULATOR_MODE_NORMAL;
+}
+
+static const struct regulator_ops rt5190a_ranged_buck_ops = {
+	.enable = regulator_enable_regmap,
+	/*.disable = regulator_disable_regmap,*/
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.list_voltage = regulator_list_voltage_linear,
+	.set_active_discharge = regulator_set_active_discharge_regmap,
+	.get_error_flags = rt5190a_get_error_flags,
+};
+
+static const struct regulator_ops rt5190a_fixed_buck_ops = {
+	.enable = regulator_enable_regmap,
+	/*.disable = regulator_disable_regmap,*/
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_active_discharge = regulator_set_active_discharge_regmap,
+	.set_mode = rt5190a_fixed_buck_set_mode,
+	.get_mode = rt5190a_fixed_buck_get_mode,
+	.get_error_flags = rt5190a_get_error_flags,
+};
+
+static const struct regulator_ops rt5190a_fixed_ldo_ops = {
+	.enable = regulator_enable_regmap,
+	/*.disable = regulator_disable_regmap,*/
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_active_discharge = regulator_set_active_discharge_regmap,
+	.get_error_flags = rt5190a_get_error_flags,
+};
+
+static const struct event {
+	unsigned int bitmask;
+	unsigned int report;
+};
+
+static const struct event event_tbl[] = {
+	{ RT5190A_OVERVOLT_MASK, REGULATOR_ERROR_REGULATION_OUT },
+	{ RT5190A_UNDERVOLT_MASK, REGULATOR_ERROR_UNDER_VOLTAGE }
+};
+
+static irqreturn_t rt5190a_irq_handler(int irq, void *data)
+{
+	struct rt5190a_priv *priv = data;
+	__le32 raws;
+	unsigned int events, fields;
+	int i, j, ret;
+
+	ret = regmap_raw_read(priv->regmap, RT5190A_REG_OVINT, &raws,
+			      sizeof(raws));
+	if (ret) {
+		dev_err(priv->dev, "Failed to read events\n");
+		return IRQ_NONE;
+	}
+
+	events = le32_to_cpu(raws);
+
+	ret = regmap_raw_write(priv->regmap, RT5190A_REG_OVINT, &raws,
+			       sizeof(raws));
+	if (ret)
+		dev_err(priv->dev, "Failed to write-clear events\n");
+
+	/* Handle OV,UV events */
+	for (i = 0; i < ARRAY_SIZE(event_tbl); i++) {
+		fields = events & event_tbl[i].bitmask;
+		fields >>= ffs(event_tbl[i].bitmask) - 1;
+
+		for (j = 0; j < RT5190A_MAX_IDX; j++) {
+			if (!(fields & RT5190A_RID_BITMASK(j)))
+				continue;
+
+			regulator_notifier_call_chain(
+				priv->rdev[j], event_tbl[i].report, NULL);
+		}
+	}
+
+	/* Handle CH234 OT event */
+	if (events & RT5190A_CH234OT_MASK) {
+		for (j = RT5190A_IDX_BUCK2; j < RT5190A_IDX_LDO; j++) {
+			regulator_notifier_call_chain(
+				priv->rdev[j], REGULATOR_ERROR_OVER_TEMP, NULL);
+		}
+	}
+
+	/* Warning if CHIP OT occur */
+	if (events & RT5190A_CHIPOT_MASK)
+		dev_warn(priv->dev, "CHIP overheat\n");
+
+	return IRQ_HANDLED;
+}
+
+static unsigned int rt5190a_of_map_mode(unsigned int mode)
+{
+	switch (mode) {
+	case RT5190A_OPMODE_AUTO:
+		return REGULATOR_MODE_NORMAL;
+	case RT5190A_OPMODE_FPWM:
+		return REGULATOR_MODE_FAST;
+	default:
+		return REGULATOR_MODE_INVALID;
+	}
+}
+
+static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid,
+			       struct of_regulator_match *match)
+{
+	struct regulator_desc *desc = priv->rdesc + rid;
+	struct regulator_init_data *init_data = match->init_data;
+	struct device_node *np = match->of_node;
+	bool latchup_enable;
+	unsigned int mask = RT5190A_RID_BITMASK(rid), val;
+
+	switch (rid) {
+	case RT5190A_IDX_BUCK1:
+	case RT5190A_IDX_BUCK4:
+	case RT5190A_IDX_LDO:
+		init_data->constraints.apply_uV = 0;
+
+		if (init_data->constraints.min_uV ==
+		    init_data->constraints.max_uV)
+			desc->fixed_uV = init_data->constraints.min_uV;
+		else {
+			dev_err(priv->dev,
+				"Variable voltage for fixed regulator\n");
+			return -EINVAL;
+		}
+		break;
+	default:
+		break;
+	}
+
+	latchup_enable = of_property_read_bool(np, "richtek,latchup-enable");
+
+	/* latchup: 0, default hiccup: 1 */
+	val = !latchup_enable ? mask : 0;
+
+	return regmap_update_bits(priv->regmap, RT5190A_REG_PROTMODE, mask,
+				  val);
+}
+
+static void rt5190a_fillin_regulator_desc(struct regulator_desc *desc, int rid)
+{
+	static const char *const regu_name[] = { "buck1", "buck2", "buck3",
+						 "buck4", "ldo" };
+	static const char *const supply[] = { NULL, "vin2", "vin3", "vin4",
+					      "vinldo" };
+
+	desc->name = regu_name[rid];
+	desc->supply_name = supply[rid];
+	desc->owner = THIS_MODULE;
+	desc->type = REGULATOR_VOLTAGE;
+	desc->id = rid;
+	desc->enable_reg = RT5190A_REG_ENABLE;
+	desc->enable_mask = RT5190A_RID_BITMASK(rid);
+	desc->active_discharge_reg = RT5190A_REG_DISCHARGE;
+	desc->active_discharge_mask = RT5190A_RID_BITMASK(rid);
+	desc->active_discharge_on = RT5190A_RID_BITMASK(rid);
+
+	switch (rid) {
+	case RT5190A_IDX_BUCK1:
+		desc->active_discharge_mask = RT5190A_BUCK1_DISCHG_MASK;
+		desc->active_discharge_on = RT5190A_BUCK1_DISCHG_ONVAL;
+		desc->n_voltages = 1;
+		desc->ops = &rt5190a_fixed_buck_ops;
+		desc->of_map_mode = rt5190a_of_map_mode;
+		break;
+	case RT5190A_IDX_BUCK2:
+		desc->vsel_reg = RT5190A_REG_BUCK2VSEL;
+		desc->vsel_mask = RT5190A_VSEL_MASK;
+		desc->min_uV = RT5190A_BUCK23_MINUV;
+		desc->uV_step = RT5190A_BUCK23_STEPUV;
+		desc->n_voltages = RT5190A_BUCK23_STEPNUM;
+		desc->ops = &rt5190a_ranged_buck_ops;
+		break;
+	case RT5190A_IDX_BUCK3:
+		desc->vsel_reg = RT5190A_REG_BUCK3VSEL;
+		desc->vsel_mask = RT5190A_VSEL_MASK;
+		desc->min_uV = RT5190A_BUCK23_MINUV;
+		desc->uV_step = RT5190A_BUCK23_STEPUV;
+		desc->n_voltages = RT5190A_BUCK23_STEPNUM;
+		desc->ops = &rt5190a_ranged_buck_ops;
+		break;
+	case RT5190A_IDX_BUCK4:
+		desc->n_voltages = 1;
+		desc->ops = &rt5190a_fixed_buck_ops;
+		desc->of_map_mode = rt5190a_of_map_mode;
+		break;
+	case RT5190A_IDX_LDO:
+		desc->n_voltages = 1;
+		desc->ops = &rt5190a_fixed_ldo_ops;
+		break;
+	}
+}
+
+static struct of_regulator_match rt5190a_regulator_match[] = {
+	{
+		.name = "buck1",
+	},
+	{
+		.name = "buck2",
+	},
+	{
+		.name = "buck3",
+	},
+	{
+		.name = "buck4",
+	},
+	{
+		.name = "ldo",
+	}
+};
+
+static int rt5190a_parse_regulator_dt_data(struct rt5190a_priv *priv)
+{
+	struct device_node *regulator_np;
+	struct regulator_desc *reg_desc;
+	struct of_regulator_match *match;
+	int i, ret;
+
+	for (i = 0; i < RT5190A_MAX_IDX; i++) {
+		reg_desc = priv->rdesc + i;
+		match = rt5190a_regulator_match + i;
+
+		rt5190a_fillin_regulator_desc(reg_desc, i);
+
+		match->desc = reg_desc;
+	}
+
+	regulator_np = of_get_child_by_name(priv->dev->of_node, "regulators");
+	if (!regulator_np) {
+		dev_err(priv->dev, "Could not find 'regulators' node\n");
+		return -ENODEV;
+	}
+
+	ret = of_regulator_match(priv->dev, regulator_np,
+				 rt5190a_regulator_match,
+				 ARRAY_SIZE(rt5190a_regulator_match));
+
+	of_node_put(regulator_np);
+
+	if (ret < 0) {
+		dev_err(priv->dev, "Error parsing regulator init data: %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < RT5190A_MAX_IDX; i++) {
+		match = rt5190a_regulator_match + i;
+
+		ret = rt5190a_of_parse_cb(priv, i, match);
+		if (ret) {
+			dev_err(priv->dev, "Failed in [%d] of_parse_cb\n", i);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct reg_sequence rt5190a_init_patch[] = { {
+								  0x09,
+								  0x3d,
+							  },
+							{
+								  0x0a,
+								  0x3e,
+							  },
+							{
+								  0x0b,
+								  0x01,
+							  },
+							{
+								  0x10,
+								  0xff,
+							  },
+							{
+								  0x11,
+								  0xff,
+							  },
+							{
+								  0x12,
+								  0xff,
+							  },
+							{
+								  0x13,
+								  0xff,
+							  },
+							{
+								  0x14,
+								  0,
+							  },
+							{
+								  0x15,
+								  0,
+							  },
+							{
+								  0x16,
+								  0x3e,
+							  },
+							{
+								  0x17,
+								  0,
+							  } };
+
+static int rt5190a_device_initialize(struct rt5190a_priv *priv)
+{
+	bool mute_enable;
+	int ret;
+
+	ret = regmap_register_patch(priv->regmap, rt5190a_init_patch,
+				    ARRAY_SIZE(rt5190a_init_patch));
+	if (ret) {
+		dev_err(priv->dev, "Failed to do register patch\n");
+		return ret;
+	}
+
+	mute_enable =
+		device_property_read_bool(priv->dev, "richtek,mute-enable");
+
+	if (mute_enable) {
+		ret = regmap_write(priv->regmap, RT5190A_REG_MUTECNTL, 0x00);
+		if (ret) {
+			dev_err(priv->dev, "Failed to enable mute function\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rt5190a_device_check(struct rt5190a_priv *priv)
+{
+	u16 devid;
+	int ret;
+
+	ret = regmap_raw_read(priv->regmap, RT5190A_REG_MANUFACTURE, &devid,
+			      sizeof(devid));
+	if (ret)
+		return ret;
+
+	if (devid) {
+		dev_err(priv->dev, "Incorrect device id 0x%04x\n", devid);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static const struct regmap_config rt5190a_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = RT5190A_REG_HOTDIEMASK,
+};
+
+static int rt5190a_probe(struct i2c_client *i2c)
+{
+	struct rt5190a_priv *priv;
+	struct regulator_config cfg = {};
+	int i, ret;
+
+	priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &i2c->dev;
+
+	priv->regmap = devm_regmap_init_i2c(i2c, &rt5190a_regmap_config);
+	if (IS_ERR(priv->regmap)) {
+		dev_err(&i2c->dev, "Failed to allocate regmap\n");
+		return PTR_ERR(priv->regmap);
+	}
+
+	ret = rt5190a_device_check(priv);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to check device %d\n", ret);
+		return ret;
+	}
+
+	ret = rt5190a_device_initialize(priv);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to initialize the device\n");
+		return ret;
+	}
+
+	ret = rt5190a_parse_regulator_dt_data(priv);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to parse regulator dt\n");
+		return ret;
+	}
+
+	cfg.dev = &i2c->dev;
+	cfg.regmap = priv->regmap;
+
+	for (i = 0; i < RT5190A_MAX_IDX; i++) {
+		struct regulator_desc *desc = priv->rdesc + i;
+		struct of_regulator_match *match = rt5190a_regulator_match + i;
+
+		cfg.init_data = match->init_data;
+		cfg.of_node = match->of_node;
+
+		priv->rdev[i] = devm_regulator_register(&i2c->dev, desc, &cfg);
+		if (IS_ERR(priv->rdev[i])) {
+			dev_err(&i2c->dev, "Failed to register regulator %s\n",
+				desc->name);
+			return PTR_ERR(priv->rdev[i]);
+		}
+	}
+
+	if (i2c->irq) {
+		ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+						rt5190a_irq_handler,
+						IRQF_ONESHOT,
+						dev_name(&i2c->dev), priv);
+		if (ret) {
+			dev_err(&i2c->dev, "Failed to register interrupt\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct of_device_id __maybe_unused rt5190a_device_table[] = {
+	{
+		.compatible = "richtek,rt5190a",
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, rt5190a_device_table);
+
+static struct i2c_driver rt5190a_driver = {
+	.driver = {
+		.name = "rt5190a",
+		.of_match_table = rt5190a_device_table,
+	},
+	.probe_new = rt5190a_probe,
+};
+module_i2c_driver(rt5190a_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT5190A Regulator Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mt7988-pm-domains.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mt7988-pm-domains.h
new file mode 100644
index 0000000..f7db02c
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mt7988-pm-domains.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ */
+
+#ifndef __SOC_MEDIATEK_MT7988_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MT7988_PM_DOMAINS_H
+
+#include "mtk-pm-domains.h"
+//#include "mt7988-power.h"
+#include <dt-bindings/power/mt7988-power.h>
+
+/*
+ * MT8139 power domain support
+ */
+
+static const struct scpsys_domain_data scpsys_domain_data_mt7988[] = {
+	[MT7988_POWER_DOMAIN_TOPS0] = {
+		.sta_mask = BIT(30),
+		.sta_2nd_mask = BIT(31),
+		.pwr_sta_offs = 0x040,
+		.pwr_sta_2nd_offs = 0x040,
+		.pwr_on_bit = BIT(1),
+		.pwr_on_2nd_bit = BIT(2),
+		.pwr_on_offs  = 0x040,
+		.pwr_on_2nd_offs = 0x040,
+		.pwr_clamp_bit = BIT(4),
+		.pwr_rst_bit = BIT(0),
+		.sram_pdn_bit = BIT(2),
+		.sram_pdn_ack_bit = BIT(28),
+		.sram_clk_iso_bit = BIT(0),
+		.sram_ctrl_offs = 0x048,
+		.sram_2nd_pdn_bit = BIT(8),
+		.sram_2nd_pdn_ack_bit = BIT(24),
+		.sram_2nd_clk_iso_bit = BIT(5),
+		.sram_2nd_clk_dis_bit = BIT(3),
+		.sram_2nd_ctrl_offs = 0x040,
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+	},
+	[MT7988_POWER_DOMAIN_TOPS1] = {
+		.sta_mask = BIT(30),
+		.sta_2nd_mask = BIT(31),
+		.pwr_sta_offs = 0x044,
+		.pwr_sta_2nd_offs = 0x044,
+		.pwr_on_bit = BIT(1),
+		.pwr_on_2nd_bit = BIT(2),
+		.pwr_on_offs  = 0x044,
+		.pwr_on_2nd_offs = 0x044,
+		.pwr_clamp_bit = BIT(4),
+		.pwr_rst_bit = BIT(0),
+		.sram_pdn_bit = BIT(6),
+		.sram_pdn_ack_bit = BIT(30),
+		.sram_clk_iso_bit = BIT(4),
+		.sram_ctrl_offs = 0x048,
+		.sram_2nd_pdn_bit = BIT(8),
+		.sram_2nd_pdn_ack_bit = BIT(24),
+		.sram_2nd_clk_iso_bit = BIT(5),
+		.sram_2nd_clk_dis_bit = BIT(3),
+		.sram_2nd_ctrl_offs = 0x044,
+		.caps = MTK_SCPD_KEEP_DEFAULT_OFF,
+
+	},
+	[MT7988_POWER_DOMAIN_ETH2P5] = {
+		.sta_mask = BIT(30),
+		.sta_2nd_mask = BIT(31),
+		.pwr_sta_offs = 0x060,
+		.pwr_sta_2nd_offs = 0x060,
+		.pwr_on_bit = BIT(1),
+		.pwr_on_2nd_bit = BIT(2),
+		.pwr_on_offs  = 0x060,
+		.pwr_on_2nd_offs = 0x060,
+		.pwr_clamp_bit = BIT(4),
+	    .pwr_rst_bit = BIT(0),
+		.sram_2nd_pdn_bit = BIT(8),
+		.sram_2nd_clk_dis_bit = BIT(5),
+		.sram_2nd_ctrl_offs = 0x060,
+		.caps = MTK_SCPD_CLAMP_PROTECTION,
+
+	},
+
+};
+
+static const struct scpsys_soc_data mt7988_scpsys_data = {
+	.domains_data = scpsys_domain_data_mt7988,
+	.num_domains = ARRAY_SIZE(scpsys_domain_data_mt7988),
+};
+
+#endif /* __SOC_MEDIATEK_MT7988_PM_DOMAINS_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.c
new file mode 100644
index 0000000..fc6b5ff
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 Collabora Ltd.
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_clk.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/regmap.h>
+#include <linux/soc/mediatek/infracfg.h>
+#include <linux/regulator/consumer.h>
+
+#include "mt7988-pm-domains.h"
+
+#define MTK_POLL_DELAY_US 30
+#define MTK_POLL_TIMEOUT  USEC_PER_SEC
+
+struct scpsys_domain {
+	struct generic_pm_domain genpd;
+	const struct scpsys_domain_data *data;
+	struct scpsys *scpsys;
+	int num_clks;
+	struct clk_bulk_data *clks;
+	int num_subsys_clks;
+	struct clk_bulk_data *subsys_clks;
+	struct regmap *infracfg;
+	struct regulator *supply;
+};
+
+struct scpsys {
+	struct device *dev;
+	struct regmap *base;
+	const struct scpsys_soc_data *soc_data;
+	struct genpd_onecell_data pd_data;
+	struct generic_pm_domain *domains[];
+};
+
+static inline int mtk_regmap_set_bits(struct regmap *map, unsigned int reg,
+				      unsigned int bits)
+{
+	return regmap_update_bits_base(map, reg, bits, bits, NULL, false,
+				       false);
+}
+
+static inline int mtk_regmap_clear_bits(struct regmap *map, unsigned int reg,
+					unsigned int bits)
+{
+	return regmap_update_bits_base(map, reg, bits, 0, NULL, false, false);
+}
+
+#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd)
+
+static bool scpsys_domain_is_on(struct scpsys_domain *pd)
+{
+	struct scpsys *scpsys = pd->scpsys;
+	u32 status = 0, status2 = 0;
+
+	regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status);
+	status &= pd->data->sta_mask;
+
+	regmap_read(scpsys->base, pd->data->pwr_sta_2nd_offs, &status2);
+	status2 &= pd->data->sta_2nd_mask;
+
+	/* A domain is on when both status bits are set. */
+	return status && status2;
+}
+
+static int scpsys_sram_enable(struct scpsys_domain *pd)
+{
+	u32 pdn_ack = pd->data->sram_pdn_ack_bit;
+	u32 pdn_2nd_ack = pd->data->sram_2nd_pdn_ack_bit;
+	struct scpsys *scpsys = pd->scpsys;
+	unsigned int tmp = 0;
+	int ret;
+
+	if (pd->data->sram_pdn_bit) {
+		mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				      pd->data->sram_pdn_bit);
+
+		/* Either wait until SRAM_PDN_ACK all 1 or 0 */
+		ret = regmap_read_poll_timeout(scpsys->base,
+					       pd->data->sram_ctrl_offs, tmp,
+					       (tmp & pdn_ack) == 0,
+					       MTK_POLL_DELAY_US,
+					       MTK_POLL_TIMEOUT);
+		if (ret < 0)
+			return ret;
+	}
+	if (pd->data->sram_2nd_pdn_bit) {
+		/* sram pdn 2nd for special mtcmos */
+		mtk_regmap_clear_bits(scpsys->base,
+				      pd->data->sram_2nd_ctrl_offs,
+				      pd->data->sram_2nd_pdn_bit);
+
+		ret = regmap_read_poll_timeout(scpsys->base,
+					       pd->data->sram_2nd_ctrl_offs,
+					       tmp, (tmp & pdn_2nd_ack) == 0,
+					       MTK_POLL_DELAY_US,
+					       MTK_POLL_TIMEOUT);
+		if (ret < 0)
+			return ret;
+	}
+	if (pd->data->sram_clk_iso_bit) {
+		mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				      pd->data->sram_clk_iso_bit);
+	}
+	if (pd->data->sram_clk_dis_bit) {
+		mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				      pd->data->sram_clk_dis_bit);
+	}
+	if (pd->data->sram_2nd_clk_iso_bit) {
+		mtk_regmap_clear_bits(scpsys->base,
+				      pd->data->sram_2nd_ctrl_offs,
+				      pd->data->sram_2nd_clk_iso_bit);
+	}
+	if (pd->data->sram_2nd_clk_dis_bit) {
+		mtk_regmap_clear_bits(scpsys->base,
+				      pd->data->sram_2nd_ctrl_offs,
+				      pd->data->sram_2nd_clk_dis_bit);
+	}
+
+	return 0;
+}
+
+static int scpsys_sram_disable(struct scpsys_domain *pd)
+{
+	u32 pdn_ack = pd->data->sram_pdn_ack_bit;
+	u32 pdn_2nd_ack = pd->data->sram_2nd_pdn_ack_bit;
+	struct scpsys *scpsys = pd->scpsys;
+	unsigned int tmp = 0;
+	int ret;
+
+	if (pd->data->sram_2nd_clk_dis_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
+				    pd->data->sram_2nd_clk_dis_bit);
+	}
+	if (pd->data->sram_clk_iso_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				    pd->data->sram_clk_iso_bit);
+		udelay(1);
+	}
+	if (pd->data->sram_pdn_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_ctrl_offs,
+				    pd->data->sram_pdn_bit);
+	}
+
+	if (pd->data->sram_2nd_clk_iso_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
+				    pd->data->sram_2nd_clk_iso_bit);
+		udelay(1);
+	}
+	if (pd->data->sram_2nd_pdn_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
+				    pd->data->sram_2nd_pdn_bit);
+	}
+
+	return 0;
+}
+
+static int scpsys_regulator_get(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+	struct device_node *node;
+	struct device_node *root;
+
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY) && !pd->supply) {
+		root = pd->scpsys->dev->of_node;
+		node = of_find_node_by_name(root, genpd->name);
+		if (node) {
+			pd->scpsys->dev->of_node = node;
+			pd->supply =
+				devm_regulator_get(pd->scpsys->dev, "domain");
+			pd->scpsys->dev->of_node = root;
+			if (IS_ERR(pd->supply))
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int scpsys_regulator_enable(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+	int ret = scpsys_regulator_get(genpd);
+
+	if (ret)
+		return ret;
+
+	return pd->supply ? regulator_enable(pd->supply) : 0;
+}
+
+static int scpsys_regulator_disable(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+
+	return pd->supply ? regulator_disable(pd->supply) : 0;
+}
+
+static int scpsys_power_on(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+	struct scpsys *scpsys = pd->scpsys;
+	bool tmp;
+	int ret;
+
+	ret = scpsys_regulator_enable(genpd);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
+	if (ret)
+		goto err_pwr_ack;
+
+	/* subsys power on */
+	mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
+			    pd->data->pwr_on_bit);
+	mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_2nd_offs,
+			    pd->data->pwr_on_2nd_bit);
+
+	/* wait until PWR_ACK = 1 */
+	ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp,
+				 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
+	if (ret < 0)
+		goto err_pwr_ack;
+	udelay(30);
+
+	if (pd->data->pwr_clamp_bit) {
+		mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
+				      pd->data->pwr_clamp_bit);
+		udelay(30);
+	}
+
+	if (pd->data->pwr_rst_bit)
+		mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
+				    pd->data->pwr_rst_bit);
+
+	ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
+	if (ret)
+		goto err_disable_subsys_clks;
+
+	ret = scpsys_sram_enable(pd);
+	if (ret < 0)
+		goto err_disable_sram;
+
+	return 0;
+
+err_disable_sram:
+	scpsys_sram_disable(pd);
+err_disable_subsys_clks:
+	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
+err_pwr_ack:
+	clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
+err_reg:
+	scpsys_regulator_disable(genpd);
+	return ret;
+}
+
+static int scpsys_power_off(struct generic_pm_domain *genpd)
+{
+	struct scpsys_domain *pd =
+		container_of(genpd, struct scpsys_domain, genpd);
+	struct scpsys *scpsys = pd->scpsys;
+	bool tmp;
+	int ret;
+
+	ret = scpsys_sram_disable(pd);
+	if (ret < 0)
+		return ret;
+
+	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
+
+	if (pd->data->pwr_clamp_bit) {
+		mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
+				    pd->data->pwr_clamp_bit);
+		udelay(30);
+	}
+	if (pd->data->pwr_rst_bit)
+		mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
+				      pd->data->pwr_rst_bit);
+
+	mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
+			      pd->data->pwr_on_bit);
+	mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_2nd_offs,
+			      pd->data->pwr_on_2nd_bit);
+
+	clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
+	scpsys_regulator_disable(genpd);
+
+	return 0;
+}
+
+static struct generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys,
+						       struct device_node *node)
+{
+	const struct scpsys_domain_data *domain_data;
+	struct scpsys_domain *pd;
+	struct property *prop;
+	const char *clk_name;
+	int i, ret, num_clks;
+	struct clk *clk;
+	struct device_node *smi_node;
+	struct device_node *larb_node;
+	int clk_ind = 0;
+	u32 id;
+
+	ret = of_property_read_u32(node, "reg", &id);
+	if (ret) {
+		dev_err(scpsys->dev,
+			"%pOF: failed to retrieve domain id from reg: %d\n",
+			node, ret);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (id >= scpsys->soc_data->num_domains) {
+		dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	domain_data = &scpsys->soc_data->domains_data[id];
+	if (domain_data->sta_mask == 0) {
+		dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node,
+			id);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return ERR_PTR(-ENOMEM);
+
+	pd->data = domain_data;
+	pd->scpsys = scpsys;
+
+	num_clks = of_clk_get_parent_count(node);
+	if (num_clks > 0) {
+		/* Calculate number of subsys_clks */
+		of_property_for_each_string(node, "clock-names", prop,
+					     clk_name) {
+			char *subsys;
+
+			subsys = strchr(clk_name, '-');
+			if (subsys)
+				pd->num_subsys_clks++;
+			else
+				pd->num_clks++;
+		}
+
+		pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks,
+					sizeof(*pd->clks), GFP_KERNEL);
+		if (!pd->clks)
+			return ERR_PTR(-ENOMEM);
+
+		pd->subsys_clks =
+			devm_kcalloc(scpsys->dev, pd->num_subsys_clks,
+				     sizeof(*pd->subsys_clks), GFP_KERNEL);
+		if (!pd->subsys_clks)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	for (i = 0; i < pd->num_clks; i++) {
+		clk = of_clk_get(node, i);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			dev_err(scpsys->dev,
+				"%pOF: failed to get clk at index %d: %d\n",
+				node, i, ret);
+			goto err_put_clocks;
+		}
+
+		pd->clks[clk_ind++].clk = clk;
+	}
+
+	for (i = 0; i < pd->num_subsys_clks; i++) {
+		clk = of_clk_get(node, i + clk_ind);
+		if (IS_ERR(clk)) {
+			ret = PTR_ERR(clk);
+			dev_err(scpsys->dev,
+				"%pOF: failed to get clk at index %d: %d\n",
+				node, i + clk_ind, ret);
+			goto err_put_subsys_clocks;
+		}
+
+		pd->subsys_clks[i].clk = clk;
+	}
+
+	/*
+	 * Initially turn on all domains to make the domains usable
+	 * with !CONFIG_PM and to get the hardware in sync with the
+	 * software.  The unused domains will be switched off during
+	 * late_init time.
+	 */
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
+		if (scpsys_domain_is_on(pd))
+			dev_warn(
+				scpsys->dev,
+				"%pOF: A default off power domain has been ON\n",
+				node);
+	} else {
+		ret = scpsys_power_on(&pd->genpd);
+		if (ret < 0) {
+			dev_err(scpsys->dev,
+				"%pOF: failed to power on domain: %d\n", node,
+				ret);
+			goto err_put_subsys_clocks;
+		}
+	}
+
+	if (scpsys->domains[id]) {
+		ret = -EINVAL;
+		dev_err(scpsys->dev,
+			"power domain with id %d already exists, check your device-tree\n",
+			id);
+		goto err_put_subsys_clocks;
+	}
+
+	pd->genpd.name = node->name;
+	pd->genpd.power_off = scpsys_power_off;
+	pd->genpd.power_on = scpsys_power_on;
+
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP))
+		pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
+
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF))
+		pm_genpd_init(&pd->genpd, NULL, true);
+	else
+		pm_genpd_init(&pd->genpd, NULL, false);
+
+	scpsys->domains[id] = &pd->genpd;
+
+	return scpsys->pd_data.domains[id];
+
+err_put_subsys_clocks:
+	clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
+err_put_clocks:
+	clk_bulk_put(pd->num_clks, pd->clks);
+	return ERR_PTR(ret);
+}
+
+static int scpsys_add_subdomain(struct scpsys *scpsys,
+				struct device_node *parent)
+{
+	struct generic_pm_domain *child_pd, *parent_pd;
+	struct device_node *child;
+	int ret;
+
+	for_each_child_of_node(parent, child) {
+		u32 id;
+
+		ret = of_property_read_u32(parent, "reg", &id);
+		if (ret) {
+			dev_err(scpsys->dev,
+				"%pOF: failed to get parent domain id\n",
+				child);
+			goto err_put_node;
+		}
+
+		if (!scpsys->pd_data.domains[id]) {
+			ret = -EINVAL;
+			dev_err(scpsys->dev,
+				"power domain with id %d does not exist\n", id);
+			goto err_put_node;
+		}
+
+		parent_pd = scpsys->pd_data.domains[id];
+
+		child_pd = scpsys_add_one_domain(scpsys, child);
+		if (IS_ERR(child_pd)) {
+			ret = PTR_ERR(child_pd);
+			dev_err(scpsys->dev,
+				"%pOF: failed to get child domain id\n", child);
+			goto err_put_node;
+		}
+
+		ret = pm_genpd_add_subdomain(parent_pd, child_pd);
+		if (ret) {
+			dev_err(scpsys->dev,
+				"failed to add %s subdomain to parent %s\n",
+				child_pd->name, parent_pd->name);
+			goto err_put_node;
+		} else {
+			dev_dbg(scpsys->dev, "%s add subdomain: %s\n",
+				parent_pd->name, child_pd->name);
+		}
+
+		/* recursive call to add all subdomains */
+		ret = scpsys_add_subdomain(scpsys, child);
+		if (ret)
+			goto err_put_node;
+	}
+
+	return 0;
+
+err_put_node:
+	of_node_put(child);
+	return ret;
+}
+
+static void scpsys_remove_one_domain(struct scpsys_domain *pd)
+{
+	int ret;
+
+	if (scpsys_domain_is_on(pd))
+		scpsys_power_off(&pd->genpd);
+
+	/*
+	 * We're in the error cleanup already, so we only complain,
+	 * but won't emit another error on top of the original one.
+	 */
+	ret = pm_genpd_remove(&pd->genpd);
+	if (ret < 0)
+		dev_err(pd->scpsys->dev,
+			"failed to remove domain '%s' : %d - state may be inconsistent\n",
+			pd->genpd.name, ret);
+
+	clk_bulk_put(pd->num_clks, pd->clks);
+	clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
+}
+
+static void scpsys_domain_cleanup(struct scpsys *scpsys)
+{
+	struct generic_pm_domain *genpd;
+	struct scpsys_domain *pd;
+	int i;
+
+	for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) {
+		genpd = scpsys->pd_data.domains[i];
+		if (genpd) {
+			pd = to_scpsys_domain(genpd);
+			scpsys_remove_one_domain(pd);
+		}
+	}
+}
+
+static const struct of_device_id scpsys_of_match[] = {
+	{
+		.compatible = "mediatek,mt7988-power-controller",
+		.data = &mt7988_scpsys_data,
+	},
+	{}
+};
+
+static int scpsys_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	const struct scpsys_soc_data *soc;
+	struct device_node *node;
+	struct scpsys *scpsys;
+	struct resource *res;
+	int ret;
+
+	soc = of_device_get_match_data(&pdev->dev);
+	if (!soc) {
+		dev_err(&pdev->dev, "no power controller data\n");
+		return -EINVAL;
+	}
+
+	scpsys = devm_kzalloc(dev,
+			      struct_size(scpsys, domains, soc->num_domains),
+			      GFP_KERNEL);
+	if (!scpsys)
+		return -ENOMEM;
+
+	scpsys->dev = dev;
+	scpsys->soc_data = soc;
+
+	scpsys->pd_data.domains = scpsys->domains;
+	scpsys->pd_data.num_domains = soc->num_domains;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	scpsys->base = syscon_node_to_regmap(np);
+	if (IS_ERR(scpsys->base)) {
+		dev_err(dev, "no regmap available\n");
+		return PTR_ERR(scpsys->base);
+	}
+
+	ret = -ENODEV;
+	for_each_available_child_of_node(np, node) {
+		struct generic_pm_domain *domain;
+
+		domain = scpsys_add_one_domain(scpsys, node);
+		if (IS_ERR(domain)) {
+			ret = PTR_ERR(domain);
+			of_node_put(node);
+			goto err_cleanup_domains;
+		}
+
+		ret = scpsys_add_subdomain(scpsys, node);
+		if (ret) {
+			of_node_put(node);
+			goto err_cleanup_domains;
+		}
+	}
+
+	if (ret) {
+		dev_dbg(dev, "no power domains present\n");
+		return ret;
+	}
+
+	ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data);
+	if (ret) {
+		dev_err(dev, "failed to add provider: %d\n", ret);
+		goto err_cleanup_domains;
+	}
+
+	return 0;
+
+err_cleanup_domains:
+	scpsys_domain_cleanup(scpsys);
+	return ret;
+}
+
+static struct platform_driver scpsys_pm_domain_driver = {
+	.probe = scpsys_probe,
+	.driver = {
+		.name = "mtk-power-controller",
+		.suppress_bind_attrs = true,
+		.of_match_table = scpsys_of_match,
+	},
+};
+builtin_platform_driver(scpsys_pm_domain_driver);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.h
new file mode 100644
index 0000000..853f5e6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/soc/mediatek/mtk-pm-domains.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_MEDIATEK_MTK_PM_DOMAINS_H
+#define __SOC_MEDIATEK_MTK_PM_DOMAINS_H
+
+#define MTK_SCPD_ACTIVE_WAKEUP		BIT(0)
+#define MTK_SCPD_FWAIT_SRAM		BIT(1)
+#define MTK_SCPD_SRAM_ISO		BIT(2)
+#define MTK_SCPD_KEEP_DEFAULT_OFF	BIT(3)
+#define MTK_SCPD_DOMAIN_SUPPLY		BIT(4)
+#define MTK_SCPD_CLAMP_PROTECTION	BIT(5)
+#define MTK_SCPD_CAPS(_scpd, _x)	((_scpd)->data->caps & (_x))
+
+/**
+ * struct scpsys_domain_data - scp domain data for power on/off flow
+ * @sta_mask: The mask for power on/off status bit.
+ * @sta_2nd_mask: The mask for 2nd power on/off status bit.
+ * @pwr_sta_offs: the main power status register.
+ * @pwr_sta_2nd_offs: the 2nd power status register.
+ * @pwr_on_bit: The power on/off bit.
+ * @pwr_on_2nd_bit: The 2nd power on/off bit.
+ * @pwr_on_offs: The offset for main power control register.
+ * @pwr_on_2nd_offs: The offset for 2nd power control register.
+ * @sram_pdn_bit: The mask for sram power control bit.
+ * @sram_pdn_ack_bit: The sram power control acked bit.
+ * @sram_clk_iso_bit: The sram  clk iso bit.
+ * @sram_clk_dis_bit: The sram clk disable bit.
+ * @sram_ctrl_offs: The sram power control register.
+ * @caps: The flag for active wake-up action.
+ * @bp_infracfg: bus protection for infracfg subsystem
+ */
+struct scpsys_domain_data {
+	u32 sta_mask;
+	u32 sta_2nd_mask;
+	int pwr_sta_offs;
+	int pwr_sta_2nd_offs;
+	u32 pwr_on_bit;
+	u32 pwr_on_2nd_bit;
+	int pwr_on_offs;
+	int pwr_on_2nd_offs;
+	u32 pwr_clamp_bit;
+	u32 pwr_rst_bit;
+	u32 sram_pdn_bit;
+	u32 sram_pdn_ack_bit;
+	u32 sram_clk_iso_bit;
+	u32 sram_clk_dis_bit;
+	int sram_ctrl_offs;
+	u32 sram_2nd_pdn_bit;
+	u32 sram_2nd_pdn_ack_bit;
+	u32 sram_2nd_clk_iso_bit;
+	u32 sram_2nd_clk_dis_bit;
+	int sram_2nd_ctrl_offs;
+	u8 caps;
+
+};
+
+struct scpsys_soc_data {
+	const struct scpsys_domain_data *domains_data;
+	int num_domains;
+};
+
+#endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/Kconfig b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/Kconfig
new file mode 100644
index 0000000..edc0aa4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/Kconfig
@@ -0,0 +1,9 @@
+config MTK_SOC_THERMAL_LVTS
+        tristate "LVTS (Low voltage thermal sensor) driver for Mediatek SoCs"
+        depends on HAS_IOMEM
+        depends on NVMEM
+        help
+          Enable this option if you want to get SoC temperature
+          information for Mediatek platforms. This driver
+          configures LVTS thermal controllers to collect temperatures
+          via Analog Serial Interface(ASIF).
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/Makefile b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/Makefile
new file mode 100644
index 0000000..c9225cb
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MTK_SOC_THERMAL_LVTS)	+= soc_temp_lvts.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.c
new file mode 100644
index 0000000..570ac17
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.c
@@ -0,0 +1,1895 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Henry Yen <henry.yen@mediatek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/thermal.h>
+#include "soc_temp_lvts.h"
+
+/*
+ * Definition or macro function
+ */
+#define STOP_COUNTING_V5	     (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00)
+#define SET_RG_TSFM_LPDLY_V5	     (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6)
+#define SET_COUNTING_WINDOW_20US1_V5 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00)
+#define SET_COUNTING_WINDOW_20US2_V5 (DEVICE_WRITE | RG_TSFM_CTRL_1 << 8 | 0x20)
+#define TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V5                                       \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_2 << 8 | 0x8C)
+#define TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V5                                       \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_4 << 8 | 0xFC)
+#define SET_TS_RSV_V5 (DEVICE_WRITE | RG_TSV2F_CTRL_1 << 8 | 0x8D)
+#define SET_TS_EN_V5  (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF1)
+
+#define SET_MANUAL_RCK_V5	  (DEVICE_WRITE | RG_TSV2F_CTRL_6 << 8 | 0x00)
+#define SELECT_SENSOR_RCK_V5(id)  (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | (id))
+#define SET_DEVICE_SINGLE_MODE_V5 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8)
+#define KICK_OFF_RCK_COUNTING_V5  (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x02)
+#define SET_SENSOR_NO_RCK_V5(id)                                               \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | 0x10 | (id))
+#define SET_DEVICE_LOW_POWER_SINGLE_MODE_V5                                    \
+	(DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8)
+
+#define STOP_COUNTING_V4	     (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x00)
+#define SET_RG_TSFM_LPDLY_V4	     (DEVICE_WRITE | RG_TSFM_CTRL_4 << 8 | 0xA6)
+#define SET_COUNTING_WINDOW_20US1_V4 (DEVICE_WRITE | RG_TSFM_CTRL_2 << 8 | 0x00)
+#define SET_COUNTING_WINDOW_20US2_V4 (DEVICE_WRITE | RG_TSFM_CTRL_1 << 8 | 0x20)
+#define TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4                                       \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_2 << 8 | 0x84)
+#define TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4                                       \
+	(DEVICE_WRITE | RG_TSV2F_CTRL_4 << 8 | 0x7C)
+#define SET_TS_RSV_V4		    (DEVICE_WRITE | RG_TSV2F_CTRL_1 << 8 | 0x8D)
+#define SET_TS_EN_V4		    (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4)
+#define TOGGLE_RG_TSV2F_VCO_RST1_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xFC)
+#define TOGGLE_RG_TSV2F_VCO_RST2_V4 (DEVICE_WRITE | RG_TSV2F_CTRL_0 << 8 | 0xF4)
+
+#define SET_LVTS_AUTO_RCK_V4	  (DEVICE_WRITE | RG_TSV2F_CTRL_6 << 8 | 0x01)
+#define SELECT_SENSOR_RCK_V4(id)  (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | (id))
+#define SET_DEVICE_SINGLE_MODE_V4 (DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0x78)
+#define KICK_OFF_RCK_COUNTING_V4  (DEVICE_WRITE | RG_TSFM_CTRL_0 << 8 | 0x02)
+#define SET_SENSOR_NO_RCK_V4	  (DEVICE_WRITE | RG_TSV2F_CTRL_5 << 8 | 0x10)
+#define SET_DEVICE_LOW_POWER_SINGLE_MODE_V4                                    \
+	(DEVICE_WRITE | RG_TSFM_CTRL_3 << 8 | 0xB8)
+
+#define ENABLE_FEATURE(feature)	 (lvts_data->feature_bitmap |= (feature))
+#define DISABLE_FEATURE(feature) (lvts_data->feature_bitmap &= (~(feature)))
+#define IS_ENABLE(feature)	 (lvts_data->feature_bitmap & (feature))
+
+#define DISABLE_THERMAL_HW_REBOOT (-274000)
+
+#define CLOCK_26MHZ_CYCLE_NS	(38)
+#define BUS_ACCESS_US		(2)
+#define GOLDEN_TEMP_MAX		(62)
+#define FEATURE_DEVICE_AUTO_RCK (BIT(0))
+#define FEATURE_CK26M_ACTIVE	(BIT(1))
+#define FEATURE_IRQ		(BIT(2))
+#define FEATURE_RESET		(BIT(3))
+#define CK26M_ACTIVE                                                           \
+	(((lvts_data->feature_bitmap & FEATURE_CK26M_ACTIVE) ? 1 : 0) << 30)
+#define GET_BASE_ADDR(tc_id)                                                   \
+	(lvts_data->domain[lvts_data->tc[tc_id].domain_index].base +           \
+	 lvts_data->tc[tc_id].addr_offset)
+
+#define SET_TC_SPEED_IN_US(pu, gd, fd, sd)                                     \
+	{                                                                      \
+		.period_unit = (((pu)*1000) / (256 * CLOCK_26MHZ_CYCLE_NS)),   \
+		.group_interval_delay = ((gd) / (pu)),                         \
+		.filter_interval_delay = ((fd) / (pu)),                        \
+		.sensor_interval_delay = ((sd) / (pu)),                        \
+	}
+
+#define GET_CAL_DATA_BITMASK(index, h, l)                                      \
+	(((index) < lvts_data->num_efuse_addr) ?                               \
+		 ((lvts_data->efuse[(index)] & GENMASK(h, l)) >> l) :          \
+		 0)
+
+#define GET_CAL_DATA_BIT(index, bit)                                           \
+	(((index) < lvts_data->num_efuse_addr) ?                               \
+		 ((lvts_data->efuse[index] & BIT(bit)) >> (bit)) :             \
+		 0)
+
+#define GET_TC_SENSOR_NUM(tc_id) (lvts_data->tc[tc_id].num_sensor)
+
+#define ONE_SAMPLE (lvts_data->counting_window_us + 2 * BUS_ACCESS_US)
+
+#define NUM_OF_SAMPLE(tc_id)                                                   \
+	((lvts_data->tc[tc_id].hw_filter < LVTS_FILTER_2) ?                    \
+		 1 :                                                           \
+		 ((lvts_data->tc[tc_id].hw_filter > LVTS_FILTER_16_OF_18) ?    \
+			  1 :                                                  \
+			  ((lvts_data->tc[tc_id].hw_filter ==                  \
+			    LVTS_FILTER_16_OF_18) ?                            \
+				   18 :                                        \
+				   ((lvts_data->tc[tc_id].hw_filter ==         \
+				     LVTS_FILTER_8_OF_10) ?                    \
+					    10 :                               \
+					    (lvts_data->tc[tc_id].hw_filter *  \
+					     2)))))
+
+#define PERIOD_UNIT_US(tc_id)                                                  \
+	((lvts_data->tc[tc_id].tc_speed.period_unit * 256 *                    \
+	  CLOCK_26MHZ_CYCLE_NS) /                                              \
+	 1000)
+#define FILTER_INT_US(tc_id)                                                   \
+	(lvts_data->tc[tc_id].tc_speed.filter_interval_delay *                 \
+	 PERIOD_UNIT_US(tc_id))
+#define SENSOR_INT_US(tc_id)                                                   \
+	(lvts_data->tc[tc_id].tc_speed.sensor_interval_delay *                 \
+	 PERIOD_UNIT_US(tc_id))
+#define GROUP_INT_US(tc_id)                                                    \
+	(lvts_data->tc[tc_id].tc_speed.group_interval_delay *                  \
+	 PERIOD_UNIT_US(tc_id))
+
+#define SENSOR_LATENCY_US(tc_id)                                               \
+	((NUM_OF_SAMPLE(tc_id) - 1) * FILTER_INT_US(tc_id) +                   \
+	 NUM_OF_SAMPLE(tc_id) * ONE_SAMPLE)
+
+#define GROUP_LATENCY_US(tc_id)                                                \
+	(GET_TC_SENSOR_NUM(tc_id) * SENSOR_LATENCY_US(tc_id) +                 \
+	 (GET_TC_SENSOR_NUM(tc_id) - 1) * SENSOR_INT_US(tc_id) +               \
+	 GROUP_INT_US(tc_id))
+
+/*
+ * LVTS local common code
+ */
+static int lvts_raw_to_temp(struct formula_coeff *co, unsigned int msr_raw)
+{
+	/* This function returns degree mC */
+
+	int temp;
+
+	msr_raw &= 0xffff;
+	temp = (co->a * ((unsigned long long)msr_raw)) >> 14;
+	temp = temp + co->golden_temp * 500 + co->b;
+
+	return temp;
+}
+
+static unsigned int lvts_temp_to_raw(struct formula_coeff *co, int temp)
+{
+	unsigned int msr_raw;
+
+	msr_raw = ((long long)((co->golden_temp * 500 + co->b - temp)) << 14) /
+		  (-1 * co->a);
+
+	return msr_raw;
+}
+
+static int lvts_read_all_tc_temperature(struct lvts_data *lvts_data)
+{
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int i, j, s_index, msr_raw;
+	int max_temp = -100000, current_temp;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		for (j = 0; j < tc[i].num_sensor; j++) {
+			s_index = tc[i].sensor_map[j];
+
+			msr_raw = readl(LVTSMSR0_0 + base + 0x4 * j) &
+				  MRS_RAW_MASK;
+			current_temp =
+				lvts_raw_to_temp(&lvts_data->coeff, msr_raw);
+
+			if (msr_raw == 0)
+				current_temp = THERMAL_TEMP_INVALID;
+
+			max_temp = max(max_temp, current_temp);
+
+			lvts_data->sen_data[s_index].msr_raw = msr_raw;
+			lvts_data->sen_data[s_index].temp = current_temp;
+		}
+	}
+
+	return max_temp;
+}
+
+static int soc_temp_lvts_read_temp(void *data, int *temperature)
+{
+	struct soc_temp_tz *lvts_tz = (struct soc_temp_tz *)data;
+	struct lvts_data *lvts_data = lvts_tz->lvts_data;
+
+	if (lvts_tz->id == 0)
+		*temperature = lvts_read_all_tc_temperature(lvts_data);
+	else if (lvts_tz->id - 1 < lvts_data->num_sensor)
+		*temperature = lvts_data->sen_data[lvts_tz->id - 1].temp;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct thermal_zone_of_device_ops soc_temp_lvts_ops = {
+	.get_temp = soc_temp_lvts_read_temp,
+};
+
+static void lvts_write_device(struct lvts_data *lvts_data, unsigned int data,
+			      int tc_id)
+{
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	writel(data, LVTS_CONFIG_0 + base);
+
+	usleep_range(5, 15);
+}
+
+static unsigned int lvts_read_device(struct lvts_data *lvts_data,
+				     unsigned int reg_idx, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	void __iomem *base;
+	unsigned int data;
+	int ret;
+
+	base = GET_BASE_ADDR(tc_id);
+	writel(READ_DEVICE_REG(reg_idx), LVTS_CONFIG_0 + base);
+
+	ret = readl_poll_timeout(LVTS_CONFIG_0 + base, data,
+				 !(data & DEVICE_ACCESS_STARTUS), 2, 200);
+	if (ret)
+		dev_err(dev,
+			"Error: LVTS %d DEVICE_ACCESS_START didn't ready\n",
+			tc_id);
+
+	data = readl(LVTSRDATA0_0 + base);
+
+	return data;
+}
+
+static void wait_all_tc_sensing_point_idle(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int mask, error_code, is_error;
+	void __iomem *base;
+	int i, cnt, ret;
+
+	mask = BIT(10) | BIT(7) | BIT(0);
+
+	for (cnt = 0; cnt < 2; cnt++) {
+		is_error = 0;
+		for (i = 0; i < lvts_data->num_tc; i++) {
+			base = GET_BASE_ADDR(i);
+			ret = readl_poll_timeout(LVTSMSRCTL1_0 + base,
+						 error_code,
+						 !(error_code & mask), 2, 200);
+			/*
+			 * Error code
+			 * 000: IDLE
+			 * 001: Write transaction
+			 * 010: Waiting for read after Write
+			 * 011: Disable Continue fetching on Device
+			 * 100: Read transaction
+			 * 101: Set Device special Register for Voltage
+			 *	threshold
+			 * 111: Set TSMCU number for Fetch
+			 */
+			error_code = ((error_code & BIT(10)) >> 8) +
+				     ((error_code & BIT(7)) >> 6) +
+				     (error_code & BIT(0));
+
+			if (ret)
+				dev_err(dev,
+					"Error LVTS %d sensing points aren't idle, error_code %d\n",
+					i, error_code);
+
+			if (error_code != 0)
+				is_error = 1;
+		}
+
+		if (is_error == 0)
+			break;
+	}
+}
+
+static void lvts_reset(struct lvts_data *lvts_data)
+{
+	int i;
+
+	for (i = 0; i < lvts_data->num_domain; i++) {
+		if (lvts_data->domain[i].reset)
+			reset_control_assert(lvts_data->domain[i].reset);
+
+		if (lvts_data->domain[i].reset)
+			reset_control_deassert(lvts_data->domain[i].reset);
+	}
+}
+
+static void device_identification(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int i, data;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+
+		writel(ENABLE_LVTS_CTRL_CLK, LVTSCLKEN_0 + base);
+
+		lvts_write_device(lvts_data, RESET_ALL_DEVICES, i);
+
+		lvts_write_device(lvts_data, READ_BACK_DEVICE_ID, i);
+
+		/* Check LVTS device ID */
+		data = (readl(LVTS_ID_0 + base) & GENMASK(7, 0));
+		if (data != (0x83 + i))
+			dev_err(dev,
+				"LVTS_TC_%d, Device ID should be 0x%x, but 0x%x\n",
+				i, (0x83 + i), data);
+	}
+}
+
+static void disable_all_sensing_points(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		writel(DISABLE_SENSING_POINT, LVTSMONCTL0_0 + base);
+	}
+}
+
+static void enable_all_sensing_points(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int i, num;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		num = tc[i].num_sensor;
+
+		if (num > ALL_SENSING_POINTS) {
+			dev_err(dev,
+				"%s, LVTS%d, illegal number of sensors: %d\n",
+				__func__, i, tc[i].num_sensor);
+			continue;
+		}
+
+		writel(ENABLE_SENSING_POINT(num), LVTSMONCTL0_0 + base);
+	}
+}
+
+static void set_polling_speed(struct lvts_data *lvts_data, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int lvts_mon_ctl_1, lvts_mon_ctl_2;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	lvts_mon_ctl_1 = ((tc[tc_id].tc_speed.group_interval_delay << 20) &
+			  GENMASK(29, 20)) |
+			 (tc[tc_id].tc_speed.period_unit & GENMASK(9, 0));
+	lvts_mon_ctl_2 =
+		((tc[tc_id].tc_speed.filter_interval_delay << 16) &
+		 GENMASK(25, 16)) |
+		(tc[tc_id].tc_speed.sensor_interval_delay & GENMASK(9, 0));
+	/*
+	 * Clock source of LVTS thermal controller is 26MHz.
+	 * Period unit is a base for all interval delays
+	 * All interval delays must multiply it to convert a setting to time.
+	 *
+	 * Filter interval delay:
+	 * A delay between two samples of the same sensor
+	 *
+	 * Sensor interval delay:
+	 * A delay between two samples of differnet sensors
+	 *
+	 * Group interval delay:
+	 * A delay between different rounds.
+	 *
+	 * For example:
+	 *     If Period unit = C, filter delay = 1, sensor delay = 2,
+	 *     group delay = 1, and two sensors, TS1 and TS2, are in a LVTS
+	 *     thermal controller and then
+	 *     Period unit = C * 1/26M * 256 = 12 * 38.46ns * 256 = 118.149us
+	 *     Filter interval delay = 1 * Period unit = 118.149us
+	 *     Sensor interval delay = 2 * Period unit = 236.298us
+	 *     Group interval delay = 1 * Period unit = 118.149us
+	 *
+	 *     TS1    TS1 ... TS1    TS2    TS2 ... TS2    TS1...
+	 *        <--> Filter interval delay
+	 *                       <--> Sensor interval delay
+	 *                                             <--> Group interval delay
+	 */
+	writel(lvts_mon_ctl_1, LVTSMONCTL1_0 + base);
+	writel(lvts_mon_ctl_2, LVTSMONCTL2_0 + base);
+
+	dev_info(dev, "%s %d, LVTSMONCTL1_0= 0x%x,LVTSMONCTL2_0= 0x%x\n",
+		 __func__, tc_id, readl(LVTSMONCTL1_0 + base),
+		 readl(LVTSMONCTL2_0 + base));
+}
+
+static void set_hw_filter(struct lvts_data *lvts_data, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int option;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+	option = tc[tc_id].hw_filter & 0x7;
+	/* hw filter
+	 * 000: Get one sample
+	 * 001: Get 2 samples and average them
+	 * 010: Get 4 samples, drop max and min, then average the rest of 2
+	 *      samples
+	 * 011: Get 6 samples, drop max and min, then average the rest of 4
+	 *      samples
+	 * 100: Get 10 samples, drop max and min, then average the rest of 8
+	 *      samples
+	 * 101: Get 18 samples, drop max and min, then average the rest of 16
+	 * samples
+	 */
+	option = (option << 9) | (option << 6) | (option << 3) | option;
+
+	writel(option, LVTSMSRCTL0_0 + base);
+	dev_info(dev, "%s %d, LVTSMSRCTL0_0= 0x%x\n", __func__, tc_id,
+		 readl(LVTSMSRCTL0_0 + base));
+}
+
+static int get_dominator_index(struct lvts_data *lvts_data, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	int d_index;
+
+	if (tc[tc_id].dominator_sensing_point == ALL_SENSING_POINTS) {
+		d_index = ALL_SENSING_POINTS;
+	} else if (tc[tc_id].dominator_sensing_point < tc[tc_id].num_sensor) {
+		d_index = tc[tc_id].dominator_sensing_point;
+	} else {
+		dev_err(dev,
+			"Error: LVTS%d, dominator_sensing_point= %d should smaller than num_sensor= %d\n",
+			tc_id, tc[tc_id].dominator_sensing_point,
+			tc[tc_id].num_sensor);
+
+		dev_err(dev,
+			"Use the sensing point 0 as the dominated sensor\n");
+		d_index = SENSING_POINT0;
+	}
+
+	return d_index;
+}
+
+static void disable_hw_reboot_interrupt(struct lvts_data *lvts_data, int tc_id)
+{
+	unsigned int temp;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	/* LVTS thermal controller has two interrupts for thermal HW reboot
+	 * One is for AP SW and the other is for RGU
+	 * The interrupt of AP SW can turn off by a bit of a register, but
+	 * the other for RGU cannot.
+	 * To prevent rebooting device accidentally, we are going to add
+	 * a huge offset to LVTS and make LVTS always report extremely low
+	 * temperature.
+	 */
+
+	/* After adding the huge offset 0x3FFF, LVTS alawys adds the
+	 * offset to MSR_RAW.
+	 * When MSR_RAW is larger, SW will convert lower temperature/
+	 */
+	temp = readl(LVTSPROTCTL_0 + base);
+	writel(temp | 0x3FFF, LVTSPROTCTL_0 + base);
+
+	/* Disable the interrupt of AP SW */
+	temp = readl(LVTSMONINT_0 + base);
+	writel(temp & ~(STAGE3_INT_EN), LVTSMONINT_0 + base);
+}
+
+static void enable_hw_reboot_interrupt(struct lvts_data *lvts_data, int tc_id)
+{
+	unsigned int temp;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	/* Enable the interrupt of AP SW */
+	temp = readl(LVTSMONINT_0 + base);
+	writel(temp | STAGE3_INT_EN, LVTSMONINT_0 + base);
+	/* Clear the offset */
+	temp = readl(LVTSPROTCTL_0 + base);
+	writel(temp & ~PROTOFFSET, LVTSPROTCTL_0 + base);
+}
+
+static void set_tc_hw_reboot_threshold(struct lvts_data *lvts_data,
+				       int trip_point, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int msr_raw, temp, config, d_index;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+	d_index = get_dominator_index(lvts_data, tc_id);
+
+	dev_info(dev, "%s: LVTS%d, the dominator sensing point= %d\n", __func__,
+		 tc_id, d_index);
+
+	disable_hw_reboot_interrupt(lvts_data, tc_id);
+
+	temp = readl(LVTSPROTCTL_0 + base);
+	if (d_index == ALL_SENSING_POINTS) {
+		/* Maximum of 4 sensing points */
+		config = (0x1 << 16);
+		writel(config | temp, LVTSPROTCTL_0 + base);
+	} else {
+		/* Select protection sensor */
+		config = ((d_index << 2) + 0x2) << 16;
+		writel(config | temp, LVTSPROTCTL_0 + base);
+	}
+
+	msr_raw = lvts_temp_to_raw(&lvts_data->coeff, trip_point);
+	writel(msr_raw, LVTSPROTTC_0 + base);
+
+	enable_hw_reboot_interrupt(lvts_data, tc_id);
+}
+
+static void set_all_tc_hw_reboot(struct lvts_data *lvts_data)
+{
+	struct tc_settings *tc = lvts_data->tc;
+	int i, trip_point;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		trip_point = tc[i].hw_reboot_trip_point;
+
+		if (tc[i].num_sensor == 0)
+			continue;
+
+		if (trip_point == DISABLE_THERMAL_HW_REBOOT)
+			continue;
+
+		set_tc_hw_reboot_threshold(lvts_data, trip_point, i);
+	}
+}
+
+static int lvts_init(struct lvts_data *lvts_data)
+{
+	struct platform_ops *ops = &lvts_data->ops;
+	struct device *dev = lvts_data->dev;
+	int ret;
+
+	ret = clk_prepare_enable(lvts_data->clk);
+	if (ret) {
+		dev_err(dev,
+			"Error: Failed to enable lvts controller clock: %d\n",
+			ret);
+		return ret;
+	}
+
+	if (lvts_data->feature_bitmap & FEATURE_RESET)
+		lvts_reset(lvts_data);
+
+	device_identification(lvts_data);
+	if (ops->device_enable_and_init)
+		ops->device_enable_and_init(lvts_data);
+
+	if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK)) {
+		if (ops->device_enable_auto_rck)
+			ops->device_enable_auto_rck(lvts_data);
+	} else {
+		if (ops->device_read_count_rc_n)
+			ops->device_read_count_rc_n(lvts_data);
+	}
+
+	if (ops->set_cal_data)
+		ops->set_cal_data(lvts_data);
+
+	disable_all_sensing_points(lvts_data);
+	wait_all_tc_sensing_point_idle(lvts_data);
+	if (ops->init_controller)
+		ops->init_controller(lvts_data);
+	enable_all_sensing_points(lvts_data);
+
+	set_all_tc_hw_reboot(lvts_data);
+
+	return 0;
+}
+
+static int prepare_calibration_data(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+	struct platform_ops *ops = &lvts_data->ops;
+	int i, offset, size;
+	char buffer[512];
+
+	cal_data->count_r =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*cal_data->count_r), GFP_KERNEL);
+	if (!cal_data->count_r)
+		return -ENOMEM;
+
+	cal_data->count_rc =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*cal_data->count_rc), GFP_KERNEL);
+	if (!cal_data->count_rc)
+		return -ENOMEM;
+
+	if (ops->efuse_to_cal_data && !cal_data->use_fake_efuse)
+		ops->efuse_to_cal_data(lvts_data);
+
+	if (cal_data->golden_temp == 0 ||
+	    cal_data->golden_temp > GOLDEN_TEMP_MAX)
+		cal_data->use_fake_efuse = 1;
+
+	if (cal_data->use_fake_efuse) {
+		/* It means all efuse data are equal to 0 */
+		dev_err(dev,
+			"[lvts_cal] This sample is not calibrated, fake !!\n");
+
+		cal_data->golden_temp = cal_data->default_golden_temp;
+		for (i = 0; i < lvts_data->num_sensor; i++) {
+			cal_data->count_r[i] = cal_data->default_count_r;
+			cal_data->count_rc[i] = cal_data->default_count_rc;
+		}
+	}
+
+	lvts_data->coeff.golden_temp = cal_data->golden_temp;
+
+	dev_info(dev, "[lvts_cal] golden_temp = %d\n", cal_data->golden_temp);
+
+	size = sizeof(buffer);
+	offset = snprintf(buffer, size, "[lvts_cal] num:g_count:g_count_rc ");
+	for (i = 0; i < lvts_data->num_sensor; i++)
+		offset +=
+			snprintf(buffer + offset, size - offset, "%d:%d:%d ", i,
+				 cal_data->count_r[i], cal_data->count_rc[i]);
+
+	buffer[offset] = '\0';
+	dev_info(dev, "%s\n", buffer);
+
+	return 0;
+}
+
+static int get_calibration_data(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	char cell_name[8];
+	struct nvmem_cell *cell;
+	u32 *buf;
+	size_t len;
+	int i, j, index = 0;
+
+	lvts_data->efuse = devm_kcalloc(dev, lvts_data->num_efuse_addr,
+					sizeof(*lvts_data->efuse), GFP_KERNEL);
+	if (!lvts_data->efuse)
+		return -ENOMEM;
+
+	for (i = 0; i < lvts_data->num_efuse_block; i++) {
+		snprintf(cell_name, sizeof(cell_name), "e_data%d", i + 1);
+		cell = nvmem_cell_get(dev, cell_name);
+		if (IS_ERR(cell)) {
+			dev_err(dev, "Error: Failed to get nvmem cell %s\n",
+				cell_name);
+			return PTR_ERR(cell);
+		}
+
+		buf = (u32 *)nvmem_cell_read(cell, &len);
+		nvmem_cell_put(cell);
+
+		if (IS_ERR(buf))
+			return PTR_ERR(buf);
+
+		for (j = 0; j < (len / sizeof(u32)); j++) {
+			if (index >= lvts_data->num_efuse_addr) {
+				dev_err(dev,
+					"Array efuse is going to overflow");
+				kfree(buf);
+				return -EINVAL;
+			}
+
+			lvts_data->efuse[index] = buf[j];
+			index++;
+		}
+
+		kfree(buf);
+	}
+
+	return 0;
+}
+
+static int of_update_lvts_data(struct lvts_data *lvts_data,
+			       struct platform_device *pdev)
+{
+	struct device *dev = lvts_data->dev;
+	struct power_domain *domain;
+	struct resource *res;
+	unsigned int i;
+	int ret;
+
+	lvts_data->clk = devm_clk_get(dev, "lvts_clk");
+	if (IS_ERR(lvts_data->clk))
+		return PTR_ERR(lvts_data->clk);
+
+	domain = devm_kcalloc(dev, lvts_data->num_domain, sizeof(*domain),
+			      GFP_KERNEL);
+	if (!domain)
+		return -ENOMEM;
+
+	for (i = 0; i < lvts_data->num_domain; i++) {
+		/* Get base address */
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			dev_err(dev, "No IO resource, index %d\n", i);
+			return -ENXIO;
+		}
+
+		domain[i].base = devm_ioremap_resource(dev, res);
+		if (IS_ERR(domain[i].base)) {
+			dev_err(dev, "Failed to remap io, index %d\n", i);
+			return PTR_ERR(domain[i].base);
+		}
+
+		/* Get interrupt number */
+		if (lvts_data->feature_bitmap & FEATURE_IRQ) {
+			res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+			if (!res) {
+				dev_err(dev, "No irq resource, index %d\n", i);
+				return -EINVAL;
+			}
+			domain[i].irq_num = res->start;
+		}
+
+		/* Get reset control */
+		if (lvts_data->feature_bitmap & FEATURE_RESET) {
+			domain[i].reset =
+				devm_reset_control_get_by_index(dev, i);
+			if (IS_ERR(domain[i].reset)) {
+				dev_err(dev, "Failed to get, index %d\n", i);
+				return PTR_ERR(domain[i].reset);
+			}
+		}
+	}
+
+	lvts_data->domain = domain;
+
+	lvts_data->sen_data =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*lvts_data->sen_data), GFP_KERNEL);
+	if (!lvts_data->sen_data)
+		return -ENOMEM;
+
+	ret = get_calibration_data(lvts_data);
+	if (ret)
+		lvts_data->cal_data.use_fake_efuse = 1;
+	ret = prepare_calibration_data(lvts_data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void lvts_device_close(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		lvts_write_device(lvts_data, RESET_ALL_DEVICES, i);
+		writel(DISABLE_LVTS_CTRL_CLK, LVTSCLKEN_0 + base);
+	}
+}
+
+static void lvts_close(struct lvts_data *lvts_data)
+{
+	disable_all_sensing_points(lvts_data);
+	wait_all_tc_sensing_point_idle(lvts_data);
+	lvts_device_close(lvts_data);
+	clk_disable_unprepare(lvts_data->clk);
+}
+
+static void tc_irq_handler(struct lvts_data *lvts_data, int tc_id)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int ret = 0;
+	void __iomem *base;
+
+	base = GET_BASE_ADDR(tc_id);
+
+	ret = readl(LVTSMONINTSTS_0 + base);
+	/* Write back to clear interrupt status */
+	writel(ret, LVTSMONINTSTS_0 + base);
+
+	dev_info(
+		dev,
+		"[Thermal IRQ] LVTS thermal controller %d, LVTSMONINTSTS=0x%08x\n",
+		tc_id, ret);
+
+	if (ret & THERMAL_PROTECTION_STAGE_3)
+		dev_info(
+			dev,
+			"[Thermal IRQ]: Thermal protection stage 3 interrupt triggered\n");
+}
+
+static irqreturn_t irq_handler(int irq, void *dev_id)
+{
+	struct lvts_data *lvts_data = (struct lvts_data *)dev_id;
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	unsigned int i, *irq_bitmap;
+	void __iomem *base;
+
+	irq_bitmap =
+		kcalloc(lvts_data->num_domain, sizeof(*irq_bitmap), GFP_ATOMIC);
+
+	if (!irq_bitmap)
+		return IRQ_NONE;
+
+	for (i = 0; i < lvts_data->num_domain; i++) {
+		base = lvts_data->domain[i].base;
+		irq_bitmap[i] = readl(THERMINTST + base);
+		dev_info(dev, "%s : THERMINTST = 0x%x\n", __func__,
+			 irq_bitmap[i]);
+	}
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		if ((irq_bitmap[tc[i].domain_index] & tc[i].irq_bit) == 0)
+			tc_irq_handler(lvts_data, i);
+	}
+
+	kfree(irq_bitmap);
+
+	return IRQ_HANDLED;
+}
+
+static int lvts_register_irq_handler(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < lvts_data->num_domain; i++) {
+		ret = devm_request_irq(dev, lvts_data->domain[i].irq_num,
+				       irq_handler, IRQF_TRIGGER_HIGH,
+				       "mtk_lvts", lvts_data);
+
+		if (ret) {
+			dev_err(dev,
+				"Failed to register LVTS IRQ, ret %d, domain %d irq_num %d\n",
+				ret, i, lvts_data->domain[i].irq_num);
+			lvts_close(lvts_data);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int lvts_register_thermal_zones(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	struct thermal_zone_device *tzdev;
+	struct soc_temp_tz *lvts_tz;
+	int i, ret;
+
+	for (i = 0; i < lvts_data->num_sensor + 1; i++) {
+		lvts_tz = devm_kzalloc(dev, sizeof(*lvts_tz), GFP_KERNEL);
+		if (!lvts_tz) {
+			lvts_close(lvts_data);
+			return -ENOMEM;
+		}
+
+		lvts_tz->id = i;
+		lvts_tz->lvts_data = lvts_data;
+
+		tzdev = devm_thermal_zone_of_sensor_register(
+			dev, lvts_tz->id, lvts_tz, &soc_temp_lvts_ops);
+
+		if (IS_ERR(tzdev)) {
+			if (lvts_tz->id != 0)
+				return 0;
+
+			ret = PTR_ERR(tzdev);
+			lvts_close(lvts_data);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int lvts_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lvts_data *lvts_data;
+	int ret;
+
+	lvts_data = (struct lvts_data *)of_device_get_match_data(dev);
+
+	if (!lvts_data) {
+		dev_err(dev, "Error: Failed to get lvts platform data\n");
+		return -ENODATA;
+	}
+
+	lvts_data->dev = &pdev->dev;
+
+	ret = of_update_lvts_data(lvts_data, pdev);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, lvts_data);
+
+	ret = lvts_init(lvts_data);
+	if (ret)
+		return ret;
+
+	if (lvts_data->feature_bitmap & FEATURE_IRQ) {
+		ret = lvts_register_irq_handler(lvts_data);
+		if (ret)
+			return ret;
+	}
+
+	ret = lvts_register_thermal_zones(lvts_data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int lvts_remove(struct platform_device *pdev)
+{
+	struct lvts_data *lvts_data;
+
+	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
+
+	lvts_close(lvts_data);
+
+	return 0;
+}
+
+static int lvts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct lvts_data *lvts_data;
+
+	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
+
+	lvts_close(lvts_data);
+
+	return 0;
+}
+
+static int lvts_resume(struct platform_device *pdev)
+{
+	int ret;
+	struct lvts_data *lvts_data;
+
+	lvts_data = (struct lvts_data *)platform_get_drvdata(pdev);
+
+	ret = lvts_init(lvts_data);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * LVTS v4 common code
+ */
+
+static void device_enable_and_init_v4(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		lvts_write_device(lvts_data, STOP_COUNTING_V4, i);
+		lvts_write_device(lvts_data, SET_RG_TSFM_LPDLY_V4, i);
+		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US1_V4, i);
+		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US2_V4, i);
+		lvts_write_device(lvts_data, TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V4,
+				  i);
+		lvts_write_device(lvts_data, TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V4,
+				  i);
+		lvts_write_device(lvts_data, SET_TS_RSV_V4, i);
+		lvts_write_device(lvts_data, SET_TS_EN_V4, i);
+		lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST1_V4, i);
+		lvts_write_device(lvts_data, TOGGLE_RG_TSV2F_VCO_RST2_V4, i);
+	}
+
+	lvts_data->counting_window_us = 20;
+}
+
+static void device_enable_auto_rck_v4(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+
+	for (i = 0; i < lvts_data->num_tc; i++)
+		lvts_write_device(lvts_data, SET_LVTS_AUTO_RCK_V4, i);
+}
+
+static int device_read_count_rc_n_v4(struct lvts_data *lvts_data)
+{
+	/* Resistor-Capacitor Calibration */
+	/* count_RC_N: count RC now */
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+	unsigned int offset, size, s_index, data;
+	void __iomem *base;
+	int ret, i, j;
+	char buffer[512];
+
+	cal_data->count_rc_now =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*cal_data->count_rc_now), GFP_KERNEL);
+	if (!cal_data->count_rc_now)
+		return -ENOMEM;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		for (j = 0; j < tc[i].num_sensor; j++) {
+			s_index = tc[i].sensor_map[j];
+
+			lvts_write_device(lvts_data, SELECT_SENSOR_RCK_V4(j),
+					  i);
+			lvts_write_device(lvts_data, SET_DEVICE_SINGLE_MODE_V4,
+					  i);
+			usleep_range(10, 20);
+
+			lvts_write_device(lvts_data, KICK_OFF_RCK_COUNTING_V4,
+					  i);
+			usleep_range(30, 40);
+
+			ret = readl_poll_timeout(
+				LVTS_CONFIG_0 + base, data,
+				!(data & DEVICE_SENSING_STATUS), 2, 200);
+
+			data = lvts_read_device(lvts_data, 0x00, i);
+
+			cal_data->count_rc_now[s_index] =
+				(data & GENMASK(23, 0));
+		}
+
+		/* Recover Setting for Normal Access on
+		 * temperature fetch
+		 */
+		lvts_write_device(lvts_data, SET_SENSOR_NO_RCK_V4, i);
+		lvts_write_device(lvts_data,
+				  SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i);
+	}
+
+	size = sizeof(buffer);
+	offset = snprintf(buffer, size, "[COUNT_RC_NOW] ");
+	for (i = 0; i < lvts_data->num_sensor; i++)
+		offset += snprintf(buffer + offset, size - offset, "%d:%d ", i,
+				   cal_data->count_rc_now[i]);
+
+	buffer[offset] = '\0';
+	dev_info(dev, "%s\n", buffer);
+
+	return 0;
+}
+
+static void set_calibration_data_v4(struct lvts_data *lvts_data)
+{
+	struct tc_settings *tc = lvts_data->tc;
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+	unsigned int i, j, s_index, e_data;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+
+		for (j = 0; j < tc[i].num_sensor; j++) {
+			s_index = tc[i].sensor_map[j];
+			if (IS_ENABLE(FEATURE_DEVICE_AUTO_RCK))
+				e_data = cal_data->count_r[s_index];
+			else
+				e_data = (((unsigned long long)cal_data
+						   ->count_rc_now[s_index]) *
+					  cal_data->count_r[s_index]) >>
+					 14;
+
+			writel(e_data, LVTSEDATA00_0 + base + 0x4 * j);
+		}
+	}
+}
+
+static void init_controller_v4(struct lvts_data *lvts_data)
+{
+	struct device *dev = lvts_data->dev;
+	unsigned int i;
+	void __iomem *base;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+
+		lvts_write_device(lvts_data,
+				  SET_DEVICE_LOW_POWER_SINGLE_MODE_V4, i);
+
+		writel(SET_SENSOR_INDEX, LVTSTSSEL_0 + base);
+		writel(SET_CALC_SCALE_RULES, LVTSCALSCALE_0 + base);
+
+		set_polling_speed(lvts_data, i);
+		set_hw_filter(lvts_data, i);
+
+		dev_info(dev,
+			 "lvts%d: read all %d sensors in %d us, one in %d us\n",
+			 i, GET_TC_SENSOR_NUM(i), GROUP_LATENCY_US(i),
+			 SENSOR_LATENCY_US(i));
+	}
+}
+
+/*
+ * LVTS v5 common code
+ */
+static void device_enable_and_init_v5(struct lvts_data *lvts_data)
+{
+	unsigned int i;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		lvts_write_device(lvts_data, STOP_COUNTING_V5, i);
+		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US2_V5, i);
+		lvts_write_device(lvts_data, SET_COUNTING_WINDOW_20US1_V5, i);
+		lvts_write_device(lvts_data, SET_RG_TSFM_LPDLY_V5, i);
+		lvts_write_device(lvts_data, TSBG_DEM_CKSEL_X_TSBG_CHOP_EN_V5,
+				  i);
+		lvts_write_device(lvts_data, TSV2F_CHOP_CKSEL_AND_TSV2F_EN_V5,
+				  i);
+		lvts_write_device(lvts_data, SET_TS_RSV_V5, i);
+		lvts_write_device(lvts_data, SET_TS_EN_V5, i);
+	}
+
+	lvts_data->counting_window_us = 20;
+}
+
+static int device_read_count_rc_n_v5(struct lvts_data *lvts_data)
+{
+	/* Resistor-Capacitor Calibration */
+	/* count_RC_N: count RC now */
+	struct device *dev = lvts_data->dev;
+	struct tc_settings *tc = lvts_data->tc;
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+	unsigned int offset, size, s_index, data;
+	void __iomem *base;
+	int ret, i, j;
+	char buffer[512];
+
+	cal_data->count_rc_now =
+		devm_kcalloc(dev, lvts_data->num_sensor,
+			     sizeof(*cal_data->count_rc_now), GFP_KERNEL);
+	if (!cal_data->count_rc_now)
+		return -ENOMEM;
+
+	for (i = 0; i < lvts_data->num_tc; i++) {
+		base = GET_BASE_ADDR(i);
+		lvts_write_device(lvts_data, SET_MANUAL_RCK_V5, i);
+
+		for (j = 0; j < tc[i].num_sensor; j++) {
+			s_index = tc[i].sensor_map[j];
+
+			lvts_write_device(lvts_data, SELECT_SENSOR_RCK_V5(j),
+					  i);
+			lvts_write_device(lvts_data, SET_DEVICE_SINGLE_MODE_V5,
+					  i);
+			lvts_write_device(lvts_data,
+					  SET_COUNTING_WINDOW_20US2_V5, i);
+			lvts_write_device(lvts_data,
+					  SET_COUNTING_WINDOW_20US1_V5, i);
+			lvts_write_device(lvts_data, KICK_OFF_RCK_COUNTING_V5,
+					  i);
+			udelay(40);
+
+			ret = readl_poll_timeout(
+				LVTS_CONFIG_0 + base, data,
+				!(data & DEVICE_SENSING_STATUS), 2, 200);
+			if (ret)
+				dev_err(dev,
+					"Error: LVTS %d DEVICE_SENSING_STATUS didn't ready\n",
+					i);
+
+			data = lvts_read_device(lvts_data, 0x00, i);
+
+			cal_data->count_rc_now[s_index] =
+				(data & GENMASK(23, 0));
+
+			/* Recover Setting for Normal Access on
+			 * temperature fetch
+			 */
+			lvts_write_device(lvts_data, SET_SENSOR_NO_RCK_V5(j),
+					  i);
+			lvts_write_device(lvts_data,
+					  SET_DEVICE_LOW_POWER_SINGLE_MODE_V5,
+					  i);
+		}
+	}
+
+	size = sizeof(buffer);
+	offset = snprintf(buffer, size, "[COUNT_RC_NOW] ");
+	for (i = 0; i < lvts_data->num_sensor; i++)
+		offset += snprintf(buffer + offset, size - offset, "%d:%d ", i,
+				   cal_data->count_rc_now[i]);
+
+	buffer[offset] = '\0';
+	dev_info(dev, "%s\n", buffer);
+
+	return 0;
+}
+
+/*
+ * LVTS MT6873
+ */
+
+#define MT6873_NUM_LVTS (ARRAY_SIZE(mt6873_tc_settings))
+
+enum mt6873_lvts_domain {
+	MT6873_AP_DOMAIN,
+	MT6873_MCU_DOMAIN,
+	MT6873_NUM_DOMAIN
+};
+
+enum mt6873_lvts_sensor_enum {
+	MT6873_TS1_0,
+	MT6873_TS1_1,
+	MT6873_TS2_0,
+	MT6873_TS2_1,
+	MT6873_TS3_0,
+	MT6873_TS3_1,
+	MT6873_TS3_2,
+	MT6873_TS3_3,
+	MT6873_TS4_0,
+	MT6873_TS4_1,
+	MT6873_TS5_0,
+	MT6873_TS5_1,
+	MT6873_TS6_0,
+	MT6873_TS6_1,
+	MT6873_TS7_0,
+	MT6873_TS7_1,
+	MT6873_TS7_2,
+	MT6873_NUM_TS
+};
+
+static void mt6873_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24);
+	cal_data->count_r[MT6873_TS1_0] = GET_CAL_DATA_BITMASK(1, 23, 0);
+	cal_data->count_r[MT6873_TS1_1] = GET_CAL_DATA_BITMASK(2, 23, 0);
+	cal_data->count_r[MT6873_TS2_0] = GET_CAL_DATA_BITMASK(3, 23, 0);
+	cal_data->count_r[MT6873_TS2_1] = GET_CAL_DATA_BITMASK(4, 23, 0);
+	cal_data->count_r[MT6873_TS3_0] = GET_CAL_DATA_BITMASK(5, 23, 0);
+	cal_data->count_r[MT6873_TS3_1] = GET_CAL_DATA_BITMASK(6, 23, 0);
+	cal_data->count_r[MT6873_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0);
+	cal_data->count_r[MT6873_TS3_3] = GET_CAL_DATA_BITMASK(8, 23, 0);
+	cal_data->count_r[MT6873_TS4_0] = GET_CAL_DATA_BITMASK(9, 23, 0);
+	cal_data->count_r[MT6873_TS4_1] = GET_CAL_DATA_BITMASK(10, 23, 0);
+	cal_data->count_r[MT6873_TS5_0] = GET_CAL_DATA_BITMASK(11, 23, 0);
+	cal_data->count_r[MT6873_TS5_1] = GET_CAL_DATA_BITMASK(12, 23, 0);
+	cal_data->count_r[MT6873_TS6_0] = GET_CAL_DATA_BITMASK(13, 23, 0);
+	cal_data->count_r[MT6873_TS6_1] = GET_CAL_DATA_BITMASK(14, 23, 0);
+	cal_data->count_r[MT6873_TS7_0] = GET_CAL_DATA_BITMASK(15, 23, 0);
+	cal_data->count_r[MT6873_TS7_1] = GET_CAL_DATA_BITMASK(16, 23, 0);
+	cal_data->count_r[MT6873_TS7_2] = GET_CAL_DATA_BITMASK(17, 23, 0);
+
+	cal_data->count_rc[MT6873_TS1_0] = GET_CAL_DATA_BITMASK(21, 23, 0);
+
+	cal_data->count_rc[MT6873_TS2_0] =
+		(GET_CAL_DATA_BITMASK(1, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(2, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(3, 31, 24);
+
+	cal_data->count_rc[MT6873_TS3_0] =
+		(GET_CAL_DATA_BITMASK(4, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(5, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(6, 31, 24);
+
+	cal_data->count_rc[MT6873_TS4_0] =
+		(GET_CAL_DATA_BITMASK(7, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(8, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(9, 31, 24);
+
+	cal_data->count_rc[MT6873_TS5_0] =
+		(GET_CAL_DATA_BITMASK(10, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(11, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(12, 31, 24);
+
+	cal_data->count_rc[MT6873_TS6_0] =
+		(GET_CAL_DATA_BITMASK(13, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(14, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(15, 31, 24);
+
+	cal_data->count_rc[MT6873_TS7_0] =
+		(GET_CAL_DATA_BITMASK(16, 31, 24) << 16) +
+		(GET_CAL_DATA_BITMASK(17, 31, 24) << 8) +
+		GET_CAL_DATA_BITMASK(18, 31, 24);
+}
+
+static struct tc_settings mt6873_tc_settings[] = {
+	[0] = {
+		.domain_index = MT6873_MCU_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS1_0, MT6873_TS1_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[1] = {
+		.domain_index = MT6873_MCU_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS2_0, MT6873_TS2_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[2] = {
+		.domain_index = MT6873_MCU_DOMAIN,
+		.addr_offset = 0x200,
+		.num_sensor = 4,
+		.sensor_map = {MT6873_TS3_0, MT6873_TS3_1, MT6873_TS3_2,
+			       MT6873_TS3_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	},
+	[3] = {
+		.domain_index = MT6873_AP_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS4_0, MT6873_TS4_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[4] = {
+		.domain_index = MT6873_AP_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS5_0, MT6873_TS5_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[5] = {
+		.domain_index = MT6873_AP_DOMAIN,
+		.addr_offset = 0x200,
+		.num_sensor = 2,
+		.sensor_map = {MT6873_TS6_0, MT6873_TS6_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	},
+	[6] = {
+		.domain_index = MT6873_AP_DOMAIN,
+		.addr_offset = 0x300,
+		.num_sensor = 3,
+		.sensor_map = {MT6873_TS7_0, MT6873_TS7_1, MT6873_TS7_2},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT2,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(6),
+	}
+};
+
+static struct lvts_data mt6873_lvts_data = {
+	.num_domain = MT6873_NUM_DOMAIN,
+	.num_tc = MT6873_NUM_LVTS,
+	.tc = mt6873_tc_settings,
+	.num_sensor = MT6873_NUM_TS,
+	.ops = {
+		.efuse_to_cal_data = mt6873_efuse_to_cal_data,
+		.device_enable_and_init = device_enable_and_init_v4,
+		.device_enable_auto_rck = device_enable_auto_rck_v4,
+		.device_read_count_rc_n = device_read_count_rc_n_v4,
+		.set_cal_data = set_calibration_data_v4,
+		.init_controller = init_controller_v4,
+	},
+	.feature_bitmap = FEATURE_DEVICE_AUTO_RCK,
+	.num_efuse_addr = 22,
+	.num_efuse_block = 1,
+	.cal_data = {
+		.default_golden_temp = 50,
+		.default_count_r = 35000,
+		.default_count_rc = 2750,
+	},
+	.coeff = {
+		.a = -250460,
+		.b = 250460,
+	},
+};
+
+/*
+ * LVTS MT7988
+ */
+
+#define MT7988_NUM_LVTS (ARRAY_SIZE(mt7988_tc_settings))
+
+enum mt7988_lvts_domain { MT7988_AP_DOMAIN, MT7988_NUM_DOMAIN };
+
+enum mt7988_lvts_sensor_enum {
+	MT7988_TS2_0,
+	MT7988_TS2_1,
+	MT7988_TS2_2,
+	MT7988_TS2_3,
+	MT7988_TS3_0,
+	MT7988_TS3_1,
+	MT7988_TS3_2,
+	MT7988_TS3_3,
+	MT7988_NUM_TS
+};
+
+static void mt7988_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24);
+
+	cal_data->count_r[MT7988_TS2_0] = GET_CAL_DATA_BITMASK(0, 23, 0);
+	cal_data->count_r[MT7988_TS2_1] = GET_CAL_DATA_BITMASK(1, 23, 0);
+	cal_data->count_r[MT7988_TS2_2] = GET_CAL_DATA_BITMASK(2, 23, 0);
+	cal_data->count_r[MT7988_TS2_3] = GET_CAL_DATA_BITMASK(3, 23, 0);
+	cal_data->count_rc[MT7988_TS2_0] = GET_CAL_DATA_BITMASK(4, 23, 0);
+
+	cal_data->count_r[MT7988_TS3_0] = GET_CAL_DATA_BITMASK(5, 23, 0);
+	cal_data->count_r[MT7988_TS3_1] = GET_CAL_DATA_BITMASK(6, 23, 0);
+	cal_data->count_r[MT7988_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0);
+	cal_data->count_r[MT7988_TS3_3] = GET_CAL_DATA_BITMASK(8, 23, 0);
+	cal_data->count_rc[MT7988_TS3_0] = GET_CAL_DATA_BITMASK(9, 23, 0);
+}
+
+static struct tc_settings mt7988_tc_settings[] = {
+	[0] = {
+		.domain_index = MT7988_AP_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 4,
+		.sensor_map = {MT7988_TS2_0, MT7988_TS2_1, MT7988_TS2_2,
+			       MT7988_TS2_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_16_OF_18,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[1] = {
+		.domain_index = MT7988_AP_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 4,
+		.sensor_map = {MT7988_TS3_0, MT7988_TS3_1, MT7988_TS3_2,
+			       MT7988_TS3_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_16_OF_18,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	}
+
+};
+
+static struct lvts_data mt7988_lvts_data = {
+	.num_domain = MT7988_NUM_DOMAIN,
+	.num_tc = MT7988_NUM_LVTS,
+	.tc = mt7988_tc_settings,
+	.num_sensor = MT7988_NUM_TS,
+	.ops = {
+		.efuse_to_cal_data = mt7988_efuse_to_cal_data,
+		.device_enable_and_init = device_enable_and_init_v5,
+		.device_enable_auto_rck = device_enable_auto_rck_v4,
+		.device_read_count_rc_n = device_read_count_rc_n_v5,
+		.set_cal_data = set_calibration_data_v4,
+		.init_controller = init_controller_v4,
+	},
+	.feature_bitmap = 0,
+	.num_efuse_addr = 10,
+	.num_efuse_block = 1,
+	.cal_data = {
+		.default_golden_temp = 60,
+		.default_count_r = 19380,
+		.default_count_rc = 5330,
+	},
+	.coeff = {
+		.a = -204650,
+		.b = 204650,
+	},
+};
+
+/*
+ * LVTS MT8195
+ */
+
+#define MT8195_NUM_LVTS (ARRAY_SIZE(mt8195_tc_settings))
+
+enum mt8195_lvts_domain {
+	MT8195_AP_DOMAIN,
+	MT8195_MCU_DOMAIN,
+	MT8195_NUM_DOMAIN
+};
+
+enum mt8195_lvts_sensor_enum {
+	MT8195_TS1_0,
+	MT8195_TS1_1,
+	MT8195_TS2_0,
+	MT8195_TS2_1,
+	MT8195_TS3_0,
+	MT8195_TS3_1,
+	MT8195_TS3_2,
+	MT8195_TS3_3,
+	MT8195_TS4_0,
+	MT8195_TS4_1,
+	MT8195_TS5_0,
+	MT8195_TS5_1,
+	MT8195_TS6_0,
+	MT8195_TS6_1,
+	MT8195_TS6_2,
+	MT8195_TS7_0,
+	MT8195_TS7_1,
+	MT8195_NUM_TS
+};
+
+static void mt8195_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 31, 24);
+	cal_data->count_r[MT8195_TS1_0] = GET_CAL_DATA_BITMASK(1, 23, 0);
+	cal_data->count_r[MT8195_TS1_1] =
+		(GET_CAL_DATA_BITMASK(2, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(1, 31, 24);
+	cal_data->count_r[MT8195_TS2_0] = GET_CAL_DATA_BITMASK(3, 31, 8);
+	cal_data->count_r[MT8195_TS2_1] = GET_CAL_DATA_BITMASK(4, 23, 0);
+	cal_data->count_r[MT8195_TS3_0] =
+		(GET_CAL_DATA_BITMASK(6, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(5, 31, 16);
+	cal_data->count_r[MT8195_TS3_1] = GET_CAL_DATA_BITMASK(6, 31, 8);
+	cal_data->count_r[MT8195_TS3_2] = GET_CAL_DATA_BITMASK(7, 23, 0);
+	cal_data->count_r[MT8195_TS3_3] =
+		(GET_CAL_DATA_BITMASK(8, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(7, 31, 24);
+	cal_data->count_r[MT8195_TS4_0] = GET_CAL_DATA_BITMASK(9, 31, 8);
+	cal_data->count_r[MT8195_TS4_1] = GET_CAL_DATA_BITMASK(10, 23, 0);
+	cal_data->count_r[MT8195_TS5_0] =
+		(GET_CAL_DATA_BITMASK(12, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(11, 31, 16);
+	cal_data->count_r[MT8195_TS5_1] = GET_CAL_DATA_BITMASK(12, 31, 8);
+	cal_data->count_r[MT8195_TS6_0] =
+		(GET_CAL_DATA_BITMASK(14, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(13, 31, 24);
+	cal_data->count_r[MT8195_TS6_1] =
+		(GET_CAL_DATA_BITMASK(15, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(14, 31, 16);
+	cal_data->count_r[MT8195_TS6_2] = GET_CAL_DATA_BITMASK(15, 31, 8);
+	cal_data->count_r[MT8195_TS7_0] =
+		(GET_CAL_DATA_BITMASK(17, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(16, 31, 24);
+	cal_data->count_r[MT8195_TS7_1] =
+		(GET_CAL_DATA_BITMASK(18, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(17, 31, 16);
+	cal_data->count_rc[MT8195_TS1_0] =
+		(GET_CAL_DATA_BITMASK(3, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(2, 31, 16);
+	cal_data->count_rc[MT8195_TS2_0] =
+		(GET_CAL_DATA_BITMASK(5, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(4, 31, 24);
+	cal_data->count_rc[MT8195_TS3_0] =
+		(GET_CAL_DATA_BITMASK(9, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(8, 31, 16);
+	cal_data->count_rc[MT8195_TS4_0] =
+		(GET_CAL_DATA_BITMASK(11, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(10, 31, 24);
+	cal_data->count_rc[MT8195_TS5_0] = GET_CAL_DATA_BITMASK(13, 23, 0);
+	cal_data->count_rc[MT8195_TS6_0] = GET_CAL_DATA_BITMASK(16, 23, 0);
+	cal_data->count_rc[MT8195_TS7_0] = GET_CAL_DATA_BITMASK(18, 31, 8);
+}
+
+static struct tc_settings mt8195_tc_settings[] = {
+	[0] = {
+		.domain_index = MT8195_MCU_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS1_0, MT8195_TS1_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[1] = {
+		.domain_index = MT8195_MCU_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS2_0, MT8195_TS2_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[2] = {
+		.domain_index = MT8195_MCU_DOMAIN,
+		.addr_offset = 0x200,
+		.num_sensor = 4,
+		.sensor_map = {MT8195_TS3_0, MT8195_TS3_1, MT8195_TS3_2,
+			       MT8195_TS3_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	},
+	[3] = {
+		.domain_index = MT8195_AP_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS4_0, MT8195_TS4_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[4] = {
+		.domain_index = MT8195_AP_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS5_0, MT8195_TS5_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[5] = {
+		.domain_index = MT8195_AP_DOMAIN,
+		.addr_offset = 0x200,
+		.num_sensor = 3,
+		.sensor_map = {MT8195_TS6_0, MT8195_TS6_1, MT8195_TS6_2},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	},
+	[6] = {
+		.domain_index = MT8195_AP_DOMAIN,
+		.addr_offset = 0x300,
+		.num_sensor = 2,
+		.sensor_map = {MT8195_TS7_0, MT8195_TS7_1},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(6),
+	}
+};
+
+static struct lvts_data mt8195_lvts_data = {
+	.num_domain = MT8195_NUM_DOMAIN,
+	.num_tc = MT8195_NUM_LVTS,
+	.tc = mt8195_tc_settings,
+	.num_sensor = MT8195_NUM_TS,
+	.ops = {
+		.efuse_to_cal_data = mt8195_efuse_to_cal_data,
+		.device_enable_and_init = device_enable_and_init_v4,
+		.device_enable_auto_rck = device_enable_auto_rck_v4,
+		.device_read_count_rc_n = device_read_count_rc_n_v4,
+		.set_cal_data = set_calibration_data_v4,
+		.init_controller = init_controller_v4,
+	},
+	.feature_bitmap = FEATURE_DEVICE_AUTO_RCK,
+	.num_efuse_addr = 22,
+	.num_efuse_block = 2,
+	.cal_data = {
+		.default_golden_temp = 50,
+		.default_count_r = 35000,
+		.default_count_rc = 2750,
+	},
+	.coeff = {
+		.a = -250460,
+		.b = 250460,
+	},
+};
+
+/*
+ * LVTS MT8139
+ */
+
+#define MT8139_NUM_LVTS (ARRAY_SIZE(mt8139_tc_settings))
+
+enum mt8139_lvts_domain {
+	MT8139_AP_DOMAIN,
+	MT8139_MCU_DOMAIN,
+	MT8139_NUM_DOMAIN
+};
+
+enum mt8139_lvts_sensor_enum {
+	MT8139_TS1_0,
+	MT8139_TS1_1,
+	MT8139_TS1_2,
+	MT8139_TS1_3,
+	MT8139_TS2_0,
+	MT8139_TS2_1,
+	MT8139_TS2_2,
+	MT8139_TS2_3,
+	MT8139_TS3_0,
+	MT8139_TS3_1,
+	MT8139_TS3_2,
+	MT8139_TS3_3,
+	MT8139_NUM_TS
+};
+
+static void mt8139_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+	struct sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+	cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, 7, 0);
+	cal_data->count_r[MT8139_TS1_0] = GET_CAL_DATA_BITMASK(0, 31, 8);
+	cal_data->count_r[MT8139_TS1_1] = GET_CAL_DATA_BITMASK(1, 23, 0);
+	cal_data->count_r[MT8139_TS1_2] =
+		(GET_CAL_DATA_BITMASK(2, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(1, 31, 24);
+	cal_data->count_r[MT8139_TS1_3] =
+		(GET_CAL_DATA_BITMASK(3, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(2, 31, 16);
+	cal_data->count_rc[MT8139_TS1_0] = GET_CAL_DATA_BITMASK(3, 31, 8);
+
+	cal_data->count_r[MT8139_TS2_0] = GET_CAL_DATA_BITMASK(4, 23, 0);
+	cal_data->count_r[MT8139_TS2_1] =
+		(GET_CAL_DATA_BITMASK(5, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(4, 31, 24);
+	cal_data->count_r[MT8139_TS2_2] =
+		(GET_CAL_DATA_BITMASK(6, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(5, 31, 16);
+	cal_data->count_r[MT8139_TS2_3] = GET_CAL_DATA_BITMASK(6, 31, 8);
+	cal_data->count_rc[MT8139_TS2_0] = GET_CAL_DATA_BITMASK(7, 23, 0);
+
+	cal_data->count_r[MT8139_TS3_0] =
+		(GET_CAL_DATA_BITMASK(8, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(7, 31, 24);
+	cal_data->count_r[MT8139_TS3_1] =
+		(GET_CAL_DATA_BITMASK(9, 7, 0) << 16) +
+		GET_CAL_DATA_BITMASK(8, 31, 16);
+	cal_data->count_r[MT8139_TS3_2] = GET_CAL_DATA_BITMASK(9, 31, 8);
+	cal_data->count_r[MT8139_TS3_3] = GET_CAL_DATA_BITMASK(10, 23, 0);
+	cal_data->count_rc[MT8139_TS3_0] =
+		(GET_CAL_DATA_BITMASK(11, 15, 0) << 8) +
+		GET_CAL_DATA_BITMASK(10, 31, 24);
+}
+
+static struct tc_settings mt8139_tc_settings[] = {
+	[0] = {
+		.domain_index = MT8139_MCU_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 4,
+		.sensor_map = {MT8139_TS1_0, MT8139_TS1_1, MT8139_TS1_2,
+			       MT8139_TS1_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT1,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(3),
+	},
+	[1] = {
+		.domain_index = MT8139_AP_DOMAIN,
+		.addr_offset = 0x0,
+		.num_sensor = 4,
+		.sensor_map = {MT8139_TS2_0, MT8139_TS2_1, MT8139_TS2_2,
+			       MT8139_TS2_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(4),
+	},
+	[2] = {
+		.domain_index = MT8139_AP_DOMAIN,
+		.addr_offset = 0x100,
+		.num_sensor = 4,
+		.sensor_map = {MT8139_TS3_0, MT8139_TS3_1, MT8139_TS3_2,
+			       MT8139_TS3_3},
+		.tc_speed = SET_TC_SPEED_IN_US(118, 118, 118, 118),
+		.hw_filter = LVTS_FILTER_2_OF_4,
+		.dominator_sensing_point = SENSING_POINT0,
+		.hw_reboot_trip_point = 117000,
+		.irq_bit = BIT(5),
+	}
+
+};
+
+static struct lvts_data mt8139_lvts_data = {
+	.num_domain = MT8139_NUM_DOMAIN,
+	.num_tc = MT8139_NUM_LVTS,
+	.tc = mt8139_tc_settings,
+	.num_sensor = MT8139_NUM_TS,
+	.ops = {
+		.efuse_to_cal_data = mt8139_efuse_to_cal_data,
+		.device_enable_and_init = device_enable_and_init_v4,
+		.device_enable_auto_rck = device_enable_auto_rck_v4,
+		.device_read_count_rc_n = device_read_count_rc_n_v4,
+		.set_cal_data = set_calibration_data_v4,
+		.init_controller = init_controller_v4,
+	},
+	.feature_bitmap = 0,
+	.num_efuse_addr = 48,
+	.num_efuse_block = 1,
+	.cal_data = {
+		.default_golden_temp = 50,
+		.default_count_r = 35000,
+		.default_count_rc = 2750,
+	},
+	.coeff = {
+		.a = -250460,
+		.b = 250460,
+	},
+};
+
+/*
+ * Support chips
+ */
+static const struct of_device_id lvts_of_match[] = {
+	{
+		.compatible = "mediatek,mt6873-lvts",
+		.data = (void *)&mt6873_lvts_data,
+	},
+	{
+		.compatible = "mediatek,mt8195-lvts",
+		.data = (void *)&mt8195_lvts_data,
+	},
+	{
+		.compatible = "mediatek,mt8139-lvts",
+		.data = (void *)&mt8139_lvts_data,
+	},
+	{
+		.compatible = "mediatek,mt7988-lvts",
+		.data = (void *)&mt7988_lvts_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, lvts_of_match);
+
+static struct platform_driver soc_temp_lvts = {
+	.probe = lvts_probe,
+	.remove = lvts_remove,
+	.suspend = lvts_suspend,
+	.resume = lvts_resume,
+	.driver = {
+		.name = "mtk-soc-temp-lvts",
+		.of_match_table = lvts_of_match,
+	},
+};
+
+module_platform_driver(soc_temp_lvts);
+MODULE_AUTHOR("Yu-Chia Chang <ethan.chang@mediatek.com>");
+MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
+MODULE_AUTHOR("Henry Yen <henry.yen@mediatek.com>");
+MODULE_DESCRIPTION("Mediatek soc temperature driver");
+MODULE_LICENSE("GPL v2");
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.h
new file mode 100644
index 0000000..ed3d058
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/thermal/mediatek/soc_temp_lvts.h
@@ -0,0 +1,314 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ */
+
+#ifndef __MTK_SOC_TEMP_LVTS_H__
+#define __MTK_SOC_TEMP_LVTS_H__
+
+/* LVTS HW filter settings
+ * 000: Get one sample
+ * 001: Get 2 samples and average them
+ * 010: Get 4 samples, drop max and min, then average the rest of 2 samples
+ * 011: Get 6 samples, drop max and min, then average the rest of 4 samples
+ * 100: Get 10 samples, drop max and min, then average the rest of 8 samples
+ * 101: Get 18 samples, drop max and min, then average the rest of 16 samples
+ */
+enum lvts_hw_filter {
+	LVTS_FILTER_1,
+	LVTS_FILTER_2,
+	LVTS_FILTER_2_OF_4,
+	LVTS_FILTER_4_OF_6,
+	LVTS_FILTER_8_OF_10,
+	LVTS_FILTER_16_OF_18
+};
+
+enum lvts_sensing_point {
+	SENSING_POINT0,
+	SENSING_POINT1,
+	SENSING_POINT2,
+	SENSING_POINT3,
+	ALL_SENSING_POINTS
+};
+
+/*
+ * Data structure
+ */
+struct lvts_data;
+
+struct speed_settings {
+	unsigned int period_unit;
+	unsigned int group_interval_delay;
+	unsigned int filter_interval_delay;
+	unsigned int sensor_interval_delay;
+};
+
+struct tc_settings {
+	unsigned int domain_index;
+	unsigned int addr_offset;
+	unsigned int num_sensor;
+	unsigned int sensor_map[ALL_SENSING_POINTS]; /* In sensor ID */
+	struct speed_settings tc_speed;
+	/* HW filter setting
+	 * 000: Get one sample
+	 * 001: Get 2 samples and average them
+	 * 010: Get 4 samples, drop max and min, then average the rest of 2
+	 *	samples
+	 * 011: Get 6 samples, drop max and min, then average the rest of 4
+	 *      samples
+	 * 100: Get 10 samples, drop max and min, then average the rest of 8
+	 *      samples
+	 * 101: Get 18 samples, drop max and min, then average the rest of 16
+	 *      samples
+	 */
+	unsigned int hw_filter;
+	/* Dominator_sensing point is used to select a sensing point
+	 * and reference its temperature to trigger Thermal HW Reboot
+	 * When it is ALL_SENSING_POINTS, it will select all sensing points
+	 */
+	int dominator_sensing_point;
+	int hw_reboot_trip_point; /* -274000: Disable HW reboot */
+	unsigned int irq_bit;
+};
+
+struct formula_coeff {
+	int a;
+	int b;
+	unsigned int golden_temp;
+};
+
+struct sensor_cal_data {
+	int use_fake_efuse; /* 1: Use fake efuse, 0: Use real efuse */
+	unsigned int golden_temp;
+	unsigned int *count_r;
+	unsigned int *count_rc;
+	unsigned int *count_rc_now;
+
+	unsigned int default_golden_temp;
+	unsigned int default_count_r;
+	unsigned int default_count_rc;
+};
+
+struct platform_ops {
+	void (*efuse_to_cal_data)(struct lvts_data *lvts_data);
+	void (*device_enable_and_init)(struct lvts_data *lvts_data);
+	void (*device_enable_auto_rck)(struct lvts_data *lvts_data);
+	int (*device_read_count_rc_n)(struct lvts_data *lvts_data);
+	void (*set_cal_data)(struct lvts_data *lvts_data);
+	void (*init_controller)(struct lvts_data *lvts_data);
+};
+
+struct power_domain {
+	void __iomem *base; /* LVTS base addresses */
+	unsigned int irq_num; /* LVTS interrupt numbers */
+	struct reset_control *reset;
+};
+
+struct sensor_data {
+	int temp; /* Current temperature */
+	unsigned int msr_raw; /* MSR raw data from LVTS */
+};
+
+struct lvts_data {
+	struct device *dev;
+	struct clk *clk;
+	unsigned int num_domain;
+	struct power_domain *domain;
+
+	int num_tc; /* Number of LVTS thermal controllers */
+	struct tc_settings *tc;
+	int counting_window_us; /* LVTS device counting window */
+
+	int num_sensor; /* Number of sensors in this platform */
+	struct sensor_data *sen_data;
+
+	struct platform_ops ops;
+	int feature_bitmap; /* Show what features are enabled */
+
+	unsigned int num_efuse_addr;
+	unsigned int *efuse;
+	unsigned int num_efuse_block; /* Number of contiguous efuse indexes */
+	struct sensor_cal_data cal_data;
+	struct formula_coeff coeff;
+};
+
+struct soc_temp_tz {
+	unsigned int id; /* if id is 0, get max temperature of all sensors */
+	struct lvts_data *lvts_data;
+};
+
+struct match_entry {
+	char chip[32];
+	struct lvts_data *lvts_data;
+};
+
+struct lvts_match_data {
+	unsigned int hw_version;
+	struct match_entry *table;
+	void (*set_up_common_callbacks)(struct lvts_data *lvts_data);
+	struct list_head node;
+};
+
+struct lvts_id {
+	unsigned int hw_version;
+	char chip[32];
+};
+
+/*
+ * LVTS device register
+ */
+#define RG_TSFM_DATA_0	0x00
+#define RG_TSFM_DATA_1	0x01
+#define RG_TSFM_DATA_2	0x02
+#define RG_TSFM_CTRL_0	0x03
+#define RG_TSFM_CTRL_1	0x04
+#define RG_TSFM_CTRL_2	0x05
+#define RG_TSFM_CTRL_3	0x06
+#define RG_TSFM_CTRL_4	0x07
+#define RG_TSV2F_CTRL_0 0x08
+#define RG_TSV2F_CTRL_1 0x09
+#define RG_TSV2F_CTRL_2 0x0A
+#define RG_TSV2F_CTRL_3 0x0B
+#define RG_TSV2F_CTRL_4 0x0C
+#define RG_TSV2F_CTRL_5 0x0D
+#define RG_TSV2F_CTRL_6 0x0E
+#define RG_TEMP_DATA_0	0x10
+#define RG_TEMP_DATA_1	0x11
+#define RG_TEMP_DATA_2	0x12
+#define RG_TEMP_DATA_3	0x13
+#define RG_RC_DATA_0	0x14
+#define RG_RC_DATA_1	0x15
+#define RG_RC_DATA_2	0x16
+#define RG_RC_DATA_3	0x17
+#define RG_DIV_DATA_0	0x18
+#define RG_DIV_DATA_1	0x19
+#define RG_DIV_DATA_2	0x1A
+#define RG_DIV_DATA_3	0x1B
+#define RG_TST_DATA_0	0x70
+#define RG_TST_DATA_1	0x71
+#define RG_TST_DATA_2	0x72
+#define RG_TST_CTRL	0x73
+#define RG_DBG_FQMTR	0xF0
+#define RG_DBG_LPSEQ	0xF1
+#define RG_DBG_STATE	0xF2
+#define RG_DBG_CHKSUM	0xF3
+#define RG_DID_LVTS	0xFC
+#define RG_DID_REV	0xFD
+#define RG_TSFM_RST	0xFF
+/*
+ * LVTS controller register
+ */
+#define LVTSMONCTL0_0		  0x000
+#define LVTS_SINGLE_SENSE	  BIT(9)
+#define ENABLE_SENSING_POINT(num) (LVTS_SINGLE_SENSE | GENMASK(((num)-1), 0))
+#define DISABLE_SENSING_POINT	  (LVTS_SINGLE_SENSE | 0x0)
+#define LVTSMONCTL1_0		  0x004
+#define LVTSMONCTL2_0		  0x008
+#define LVTSMONINT_0		  0x00C
+#define STAGE3_INT_EN		  BIT(31)
+#define LVTSMONINTSTS_0		  0x010
+#define LVTSMONIDET0_0		  0x014
+#define LVTSMONIDET1_0		  0x018
+#define LVTSMONIDET2_0		  0x01C
+#define LVTSMONIDET3_0		  0x020
+#define LVTSH2NTHRE_0		  0x024
+#define LVTSHTHRE_0		  0x028
+#define LVTSCTHRE_0		  0x02C
+#define LVTSOFFSETH_0		  0x030
+#define LVTSOFFSETL_0		  0x034
+#define LVTSMSRCTL0_0		  0x038
+#define LVTSMSRCTL1_0		  0x03C
+#define LVTSTSSEL_0		  0x040
+#define SET_SENSOR_INDEX	  0x13121110
+#define LVTSDEVICETO_0		  0x044
+#define LVTSCALSCALE_0		  0x048
+#define SET_CALC_SCALE_RULES	  0x00000300
+#define LVTS_ID_0		  0x04C
+#define LVTS_CONFIG_0		  0x050
+
+#define BROADCAST_ID_UPDATE	  BIT(26)
+#define DEVICE_SENSING_STATUS	  BIT(25)
+#define DEVICE_ACCESS_STARTUS	  BIT(24)
+#define WRITE_ACCESS		  BIT(16)
+#define DEVICE_WRITE                                                           \
+	(BIT(31) | CK26M_ACTIVE | DEVICE_ACCESS_STARTUS | BIT(17) |            \
+	 WRITE_ACCESS)
+#define DEVICE_READ                                                            \
+	(BIT(31) | CK26M_ACTIVE | DEVICE_ACCESS_STARTUS | 1 << 17)
+#define RESET_ALL_DEVICES                                                      \
+	(DEVICE_WRITE | RG_TSFM_RST << 8 | 0xFF)
+#define READ_BACK_DEVICE_ID                                                    \
+	(BIT(31) | CK26M_ACTIVE | BROADCAST_ID_UPDATE |                        \
+	 DEVICE_ACCESS_STARTUS | BIT(17) | RG_DID_LVTS << 8)
+#define READ_DEVICE_REG(reg_idx) (DEVICE_READ | (reg_idx) << 8 | 0x00)
+#define LVTSEDATA00_0		 0x054
+#define LVTSEDATA01_0		 0x058
+#define LVTSEDATA02_0		 0x05C
+#define LVTSEDATA03_0		 0x060
+#define LVTSMSR0_0		 0x090
+#define MRS_RAW_MASK		 GENMASK(15, 0)
+#define MRS_RAW_VALID_BIT	 BIT(16)
+#define LVTSMSR1_0		 0x094
+#define LVTSMSR2_0		 0x098
+#define LVTSMSR3_0		 0x09C
+#define LVTSIMMD0_0		 0x0A0
+#define LVTSIMMD1_0		 0x0A4
+#define LVTSIMMD2_0		 0x0A8
+#define LVTSIMMD3_0		 0x0AC
+#define LVTSRDATA0_0		 0x0B0
+#define LVTSRDATA1_0		 0x0B4
+#define LVTSRDATA2_0		 0x0B8
+#define LVTSRDATA3_0		 0x0BC
+#define LVTSPROTCTL_0		 0x0C0
+#define PROTOFFSET		 GENMASK(15, 0)
+#define LVTSPROTTA_0		 0x0C4
+#define LVTSPROTTB_0		 0x0C8
+#define LVTSPROTTC_0		 0x0CC
+#define LVTSCLKEN_0		 0x0E4
+#define ENABLE_LVTS_CTRL_CLK	 (1)
+#define DISABLE_LVTS_CTRL_CLK	 (0)
+#define LVTSDBGSEL_0		 0x0E8
+#define LVTSDBGSIG_0		 0x0EC
+#define LVTSSPARE0_0		 0x0F0
+#define LVTSSPARE1_0		 0x0F4
+#define LVTSSPARE2_0		 0x0F8
+#define LVTSSPARE3_0		 0x0FC
+
+#define THERMINTST 0xF04
+/*
+ * LVTS register mask
+ */
+#define THERMAL_COLD_INTERRUPT_0	 0x00000001
+#define THERMAL_HOT_INTERRUPT_0		 0x00000002
+#define THERMAL_LOW_OFFSET_INTERRUPT_0	 0x00000004
+#define THERMAL_HIGH_OFFSET_INTERRUPT_0	 0x00000008
+#define THERMAL_HOT2NORMAL_INTERRUPT_0	 0x00000010
+#define THERMAL_COLD_INTERRUPT_1	 0x00000020
+#define THERMAL_HOT_INTERRUPT_1		 0x00000040
+#define THERMAL_LOW_OFFSET_INTERRUPT_1	 0x00000080
+#define THERMAL_HIGH_OFFSET_INTERRUPT_1	 0x00000100
+#define THERMAL_HOT2NORMAL_INTERRUPT_1	 0x00000200
+#define THERMAL_COLD_INTERRUPT_2	 0x00000400
+#define THERMAL_HOT_INTERRUPT_2		 0x00000800
+#define THERMAL_LOW_OFFSET_INTERRUPT_2	 0x00001000
+#define THERMAL_HIGH_OFFSET_INTERRUPT_2	 0x00002000
+#define THERMAL_HOT2NORMAL_INTERRUPT_2	 0x00004000
+#define THERMAL_AHB_TIMEOUT_INTERRUPT	 0x00008000
+#define THERMAL_DEVICE_TIMEOUT_INTERRUPT 0x00008000
+#define THERMAL_IMMEDIATE_INTERRUPT_0	 0x00010000
+#define THERMAL_IMMEDIATE_INTERRUPT_1	 0x00020000
+#define THERMAL_IMMEDIATE_INTERRUPT_2	 0x00040000
+#define THERMAL_FILTER_INTERRUPT_0	 0x00080000
+#define THERMAL_FILTER_INTERRUPT_1	 0x00100000
+#define THERMAL_FILTER_INTERRUPT_2	 0x00200000
+#define THERMAL_COLD_INTERRUPT_3	 0x00400000
+#define THERMAL_HOT_INTERRUPT_3		 0x00800000
+#define THERMAL_LOW_OFFSET_INTERRUPT_3	 0x01000000
+#define THERMAL_HIGH_OFFSET_INTERRUPT_3	 0x02000000
+#define THERMAL_HOT2NORMAL_INTERRUPT_3	 0x04000000
+#define THERMAL_IMMEDIATE_INTERRUPT_3	 0x08000000
+#define THERMAL_FILTER_INTERRUPT_3	 0x10000000
+#define THERMAL_PROTECTION_STAGE_1	 0x20000000
+#define THERMAL_PROTECTION_STAGE_2	 0x40000000
+#define THERMAL_PROTECTION_STAGE_3	 0x80000000
+#endif /* __MTK_SOC_TEMP_LVTS_H__ */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7988-clk.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7988-clk.h
new file mode 100644
index 0000000..fb97122
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/clock/mt7988-clk.h
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Xiufeng Li <Xiufeng.Li@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT7988_H
+#define _DT_BINDINGS_CLK_MT7988_H
+
+/* INFRACFG */
+
+#define CK_INFRA_CK_F26M		0
+#define CK_INFRA_PWM_O			1
+#define CK_INFRA_PCIE_OCC_P0		2
+#define CK_INFRA_PCIE_OCC_P1		3
+#define CK_INFRA_PCIE_OCC_P2		4
+#define CK_INFRA_PCIE_OCC_P3		5
+#define CK_INFRA_133M_HCK		6
+#define CK_INFRA_133M_PHCK		7
+#define CK_INFRA_66M_PHCK		8
+#define CK_INFRA_FAUD_L_O		9
+#define CK_INFRA_FAUD_AUD_O		10
+#define CK_INFRA_FAUD_EG2_O		11
+#define CK_INFRA_I2C_O			12
+#define CK_INFRA_UART_O0		13
+#define CK_INFRA_UART_O1		14
+#define CK_INFRA_UART_O2		15
+#define CK_INFRA_NFI_O			16
+#define CK_INFRA_SPINFI_O		17
+#define CK_INFRA_SPI0_O			18
+#define CK_INFRA_SPI1_O			19
+#define CK_INFRA_LB_MUX_FRTC		20
+#define CK_INFRA_FRTC			21
+#define CK_INFRA_FMSDC400_O		22
+#define CK_INFRA_FMSDC2_HCK_OCC		23
+#define CK_INFRA_PERI_133M		24
+#define CK_INFRA_USB_O			25
+#define CK_INFRA_USB_O_P1		26
+#define CK_INFRA_USB_FRMCNT_O		27
+#define CK_INFRA_USB_FRMCNT_O_P1	28
+#define CK_INFRA_USB_XHCI_O		29
+#define CK_INFRA_USB_XHCI_O_P1		30
+#define CK_INFRA_USB_PIPE_O		31
+#define CK_INFRA_USB_PIPE_O_P1		32
+#define CK_INFRA_USB_UTMI_O		33
+#define CK_INFRA_USB_UTMI_O_P1		34
+#define CK_INFRA_PCIE_PIPE_OCC_P0	35
+#define CK_INFRA_PCIE_PIPE_OCC_P1	36
+#define CK_INFRA_PCIE_PIPE_OCC_P2	37
+#define CK_INFRA_PCIE_PIPE_OCC_P3	38
+#define CK_INFRA_F26M_O0		39
+#define CK_INFRA_F26M_O1		40
+#define CK_INFRA_133M_MCK		41
+#define CK_INFRA_66M_MCK		42
+#define CK_INFRA_PERI_66M_O		43
+#define CK_INFRA_USB_SYS_O		44
+#define CK_INFRA_USB_SYS_O_P1		45
+#define CLK_INFRA_NR_CLK		46
+
+
+/* INFRACFG_AO */
+
+#define CK_INFRA_MUX_UART0_SEL		0
+#define CK_INFRA_MUX_UART1_SEL		1
+#define CK_INFRA_MUX_UART2_SEL		2
+#define CK_INFRA_MUX_SPI0_SEL		3
+#define CK_INFRA_MUX_SPI1_SEL		4
+#define CK_INFRA_MUX_SPI2_SEL		5
+#define CK_INFRA_PWM_SEL		6
+#define CK_INFRA_PWM_CK1_SEL		7
+#define CK_INFRA_PWM_CK2_SEL		8
+#define CK_INFRA_PWM_CK3_SEL		9
+#define CK_INFRA_PWM_CK4_SEL		10
+#define CK_INFRA_PWM_CK5_SEL		11
+#define CK_INFRA_PWM_CK6_SEL		12
+#define CK_INFRA_PWM_CK7_SEL		13
+#define CK_INFRA_PWM_CK8_SEL		14
+#define CK_INFRA_PCIE_GFMUX_TL_O_P0_SEL	15
+#define CK_INFRA_PCIE_GFMUX_TL_O_P1_SEL	16
+#define CK_INFRA_PCIE_GFMUX_TL_O_P2_SEL	17
+#define CK_INFRA_PCIE_GFMUX_TL_O_P3_SEL	18
+#define CK_INFRA_66M_GPT_BCK		19
+#define CK_INFRA_66M_PWM_HCK		20
+#define CK_INFRA_66M_PWM_BCK		21
+#define CK_INFRA_66M_PWM_CK1		22
+#define CK_INFRA_66M_PWM_CK2		23
+#define CK_INFRA_66M_PWM_CK3		24
+#define CK_INFRA_66M_PWM_CK4		25
+#define CK_INFRA_66M_PWM_CK5		26
+#define CK_INFRA_66M_PWM_CK6		27
+#define CK_INFRA_66M_PWM_CK7		28
+#define CK_INFRA_66M_PWM_CK8		29
+#define CK_INFRA_133M_CQDMA_BCK		30
+#define CK_INFRA_66M_AUD_SLV_BCK	31
+#define CK_INFRA_AUD_26M		32
+#define CK_INFRA_AUD_L			33
+#define CK_INFRA_AUD_AUD		34
+#define CK_INFRA_AUD_EG2		35
+#define CK_INFRA_DRAMC_F26M		36
+#define CK_INFRA_133M_DBG_ACKM		37
+#define CK_INFRA_66M_AP_DMA_BCK		38
+#define CK_INFRA_66M_SEJ_BCK		39
+#define CK_INFRA_PRE_CK_SEJ_F13M	40
+#define CK_INFRA_66M_TRNG		41
+#define CK_INFRA_26M_THERM_SYSTEM	42
+#define CK_INFRA_I2C_BCK		43
+#define CK_INFRA_66M_UART0_PCK		44
+#define CK_INFRA_66M_UART1_PCK		45
+#define CK_INFRA_66M_UART2_PCK		46
+#define CK_INFRA_52M_UART0_CK		47
+#define CK_INFRA_52M_UART1_CK		48
+#define CK_INFRA_52M_UART2_CK		49
+#define CK_INFRA_NFI			50
+#define CK_INFRA_SPINFI			51
+#define CK_INFRA_66M_NFI_HCK		52
+#define CK_INFRA_104M_SPI0		53
+#define CK_INFRA_104M_SPI1		54
+#define CK_INFRA_104M_SPI2_BCK		55
+#define CK_INFRA_66M_SPI0_HCK		56
+#define CK_INFRA_66M_SPI1_HCK		57
+#define CK_INFRA_66M_SPI2_HCK		58
+#define CK_INFRA_66M_FLASHIF_AXI	59
+#define CK_INFRA_RTC			60
+#define CK_INFRA_26M_ADC_BCK		61
+#define CK_INFRA_RC_ADC			62
+#define CK_INFRA_MSDC400		63
+#define CK_INFRA_MSDC2_HCK		64
+#define CK_INFRA_133M_MSDC_0_HCK	65
+#define CK_INFRA_66M_MSDC_0_HCK		66
+#define CK_INFRA_133M_CPUM_BCK		67
+#define CK_INFRA_BIST2FPC		68
+#define CK_INFRA_I2C_X16W_MCK_CK_P1	69
+#define CK_INFRA_I2C_X16W_PCK_CK_P1	70
+#define CK_INFRA_133M_USB_HCK		71
+#define CK_INFRA_133M_USB_HCK_CK_P1	72
+#define CK_INFRA_66M_USB_HCK		73
+#define CK_INFRA_66M_USB_HCK_CK_P1	74
+#define CK_INFRA_USB_SYS		75
+#define CK_INFRA_USB_SYS_CK_P1		76
+#define CK_INFRA_USB_REF		77
+#define CK_INFRA_USB_CK_P1		78
+#define CK_INFRA_USB_FRMCNT		79
+#define CK_INFRA_USB_FRMCNT_CK_P1	80
+#define CK_INFRA_USB_PIPE		81
+#define CK_INFRA_USB_PIPE_CK_P1		82
+#define CK_INFRA_USB_UTMI		83
+#define CK_INFRA_USB_UTMI_CK_P1		84
+#define CK_INFRA_USB_XHCI		85
+#define CK_INFRA_USB_XHCI_CK_P1		86
+#define CK_INFRA_PCIE_GFMUX_TL_P0	87
+#define CK_INFRA_PCIE_GFMUX_TL_P1	88
+#define CK_INFRA_PCIE_GFMUX_TL_P2	89
+#define CK_INFRA_PCIE_GFMUX_TL_P3	90
+#define CK_INFRA_PCIE_PIPE_P0		91
+#define CK_INFRA_PCIE_PIPE_P1		92
+#define CK_INFRA_PCIE_PIPE_P2		93
+#define CK_INFRA_PCIE_PIPE_P3		94
+#define CK_INFRA_133M_PCIE_CK_P0	95
+#define CK_INFRA_133M_PCIE_CK_P1	96
+#define CK_INFRA_133M_PCIE_CK_P2	97
+#define CK_INFRA_133M_PCIE_CK_P3	98
+#define CK_INFRA_PCIE_PERI_26M_CK_P0	99
+#define CK_INFRA_PCIE_PERI_26M_CK_P1	100
+#define CK_INFRA_PCIE_PERI_26M_CK_P2	101
+#define CK_INFRA_PCIE_PERI_26M_CK_P3	102
+#define CLK_INFRA_AO_NR_CLK		103
+
+/* TOPCKGEN */
+
+#define CK_TOP_NETSYS_SEL		0
+#define CK_TOP_NETSYS_500M_SEL		1
+#define CK_TOP_NETSYS_2X_SEL		2
+#define CK_TOP_NETSYS_GSW_SEL		3
+#define CK_TOP_ETH_GMII_SEL		4
+#define CK_TOP_NETSYS_MCU_SEL		5
+#define CK_TOP_NETSYS_PAO_2X_SEL	6
+#define CK_TOP_EIP197_SEL		7
+#define CK_TOP_AXI_INFRA_SEL		8
+#define CK_TOP_UART_SEL			9
+#define CK_TOP_EMMC_250M_SEL		10
+#define CK_TOP_EMMC_400M_SEL		11
+#define CK_TOP_SPI_SEL			12
+#define CK_TOP_SPIM_MST_SEL		13
+#define CK_TOP_NFI1X_SEL		14
+#define CK_TOP_SPINFI_SEL		15
+#define CK_TOP_PWM_SEL			16
+#define CK_TOP_I2C_SEL			17
+#define CK_TOP_PCIE_MBIST_250M_SEL	18
+#define CK_TOP_PEXTP_TL_SEL		19
+#define CK_TOP_PEXTP_TL_P1_SEL		20
+#define CK_TOP_PEXTP_TL_P2_SEL		21
+#define CK_TOP_PEXTP_TL_P3_SEL		22
+#define CK_TOP_USB_SYS_SEL		23
+#define CK_TOP_USB_SYS_P1_SEL		24
+#define CK_TOP_USB_XHCI_SEL		25
+#define CK_TOP_USB_XHCI_P1_SEL		26
+#define CK_TOP_USB_FRMCNT_SEL		27
+#define CK_TOP_USB_FRMCNT_P1_SEL	28
+#define CK_TOP_AUD_SEL			29
+#define CK_TOP_A1SYS_SEL		30
+#define CK_TOP_AUD_L_SEL		31
+#define CK_TOP_A_TUNER_SEL		32
+#define CK_TOP_SSPXTP_SEL		33
+#define CK_TOP_USB_PHY_SEL		34
+#define CK_TOP_USXGMII_SBUS_0_SEL	35
+#define CK_TOP_USXGMII_SBUS_1_SEL	36
+#define CK_TOP_SGM_0_SEL		37
+#define CK_TOP_SGM_SBUS_0_SEL		38
+#define CK_TOP_SGM_1_SEL		39
+#define CK_TOP_SGM_SBUS_1_SEL		40
+#define CK_TOP_XFI_PHY_0_XTAL_SEL	41
+#define CK_TOP_XFI_PHY_1_XTAL_SEL	42
+#define CK_TOP_SYSAXI_SEL		43
+#define CK_TOP_SYSAPB_SEL		44
+#define CK_TOP_ETH_REFCK_50M_SEL	45
+#define CK_TOP_ETH_SYS_200M_SEL		46
+#define CK_TOP_ETH_SYS_SEL		47
+#define CK_TOP_ETH_XGMII_SEL		48
+#define CK_TOP_BUS_TOPS_SEL		49
+#define CK_TOP_NPU_TOPS_SEL		50
+#define CK_TOP_DRAMC_SEL		51
+#define CK_TOP_DRAMC_MD32_SEL		52
+#define CK_TOP_INFRA_F26M_SEL		53
+#define CK_TOP_PEXTP_P0_SEL		54
+#define CK_TOP_PEXTP_P1_SEL		55
+#define CK_TOP_PEXTP_P2_SEL		56
+#define CK_TOP_PEXTP_P3_SEL		57
+#define CK_TOP_DA_XTP_GLB_P0_SEL	58
+#define CK_TOP_DA_XTP_GLB_P1_SEL	59
+#define CK_TOP_DA_XTP_GLB_P2_SEL	60
+#define CK_TOP_DA_XTP_GLB_P3_SEL	61
+#define CK_TOP_CKM_SEL			62
+#define CK_TOP_DA_SELM_XTAL_SEL		63
+#define CK_TOP_PEXTP_SEL		64
+#define CK_TOP_TOPS_P2_26M_SEL		65
+#define CK_TOP_MCUSYS_BACKUP_625M_SEL	66
+#define CK_TOP_NETSYS_SYNC_250M_SEL	67
+#define CK_TOP_MACSEC_SEL		68
+#define CK_TOP_NETSYS_TOPS_400M_SEL	69
+#define CK_TOP_NETSYS_PPEFB_250M_SEL	70
+#define CK_TOP_NETSYS_WARP_SEL		71
+#define CK_TOP_ETH_MII_SEL		72
+#define CK_TOP_CK_NPU_SEL_CM_TOPS_SEL	73
+#define CK_TOP_CB_CKSQ_40M		74
+#define CK_TOP_CB_M_416M		75
+#define CK_TOP_CB_M_D2			76
+#define CK_TOP_M_D3_D2			77
+#define CK_TOP_CB_M_D4			78
+#define CK_TOP_CB_M_D8			79
+#define CK_TOP_M_D8_D2			80
+#define CK_TOP_CB_MM_720M		81
+#define CK_TOP_CB_MM_D2			82
+#define CK_TOP_CB_MM_D3_D5		83
+#define CK_TOP_CB_MM_D4			84
+#define CK_TOP_MM_D6_D2			85
+#define CK_TOP_CB_MM_D8			86
+#define CK_TOP_CB_APLL2_196M		87
+#define CK_TOP_CB_APLL2_D4		88
+#define CK_TOP_CB_NET1_D4		89
+#define CK_TOP_CB_NET1_D5		90
+#define CK_TOP_NET1_D5_D2		91
+#define CK_TOP_NET1_D5_D4		92
+#define CK_TOP_CB_NET1_D8		93
+#define CK_TOP_NET1_D8_D2		94
+#define CK_TOP_NET1_D8_D4		95
+#define CK_TOP_NET1_D8_D8		96
+#define CK_TOP_NET1_D8_D16		97
+#define CK_TOP_CB_NET2_800M		98
+#define CK_TOP_CB_NET2_D2		99
+#define CK_TOP_CB_NET2_D4		100
+#define CK_TOP_NET2_D4_D4		101
+#define CK_TOP_NET2_D4_D8		102
+#define CK_TOP_CB_NET2_D6		103
+#define CK_TOP_CB_NET2_D8		104
+#define CK_TOP_CB_WEDMCU_208M		105
+#define CK_TOP_CB_SGM_325M		106
+#define CK_TOP_CB_NETSYS_850M		107
+#define CK_TOP_CB_MSDC_400M		108
+#define CK_TOP_CKSQ_40M_D2		109
+#define CK_TOP_CB_RTC_32K		110
+#define CK_TOP_CB_RTC_32P7K		111
+#define CK_TOP_INFRA_F32K		112
+#define CK_TOP_CKSQ_SRC			113
+#define CK_TOP_NETSYS_2X		114
+#define CK_TOP_NETSYS_GSW		115
+#define CK_TOP_NETSYS_WED_MCU		116
+#define CK_TOP_EIP197			117
+#define CK_TOP_EMMC_250M		118
+#define CK_TOP_EMMC_400M		119
+#define CK_TOP_SPI			120
+#define CK_TOP_SPIM_MST			121
+#define CK_TOP_NFI1X			122
+#define CK_TOP_SPINFI_BCK		123
+#define CK_TOP_I2C_BCK			124
+#define CK_TOP_USB_SYS			125
+#define CK_TOP_USB_SYS_P1		126
+#define CK_TOP_USB_XHCI			127
+#define CK_TOP_USB_XHCI_P1		128
+#define CK_TOP_USB_FRMCNT		129
+#define CK_TOP_USB_FRMCNT_P1		130
+#define CK_TOP_AUD			131
+#define CK_TOP_A1SYS			132
+#define CK_TOP_AUD_L			133
+#define CK_TOP_A_TUNER			134
+#define CK_TOP_SYSAXI			135
+#define CK_TOP_INFRA_F26M		136
+#define CK_TOP_USB_REF			137
+#define CK_TOP_USB_CK_P1		138
+#define CK_TOP_AUD_I2S_M		139
+#define CLK_TOP_NR_CLK			140
+
+/* APMIXEDSYS */
+
+#define CK_APMIXED_NETSYSPLL		0
+#define CK_APMIXED_MPLL			1
+#define CK_APMIXED_MMPLL		2
+#define CK_APMIXED_APLL2		3
+#define CK_APMIXED_NET1PLL		4
+#define CK_APMIXED_NET2PLL		5
+#define CK_APMIXED_WEDMCUPLL		6
+#define CK_APMIXED_SGMPLL		7
+#define CK_APMIXED_ARM_B		8
+#define CK_APMIXED_CCIPLL2_B		9
+#define CK_APMIXED_USXGMIIPLL		10
+#define CK_APMIXED_MSDCPLL		11
+#define CLK_APMIXED_NR_CLK		12
+
+/* MCUSYS */
+
+#define CK_MCU_BUS_DIV_SEL		0
+#define CK_MCU_ARM_DIV_SEL		1
+#define CLK_MCU_NR_CLK			2
+
+/* ETHDMA */
+
+#define CK_ETHDMA_XGP1_EN		0
+#define CK_ETHDMA_XGP2_EN		1
+#define CK_ETHDMA_XGP3_EN		2
+#define CK_ETHDMA_FE_EN			3
+#define CK_ETHDMA_GP2_EN		4
+#define CK_ETHDMA_GP1_EN		5
+#define CK_ETHDMA_GP3_EN		6
+#define CK_ETHDMA_ESW_EN		7
+#define CK_ETHDMA_CRYPT0_EN		8
+#define CLK_ETHDMA_NR_CLK		9
+/* SGMIISYS_0 */
+
+#define CK_SGM0_TX_EN			0
+#define CK_SGM0_RX_EN			1
+#define CLK_SGMII0_NR_CLK		2
+
+/* SGMIISYS_1 */
+
+#define CK_SGM1_TX_EN			0
+#define CK_SGM1_RX_EN			1
+#define CLK_SGMII1_NR_CLK		2
+
+/* ETHWARP */
+
+#define CK_ETHWARP_WOCPU2_EN		0
+#define CK_ETHWARP_WOCPU1_EN		1
+#define CK_ETHWARP_WOCPU0_EN		2
+#define CLK_ETHWARP_NR_CLK		3
+
+#endif /* _DT_BINDINGS_CLK_MT7988_H */
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/power/mt7988-power.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/power/mt7988-power.h
new file mode 100644
index 0000000..ff1100a
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/power/mt7988-power.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ *
+ */
+
+#ifndef _DT_BINDINGS_POWER_MT7988_POWER_H
+#define _DT_BINDINGS_POWER_MT7988_POWER_H
+
+#define MT7988_POWER_DOMAIN_TOPS0			0
+#define MT7988_POWER_DOMAIN_TOPS1			1
+#define MT7988_POWER_DOMAIN_ETH2P5			2
+
+
+#endif /* _DT_BINDINGS_POWER_MT7988_POWER_H */
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/regulator/richtek,rt5190a-regulator.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/regulator/richtek,rt5190a-regulator.h
new file mode 100644
index 0000000..63f99d4
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/include/dt-bindings/regulator/richtek,rt5190a-regulator.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __DT_BINDINGS_RICHTEK_RT5190A_REGULATOR_H__
+#define __DT_BINDINGS_RICHTEK_RT5190A_REGULATOR_H__
+
+/*
+ * BUCK/LDO mode constants which may be used in devicetree properties
+ * (eg. regulator-allowed-modes).
+ * See the manufacturer's datasheet for more information on these modes.
+ */
+
+#define RT5190A_OPMODE_AUTO	0
+#define RT5190A_OPMODE_FPWM	1
+
+#endif
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-cpufreq-add-the-missing-platform-driver-unregister.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-cpufreq-add-the-missing-platform-driver-unregister.patch
new file mode 100644
index 0000000..fdf953d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0001-cpufreq-add-the-missing-platform-driver-unregister.patch
@@ -0,0 +1,12 @@
+diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
+index 927ebc5..03bb7b5 100644
+--- a/drivers/cpufreq/mediatek-cpufreq.c
++++ b/drivers/cpufreq/mediatek-cpufreq.c
+@@ -573,6 +573,7 @@ static int __init mtk_cpufreq_driver_init(void)
+ 	pdev = platform_device_register_simple("mtk-cpufreq", -1, NULL, 0);
+ 	if (IS_ERR(pdev)) {
+ 		pr_err("failed to register mtk-cpufreq platform device\n");
++		platform_driver_unregister(&mtk_cpufreq_platdrv);
+ 		return PTR_ERR(pdev);
+ 	}
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-cpufreq-Enable-clocks-and-regulators.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-cpufreq-Enable-clocks-and-regulators.patch
new file mode 100644
index 0000000..2fa9359
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0002-cpufreq-Enable-clocks-and-regulators.patch
@@ -0,0 +1,88 @@
+diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
+index 03bb7b5..010a947 100644
+--- a/drivers/cpufreq/mediatek-cpufreq.c
++++ b/drivers/cpufreq/mediatek-cpufreq.c
+@@ -351,6 +351,12 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ 		goto out_free_resources;
+ 	}
+ 
++	ret = regulator_enable(proc_reg);
++	if (ret) {
++		dev_warn(cpu_dev, "cpu%d: failed to enable vproc\n", cpu);
++		goto out_free_resources;
++	}
++
+ 	/* Both presence and absence of sram regulator are valid cases. */
+ 	sram_reg = regulator_get_exclusive(cpu_dev, "sram");
+ 
+@@ -368,13 +374,21 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ 		goto out_free_resources;
+ 	}
+ 
++	ret = clk_prepare_enable(cpu_clk);
++	if (ret)
++		goto out_free_opp_table;
++
++	ret = clk_prepare_enable(inter_clk);
++	if (ret)
++		goto out_disable_mux_clock;
++
+ 	/* Search a safe voltage for intermediate frequency. */
+ 	rate = clk_get_rate(inter_clk);
+ 	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
+ 	if (IS_ERR(opp)) {
+ 		pr_err("failed to get intermediate opp for cpu%d\n", cpu);
+ 		ret = PTR_ERR(opp);
+-		goto out_free_opp_table;
++		goto out_disable_inter_clock;
+ 	}
+ 	info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
+ 	dev_pm_opp_put(opp);
+@@ -393,10 +407,23 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ 
+ 	return 0;
+ 
++out_disable_inter_clock:
++	if(!IS_ERR(inter_clk))
++		clk_disable_unprepare(inter_clk);
++
++out_disable_mux_clock:
++	if(!IS_ERR(cpu_clk))
++		clk_disable_unprepare(cpu_clk);
++
+ out_free_opp_table:
+ 	dev_pm_opp_of_cpumask_remove_table(&info->cpus);
+ 
+ out_free_resources:
++	if (!IS_ERR(proc_reg)) {
++		if (regulator_is_enabled(proc_reg))
++			regulator_disable(proc_reg);
++	}
++
+ 	if (!IS_ERR(proc_reg))
+ 		regulator_put(proc_reg);
+ 	if (!IS_ERR(sram_reg))
+@@ -411,14 +438,20 @@ out_free_resources:
+ 
+ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
+ {
+-	if (!IS_ERR(info->proc_reg))
++	if (!IS_ERR(info->proc_reg)){
++		regulator_disable(info->proc_reg);
+ 		regulator_put(info->proc_reg);
++	}
+ 	if (!IS_ERR(info->sram_reg))
+ 		regulator_put(info->sram_reg);
+-	if (!IS_ERR(info->cpu_clk))
++	if (!IS_ERR(info->cpu_clk)){
++		clk_disable_unprepare(info->cpu_clk);
+ 		clk_put(info->cpu_clk);
+-	if (!IS_ERR(info->inter_clk))
++	}
++	if (!IS_ERR(info->inter_clk)){
++		clk_disable_unprepare(info->inter_clk);
+ 		clk_put(info->inter_clk);
++	}
+ 
+ 	dev_pm_opp_of_cpumask_remove_table(&info->cpus);
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-clk-mtk-add-mt7988-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-clk-mtk-add-mt7988-support.patch
new file mode 100644
index 0000000..e673148
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-clk-mtk-add-mt7988-support.patch
@@ -0,0 +1,38 @@
+diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
+index 23393d5..cf3a53e 100644
+--- a/drivers/clk/mediatek/Kconfig
++++ b/drivers/clk/mediatek/Kconfig
+@@ -275,6 +275,14 @@ config COMMON_CLK_MT7981
+ 	  This driver supports MediaTek MT7981 basic clocks and clocks
+ 	  required for various periperals found on MediaTek.
+ 
++config COMMON_CLK_MT7988
++	bool "Clock driver for MediaTek MT7988"
++	depends on ARCH_MEDIATEK || COMPILE_TEST
++	select COMMON_CLK_MEDIATEK
++	---help---
++	  This driver supports MediaTek MT7988 basic clocks and clocks
++	  required for various periperals found on MediaTek.
++
+ config COMMON_CLK_MT8135
+ 	bool "Clock driver for MediaTek MT8135"
+ 	depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
+diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
+index ffe0850..43ca85d 100644
+--- a/drivers/clk/mediatek/Makefile
++++ b/drivers/clk/mediatek/Makefile
+@@ -41,6 +41,7 @@ obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o
+ obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o
+ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986.o
+ obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981.o
++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988.o
+ obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
+ obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o
+ obj-$(CONFIG_COMMON_CLK_MT8183) += clk-mt8183.o
+@@ -57,4 +58,4 @@ obj-$(CONFIG_COMMON_CLK_MT8183_VDECSYS) += clk-mt8183-vdec.o
+ obj-$(CONFIG_COMMON_CLK_MT8183_VENCSYS) += clk-mt8183-venc.o
+ obj-$(CONFIG_COMMON_CLK_MT8516) += clk-mt8516.o
+ obj-$(CONFIG_COMMON_CLK_MT8516_AUDSYS) += clk-mt8516-aud.o
+-obj-y += clk-bringup.o
+\ No newline at end of file
++obj-y += clk-bringup.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-cpufreq-add-mt7988a-spim-snand-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-cpufreq-add-mt7988a-spim-snand-support.patch
new file mode 100644
index 0000000..ee87f4e
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0003-cpufreq-add-mt7988a-spim-snand-support.patch
@@ -0,0 +1,212 @@
+diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
+index 010a947..291f629 100644
+--- a/drivers/cpufreq/mediatek-cpufreq.c
++++ b/drivers/cpufreq/mediatek-cpufreq.c
+@@ -38,6 +38,7 @@ struct mtk_cpu_dvfs_info {
+ 	struct regulator *proc_reg;
+ 	struct regulator *sram_reg;
+ 	struct clk *cpu_clk;
++	struct clk *cci_clk;
+ 	struct clk *inter_clk;
+ 	struct list_head list_head;
+ 	int intermediate_voltage;
+@@ -205,15 +206,24 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
+ 	struct cpufreq_frequency_table *freq_table = policy->freq_table;
+ 	struct clk *cpu_clk = policy->clk;
+ 	struct clk *armpll = clk_get_parent(cpu_clk);
++	struct clk *cci_clk = ERR_PTR(-ENODEV);
++	struct clk *ccipll;
+ 	struct mtk_cpu_dvfs_info *info = policy->driver_data;
+ 	struct device *cpu_dev = info->cpu_dev;
+ 	struct dev_pm_opp *opp;
+-	long freq_hz, old_freq_hz;
++	long freq_hz, old_freq_hz, cci_freq_hz, cci_old_freq_hz;
+ 	int vproc, old_vproc, inter_vproc, target_vproc, ret;
+ 
+ 	inter_vproc = info->intermediate_voltage;
+ 
+ 	old_freq_hz = clk_get_rate(cpu_clk);
++
++	if (!IS_ERR(info->cci_clk)) {
++		cci_clk = info->cci_clk;
++		ccipll = clk_get_parent(cci_clk);
++		cci_old_freq_hz = clk_get_rate(cci_clk);
++	}
++
+ 	old_vproc = regulator_get_voltage(info->proc_reg);
+ 	if (old_vproc < 0) {
+ 		pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc);
+@@ -221,6 +231,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
+ 	}
+ 
+ 	freq_hz = freq_table[index].frequency * 1000;
++	cci_freq_hz = freq_table[index].frequency * 600;
+ 
+ 	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
+ 	if (IS_ERR(opp)) {
+@@ -246,6 +257,18 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
+ 		}
+ 	}
+ 
++	/* Reparent the CCI clock to intermediate clock. */
++	if (!IS_ERR(cci_clk)) {
++		ret = clk_set_parent(cci_clk, info->inter_clk);
++		if (ret) {
++			pr_err("cpu%d: failed to re-parent cci clock!\n",
++			       policy->cpu);
++			mtk_cpufreq_set_voltage(info, old_vproc);
++			WARN_ON(1);
++			return ret;
++		}
++	}
++
+ 	/* Reparent the CPU clock to intermediate clock. */
+ 	ret = clk_set_parent(cpu_clk, info->inter_clk);
+ 	if (ret) {
+@@ -266,6 +289,18 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
+ 		return ret;
+ 	}
+ 
++	/* Set the original PLL to target rate. */
++	if (!IS_ERR(cci_clk)) {
++		ret = clk_set_rate(ccipll, cci_freq_hz);
++		if (ret) {
++			pr_err("cpu%d: failed to scale cci clock rate!\n",
++			       policy->cpu);
++			clk_set_parent(cci_clk, ccipll);
++			mtk_cpufreq_set_voltage(info, old_vproc);
++			return ret;
++		}
++	}
++
+ 	/* Set parent of CPU clock back to the original PLL. */
+ 	ret = clk_set_parent(cpu_clk, armpll);
+ 	if (ret) {
+@@ -276,6 +311,17 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
+ 		return ret;
+ 	}
+ 
++	/* Set parent of CCI clock back to the original PLL. */
++	if (!IS_ERR(cci_clk)) {
++		ret = clk_set_parent(cci_clk, ccipll);
++		if (ret) {
++			pr_err("cpu%d: failed to re-parent cci clock!\n",
++			       policy->cpu);
++			mtk_cpufreq_set_voltage(info, inter_vproc);
++			WARN_ON(1);
++			return ret;
++		}
++	}
+ 	/*
+ 	 * If the new voltage is lower than the intermediate voltage or the
+ 	 * original voltage, scale down to the new voltage.
+@@ -285,9 +331,20 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
+ 		if (ret) {
+ 			pr_err("cpu%d: failed to scale down voltage!\n",
+ 			       policy->cpu);
++			if (!IS_ERR(cci_clk))
++				clk_set_parent(cci_clk, info->inter_clk);
++
+ 			clk_set_parent(cpu_clk, info->inter_clk);
+ 			clk_set_rate(armpll, old_freq_hz);
++
++			if (!IS_ERR(cci_clk))
++				clk_set_rate(ccipll, cci_old_freq_hz);
++
+ 			clk_set_parent(cpu_clk, armpll);
++
++			if (!IS_ERR(cci_clk))
++				clk_set_parent(cci_clk, ccipll);
++
+ 			return ret;
+ 		}
+ 	}
+@@ -303,6 +360,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ 	struct regulator *proc_reg = ERR_PTR(-ENODEV);
+ 	struct regulator *sram_reg = ERR_PTR(-ENODEV);
+ 	struct clk *cpu_clk = ERR_PTR(-ENODEV);
++	struct clk *cci_clk = ERR_PTR(-ENODEV);
+ 	struct clk *inter_clk = ERR_PTR(-ENODEV);
+ 	struct dev_pm_opp *opp;
+ 	unsigned long rate;
+@@ -338,6 +396,8 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ 		goto out_free_resources;
+ 	}
+ 
++	cci_clk = clk_get(cpu_dev, "cci");
++
+ 	proc_reg = regulator_get_optional(cpu_dev, "proc");
+ 	if (IS_ERR(proc_reg)) {
+ 		if (PTR_ERR(proc_reg) == -EPROBE_DEFER)
+@@ -379,16 +439,23 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ 		goto out_free_opp_table;
+ 
+ 	ret = clk_prepare_enable(inter_clk);
++
+ 	if (ret)
+ 		goto out_disable_mux_clock;
+ 
++	if(!(IS_ERR(cci_clk))) {
++		ret = clk_prepare_enable(cci_clk);
++		if(ret)
++			goto out_disable_inter_clock;
++	}
++
+ 	/* Search a safe voltage for intermediate frequency. */
+ 	rate = clk_get_rate(inter_clk);
+ 	opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
+ 	if (IS_ERR(opp)) {
+ 		pr_err("failed to get intermediate opp for cpu%d\n", cpu);
+ 		ret = PTR_ERR(opp);
+-		goto out_disable_inter_clock;
++		goto out_disable_cci_clock;
+ 	}
+ 	info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
+ 	dev_pm_opp_put(opp);
+@@ -397,6 +464,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ 	info->proc_reg = proc_reg;
+ 	info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg;
+ 	info->cpu_clk = cpu_clk;
++	info->cci_clk = cci_clk;
+ 	info->inter_clk = inter_clk;
+ 
+ 	/*
+@@ -407,6 +475,10 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
+ 
+ 	return 0;
+ 
++out_disable_cci_clock:
++	if(!IS_ERR(cci_clk))
++		clk_disable_unprepare(cci_clk);
++
+ out_disable_inter_clock:
+ 	if(!IS_ERR(inter_clk))
+ 		clk_disable_unprepare(inter_clk);
+@@ -432,6 +504,8 @@ out_free_resources:
+ 		clk_put(cpu_clk);
+ 	if (!IS_ERR(inter_clk))
+ 		clk_put(inter_clk);
++	if (!IS_ERR(cci_clk))
++		clk_put(cci_clk);
+ 
+ 	return ret;
+ }
+@@ -452,6 +526,10 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
+ 		clk_disable_unprepare(info->inter_clk);
+ 		clk_put(info->inter_clk);
+ 	}
++	if (!IS_ERR(info->cci_clk)){
++		clk_disable_unprepare(info->cci_clk);
++		clk_put(info->cci_clk);
++	}
+ 
+ 	dev_pm_opp_of_cpumask_remove_table(&info->cpus);
+ }
+@@ -570,6 +648,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
+ 	{ .compatible = "mediatek,mt8176", },
+ 	{ .compatible = "mediatek,mt8183", },
+ 	{ .compatible = "mediatek,mt8516", },
++	{ .compatible = "mediatek,mt7988", },
+ 
+ 	{ }
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-clk-mtk-add-chg-shift-control.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-clk-mtk-add-chg-shift-control.patch
new file mode 100644
index 0000000..4a9ff6f
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0005-clk-mtk-add-chg-shift-control.patch
@@ -0,0 +1,28 @@
+diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
+index c3d6756..d84c45d 100644
+--- a/drivers/clk/mediatek/clk-mtk.h
++++ b/drivers/clk/mediatek/clk-mtk.h
+@@ -231,6 +231,7 @@ struct mtk_pll_data {
+ 	uint32_t pcw_reg;
+ 	int pcw_shift;
+ 	uint32_t pcw_chg_reg;
++	int pcw_chg_shift;
+ 	const struct mtk_pll_div_table *div_table;
+ 	const char *parent_name;
+ };
+diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
+index f440f2c..db318fe 100644
+--- a/drivers/clk/mediatek/clk-pll.c
++++ b/drivers/clk/mediatek/clk-pll.c
+@@ -136,7 +136,10 @@ static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
+ 			pll->data->pcw_shift);
+ 	val |= pcw << pll->data->pcw_shift;
+ 	writel(val, pll->pcw_addr);
+-	chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK;
++	if (pll->data->pcw_chg_shift)
++		chg = readl(pll->pcw_chg_addr) | BIT(pll->data->pcw_chg_shift);
++	else
++		chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK;
+ 	writel(chg, pll->pcw_chg_addr);
+ 	if (pll->tuner_addr)
+ 		writel(val + 1, pll->tuner_addr);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-powerdomain-add-mt7988-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-powerdomain-add-mt7988-support.patch
new file mode 100644
index 0000000..7fc4f1d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0006-powerdomain-add-mt7988-support.patch
@@ -0,0 +1,9 @@
+diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
+index b017330..1c485e3 100644
+--- a/drivers/soc/mediatek/Makefile
++++ b/drivers/soc/mediatek/Makefile
+@@ -3,3 +3,4 @@ obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
+ obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
+ obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
+ obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
++obj-$(CONFIG_MTK_SCPSYS) += mtk-pm-domains.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch
new file mode 100644
index 0000000..8e99118
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0007-cpufreq-mtk-vbining-add-mt7988-support.patch
@@ -0,0 +1,47 @@
+diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
+index b23b6d2..147a224 100644
+--- a/drivers/cpufreq/mediatek-cpufreq.c
++++ b/drivers/cpufreq/mediatek-cpufreq.c
+@@ -15,6 +15,7 @@
+ #include <linux/regulator/consumer.h>
+ #include <linux/slab.h>
+ #include <linux/thermal.h>
++#include <linux/nvmem-consumer.h>
+ 
+ #define MIN_VOLT_SHIFT		(100000)
+ #define MAX_VOLT_SHIFT		(200000)
+@@ -539,6 +540,11 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy)
+ 	struct mtk_cpu_dvfs_info *info;
+ 	struct cpufreq_frequency_table *freq_table;
+ 	int ret;
++	int target_vproc;
++	u32 reg_val;
++	struct nvmem_cell *cell;
++	size_t len;
++	u32 *buf;
+ 
+ 	info = mtk_cpu_dvfs_info_lookup(policy->cpu);
+ 	if (!info) {
+@@ -547,6 +553,22 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy)
+ 		return -EINVAL;
+ 	}
+ 
++	cell = nvmem_cell_get(info->cpu_dev, "calibration-data");
++	if (!IS_ERR(cell)) {
++		buf = (u32 *)nvmem_cell_read(cell, &len);
++		nvmem_cell_put(cell);
++		if (!IS_ERR(buf)) {
++			reg_val = buf[0] & 0x1f;
++			pr_debug("%s: read vbinning value: %d\n", __func__, reg_val);
++			if (reg_val > 0) {
++				target_vproc = 850000 + reg_val * 10000;
++				dev_pm_opp_remove(info->cpu_dev, 1800000000);
++				dev_pm_opp_add(info->cpu_dev, 1800000000, target_vproc);
++			}
++			kfree(buf);
++		}
++	}
++
+ 	ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
+ 	if (ret) {
+ 		pr_err("failed to init cpufreq table for cpu%d: %d\n",
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0505-crypto-add-eip197-inside-secure-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0505-crypto-add-eip197-inside-secure-support.patch
index ed30817..eff209b 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0505-crypto-add-eip197-inside-secure-support.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0505-crypto-add-eip197-inside-secure-support.patch
@@ -12,7 +12,14 @@
  	}
  
  }
-@@ -409,7 +414,7 @@
+@@ -403,13 +408,13 @@
+ 	const struct firmware *fw[FW_NB];
+ 	char fw_path[37], *dir = NULL;
+ 	int i, j, ret = 0, pe;
+-	int ipuesz, ifppsz, minifw = 0;
++	int ipuesz, ifppsz, minifw = 1;
+ 
+ 	if (priv->version == EIP197D_MRVL)
  		dir = "eip197d";
  	else if (priv->version == EIP197B_MRVL ||
  		 priv->version == EIP197_DEVBRD)
@@ -21,7 +28,19 @@
  	else
  		return -ENODEV;
  
-@@ -792,6 +797,12 @@
+@@ -592,6 +597,11 @@
+ 	 */
+ 	if (priv->flags & SAFEXCEL_HW_EIP197) {
+ 		val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
++		/* Clear axi_burst_size and rx_burst_size */
++		val &= 0xffffff00;
++		/* Set axi_burst_size = 3, rx_burst_size = 3 */
++		val |= EIP197_MST_CTRL_RD_CACHE(3);
++		val |= EIP197_MST_CTRL_WD_CACHE(3);
+ 		val |= EIP197_MST_CTRL_TX_MAX_CMD(5);
+ 		writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
+ 	}
+@@ -792,6 +802,12 @@
  			return ret;
  	}
  
@@ -34,7 +53,7 @@
  	return safexcel_hw_setup_cdesc_rings(priv) ?:
  	       safexcel_hw_setup_rdesc_rings(priv) ?:
  	       0;
-@@ -1498,6 +1509,9 @@
+@@ -1498,6 +1514,9 @@
  	hwopt = readl(EIP197_GLOBAL(priv) + EIP197_OPTIONS);
  	hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS);
  
@@ -44,7 +63,7 @@
  	if (priv->flags & SAFEXCEL_HW_EIP197) {
  		/* EIP197 */
  		peopt = readl(EIP197_PE(priv) + EIP197_PE_OPTIONS(0));
-@@ -1516,8 +1530,37 @@
+@@ -1516,8 +1535,37 @@
  					    EIP197_N_RINGS_MASK;
  		if (hiaopt & EIP197_HIA_OPT_HAS_PE_ARB)
  			priv->flags |= EIP197_PE_ARB;
@@ -83,7 +102,7 @@
  		/* If not a full TRC, then assume simple TRC */
  		if (!(hwopt & EIP197_OPT_HAS_TRC))
  			priv->flags |= EIP197_SIMPLE_TRC;
-@@ -1555,13 +1598,14 @@
+@@ -1555,13 +1603,14 @@
  				    EIP197_PE_EIP96_OPTIONS(0));
  
  	/* Print single info line describing what we just detected */
@@ -100,7 +119,7 @@
  
  	safexcel_configure(priv);
  
-@@ -1690,6 +1734,7 @@
+@@ -1690,6 +1739,7 @@
  {
  	struct device *dev = &pdev->dev;
  	struct safexcel_crypto_priv *priv;
@@ -108,7 +127,7 @@
  	int ret;
  
  	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-@@ -1701,7 +1746,11 @@
+@@ -1701,7 +1751,11 @@
  
  	platform_set_drvdata(pdev, priv);
  
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0932-add-pwm-feature-in-mt7988-project.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0932-add-pwm-feature-in-mt7988-project.patch
new file mode 100644
index 0000000..8268e7d
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0932-add-pwm-feature-in-mt7988-project.patch
@@ -0,0 +1,25 @@
+diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
+index 3a5a456..6d6206e 100644
+--- a/drivers/pwm/pwm-mediatek.c
++++ b/drivers/pwm/pwm-mediatek.c
+@@ -350,6 +350,12 @@ static const struct pwm_mediatek_of_data mt7986_pwm_data = {
+ 	.reg_ver = REG_V2,
+ };
+ 
++static const struct pwm_mediatek_of_data mt7988_pwm_data = {
++	.num_pwms = 8,
++	.pwm45_fixup = false,
++	.reg_ver = REG_V2,
++};
++
+ static const struct pwm_mediatek_of_data mt8516_pwm_data = {
+ 	.num_pwms = 5,
+ 	.pwm45_fixup = false,
+@@ -364,6 +370,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = {
+ 	{ .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data },
+ 	{ .compatible = "mediatek,mt7981-pwm", .data = &mt7981_pwm_data },
+ 	{ .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data },
++	{ .compatible = "mediatek,mt7988-pwm", .data = &mt7988_pwm_data },
+ 	{ .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
+ 	{ },
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0950-add-pmic-config.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0950-add-pmic-config.patch
new file mode 100644
index 0000000..f5384f3
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/0950-add-pmic-config.patch
@@ -0,0 +1,36 @@
+diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
+index 3ee6353..2e393a7 100644
+--- a/drivers/regulator/Kconfig
++++ b/drivers/regulator/Kconfig
+@@ -798,6 +798,16 @@ config REGULATOR_RT5033
+ 	  RT5033 PMIC. The device supports multiple regulators like
+ 	  current source, LDO and Buck.
+ 
++config REGULATOR_RT5190A
++	tristate "Richtek RT5190A PMIC"
++	depends on I2C
++       select REGMAP_I2C
++	help
++	  This add support for voltage regulator in Ritchtek RT5190A PMIC.
++	  It integrates 1 channel buck controller, 3 channels high efficiency
++	  buck converters, 1 LDO, mute AC OFF depop function, with the general
++	  I2C control interface.
++
+ config REGULATOR_S2MPA01
+ 	tristate "Samsung S2MPA01 voltage regulator"
+ 	depends on MFD_SEC_CORE
+diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
+index 2210ba5..bf75b77 100644
+--- a/drivers/regulator/Makefile
++++ b/drivers/regulator/Makefile
+@@ -100,6 +100,7 @@ obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
+ obj-$(CONFIG_REGULATOR_RK808)   += rk808-regulator.o
+ obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
+ obj-$(CONFIG_REGULATOR_RT5033)	+= rt5033-regulator.o
++obj-$(CONFIG_REGULATOR_RT5190A) += rt5190a-regulator.o
+ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
+ obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
+ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1662-trng-Add-trng-support-for-mt7988.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1662-trng-Add-trng-support-for-mt7988.patch
new file mode 100644
index 0000000..a8f1dfe
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/1662-trng-Add-trng-support-for-mt7988.patch
@@ -0,0 +1,38 @@
+From cbd37bfc8221c1a81d235ddfb1898536a821c650 Mon Sep 17 00:00:00 2001
+From: "mingming.su" <Mingming.Su@mediatek.com>
+Date: Wed, 7 Sep 2022 15:44:46 +0800
+Subject: [PATCH] trng: Add trng support for mt7988
+
+Add trng support for mt7988.
+
+Signed-off-by: mingming.su <Mingming.Su@mediatek.com>
+---
+ drivers/char/hw_random/mtk-rng.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c
+index 75fca4cef..878170c15 100644
+--- a/drivers/char/hw_random/mtk-rng.c
++++ b/drivers/char/hw_random/mtk-rng.c
+@@ -231,6 +231,10 @@ static const struct mtk_rng_of_data mt7986_rng_data = {
+ 	.rng_version = 1,
+ };
+ 
++static const struct mtk_rng_of_data mt7988_rng_data = {
++	.rng_version = 2,
++};
++
+ static const struct mtk_rng_of_data mt7623_rng_data = {
+ 	.rng_version = 1,
+ };
+@@ -238,6 +242,7 @@ static const struct mtk_rng_of_data mt7623_rng_data = {
+ static const struct of_device_id mtk_rng_match[] = {
+ 	{ .compatible = "mediatek,mt7981-rng", .data = &mt7981_rng_data },
+ 	{ .compatible = "mediatek,mt7986-rng", .data = &mt7986_rng_data },
++	{ .compatible = "mediatek,mt7988-rng", .data = &mt7988_rng_data },
+ 	{ .compatible = "mediatek,mt7623-rng", .data = &mt7623_rng_data },
+ 	{},
+ };
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/401-pinctrl-enable-mt7988-pinctrl-config.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/401-pinctrl-enable-mt7988-pinctrl-config.patch
new file mode 100644
index 0000000..01f01f6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/401-pinctrl-enable-mt7988-pinctrl-config.patch
@@ -0,0 +1,30 @@
+diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
+index e7ec276..b6341dd 100644
+--- a/drivers/pinctrl/mediatek/Kconfig
++++ b/drivers/pinctrl/mediatek/Kconfig
+@@ -112,6 +112,13 @@ config PINCTRL_MT7986
+ 	default ARM64 && ARCH_MEDIATEK
+ 	select PINCTRL_MTK_MOORE
+ 
++config PINCTRL_MT7988
++        bool "Mediatek MT7988 pin control"
++        depends on OF
++        depends on ARM64 || COMPILE_TEST
++        default ARM64 && ARCH_MEDIATEK
++        select PINCTRL_MTK_MOORE
++
+ config PINCTRL_MT8173
+ 	bool "Mediatek MT8173 pin control"
+ 	depends on OF
+diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
+index e6813cf..6e28df9 100644
+--- a/drivers/pinctrl/mediatek/Makefile
++++ b/drivers/pinctrl/mediatek/Makefile
+@@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_MT7623)	+= pinctrl-mt7623.o
+ obj-$(CONFIG_PINCTRL_MT7629)	+= pinctrl-mt7629.o
+ obj-$(CONFIG_PINCTRL_MT7981)	+= pinctrl-mt7981.o
+ obj-$(CONFIG_PINCTRL_MT7986)	+= pinctrl-mt7986.o
++obj-$(CONFIG_PINCTRL_MT7988)    += pinctrl-mt7988.o
+ obj-$(CONFIG_PINCTRL_MT8173)	+= pinctrl-mt8173.o
+ obj-$(CONFIG_PINCTRL_MT8183)	+= pinctrl-mt8183.o
+ obj-$(CONFIG_PINCTRL_MT8516)	+= pinctrl-mt8516.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/6001-mtk-thermal-add-lvts-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/6001-mtk-thermal-add-lvts-support.patch
new file mode 100644
index 0000000..1591144
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/6001-mtk-thermal-add-lvts-support.patch
@@ -0,0 +1,28 @@
+diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
+index 001a21ab..67d3da48 100644
+--- a/drivers/thermal/Kconfig
++++ b/drivers/thermal/Kconfig
+@@ -348,6 +348,11 @@ config MTK_THERMAL
+ 	  Enable this option if you want to have support for thermal management
+ 	  controller present in Mediatek SoCs
+ 
++menu "Mediatek thermal drivers"
++depends on ARCH_MEDIATEK || COMPILE_TEST
++source "drivers/thermal/mediatek/Kconfig"
++endmenu
++
+ menu "Intel thermal drivers"
+ depends on X86 || X86_INTEL_QUARK || COMPILE_TEST
+ source "drivers/thermal/intel/Kconfig"
+diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
+index 74a37c7f..6be9ff19 100644
+--- a/drivers/thermal/Makefile
++++ b/drivers/thermal/Makefile
+@@ -51,6 +51,7 @@ obj-$(CONFIG_QCOM_TSENS)	+= qcom/
+ obj-y				+= tegra/
+ obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
+ obj-$(CONFIG_MTK_THERMAL)	+= mtk_thermal.o
++obj-y				+= mediatek/
+ obj-$(CONFIG_GENERIC_ADC_THERMAL)	+= thermal-generic-adc.o
+ obj-$(CONFIG_ZX2967_THERMAL)	+= zx2967_thermal.o
+ obj-$(CONFIG_UNIPHIER_THERMAL)	+= uniphier_thermal.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/746-add-mediatek-2p5ge-phy-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/746-add-mediatek-2p5ge-phy-support.patch
new file mode 100644
index 0000000..a102660
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/746-add-mediatek-2p5ge-phy-support.patch
@@ -0,0 +1,24 @@
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -522,6 +522,11 @@ config MEDIATEK_GE_PHY
+ 	help
+ 	  Supports the MediaTek Gigabit Ethernet PHYs.
+ 
++config MEDIATEK_2P5GE_PHY
++	tristate "MediaTek 2.5Gb Ethernet PHYs"
++	---help---
++	  Supports MediaTek internal 2.5Gb Ethernet PHYs.
++
+ config MICREL_PHY
+ 	tristate "Micrel PHYs"
+ 	---help---
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -95,6 +95,7 @@ obj-$(CONFIG_LXT_PHY)		+= lxt.o
+ obj-$(CONFIG_MARVELL_PHY)	+= marvell.o
+ obj-$(CONFIG_MARVELL_10G_PHY)	+= marvell10g.o
+ obj-$(CONFIG_MEDIATEK_GE_PHY)	+= mediatek-ge.o
++obj-$(CONFIG_MEDIATEK_2P5GE_PHY)+= mediatek-2p5ge.o
+ obj-$(CONFIG_MESON_GXL_PHY)	+= meson-gxl.o
+ obj-$(CONFIG_MICREL_KS8995MA)	+= spi_ks8995.o
+ obj-$(CONFIG_MICREL_PHY)	+= micrel.o
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/748-add-netlink-support-for-dsa.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/748-add-netlink-support-for-dsa.patch
new file mode 100644
index 0000000..8853324
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/748-add-netlink-support-for-dsa.patch
@@ -0,0 +1,498 @@
+Index: linux-5.4.203/drivers/net/dsa/Makefile
+===================================================================
+--- linux-5.4.203.orig/drivers/net/dsa/Makefile
++++ linux-5.4.203/drivers/net/dsa/Makefile
+@@ -7,7 +7,7 @@ obj-$(CONFIG_FIXED_PHY)		+= dsa_loop_bdi
+ endif
+ obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
+ obj-$(CONFIG_NET_DSA_MT7530)	+= mt7530-dsa.o
+-mt7530-dsa-objs			:= mt7530.o mt7531_phy.o
++mt7530-dsa-objs			:= mt7530.o mt7530_nl.o mt7531_phy.o
+ obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
+ obj-$(CONFIG_NET_DSA_QCA8K)	+= qca8k.o
+ obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
+Index: linux-5.4.203/drivers/net/dsa/mt7530.c
+===================================================================
+--- linux-5.4.203.orig/drivers/net/dsa/mt7530.c
++++ linux-5.4.203/drivers/net/dsa/mt7530.c
+@@ -21,6 +21,7 @@
+ #include <net/dsa.h>
+
+ #include "mt7530.h"
++#include "mt7530_nl.h"
+
+ /* String, offset, and register size in bytes if different from 4 bytes */
+ static const struct mt7530_mib_desc mt7530_mib[] = {
+@@ -222,7 +223,7 @@ mt7530_mii_read(struct mt7530_priv *priv
+ 	return (hi << 16) | (lo & 0xffff);
+ }
+
+-static void
++void
+ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
+ {
+ 	struct mii_bus *bus = priv->bus;
+@@ -255,7 +256,7 @@ _mt7530_read(struct mt7530_dummy_poll *p
+ 	return val;
+ }
+
+-static u32
++u32
+ mt7530_read(struct mt7530_priv *priv, u32 reg)
+ {
+ 	struct mt7530_dummy_poll p;
+@@ -614,7 +615,7 @@ static int mt7530_phy_write(struct dsa_s
+ 	return mdiobus_write_nested(priv->bus, port, regnum, val);
+ }
+
+-static int
++int
+ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
+ 			int regnum)
+ {
+@@ -663,7 +664,7 @@ out:
+ 	return ret;
+ }
+
+-static int
++int
+ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
+ 			 int regnum, u32 data)
+ {
+@@ -711,7 +712,7 @@ out:
+ 	return ret;
+ }
+
+-static int
++int
+ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
+ {
+ 	struct mii_bus *bus = priv->bus;
+@@ -749,7 +750,7 @@ out:
+ 	return ret;
+ }
+
+-static int
++int
+ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
+ 			 u16 data)
+ {
+@@ -2690,6 +2691,7 @@ mt7530_probe(struct mdio_device *mdiodev
+ {
+ 	struct mt7530_priv *priv;
+ 	struct device_node *dn;
++	int ret;
+
+ 	dn = mdiodev->dev.of_node;
+
+@@ -2765,7 +2767,13 @@ mt7530_probe(struct mdio_device *mdiodev
+ 	mutex_init(&priv->reg_mutex);
+ 	dev_set_drvdata(&mdiodev->dev, priv);
+
+-	return dsa_register_switch(priv->ds);
++	ret = dsa_register_switch(priv->ds);
++	if (ret)
++		return ret;
++
++	mt7530_nl_init(&priv);
++
++	return 0;
+ }
+
+ static void
+@@ -2786,6 +2794,8 @@ mt7530_remove(struct mdio_device *mdiode
+
+ 	dsa_unregister_switch(priv->ds);
+ 	mutex_destroy(&priv->reg_mutex);
++
++	mt7530_nl_exit();
+ }
+
+ static struct mdio_driver mt7530_mdio_driver = {
+Index: linux-5.4.203/drivers/net/dsa/mt7530.h
+===================================================================
+--- linux-5.4.203.orig/drivers/net/dsa/mt7530.h
++++ linux-5.4.203/drivers/net/dsa/mt7530.h
+@@ -783,4 +783,12 @@ static inline void INIT_MT7530_DUMMY_POL
+ }
+
+ int mt7531_phy_setup(struct dsa_switch *ds);
++u32 mt7530_read(struct mt7530_priv *priv, u32 reg);
++void mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val);
++int mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad, int regnum);
++int mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad, int regnum, u32 data);
++int mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum);
++int mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum, u16 data);
++
++
+ #endif /* __MT7530_H */
+Index: linux-5.4.203/drivers/net/dsa/mt7530_nl.c
+===================================================================
+--- /dev/null
++++ linux-5.4.203/drivers/net/dsa/mt7530_nl.c
+@@ -0,0 +1,311 @@
++// SPDX-License-Identifier: GPL-2.0

++/*

++ * Copyright (c) 2018 MediaTek Inc.

++ * Author: Sirui Zhao <Sirui.Zhao@mediatek.com>

++ */

++

++#include <linux/types.h>

++#include <linux/kernel.h>

++#include <linux/module.h>

++#include <linux/init.h>

++#include <net/genetlink.h>

++#include <linux/of_mdio.h>

++#include <linux/phylink.h>

++#include <net/dsa.h>

++

++#include "mt7530.h"

++#include "mt7530_nl.h"

++

++struct mt7530_nl_cmd_item {

++	enum mt7530_cmd cmd;

++	bool require_dev;

++	int (*process)(struct genl_info *info);

++	u32 nr_required_attrs;

++	const enum mt7530_attr *required_attrs;

++};

++

++struct mt7530_priv *sw_priv;

++

++static DEFINE_MUTEX(mt7530_devs_lock);

++

++void mt7530_put(void)

++{

++	mutex_unlock(&mt7530_devs_lock);

++}

++

++void mt7530_lock(void)

++{

++	mutex_lock(&mt7530_devs_lock);

++}

++

++static int mt7530_nl_response(struct sk_buff *skb, struct genl_info *info);

++

++static const struct nla_policy mt7530_nl_cmd_policy[] = {

++	[MT7530_ATTR_TYPE_MESG] = { .type = NLA_STRING },

++	[MT7530_ATTR_TYPE_PHY] = { .type = NLA_S32 },

++	[MT7530_ATTR_TYPE_REG] = { .type = NLA_S32 },

++	[MT7530_ATTR_TYPE_VAL] = { .type = NLA_S32 },

++	[MT7530_ATTR_TYPE_DEV_NAME] = { .type = NLA_S32 },

++	[MT7530_ATTR_TYPE_DEV_ID] = { .type = NLA_S32 },

++	[MT7530_ATTR_TYPE_DEVAD] = { .type = NLA_S32 },

++};

++

++static const struct genl_ops mt7530_nl_ops[] = {

++	{

++		.cmd = MT7530_CMD_REQUEST,

++		.doit = mt7530_nl_response,

++		.flags = GENL_ADMIN_PERM,

++	}, {

++		.cmd = MT7530_CMD_READ,

++		.doit = mt7530_nl_response,

++		.flags = GENL_ADMIN_PERM,

++	}, {

++		.cmd = MT7530_CMD_WRITE,

++		.doit = mt7530_nl_response,

++		.flags = GENL_ADMIN_PERM,

++	},

++};

++

++static struct genl_family mt7530_nl_family = {

++	.name =		MT7530_DSA_GENL_NAME,

++	.version =	MT7530_GENL_VERSION,

++	.maxattr =	MT7530_NR_ATTR_TYPE,

++	.ops =		mt7530_nl_ops,

++	.n_ops =	ARRAY_SIZE(mt7530_nl_ops),

++	.policy =	mt7530_nl_cmd_policy,

++};

++

++static int mt7530_nl_prepare_reply(struct genl_info *info, u8 cmd,

++				   struct sk_buff **skbp)

++{

++	struct sk_buff *msg;

++	void *reply;

++

++	if (!info)

++		return -EINVAL;

++

++	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);

++	if (!msg)

++		return -ENOMEM;

++

++	/* Construct send-back message header */

++	reply = genlmsg_put(msg, info->snd_portid, info->snd_seq,

++			    &mt7530_nl_family, 0, cmd);

++	if (!reply) {

++		nlmsg_free(msg);

++		return -EINVAL;

++	}

++

++	*skbp = msg;

++	return 0;

++}

++

++static int mt7530_nl_send_reply(struct sk_buff *skb, struct genl_info *info)

++{

++	struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));

++	void *reply = genlmsg_data(genlhdr);

++

++	/* Finalize a generic netlink message (update message header) */

++	genlmsg_end(skb, reply);

++

++	/* reply to a request */

++	return genlmsg_reply(skb, info);

++}

++

++static s32 mt7530_nl_get_s32(struct genl_info *info, enum mt7530_attr attr,

++			     s32 defval)

++{

++	struct nlattr *na;

++

++	na = info->attrs[attr];

++	if (na)

++		return nla_get_s32(na);

++

++	return defval;

++}

++

++static int mt7530_nl_get_u32(struct genl_info *info, enum mt7530_attr attr,

++			     u32 *val)

++{

++	struct nlattr *na;

++

++	na = info->attrs[attr];

++	if (na) {

++		*val = nla_get_u32(na);

++		return 0;

++	}

++

++	return -1;

++}

++

++static int mt7530_nl_reply_read(struct genl_info *info)

++{

++	struct sk_buff *rep_skb = NULL;

++	s32 phy, devad, reg;

++	int value;

++	int ret = 0;

++

++	phy = mt7530_nl_get_s32(info, MT7530_ATTR_TYPE_PHY, -1);

++	devad = mt7530_nl_get_s32(info, MT7530_ATTR_TYPE_DEVAD, -1);

++	reg = mt7530_nl_get_s32(info, MT7530_ATTR_TYPE_REG, -1);

++

++	if (reg < 0)

++		goto err;

++

++	ret = mt7530_nl_prepare_reply(info, MT7530_CMD_READ, &rep_skb);

++	if (ret < 0)

++		goto err;

++

++	if (phy >= 0) {

++		if (devad < 0)

++			value = mt7531_ind_c22_phy_read(sw_priv, phy, reg);

++		else

++			value = mt7531_ind_c45_phy_read(sw_priv, phy, devad, reg);

++	} else

++		value = mt7530_read(sw_priv, reg);

++

++	ret = nla_put_s32(rep_skb, MT7530_ATTR_TYPE_REG, reg);

++	if (ret < 0)

++		goto err;

++

++	ret = nla_put_s32(rep_skb, MT7530_ATTR_TYPE_VAL, value);

++	if (ret < 0)

++		goto err;

++

++	return mt7530_nl_send_reply(rep_skb, info);

++

++err:

++	if (rep_skb)

++		nlmsg_free(rep_skb);

++

++	return ret;

++}

++

++static int mt7530_nl_reply_write(struct genl_info *info)

++{

++	struct sk_buff *rep_skb = NULL;

++	s32 phy, devad, reg;

++	u32 value;

++	int ret = 0;

++

++	phy = mt7530_nl_get_s32(info, MT7530_ATTR_TYPE_PHY, -1);

++	devad = mt7530_nl_get_s32(info, MT7530_ATTR_TYPE_DEVAD, -1);

++	reg = mt7530_nl_get_s32(info, MT7530_ATTR_TYPE_REG, -1);

++

++	if (mt7530_nl_get_u32(info, MT7530_ATTR_TYPE_VAL, &value))

++		goto err;

++

++	if (reg < 0)

++		goto err;

++

++	ret = mt7530_nl_prepare_reply(info, MT7530_CMD_WRITE, &rep_skb);

++	if (ret < 0)

++		goto err;

++

++	if (phy >= 0) {

++		if (devad < 0)

++			mt7531_ind_c22_phy_write(sw_priv, phy, reg, value);

++		else

++			mt7531_ind_c45_phy_write(sw_priv, phy, devad, reg, value);

++	} else

++		mt7530_write(sw_priv, reg, value);

++

++	ret = nla_put_s32(rep_skb, MT7530_ATTR_TYPE_REG, reg);

++	if (ret < 0)

++		goto err;

++

++	ret = nla_put_s32(rep_skb, MT7530_ATTR_TYPE_VAL, value);

++	if (ret < 0)

++		goto err;

++

++	return mt7530_nl_send_reply(rep_skb, info);

++

++err:

++	if (rep_skb)

++		nlmsg_free(rep_skb);

++

++	return ret;

++}

++

++static const enum mt7530_attr mt7530_nl_cmd_read_attrs[] = {

++	MT7530_ATTR_TYPE_REG

++};

++

++static const enum mt7530_attr mt7530_nl_cmd_write_attrs[] = {

++	MT7530_ATTR_TYPE_REG,

++	MT7530_ATTR_TYPE_VAL

++};

++

++static const struct mt7530_nl_cmd_item mt7530_nl_cmds[] = {

++	{

++		.cmd = MT7530_CMD_READ,

++		.require_dev = true,

++		.process = mt7530_nl_reply_read,

++		.required_attrs = mt7530_nl_cmd_read_attrs,

++		.nr_required_attrs = ARRAY_SIZE(mt7530_nl_cmd_read_attrs),

++	}, {

++		.cmd = MT7530_CMD_WRITE,

++		.require_dev = true,

++		.process = mt7530_nl_reply_write,

++		.required_attrs = mt7530_nl_cmd_write_attrs,

++		.nr_required_attrs = ARRAY_SIZE(mt7530_nl_cmd_write_attrs),

++	}

++};

++

++static int mt7530_nl_response(struct sk_buff *skb, struct genl_info *info)

++{

++	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);

++	const struct mt7530_nl_cmd_item *cmditem = NULL;

++	u32 sat_req_attrs = 0;

++	int i, ret;

++

++	for (i = 0; i < ARRAY_SIZE(mt7530_nl_cmds); i++) {

++		if (hdr->cmd == mt7530_nl_cmds[i].cmd) {

++			cmditem = &mt7530_nl_cmds[i];

++			break;

++		}

++	}

++

++	if (!cmditem) {

++		pr_info("mt7530-nl: unknown cmd %u\n", hdr->cmd);

++		return -EINVAL;

++	}

++

++	for (i = 0; i < cmditem->nr_required_attrs; i++) {

++		if (info->attrs[cmditem->required_attrs[i]])

++			sat_req_attrs++;

++	}

++

++	if (sat_req_attrs != cmditem->nr_required_attrs) {

++		pr_info("mt7530-nl: missing required attr(s) for cmd %u\n",

++			hdr->cmd);

++		return -EINVAL;

++	}

++

++	ret = cmditem->process(info);

++

++	mt7530_put();

++

++	return ret;

++}

++

++int mt7530_nl_init(struct mt7530_priv **priv)

++{

++	int ret;

++

++	pr_info("mt7530-nl: genl_register_family_with_ops \n");

++

++	sw_priv = *priv;

++	ret = genl_register_family(&mt7530_nl_family);

++	if (ret) {

++		return ret;

++	}

++

++	return 0;

++}

++

++void mt7530_nl_exit()

++{

++	sw_priv = NULL;

++	genl_unregister_family(&mt7530_nl_family);

++}

+Index: linux-5.4.203/drivers/net/dsa/mt7530_nl.h
+===================================================================
+--- /dev/null
++++ linux-5.4.203/drivers/net/dsa/mt7530_nl.h
+@@ -0,0 +1,49 @@
++/* SPDX-License-Identifier: GPL-2.0-only */

++/*

++ * Copyright (c) 2018 MediaTek Inc.

++ * Author: Sirui Zhao <Sirui.Zhao@mediatek.com>

++ */

++

++#ifndef _MT753x_NL_H_

++#define _MT753x_NL_H_

++

++#define MT7530_DSA_GENL_NAME "mt753x_dsa"

++#define MT7530_GENL_VERSION		0x1

++

++enum mt7530_cmd {

++	MT7530_CMD_UNSPEC = 0,

++	MT7530_CMD_REQUEST,

++	MT7530_CMD_REPLY,

++	MT7530_CMD_READ,

++	MT7530_CMD_WRITE,

++

++	__MT7530_CMD_MAX,

++};

++

++enum mt7530_attr {

++	MT7530_ATTR_TYPE_UNSPEC = 0,

++	MT7530_ATTR_TYPE_MESG,

++	MT7530_ATTR_TYPE_PHY,

++	MT7530_ATTR_TYPE_DEVAD,

++	MT7530_ATTR_TYPE_REG,

++	MT7530_ATTR_TYPE_VAL,

++	MT7530_ATTR_TYPE_DEV_NAME,

++	MT7530_ATTR_TYPE_DEV_ID,

++

++	__MT7530_ATTR_TYPE_MAX,

++};

++

++#define MT7530_NR_ATTR_TYPE		(__MT7530_ATTR_TYPE_MAX - 1)

++

++struct mt7530_info {

++	struct mii_bus	*bus;

++	void __iomem *base;

++	int direct_access;

++};

++

++#ifdef __KERNEL__

++int  mt7530_nl_init(struct mt7530_priv **priv);

++void mt7530_nl_exit(void);

++#endif /* __KERNEL__ */

++

++#endif /* _MT7530_NL_H_ */

diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/749-net-dsa-support-mt7988.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/749-net-dsa-support-mt7988.patch
new file mode 100644
index 0000000..7c468d8
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/749-net-dsa-support-mt7988.patch
@@ -0,0 +1,360 @@
+Index: linux-5.4.203/drivers/net/dsa/mt7530.c
+===================================================================
+--- linux-5.4.203.orig/drivers/net/dsa/mt7530.c
++++ linux-5.4.203/drivers/net/dsa/mt7530.c
+@@ -19,6 +19,7 @@
+ #include <linux/reset.h>
+ #include <linux/gpio/consumer.h>
+ #include <net/dsa.h>
++#include <linux/of_address.h>
+
+ #include "mt7530.h"
+ #include "mt7530_nl.h"
+@@ -170,28 +171,44 @@ core_clear(struct mt7530_priv *priv, u32
+ 	core_rmw(priv, reg, val, 0);
+ }
+
++static void
++mtk_w32(struct mt7530_priv *priv, u32 val, unsigned reg)
++{
++	__raw_writel(val, priv->base + reg);
++}
++
++static u32
++mtk_r32(struct mt7530_priv *priv, unsigned reg)
++{
++	return __raw_readl(priv->base + reg);
++}
++
+ static int
+ mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
+ {
+ 	struct mii_bus *bus = priv->bus;
+ 	u16 page, r, lo, hi;
+-	int ret;
+-
+-	page = (reg >> 6) & 0x3ff;
+-	r  = (reg >> 2) & 0xf;
+-	lo = val & 0xffff;
+-	hi = val >> 16;
+-
+-	/* MT7530 uses 31 as the pseudo port */
+-	ret = bus->write(bus, 0x1f, 0x1f, page);
+-	if (ret < 0)
+-		goto err;
++	int ret = 0;
+
+-	ret = bus->write(bus, 0x1f, r,  lo);
+-	if (ret < 0)
+-		goto err;
++	if (priv->direct_access){
++		mtk_w32(priv, val, reg);
++	} else {
++		page = (reg >> 6) & 0x3ff;
++		r  = (reg >> 2) & 0xf;
++		lo = val & 0xffff;
++		hi = val >> 16;
++
++		/* MT7530 uses 31 as the pseudo port */
++		ret = bus->write(bus, 0x1f, 0x1f, page);
++		if (ret < 0)
++			goto err;
++
++		ret = bus->write(bus, 0x1f, r,  lo);
++		if (ret < 0)
++			goto err;
+
+-	ret = bus->write(bus, 0x1f, 0x10, hi);
++		ret = bus->write(bus, 0x1f, 0x10, hi);
++	}
+ err:
+ 	if (ret < 0)
+ 		dev_err(&bus->dev,
+@@ -206,21 +223,25 @@ mt7530_mii_read(struct mt7530_priv *priv
+ 	u16 page, r, lo, hi;
+ 	int ret;
+
+-	page = (reg >> 6) & 0x3ff;
+-	r = (reg >> 2) & 0xf;
++	if (priv->direct_access){
++		return mtk_r32(priv, reg);
++	} else {
++		page = (reg >> 6) & 0x3ff;
++		r = (reg >> 2) & 0xf;
+
+-	/* MT7530 uses 31 as the pseudo port */
+-	ret = bus->write(bus, 0x1f, 0x1f, page);
+-	if (ret < 0) {
+-		dev_err(&bus->dev,
+-			"failed to read mt7530 register\n");
+-		return ret;
+-	}
++		/* MT7530 uses 31 as the pseudo port */
++		ret = bus->write(bus, 0x1f, 0x1f, page);
++		if (ret < 0) {
++			dev_err(&bus->dev,
++				"failed to read mt7530 register\n");
++			return ret;
++		}
+
+-	lo = bus->read(bus, 0x1f, r);
+-	hi = bus->read(bus, 0x1f, 0x10);
++		lo = bus->read(bus, 0x1f, r);
++		hi = bus->read(bus, 0x1f, 0x10);
+
+-	return (hi << 16) | (lo & 0xffff);
++		return (hi << 16) | (lo & 0xffff);
++	}
+ }
+
+ void
+@@ -1906,9 +1927,9 @@ mt7531_phy_supported(struct dsa_switch *
+ 		if (mt7531_is_rgmii_port(priv, port))
+ 			return phy_interface_mode_is_rgmii(state->interface);
+ 		fallthrough;
+-	case 6: /* 1st cpu port supports sgmii/8023z only */
+-		if (state->interface != PHY_INTERFACE_MODE_SGMII &&
+-		    !phy_interface_mode_is_8023z(state->interface))
++	case 6: /* 1st cpu port supports sgmii/8023z/usxgmii/10gkr */
++		if (state->interface != PHY_INTERFACE_MODE_SGMII && state->interface != PHY_INTERFACE_MODE_USXGMII &&
++		    state->interface != PHY_INTERFACE_MODE_10GKR && !phy_interface_mode_is_8023z(state->interface))
+ 			goto unsupported;
+ 		break;
+ 	default:
+@@ -2017,6 +2038,13 @@ static void mt7531_sgmii_validate(struct
+ 		phylink_set(supported, 1000baseX_Full);
+ 		phylink_set(supported, 2500baseX_Full);
+ 		phylink_set(supported, 2500baseT_Full);
++		phylink_set(supported, 10000baseKR_Full);
++		phylink_set(supported, 10000baseT_Full);
++		phylink_set(supported, 10000baseCR_Full);
++		phylink_set(supported, 10000baseSR_Full);
++		phylink_set(supported, 10000baseLR_Full);
++		phylink_set(supported, 10000baseLRM_Full);
++		phylink_set(supported, 10000baseER_Full);
+ 	}
+ }
+
+@@ -2165,6 +2193,8 @@ mt7531_mac_config(struct dsa_switch *ds,
+ 	case PHY_INTERFACE_MODE_NA:
+ 	case PHY_INTERFACE_MODE_1000BASEX:
+ 	case PHY_INTERFACE_MODE_2500BASEX:
++	case PHY_INTERFACE_MODE_USXGMII:
++	case PHY_INTERFACE_MODE_10GKR:
+ 		if (phylink_autoneg_inband(mode))
+ 			return -EINVAL;
+
+@@ -2302,8 +2332,8 @@ static void mt753x_phylink_mac_link_up(s
+ 	/* MT753x MAC works in 1G full duplex mode for all up-clocked
+ 	 * variants.
+ 	 */
+-	if (interface == PHY_INTERFACE_MODE_TRGMII ||
+-	    (phy_interface_mode_is_8023z(interface))) {
++	if (interface == PHY_INTERFACE_MODE_TRGMII || interface == PHY_INTERFACE_MODE_USXGMII ||
++	    interface == PHY_INTERFACE_MODE_10GKR || (phy_interface_mode_is_8023z(interface))) {
+ 		speed = SPEED_1000;
+ 		duplex = DUPLEX_FULL;
+ 	}
+@@ -2402,8 +2432,8 @@ mt753x_phylink_validate(struct dsa_switc
+
+ 	phylink_set_port_modes(mask);
+
+-	if (state->interface != PHY_INTERFACE_MODE_TRGMII ||
+-	    !phy_interface_mode_is_8023z(state->interface)) {
++	if (state->interface != PHY_INTERFACE_MODE_TRGMII || state->interface != PHY_INTERFACE_MODE_USXGMII ||
++	    state->interface != PHY_INTERFACE_MODE_10GKR || !phy_interface_mode_is_8023z(state->interface)) {
+ 		phylink_set(mask, 10baseT_Half);
+ 		phylink_set(mask, 10baseT_Full);
+ 		phylink_set(mask, 100baseT_Half);
+@@ -2607,6 +2637,66 @@ mt753x_phy_write(struct dsa_switch *ds,
+ 	return priv->info->phy_write(ds, port, regnum, val);
+ }
+
++static int
++mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
++{
++	return 0;
++}
++
++static int
++mt7988_setup(struct dsa_switch *ds)
++{
++	struct mt7530_priv *priv = ds->priv;
++	u32 unused_pm = 0;
++	int ret, i;
++
++	/* Reset the switch through internal reset */
++	mt7530_write(priv, MT7530_SYS_CTRL,
++		     SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST);
++
++	/* BPDU to CPU port */
++	mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
++		   BIT(MT7530_CPU_PORT));
++	mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
++		   MT753X_BPDU_CPU_ONLY);
++
++	/* Enable and reset MIB counters */
++	mt7530_mib_reset(ds);
++
++	for (i = 0; i < MT7530_NUM_PORTS; i++) {
++		/* Disable forwarding by default on all ports */
++		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
++			   PCR_MATRIX_CLR);
++
++		mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
++
++		if (dsa_is_unused_port(ds, i))
++			unused_pm |= BIT(i);
++		else if (dsa_is_cpu_port(ds, i))
++			mt753x_cpu_port_enable(ds, i);
++		else
++			mt7530_port_disable(ds, i);
++
++		/* Enable consistent egress tag */
++		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
++			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
++	}
++
++	mt7531_phy_setup(ds);
++
++	/* Group and enable unused ports as a standalone dumb switch. */
++	setup_unused_ports(ds, unused_pm);
++
++	ds->configure_vlan_while_not_filtering = true;
++
++	/* Flush the FDB table */
++	ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
++	if (ret < 0)
++		return ret;
++
++	return 0;
++}
++
+ static const struct dsa_switch_ops mt7530_switch_ops = {
+ 	.get_tag_protocol	= mtk_get_tag_protocol,
+ 	.setup			= mt753x_setup,
+@@ -2676,12 +2766,28 @@ static const struct mt753x_info mt753x_t
+ 		.mac_pcs_an_restart = mt7531_sgmii_restart_an,
+ 		.mac_pcs_link_up = mt7531_sgmii_link_up_force,
+ 	},
++	[ID_MT7988] = {
++		.id = ID_MT7988,
++		.sw_setup = mt7988_setup,
++		.phy_read = mt7531_ind_phy_read,
++		.phy_write = mt7531_ind_phy_write,
++		.pad_setup = mt7988_pad_setup,
++		.cpu_port_config = mt7531_cpu_port_config,
++		.phy_mode_supported = mt7531_phy_supported,
++		.mac_port_validate = mt7531_mac_port_validate,
++		.mac_port_get_state = mt7531_phylink_mac_link_state,
++		.mac_port_config = mt7531_mac_config,
++		.mac_pcs_an_restart = mt7531_sgmii_restart_an,
++		.mac_pcs_link_up = mt7531_sgmii_link_up_force,
++	},
++
+ };
+
+ static const struct of_device_id mt7530_of_match[] = {
+ 	{ .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
+ 	{ .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
+ 	{ .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
++	{ .compatible = "mediatek,mt7988", .data = &mt753x_table[ID_MT7988], },
+ 	{ /* sentinel */ },
+ };
+ MODULE_DEVICE_TABLE(of, mt7530_of_match);
+@@ -2691,6 +2797,7 @@ mt7530_probe(struct mdio_device *mdiodev
+ {
+ 	struct mt7530_priv *priv;
+ 	struct device_node *dn;
++	struct device_node *switch_node = NULL;
+ 	int ret;
+
+ 	dn = mdiodev->dev.of_node;
+@@ -2760,6 +2867,16 @@ mt7530_probe(struct mdio_device *mdiodev
+ 		}
+ 	}
+
++	switch_node = of_find_node_by_name(NULL, "switch0");
++	if(switch_node) {
++		priv->base = of_iomap(switch_node, 0);
++		if(priv->base == NULL){
++			dev_err(&mdiodev->dev, "of_iomap failed\n");
++			return -ENOMEM;
++		}
++		priv->direct_access = 1;
++	}
++
+ 	priv->bus = mdiodev->bus;
+ 	priv->dev = &mdiodev->dev;
+ 	priv->ds->priv = priv;
+@@ -2768,9 +2885,12 @@ mt7530_probe(struct mdio_device *mdiodev
+ 	dev_set_drvdata(&mdiodev->dev, priv);
+
+ 	ret = dsa_register_switch(priv->ds);
+-	if (ret)
+-		return ret;
+-
++	if (ret) {
++		if(priv->base)
++			iounmap(priv->base);
++
++		return ret;
++	}
+ 	mt7530_nl_init(&priv);
+
+ 	return 0;
+@@ -2795,6 +2915,9 @@ mt7530_remove(struct mdio_device *mdiode
+ 	dsa_unregister_switch(priv->ds);
+ 	mutex_destroy(&priv->reg_mutex);
+
++	if(priv->base)
++		iounmap(priv->base);
++
+ 	mt7530_nl_exit();
+ }
+
+Index: linux-5.4.203/drivers/net/dsa/mt7530.h
+===================================================================
+--- linux-5.4.203.orig/drivers/net/dsa/mt7530.h
++++ linux-5.4.203/drivers/net/dsa/mt7530.h
+@@ -16,6 +16,7 @@ enum mt753x_id {
+ 	ID_MT7530 = 0,
+ 	ID_MT7621 = 1,
+ 	ID_MT7531 = 2,
++	ID_MT7988 = 3,
+ };
+
+ #define	NUM_TRGMII_CTRL			5
+@@ -51,11 +52,11 @@ enum mt753x_id {
+ #define  MT7531_MIRROR_PORT_SET(x)	(((x) & MIRROR_MASK) << 16)
+ #define  MT7531_CPU_PMAP_MASK		GENMASK(7, 0)
+
+-#define MT753X_MIRROR_REG(id)		(((id) == ID_MT7531) ? \
++#define MT753X_MIRROR_REG(id)		((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
+ 					 MT7531_CFC : MT7530_MFC)
+-#define MT753X_MIRROR_EN(id)		(((id) == ID_MT7531) ? \
++#define MT753X_MIRROR_EN(id)		((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
+ 					 MT7531_MIRROR_EN : MIRROR_EN)
+-#define MT753X_MIRROR_MASK(id)		(((id) == ID_MT7531) ? \
++#define MT753X_MIRROR_MASK(id)		((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
+ 					 MT7531_MIRROR_MASK : MIRROR_MASK)
+
+ /* Registers for BPDU and PAE frame control*/
+@@ -261,7 +262,7 @@ enum mt7530_vlan_port_attr {
+ 					 MT7531_FORCE_DPX | \
+ 					 MT7531_FORCE_RX_FC | \
+ 					 MT7531_FORCE_TX_FC)
+-#define  PMCR_FORCE_MODE_ID(id)		(((id) == ID_MT7531) ? \
++#define  PMCR_FORCE_MODE_ID(id)		((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
+ 					 MT7531_FORCE_MODE : \
+ 					 PMCR_FORCE_MODE)
+ #define  PMCR_LINK_SETTINGS_MASK	(PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
+@@ -733,6 +734,8 @@ struct mt7530_priv {
+ 	struct regulator	*core_pwr;
+ 	struct regulator	*io_pwr;
+ 	struct gpio_desc	*reset;
++	void  __iomem *base;
++	int   direct_access;
+ 	const struct mt753x_info *info;
+ 	unsigned int		id;
+ 	bool			mcm;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch
new file mode 100644
index 0000000..5a130b1
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/750-add-mdio-bus-for-phy-node.patch
@@ -0,0 +1,165 @@
+Index: linux-5.4.203/drivers/net/dsa/mt7530.c
+===================================================================
+--- linux-5.4.203.orig/drivers/net/dsa/mt7530.c
++++ linux-5.4.203/drivers/net/dsa/mt7530.c
+@@ -847,6 +847,132 @@ mt7531_ind_phy_write(struct dsa_switch *
+ 	return ret;
+ }
+
++static int mt753x_mdio_read(struct mii_bus *bus, int addr, int regnum)
++{
++	struct mt7530_priv *priv = bus->priv;
++	struct mt7530_dummy_poll p;
++	int ret;
++	u32 val;
++
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++	mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(addr) |
++		  MT7531_MDIO_REG_ADDR(regnum);
++
++	mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
++				 !(val & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	ret = val & MT7531_MDIO_RW_DATA_MASK;
++out:
++	mutex_unlock(&priv->bus->mdio_lock);
++
++	return ret;
++}
++
++static int mt753x_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
++{
++	struct mt7530_priv *priv = bus->priv;
++	struct mt7530_dummy_poll p;
++	int ret;
++	u32 reg;
++
++	INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
++
++	mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
++				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++	reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(addr) |
++		  MT7531_MDIO_REG_ADDR(regnum) | val;
++
++	mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
++
++	ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
++				 !(reg & MT7531_PHY_ACS_ST), 20, 100000);
++	if (ret < 0) {
++		dev_err(priv->dev, "poll timeout\n");
++		goto out;
++	}
++
++out:
++	mutex_unlock(&priv->bus->mdio_lock);
++
++	return ret;
++}
++
++static int mt753x_mdio_init(struct mt7530_priv *priv)
++{
++	struct device_node *dn;
++	struct device_node *mii_np;
++	int ret;
++
++	dn = priv->dev->of_node;
++
++	mii_np = of_get_child_by_name(dn, "mdio-bus");
++	if (!mii_np) {
++		ret = -ENODEV;
++		goto err_put_node;
++	}
++
++	if (!of_device_is_available(mii_np)) {
++		ret = -ENODEV;
++		goto err_put_node;
++	}
++
++	priv->gbus = devm_mdiobus_alloc(priv->dev);
++	if (!priv->gbus) {
++		ret = -ENOMEM;
++		goto err_put_node;
++	}
++	priv->gbus->name = "mt753x_mdio";
++	priv->gbus->read = mt753x_mdio_read;
++	priv->gbus->write = mt753x_mdio_write;
++	priv->gbus->priv = priv;
++	priv->gbus->parent = priv->dev;
++
++	if(snprintf(priv->gbus->id, MII_BUS_ID_SIZE, "%s@%s", mii_np->name, dn->name) < 0) {
++		ret = -ENOMEM;
++		goto err_put_node;
++	}
++
++	ret = of_mdiobus_register(priv->gbus, mii_np);
++	if (ret)
++		priv->gbus = NULL;
++
++err_put_node:
++	of_node_put(mii_np);
++
++	return ret;
++}
++
++static void mt753x_mdio_exit(struct mt7530_priv *priv)
++{
++	if (!priv->gbus)
++		return;
++
++	mdiobus_unregister(priv->gbus);
++}
++
+ static void
+ mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+ 		   uint8_t *data)
+@@ -2892,6 +3018,7 @@ mt7530_probe(struct mdio_device *mdiodev
+ 		return ret;
+ 	}
+ 	mt7530_nl_init(&priv);
++	mt753x_mdio_init(priv);
+
+ 	return 0;
+ }
+@@ -2919,6 +3046,7 @@ mt7530_remove(struct mdio_device *mdiode
+ 		iounmap(priv->base);
+
+ 	mt7530_nl_exit();
++	mt753x_mdio_exit(priv);
+ }
+
+ static struct mdio_driver mt7530_mdio_driver = {
+Index: linux-5.4.203/drivers/net/dsa/mt7530.h
+===================================================================
+--- linux-5.4.203.orig/drivers/net/dsa/mt7530.h
++++ linux-5.4.203/drivers/net/dsa/mt7530.h
+@@ -730,6 +730,7 @@ struct mt7530_priv {
+ 	struct device		*dev;
+ 	struct dsa_switch	*ds;
+ 	struct mii_bus		*bus;
++	struct mii_bus		*gbus;
+ 	struct reset_control	*rstc;
+ 	struct regulator	*core_pwr;
+ 	struct regulator	*io_pwr;
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8010-phy-phy-mtk-xsphy-support-type-switch-by-pericfg.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8010-phy-phy-mtk-xsphy-support-type-switch-by-pericfg.patch
new file mode 100644
index 0000000..c20e930
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/8010-phy-phy-mtk-xsphy-support-type-switch-by-pericfg.patch
@@ -0,0 +1,142 @@
+diff --git a/drivers/phy/mediatek/phy-mtk-xsphy.c b/drivers/phy/mediatek/phy-mtk-xsphy.c
+index 8c51131..e77092c 100644
+--- a/drivers/phy/mediatek/phy-mtk-xsphy.c
++++ b/drivers/phy/mediatek/phy-mtk-xsphy.c
+@@ -12,10 +12,12 @@
+ #include <linux/delay.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
++#include <linux/mfd/syscon.h>
+ #include <linux/module.h>
+ #include <linux/of_address.h>
+ #include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
++#include <linux/regmap.h>
+ 
+ /* u2 phy banks */
+ #define SSUSB_SIFSLV_MISC		0x000
+@@ -88,12 +90,22 @@
+ #define XSP_SR_COEF_DIVISOR	1000
+ #define XSP_FM_DET_CYCLE_CNT	1024
+ 
++/* PHY switch between pcie/usb3/sgmii */
++#define USB_PHY_SWITCH_CTRL	0x0
++#define RG_PHY_SW_TYPE		GENMASK(3, 0)
++#define RG_PHY_SW_PCIE		0x0
++#define RG_PHY_SW_USB3		0x1
++#define RG_PHY_SW_SGMII		0x2
++
+ struct xsphy_instance {
+ 	struct phy *phy;
+ 	void __iomem *port_base;
+ 	struct clk *ref_clk;	/* reference clock of anolog phy */
+ 	u32 index;
+ 	u32 type;
++	struct regmap *type_sw;
++	u32 type_sw_reg;
++	u32 type_sw_index;
+ 	/* only for HQA test */
+ 	int efuse_intr;
+ 	int efuse_tx_imp;
+@@ -365,6 +377,62 @@ static void u3_phy_props_set(struct mtk_xsphy *xsphy,
+ 	}
+ }
+ 
++/* type switch for usb3/pcie/sgmii */
++static int phy_type_syscon_get(struct xsphy_instance *instance,
++			       struct device_node *dn)
++{
++	struct of_phandle_args args;
++	int ret;
++
++	/* type switch function is optional */
++	if (!of_property_read_bool(dn, "mediatek,syscon-type"))
++		return 0;
++
++	ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
++					       2, 0, &args);
++	if (ret)
++		return ret;
++
++	instance->type_sw_reg = args.args[0];
++	instance->type_sw_index = args.args[1] & 0x3; /* <=3 */
++	instance->type_sw = syscon_node_to_regmap(args.np);
++	of_node_put(args.np);
++	dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n",
++		 instance->type_sw_reg, instance->type_sw_index);
++
++	return PTR_ERR_OR_ZERO(instance->type_sw);
++}
++
++static int phy_type_set(struct xsphy_instance *instance)
++{
++	int type;
++	u32 offset;
++
++	if (!instance->type_sw)
++		return 0;
++
++	switch (instance->type) {
++	case PHY_TYPE_USB3:
++		type = RG_PHY_SW_USB3;
++		break;
++	case PHY_TYPE_PCIE:
++		type = RG_PHY_SW_PCIE;
++		break;
++	case PHY_TYPE_SGMII:
++		type = RG_PHY_SW_SGMII;
++		break;
++	case PHY_TYPE_USB2:
++	default:
++		return 0;
++	}
++
++	offset = instance->type_sw_index * BITS_PER_BYTE;
++	regmap_update_bits(instance->type_sw, instance->type_sw_reg,
++			   RG_PHY_SW_TYPE << offset, type << offset);
++
++	return 0;
++}
++
+ static int mtk_phy_init(struct phy *phy)
+ {
+ 	struct xsphy_instance *inst = phy_get_drvdata(phy);
+@@ -385,6 +453,10 @@ static int mtk_phy_init(struct phy *phy)
+ 	case PHY_TYPE_USB3:
+ 		u3_phy_props_set(xsphy, inst);
+ 		break;
++	case PHY_TYPE_PCIE:
++	case PHY_TYPE_SGMII:
++		/* nothing to do, only used to set type */
++		break;
+ 	default:
+ 		dev_err(xsphy->dev, "incompatible phy type\n");
+ 		clk_disable_unprepare(inst->ref_clk);
+@@ -463,12 +535,15 @@ static struct phy *mtk_phy_xlate(struct device *dev,
+ 
+ 	inst->type = args->args[0];
+ 	if (!(inst->type == PHY_TYPE_USB2 ||
+-	      inst->type == PHY_TYPE_USB3)) {
++	      inst->type == PHY_TYPE_USB3 ||
++	      inst->type == PHY_TYPE_PCIE ||
++	      inst->type == PHY_TYPE_SGMII)) {
+ 		dev_err(dev, "unsupported phy type: %d\n", inst->type);
+ 		return ERR_PTR(-EINVAL);
+ 	}
+ 
+ 	phy_parse_property(xsphy, inst);
++	phy_type_set(inst);
+ 
+ 	return inst->phy;
+ }
+@@ -575,6 +650,10 @@ static int mtk_xsphy_probe(struct platform_device *pdev)
+ 			retval = PTR_ERR(inst->ref_clk);
+ 			goto put_child;
+ 		}
++
++		retval = phy_type_syscon_get(inst, child_np);
++		if (retval)
++			goto put_child;
+ 	}
+ 
+ 	provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9000-PATCH-1-1-xHCI-change-compliance-mode-de-emphasis-default-as-g.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9000-PATCH-1-1-xHCI-change-compliance-mode-de-emphasis-default-as-g.patch
new file mode 100644
index 0000000..e82e1bc
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/9000-PATCH-1-1-xHCI-change-compliance-mode-de-emphasis-default-as-g.patch
@@ -0,0 +1,57 @@
+From 5f8c12ffa661e3707790f59827a45ff4102f2886 Mon Sep 17 00:00:00 2001
+From: Zhanyong Wang <zhanyong.wang@mediatek.com>
+Date: Mon, 15 Aug 2022 14:13:50 +0800
+Subject: [PATCH] xHCI: change compliance mode de-emphasis default as gen1
+
+Port0 is using Gen2 Phy for 10GHz, and Port0 is running
+on 5GHz actually. hence to change compliance mode de-
+emphasis default as Gen1.
+
+Signed-off-by: Zhanyong Wang <zhanyong.wang@mediatek.com>
+---
+ drivers/usb/host/xhci-mtk.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
+index 2a4b73a658f9..b1201fb65fd6 100644
+--- a/drivers/usb/host/xhci-mtk.c
++++ b/drivers/usb/host/xhci-mtk.c
+@@ -24,6 +24,11 @@
+ #include "xhci-mtk.h"
+ #include "xhci-mtk-test.h"
+ 
++/* COMPLIANCE_CP5_CP7_TXDEEMPH_10G register */
++#define COMPLIANCE_CP5_CP7_TXDEEMPH_10G  0x2428
++#define CP5_CP7_TXDEEMPH_10G		 GENMASK(17, 0)
++#define CP5_CP7_TXDEEMPH_10G_VAL(val)	((val) & 0x03FFFF)
++
+ /* ip_pw_ctrl0 register */
+ #define CTRL0_IP_SW_RST	BIT(0)
+ 
+@@ -415,6 +420,7 @@ static int xhci_mtk_setup(struct usb_hcd *hcd)
+ {
+ 	struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd);
+ 	int ret;
++	u32 val;
+ 
+ 	if (usb_hcd_is_primary_hcd(hcd)) {
+ 		ret = xhci_mtk_ssusb_config(mtk);
+@@ -432,6 +438,15 @@ static int xhci_mtk_setup(struct usb_hcd *hcd)
+ 			return ret;
+ 	}
+ 
++	/* change COMPLIANCE_CP5_CP7_TXDEEMPH_10G  as Gen1 instead Gen2 */
++	if (hcd->rsrc_start == 0x11190000ULL) {
++		val  = readl(mtk->hcd->regs + COMPLIANCE_CP5_CP7_TXDEEMPH_10G);
++		val &= ~CP5_CP7_TXDEEMPH_10G;
++		val |= 0x00001;
++		val = CP5_CP7_TXDEEMPH_10G_VAL(val);
++		writel(val, mtk->hcd->regs + COMPLIANCE_CP5_CP7_TXDEEMPH_10G);
++	}
++
+ 	return ret;
+ }
+ 
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
index 2ad7eec..4c9012a 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
@@ -1,14 +1,21 @@
 #patch patches-5.4 (come from openwrt/lede/target/linux/mediatek)
 SRC_URI_append = " \
     file://0001-clk-mtk-add-mt7986-support.patch \
+    file://0001-cpufreq-add-the-missing-platform-driver-unregister.patch \
     file://0001-v5.7-spi-make-spi-max-frequency-optional.patch \
     file://0002-clk-mtk-add-mt7981-support.patch \
+    file://0002-cpufreq-Enable-clocks-and-regulators.patch \
     file://0002-v5.7-spi-add-support-for-mediatek-spi-nor-controller.patch \
+    file://0003-clk-mtk-add-mt7988-support.patch \
+    file://0003-cpufreq-add-mt7988a-spim-snand-support.patch \
     file://0003-switch-add-mt7531.patch \
+    file://0005-clk-mtk-add-chg-shift-control.patch \
     file://0005-dts-mt7622-add-gsw.patch \
     file://0005-dts-mt7629-add-gsw.patch \
     file://0006-dts-fix-bpi2-console.patch \
     file://0006-dts-fix-bpi64-console.patch \
+    file://0006-powerdomain-add-mt7988-support.patch \
+    file://0007-cpufreq-mtk-vbining-add-mt7988-support.patch \
     file://0010-dts-mt7629-rfb-fix-firmware-partition.patch \
     file://0020-dts-mt7622-enable-new-mtk-snand-for-ubi.patch \
     file://0021-dts-mt7622-remove-cooling-device.patch \
@@ -54,6 +61,8 @@
     file://0901-i2c-busses-add-mt7981-support.patch \
     file://0930-pwm-add-mt7986-support.patch \
     file://0931-pwm-add-mt7981-support.patch \
+    file://0932-add-pwm-feature-in-mt7988-project.patch \
+    file://0950-add-pmic-config.patch \
     file://0960-watchdog-add-mt7986-assert.patch \
     file://0990-gsw-rtl8367s-mt7622-support.patch \
     file://0991-dt-bindings-PCI-Mediatek-Update-PCIe-binding.patch \
@@ -69,15 +78,18 @@
     file://1023-kgdb-add-interrupt-control.patch \
     file://1024-pcie-add-multi-MSI-support.patch \
     file://1661-Add-trngv2-driver-support.patch \
+    file://1662-trng-Add-trng-support-for-mt7988.patch \
     file://2000-misc-add-mtk-platform.patch \
     file://400-mtd-add-mtk-snand-driver.patch \
     file://401-pinctrl-add-mt7986-driver.patch \
+    file://401-pinctrl-enable-mt7988-pinctrl-config.patch \
     file://402-pinctrl-add-mt7981-driver.patch \
     file://412-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB-and-GD5F1GQ5UExxG.patch \
     file://413-mtd-spinand-gigadevice-Add-support-for-GD5FxGQxUExxG-GD5FxGQxUExxH-and-GD5FxGMxUExxG-series.patch \
     file://414-mtd-spinand-fix-gigadevice-read-dummy.patch \
     file://415-mtd-spinand-fix-F50L1G41LB-ecc-check.patch \
     file://500-auxadc-add-auxadc-32k-clk.patch \
+    file://6001-mtk-thermal-add-lvts-support.patch \
     file://7000-fix-race-inside-napi-enable.patch \
     file://7001-net-make-napi-disable-symmetric-with-enable.patch \
     file://7002-net-fix-premature-exit-from-napi-state-polling-in-napi-disable-v2.patch \
@@ -91,8 +103,12 @@
     file://744-en8801s-gphy-support.patch \
     file://745-en8801sc-gphy-support.patch \
     file://745-mdiobus-add-c45.patch \
+    file://746-add-mediatek-2p5ge-phy-support.patch \
     file://746-mxl-gpy-phy-support.patch \
     file://747-net-phy-aquantia-add-AQR113C.patch \
+    file://748-add-netlink-support-for-dsa.patch \
+    file://749-net-dsa-support-mt7988.patch \
+    file://750-add-mdio-bus-for-phy-node.patch \
     file://8000-PATCH-1-4-tphy-support-type-switch-by-pericfg.patch \
     file://8001-PATCH-2-4-dt-bindings-phy-Add-PHY_TYPE_DP-definition.patch \
     file://8002-PATCH-3-4-dt-bindings-phy-Add-PHY_TYPE_XPCS-definition.patch \
@@ -103,6 +119,8 @@
     file://8007-phy-phy-mtk-tphy-Add-PCIe-2-lane-efuse-support.patch \
     file://8008-phy-phy-mtk-tphy-add-auto-load-valid-check-mechanism.patch \
     file://8010-ovs-support-flow-offload.patch \
+    file://8010-phy-phy-mtk-xsphy-support-type-switch-by-pericfg.patch \
+    file://9000-PATCH-1-1-xHCI-change-compliance-mode-de-emphasis-default-as-g.patch \
     file://9001-PATCH-1-2-xHCI-MT7986-USB-2.0-USBIF-compliance-toolkit.patch \
     file://9002-PATCH-1-1-usb-add-embedded-Host-feature-support.patch \
     file://9009-Add-spi-runtime-PM-support.patch \