| From 43266cd8b1ba9bedd0541e994435017bb1bcbec6 Mon Sep 17 00:00:00 2001 |
| From: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| Date: Wed, 1 Mar 2023 12:12:51 +0800 |
| Subject: [PATCH 1012/1024] wifi: mt76: mt7996: add normal mode pre-calibration |
| support |
| |
| Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| --- |
| mt76_connac_mcu.h | 1 + |
| mt7996/eeprom.c | 23 +++++++ |
| mt7996/eeprom.h | 2 + |
| mt7996/init.c | 6 ++ |
| mt7996/main.c | 6 ++ |
| mt7996/mcu.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ |
| mt7996/mt7996.h | 2 + |
| 7 files changed, 206 insertions(+) |
| |
| diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h |
| index b2c22568d..196b4921d 100644 |
| --- a/mt76_connac_mcu.h |
| +++ b/mt76_connac_mcu.h |
| @@ -1248,6 +1248,7 @@ enum { |
| MCU_UNI_CMD_VOW = 0x37, |
| MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, |
| MCU_UNI_CMD_TESTMODE_CTRL = 0x46, |
| + MCU_UNI_CMD_PRECAL_RESULT = 0x47, |
| MCU_UNI_CMD_RRO = 0x57, |
| MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, |
| MCU_UNI_CMD_PER_STA_INFO = 0x6d, |
| diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c |
| index 4e50460be..ac8e229a8 100644 |
| --- a/mt7996/eeprom.c |
| +++ b/mt7996/eeprom.c |
| @@ -332,6 +332,25 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) |
| return mt7996_eeprom_parse_band_config(phy); |
| } |
| |
| +static int mt7996_eeprom_load_precal(struct mt7996_dev *dev) |
| +{ |
| + struct mt76_dev *mdev = &dev->mt76; |
| + u8 *eeprom = mdev->eeprom.data; |
| + u32 offs = MT_EE_DO_PRE_CAL; |
| + u32 size, val = eeprom[offs]; |
| + |
| + if (!dev->flash_mode || !val) |
| + return 0; |
| + |
| + size = MT_EE_CAL_GROUP_SIZE + MT_EE_CAL_DPD_SIZE; |
| + |
| + dev->cal = devm_kzalloc(mdev->dev, size, GFP_KERNEL); |
| + if (!dev->cal) |
| + return -ENOMEM; |
| + |
| + return mt76_get_of_eeprom(mdev, dev->cal, MT_EE_PRECAL, size); |
| +} |
| + |
| int mt7996_eeprom_init(struct mt7996_dev *dev) |
| { |
| int ret; |
| @@ -349,6 +368,10 @@ int mt7996_eeprom_init(struct mt7996_dev *dev) |
| return ret; |
| } |
| |
| + ret = mt7996_eeprom_load_precal(dev); |
| + if (ret) |
| + return ret; |
| + |
| ret = mt7996_eeprom_parse_hw_cap(dev, &dev->phy); |
| if (ret < 0) |
| return ret; |
| diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h |
| index 20dd87714..0f3f31d8f 100644 |
| --- a/mt7996/eeprom.h |
| +++ b/mt7996/eeprom.h |
| @@ -25,6 +25,8 @@ enum mt7996_eeprom_field { |
| MT_EE_TX0_POWER_6G = 0x1310, |
| |
| __MT_EE_MAX = 0x1dff, |
| + /* 0x1e10 ~ 0x2d644 used to save group cal data */ |
| + MT_EE_PRECAL = 0x1e10, |
| }; |
| |
| #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) |
| diff --git a/mt7996/init.c b/mt7996/init.c |
| index 70af2f964..06e6f30f3 100644 |
| --- a/mt7996/init.c |
| +++ b/mt7996/init.c |
| @@ -685,6 +685,12 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) |
| if (ret < 0) |
| return ret; |
| |
| + if (dev->flash_mode) { |
| + ret = mt7996_mcu_apply_group_cal(dev); |
| + if (ret) |
| + return ret; |
| + } |
| + |
| /* Beacon and mgmt frames should occupy wcid 0 */ |
| idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); |
| if (idx) |
| diff --git a/mt7996/main.c b/mt7996/main.c |
| index c1d4b3805..f2e2de850 100644 |
| --- a/mt7996/main.c |
| +++ b/mt7996/main.c |
| @@ -312,6 +312,12 @@ int mt7996_set_channel(struct mt7996_phy *phy) |
| |
| mt76_set_channel(phy->mt76); |
| |
| + if (dev->flash_mode) { |
| + ret = mt7996_mcu_apply_tx_dpd(phy); |
| + if (ret) |
| + goto out; |
| + } |
| + |
| ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); |
| if (ret) |
| goto out; |
| diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
| index dd3374a99..802b21685 100644 |
| --- a/mt7996/mcu.c |
| +++ b/mt7996/mcu.c |
| @@ -3493,6 +3493,172 @@ int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) |
| return 0; |
| } |
| |
| +static int mt7996_mcu_set_pre_cal(struct mt7996_dev *dev, u32 idx, |
| + u8 *cal, u32 len, u32 cal_id) |
| +{ |
| +#define PRECAL_CMD_PRE_CAL_RESULT 0x0 |
| + struct { |
| + /* fixed field */ |
| + u8 action; |
| + u8 dest; |
| + u8 attribute; |
| + u8 tag_num; |
| + |
| + __le16 tag; |
| + __le16 len; |
| + |
| + __le32 cal_id; |
| + s8 precal; |
| + u8 band; |
| + u8 rsv[2]; |
| + __le32 idx; |
| + __le32 cal_len; |
| + } req = { |
| + .tag = cpu_to_le16(PRECAL_CMD_PRE_CAL_RESULT), |
| + .len = cpu_to_le16(sizeof(req) - 4 + len), |
| + .cal_id = cpu_to_le32(cal_id), |
| + .idx = cpu_to_le32(idx), |
| + .cal_len = cpu_to_le32(len), |
| + }; |
| + struct sk_buff *skb; |
| + |
| + if (!len) |
| + return 0; |
| + |
| + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len); |
| + if (!skb) |
| + return -ENOMEM; |
| + |
| + skb_put_data(skb, &req, sizeof(req)); |
| + skb_put_data(skb, cal, len); |
| + |
| + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(PRECAL_RESULT), false); |
| +} |
| + |
| +int mt7996_mcu_apply_group_cal(struct mt7996_dev *dev) |
| +{ |
| + u8 *cal = dev->cal, *eeprom = dev->mt76.eeprom.data; |
| + u32 idx = 0, total_idx = MT_EE_CAL_GROUP_SIZE / MT_EE_CAL_UNIT; |
| + u32 offs = MT_EE_DO_PRE_CAL; |
| + int ret = 0; |
| + |
| + if (!(eeprom[offs] & MT_EE_WIFI_CAL_GROUP)) |
| + return 0; |
| + |
| + for (idx = 0; idx < total_idx; idx++, cal += MT_EE_CAL_UNIT) { |
| + ret = mt7996_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT, RF_PRE_CAL); |
| + if (ret) |
| + goto out; |
| + } |
| + |
| + ret = mt7996_mcu_set_pre_cal(dev, total_idx, cal, |
| + MT_EE_CAL_GROUP_SIZE % MT_EE_CAL_UNIT, RF_PRE_CAL); |
| + |
| +out: |
| + return ret; |
| +} |
| + |
| +int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy) |
| +{ |
| + struct mt7996_dev *dev = phy->dev; |
| + struct mt76_phy *mphy = phy->mt76; |
| + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; |
| + enum nl80211_band band = chandef->chan->band; |
| + enum nl80211_chan_width bw = chandef->width; |
| + const struct ieee80211_channel *chan_list; |
| + u32 cal_id, chan_list_size, base_offset = 0, offs = MT_EE_DO_PRE_CAL; |
| + u32 dpd_size_2g, dpd_size_5g, per_chan_size = DPD_PER_CH_BW20_SIZE; |
| + u16 channel = ieee80211_frequency_to_channel(chandef->center_freq1); |
| + u8 dpd_mask, *cal = dev->cal, *eeprom = dev->mt76.eeprom.data; |
| + int idx, i, ret; |
| + |
| + dpd_size_2g = mt7996_get_dpd_per_band_size(dev, NL80211_BAND_2GHZ); |
| + dpd_size_5g = mt7996_get_dpd_per_band_size(dev, NL80211_BAND_5GHZ); |
| + |
| + switch (band) { |
| + case NL80211_BAND_2GHZ: |
| + dpd_mask = MT_EE_WIFI_CAL_DPD_2G; |
| + /* channel 14 don't need DPD cal */ |
| + if (channel >= 1 && channel <= 4) |
| + channel = 3; |
| + else if (channel >= 5 && channel <= 9) |
| + channel = 7; |
| + else if (channel >= 10 && channel <= 13) |
| + channel = 11; |
| + else |
| + return 0; |
| + cal_id = RF_DPD_FLAT_CAL; |
| + chan_list = dpd_2g_ch_list_bw20; |
| + chan_list_size = dpd_2g_bw20_ch_num; |
| + break; |
| + case NL80211_BAND_5GHZ: |
| + dpd_mask = MT_EE_WIFI_CAL_DPD_5G; |
| + cal_id = RF_DPD_FLAT_5G_CAL; |
| + chan_list = mphy->sband_5g.sband.channels; |
| + chan_list_size = mphy->sband_5g.sband.n_channels; |
| + base_offset += dpd_size_2g; |
| + if (bw == NL80211_CHAN_WIDTH_160) { |
| + base_offset += mphy->sband_5g.sband.n_channels * DPD_PER_CH_BW20_SIZE; |
| + per_chan_size = DPD_PER_CH_GT_BW20_SIZE; |
| + cal_id = RF_DPD_FLAT_5G_MEM_CAL; |
| + chan_list = dpd_5g_ch_list_bw160; |
| + chan_list_size = dpd_5g_bw160_ch_num; |
| + } else if (bw > NL80211_CHAN_WIDTH_20) { |
| + /* apply (center channel - 2)'s dpd cal data for bw 40/80 channels */ |
| + channel -= 2; |
| + } |
| + break; |
| + case NL80211_BAND_6GHZ: |
| + dpd_mask = MT_EE_WIFI_CAL_DPD_6G; |
| + cal_id = RF_DPD_FLAT_6G_CAL; |
| + chan_list = mphy->sband_6g.sband.channels; |
| + chan_list_size = mphy->sband_6g.sband.n_channels; |
| + base_offset += dpd_size_2g + dpd_size_5g; |
| + if (bw == NL80211_CHAN_WIDTH_160) { |
| + base_offset += mphy->sband_6g.sband.n_channels * DPD_PER_CH_BW20_SIZE; |
| + per_chan_size = DPD_PER_CH_GT_BW20_SIZE; |
| + cal_id = RF_DPD_FLAT_6G_MEM_CAL; |
| + chan_list = dpd_6g_ch_list_bw160; |
| + chan_list_size = dpd_6g_bw160_ch_num; |
| + } else if (bw == NL80211_CHAN_WIDTH_320) { |
| + base_offset += mphy->sband_6g.sband.n_channels * DPD_PER_CH_BW20_SIZE + |
| + dpd_6g_bw160_ch_num * DPD_PER_CH_GT_BW20_SIZE; |
| + per_chan_size = DPD_PER_CH_GT_BW20_SIZE; |
| + cal_id = RF_DPD_FLAT_6G_MEM_CAL; |
| + chan_list = dpd_6g_ch_list_bw320; |
| + chan_list_size = dpd_6g_bw320_ch_num; |
| + } else if (bw > NL80211_CHAN_WIDTH_20) { |
| + /* apply (center channel - 2)'s dpd cal data for bw 40/80 channels */ |
| + channel -= 2; |
| + } |
| + break; |
| + default: |
| + dpd_mask = 0; |
| + break; |
| + } |
| + |
| + if (!(eeprom[offs] & dpd_mask)) |
| + return 0; |
| + |
| + for (idx = 0; idx < chan_list_size; idx++) |
| + if (channel == chan_list[idx].hw_value) |
| + break; |
| + if (idx == chan_list_size) |
| + return -EINVAL; |
| + |
| + cal += MT_EE_CAL_GROUP_SIZE + base_offset + idx * per_chan_size; |
| + |
| + for (i = 0; i < per_chan_size / MT_EE_CAL_UNIT; i++) { |
| + ret = mt7996_mcu_set_pre_cal(dev, i, cal, MT_EE_CAL_UNIT, cal_id); |
| + if (ret) |
| + return ret; |
| + |
| + cal += MT_EE_CAL_UNIT; |
| + } |
| + |
| + return ret; |
| +} |
| + |
| int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) |
| { |
| #define NIC_CAP 3 |
| diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| index 64e1bebf7..99d4659f1 100644 |
| --- a/mt7996/mt7996.h |
| +++ b/mt7996/mt7996.h |
| @@ -554,6 +554,8 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); |
| void mt7996_mcu_exit(struct mt7996_dev *dev); |
| 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_apply_group_cal(struct mt7996_dev *dev); |
| +int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy); |
| int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable); |
| void mt7996_mcu_scs_sta_poll(struct work_struct *work); |
| #ifdef CONFIG_NL80211_TESTMODE |
| -- |
| 2.39.2 |
| |