Commit ad380ad1 authored by Felix Fietkau's avatar Felix Fietkau
Browse files

mt76: mt7615: add support for applying DC offset calibration from EEPROM



When the EEPROM data is read from flash, it can contain DC offset calibration
data. Add support for sending the data to the firmware.

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent b90728f8
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -72,7 +72,8 @@ static int mt7615_eeprom_load(struct mt7615_dev *dev, u32 addr)
{
	int ret;

	ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_SIZE);
	ret = mt76_eeprom_init(&dev->mt76, MT7615_EEPROM_SIZE +
					   MT7615_EEPROM_EXTRA_DATA);
	if (ret < 0)
		return ret;

@@ -280,11 +281,13 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr)
		return ret;

	ret = mt7615_check_eeprom(&dev->mt76);
	if (ret && dev->mt76.otp.data)
	if (ret && dev->mt76.otp.data) {
		memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
		       MT7615_EEPROM_SIZE);
	else
	} else {
		dev->flash_eeprom = true;
		mt7615_cal_free_data(dev);
	}

	mt7615_eeprom_parse_hw_cap(dev);
	memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
+19 −0
Original line number Diff line number Diff line
@@ -6,6 +6,21 @@

#include "mt7615.h"


#define MT7615_EEPROM_DCOC_OFFSET		MT7615_EEPROM_SIZE
#define MT7615_EEPROM_DCOC_SIZE			256
#define MT7615_EEPROM_DCOC_COUNT		34

#define MT7615_EEPROM_TXDPD_OFFSET		(MT7615_EEPROM_SIZE + \
						 MT7615_EEPROM_DCOC_COUNT * \
						 MT7615_EEPROM_DCOC_SIZE)
#define MT7615_EEPROM_TXDPD_SIZE		216
#define MT7615_EEPROM_TXDPD_COUNT		(44 + 3)

#define MT7615_EEPROM_EXTRA_DATA		(MT7615_EEPROM_TXDPD_OFFSET + \
						 MT7615_EEPROM_TXDPD_COUNT * \
						 MT7615_EEPROM_TXDPD_SIZE)

enum mt7615_eeprom_field {
	MT_EE_CHIP_ID =				0x000,
	MT_EE_VERSION =				0x002,
@@ -13,6 +28,7 @@ enum mt7615_eeprom_field {
	MT_EE_NIC_CONF_0 =			0x034,
	MT_EE_NIC_CONF_1 =			0x036,
	MT_EE_WIFI_CONF =			0x03e,
	MT_EE_CALDATA_FLASH =			0x052,
	MT_EE_TX0_2G_TARGET_POWER =		0x058,
	MT_EE_TX0_5G_G0_TARGET_POWER =		0x070,
	MT_EE_TX1_5G_G0_TARGET_POWER =		0x098,
@@ -27,6 +43,9 @@ enum mt7615_eeprom_field {
	MT7663_EE_MAX =				0x400,
};

#define MT_EE_CALDATA_FLASH_TX_DPD		BIT(0)
#define MT_EE_CALDATA_FLASH_RX_CAL		BIT(1)

#define MT_EE_NIC_CONF_TX_MASK			GENMASK(7, 4)
#define MT_EE_NIC_CONF_RX_MASK			GENMASK(3, 0)

+3 −0
Original line number Diff line number Diff line
@@ -253,6 +253,9 @@ static int mt7615_set_channel(struct mt7615_phy *phy)
	mt7615_init_dfs_state(phy);
	mt76_set_channel(phy->mt76);

	if (is_mt7615(&dev->mt76) && dev->flash_eeprom)
		mt7615_mcu_apply_rx_dcoc(phy);

	ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH);
	if (ret)
		goto out;
+169 −26
Original line number Diff line number Diff line
@@ -2481,6 +2481,25 @@ static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku)
	}
}

