@@ -961,6 +961,20 @@ struct mt76_sta_stats {
u32 rx_ampdu_len[15];
};
+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
void mt76_inc_ampdu_bucket(int ampdu_len, struct mt76_sta_stats *stats)
{
@@ -108,6 +108,28 @@ mt7915_eeprom_load_default(struct mt7915_dev *dev)
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;
@@ -139,6 +161,122 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
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-<bus>-<id>.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;
@@ -149,6 +287,29 @@ static void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy)
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 + phy->band_idx],
+ 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 + phy->band_idx],
+ 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 + phy->band_idx];
+ 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;
@@ -270,6 +431,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);
+
dev->bin_file_mode = mt76_check_bin_file_mode(&dev->mt76);
if (dev->bin_file_mode) {
@@ -1195,7 +1195,6 @@ int mt7915_register_device(struct mt7915_dev *dev)
if (ret)
goto unreg_dev;
- ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
if (phy2) {
ret = mt7915_register_ext_phy(dev, phy2);
@@ -1203,6 +1202,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
goto unreg_thermal;
}
+ ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+
mt7915_init_debugfs(&dev->phy);
dev->ser.hw_init_done = true;
@@ -5,6 +5,7 @@
#define __MT7915_H
#include <linux/interrupt.h>
+#include <linux/firmware.h>
#include <linux/ktime.h>
#include "../mt76_connac.h"
#include "regs.h"
@@ -28,6 +29,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"
@@ -467,6 +470,13 @@ struct mt7915_dev {
u8 dpd_chan_num_5g;
u8 dpd_chan_num_6g;
+ 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;
u8 debug_wa;