[rdk-b][common][bsp][Refactor and sync kernel/wifi from Openwrt]
[Description]
Refactor and sync kernel/wifi from Openwrt
[Release-log]
N/A
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
new file mode 100644
index 0000000..7ecdd8b
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/1112-mt76-testmode-add-pre-cal-support.patch
@@ -0,0 +1,846 @@
+From 3e0328c381fcaaa6e5fcf50494934c770d9ade49 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/1121] mt76: testmode: add pre-cal support
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: Ibfbbc3443de994eeb4daa5e364b0a90f5d7d3bcd
+---
+ eeprom.c | 6 +-
+ mt76.h | 1 +
+ mt76_connac_mcu.h | 1 +
+ mt7915/eeprom.h | 34 +++-
+ mt7915/mcu.c | 27 ++-
+ mt7915/mt7915.h | 5 +
+ mt7915/testmode.c | 425 +++++++++++++++++++++++++++++++++++++++++++++-
+ mt7915/testmode.h | 36 ++++
+ testmode.c | 15 +-
+ testmode.h | 17 ++
+ tools/fields.c | 8 +
+ 11 files changed, 562 insertions(+), 13 deletions(-)
+
+diff --git a/eeprom.c b/eeprom.c
+index 1e41b94..e083964 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)
+ }
+
+ #ifdef CONFIG_NL80211_TESTMODE
+- dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
+- dev->test_mtd.offset = offset;
++ if (len == dev->eeprom.size) {
++ dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
++ dev->test_mtd.offset = offset;
++ }
+ #endif
+
+ out_put_node:
+diff --git a/mt76.h b/mt76.h
+index d03f312..0ed4188 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -611,6 +611,7 @@ struct mt76_testmode_ops {
+ enum mt76_testmode_state new_state);
+ int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg);
+ int (*set_eeprom)(struct mt76_phy *phy, u32 offset, u8 *val, u8 action);
++ int (*dump_precal)(struct mt76_phy *phy, struct sk_buff *msg, int flag, int type);
+ };
+
+ struct mt76_testmode_entry_data {
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index cb1e94a..9789380 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -963,6 +963,7 @@ enum {
+
+ /* ext event table */
+ enum {
++ MCU_EXT_EVENT_RF_TEST = 0x4,
+ MCU_EXT_EVENT_PS_SYNC = 0x5,
+ 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 7578ac6..b980342 100644
+--- a/mt7915/eeprom.h
++++ b/mt7915/eeprom.h
+@@ -39,10 +39,18 @@ enum mt7915_eeprom_field {
+ };
+
+ #define MT_EE_WIFI_CAL_GROUP BIT(0)
+-#define MT_EE_WIFI_CAL_DPD GENMASK(2, 1)
++#define MT_EE_WIFI_CAL_DPD_2G BIT(2)
++#define MT_EE_WIFI_CAL_DPD_5G BIT(1)
++#define MT_EE_WIFI_CAL_DPD_6G BIT(3)
++#define MT_EE_WIFI_CAL_DPD GENMASK(3, 1)
+ #define MT_EE_CAL_UNIT 1024
+-#define MT_EE_CAL_GROUP_SIZE (49 * MT_EE_CAL_UNIT + 16)
+-#define MT_EE_CAL_DPD_SIZE (54 * MT_EE_CAL_UNIT)
++#define MT_EE_CAL_GROUP_SIZE_7915 (49 * MT_EE_CAL_UNIT + 16)
++#define MT_EE_CAL_GROUP_SIZE_7916 (54 * MT_EE_CAL_UNIT + 16)
++#define MT_EE_CAL_GROUP_SIZE_7975 (54 * MT_EE_CAL_UNIT + 16)
++#define MT_EE_CAL_GROUP_SIZE_7976 (94 * MT_EE_CAL_UNIT + 16)
++#define MT_EE_CAL_GROUP_SIZE_7916_6G (94 * MT_EE_CAL_UNIT + 16)
++#define MT_EE_CAL_DPD_SIZE_V1 (54 * MT_EE_CAL_UNIT)
++#define MT_EE_CAL_DPD_SIZE_V2 (300 * MT_EE_CAL_UNIT)
+
+ #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0)
+ #define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(7, 6)
+@@ -160,6 +168,26 @@ mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band)
+ return val & MT_EE_WIFI_CONF7_TSSI0_5G;
+ }
+
++static inline u32
++mt7915_get_cal_group_size(struct mt7915_dev *dev)
++{
++ u8 *eep = dev->mt76.eeprom.data;
++ u32 val;
++
++ if (is_mt7915(&dev->mt76)) {
++ return MT_EE_CAL_GROUP_SIZE_7915;
++ } else if (is_mt7916(&dev->mt76)) {
++ val = eep[MT_EE_WIFI_CONF + 1];
++ val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
++ return (val == MT_EE_V2_BAND_SEL_6GHZ) ? MT_EE_CAL_GROUP_SIZE_7916_6G :
++ MT_EE_CAL_GROUP_SIZE_7916;
++ } else if (mt7915_check_adie(dev, false)) {
++ return MT_EE_CAL_GROUP_SIZE_7976;
++ } else {
++ return MT_EE_CAL_GROUP_SIZE_7975;
++ }
++}
++
+ extern const u8 mt7915_sku_group_len[MAX_SKU_RATE_GROUP_NUM];
+
+ #endif
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index ecdc4fb..42b1abc 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)
+ case MCU_EXT_EVENT_BF_STATUS_READ:
+ mt7915_tm_txbf_status_read(dev, skb);
+ break;
++ case MCU_EXT_EVENT_RF_TEST:
++ mt7915_tm_rf_test_event(dev, skb);
++ break;
+ #endif
+ default:
+ break;
+@@ -2925,7 +2928,7 @@ int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
+ u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data;
+ u32 total = MT_EE_CAL_GROUP_SIZE;
+
+- if (1 || !(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_GROUP))
++ if (!(eep[offs] & MT_EE_WIFI_CAL_GROUP))
+ return 0;
+
+ /*
+@@ -3005,11 +3008,29 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
+ {
+ struct mt7915_dev *dev = phy->dev;
+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
+- u16 total = 2, center_freq = chandef->center_freq1;
++ enum nl80211_band band = chandef->chan->band;
++ u32 offs = is_mt7915(&dev->mt76) ? MT_EE_DO_PRE_CAL : MT_EE_DO_PRE_CAL_V2;
++ u16 center_freq = chandef->center_freq1;
+ u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data;
++ u8 dpd_mask, cal_num = is_mt7915(&dev->mt76) ? 2 : 3;
+ int idx;
+
+- if (1 || !(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD))
++ switch (band) {
++ case NL80211_BAND_2GHZ:
++ dpd_mask = MT_EE_WIFI_CAL_DPD_2G;
++ break;
++ case NL80211_BAND_5GHZ:
++ dpd_mask = MT_EE_WIFI_CAL_DPD_5G;
++ break;
++ case NL80211_BAND_6GHZ:
++ dpd_mask = MT_EE_WIFI_CAL_DPD_6G;
++ break;
++ default:
++ dpd_mask = 0;
++ break;
++ }
++
++ if (!(eep[offs] & dpd_mask))
+ return 0;
+
+ idx = mt7915_dpd_freq_idx(center_freq, chandef->width);
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index 99f364c..fc0621e 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -381,6 +381,10 @@ struct mt7915_dev {
+ struct rchan *relay_fwlog;
+
+ void *cal;
++ u32 cur_prek_offset;
++ u8 dpd_chan_num_2g;
++ u8 dpd_chan_num_5g;
++ u8 dpd_chan_num_6g;
+
+ struct {
+ u8 debug_wm;
+@@ -617,6 +621,7 @@ 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);
+ void mt7915_mcu_exit(struct mt7915_dev *dev);
+ int mt7915_tm_txbf_status_read(struct mt7915_dev *dev, struct sk_buff *skb);
++void mt7915_tm_rf_test_event(struct mt7915_dev *dev, struct sk_buff *skb);
+
+ static inline u16 mt7915_wtbl_size(struct mt7915_dev *dev)
+ {
+diff --git a/mt7915/testmode.c b/mt7915/testmode.c
+index bc4cd80..7a49608 100644
+--- a/mt7915/testmode.c
++++ b/mt7915/testmode.c
+@@ -5,6 +5,7 @@
+ #include "mac.h"
+ #include "mcu.h"
+ #include "testmode.h"
++#include "eeprom.h"
+
+ enum {
+ TM_CHANGED_TXPOWER,
+@@ -1578,17 +1579,15 @@ mt7915_tm_rf_switch_mode(struct mt7915_dev *dev, u32 oper)
+ static int
+ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en)
+ {
+-#define TX_CONT_START 0x05
+-#define TX_CONT_STOP 0x06
+ struct mt7915_dev *dev = phy->dev;
+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
+ int freq1 = ieee80211_frequency_to_channel(chandef->center_freq1);
+ struct mt76_testmode_data *td = &phy->mt76->test;
+- u32 func_idx = en ? TX_CONT_START : TX_CONT_STOP;
++ u32 func_idx = en ? RF_TEST_TX_CONT_START : RF_TEST_TX_CONT_STOP;
+ u8 rate_idx = td->tx_rate_idx, mode;
+ u16 rateval;
+ struct mt7915_tm_rf_test req = {
+- .action = 1,
++ .action = RF_ACT_IN_RFTEST,
+ .icap_len = 120,
+ .op.rf.func_idx = cpu_to_le32(func_idx),
+ };
+@@ -1672,6 +1671,316 @@ out:
+ sizeof(req), true);
+ }
+
++static int
++mt7915_tm_group_prek(struct mt7915_phy *phy, enum mt76_testmode_state state)
++{
++ u8 *eeprom;
++ u32 i, group_size, dpd_size, size, offs, *pre_cal;
++ int ret = 0;
++ struct mt7915_dev *dev = phy->dev;
++ struct mt76_dev *mdev = &dev->mt76;
++ struct mt7915_tm_rf_test req = {
++ .action = RF_ACT_IN_RFTEST,
++ .icap_len = 8,
++ .op.rf.func_idx = cpu_to_le32(RF_TEST_RE_CAL),
++ };
++
++ if (!dev->flash_mode && !dev->bin_file_mode) {
++ dev_err(dev->mt76.dev, "Currently not in FLASH or BIN MODE,return!\n");
++ return 1;
++ }
++
++ eeprom = mdev->eeprom.data;
++ dev->cur_prek_offset = 0;
++ group_size = mt7915_get_cal_group_size(dev);
++ dpd_size = is_mt7915(&dev->mt76) ? MT_EE_CAL_DPD_SIZE_V1 : MT_EE_CAL_DPD_SIZE_V2;
++ size = group_size + dpd_size;
++ offs = is_mt7915(&dev->mt76) ? MT_EE_DO_PRE_CAL : MT_EE_DO_PRE_CAL_V2;
++
++ switch (state) {
++ case MT76_TM_STATE_GROUP_PREK:
++ req.op.rf.param.cal_param.func_data = cpu_to_le32(RF_PRE_CAL);
++
++ if (!dev->cal) {
++ dev->cal = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
++ if (!dev->cal)
++ return -ENOMEM;
++ }
++
++ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req,
++ sizeof(req), true);
++
++ if (!ret)
++ eeprom[offs] |= MT_EE_WIFI_CAL_GROUP;
++ break;
++ case MT76_TM_STATE_GROUP_PREK_DUMP:
++ pre_cal = (u32 *)dev->cal;
++ if (!pre_cal) {
++ dev_info(dev->mt76.dev, "Not group pre-cal yet!\n");
++ return ret;
++ }
++ dev_info(dev->mt76.dev, "Group Pre-Cal:\n");
++ for (i = 0; i < (group_size / sizeof(u32)); i += 4) {
++ dev_info(dev->mt76.dev, "[0x%08x] 0x%8x 0x%8x 0x%8x 0x%8x\n",
++ i * sizeof(u32), pre_cal[i], pre_cal[i + 1],
++ pre_cal[i + 2], pre_cal[i + 3]);
++ }
++ break;
++ case MT76_TM_STATE_GROUP_PREK_CLEAN:
++ pre_cal = (u32 *)dev->cal;
++ if (!pre_cal)
++ return ret;
++ memset(pre_cal, 0, group_size);
++ eeprom[offs] &= ~MT_EE_WIFI_CAL_GROUP;
++ break;
++ default:
++ return -EINVAL;
++ }
++ return ret;
++}
++
++static int
++mt7915_tm_dpd_prek(struct mt7915_phy *phy, enum mt76_testmode_state state)
++{
++#define DPD_2G_CH_BW20_BITMAP_0 0x444
++#define DPD_5G_CH_BW20_BITMAP_0 0xffffc0ff
++#define DPD_5G_CH_BW20_BITMAP_1 0x3
++#define DPD_5G_CH_BW20_BITMAP_7915_0 0x7dffc0ff
++#define DPD_6G_CH_BW20_BITMAP_0 0xffffffff
++#define DPD_6G_CH_BW20_BITMAP_1 0x07ffffff
++ bool is_set = false;
++ u8 band, do_precal, *eeprom;
++ u16 bw20_size, bw160_size;
++ u32 i, j, *bw160_freq, bw160_5g_freq[] = {5250, 5570, 5815};
++ u32 bw160_6g_freq[] = {6025, 6185, 6345, 6505, 6665, 6825, 6985};
++ u32 shift, freq, group_size, dpd_size, size, offs, *pre_cal, dpd_ch_bw20_bitmap[2] = {0};
++ __le32 func_data = 0;
++ int ret = 0;
++ struct mt7915_dev *dev = phy->dev;
++ struct mt76_dev *mdev = &dev->mt76;
++ struct mt76_phy *mphy = phy->mt76;
++ struct cfg80211_chan_def chandef_backup, *chandef = &mphy->chandef;
++ struct ieee80211_channel chan_backup, chan, *bw20_ch;
++ struct mt7915_tm_rf_test req = {
++ .action = RF_ACT_IN_RFTEST,
++ .icap_len = 8,
++ .op.rf.func_idx = cpu_to_le32(RF_TEST_RE_CAL),
++ };
++
++ if (!dev->flash_mode && !dev->bin_file_mode) {
++ dev_err(dev->mt76.dev, "Currently not in FLASH or BIN MODE,return!\n");
++ return -EOPNOTSUPP;
++ }
++
++ eeprom = mdev->eeprom.data;
++ dev->cur_prek_offset = 0;
++ group_size = mt7915_get_cal_group_size(dev);
++ dev->dpd_chan_num_2g = hweight32(DPD_2G_CH_BW20_BITMAP_0);
++ if (is_mt7915(&dev->mt76)) {
++ dev->dpd_chan_num_5g = hweight32(DPD_5G_CH_BW20_BITMAP_7915_0);
++ dev->dpd_chan_num_6g = 0;
++ dpd_size = MT_EE_CAL_DPD_SIZE_V1;
++ offs = MT_EE_DO_PRE_CAL;
++ } else {
++ dev->dpd_chan_num_5g = hweight32(DPD_5G_CH_BW20_BITMAP_0) +
++ hweight32(DPD_5G_CH_BW20_BITMAP_1) +
++ ARRAY_SIZE(bw160_5g_freq);
++ dev->dpd_chan_num_6g = hweight32(DPD_6G_CH_BW20_BITMAP_0) +
++ hweight32(DPD_6G_CH_BW20_BITMAP_1) +
++ ARRAY_SIZE(bw160_6g_freq);
++ dpd_size = MT_EE_CAL_DPD_SIZE_V2;
++ offs = MT_EE_DO_PRE_CAL_V2;
++ }
++ size = group_size + dpd_size;
++
++ switch (state) {
++ case MT76_TM_STATE_DPD_2G:
++ if (!is_set) {
++ func_data = cpu_to_le32(RF_DPD_FLAT_CAL);
++ dpd_ch_bw20_bitmap[0] = DPD_2G_CH_BW20_BITMAP_0;
++ bw20_ch = mphy->sband_2g.sband.channels;
++ bw160_freq = NULL;
++ bw160_size = 0;
++ band = NL80211_BAND_2GHZ;
++ do_precal = MT_EE_WIFI_CAL_DPD_2G;
++ is_set = true;
++ }
++ fallthrough;
++ case MT76_TM_STATE_DPD_5G:
++ if (!is_set) {
++ if (is_mt7915(&dev->mt76)) {
++ func_data = cpu_to_le32(RF_DPD_FLAT_CAL);
++ dpd_ch_bw20_bitmap[0] = DPD_5G_CH_BW20_BITMAP_7915_0;
++ bw160_size = 0;
++ dev->cur_prek_offset -= dev->dpd_chan_num_5g * MT_EE_CAL_UNIT * 2;
++ } else {
++ func_data = cpu_to_le32(RF_DPD_FLAT_5G_CAL);
++ dpd_ch_bw20_bitmap[0] = DPD_5G_CH_BW20_BITMAP_0;
++ dpd_ch_bw20_bitmap[1] = DPD_5G_CH_BW20_BITMAP_1;
++ bw160_size = ARRAY_SIZE(bw160_5g_freq);
++ }
++ bw20_ch = mphy->sband_5g.sband.channels;
++ bw160_freq = bw160_5g_freq;
++ band = NL80211_BAND_5GHZ;
++ do_precal = MT_EE_WIFI_CAL_DPD_5G;
++ is_set = true;
++ }
++ fallthrough;
++ case MT76_TM_STATE_DPD_6G:
++ if (!is_set) {
++ func_data = cpu_to_le32(RF_DPD_FLAT_6G_CAL);
++ dpd_ch_bw20_bitmap[0] = DPD_6G_CH_BW20_BITMAP_0;
++ dpd_ch_bw20_bitmap[1] = DPD_6G_CH_BW20_BITMAP_1;
++ bw20_ch = mphy->sband_6g.sband.channels;
++ bw160_freq = bw160_6g_freq;
++ bw160_size = ARRAY_SIZE(bw160_6g_freq);
++ band = NL80211_BAND_6GHZ;
++ do_precal = MT_EE_WIFI_CAL_DPD_6G;
++ is_set = true;
++ }
++
++ if (!bw20_ch)
++ return -EOPNOTSUPP;
++ if (!dev->cal) {
++ dev->cal = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
++ if (!dev->cal)
++ return -ENOMEM;
++ }
++
++ req.op.rf.param.cal_param.func_data = func_data;
++ req.op.rf.param.cal_param.band_idx = phy->band_idx;
++
++ memcpy(&chan_backup, chandef->chan, sizeof(struct ieee80211_channel));
++ memcpy(&chandef_backup, chandef, sizeof(struct cfg80211_chan_def));
++
++ bw20_size = hweight32(dpd_ch_bw20_bitmap[0]) + hweight32(dpd_ch_bw20_bitmap[1]);
++ for (i = 0, j = 0; i < bw20_size + bw160_size; i++) {
++ if (i < bw20_size) {
++ freq = dpd_ch_bw20_bitmap[0] ? 0 : 1;
++ shift = ffs(dpd_ch_bw20_bitmap[freq]);
++ j += shift;
++ memcpy(&chan, &bw20_ch[j - 1], sizeof(struct ieee80211_channel));
++ chandef->width = NL80211_CHAN_WIDTH_20;
++ dpd_ch_bw20_bitmap[0] >>= shift;
++ } else {
++ freq = bw160_freq[i - bw20_size];
++ chan.center_freq = freq;
++ chan.hw_value = ieee80211_frequency_to_channel(freq);
++ chan.band = band;
++ chandef->width = NL80211_CHAN_WIDTH_160;
++ }
++
++ memcpy(chandef->chan, &chan, sizeof(struct ieee80211_channel));
++ if (is_mt7915(&dev->mt76))
++ mphy->hw->conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
++ else
++ mphy->hw->conf.flags |= IEEE80211_CONF_OFFCHANNEL;
++
++ mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH));
++
++ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req,
++ sizeof(req), true);
++ if (ret) {
++ dev_err(dev->mt76.dev, "DPD Pre-cal: mcu send msg failed!\n");
++ break;
++ }
++ }
++ memcpy(chandef, &chandef_backup, sizeof(struct cfg80211_chan_def));
++ memcpy(chandef->chan, &chan_backup, sizeof(struct ieee80211_channel));
++ mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH));
++
++ if (!ret)
++ eeprom[offs] |= do_precal;
++
++ break;
++ case MT76_TM_STATE_DPD_DUMP:
++ pre_cal = (u32 *)dev->cal;
++ if (!dev->cal) {
++ dev_info(dev->mt76.dev, "Not DPD pre-cal yet!\n");
++ return ret;
++ }
++ dev_info(dev->mt76.dev, "DPD Pre-Cal:\n");
++ for (i = 0; i < dpd_size / sizeof(u32); i += 4) {
++ j = i + (group_size / sizeof(u32));
++ dev_info(dev->mt76.dev, "[0x%08x] 0x%8x 0x%8x 0x%8x 0x%8x\n",
++ j * sizeof(u32), pre_cal[j], pre_cal[j + 1],
++ pre_cal[j + 2], pre_cal[j + 3]);
++ }
++ break;
++ case MT76_TM_STATE_DPD_CLEAN:
++ pre_cal = (u32 *)dev->cal;
++ if (!pre_cal)
++ return ret;
++ memset(pre_cal + (group_size / sizeof(u32)), 0, dpd_size);
++ do_precal = MT_EE_WIFI_CAL_DPD;
++ eeprom[offs] &= ~do_precal;
++ break;
++ default:
++ return -EINVAL;
++ }
++ return ret;
++}
++
++void mt7915_tm_re_cal_event(struct mt7915_dev *dev, struct mt7915_tm_rf_test_result *result,
++ struct mt7915_tm_rf_test_data *data)
++{
++#define DPD_PER_CHAN_SIZE_7915 2
++#define DPD_PER_CHAN_SIZE_7986 3
++ u32 base, dpd_offest_2g, dpd_offest_5g, cal_idx = 0, cal_type = 0, len = 0;
++ u8 *pre_cal;
++
++ pre_cal = dev->cal;
++ dpd_offest_5g = dev->dpd_chan_num_6g * DPD_PER_CHAN_SIZE_7986 * MT_EE_CAL_UNIT;
++ dpd_offest_2g = dpd_offest_5g + dev->dpd_chan_num_5g * MT_EE_CAL_UNIT *
++ (is_mt7915(&dev->mt76) ? DPD_PER_CHAN_SIZE_7915 : DPD_PER_CHAN_SIZE_7986);
++ cal_idx = le32_to_cpu(data->cal_idx);
++ cal_type = le32_to_cpu(data->cal_type);
++ len = le32_to_cpu(result->payload_len);
++ len = len - sizeof(struct mt7915_tm_rf_test_data);
++
++ switch (cal_type) {
++ case RF_PRE_CAL:
++ base = 0;
++ break;
++ case RF_DPD_FLAT_CAL:
++ base = mt7915_get_cal_group_size(dev) + dpd_offest_2g;
++ break;
++ case RF_DPD_FLAT_5G_CAL:
++ base = mt7915_get_cal_group_size(dev) + dpd_offest_5g;
++ break;
++ case RF_DPD_FLAT_6G_CAL:
++ base = mt7915_get_cal_group_size(dev);
++ break;
++ default:
++ dev_info(dev->mt76.dev, "Unknown calibration type!\n");
++ return;
++ }
++ pre_cal += (base + dev->cur_prek_offset);
++
++ memcpy(pre_cal, data->data, len);
++ dev->cur_prek_offset += len;
++}
++
++void mt7915_tm_rf_test_event(struct mt7915_dev *dev, struct sk_buff *skb)
++{
++ struct mt7915_tm_rf_test_result *result;
++ struct mt7915_tm_rf_test_data *data;
++ static u32 event_type;
++
++ result = (struct mt7915_tm_rf_test_result *)skb->data;
++ data = (struct mt7915_tm_rf_test_data *)result->event;
++
++ event_type = le32_to_cpu(result->func_idx);
++
++ switch (event_type) {
++ case RF_TEST_RE_CAL:
++ mt7915_tm_re_cal_event(dev, result, data);
++ break;
++ default:
++ break;
++ }
++}
++
+ static void
+ mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed)
+ {
+@@ -1711,6 +2020,10 @@ mt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
+ else if (prev_state == MT76_TM_STATE_OFF ||
+ state == MT76_TM_STATE_OFF)
+ mt7915_tm_init(phy, !(state == MT76_TM_STATE_OFF));
++ else if (state >= MT76_TM_STATE_GROUP_PREK && state <= MT76_TM_STATE_GROUP_PREK_CLEAN)
++ return mt7915_tm_group_prek(phy, state);
++ else if (state >= MT76_TM_STATE_DPD_2G && state <= MT76_TM_STATE_DPD_CLEAN)
++ return mt7915_tm_dpd_prek(phy, state);
+
+ if ((state == MT76_TM_STATE_IDLE &&
+ prev_state == MT76_TM_STATE_OFF) ||
+@@ -1872,9 +2185,113 @@ mt7915_tm_set_eeprom(struct mt76_phy *mphy, u32 offset, u8 *val, u8 action)
+ return ret;
+ }
+
++static int
++mt7915_tm_dump_precal(struct mt76_phy *mphy, struct sk_buff *msg, int flag, int type)
++{
++#define DPD_PER_CHAN_SIZE_MASK GENMASK(31, 24)
++#define DPD_CHAN_NUM_2G_MASK GENMASK(23, 16)
++#define DPD_CHAN_NUM_5G_MASK GENMASK(15, 8)
++#define DPD_CHAN_NUM_6G_MASK GENMASK(7, 0)
++ struct mt7915_phy *phy = mphy->priv;
++ struct mt7915_dev *dev = phy->dev;
++ u32 i, group_size, dpd_size, total_size, dpd_per_chan_size, dpd_info = 0;
++ u32 base, size, total_chan_num, offs, transmit_size = 1000;
++ u8 *pre_cal, *eeprom;
++ void *precal;
++ enum prek_ops {
++ PREK_GET_INFO,
++ PREK_SYNC_ALL,
++ PREK_SYNC_GROUP,
++ PREK_SYNC_DPD_2G,
++ PREK_SYNC_DPD_5G,
++ PREK_SYNC_DPD_6G,
++ PREK_CLEAN_GROUP,
++ PREK_CLEAN_DPD,
++ };
++
++ if (!dev->cal) {
++ dev_info(dev->mt76.dev, "Not pre-cal yet!\n");
++ return 0;
++ }
++
++ group_size = mt7915_get_cal_group_size(dev);
++ dpd_size = is_mt7915(&dev->mt76) ? MT_EE_CAL_DPD_SIZE_V1 : MT_EE_CAL_DPD_SIZE_V2;
++ dpd_per_chan_size = is_mt7915(&dev->mt76) ? 2 : 3;
++ total_size = group_size + dpd_size;
++ pre_cal = dev->cal;
++ eeprom = dev->mt76.eeprom.data;
++ offs = is_mt7915(&dev->mt76) ? MT_EE_DO_PRE_CAL : MT_EE_DO_PRE_CAL_V2;
++
++ total_chan_num = dev->dpd_chan_num_2g + dev->dpd_chan_num_5g + dev->dpd_chan_num_6g;
++
++ switch (type) {
++ case PREK_SYNC_ALL:
++ base = 0;
++ size = total_size;
++ break;
++ case PREK_SYNC_GROUP:
++ base = 0;
++ size = group_size;
++ break;
++ case PREK_SYNC_DPD_6G:
++ base = group_size;
++ size = dpd_size * dev->dpd_chan_num_6g / total_chan_num;
++ break;
++ case PREK_SYNC_DPD_5G:
++ base = group_size + dev->dpd_chan_num_6g * dpd_per_chan_size * MT_EE_CAL_UNIT;
++ size = dpd_size * dev->dpd_chan_num_5g / total_chan_num;
++ break;
++ case PREK_SYNC_DPD_2G:
++ base = group_size + (dev->dpd_chan_num_6g + dev->dpd_chan_num_5g) *
++ dpd_per_chan_size * MT_EE_CAL_UNIT;
++ size = dpd_size * dev->dpd_chan_num_2g / total_chan_num;
++ break;
++ case PREK_GET_INFO:
++ break;
++ default:
++ return 0;
++ }
++
++ if (!flag) {
++ if (eeprom[offs] & MT_EE_WIFI_CAL_DPD) {
++ dpd_info |= u32_encode_bits(dpd_per_chan_size, DPD_PER_CHAN_SIZE_MASK) |
++ u32_encode_bits(dev->dpd_chan_num_2g, DPD_CHAN_NUM_2G_MASK) |
++ u32_encode_bits(dev->dpd_chan_num_5g, DPD_CHAN_NUM_5G_MASK) |
++ u32_encode_bits(dev->dpd_chan_num_6g, DPD_CHAN_NUM_6G_MASK);
++ }
++ dev->cur_prek_offset = 0;
++ precal = nla_nest_start(msg, MT76_TM_ATTR_PRECAL_INFO);
++ if (!precal)
++ return -ENOMEM;
++ nla_put_u32(msg, 0, group_size);
++ nla_put_u32(msg, 1, dpd_size);
++ nla_put_u32(msg, 2, dpd_info);
++ nla_put_u32(msg, 3, transmit_size);
++ nla_put_u32(msg, 4, eeprom[offs]);
++ nla_nest_end(msg, precal);
++ } else {
++ precal = nla_nest_start(msg, MT76_TM_ATTR_PRECAL);
++ if (!precal)
++ return -ENOMEM;
++
++ transmit_size = (dev->cur_prek_offset + transmit_size < size) ?
++ transmit_size : (size - dev->cur_prek_offset);
++ for (i = 0; i < transmit_size; i++) {
++ if (nla_put_u8(msg, i, pre_cal[base + dev->cur_prek_offset + i]))
++ return -ENOMEM;
++ }
++ dev->cur_prek_offset += transmit_size;
++
++ nla_nest_end(msg, precal);
++ }
++
++ return 0;
++}
++
+ const struct mt76_testmode_ops mt7915_testmode_ops = {
+ .set_state = mt7915_tm_set_state,
+ .set_params = mt7915_tm_set_params,
+ .dump_stats = mt7915_tm_dump_stats,
+ .set_eeprom = mt7915_tm_set_eeprom,
++ .dump_precal = mt7915_tm_dump_precal,
+ };
+diff --git a/mt7915/testmode.h b/mt7915/testmode.h
+index 01b08e9..d500987 100644
+--- a/mt7915/testmode.h
++++ b/mt7915/testmode.h
+@@ -81,6 +81,11 @@ struct tm_tx_cont {
+ u8 txfd_mode;
+ };
+
++struct tm_cal_param {
++ __le32 func_data;
++ u8 band_idx;
++};
++
+ struct mt7915_tm_rf_test {
+ u8 action;
+ u8 icap_len;
+@@ -96,6 +101,7 @@ struct mt7915_tm_rf_test {
+ __le32 cal_dump;
+
+ struct tm_tx_cont tx_cont;
++ struct tm_cal_param cal_param;
+
+ u8 _pad[80];
+ } param;
+@@ -103,6 +109,20 @@ struct mt7915_tm_rf_test {
+ } op;
+ } __packed;
+
++struct mt7915_tm_rf_test_result {
++ struct mt76_connac2_mcu_rxd rxd;
++
++ u32 func_idx;
++ u32 payload_len;
++ u8 event[0];
++} __packed;
++
++struct mt7915_tm_rf_test_data {
++ u32 cal_idx;
++ u32 cal_type;
++ u8 data[0];
++} __packed;
++
+ enum {
+ RF_OPER_NORMAL,
+ RF_OPER_RF_TEST,
+@@ -111,6 +131,22 @@ enum {
+ RF_OPER_WIFI_SPECTRUM,
+ };
+
++enum {
++ RF_ACT_SWITCH_MODE,
++ RF_ACT_IN_RFTEST,
++};
++
++enum {
++ RF_TEST_RE_CAL = 0x01,
++ RF_TEST_TX_CONT_START = 0x05,
++ RF_TEST_TX_CONT_STOP = 0x06,
++};
++
++#define RF_DPD_FLAT_CAL BIT(28)
++#define RF_PRE_CAL BIT(29)
++#define RF_DPD_FLAT_5G_CAL GENMASK(29, 28)
++#define RF_DPD_FLAT_6G_CAL (BIT(30) | BIT(28))
++
+ enum {
+ TAM_ARB_OP_MODE_NORMAL = 1,
+ TAM_ARB_OP_MODE_TEST,
+diff --git a/testmode.c b/testmode.c
+index 7a9ed54..82b8e98 100644
+--- a/testmode.c
++++ b/testmode.c
+@@ -763,6 +763,18 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
+
+ mutex_lock(&dev->mutex);
+
++ if (tb[MT76_TM_ATTR_PRECAL] || tb[MT76_TM_ATTR_PRECAL_INFO]) {
++ int flag, type;
++
++ err = -EINVAL;
++ flag = tb[MT76_TM_ATTR_PRECAL] ? 1 : 0;
++ type = flag ? nla_get_u8(tb[MT76_TM_ATTR_PRECAL_INFO]) : 0;
++ if (dev->test_ops->dump_precal)
++ err = dev->test_ops->dump_precal(phy, msg, flag, type);
++
++ goto out;
++ }
++
+ if (tb[MT76_TM_ATTR_STATS]) {
+ err = -EINVAL;
+
+@@ -796,7 +808,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
+
+ if (dev->test_mtd.name &&
+ (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, dev->test_mtd.name) ||
+- nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset)))
++ nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset) ||
++ nla_put_u8(msg, MT76_TM_ATTR_IS_MAIN_PHY, phy == &dev->phy)))
+ goto out;
+
+ 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
+--- a/testmode.h
++++ b/testmode.h
+@@ -19,6 +19,7 @@
+ *
+ * @MT76_TM_ATTR_MTD_PART: mtd partition used for eeprom data (string)
+ * @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32)
++ * @MT76_TM_ATTR_IS_MAIN_PHY: Is current phy index the main phy or the ext phy (u8)
+ *
+ * @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting
+ * state to MT76_TM_STATE_TX_FRAMES (u32)
+@@ -40,6 +41,11 @@
+ *
+ * @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr)
+ *
++ * @MT76_TM_ATTR_PRECAL: Pre-cal data (u8)
++ * @MT76_TM_ATTR_PRECAL_INFO: group size, dpd size, dpd_info, transmit size,
++ * eeprom cal indicator (u32),
++ * dpd_info = [dpd_per_chan_size, chan_num_2g,
++ * chan_num_5g, chan_num_6g]
+ * @MT76_TM_ATTR_TX_SPE_IDX: tx spatial extension index (u8)
+ *
+ * @MT76_TM_ATTR_TX_DUTY_CYCLE: packet tx duty cycle (u8)
+@@ -67,6 +73,7 @@ enum mt76_testmode_attr {
+
+ MT76_TM_ATTR_MTD_PART,
+ MT76_TM_ATTR_MTD_OFFSET,
++ MT76_TM_ATTR_IS_MAIN_PHY,
+
+ MT76_TM_ATTR_TX_COUNT,
+ MT76_TM_ATTR_TX_LENGTH,
+@@ -85,6 +92,8 @@ enum mt76_testmode_attr {
+ MT76_TM_ATTR_FREQ_OFFSET,
+
+ MT76_TM_ATTR_STATS,
++ MT76_TM_ATTR_PRECAL,
++ MT76_TM_ATTR_PRECAL_INFO,
+
+ MT76_TM_ATTR_TX_SPE_IDX,
+
+@@ -184,6 +193,14 @@ enum mt76_testmode_state {
+ MT76_TM_STATE_TX_FRAMES,
+ MT76_TM_STATE_RX_FRAMES,
+ MT76_TM_STATE_TX_CONT,
++ MT76_TM_STATE_GROUP_PREK,
++ MT76_TM_STATE_GROUP_PREK_DUMP,
++ MT76_TM_STATE_GROUP_PREK_CLEAN,
++ MT76_TM_STATE_DPD_2G,
++ MT76_TM_STATE_DPD_5G,
++ MT76_TM_STATE_DPD_6G,
++ MT76_TM_STATE_DPD_DUMP,
++ MT76_TM_STATE_DPD_CLEAN,
+ MT76_TM_STATE_ON,
+
+ /* keep last */
+diff --git a/tools/fields.c b/tools/fields.c
+index 6e36ab2..1be1ffd 100644
+--- a/tools/fields.c
++++ b/tools/fields.c
+@@ -11,6 +11,14 @@ static const char * const testmode_state[] = {
+ [MT76_TM_STATE_TX_FRAMES] = "tx_frames",
+ [MT76_TM_STATE_RX_FRAMES] = "rx_frames",
+ [MT76_TM_STATE_TX_CONT] = "tx_cont",
++ [MT76_TM_STATE_GROUP_PREK] = "group_prek",
++ [MT76_TM_STATE_GROUP_PREK_DUMP] = "group_prek_dump",
++ [MT76_TM_STATE_GROUP_PREK_CLEAN] = "group_prek_clean",
++ [MT76_TM_STATE_DPD_2G] = "dpd_2g",
++ [MT76_TM_STATE_DPD_5G] = "dpd_5g",
++ [MT76_TM_STATE_DPD_6G] = "dpd_6g",
++ [MT76_TM_STATE_DPD_DUMP] = "dpd_dump",
++ [MT76_TM_STATE_DPD_CLEAN] = "dpd_clean",
+ };
+
+ static const char * const testmode_tx_mode[] = {
+--
+2.18.0
+