18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include "mt7915.h"
58c2ecf20Sopenharmony_ci#include "eeprom.h"
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_cistatic inline bool mt7915_efuse_valid(u8 val)
88c2ecf20Sopenharmony_ci{
98c2ecf20Sopenharmony_ci	return !(val == 0xff);
108c2ecf20Sopenharmony_ci}
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ciu32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	u8 *data = dev->mt76.eeprom.data;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	if (!mt7915_efuse_valid(data[offset]))
178c2ecf20Sopenharmony_ci		mt7915_mcu_get_eeprom(dev, offset);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	return data[offset];
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistatic int mt7915_eeprom_load(struct mt7915_dev *dev)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	int ret;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	ret = mt76_eeprom_init(&dev->mt76, MT7915_EEPROM_SIZE);
278c2ecf20Sopenharmony_ci	if (ret < 0)
288c2ecf20Sopenharmony_ci		return ret;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	return 0;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic int mt7915_check_eeprom(struct mt7915_dev *dev)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	u16 val;
388c2ecf20Sopenharmony_ci	u8 *eeprom = dev->mt76.eeprom.data;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	mt7915_eeprom_read(dev, 0);
418c2ecf20Sopenharmony_ci	val = get_unaligned_le16(eeprom);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	switch (val) {
448c2ecf20Sopenharmony_ci	case 0x7915:
458c2ecf20Sopenharmony_ci		return 0;
468c2ecf20Sopenharmony_ci	default:
478c2ecf20Sopenharmony_ci		return -EINVAL;
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	u8 *eeprom = dev->mt76.eeprom.data;
548c2ecf20Sopenharmony_ci	u8 tx_mask, max_nss = 4;
558c2ecf20Sopenharmony_ci	u32 val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val);
588c2ecf20Sopenharmony_ci	switch (val) {
598c2ecf20Sopenharmony_ci	case MT_EE_5GHZ:
608c2ecf20Sopenharmony_ci		dev->mphy.cap.has_5ghz = true;
618c2ecf20Sopenharmony_ci		break;
628c2ecf20Sopenharmony_ci	case MT_EE_2GHZ:
638c2ecf20Sopenharmony_ci		dev->mphy.cap.has_2ghz = true;
648c2ecf20Sopenharmony_ci		break;
658c2ecf20Sopenharmony_ci	default:
668c2ecf20Sopenharmony_ci		dev->mphy.cap.has_2ghz = true;
678c2ecf20Sopenharmony_ci		dev->mphy.cap.has_5ghz = true;
688c2ecf20Sopenharmony_ci		break;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/* read tx mask from eeprom */
728c2ecf20Sopenharmony_ci	tx_mask =  FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
738c2ecf20Sopenharmony_ci			     eeprom[MT_EE_WIFI_CONF]);
748c2ecf20Sopenharmony_ci	if (!tx_mask || tx_mask > max_nss)
758c2ecf20Sopenharmony_ci		tx_mask = max_nss;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	dev->chainmask = BIT(tx_mask) - 1;
788c2ecf20Sopenharmony_ci	dev->mphy.antenna_mask = dev->chainmask;
798c2ecf20Sopenharmony_ci	dev->phy.chainmask = dev->chainmask;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciint mt7915_eeprom_init(struct mt7915_dev *dev)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	int ret;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	ret = mt7915_eeprom_load(dev);
878c2ecf20Sopenharmony_ci	if (ret < 0)
888c2ecf20Sopenharmony_ci		return ret;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	ret = mt7915_check_eeprom(dev);
918c2ecf20Sopenharmony_ci	if (ret)
928c2ecf20Sopenharmony_ci		return ret;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	mt7915_eeprom_parse_hw_cap(dev);
958c2ecf20Sopenharmony_ci	memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
968c2ecf20Sopenharmony_ci	       ETH_ALEN);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	mt76_eeprom_override(&dev->mt76);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return 0;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciint mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
1048c2ecf20Sopenharmony_ci				   struct ieee80211_channel *chan,
1058c2ecf20Sopenharmony_ci				   u8 chain_idx)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int index, target_power;
1088c2ecf20Sopenharmony_ci	bool tssi_on;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (chain_idx > 3)
1118c2ecf20Sopenharmony_ci		return -EINVAL;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	tssi_on = mt7915_tssi_enabled(dev, chan->band);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (chan->band == NL80211_BAND_2GHZ) {
1168c2ecf20Sopenharmony_ci		index = MT_EE_TX0_POWER_2G + chain_idx * 3;
1178c2ecf20Sopenharmony_ci		target_power = mt7915_eeprom_read(dev, index);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci		if (!tssi_on)
1208c2ecf20Sopenharmony_ci			target_power += mt7915_eeprom_read(dev, index + 1);
1218c2ecf20Sopenharmony_ci	} else {
1228c2ecf20Sopenharmony_ci		int group = mt7915_get_channel_group(chan->hw_value);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		index = MT_EE_TX0_POWER_5G + chain_idx * 12;
1258c2ecf20Sopenharmony_ci		target_power = mt7915_eeprom_read(dev, index + group);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		if (!tssi_on)
1288c2ecf20Sopenharmony_ci			target_power += mt7915_eeprom_read(dev, index + 8);
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return target_power;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic const u8 sku_cck_delta_map[] = {
1358c2ecf20Sopenharmony_ci	SKU_CCK_GROUP0,
1368c2ecf20Sopenharmony_ci	SKU_CCK_GROUP0,
1378c2ecf20Sopenharmony_ci	SKU_CCK_GROUP1,
1388c2ecf20Sopenharmony_ci	SKU_CCK_GROUP1,
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic const u8 sku_ofdm_delta_map[] = {
1428c2ecf20Sopenharmony_ci	SKU_OFDM_GROUP0,
1438c2ecf20Sopenharmony_ci	SKU_OFDM_GROUP0,
1448c2ecf20Sopenharmony_ci	SKU_OFDM_GROUP1,
1458c2ecf20Sopenharmony_ci	SKU_OFDM_GROUP1,
1468c2ecf20Sopenharmony_ci	SKU_OFDM_GROUP2,
1478c2ecf20Sopenharmony_ci	SKU_OFDM_GROUP2,
1488c2ecf20Sopenharmony_ci	SKU_OFDM_GROUP3,
1498c2ecf20Sopenharmony_ci	SKU_OFDM_GROUP4,
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic const u8 sku_mcs_delta_map[] = {
1538c2ecf20Sopenharmony_ci	SKU_MCS_GROUP0,
1548c2ecf20Sopenharmony_ci	SKU_MCS_GROUP1,
1558c2ecf20Sopenharmony_ci	SKU_MCS_GROUP1,
1568c2ecf20Sopenharmony_ci	SKU_MCS_GROUP2,
1578c2ecf20Sopenharmony_ci	SKU_MCS_GROUP2,
1588c2ecf20Sopenharmony_ci	SKU_MCS_GROUP3,
1598c2ecf20Sopenharmony_ci	SKU_MCS_GROUP4,
1608c2ecf20Sopenharmony_ci	SKU_MCS_GROUP5,
1618c2ecf20Sopenharmony_ci	SKU_MCS_GROUP6,
1628c2ecf20Sopenharmony_ci	SKU_MCS_GROUP7,
1638c2ecf20Sopenharmony_ci	SKU_MCS_GROUP8,
1648c2ecf20Sopenharmony_ci	SKU_MCS_GROUP9,
1658c2ecf20Sopenharmony_ci};
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci#define SKU_GROUP(_mode, _len, _ofs_2g, _ofs_5g, _map)	\
1688c2ecf20Sopenharmony_ci	[_mode] = {					\
1698c2ecf20Sopenharmony_ci	.len = _len,					\
1708c2ecf20Sopenharmony_ci	.offset = {					\
1718c2ecf20Sopenharmony_ci		_ofs_2g,				\
1728c2ecf20Sopenharmony_ci		_ofs_5g,				\
1738c2ecf20Sopenharmony_ci	},						\
1748c2ecf20Sopenharmony_ci	.delta_map = _map				\
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ciconst struct sku_group mt7915_sku_groups[] = {
1788c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_CCK, 4, 0x252, 0, sku_cck_delta_map),
1798c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_OFDM, 8, 0x254, 0x29d, sku_ofdm_delta_map),
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HT_BW20, 8, 0x259, 0x2a2, sku_mcs_delta_map),
1828c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HT_BW40, 9, 0x262, 0x2ab, sku_mcs_delta_map),
1838c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_VHT_BW20, 12, 0x259, 0x2a2, sku_mcs_delta_map),
1848c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_VHT_BW40, 12, 0x262, 0x2ab, sku_mcs_delta_map),
1858c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_VHT_BW80, 12, 0, 0x2b4, sku_mcs_delta_map),
1868c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_VHT_BW160, 12, 0, 0, sku_mcs_delta_map),
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HE_RU26, 12, 0x27f, 0x2dd, sku_mcs_delta_map),
1898c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HE_RU52, 12, 0x289, 0x2e7, sku_mcs_delta_map),
1908c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HE_RU106, 12, 0x293, 0x2f1, sku_mcs_delta_map),
1918c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HE_RU242, 12, 0x26b, 0x2bf, sku_mcs_delta_map),
1928c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HE_RU484, 12, 0x275, 0x2c9, sku_mcs_delta_map),
1938c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HE_RU996, 12, 0, 0x2d3, sku_mcs_delta_map),
1948c2ecf20Sopenharmony_ci	SKU_GROUP(SKU_HE_RU2x996, 12, 0, 0, sku_mcs_delta_map),
1958c2ecf20Sopenharmony_ci};
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic s8
1988c2ecf20Sopenharmony_cimt7915_get_sku_delta(struct mt7915_dev *dev, u32 addr)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	u32 val = mt7915_eeprom_read(dev, addr);
2018c2ecf20Sopenharmony_ci	s8 delta = FIELD_GET(SKU_DELTA_VAL, val);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (!(val & SKU_DELTA_EN))
2048c2ecf20Sopenharmony_ci		return 0;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	return val & SKU_DELTA_ADD ? delta : -delta;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic void
2108c2ecf20Sopenharmony_cimt7915_eeprom_init_sku_band(struct mt7915_dev *dev,
2118c2ecf20Sopenharmony_ci			    struct ieee80211_supported_band *sband)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	int i, band = sband->band;
2148c2ecf20Sopenharmony_ci	s8 *rate_power = dev->rate_power[band], max_delta = 0;
2158c2ecf20Sopenharmony_ci	u8 idx = 0;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mt7915_sku_groups); i++) {
2188c2ecf20Sopenharmony_ci		const struct sku_group *sku = &mt7915_sku_groups[i];
2198c2ecf20Sopenharmony_ci		u32 offset = sku->offset[band];
2208c2ecf20Sopenharmony_ci		int j;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		if (!offset) {
2238c2ecf20Sopenharmony_ci			idx += sku->len;
2248c2ecf20Sopenharmony_ci			continue;
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		rate_power[idx++] = mt7915_get_sku_delta(dev, offset);
2288c2ecf20Sopenharmony_ci		if (rate_power[idx - 1] > max_delta)
2298c2ecf20Sopenharmony_ci			max_delta = rate_power[idx - 1];
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
2328c2ecf20Sopenharmony_ci			offset += 1;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		for (j = 1; j < sku->len; j++) {
2358c2ecf20Sopenharmony_ci			u32 addr = offset + sku->delta_map[j];
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci			rate_power[idx++] = mt7915_get_sku_delta(dev, addr);
2388c2ecf20Sopenharmony_ci			if (rate_power[idx - 1] > max_delta)
2398c2ecf20Sopenharmony_ci				max_delta = rate_power[idx - 1];
2408c2ecf20Sopenharmony_ci		}
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	rate_power[idx] = max_delta;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_civoid mt7915_eeprom_init_sku(struct mt7915_dev *dev)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_2g.sband);
2498c2ecf20Sopenharmony_ci	mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_5g.sband);
2508c2ecf20Sopenharmony_ci}
251