From 027cdfa4869e252c6f2dbef992b14fa5bab4218c Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 31 Aug 2022 20:06:52 +0800 Subject: [PATCH 1113/1131] mt76: testmode: add pre-cal support Signed-off-by: StanleyYP Wang 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 0a88048..cb6ff17 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 58258e1..89c8570 100644 --- a/mt76.h +++ b/mt76.h @@ -636,6 +636,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 a8ce98c..f42946e 100644 --- a/mt76_connac_mcu.h +++ b/mt76_connac_mcu.h @@ -990,6 +990,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 f3e5681..88aaa16 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) @@ -155,6 +163,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 85450ea..8e3217b 100644 --- a/mt7915/mcu.c +++ b/mt7915/mcu.c @@ -387,6 +387,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; @@ -2901,7 +2904,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; /* @@ -2981,11 +2984,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 4336f20..b6c9fc5 100644 --- a/mt7915/mt7915.h +++ b/mt7915/mt7915.h @@ -406,6 +406,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; @@ -640,6 +644,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 e0ba088..a9e57e4 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, @@ -1580,18 +1581,16 @@ 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; u8 band = phy->mt76->band_idx; 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), }; @@ -1676,6 +1675,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%08lx] 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->mt76->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%08lx] 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) { @@ -1715,6 +2024,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) || @@ -1876,9 +2189,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.36.1