blob: c2d6b3134c60b497f23ba56ad5867ac786f413a8 [file] [log] [blame]
From ad34fb7616d5c2a679f4344dce94b0edd6e66609 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Mon, 11 Mar 2024 10:43:03 +0800
Subject: [PATCH 036/120] mtk: wifi: mt76: mt7996: refactor eeprom loading flow
for sku checking
Add eeprom sku checking mechanism to avoid using the
wrong eeprom in flash/binfile mode
The fields listed below will be checked by comparing the loaded eeprom to the default bin
1. FEM type
2. MAC address (warning for using default MAC address)
3. RF path & streams
(to distinguish cases such as BE7200 4i5i, BE6500 3i5i, and BE5040 2i3i)
CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Change-Id: If1905086f2a876a593d07f23a5facad35067f94a
---
mt7996/eeprom.c | 185 ++++++++++++++++++++++++++-----------------
mt7996/eeprom.h | 32 ++++++++
mt7996/mtk_debugfs.c | 2 +-
3 files changed, 144 insertions(+), 75 deletions(-)
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
index fe8b25352..138bdb472 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -49,23 +49,43 @@ const u32 dpd_6g_bw160_ch_num = ARRAY_SIZE(dpd_6g_ch_list_bw160);
const u32 dpd_6g_bw320_ch_num = ARRAY_SIZE(dpd_6g_ch_list_bw320);
static int mt7996_check_eeprom(struct mt7996_dev *dev)
+{
+ u8 *eeprom = dev->mt76.eeprom.data;
+ u16 val = get_unaligned_le16(eeprom);
+
+ switch (val) {
+ case 0x7990:
+ return is_mt7996(&dev->mt76) ? 0 : -EINVAL;
+ case 0x7992:
+ return is_mt7992(&dev->mt76) ? 0 : -EINVAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mt7996_check_eeprom_sku(struct mt7996_dev *dev, const u8 *dflt)
{
#define FEM_INT 0
#define FEM_EXT 3
u8 *eeprom = dev->mt76.eeprom.data;
u8 i, fem[__MT_MAX_BAND], fem_type;
u16 val = get_unaligned_le16(eeprom);
+ u16 mac_addr[__MT_MAX_BAND] = {MT_EE_MAC_ADDR, MT_EE_MAC_ADDR2, MT_EE_MAC_ADDR3};
+ int max_band = __MT_MAX_BAND;
+
+ if (dev->fem_type == MT7996_FEM_UNSET)
+ return -EINVAL;
for (i = 0; i < __MT_MAX_BAND; i++)
fem[i] = eeprom[MT_EE_WIFI_CONF + 6 + i] & MT_EE_WIFI_PA_LNA_CONFIG;
switch (val) {
case 0x7990:
- return is_mt7996(&dev->mt76) ? 0 : -EINVAL;
+ /* Don't care Eagle's FEM type */
+ fem_type = 0;
+ break;
case 0x7992:
- if (dev->fem_type == MT7996_FEM_UNSET)
- return is_mt7992(&dev->mt76) ? 0 : -EINVAL;
-
+ max_band = 2;
if (fem[0] == FEM_EXT && fem[1] == FEM_EXT)
fem_type = MT7996_FEM_EXT;
else if (fem[0] == FEM_INT && fem[1] == FEM_INT)
@@ -74,19 +94,45 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
fem_type = MT7996_FEM_MIX;
else
return -EINVAL;
-
- return (is_mt7992(&dev->mt76) ? 0 : -EINVAL) |
- (dev->fem_type == fem_type ? 0 : -EINVAL);
+ break;
default:
return -EINVAL;
}
+
+ /* FEM type */
+ if (fem_type && dev->fem_type != fem_type)
+ return -EINVAL;
+
+ /* RF path & stream */
+ for (i = 0; i < max_band; i++) {
+ u8 path, rx_path, nss;
+ u8 dflt_path, dflt_rx_path, dflt_nss;
+
+ /* MAC address */
+ if (ether_addr_equal(eeprom + mac_addr[i], dflt + mac_addr[i]))
+ dev_warn(dev->mt76.dev,
+ "Currently using default MAC address for band %d\n", i);
+
+ mt7996_parse_eeprom_stream(eeprom, i, &path, &rx_path, &nss);
+ mt7996_parse_eeprom_stream(dflt, i, &dflt_path, &dflt_rx_path, &dflt_nss);
+ if (path > dflt_path || rx_path > dflt_rx_path || nss > dflt_nss) {
+ dev_err(dev->mt76.dev,
+ "Invalid path/stream configuration for band %d\n", i);
+ return -EINVAL;
+ } else if (path < dflt_path || rx_path < dflt_rx_path || nss < dflt_nss) {
+ dev_warn(dev->mt76.dev,
+ "Restricted path/stream configuration for band %d\n", i);
+ dev_warn(dev->mt76.dev,
+ "path: %u/%u, rx_path: %u/%u, nss: %u/%u\n",
+ path, dflt_path, rx_path, dflt_rx_path, nss, dflt_nss);
+ }
+ }
+
+ return 0;
}
const char *mt7996_eeprom_name(struct mt7996_dev *dev)
{
- if (dev->bin_file_mode)
- return dev->mt76.bin_file_name;
-
if (dev->testmode_enable) {
if (is_mt7992(&dev->mt76))
return MT7992_EEPROM_DEFAULT_TM;
@@ -148,21 +194,18 @@ mt7996_get_dpd_per_band_size(struct mt7996_dev *dev, enum nl80211_band band)
}
static int
-mt7996_eeprom_load_default(struct mt7996_dev *dev)
+mt7996_eeprom_load_bin(struct mt7996_dev *dev)
{
u8 *eeprom = dev->mt76.eeprom.data;
const struct firmware *fw = NULL;
int ret;
- ret = request_firmware(&fw, mt7996_eeprom_name(dev), dev->mt76.dev);
+ ret = request_firmware(&fw, dev->mt76.bin_file_name, dev->mt76.dev);
if (ret)
return ret;
if (!fw || !fw->data) {
- if (dev->bin_file_mode)
- dev_err(dev->mt76.dev, "Invalid bin (bin file mode)\n");
- else
- dev_err(dev->mt76.dev, "Invalid default bin\n");
+ dev_err(dev->mt76.dev, "Invalid bin %s\n", dev->mt76.bin_file_name);
ret = -EINVAL;
goto out;
}
@@ -180,7 +223,7 @@ static int mt7996_eeprom_load_flash(struct mt7996_dev *dev)
{
int ret = 1;
- /* return > 0 for load success, return 0 for load failed, return < 0 for non memory */
+ /* return > 0 for load success, return 0 for load failed, return < 0 for no memory */
dev->bin_file_mode = mt76_check_bin_file_mode(&dev->mt76);
if (dev->bin_file_mode) {
dev->mt76.eeprom.size = MT7996_EEPROM_SIZE;
@@ -189,15 +232,15 @@ static int mt7996_eeprom_load_flash(struct mt7996_dev *dev)
if (!dev->mt76.eeprom.data)
return -ENOMEM;
- if (mt7996_eeprom_load_default(dev))
- return 0;
-
- if (mt7996_check_eeprom(dev))
+ if (mt7996_eeprom_load_bin(dev))
return 0;
} else {
ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE);
}
+ if (mt7996_check_eeprom(dev))
+ return 0;
+
return ret;
}
@@ -206,30 +249,30 @@ int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev)
u8 *eeprom;
int ret;
+ dev->testmode_enable = testmode_enable;
+
/* load eeprom in flash or bin file mode to determine fw mode */
ret = mt7996_eeprom_load_flash(dev);
+ if (ret <= 0)
+ goto out;
- if (ret < 0)
- return ret;
-
- if (ret) {
- dev->flash_mode = true;
- dev->eeprom_mode = dev->bin_file_mode ? BIN_FILE_MODE : FLASH_MODE;
- eeprom = dev->mt76.eeprom.data;
- /* testmode enable priority: eeprom field > module parameter */
- dev->testmode_enable = !mt7996_check_eeprom(dev) ? eeprom[MT_EE_TESTMODE_EN] :
- testmode_enable;
- }
+ dev->flash_mode = true;
+ dev->eeprom_mode = dev->bin_file_mode ? BIN_FILE_MODE : FLASH_MODE;
+ eeprom = dev->mt76.eeprom.data;
+ /* testmode enable priority: eeprom field > module parameter */
+ dev->testmode_enable = eeprom[MT_EE_TESTMODE_EN];
+out:
return ret;
}
static int mt7996_eeprom_load(struct mt7996_dev *dev)
{
+ const struct firmware *fw = NULL;
int ret;
- u8 free_block_num;
u32 block_num, i;
u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
+ u8 free_block_num;
/* flash or bin file mode eeprom is loaded before mcu init */
if (!dev->flash_mode) {
@@ -239,19 +282,47 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
/* efuse info isn't enough */
if (free_block_num >= 59)
- return -EINVAL;
+ goto dflt;
+
+ /* check if efuse contains valid eeprom data */
+ if (mt7996_mcu_get_eeprom(dev, 0, NULL) ||
+ mt7996_check_eeprom(dev))
+ goto dflt;
/* read eeprom data from efuse */
block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
- for (i = 0; i < block_num; i++) {
+ for (i = 1; i < block_num; i++) {
ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, NULL);
if (ret && ret != -EINVAL)
- return ret;
+ goto dflt;
}
dev->eeprom_mode = EFUSE_MODE;
}
- return mt7996_check_eeprom(dev);
+dflt:
+ ret = request_firmware(&fw, mt7996_eeprom_name(dev), dev->mt76.dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data) {
+ dev_err(dev->mt76.dev, "Invalid default bin\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (dev->eeprom_mode && !mt7996_check_eeprom_sku(dev, fw->data)) {
+ ret = 0;
+ goto out;
+ }
+
+ memcpy(dev->mt76.eeprom.data, fw->data, MT7996_EEPROM_SIZE);
+ dev->bin_file_mode = false;
+ dev->flash_mode = true;
+ dev->eeprom_mode = DEFAULT_BIN_MODE;
+ dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
+out:
+ release_firmware(fw);
+ return ret;
}
static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
@@ -323,32 +394,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
int max_path = 5, max_nss = 4;
int ret;
- switch (band_idx) {
- case MT_BAND1:
- path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1,
- eeprom[MT_EE_WIFI_CONF + 2]);
- rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1,
- eeprom[MT_EE_WIFI_CONF + 3]);
- nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1,
- eeprom[MT_EE_WIFI_CONF + 5]);
- break;
- case MT_BAND2:
- path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2,
- eeprom[MT_EE_WIFI_CONF + 2]);
- rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2,
- eeprom[MT_EE_WIFI_CONF + 4]);
- nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2,
- eeprom[MT_EE_WIFI_CONF + 5]);
- break;
- default:
- path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0,
- eeprom[MT_EE_WIFI_CONF + 1]);
- rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0,
- eeprom[MT_EE_WIFI_CONF + 3]);
- nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0,
- eeprom[MT_EE_WIFI_CONF + 4]);
- break;
- }
+ mt7996_parse_eeprom_stream(eeprom, band_idx, &path, &rx_path, &nss);
if (!path || path > max_path)
path = max_path;
@@ -437,17 +483,8 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
return ret;
ret = mt7996_eeprom_load(dev);
- if (ret < 0) {
- if (ret != -EINVAL)
- return ret;
-
- dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
- dev->bin_file_mode = false;
- dev->eeprom_mode = DEFAULT_BIN_MODE;
- ret = mt7996_eeprom_load_default(dev);
- if (ret)
- return ret;
- }
+ if (ret)
+ return ret;
ret = mt7996_eeprom_load_precal(dev);
if (ret)
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
index 8f0f87b6b..03a4fd07d 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
@@ -132,6 +132,38 @@ mt7996_get_channel_group_6g(int channel)
return DIV_ROUND_UP(channel - 29, 32);
}
+static inline void
+mt7996_parse_eeprom_stream(const u8 *eep, int band_idx,
+ u8 *path, u8 *rx_path, u8 *nss)
+{
+ switch (band_idx) {
+ case MT_BAND1:
+ *path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1,
+ eep[MT_EE_WIFI_CONF + 2]);
+ *rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1,
+ eep[MT_EE_WIFI_CONF + 3]);
+ *nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1,
+ eep[MT_EE_WIFI_CONF + 5]);
+ break;
+ case MT_BAND2:
+ *path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2,
+ eep[MT_EE_WIFI_CONF + 2]);
+ *rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2,
+ eep[MT_EE_WIFI_CONF + 4]);
+ *nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2,
+ eep[MT_EE_WIFI_CONF + 5]);
+ break;
+ default:
+ *path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0,
+ eep[MT_EE_WIFI_CONF + 1]);
+ *rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0,
+ eep[MT_EE_WIFI_CONF + 3]);
+ *nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0,
+ eep[MT_EE_WIFI_CONF + 4]);
+ break;
+ }
+}
+
enum mt7996_sku_rate_group {
SKU_CCK,
SKU_OFDM,
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
index 09652ef52..8db8b6805 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
@@ -2768,7 +2768,7 @@ static int mt7996_show_eeprom_mode(struct seq_file *s, void *data)
seq_printf(s, " flash mode\n");
break;
case BIN_FILE_MODE:
- seq_printf(s, " bin file mode\n filename = %s\n", mt7996_eeprom_name(dev));
+ seq_printf(s, " bin file mode\n filename = %s\n", dev->mt76.bin_file_name);
break;
default:
break;
--
2.39.2