From: StanleyYP Wang For the MT7992 and MT7990 chipsets, efuse mode is not supported because there is insufficient space in the efuse to store the calibration data. Therefore, an additional on-chip EEPROM is added to address this limitation. Co-developed-by: Elwin Huang Signed-off-by: Elwin Huang Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: StanleyYP Wang --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../wireless/mediatek/mt76/mt7996/eeprom.c | 59 +++++++------ .../net/wireless/mediatek/mt76/mt7996/init.c | 3 +- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 83 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 43 +++++++++- .../wireless/mediatek/mt76/mt7996/mt7996.h | 20 ++++- 6 files changed, 148 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index f44977f9093d..e91966cd5efe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1308,6 +1308,7 @@ enum { MCU_UNI_CMD_PER_STA_INFO = 0x6d, MCU_UNI_CMD_ALL_STA_INFO = 0x6e, MCU_UNI_CMD_ASSERT_DUMP = 0x6f, + MCU_UNI_CMD_EXT_EEPROM_CTRL = 0x74, MCU_UNI_CMD_RADIO_STATUS = 0x80, MCU_UNI_CMD_SDO = 0x88, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 8f60772913b4..00c72be8498f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -153,7 +153,7 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default) dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE); - dev->flash_mode = true; + dev->eeprom_mode = EEPROM_MODE_DEFAULT_BIN; out: release_firmware(fw); @@ -163,26 +163,31 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default) static int mt7996_eeprom_load(struct mt7996_dev *dev) { + u32 eeprom_blk_size, block_num; bool use_default = false; - int ret; + int ret, i; ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE); if (ret < 0) return ret; if (ret && !mt7996_check_eeprom(dev)) { - dev->flash_mode = true; + dev->eeprom_mode = EEPROM_MODE_FLASH; goto out; } - if (!dev->flash_mode) { - u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; - u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); + memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); + if (mt7996_has_ext_eeprom(dev)) { + /* external eeprom mode */ + dev->eeprom_mode = EEPROM_MODE_EXT; + eeprom_blk_size = MT7996_EXT_EEPROM_BLOCK_SIZE; + } else { u8 free_block_num; - int i; - memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); - ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num); + /* efuse mode */ + dev->eeprom_mode = EEPROM_MODE_EFUSE; + eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; + ret = mt7996_mcu_get_efuse_free_block(dev, &free_block_num); if (ret < 0) return ret; @@ -191,27 +196,29 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev) use_default = true; goto out; } + } + + /* check if eeprom data from fw is valid */ + if (mt7996_mcu_get_eeprom(dev, 0, NULL, eeprom_blk_size, + dev->eeprom_mode) || + mt7996_check_eeprom(dev)) { + use_default = true; + goto out; + } + + /* read eeprom data from fw */ + block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); + for (i = 1; i < block_num; i++) { + u32 len = eeprom_blk_size; - /* check if eeprom data from fw is valid */ - if (mt7996_mcu_get_eeprom(dev, 0, NULL, 0) || - mt7996_check_eeprom(dev)) { + if (i == block_num - 1) + len = MT7996_EEPROM_SIZE % eeprom_blk_size; + ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, + NULL, len, dev->eeprom_mode); + if (ret && ret != -EINVAL) { use_default = true; goto out; } - - /* read eeprom data from fw */ - for (i = 1; i < block_num; i++) { - u32 len = eeprom_blk_size; - - if (i == block_num - 1) - len = MT7996_EEPROM_SIZE % eeprom_blk_size; - ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, - NULL, len); - if (ret && ret != -EINVAL) { - use_default = true; - goto out; - } - } } out: diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 2937e89ad0c9..1fab04909831 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -1207,7 +1207,8 @@ static int mt7996_variant_fem_init(struct mt7996_dev *dev) if (ret) return ret; - ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf)); + ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf), + EEPROM_MODE_EFUSE); if (ret && ret != -EINVAL) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 9ccf9f97c984..46099486ec09 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3950,7 +3950,7 @@ static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev) #define MAX_PAGE_IDX_MASK GENMASK(7, 5) #define PAGE_IDX_MASK GENMASK(4, 2) #define PER_PAGE_SIZE 0x400 - struct mt7996_mcu_eeprom req = { + struct mt7996_mcu_eeprom_update req = { .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), .buffer_mode = EE_MODE_BUFFER }; @@ -3992,57 +3992,80 @@ static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev) int mt7996_mcu_set_eeprom(struct mt7996_dev *dev) { - struct mt7996_mcu_eeprom req = { + 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->flash_mode) + 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) +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len, + enum mt7996_eeprom_mode mode) { - struct { - u8 _rsv[4]; - - __le16 tag; - __le16 len; - __le32 addr; - __le32 valid; - u8 data[16]; - } __packed req = { - .tag = cpu_to_le16(UNI_EFUSE_ACCESS), - .len = cpu_to_le16(sizeof(req) - 4), - .addr = cpu_to_le32(round_down(offset, - MT7996_EEPROM_BLOCK_SIZE)), + struct mt7996_mcu_eeprom_access req = { + .info.len = cpu_to_le16(sizeof(req) - 4), }; + struct mt7996_mcu_eeprom_access_event *event; struct sk_buff *skb; - bool valid; - int ret; + int ret, cmd; + u32 addr; + + switch (mode) { + case EEPROM_MODE_EFUSE: + addr = round_down(offset, MT7996_EEPROM_BLOCK_SIZE); + cmd = MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL); + req.info.tag = cpu_to_le16(UNI_EFUSE_ACCESS); + break; + case EEPROM_MODE_EXT: + addr = round_down(offset, MT7996_EXT_EEPROM_BLOCK_SIZE); + cmd = MCU_WM_UNI_CMD_QUERY(EXT_EEPROM_CTRL); + req.info.tag = cpu_to_le16(UNI_EXT_EEPROM_ACCESS); + req.eeprom.ext_eeprom.data_len = cpu_to_le32(buf_len); + break; + default: + return -EINVAL; + } - ret = mt76_mcu_send_and_get_msg(&dev->mt76, - MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), - &req, sizeof(req), true, &skb); + req.info.addr = cpu_to_le32(addr); + ret = mt76_mcu_send_and_get_msg(&dev->mt76, cmd, &req, sizeof(req), + true, &skb); if (ret) return ret; - valid = le32_to_cpu(*(__le32 *)(skb->data + 16)); - if (valid) { - u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12)); + event = (struct mt7996_mcu_eeprom_access_event *)skb->data; + if (event->valid) { + u32 ret_len = le32_to_cpu(event->eeprom.ext_eeprom.data_len); + + addr = le32_to_cpu(event->addr); if (!buf) buf = (u8 *)dev->mt76.eeprom.data + addr; - if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE) - buf_len = MT7996_EEPROM_BLOCK_SIZE; - skb_pull(skb, 48); - memcpy(buf, skb->data, buf_len); + switch (mode) { + case EEPROM_MODE_EFUSE: + if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE) + buf_len = MT7996_EEPROM_BLOCK_SIZE; + + memcpy(buf, event->eeprom.efuse, buf_len); + break; + case EEPROM_MODE_EXT: + if (!buf_len || buf_len > MT7996_EXT_EEPROM_BLOCK_SIZE) + buf_len = MT7996_EXT_EEPROM_BLOCK_SIZE; + + memcpy(buf, event->eeprom.ext_eeprom.data, + ret_len < buf_len ? ret_len : buf_len); + break; + default: + ret = -EINVAL; + break; + } } else { ret = -EINVAL; } @@ -4052,7 +4075,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l return ret; } -int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) +int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num) { struct { u8 _rsv[4]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index d70540982983..39df13679779 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -145,7 +145,7 @@ struct mt7996_mcu_background_chain_ctrl { u8 rsv[2]; } __packed; -struct mt7996_mcu_eeprom { +struct mt7996_mcu_eeprom_update { u8 _rsv[4]; __le16 tag; @@ -155,6 +155,43 @@ struct mt7996_mcu_eeprom { __le16 buf_len; } __packed; +union eeprom_data { + struct { + __le32 data_len; + DECLARE_FLEX_ARRAY(u8, data); + } ext_eeprom; + DECLARE_FLEX_ARRAY(u8, efuse); +} __packed; + +struct mt7996_mcu_eeprom_info { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + __le32 addr; + __le32 valid; +} __packed; + +struct mt7996_mcu_eeprom_access { + struct mt7996_mcu_eeprom_info info; + union eeprom_data eeprom; +} __packed; + +struct mt7996_mcu_eeprom_access_event { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + __le32 version; + __le32 addr; + __le32 valid; + __le32 size; + __le32 magic_no; + __le32 type; + __le32 rsv[4]; + union eeprom_data eeprom; +} __packed; + struct mt7996_mcu_phy_rx_info { u8 category; u8 rate; @@ -875,6 +912,10 @@ enum { UNI_EFUSE_BUFFER_RD, }; +enum { + UNI_EXT_EEPROM_ACCESS = 1, +}; + enum { UNI_VOW_DRR_CTRL, UNI_VOW_RX_AT_AIRTIME_EN = 0x0b, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 3ff730e36fa6..ea1f656a9334 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -85,6 +85,7 @@ #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 +#define MT7996_EXT_EEPROM_BLOCK_SIZE 1024 #define MT7996_TOKEN_SIZE 16384 #define MT7996_HW_TOKEN_SIZE 8192 @@ -169,6 +170,13 @@ enum mt7996_fem_type { MT7996_FEM_MIX, }; +enum mt7996_eeprom_mode { + EEPROM_MODE_DEFAULT_BIN, + EEPROM_MODE_EFUSE, + EEPROM_MODE_FLASH, + EEPROM_MODE_EXT, +}; + enum mt7996_txq_id { MT7996_TXQ_FWDL = 16, MT7996_TXQ_MCU_WM, @@ -441,7 +449,7 @@ struct mt7996_dev { u32 hw_pattern; - bool flash_mode:1; + u8 eeprom_mode; bool has_eht:1; struct { @@ -717,8 +725,9 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta, void *data, u8 link_id, u32 field); int mt7996_mcu_set_eeprom(struct mt7996_dev *dev); -int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len); -int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len, + enum mt7996_eeprom_mode mode); +int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num); int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap); int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band); int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action); @@ -816,6 +825,11 @@ static inline bool mt7996_has_wa(struct mt7996_dev *dev) return !is_mt7990(&dev->mt76); } +static inline bool mt7996_has_ext_eeprom(struct mt7996_dev *dev) +{ + return !is_mt7996(&dev->mt76); +} + void mt7996_mac_init(struct mt7996_dev *dev); u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); -- 2.51.0 Introduce VAR_TYPE_24 for the MT7992 chipsets, a dual-band variant supporting 3T3R/2SS on the 2 GHz band and 5T5R/4SS on the 5GHz band. Signed-off-by: Shayne Chen --- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 5 ++++- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 7 +++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 00c72be8498f..ac05f7d75d63 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -33,6 +33,8 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev) if (dev->var.fem == MT7996_FEM_INT) return MT7992_EEPROM_DEFAULT_23_INT; return MT7992_EEPROM_DEFAULT_23; + case MT7992_VAR_TYPE_24: + return MT7992_EEPROM_DEFAULT_24; case MT7992_VAR_TYPE_44: default: if (dev->var.fem == MT7996_FEM_INT) @@ -392,7 +394,8 @@ bool mt7996_eeprom_has_background_radar(struct mt7996_dev *dev) return false; break; case MT7992_DEVICE_ID: - if (dev->var.type == MT7992_VAR_TYPE_23) + if (dev->var.type == MT7992_VAR_TYPE_23 || + dev->var.type == MT7992_VAR_TYPE_24) return false; break; case MT7990_DEVICE_ID: { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 1fab04909831..3b4f808b968c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -1173,7 +1173,7 @@ static int mt7996_variant_type_init(struct mt7996_dev *dev) else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992)) var_type = MT7992_VAR_TYPE_44; else - return -EINVAL; + var_type = MT7992_VAR_TYPE_24; break; case MT7990_DEVICE_ID: var_type = MT7990_VAR_TYPE_23; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 46099486ec09..98db3bcf76f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -18,6 +18,9 @@ case MT7992_VAR_TYPE_23: \ _fw = MT7992_##name##_23; \ break; \ + case MT7992_VAR_TYPE_24: \ + _fw = MT7992_##name##_24; \ + break; \ default: \ _fw = MT7992_##name; \ } \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index ea1f656a9334..d36fb5396141 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -64,6 +64,11 @@ #define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin" #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin" +#define MT7992_FIRMWARE_WA_24 "mediatek/mt7996/mt7992_wa_24.bin" +#define MT7992_FIRMWARE_WM_24 "mediatek/mt7996/mt7992_wm_24.bin" +#define MT7992_FIRMWARE_DSP_24 "mediatek/mt7996/mt7992_dsp_24.bin" +#define MT7992_ROM_PATCH_24 "mediatek/mt7996/mt7992_rom_patch_24.bin" + #define MT7990_FIRMWARE_WA "" #define MT7990_FIRMWARE_WM "mediatek/mt7996/mt7990_wm.bin" #define MT7990_FIRMWARE_DSP "" @@ -79,6 +84,7 @@ #define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin" #define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin" #define MT7992_EEPROM_DEFAULT_23_INT "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin" +#define MT7992_EEPROM_DEFAULT_24 "mediatek/mt7996/mt7992_eeprom_24_2i5i.bin" #define MT7990_EEPROM_DEFAULT "mediatek/mt7996/mt7990_eeprom.bin" #define MT7990_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7990_eeprom_2i5i.bin" @@ -158,6 +164,7 @@ enum mt7996_var_type { enum mt7992_var_type { MT7992_VAR_TYPE_44, MT7992_VAR_TYPE_23, + MT7992_VAR_TYPE_24, }; enum mt7990_var_type { -- 2.51.0 From: StanleyYP Wang 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 Signed-off-by: Shayne Chen Signed-off-by: StanleyYP Wang --- .../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