[PATCH mt76 3/3] wifi: mt76: mt7996: apply calibration-free data from OTP
Shayne Chen
shayne.chen at mediatek.com
Thu Feb 12 01:03:10 PST 2026
From: StanleyYP Wang <StanleyYP.Wang at mediatek.com>
Before sending the current EEPROM data to the firmware, read the
calibration-free data (FT data) from the efuse and merge it with
the existing EEPROM data.
Co-developed-by: Shayne Chen <shayne.chen at mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen at mediatek.com>
Signed-off-by: StanleyYP Wang <StanleyYP.Wang at mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7996/mcu.c | 171 ++++++++++++++++--
.../wireless/mediatek/mt76/mt7996/mt7996.h | 5 +
2 files changed, 157 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 98db3bcf76f0..4cac1f7dd597 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -3948,7 +3948,152 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
&req, sizeof(req), true);
}
-static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev)
+static int
+mt7996_mcu_get_cal_free_data(struct mt7996_dev *dev)
+{
+#define MT_EE_7977BN_OFFSET (0x1200 - 0x500)
+ struct cal_free_data {
+ u16 adie_offs;
+ u16 eep_offs;
+ };
+ static const struct cal_free_data cal_7975[] = {
+ { 0x5cd, 0x451 }, { 0x5cf, 0x453 }, { 0x5d1, 0x455 },
+ { 0x5d3, 0x457 }, { 0x6c0, 0x44c }, { 0x6c1, 0x44d },
+ { 0x6c2, 0x44e }, { 0x6c3, 0x44f }, { 0x7a1, 0xba1 },
+ { 0x7a6, 0xba6 }, { 0x7a8, 0xba8 }, { 0x7aa, 0xbaa },
+ };
+ static const struct cal_free_data cal_7976[] = {
+ { 0x4c, 0x44c }, { 0x4d, 0x44d }, { 0x4e, 0x44e },
+ { 0x4f, 0x44f }, { 0x50, 0x450 }, { 0x51, 0x451 },
+ { 0x53, 0x453 }, { 0x55, 0x455 }, { 0x57, 0x457 },
+ { 0x59, 0x459 }, { 0x70, 0x470 }, { 0x71, 0x471 },
+ { 0x790, 0xb90 }, { 0x791, 0xb91 }, { 0x794, 0xb94 },
+ { 0x795, 0xb95 }, { 0x7a6, 0xba6 }, { 0x7a8, 0xba8 },
+ { 0x7aa, 0xbaa },
+ };
+ static const struct cal_free_data cal_7977[] = {
+ { 0x4c, 0x124c }, { 0x4d, 0x124d }, { 0x4e, 0x124e },
+ { 0x4f, 0x124f }, { 0x50, 0x1250 }, { 0x51, 0x1251 },
+ { 0x53, 0x1253 }, { 0x55, 0x1255 }, { 0x57, 0x1257 },
+ { 0x59, 0x1259 }, { 0x69, 0x1269 }, { 0x6a, 0x126a },
+ { 0x7a, 0x127a }, { 0x7b, 0x127b }, { 0x7c, 0x127c },
+ { 0x7d, 0x127d }, { 0x7e, 0x127e },
+ };
+ static const struct cal_free_data cal_7978[] = {
+ { 0x91, 0xb91 }, { 0x95, 0xb95 }, { 0x100, 0x480 },
+ { 0x102, 0x482 }, { 0x104, 0x484 }, { 0x106, 0x486 },
+ { 0x107, 0x487 }, { 0x108, 0x488 }, { 0x109, 0x489 },
+ { 0x10a, 0x48a }, { 0x10b, 0x48b }, { 0x10c, 0x48c },
+ { 0x10e, 0x48e }, { 0x110, 0x490 },
+ };
+ static const struct cal_free_data cal_7979[] = {
+ { 0x4c, 0x124c }, { 0x4d, 0x124d }, { 0x4e, 0x124e },
+ { 0x4f, 0x124f }, { 0x50, 0x1250 }, { 0x51, 0x1251 },
+ { 0x53, 0x1253 }, { 0x55, 0x1255 }, { 0x57, 0x1257 },
+ { 0x59, 0x1259 }, { 0x69, 0x1269 }, { 0x6a, 0x126a },
+ { 0x7a, 0x127a }, { 0x7b, 0x127b }, { 0x7c, 0x127c },
+ { 0x7e, 0x127e }, { 0x80, 0x1280 },
+ };
+ const struct cal_free_data *cal_arr[__MT_MAX_BAND];
+ u16 cal_arr_len[__MT_MAX_BAND] = {};
+ u8 *eeprom = (u8 *)dev->mt76.eeprom.data;
+ int band, i, ret;
+
+#define CAL_ARR(_band, _adie) do { \
+ cal_arr[_band] = cal_##_adie; \
+ cal_arr_len[_band] = ARRAY_SIZE(cal_##_adie); \
+ } while (0)
+
+ switch (mt76_chip(&dev->mt76)) {
+ case MT7996_DEVICE_ID:
+ /* adie 0 */
+ if (dev->var.fem == MT7996_FEM_INT &&
+ dev->var.type != MT7996_VAR_TYPE_233)
+ CAL_ARR(0, 7975);
+ else
+ CAL_ARR(0, 7976);
+
+ /* adie 1 */
+ if (dev->var.type == MT7996_VAR_TYPE_444)
+ CAL_ARR(1, 7977);
+
+ /* adie 2 */
+ CAL_ARR(2, 7977);
+ break;
+ case MT7992_DEVICE_ID:
+ /* adie 0 */
+ if (dev->var.type == MT7992_VAR_TYPE_44 &&
+ dev->var.fem != MT7996_FEM_EXT)
+ CAL_ARR(0, 7975);
+ else if (dev->var.type == MT7992_VAR_TYPE_24)
+ CAL_ARR(0, 7978);
+ else
+ CAL_ARR(0, 7976);
+
+ /* adie 1 */
+ if (dev->var.type == MT7992_VAR_TYPE_44 &&
+ dev->var.fem != MT7996_FEM_INT)
+ CAL_ARR(1, 7977);
+ else if (dev->var.type != MT7992_VAR_TYPE_23)
+ CAL_ARR(1, 7979);
+ break;
+ case MT7990_DEVICE_ID:
+ /* adie 0 */
+ CAL_ARR(0, 7976);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (band = 0; band < __MT_MAX_BAND; band++) {
+ const struct cal_free_data *cal;
+ u16 prev_block_idx = -1;
+ u16 adie_base;
+
+ if (!cal_arr_len[band])
+ continue;
+
+ if (band == MT_BAND0)
+ adie_base = MT7996_EFUSE_BASE_OFFS_ADIE0;
+ else if (band == MT_BAND1 && is_mt7992(&dev->mt76))
+ adie_base = MT7992_EFUSE_BASE_OFFS_ADIE1;
+ else if (band == MT_BAND1)
+ adie_base = MT7996_EFUSE_BASE_OFFS_ADIE1;
+ else
+ adie_base = MT7996_EFUSE_BASE_OFFS_ADIE2;
+
+ cal = cal_arr[band];
+ for (i = 0; i < cal_arr_len[band]; i++) {
+ u16 adie_offset = cal[i].adie_offs + adie_base;
+ u16 eep_offset = cal[i].eep_offs;
+ u16 block_idx = adie_offset / MT7996_EEPROM_BLOCK_SIZE;
+ u16 offset = adie_offset % MT7996_EEPROM_BLOCK_SIZE;
+ u8 buf[MT7996_EEPROM_BLOCK_SIZE];
+
+ if (is_mt7996(&dev->mt76) && band == MT_BAND1 &&
+ dev->var.type == MT7996_VAR_TYPE_444)
+ eep_offset -= MT_EE_7977BN_OFFSET;
+
+ if (prev_block_idx != block_idx) {
+ ret = mt7996_mcu_get_eeprom(dev, adie_offset, buf,
+ MT7996_EEPROM_BLOCK_SIZE,
+ EEPROM_MODE_EFUSE);
+ if (ret) {
+ if (ret != -EINVAL)
+ return ret;
+ prev_block_idx = -1;
+ continue;
+ }
+ }
+ eeprom[eep_offset] = buf[offset];
+ prev_block_idx = block_idx;
+ }
+ }
+
+ return 0;
+}
+
+int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
{
#define MAX_PAGE_IDX_MASK GENMASK(7, 5)
#define PAGE_IDX_MASK GENMASK(4, 2)
@@ -3960,11 +4105,15 @@ static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev)
u16 eeprom_size = MT7996_EEPROM_SIZE;
u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE);
u8 *eep = (u8 *)dev->mt76.eeprom.data;
- int eep_len, i;
+ int ret, eep_len, i;
+
+ ret = mt7996_mcu_get_cal_free_data(dev);
+ if (ret)
+ return ret;
for (i = 0; i < total; i++, eep += eep_len) {
struct sk_buff *skb;
- int ret, msg_len;
+ int msg_len;
if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE))
eep_len = eeprom_size % PER_PAGE_SIZE;
@@ -3993,22 +4142,6 @@ static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev)
return 0;
}
-int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
-{
- struct mt7996_mcu_eeprom_update req = {
- .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE),
- .len = cpu_to_le16(sizeof(req) - 4),
- .buffer_mode = EE_MODE_EFUSE,
- .format = EE_FORMAT_WHOLE
- };
-
- if (dev->eeprom_mode != EEPROM_MODE_EFUSE)
- return mt7996_mcu_set_eeprom_flash(dev);
-
- return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL),
- &req, sizeof(req), true);
-}
-
int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len,
enum mt7996_eeprom_mode mode)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index d36fb5396141..5f574ebe81cc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -184,6 +184,11 @@ enum mt7996_eeprom_mode {
EEPROM_MODE_EXT,
};
+#define MT7996_EFUSE_BASE_OFFS_ADIE0 0x400
+#define MT7996_EFUSE_BASE_OFFS_ADIE1 0x1e00
+#define MT7996_EFUSE_BASE_OFFS_ADIE2 0x1200
+#define MT7992_EFUSE_BASE_OFFS_ADIE1 0x1200
+
enum mt7996_txq_id {
MT7996_TXQ_FWDL = 16,
MT7996_TXQ_MCU_WM,
--
2.51.0
More information about the Linux-mediatek
mailing list