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

[Description]
cc3c51c7 [MAC80211][wifi6][Release][Update MT7986 Firmware]
ea393925 [MAC80211[WiFi6/7]][hostapd][Avoid unnecessary beacon update]
6763be22 [MAC80211][wifi7][Misc][Sync Internal patches to External Release Folder]
d3ed9bc8 [mac80211][wifi7][mt76][Rebase WED patch due to Cheetah MT76 modifications]
2f4b03c3 [mac80211][wifi6][mt76][Bring-up hardware path for Cheetah MT76]
cb573d78 [MAC80211][WiFi7][app][Add ibf atenl support for eagle]
04fe6893 [mac80211][wifi6][mt76][Fix rebase errors]
c301e69a [MAC80211][WiFi7][mt76][Update Kite EEPROM bin files]
463b00fb [MAC80211][WiFi7][infra][Add slot1 for kite]
8774388d [MAC80211][WiFi7][misc][Prevent deadlock in a multiple AP+STA mode]
68d43fea [MAC80211][hostapd][show acs channels config]
5aca83c6 [MAC80211][hostapd][Prevent hostapd from setting beacon too frequently]
636da369 [MAC80211][wifi6/7][misc][use current epoch date]
9eb3456f [MAC80211][hostapd][refactor AP/STA CSA handling flow]
5543f3d8 [MAC80211][WiFi6][mt76][Refactor assignment of STA BSS group]
c5631fc2 [mac80211][mt76][wifi6][Add debugfs knob for RTS threshold]
6a92a2d4 [mac80211][wifi6][mt76][Bring-up software path for Cheetah MT76]
bf66c519 [MAC80211][netifd][Remove unnecessary netifd patch]
2f141c75 [mac80211][mt76][wifi6/7][Fix build failed]
cf30db1e [mac80211[hostapd][wifi7][Fix build fial]
dc391fc0 [MAC80211][wifi6][Release][Update MT7986 Firmware]
71a7b95a [MAC80211][WiFi7][mt76][Add kite fw & eeprom to eagle codebase]
5a7bd025 [MAC80211][WiFi6][misc][Add mt7981 default eeprom bin]
e40da697 [MAC80211][WED][Fix reinsert wifi module cause memory leak issue]
0a22f8f4 [MAC80211][WiFi7][misc][fix mt7988-mt7996-mac980211 release build fail]
25f3fe1c [[Eagle][SQC3.0][BE19000][MT7996][E2][MT7976_MT7977][256][ePA][MT7988A][WiFi] [MAP][SnS][Muti-client][UES]Traffic stuck in Agent2 with invalid tid 8 found]
f59b5dad [MAC80211][WiFi6][mt76][Add additional chain signal info in station dump for merlin]
fada400d [MAC80211][WiFi6/7][mt76][Add HT40- capab when enable ACS]
98e273af [MAC80211][WiFi6/7][app][Add SKU_EN & RSSI ATTR in atenl]
aaa8eb14 [MAC80211][WiFi6][mt76][Add rssi & sku_en in testmode]
eda14aac [MAC80211][core][Remove wrong assignment on the variable "changed" when changing beacon]
000329aa [MAC80211][netifd][Move netifd patch for wifi7 used only]
57bfe0c7 [MAC80211][WiFi6][misc][fix build fail due to mt76 upgration]
fa29bb39 [MAC80211][wifi6/7][mt76][update mt76 Makefile]
56f497ec [MAC80211][netifd][not to cache previous config to avoid wifi down failure]
be9abd4d [MAC80211][WiFi6][misc][fix build fail due to netifd]
af71e303 [MAC80211][WiFi6][mt76][Fix inconsistent BSS group setting of STA for VoW]
3e42972a [MAC80211][WiFi6][mt76][Fix txpower bbp CR]
81a68c03 [MAC80211][wifi7][hostapd][rebase internal hostapd patches]
336300b7 [MAC80211][WiFi6/7][hostapd][MAX 48 mbss 6G 连线概率连不上 ]
6bebc554 [MAC80211][wifi7][core][update for backports v6.5]
19daecfd [MAC80211][wifi7][ucode][Bandwidth Synchronization in AP/STA Mode]
ddf64afb [MAC80211][mt76][add debug log in SER flow]
44611a77 [mac80211][wifi6][mt76][Enhance debug log]

[Release-log]

Change-Id: Ibf5e835de5563fff4101a77e81056f696286670b
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1006-wifi-mt76-mt7996-add-txpower-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1006-wifi-mt76-mt7996-add-txpower-support.patch
new file mode 100644
index 0000000..0a0d376
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/1006-wifi-mt76-mt7996-add-txpower-support.patch
@@ -0,0 +1,573 @@
+From 1c1dd57bde8919fdf04ef914b781eb6183582562 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Fri, 24 Mar 2023 23:35:30 +0800
+Subject: [PATCH 39/98] wifi: mt76: mt7996: add txpower support
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: Ic3e7b17f3664fa7f774137572f885359fa2ec93b
+---
+ mt7996/eeprom.c      |  34 +++++++
+ mt7996/eeprom.h      |  42 ++++++++
+ mt7996/mcu.h         |   2 +
+ mt7996/mt7996.h      |   3 +
+ mt7996/mtk_debugfs.c | 229 +++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mtk_mcu.c     |  23 +++++
+ mt7996/mtk_mcu.h     |  78 +++++++++++++++
+ mt7996/regs.h        |  29 +++---
+ 8 files changed, 429 insertions(+), 11 deletions(-)
+
+diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
+index 3276740..e4c4b86 100644
+--- a/mt7996/eeprom.c
++++ b/mt7996/eeprom.c
+@@ -296,3 +296,37 @@ s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band)
+ 
+ 	return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta;
+ }
++
++const u8 mt7996_sku_group_len[] = {
++	[SKU_CCK] = 4,
++	[SKU_OFDM] = 8,
++	[SKU_HT20] = 8,
++	[SKU_HT40] = 9,
++	[SKU_VHT20] = 12,
++	[SKU_VHT40] = 12,
++	[SKU_VHT80] = 12,
++	[SKU_VHT160] = 12,
++	[SKU_HE26] = 12,
++	[SKU_HE52] = 12,
++	[SKU_HE106] = 12,
++	[SKU_HE242] = 12,
++	[SKU_HE484] = 12,
++	[SKU_HE996] = 12,
++	[SKU_HE2x996] = 12,
++	[SKU_EHT26] = 16,
++	[SKU_EHT52] = 16,
++	[SKU_EHT106] = 16,
++	[SKU_EHT242] = 16,
++	[SKU_EHT484] = 16,
++	[SKU_EHT996] = 16,
++	[SKU_EHT2x996] = 16,
++	[SKU_EHT4x996] = 16,
++	[SKU_EHT26_52] = 16,
++	[SKU_EHT26_106] = 16,
++	[SKU_EHT484_242] = 16,
++	[SKU_EHT996_484] = 16,
++	[SKU_EHT996_484_242] = 16,
++	[SKU_EHT2x996_484] = 16,
++	[SKU_EHT3x996] = 16,
++	[SKU_EHT3x996_484] = 16,
++};
+diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
+index 9ea3667..343e65e 100644
+--- a/mt7996/eeprom.h
++++ b/mt7996/eeprom.h
+@@ -75,4 +75,46 @@ mt7996_get_channel_group_6g(int channel)
+ 	return DIV_ROUND_UP(channel - 29, 32);
+ }
+ 
++enum mt7996_sku_rate_group {
++	SKU_CCK,
++	SKU_OFDM,
++
++	SKU_HT20,
++	SKU_HT40,
++
++	SKU_VHT20,
++	SKU_VHT40,
++	SKU_VHT80,
++	SKU_VHT160,
++
++	SKU_HE26,
++	SKU_HE52,
++	SKU_HE106,
++	SKU_HE242,
++	SKU_HE484,
++	SKU_HE996,
++	SKU_HE2x996,
++
++	SKU_EHT26,
++	SKU_EHT52,
++	SKU_EHT106,
++	SKU_EHT242,
++	SKU_EHT484,
++	SKU_EHT996,
++	SKU_EHT2x996,
++	SKU_EHT4x996,
++	SKU_EHT26_52,
++	SKU_EHT26_106,
++	SKU_EHT484_242,
++	SKU_EHT996_484,
++	SKU_EHT996_484_242,
++	SKU_EHT2x996_484,
++	SKU_EHT3x996,
++	SKU_EHT3x996_484,
++
++	MAX_SKU_RATE_GROUP_NUM,
++};
++
++extern const u8 mt7996_sku_group_len[MAX_SKU_RATE_GROUP_NUM];
++
+ #endif
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index ff9cc9c..71dc165 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -826,6 +826,7 @@ struct tx_power_ctrl {
+ 		bool ate_mode_enable;
+ 		bool percentage_ctrl_enable;
+ 		bool bf_backoff_enable;
++		u8 show_info_category;
+ 		u8 power_drop_level;
+ 	};
+ 	u8 band_idx;
+@@ -839,6 +840,7 @@ enum {
+ 	UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3,
+ 	UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
+ 	UNI_TXPOWER_ATE_MODE_CTRL = 6,
++	UNI_TXPOWER_SHOW_INFO = 7,
+ };
+ 
+ enum {
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index eb48dbd..23d1614 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -63,6 +63,8 @@
+ 
+ #define MT7996_BUILD_TIME_LEN		24
+ 
++#define MT7996_SKU_RATE_NUM		417
++
+ #define MT7996_RRO_MAX_SESSION		1024
+ #define MT7996_RRO_WINDOW_MAX_LEN	1024
+ #define MT7996_RRO_ADDR_ELEM_LEN	128
+@@ -568,6 +570,7 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
+ void mt7996_mcu_exit(struct mt7996_dev *dev);
+ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
+ int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data);
++int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event);
+ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable);
+ void mt7996_mcu_scs_sta_poll(struct work_struct *work);
+ 
+diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
+index 5aa5c94..57fcbab 100644
+--- a/mt7996/mtk_debugfs.c
++++ b/mt7996/mtk_debugfs.c
+@@ -2325,6 +2325,232 @@ static int mt7996_sta_info(struct seq_file *s, void *data)
+ 	return 0;
+ }
+ 
++static int
++mt7996_txpower_level_set(void *data, u64 val)
++{
++	struct mt7996_phy *phy = data;
++	int ret;
++
++	if (val > 100)
++		return -EINVAL;
++
++	ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_PERCENTAGE_CTRL, !!val);
++	if (ret)
++		return ret;
++
++	return mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_PERCENTAGE_DROP_CTRL, val);
++}
++
++DEFINE_DEBUGFS_ATTRIBUTE(fops_txpower_level, NULL,
++			 mt7996_txpower_level_set, "%lld\n");
++
++static ssize_t
++mt7996_get_txpower_info(struct file *file, char __user *user_buf,
++			size_t count, loff_t *ppos)
++{
++	struct mt7996_phy *phy = file->private_data;
++	struct mt7996_mcu_txpower_event *event;
++	struct txpower_basic_info *basic_info;
++	static const size_t size = 2048;
++	int len = 0;
++	ssize_t ret;
++	char *buf;
++
++	buf = kzalloc(size, GFP_KERNEL);
++	event = kzalloc(sizeof(*event), GFP_KERNEL);
++	if (!buf || !event)
++		return -ENOMEM;
++
++	ret = mt7996_mcu_get_tx_power_info(phy, BASIC_INFO, event);
++	if (ret ||
++	    le32_to_cpu(event->basic_info.category) != UNI_TXPOWER_BASIC_INFO)
++		goto out;
++
++	basic_info = &event->basic_info;
++
++	len += scnprintf(buf + len, size - len,
++			 "======================== BASIC INFO ========================\n");
++	len += scnprintf(buf + len, size - len, "    Band Index: %d, Channel Band: %d\n",
++			 basic_info->band_idx, basic_info->band);
++	len += scnprintf(buf + len, size - len, "    PA Type: %s\n",
++			 basic_info->is_epa ? "ePA" : "iPA");
++	len += scnprintf(buf + len, size - len, "    LNA Type: %s\n",
++			 basic_info->is_elna ? "eLNA" : "iLNA");
++
++	len += scnprintf(buf + len, size - len,
++			 "------------------------------------------------------------\n");
++	len += scnprintf(buf + len, size - len, "    SKU: %s\n",
++			 basic_info->sku_enable ? "enable" : "disable");
++	len += scnprintf(buf + len, size - len, "    Percentage Control: %s\n",
++			 basic_info->percentage_ctrl_enable ? "enable" : "disable");
++	len += scnprintf(buf + len, size - len, "    Power Drop: %d [dBm]\n",
++			 basic_info->power_drop_level >> 1);
++	len += scnprintf(buf + len, size - len, "    Backoff: %s\n",
++			 basic_info->bf_backoff_enable ? "enable" : "disable");
++	len += scnprintf(buf + len, size - len, "    TX Front-end Loss:  %d, %d, %d, %d\n",
++			 basic_info->front_end_loss_tx[0], basic_info->front_end_loss_tx[1],
++			 basic_info->front_end_loss_tx[2], basic_info->front_end_loss_tx[3]);
++	len += scnprintf(buf + len, size - len, "    RX Front-end Loss:  %d, %d, %d, %d\n",
++			 basic_info->front_end_loss_rx[0], basic_info->front_end_loss_rx[1],
++			 basic_info->front_end_loss_rx[2], basic_info->front_end_loss_rx[3]);
++	len += scnprintf(buf + len, size - len,
++			 "    MU TX Power Mode:  %s\n",
++			 basic_info->mu_tx_power_manual_enable ? "manual" : "auto");
++	len += scnprintf(buf + len, size - len,
++			 "    MU TX Power (Auto / Manual): %d / %d [0.5 dBm]\n",
++			 basic_info->mu_tx_power_auto, basic_info->mu_tx_power_manual);
++	len += scnprintf(buf + len, size - len,
++			 "    Thermal Compensation:  %s\n",
++			 basic_info->thermal_compensate_enable ? "enable" : "disable");
++	len += scnprintf(buf + len, size - len,
++			 "    Theraml Compensation Value: %d\n",
++			 basic_info->thermal_compensate_value);
++
++	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++out:
++	kfree(buf);
++	kfree(event);
++	return ret;
++}
++
++static const struct file_operations mt7996_txpower_info_fops = {
++	.read = mt7996_get_txpower_info,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
++#define mt7996_txpower_puts(rate)							\
++({											\
++	len += scnprintf(buf + len, size - len, "%-21s:", #rate " (TMAC)");		\
++	for (i = 0; i < mt7996_sku_group_len[SKU_##rate]; i++, offs++)			\
++		len += scnprintf(buf + len, size - len, " %6d",				\
++				 event->phy_rate_info.frame_power[offs][band_idx]);	\
++	len += scnprintf(buf + len, size - len, "\n");					\
++})
++
++static ssize_t
++mt7996_get_txpower_sku(struct file *file, char __user *user_buf,
++		       size_t count, loff_t *ppos)
++{
++	struct mt7996_phy *phy = file->private_data;
++	struct mt7996_dev *dev = phy->dev;
++	struct mt7996_mcu_txpower_event *event;
++	u8 band_idx = phy->mt76->band_idx;
++	static const size_t size = 5120;
++	int i, offs = 0, len = 0;
++	ssize_t ret;
++	char *buf;
++	u32 reg;
++
++	buf = kzalloc(size, GFP_KERNEL);
++	event = kzalloc(sizeof(*event), GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++
++	ret = mt7996_mcu_get_tx_power_info(phy, PHY_RATE_INFO, event);
++	if (ret ||
++	    le32_to_cpu(event->phy_rate_info.category) != UNI_TXPOWER_PHY_RATE_INFO)
++		goto out;
++
++	len += scnprintf(buf + len, size - len,
++			 "\nPhy %d TX Power Table (Channel %d)\n",
++			 band_idx, phy->mt76->chandef.chan->hw_value);
++	len += scnprintf(buf + len, size - len, "%-21s  %6s %6s %6s %6s\n",
++			 " ", "1m", "2m", "5m", "11m");
++	mt7996_txpower_puts(CCK);
++
++	len += scnprintf(buf + len, size - len,
++			 "%-21s  %6s %6s %6s %6s %6s %6s %6s %6s\n",
++			 " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",
++			 "54m");
++	mt7996_txpower_puts(OFDM);
++
++	len += scnprintf(buf + len, size - len,
++			 "%-21s  %6s %6s %6s %6s %6s %6s %6s %6s\n",
++			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",
++			 "mcs5", "mcs6", "mcs7");
++	mt7996_txpower_puts(HT20);
++
++	len += scnprintf(buf + len, size - len,
++			 "%-21s  %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
++			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
++			 "mcs6", "mcs7", "mcs32");
++	mt7996_txpower_puts(HT40);
++
++	len += scnprintf(buf + len, size - len,
++			 "%-21s  %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
++			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
++			 "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
++	mt7996_txpower_puts(VHT20);
++	mt7996_txpower_puts(VHT40);
++	mt7996_txpower_puts(VHT80);
++	mt7996_txpower_puts(VHT160);
++	mt7996_txpower_puts(HE26);
++	mt7996_txpower_puts(HE52);
++	mt7996_txpower_puts(HE106);
++	mt7996_txpower_puts(HE242);
++	mt7996_txpower_puts(HE484);
++	mt7996_txpower_puts(HE996);
++	mt7996_txpower_puts(HE2x996);
++
++	len += scnprintf(buf + len, size - len,
++			 "%-21s  %6s %6s %6s %6s %6s %6s %6s %6s ",
++			 " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", "mcs6", "mcs7");
++	len += scnprintf(buf + len, size - len,
++			 "%6s %6s %6s %6s %6s %6s %6s %6s\n",
++			 "mcs8", "mcs9", "mcs10", "mcs11", "mcs12", "mcs13", "mcs14", "mcs15");
++	mt7996_txpower_puts(EHT26);
++	mt7996_txpower_puts(EHT52);
++	mt7996_txpower_puts(EHT106);
++	mt7996_txpower_puts(EHT242);
++	mt7996_txpower_puts(EHT484);
++	mt7996_txpower_puts(EHT996);
++	mt7996_txpower_puts(EHT2x996);
++	mt7996_txpower_puts(EHT4x996);
++	mt7996_txpower_puts(EHT26_52);
++	mt7996_txpower_puts(EHT26_106);
++	mt7996_txpower_puts(EHT484_242);
++	mt7996_txpower_puts(EHT996_484);
++	mt7996_txpower_puts(EHT996_484_242);
++	mt7996_txpower_puts(EHT2x996_484);
++	mt7996_txpower_puts(EHT3x996);
++	mt7996_txpower_puts(EHT3x996_484);
++
++	len += scnprintf(buf + len, size - len, "\nePA Gain: %d\n",
++			 event->phy_rate_info.epa_gain);
++	len += scnprintf(buf + len, size - len, "Max Power Bound: %d\n",
++			 event->phy_rate_info.max_power_bound);
++	len += scnprintf(buf + len, size - len, "Min Power Bound: %d\n",
++			 event->phy_rate_info.min_power_bound);
++
++	reg = MT_WF_PHYDFE_BAND_TPC_CTRL_STAT0(band_idx);
++	len += scnprintf(buf + len, size - len,
++			 "BBP TX Power (target power from TMAC)  : %6ld [0.5 dBm]\n",
++			 mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_TMAC));
++	len += scnprintf(buf + len, size - len,
++			 "BBP TX Power (target power from RMAC)  : %6ld [0.5 dBm]\n",
++			 mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_RMAC));
++	len += scnprintf(buf + len, size - len,
++			 "BBP TX Power (TSSI module power input)  : %6ld [0.5 dBm]\n",
++			 mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_TSSI));
++
++	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++out:
++	kfree(buf);
++	kfree(event);
++	return ret;
++}
++
++static const struct file_operations mt7996_txpower_sku_fops = {
++	.read = mt7996_get_txpower_sku,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
+ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+ {
+ 	struct mt7996_dev *dev = phy->dev;
+@@ -2367,6 +2593,9 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+ 
+ 	debugfs_create_devm_seqfile(dev->mt76.dev, "tr_info", dir,
+ 				    mt7996_trinfo_read);
++	debugfs_create_file("txpower_level", 0600, dir, phy, &fops_txpower_level);
++	debugfs_create_file("txpower_info", 0600, dir, phy, &mt7996_txpower_info_fops);
++	debugfs_create_file("txpower_sku", 0600, dir, phy, &mt7996_txpower_sku_fops);
+ 
+ 	debugfs_create_devm_seqfile(dev->mt76.dev, "wtbl_info", dir,
+ 				    mt7996_wtbl_read);
+diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
+index e887016..f772243 100644
+--- a/mt7996/mtk_mcu.c
++++ b/mt7996/mtk_mcu.c
+@@ -12,7 +12,30 @@
+ 
+ #ifdef CONFIG_MTK_DEBUG
+ 
++int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event)
++{
++	struct mt7996_dev *dev = phy->dev;
++	struct tx_power_ctrl req = {
++		.tag = cpu_to_le16(UNI_TXPOWER_SHOW_INFO),
++		.len = cpu_to_le16(sizeof(req) - 4),
++		.power_ctrl_id = UNI_TXPOWER_SHOW_INFO,
++		.show_info_category = category,
++		.band_idx = phy->mt76->band_idx,
++	};
++	struct sk_buff *skb;
++	int ret;
+ 
++	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
++					MCU_WM_UNI_CMD_QUERY(TXPOWER),
++					&req, sizeof(req), true, &skb);
++	if (ret)
++		return ret;
+ 
++	memcpy(event, skb->data, sizeof(struct mt7996_mcu_txpower_event));
++
++	dev_kfree_skb(skb);
++
++	return 0;
++}
+ 
+ #endif
+diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
+index e741aa2..beb1aba 100644
+--- a/mt7996/mtk_mcu.h
++++ b/mt7996/mtk_mcu.h
+@@ -10,6 +10,84 @@
+ 
+ #ifdef CONFIG_MTK_DEBUG
+ 
++struct txpower_basic_info {
++	u8 category;
++	u8 rsv1;
++
++	/* basic info */
++	u8 band_idx;
++	u8 band;
++
++	/* board type info */
++	bool is_epa;
++	bool is_elna;
++
++	/* power percentage info */
++	bool percentage_ctrl_enable;
++	s8 power_drop_level;
++
++	/* frond-end loss TX info */
++	s8 front_end_loss_tx[4];
++
++	/* frond-end loss RX info */
++	s8 front_end_loss_rx[4];
++
++	/* thermal info */
++	bool thermal_compensate_enable;
++	s8 thermal_compensate_value;
++	u8 rsv2;
++
++	/* TX power max/min limit info */
++	s8 max_power_bound;
++	s8 min_power_bound;
++
++	/* power limit info */
++	bool sku_enable;
++	bool bf_backoff_enable;
++
++	/* MU TX power info */
++	bool mu_tx_power_manual_enable;
++	s8 mu_tx_power_auto;
++	s8 mu_tx_power_manual;
++	u8 rsv3;
++};
++
++struct txpower_phy_rate_info {
++	u8 category;
++	u8 band_idx;
++	u8 band;
++	u8 epa_gain;
++
++	/* rate power info [dBm] */
++	s8 frame_power[MT7996_SKU_RATE_NUM][__MT_MAX_BAND];
++
++	/* TX power max/min limit info */
++	s8 max_power_bound;
++	s8 min_power_bound;
++	u8 rsv1;
++};
++
++struct mt7996_mcu_txpower_event {
++	u8 _rsv[4];
++
++	__le16 tag;
++	__le16 len;
++
++	union {
++		struct txpower_basic_info basic_info;
++		struct txpower_phy_rate_info phy_rate_info;
++	};
++};
++
++enum txpower_category {
++	BASIC_INFO,
++	PHY_RATE_INFO = 2,
++};
++
++enum txpower_event {
++	UNI_TXPOWER_BASIC_INFO = 0,
++	UNI_TXPOWER_PHY_RATE_INFO = 5,
++};
+ 
+ #endif
+ 
+diff --git a/mt7996/regs.h b/mt7996/regs.h
+index de5df91..565022a 100644
+--- a/mt7996/regs.h
++++ b/mt7996/regs.h
+@@ -672,24 +672,31 @@ enum offs_rev {
+ 						 ((_wf) << 16) + (ofs))
+ #define MT_WF_PHYRX_CSD_IRPI(_band, _wf)	MT_WF_PHYRX_CSD(_band, _wf, 0x1000)
+ 
+-/* PHYRX CTRL */
+-#define MT_WF_PHYRX_BAND_BASE			0x83080000
+-#define MT_WF_PHYRX_BAND(_band, ofs)		(MT_WF_PHYRX_BAND_BASE + \
++/* PHY CTRL */
++#define MT_WF_PHY_BAND_BASE			0x83080000
++#define MT_WF_PHY_BAND(_band, ofs)		(MT_WF_PHY_BAND_BASE + \
+ 						 ((_band) << 20) + (ofs))
+ 
+-#define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band)	MT_WF_PHYRX_BAND(_band, 0x1054)
+-#define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band)	MT_WF_PHYRX_BAND(_band, 0x1058)
+-#define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band)	MT_WF_PHYRX_BAND(_band, 0x105c)
+-#define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band)	MT_WF_PHYRX_BAND(_band, 0x1060)
+-#define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band)	MT_WF_PHYRX_BAND(_band, 0x1064)
+-#define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band)	MT_WF_PHYRX_BAND(_band, 0x1068)
++#define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band)	MT_WF_PHY_BAND(_band, 0x1054)
++#define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band)	MT_WF_PHY_BAND(_band, 0x1058)
++#define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band)	MT_WF_PHY_BAND(_band, 0x105c)
++#define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band)	MT_WF_PHY_BAND(_band, 0x1060)
++#define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band)	MT_WF_PHY_BAND(_band, 0x1064)
++#define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band)	MT_WF_PHY_BAND(_band, 0x1068)
+ 
+-#define MT_WF_PHYRX_BAND_RX_CTRL1(_band)	MT_WF_PHYRX_BAND(_band, 0x2004)
++/* PHYRX CTRL */
++#define MT_WF_PHYRX_BAND_RX_CTRL1(_band)	MT_WF_PHY_BAND(_band, 0x2004)
+ #define MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN	GENMASK(2, 0)
+ #define MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN	GENMASK(11, 9)
+ 
++/* PHYDFE CTRL */
++#define MT_WF_PHYDFE_BAND_TPC_CTRL_STAT0(_phy)	MT_WF_PHY_BAND(_phy, 0xe7a0)
++#define MT_WF_PHY_TPC_POWER_TMAC		GENMASK(15, 8)
++#define MT_WF_PHY_TPC_POWER_RMAC		GENMASK(23, 16)
++#define MT_WF_PHY_TPC_POWER_TSSI		GENMASK(31, 24)
++
+ /* PHYRX CSD BAND */
+-#define MT_WF_PHYRX_CSD_BAND_RXTD12(_band)		MT_WF_PHYRX_BAND(_band, 0x8230)
++#define MT_WF_PHYRX_CSD_BAND_RXTD12(_band)		MT_WF_PHY_BAND(_band, 0x8230)
+ #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY	BIT(18)
+ #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR		BIT(29)
+ 
+-- 
+2.18.0
+