diff -Naur a/mt76.h b/mt76.h --- a/mt76.h 2023-01-27 17:31:03.000000000 +0700 +++ b/mt76.h 2023-01-28 22:29:46.340592100 +0700 @@ -993,6 +993,20 @@ return 0; } +static inline const char *mt76_bus_str(enum mt76_bus_type bus) +{ + switch (bus) { + case MT76_BUS_MMIO: + return "mmio"; + case MT76_BUS_USB: + return "usb"; + case MT76_BUS_SDIO: + return "sdio"; + } + + return "unknown"; +} + static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, int ring_base) { diff -Naur a/mt7915/eeprom.c b/mt7915/eeprom.c --- a/mt7915/eeprom.c 2023-01-28 18:55:54.208002700 +0700 +++ b/mt7915/eeprom.c 2023-01-30 01:10:09.430897600 +0700 @@ -2,6 +2,7 @@ /* Copyright (C) 2020 MediaTek Inc. */ #include +#include #include "mt7915.h" #include "eeprom.h" @@ -99,6 +100,28 @@ return ret; } +static const struct firmware +*mt7915_eeprom_load_file(struct mt7915_dev *dev, const char *dir, const char *file) +{ + char filename[100]; + const struct firmware *fw = NULL; + int ret; + + if (!file) + return ERR_PTR(-ENOENT); + + if (!dir) + dir = "."; + + snprintf(filename, sizeof(filename), "%s/%s", dir, file); + ret = request_firmware(&fw, filename, dev->mt76.dev); + + if (ret) + return ERR_PTR(ret); + + return fw; +} + static int mt7915_eeprom_load(struct mt7915_dev *dev) { int ret; @@ -135,6 +158,122 @@ return mt7915_check_eeprom(dev); } +static int mt7915_fetch_fwcfg_file(struct mt7915_dev *dev) +{ + char filename[100]; + const struct firmware *fw; + const char *buf; + size_t i = 0; + char val[100]; + size_t key_idx; + size_t val_idx; + char c; + long t; + + dev->fwcfg.flags = 0; + + /* fwcfg--.txt */ + scnprintf(filename, sizeof(filename), "fwcfg-%s-%s.txt", + mt76_bus_str(dev->mt76.bus->type), dev_name(dev->mt76.dev)); + + fw = mt7915_eeprom_load_file(dev, MT7915_FIRMWARE_BD, filename); + if (IS_ERR(fw)) + return PTR_ERR(fw); + + /* Now, attempt to parse results. + * Format is key=value + */ + buf = (const char *)(fw->data); + while (i < fw->size) { +start_again: + /* First, eat space, or entire line if we have # as first char */ + c = buf[i]; + while (isspace(c)) { + i++; + if (i >= fw->size) + goto done; + c = buf[i]; + } + /* Eat comment ? */ + if (c == '#') { + i++; + while (i < fw->size) { + c = buf[i]; + i++; + if (c == '\n') + goto start_again; + } + /* Found no newline, must be done. */ + goto done; + } + + /* If here, we have start of token, store it in 'filename' to save space */ + key_idx = 0; + while (i < fw->size) { + c = buf[i]; + if (c == '=') { + i++; + c = buf[i]; + /* Eat any space after the '=' sign. */ + while (i < fw->size) { + if (!isspace(c)) + break; + i++; + c = buf[i]; + } + break; + } + if (isspace(c)) { + i++; + continue; + } + filename[key_idx] = c; + key_idx++; + if (key_idx >= sizeof(filename)) { + /* Too long, bail out. */ + goto done; + } + i++; + } + filename[key_idx] = 0; /* null terminate */ + + /* We have found the key, now find the value */ + val_idx = 0; + while (i < fw->size) { + c = buf[i]; + if (isspace(c)) + break; + val[val_idx] = c; + val_idx++; + if (val_idx >= sizeof(val)) { + /* Too long, bail out. */ + goto done; + } + i++; + } + val[val_idx] = 0; /* null terminate value */ + + /* We have key and value now. */ + dev_warn(dev->mt76.dev, "fwcfg key: %s val: %s\n", + filename, val); + + /* Assign key and values as appropriate */ + if (strcasecmp(filename, "high_band") == 0) { + if (kstrtol(val, 0, &t) == 0) { + dev->fwcfg.high_band = t; + dev->fwcfg.flags |= MT7915_FWCFG_HIGH_BAND; + } + } else { + dev_warn(dev->mt76.dev, "Unknown fwcfg key name -:%s:-, val: %s\n", + filename, val); + } + } + +done: + release_firmware(fw); + return 0; +} + static void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; @@ -146,6 +285,28 @@ val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); if (!is_mt7915(&dev->mt76)) { + /* fwcfg intervention to set upper band to 5GHz or 6GHz */ + if ((dev->fwcfg.flags & MT7915_FWCFG_HIGH_BAND) && + val == MT_EE_V2_BAND_SEL_5GHZ_6GHZ) { + dev_info(dev->mt76.dev, "FWCFG: Overriding 7916 high_band with %luGHz\n", + (unsigned long)dev->fwcfg.high_band); + + if (dev->fwcfg.high_band == 5) { + u8p_replace_bits(&eeprom[MT_EE_WIFI_CONF + band], + MT_EE_V2_BAND_SEL_5GHZ, + MT_EE_WIFI_CONF0_BAND_SEL); + } + if (dev->fwcfg.high_band == 6) { + u8p_replace_bits(&eeprom[MT_EE_WIFI_CONF + band], + MT_EE_V2_BAND_SEL_6GHZ, + MT_EE_WIFI_CONF0_BAND_SEL); + } + + /* force to buffer mode */ + dev->flash_mode = true; + val = eeprom[MT_EE_WIFI_CONF + band]; + val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); + } switch (val) { case MT_EE_V2_BAND_SEL_5GHZ: phy->mt76->cap.has_5ghz = true; @@ -234,6 +395,9 @@ int mt7915_eeprom_init(struct mt7915_dev *dev) { int ret; + + /* First, see if we have a special config file for this firmware */ + mt7915_fetch_fwcfg_file(dev); ret = mt7915_eeprom_load(dev); if (ret < 0) { diff -Naur a/mt7915/init.c b/mt7915/init.c --- a/mt7915/init.c 2023-01-27 17:31:03.000000000 +0700 +++ b/mt7915/init.c 2023-01-29 18:30:17.171908500 +0700 @@ -1213,13 +1213,13 @@ if (ret) goto unreg_dev; - ieee80211_queue_work(mt76_hw(dev), &dev->init_work); - if (phy2) { ret = mt7915_register_ext_phy(dev, phy2); if (ret) goto unreg_thermal; } + + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); dev->recovery.hw_init_done = true; diff -Naur a/mt7915/mt7915.h b/mt7915/mt7915.h --- a/mt7915/mt7915.h 2023-01-27 17:31:03.000000000 +0700 +++ b/mt7915/mt7915.h 2023-01-28 22:43:03.845479300 +0700 @@ -5,6 +5,7 @@ #define __MT7915_H #include +#include #include #include "../mt76_connac.h" #include "regs.h" @@ -26,6 +27,8 @@ #define MT7915_RX_RING_SIZE 1536 #define MT7915_RX_MCU_RING_SIZE 512 +#define MT7915_FIRMWARE_BD "mediatek" + #define MT7915_FIRMWARE_WA "mediatek/mt7915_wa.bin" #define MT7915_FIRMWARE_WM "mediatek/mt7915_wm.bin" #define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin" @@ -358,6 +361,13 @@ struct rchan *relay_fwlog; void *cal; + + struct { +#define MT7915_FWCFG_HIGH_BAND BIT(1) + + u32 flags; /* let us know which fields have been set */ + u32 high_band; /* sets upper-band to use ('5' or '6')GHz */ + } fwcfg; struct { u8 debug_wm;