Commit f1d96236 authored by Ryder Lee's avatar Ryder Lee Committed by Felix Fietkau
Browse files

mt76: mt7915: implement HE per-rate tx power support



Use firmware support for applying per-rate limit and power offsets.
This can support all HE RU types.

Signed-off-by: default avatarShayne Chen <shayne.chen@mediatek.com>
Signed-off-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Tested-by: default avatarChih-Min Chen <chih-min.chen@mediatek.com>
Tested-by: default avatarEvelyn Tsai <evelyn.tsai@mediatek.com>
Acked-by: default avatarYiwei Chung <yiwei.chung@mediatek.com>
Acked-by: default avatarYF Luo <yf.luo@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 5205071a
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -219,6 +219,63 @@ mt7915_queues_read(struct seq_file *s, void *data)
	return 0;
}

static void
mt7915_puts_rate_txpower(struct seq_file *s, s8 *delta,
			 s8 txpower_cur, int band)
{
	static const char * const sku_group_name[] = {
		"CCK", "OFDM", "HT20", "HT40",
		"VHT20", "VHT40", "VHT80", "VHT160",
		"RU26", "RU52", "RU106", "RU242/SU20",
		"RU484/SU40", "RU996/SU80", "RU2x996/SU160"
	};
	s8 txpower[MT7915_SKU_RATE_NUM];
	int i, idx = 0;

	for (i = 0; i < MT7915_SKU_RATE_NUM; i++)
		txpower[i] = DIV_ROUND_UP(txpower_cur + delta[i], 2);

	for (i = 0; i < MAX_SKU_RATE_GROUP_NUM; i++) {
		const struct sku_group *sku = &mt7915_sku_groups[i];
		u32 offset = sku->offset[band];

		if (!offset) {
			idx += sku->len;
			continue;
		}

		mt76_seq_puts_array(s, sku_group_name[i],
				    txpower + idx, sku->len);
		idx += sku->len;
	}
}

static int
mt7915_read_rate_txpower(struct seq_file *s, void *data)
{
	struct mt7915_dev *dev = dev_get_drvdata(s->private);
	struct mt76_phy *mphy = &dev->mphy;
	enum nl80211_band band = mphy->chandef.chan->band;
	s8 *delta = dev->rate_power[band];
	s8 txpower_base = mphy->txpower_cur - delta[MT7915_SKU_MAX_DELTA_IDX];

	seq_puts(s, "Band 0:\n");
	mt7915_puts_rate_txpower(s, delta, txpower_base, band);

	if (dev->mt76.phy2) {
		mphy = dev->mt76.phy2;
		band = mphy->chandef.chan->band;
		delta = dev->rate_power[band];
		txpower_base = mphy->txpower_cur -
			       delta[MT7915_SKU_MAX_DELTA_IDX];

		seq_puts(s, "Band 1:\n");
		mt7915_puts_rate_txpower(s, delta, txpower_base, band);
	}

	return 0;
}

int mt7915_init_debugfs(struct mt7915_dev *dev)
{
	struct dentry *dir;
@@ -240,6 +297,8 @@ int mt7915_init_debugfs(struct mt7915_dev *dev)
	debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger);
	debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
				    mt7915_read_temperature);
	debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir,
				    mt7915_read_rate_txpower);

	return 0;
}
+118 −0
Original line number Diff line number Diff line
@@ -123,3 +123,121 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,

	return mt7915_eeprom_read(dev, index);
}

static const u8 sku_cck_delta_map[] = {
	SKU_CCK_GROUP0,
	SKU_CCK_GROUP0,
	SKU_CCK_GROUP1,
	SKU_CCK_GROUP1,
};

static const u8 sku_ofdm_delta_map[] = {
	SKU_OFDM_GROUP0,
	SKU_OFDM_GROUP0,
	SKU_OFDM_GROUP1,
	SKU_OFDM_GROUP1,
	SKU_OFDM_GROUP2,
	SKU_OFDM_GROUP2,
	SKU_OFDM_GROUP3,
	SKU_OFDM_GROUP4,
};

static const u8 sku_mcs_delta_map[] = {
	SKU_MCS_GROUP0,
	SKU_MCS_GROUP1,
	SKU_MCS_GROUP1,
	SKU_MCS_GROUP2,
	SKU_MCS_GROUP2,
	SKU_MCS_GROUP3,
	SKU_MCS_GROUP4,
	SKU_MCS_GROUP5,
	SKU_MCS_GROUP6,
	SKU_MCS_GROUP7,
	SKU_MCS_GROUP8,
	SKU_MCS_GROUP9,
};

#define SKU_GROUP(_mode, _len, _ofs_2g, _ofs_5g, _map)	\
	[_mode] = {					\
	.len = _len,					\
	.offset = {					\
		_ofs_2g,				\
		_ofs_5g,				\
	},						\
	.delta_map = _map				\
}

