developer | 064da3c | 2023-06-13 15:57:26 +0800 | [diff] [blame] | 1 | From f3ff5d5029a0a589e797dd2536070d3a3e4e30a6 Mon Sep 17 00:00:00 2001 |
| 2 | From: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| 3 | Date: Wed, 1 Mar 2023 12:12:51 +0800 |
| 4 | Subject: [PATCH 1008/1015] wifi: mt76: mt7996: add normal mode pre-calibration |
| 5 | support |
| 6 | |
| 7 | Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| 8 | --- |
| 9 | mt76_connac_mcu.h | 1 + |
| 10 | mt7996/eeprom.c | 23 +++++++ |
| 11 | mt7996/eeprom.h | 2 + |
| 12 | mt7996/init.c | 6 ++ |
| 13 | mt7996/main.c | 6 ++ |
| 14 | mt7996/mcu.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ |
| 15 | mt7996/mt7996.h | 2 + |
| 16 | 7 files changed, 206 insertions(+) |
| 17 | |
| 18 | diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h |
| 19 | index 262abf88..42246fb9 100644 |
| 20 | --- a/mt76_connac_mcu.h |
| 21 | +++ b/mt76_connac_mcu.h |
| 22 | @@ -1229,6 +1229,7 @@ enum { |
| 23 | MCU_UNI_CMD_VOW = 0x37, |
| 24 | MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, |
| 25 | MCU_UNI_CMD_TESTMODE_CTRL = 0x46, |
| 26 | + MCU_UNI_CMD_PRECAL_RESULT = 0x47, |
| 27 | MCU_UNI_CMD_RRO = 0x57, |
| 28 | MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, |
| 29 | MCU_UNI_CMD_ASSERT_DUMP = 0x6f, |
| 30 | diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c |
| 31 | index 85d9e057..bee4a4b5 100644 |
| 32 | --- a/mt7996/eeprom.c |
| 33 | +++ b/mt7996/eeprom.c |
| 34 | @@ -330,6 +330,25 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) |
| 35 | return mt7996_eeprom_parse_band_config(phy); |
| 36 | } |
| 37 | |
| 38 | +static int mt7996_eeprom_load_precal(struct mt7996_dev *dev) |
| 39 | +{ |
| 40 | + struct mt76_dev *mdev = &dev->mt76; |
| 41 | + u8 *eeprom = mdev->eeprom.data; |
| 42 | + u32 offs = MT_EE_DO_PRE_CAL; |
| 43 | + u32 size, val = eeprom[offs]; |
| 44 | + |
| 45 | + if (!dev->flash_mode || !val) |
| 46 | + return 0; |
| 47 | + |
| 48 | + size = MT_EE_CAL_GROUP_SIZE + MT_EE_CAL_DPD_SIZE; |
| 49 | + |
| 50 | + dev->cal = devm_kzalloc(mdev->dev, size, GFP_KERNEL); |
| 51 | + if (!dev->cal) |
| 52 | + return -ENOMEM; |
| 53 | + |
| 54 | + return mt76_get_of_eeprom(mdev, dev->cal, MT_EE_PRECAL, size); |
| 55 | +} |
| 56 | + |
| 57 | int mt7996_eeprom_init(struct mt7996_dev *dev) |
| 58 | { |
| 59 | int ret; |
| 60 | @@ -347,6 +366,10 @@ int mt7996_eeprom_init(struct mt7996_dev *dev) |
| 61 | return ret; |
| 62 | } |
| 63 | |
| 64 | + ret = mt7996_eeprom_load_precal(dev); |
| 65 | + if (ret) |
| 66 | + return ret; |
| 67 | + |
| 68 | ret = mt7996_eeprom_parse_hw_cap(dev, &dev->phy); |
| 69 | if (ret < 0) |
| 70 | return ret; |
| 71 | diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h |
| 72 | index 20dd8771..0f3f31d8 100644 |
| 73 | --- a/mt7996/eeprom.h |
| 74 | +++ b/mt7996/eeprom.h |
| 75 | @@ -25,6 +25,8 @@ enum mt7996_eeprom_field { |
| 76 | MT_EE_TX0_POWER_6G = 0x1310, |
| 77 | |
| 78 | __MT_EE_MAX = 0x1dff, |
| 79 | + /* 0x1e10 ~ 0x2d644 used to save group cal data */ |
| 80 | + MT_EE_PRECAL = 0x1e10, |
| 81 | }; |
| 82 | |
| 83 | #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) |
| 84 | diff --git a/mt7996/init.c b/mt7996/init.c |
| 85 | index 40d610ae..31695090 100644 |
| 86 | --- a/mt7996/init.c |
| 87 | +++ b/mt7996/init.c |
| 88 | @@ -675,6 +675,12 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) |
| 89 | if (ret < 0) |
| 90 | return ret; |
| 91 | |
| 92 | + if (dev->flash_mode) { |
| 93 | + ret = mt7996_mcu_apply_group_cal(dev); |
| 94 | + if (ret) |
| 95 | + return ret; |
| 96 | + } |
| 97 | + |
| 98 | /* Beacon and mgmt frames should occupy wcid 0 */ |
| 99 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); |
| 100 | if (idx) |
| 101 | diff --git a/mt7996/main.c b/mt7996/main.c |
| 102 | index e5627c96..d40d3047 100644 |
| 103 | --- a/mt7996/main.c |
| 104 | +++ b/mt7996/main.c |
| 105 | @@ -312,6 +312,12 @@ int mt7996_set_channel(struct mt7996_phy *phy) |
| 106 | |
| 107 | mt76_set_channel(phy->mt76); |
| 108 | |
| 109 | + if (dev->flash_mode) { |
| 110 | + ret = mt7996_mcu_apply_tx_dpd(phy); |
| 111 | + if (ret) |
| 112 | + goto out; |
| 113 | + } |
| 114 | + |
| 115 | ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); |
| 116 | if (ret) |
| 117 | goto out; |
| 118 | diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
| 119 | index 1fb7bae1..6add77da 100644 |
| 120 | --- a/mt7996/mcu.c |
| 121 | +++ b/mt7996/mcu.c |
| 122 | @@ -3386,6 +3386,172 @@ int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) |
| 123 | return 0; |
| 124 | } |
| 125 | |
| 126 | +static int mt7996_mcu_set_pre_cal(struct mt7996_dev *dev, u32 idx, |
| 127 | + u8 *cal, u32 len, u32 cal_id) |
| 128 | +{ |
| 129 | +#define PRECAL_CMD_PRE_CAL_RESULT 0x0 |
| 130 | + struct { |
| 131 | + /* fixed field */ |
| 132 | + u8 action; |
| 133 | + u8 dest; |
| 134 | + u8 attribute; |
| 135 | + u8 tag_num; |
| 136 | + |
| 137 | + __le16 tag; |
| 138 | + __le16 len; |
| 139 | + |
| 140 | + __le32 cal_id; |
| 141 | + s8 precal; |
| 142 | + u8 band; |
| 143 | + u8 rsv[2]; |
| 144 | + __le32 idx; |
| 145 | + __le32 cal_len; |
| 146 | + } req = { |
| 147 | + .tag = cpu_to_le16(PRECAL_CMD_PRE_CAL_RESULT), |
| 148 | + .len = cpu_to_le16(sizeof(req) - 4 + len), |
| 149 | + .cal_id = cpu_to_le32(cal_id), |
| 150 | + .idx = cpu_to_le32(idx), |
| 151 | + .cal_len = cpu_to_le32(len), |
| 152 | + }; |
| 153 | + struct sk_buff *skb; |
| 154 | + |
| 155 | + if (!len) |
| 156 | + return 0; |
| 157 | + |
| 158 | + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len); |
| 159 | + if (!skb) |
| 160 | + return -ENOMEM; |
| 161 | + |
| 162 | + skb_put_data(skb, &req, sizeof(req)); |
| 163 | + skb_put_data(skb, cal, len); |
| 164 | + |
| 165 | + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(PRECAL_RESULT), false); |
| 166 | +} |
| 167 | + |
| 168 | +int mt7996_mcu_apply_group_cal(struct mt7996_dev *dev) |
| 169 | +{ |
| 170 | + u8 *cal = dev->cal, *eeprom = dev->mt76.eeprom.data; |
| 171 | + u32 idx = 0, total_idx = MT_EE_CAL_GROUP_SIZE / MT_EE_CAL_UNIT; |
| 172 | + u32 offs = MT_EE_DO_PRE_CAL; |
| 173 | + int ret = 0; |
| 174 | + |
| 175 | + if (!(eeprom[offs] & MT_EE_WIFI_CAL_GROUP)) |
| 176 | + return 0; |
| 177 | + |
| 178 | + for (idx = 0; idx < total_idx; idx++, cal += MT_EE_CAL_UNIT) { |
| 179 | + ret = mt7996_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT, RF_PRE_CAL); |
| 180 | + if (ret) |
| 181 | + goto out; |
| 182 | + } |
| 183 | + |
| 184 | + ret = mt7996_mcu_set_pre_cal(dev, total_idx, cal, |
| 185 | + MT_EE_CAL_GROUP_SIZE % MT_EE_CAL_UNIT, RF_PRE_CAL); |
| 186 | + |
| 187 | +out: |
| 188 | + return ret; |
| 189 | +} |
| 190 | + |
| 191 | +int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy) |
| 192 | +{ |
| 193 | + struct mt7996_dev *dev = phy->dev; |
| 194 | + struct mt76_phy *mphy = phy->mt76; |
| 195 | + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; |
| 196 | + enum nl80211_band band = chandef->chan->band; |
| 197 | + enum nl80211_chan_width bw = chandef->width; |
| 198 | + const struct ieee80211_channel *chan_list; |
| 199 | + u32 cal_id, chan_list_size, base_offset = 0, offs = MT_EE_DO_PRE_CAL; |
| 200 | + u32 dpd_size_2g, dpd_size_5g, per_chan_size = DPD_PER_CH_BW20_SIZE; |
| 201 | + u16 channel = ieee80211_frequency_to_channel(chandef->center_freq1); |
| 202 | + u8 dpd_mask, *cal = dev->cal, *eeprom = dev->mt76.eeprom.data; |
| 203 | + int idx, i, ret; |
| 204 | + |
| 205 | + dpd_size_2g = mt7996_get_dpd_per_band_size(dev, NL80211_BAND_2GHZ); |
| 206 | + dpd_size_5g = mt7996_get_dpd_per_band_size(dev, NL80211_BAND_5GHZ); |
| 207 | + |
| 208 | + switch (band) { |
| 209 | + case NL80211_BAND_2GHZ: |
| 210 | + dpd_mask = MT_EE_WIFI_CAL_DPD_2G; |
| 211 | + /* channel 14 don't need DPD cal */ |
| 212 | + if (channel >= 1 && channel <= 4) |
| 213 | + channel = 3; |
| 214 | + else if (channel >= 5 && channel <= 9) |
| 215 | + channel = 7; |
| 216 | + else if (channel >= 10 && channel <= 13) |
| 217 | + channel = 11; |
| 218 | + else |
| 219 | + return 0; |
| 220 | + cal_id = RF_DPD_FLAT_CAL; |
| 221 | + chan_list = dpd_2g_ch_list_bw20; |
| 222 | + chan_list_size = dpd_2g_bw20_ch_num; |
| 223 | + break; |
| 224 | + case NL80211_BAND_5GHZ: |
| 225 | + dpd_mask = MT_EE_WIFI_CAL_DPD_5G; |
| 226 | + cal_id = RF_DPD_FLAT_5G_CAL; |
| 227 | + chan_list = mphy->sband_5g.sband.channels; |
| 228 | + chan_list_size = mphy->sband_5g.sband.n_channels; |
| 229 | + base_offset += dpd_size_2g; |
| 230 | + if (bw == NL80211_CHAN_WIDTH_160) { |
| 231 | + base_offset += mphy->sband_5g.sband.n_channels * DPD_PER_CH_BW20_SIZE; |
| 232 | + per_chan_size = DPD_PER_CH_GT_BW20_SIZE; |
| 233 | + cal_id = RF_DPD_FLAT_5G_MEM_CAL; |
| 234 | + chan_list = dpd_5g_ch_list_bw160; |
| 235 | + chan_list_size = dpd_5g_bw160_ch_num; |
| 236 | + } else if (bw > NL80211_CHAN_WIDTH_20) { |
| 237 | + /* apply (center channel - 2)'s dpd cal data for bw 40/80 channels */ |
| 238 | + channel -= 2; |
| 239 | + } |
| 240 | + break; |
| 241 | + case NL80211_BAND_6GHZ: |
| 242 | + dpd_mask = MT_EE_WIFI_CAL_DPD_6G; |
| 243 | + cal_id = RF_DPD_FLAT_6G_CAL; |
| 244 | + chan_list = mphy->sband_6g.sband.channels; |
| 245 | + chan_list_size = mphy->sband_6g.sband.n_channels; |
| 246 | + base_offset += dpd_size_2g + dpd_size_5g; |
| 247 | + if (bw == NL80211_CHAN_WIDTH_160) { |
| 248 | + base_offset += mphy->sband_6g.sband.n_channels * DPD_PER_CH_BW20_SIZE; |
| 249 | + per_chan_size = DPD_PER_CH_GT_BW20_SIZE; |
| 250 | + cal_id = RF_DPD_FLAT_6G_MEM_CAL; |
| 251 | + chan_list = dpd_6g_ch_list_bw160; |
| 252 | + chan_list_size = dpd_6g_bw160_ch_num; |
| 253 | + } else if (bw == NL80211_CHAN_WIDTH_320) { |
| 254 | + base_offset += mphy->sband_6g.sband.n_channels * DPD_PER_CH_BW20_SIZE + |
| 255 | + dpd_6g_bw160_ch_num * DPD_PER_CH_GT_BW20_SIZE; |
| 256 | + per_chan_size = DPD_PER_CH_GT_BW20_SIZE; |
| 257 | + cal_id = RF_DPD_FLAT_6G_MEM_CAL; |
| 258 | + chan_list = dpd_6g_ch_list_bw320; |
| 259 | + chan_list_size = dpd_6g_bw320_ch_num; |
| 260 | + } else if (bw > NL80211_CHAN_WIDTH_20) { |
| 261 | + /* apply (center channel - 2)'s dpd cal data for bw 40/80 channels */ |
| 262 | + channel -= 2; |
| 263 | + } |
| 264 | + break; |
| 265 | + default: |
| 266 | + dpd_mask = 0; |
| 267 | + break; |
| 268 | + } |
| 269 | + |
| 270 | + if (!(eeprom[offs] & dpd_mask)) |
| 271 | + return 0; |
| 272 | + |
| 273 | + for (idx = 0; idx < chan_list_size; idx++) |
| 274 | + if (channel == chan_list[idx].hw_value) |
| 275 | + break; |
| 276 | + if (idx == chan_list_size) |
| 277 | + return -EINVAL; |
| 278 | + |
| 279 | + cal += MT_EE_CAL_GROUP_SIZE + base_offset + idx * per_chan_size; |
| 280 | + |
| 281 | + for (i = 0; i < per_chan_size / MT_EE_CAL_UNIT; i++) { |
| 282 | + ret = mt7996_mcu_set_pre_cal(dev, i, cal, MT_EE_CAL_UNIT, cal_id); |
| 283 | + if (ret) |
| 284 | + return ret; |
| 285 | + |
| 286 | + cal += MT_EE_CAL_UNIT; |
| 287 | + } |
| 288 | + |
| 289 | + return ret; |
| 290 | +} |
| 291 | + |
| 292 | int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) |
| 293 | { |
| 294 | #define NIC_CAP 3 |
| 295 | diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| 296 | index 6ef6bad9..c16bc8b4 100644 |
| 297 | --- a/mt7996/mt7996.h |
| 298 | +++ b/mt7996/mt7996.h |
| 299 | @@ -607,6 +607,8 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); |
| 300 | void mt7996_mcu_exit(struct mt7996_dev *dev); |
| 301 | int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data); |
| 302 | int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event); |
| 303 | +int mt7996_mcu_apply_group_cal(struct mt7996_dev *dev); |
| 304 | +int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy); |
| 305 | int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable); |
| 306 | void mt7996_mcu_scs_sta_poll(struct work_struct *work); |
| 307 | #ifdef CONFIG_NL80211_TESTMODE |
| 308 | -- |
| 309 | 2.39.2 |
| 310 | |