static u8 mt7615_mcu_chan_bw(struct cfg80211_chan_def *chandef)
{
	static const u8 width_to_bw[] = {
		[NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ,
		[NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ,
		[NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ,
		[NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ,
		[NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ,
		[NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ,
		[NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ,
		[NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ,
	};

	if (chandef->width >= ARRAY_SIZE(width_to_bw))
		return 0;

	return width_to_bw[chandef->width];
}

int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
{
	struct mt7615_dev *dev = phy->dev;
@@ -2521,32 +2540,7 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
		req.switch_reason = CH_SWITCH_NORMAL;

	req.band_idx = phy != &dev->phy;

	switch (chandef->width) {
	case NL80211_CHAN_WIDTH_40:
		req.bw = CMD_CBW_40MHZ;
		break;
	case NL80211_CHAN_WIDTH_80:
		req.bw = CMD_CBW_80MHZ;
		break;
	case NL80211_CHAN_WIDTH_80P80:
		req.bw = CMD_CBW_8080MHZ;
		break;
	case NL80211_CHAN_WIDTH_160:
		req.bw = CMD_CBW_160MHZ;
		break;
	case NL80211_CHAN_WIDTH_5:
		req.bw = CMD_CBW_5MHZ;
		break;
	case NL80211_CHAN_WIDTH_10:
		req.bw = CMD_CBW_10MHZ;
		break;
	case NL80211_CHAN_WIDTH_20_NOHT:
	case NL80211_CHAN_WIDTH_20:
	default:
		req.bw = CMD_CBW_20MHZ;
		break;
	}
	req.bw = mt7615_mcu_chan_bw(chandef);

	mt7615_mcu_set_txpower_sku(phy, req.txpower_sku);

@@ -2836,3 +2830,152 @@ int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy,
	return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE,
				   &req, sizeof(req), false);
}

static int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
{
	int i;

	for (i = 0; i < n_freqs; i++)
		if (cur == freqs[i])
			return i;

	return -1;
}

static int mt7615_dcoc_freq_idx(u16 freq, u8 bw)
{
	static const u16 freq_list[] = {
		4980, 5805, 5905, 5190,
		5230, 5270, 5310, 5350,
		5390, 5430, 5470, 5510,
		5550, 5590, 5630, 5670,
		5710, 5755, 5795, 5835,
		5875, 5210, 5290, 5370,
		5450, 5530, 5610, 5690,
		5775, 5855
	};
	static const u16 freq_bw40[] = {
		5190, 5230, 5270, 5310,
		5350, 5390, 5430, 5470,
		5510, 5550, 5590, 5630,
		5670, 5710, 5755, 5795,
		5835, 5875
	};
	int offset_2g = ARRAY_SIZE(freq_list);
	int idx;

	if (freq < 4000) {
		if (freq < 2427)
			return offset_2g;
		if (freq < 2442)
			return offset_2g + 1;
		if (freq < 2457)
			return offset_2g + 2;

		return offset_2g + 3;
	}

	switch (bw) {
	case NL80211_CHAN_WIDTH_80:
	case NL80211_CHAN_WIDTH_80P80:
	case NL80211_CHAN_WIDTH_160:
		break;
	default:
		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
					   freq + 10);
		if (idx >= 0) {
			freq = freq_bw40[idx];
			break;
		}

		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
					   freq - 10);
		if (idx >= 0) {
			freq = freq_bw40[idx];
			break;
		}
		/* fall through */
	case NL80211_CHAN_WIDTH_40:
		idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
					   freq);
		if (idx >= 0)
			break;

		return -1;

	}

	return mt7615_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
}

int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy)
{
	struct mt7615_dev *dev = phy->dev;
	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
	int freq2 = chandef->center_freq2;
	int ret;
	struct {
		u8 direction;
		u8 runtime_calibration;
		u8 _rsv[2];

		__le16 center_freq;
		u8 bw;
		u8 band;
		u8 is_freq2;
		u8 success;
		u8 dbdc_en;

		u8 _rsv2;

		struct {
			__le32 sx0_i_lna[4];
			__le32 sx0_q_lna[4];

			__le32 sx2_i_lna[4];
			__le32 sx2_q_lna[4];
		} dcoc_data[4];
	} req = {
		.direction = 1,

		.bw = mt7615_mcu_chan_bw(chandef),
		.band = chandef->center_freq1 > 4000,
		.dbdc_en = !!dev->mt76.phy2,
	};
	u16 center_freq = chandef->center_freq1;
	int freq_idx;
	u8 *eep = dev->mt76.eeprom.data;

	if (!(eep[MT_EE_CALDATA_FLASH] & MT_EE_CALDATA_FLASH_RX_CAL))
		return 0;

	if (chandef->width == NL80211_CHAN_WIDTH_160) {
		freq2 = center_freq + 40;
		center_freq -= 40;
	}

again:
	req.runtime_calibration = 1;
	freq_idx = mt7615_dcoc_freq_idx(center_freq, chandef->width);
	if (freq_idx < 0)
		goto out;

	memcpy(req.dcoc_data, eep + MT7615_EEPROM_DCOC_OFFSET +
			      freq_idx * MT7615_EEPROM_DCOC_SIZE,
	       sizeof(req.dcoc_data));
	req.runtime_calibration = 0;

out:
	req.center_freq = cpu_to_le16(center_freq);
	ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RXDCOC_CAL, &req,
				  sizeof(req), true);

	if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
	     chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
		req.is_freq2 = true;
		center_freq = freq2;
		goto again;
	}

	return ret;
}
+1 −0
Original line number Diff line number Diff line
@@ -270,6 +270,7 @@ enum {
	MCU_EXT_CMD_BCN_OFFLOAD = 0x49,
	MCU_EXT_CMD_SET_RX_PATH = 0x4e,
	MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
	MCU_EXT_CMD_RXDCOC_CAL = 0x59,
	MCU_EXT_CMD_SET_RDD_TH = 0x7c,
	MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d,
};
Loading