const struct sku_group mt7915_sku_groups[] = {
	SKU_GROUP(SKU_CCK, 4, 0x252, 0, sku_cck_delta_map),
	SKU_GROUP(SKU_OFDM, 8, 0x254, 0x29d, sku_ofdm_delta_map),

	SKU_GROUP(SKU_HT_BW20, 8, 0x259, 0x2a2, sku_mcs_delta_map),
	SKU_GROUP(SKU_HT_BW40, 9, 0x262, 0x2ab, sku_mcs_delta_map),
	SKU_GROUP(SKU_VHT_BW20, 12, 0x259, 0x2a2, sku_mcs_delta_map),
	SKU_GROUP(SKU_VHT_BW40, 12, 0x262, 0x2ab, sku_mcs_delta_map),
	SKU_GROUP(SKU_VHT_BW80, 12, 0, 0x2b4, sku_mcs_delta_map),
	SKU_GROUP(SKU_VHT_BW160, 12, 0, 0, sku_mcs_delta_map),

	SKU_GROUP(SKU_HE_RU26, 12, 0x27f, 0x2dd, sku_mcs_delta_map),
	SKU_GROUP(SKU_HE_RU52, 12, 0x289, 0x2e7, sku_mcs_delta_map),
	SKU_GROUP(SKU_HE_RU106, 12, 0x293, 0x2f1, sku_mcs_delta_map),
	SKU_GROUP(SKU_HE_RU242, 12, 0x26b, 0x2bf, sku_mcs_delta_map),
	SKU_GROUP(SKU_HE_RU484, 12, 0x275, 0x2c9, sku_mcs_delta_map),
	SKU_GROUP(SKU_HE_RU996, 12, 0, 0x2d3, sku_mcs_delta_map),
	SKU_GROUP(SKU_HE_RU2x996, 12, 0, 0, sku_mcs_delta_map),
};

static s8
mt7915_get_sku_delta(struct mt7915_dev *dev, u32 addr)
{
	u32 val = mt7915_eeprom_read(dev, addr);
	s8 delta = FIELD_GET(SKU_DELTA_VAL, val);

	if (!(val & SKU_DELTA_EN))
		return 0;

	return val & SKU_DELTA_ADD ? delta : -delta;
}

static void
mt7915_eeprom_init_sku_band(struct mt7915_dev *dev,
			    struct ieee80211_supported_band *sband)
{
	int i, band = sband->band;
	s8 *rate_power = dev->rate_power[band], max_delta = 0;
	u8 idx = 0;

	for (i = 0; i < ARRAY_SIZE(mt7915_sku_groups); i++) {
		const struct sku_group *sku = &mt7915_sku_groups[i];
		u32 offset = sku->offset[band];
		int j;

		if (!offset) {
			idx += sku->len;
			continue;
		}

		rate_power[idx++] = mt7915_get_sku_delta(dev, offset);
		if (rate_power[idx - 1] > max_delta)
			max_delta = rate_power[idx - 1];

		if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
			offset += 1;

		for (j = 1; j < sku->len; j++) {
			u32 addr = offset + sku->delta_map[j];

			rate_power[idx++] = mt7915_get_sku_delta(dev, addr);
			if (rate_power[idx - 1] > max_delta)
				max_delta = rate_power[idx - 1];
		}
	}

	rate_power[idx] = max_delta;
}

void mt7915_eeprom_init_sku(struct mt7915_dev *dev)
{
	mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_2g.sband);
	mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_5g.sband);
}
+47 −0
Original line number Diff line number Diff line
@@ -37,6 +37,51 @@ enum mt7915_eeprom_band {
	MT_EE_DBDC,
};

#define SKU_DELTA_VAL		GENMASK(5, 0)
#define SKU_DELTA_ADD		BIT(6)
#define SKU_DELTA_EN		BIT(7)

enum mt7915_sku_delta_group {
	SKU_CCK_GROUP0,
	SKU_CCK_GROUP1,

	SKU_OFDM_GROUP0 = 0,
	SKU_OFDM_GROUP1,
	SKU_OFDM_GROUP2,
	SKU_OFDM_GROUP3,
	SKU_OFDM_GROUP4,

	SKU_MCS_GROUP0 = 0,
	SKU_MCS_GROUP1,
	SKU_MCS_GROUP2,
	SKU_MCS_GROUP3,
	SKU_MCS_GROUP4,
	SKU_MCS_GROUP5,
	SKU_MCS_GROUP6,
	SKU_MCS_GROUP7,
	SKU_MCS_GROUP8,
	SKU_MCS_GROUP9,
};

enum mt7915_sku_rate_group {
	SKU_CCK,
	SKU_OFDM,
	SKU_HT_BW20,
	SKU_HT_BW40,
	SKU_VHT_BW20,
	SKU_VHT_BW40,
	SKU_VHT_BW80,
	SKU_VHT_BW160,
	SKU_HE_RU26,
	SKU_HE_RU52,
	SKU_HE_RU106,
	SKU_HE_RU242,
	SKU_HE_RU484,
	SKU_HE_RU996,
	SKU_HE_RU2x996,
	MAX_SKU_RATE_GROUP_NUM,
};

struct sku_group {
	u8 len;
	u16 offset[2];
@@ -75,4 +120,6 @@ mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band)
		return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_2G;
}

extern const struct sku_group mt7915_sku_groups[];

#endif
+2 −0
Original line number Diff line number Diff line
@@ -85,6 +85,8 @@ static void mt7915_init_txpower(struct mt7915_dev *dev)
{
	mt7915_init_txpower_band(dev, &dev->mphy.sband_2g.sband);
	mt7915_init_txpower_band(dev, &dev->mphy.sband_5g.sband);

	mt7915_eeprom_init_sku(dev);
}

static void mt7915_init_work(struct work_struct *work)
+7 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ static int mt7915_start(struct ieee80211_hw *hw)
		mt7915_mcu_set_scs(dev, 1, true);
	}

	mt7915_mcu_set_sku_en(phy, true);
	mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);

	set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
@@ -325,6 +326,12 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
		ieee80211_wake_queues(hw);
	}

	if (changed & IEEE80211_CONF_CHANGE_POWER) {
		ret = mt7915_mcu_set_sku(phy);
		if (ret)
			return ret;
	}

	mutex_lock(&dev->mt76.mutex);

	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
Loading