18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include <linux/of.h>
88c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
98c2ecf20Sopenharmony_ci#include "mt76x2.h"
108c2ecf20Sopenharmony_ci#include "eeprom.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistatic int
158c2ecf20Sopenharmony_cimt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	memcpy(dev->mt76.macaddr, src, ETH_ALEN);
208c2ecf20Sopenharmony_ci	return 0;
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic bool
248c2ecf20Sopenharmony_cimt76x2_has_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	u16 *efuse_w = (u16 *)efuse;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	if (efuse_w[MT_EE_NIC_CONF_0] != 0)
298c2ecf20Sopenharmony_ci		return false;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff)
328c2ecf20Sopenharmony_ci		return false;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0)
358c2ecf20Sopenharmony_ci		return false;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff)
388c2ecf20Sopenharmony_ci		return false;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0)
418c2ecf20Sopenharmony_ci		return false;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff)
448c2ecf20Sopenharmony_ci		return false;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	return true;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic void
508c2ecf20Sopenharmony_cimt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci#define GROUP_5G(_id)							   \
538c2ecf20Sopenharmony_ci	MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id),	   \
548c2ecf20Sopenharmony_ci	MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \
558c2ecf20Sopenharmony_ci	MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id),	   \
568c2ecf20Sopenharmony_ci	MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	static const u8 cal_free_bytes[] = {
598c2ecf20Sopenharmony_ci		MT_EE_XTAL_TRIM_1,
608c2ecf20Sopenharmony_ci		MT_EE_TX_POWER_EXT_PA_5G + 1,
618c2ecf20Sopenharmony_ci		MT_EE_TX_POWER_0_START_2G,
628c2ecf20Sopenharmony_ci		MT_EE_TX_POWER_0_START_2G + 1,
638c2ecf20Sopenharmony_ci		MT_EE_TX_POWER_1_START_2G,
648c2ecf20Sopenharmony_ci		MT_EE_TX_POWER_1_START_2G + 1,
658c2ecf20Sopenharmony_ci		GROUP_5G(0),
668c2ecf20Sopenharmony_ci		GROUP_5G(1),
678c2ecf20Sopenharmony_ci		GROUP_5G(2),
688c2ecf20Sopenharmony_ci		GROUP_5G(3),
698c2ecf20Sopenharmony_ci		GROUP_5G(4),
708c2ecf20Sopenharmony_ci		GROUP_5G(5),
718c2ecf20Sopenharmony_ci		MT_EE_RF_2G_TSSI_OFF_TXPOWER,
728c2ecf20Sopenharmony_ci		MT_EE_RF_2G_RX_HIGH_GAIN + 1,
738c2ecf20Sopenharmony_ci		MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN,
748c2ecf20Sopenharmony_ci		MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1,
758c2ecf20Sopenharmony_ci		MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN,
768c2ecf20Sopenharmony_ci		MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1,
778c2ecf20Sopenharmony_ci		MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN,
788c2ecf20Sopenharmony_ci		MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1,
798c2ecf20Sopenharmony_ci	};
808c2ecf20Sopenharmony_ci	struct device_node *np = dev->mt76.dev->of_node;
818c2ecf20Sopenharmony_ci	u8 *eeprom = dev->mt76.eeprom.data;
828c2ecf20Sopenharmony_ci	u8 prev_grp0[4] = {
838c2ecf20Sopenharmony_ci		eeprom[MT_EE_TX_POWER_0_START_5G],
848c2ecf20Sopenharmony_ci		eeprom[MT_EE_TX_POWER_0_START_5G + 1],
858c2ecf20Sopenharmony_ci		eeprom[MT_EE_TX_POWER_1_START_5G],
868c2ecf20Sopenharmony_ci		eeprom[MT_EE_TX_POWER_1_START_5G + 1]
878c2ecf20Sopenharmony_ci	};
888c2ecf20Sopenharmony_ci	u16 val;
898c2ecf20Sopenharmony_ci	int i;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp"))
928c2ecf20Sopenharmony_ci		return;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (!mt76x2_has_cal_free_data(dev, efuse))
958c2ecf20Sopenharmony_ci		return;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) {
988c2ecf20Sopenharmony_ci		int offset = cal_free_bytes[i];
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		eeprom[offset] = efuse[offset];
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (!(efuse[MT_EE_TX_POWER_0_START_5G] |
1048c2ecf20Sopenharmony_ci	      efuse[MT_EE_TX_POWER_0_START_5G + 1]))
1058c2ecf20Sopenharmony_ci		memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2);
1068c2ecf20Sopenharmony_ci	if (!(efuse[MT_EE_TX_POWER_1_START_5G] |
1078c2ecf20Sopenharmony_ci	      efuse[MT_EE_TX_POWER_1_START_5G + 1]))
1088c2ecf20Sopenharmony_ci		memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT);
1118c2ecf20Sopenharmony_ci	if (val != 0xffff)
1128c2ecf20Sopenharmony_ci		eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION);
1158c2ecf20Sopenharmony_ci	if (val != 0xffff)
1168c2ecf20Sopenharmony_ci		eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG);
1198c2ecf20Sopenharmony_ci	if (val != 0xffff)
1208c2ecf20Sopenharmony_ci		eeprom[MT_EE_BT_PMUCFG] = val & 0xff;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int mt76x2_check_eeprom(struct mt76x02_dev *dev)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	u16 val = get_unaligned_le16(dev->mt76.eeprom.data);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (!val)
1288c2ecf20Sopenharmony_ci		val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	switch (val) {
1318c2ecf20Sopenharmony_ci	case 0x7662:
1328c2ecf20Sopenharmony_ci	case 0x7612:
1338c2ecf20Sopenharmony_ci		return 0;
1348c2ecf20Sopenharmony_ci	default:
1358c2ecf20Sopenharmony_ci		dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val);
1368c2ecf20Sopenharmony_ci		return -EINVAL;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int
1418c2ecf20Sopenharmony_cimt76x2_eeprom_load(struct mt76x02_dev *dev)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	void *efuse;
1448c2ecf20Sopenharmony_ci	bool found;
1458c2ecf20Sopenharmony_ci	int ret;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE);
1488c2ecf20Sopenharmony_ci	if (ret < 0)
1498c2ecf20Sopenharmony_ci		return ret;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	found = ret;
1528c2ecf20Sopenharmony_ci	if (found)
1538c2ecf20Sopenharmony_ci		found = !mt76x2_check_eeprom(dev);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE,
1568c2ecf20Sopenharmony_ci					  GFP_KERNEL);
1578c2ecf20Sopenharmony_ci	dev->mt76.otp.size = MT7662_EEPROM_SIZE;
1588c2ecf20Sopenharmony_ci	if (!dev->mt76.otp.data)
1598c2ecf20Sopenharmony_ci		return -ENOMEM;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	efuse = dev->mt76.otp.data;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (mt76x02_get_efuse_data(dev, 0, efuse, MT7662_EEPROM_SIZE,
1648c2ecf20Sopenharmony_ci				   MT_EE_READ))
1658c2ecf20Sopenharmony_ci		goto out;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (found) {
1688c2ecf20Sopenharmony_ci		mt76x2_apply_cal_free_data(dev, efuse);
1698c2ecf20Sopenharmony_ci	} else {
1708c2ecf20Sopenharmony_ci		/* FIXME: check if efuse data is complete */
1718c2ecf20Sopenharmony_ci		found = true;
1728c2ecf20Sopenharmony_ci		memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE);
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ciout:
1768c2ecf20Sopenharmony_ci	if (!found)
1778c2ecf20Sopenharmony_ci		return -ENOENT;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return 0;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic void
1838c2ecf20Sopenharmony_cimt76x2_set_rx_gain_group(struct mt76x02_dev *dev, u8 val)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	s8 *dest = dev->cal.rx.high_gain;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (!mt76x02_field_valid(val)) {
1888c2ecf20Sopenharmony_ci		dest[0] = 0;
1898c2ecf20Sopenharmony_ci		dest[1] = 0;
1908c2ecf20Sopenharmony_ci		return;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	dest[0] = mt76x02_sign_extend(val, 4);
1948c2ecf20Sopenharmony_ci	dest[1] = mt76x02_sign_extend(val >> 4, 4);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic void
1988c2ecf20Sopenharmony_cimt76x2_set_rssi_offset(struct mt76x02_dev *dev, int chain, u8 val)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	s8 *dest = dev->cal.rx.rssi_offset;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (!mt76x02_field_valid(val)) {
2038c2ecf20Sopenharmony_ci		dest[chain] = 0;
2048c2ecf20Sopenharmony_ci		return;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	dest[chain] = mt76x02_sign_extend_optional(val, 7);
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic enum mt76x2_cal_channel_group
2118c2ecf20Sopenharmony_cimt76x2_get_cal_channel_group(int channel)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	if (channel >= 184 && channel <= 196)
2148c2ecf20Sopenharmony_ci		return MT_CH_5G_JAPAN;
2158c2ecf20Sopenharmony_ci	if (channel <= 48)
2168c2ecf20Sopenharmony_ci		return MT_CH_5G_UNII_1;
2178c2ecf20Sopenharmony_ci	if (channel <= 64)
2188c2ecf20Sopenharmony_ci		return MT_CH_5G_UNII_2;
2198c2ecf20Sopenharmony_ci	if (channel <= 114)
2208c2ecf20Sopenharmony_ci		return MT_CH_5G_UNII_2E_1;
2218c2ecf20Sopenharmony_ci	if (channel <= 144)
2228c2ecf20Sopenharmony_ci		return MT_CH_5G_UNII_2E_2;
2238c2ecf20Sopenharmony_ci	return MT_CH_5G_UNII_3;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic u8
2278c2ecf20Sopenharmony_cimt76x2_get_5g_rx_gain(struct mt76x02_dev *dev, u8 channel)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	enum mt76x2_cal_channel_group group;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	group = mt76x2_get_cal_channel_group(channel);
2328c2ecf20Sopenharmony_ci	switch (group) {
2338c2ecf20Sopenharmony_ci	case MT_CH_5G_JAPAN:
2348c2ecf20Sopenharmony_ci		return mt76x02_eeprom_get(dev,
2358c2ecf20Sopenharmony_ci					  MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN);
2368c2ecf20Sopenharmony_ci	case MT_CH_5G_UNII_1:
2378c2ecf20Sopenharmony_ci		return mt76x02_eeprom_get(dev,
2388c2ecf20Sopenharmony_ci					  MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8;
2398c2ecf20Sopenharmony_ci	case MT_CH_5G_UNII_2:
2408c2ecf20Sopenharmony_ci		return mt76x02_eeprom_get(dev,
2418c2ecf20Sopenharmony_ci					  MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN);
2428c2ecf20Sopenharmony_ci	case MT_CH_5G_UNII_2E_1:
2438c2ecf20Sopenharmony_ci		return mt76x02_eeprom_get(dev,
2448c2ecf20Sopenharmony_ci					  MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8;
2458c2ecf20Sopenharmony_ci	case MT_CH_5G_UNII_2E_2:
2468c2ecf20Sopenharmony_ci		return mt76x02_eeprom_get(dev,
2478c2ecf20Sopenharmony_ci					  MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN);
2488c2ecf20Sopenharmony_ci	default:
2498c2ecf20Sopenharmony_ci		return mt76x02_eeprom_get(dev,
2508c2ecf20Sopenharmony_ci					  MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_civoid mt76x2_read_rx_gain(struct mt76x02_dev *dev)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct ieee80211_channel *chan = dev->mphy.chandef.chan;
2578c2ecf20Sopenharmony_ci	int channel = chan->hw_value;
2588c2ecf20Sopenharmony_ci	s8 lna_5g[3], lna_2g;
2598c2ecf20Sopenharmony_ci	bool use_lna;
2608c2ecf20Sopenharmony_ci	u8 lna = 0;
2618c2ecf20Sopenharmony_ci	u16 val;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (chan->band == NL80211_BAND_2GHZ)
2648c2ecf20Sopenharmony_ci		val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8;
2658c2ecf20Sopenharmony_ci	else
2668c2ecf20Sopenharmony_ci		val = mt76x2_get_5g_rx_gain(dev, channel);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	mt76x2_set_rx_gain_group(dev, val);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	mt76x02_get_rx_gain(dev, chan->band, &val, &lna_2g, lna_5g);
2718c2ecf20Sopenharmony_ci	mt76x2_set_rssi_offset(dev, 0, val);
2728c2ecf20Sopenharmony_ci	mt76x2_set_rssi_offset(dev, 1, val >> 8);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	dev->cal.rx.mcu_gain =  (lna_2g & 0xff);
2758c2ecf20Sopenharmony_ci	dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8;
2768c2ecf20Sopenharmony_ci	dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16;
2778c2ecf20Sopenharmony_ci	dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
2808c2ecf20Sopenharmony_ci	if (chan->band == NL80211_BAND_2GHZ)
2818c2ecf20Sopenharmony_ci		use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_2G);
2828c2ecf20Sopenharmony_ci	else
2838c2ecf20Sopenharmony_ci		use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_5G);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (use_lna)
2868c2ecf20Sopenharmony_ci		lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_read_rx_gain);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_civoid mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76_rate_power *t,
2938c2ecf20Sopenharmony_ci			   struct ieee80211_channel *chan)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	bool is_5ghz;
2968c2ecf20Sopenharmony_ci	u16 val;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	is_5ghz = chan->band == NL80211_BAND_5GHZ;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	memset(t, 0, sizeof(*t));
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_CCK);
3038c2ecf20Sopenharmony_ci	t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val);
3048c2ecf20Sopenharmony_ci	t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (is_5ghz)
3078c2ecf20Sopenharmony_ci		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M);
3088c2ecf20Sopenharmony_ci	else
3098c2ecf20Sopenharmony_ci		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M);
3108c2ecf20Sopenharmony_ci	t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val);
3118c2ecf20Sopenharmony_ci	t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (is_5ghz)
3148c2ecf20Sopenharmony_ci		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M);
3158c2ecf20Sopenharmony_ci	else
3168c2ecf20Sopenharmony_ci		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M);
3178c2ecf20Sopenharmony_ci	t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val);
3188c2ecf20Sopenharmony_ci	t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0);
3218c2ecf20Sopenharmony_ci	t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val);
3228c2ecf20Sopenharmony_ci	t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4);
3258c2ecf20Sopenharmony_ci	t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val);
3268c2ecf20Sopenharmony_ci	t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8);
3298c2ecf20Sopenharmony_ci	t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val);
3308c2ecf20Sopenharmony_ci	t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12);
3338c2ecf20Sopenharmony_ci	t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val);
3348c2ecf20Sopenharmony_ci	t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0);
3378c2ecf20Sopenharmony_ci	t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val);
3388c2ecf20Sopenharmony_ci	t->vht[2] = t->vht[3] = mt76x02_rate_power_val(val >> 8);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4);
3418c2ecf20Sopenharmony_ci	t->vht[4] = t->vht[5] = mt76x02_rate_power_val(val);
3428c2ecf20Sopenharmony_ci	t->vht[6] = t->vht[7] = mt76x02_rate_power_val(val >> 8);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8);
3458c2ecf20Sopenharmony_ci	if (!is_5ghz)
3468c2ecf20Sopenharmony_ci		val >>= 8;
3478c2ecf20Sopenharmony_ci	t->vht[8] = t->vht[9] = mt76x02_rate_power_val(val >> 8);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8);
3508c2ecf20Sopenharmony_ci	t->stbc[8] = t->vht[8];
3518c2ecf20Sopenharmony_ci	t->stbc[9] = t->vht[9];
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_get_rate_power);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic void
3568c2ecf20Sopenharmony_cimt76x2_get_power_info_2g(struct mt76x02_dev *dev,
3578c2ecf20Sopenharmony_ci			 struct mt76x2_tx_power_info *t,
3588c2ecf20Sopenharmony_ci			 struct ieee80211_channel *chan,
3598c2ecf20Sopenharmony_ci			 int chain, int offset)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	int channel = chan->hw_value;
3628c2ecf20Sopenharmony_ci	int delta_idx;
3638c2ecf20Sopenharmony_ci	u8 data[6];
3648c2ecf20Sopenharmony_ci	u16 val;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (channel < 6)
3678c2ecf20Sopenharmony_ci		delta_idx = 3;
3688c2ecf20Sopenharmony_ci	else if (channel < 11)
3698c2ecf20Sopenharmony_ci		delta_idx = 4;
3708c2ecf20Sopenharmony_ci	else
3718c2ecf20Sopenharmony_ci		delta_idx = 5;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	mt76x02_eeprom_copy(dev, offset, data, sizeof(data));
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	t->chain[chain].tssi_slope = data[0];
3768c2ecf20Sopenharmony_ci	t->chain[chain].tssi_offset = data[1];
3778c2ecf20Sopenharmony_ci	t->chain[chain].target_power = data[2];
3788c2ecf20Sopenharmony_ci	t->chain[chain].delta =
3798c2ecf20Sopenharmony_ci		mt76x02_sign_extend_optional(data[delta_idx], 7);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER);
3828c2ecf20Sopenharmony_ci	t->target_power = val >> 8;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic void
3868c2ecf20Sopenharmony_cimt76x2_get_power_info_5g(struct mt76x02_dev *dev,
3878c2ecf20Sopenharmony_ci			 struct mt76x2_tx_power_info *t,
3888c2ecf20Sopenharmony_ci			 struct ieee80211_channel *chan,
3898c2ecf20Sopenharmony_ci			 int chain, int offset)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	int channel = chan->hw_value;
3928c2ecf20Sopenharmony_ci	enum mt76x2_cal_channel_group group;
3938c2ecf20Sopenharmony_ci	int delta_idx;
3948c2ecf20Sopenharmony_ci	u16 val;
3958c2ecf20Sopenharmony_ci	u8 data[5];
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	group = mt76x2_get_cal_channel_group(channel);
3988c2ecf20Sopenharmony_ci	offset += group * MT_TX_POWER_GROUP_SIZE_5G;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if (channel >= 192)
4018c2ecf20Sopenharmony_ci		delta_idx = 4;
4028c2ecf20Sopenharmony_ci	else if (channel >= 184)
4038c2ecf20Sopenharmony_ci		delta_idx = 3;
4048c2ecf20Sopenharmony_ci	else if (channel < 44)
4058c2ecf20Sopenharmony_ci		delta_idx = 3;
4068c2ecf20Sopenharmony_ci	else if (channel < 52)
4078c2ecf20Sopenharmony_ci		delta_idx = 4;
4088c2ecf20Sopenharmony_ci	else if (channel < 58)
4098c2ecf20Sopenharmony_ci		delta_idx = 3;
4108c2ecf20Sopenharmony_ci	else if (channel < 98)
4118c2ecf20Sopenharmony_ci		delta_idx = 4;
4128c2ecf20Sopenharmony_ci	else if (channel < 106)
4138c2ecf20Sopenharmony_ci		delta_idx = 3;
4148c2ecf20Sopenharmony_ci	else if (channel < 116)
4158c2ecf20Sopenharmony_ci		delta_idx = 4;
4168c2ecf20Sopenharmony_ci	else if (channel < 130)
4178c2ecf20Sopenharmony_ci		delta_idx = 3;
4188c2ecf20Sopenharmony_ci	else if (channel < 149)
4198c2ecf20Sopenharmony_ci		delta_idx = 4;
4208c2ecf20Sopenharmony_ci	else if (channel < 157)
4218c2ecf20Sopenharmony_ci		delta_idx = 3;
4228c2ecf20Sopenharmony_ci	else
4238c2ecf20Sopenharmony_ci		delta_idx = 4;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	mt76x02_eeprom_copy(dev, offset, data, sizeof(data));
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	t->chain[chain].tssi_slope = data[0];
4288c2ecf20Sopenharmony_ci	t->chain[chain].tssi_offset = data[1];
4298c2ecf20Sopenharmony_ci	t->chain[chain].target_power = data[2];
4308c2ecf20Sopenharmony_ci	t->chain[chain].delta =
4318c2ecf20Sopenharmony_ci		mt76x02_sign_extend_optional(data[delta_idx], 7);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN);
4348c2ecf20Sopenharmony_ci	t->target_power = val & 0xff;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_civoid mt76x2_get_power_info(struct mt76x02_dev *dev,
4388c2ecf20Sopenharmony_ci			   struct mt76x2_tx_power_info *t,
4398c2ecf20Sopenharmony_ci			   struct ieee80211_channel *chan)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	u16 bw40, bw80;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	memset(t, 0, sizeof(*t));
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	bw40 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40);
4468c2ecf20Sopenharmony_ci	bw80 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	if (chan->band == NL80211_BAND_5GHZ) {
4498c2ecf20Sopenharmony_ci		bw40 >>= 8;
4508c2ecf20Sopenharmony_ci		mt76x2_get_power_info_5g(dev, t, chan, 0,
4518c2ecf20Sopenharmony_ci					 MT_EE_TX_POWER_0_START_5G);
4528c2ecf20Sopenharmony_ci		mt76x2_get_power_info_5g(dev, t, chan, 1,
4538c2ecf20Sopenharmony_ci					 MT_EE_TX_POWER_1_START_5G);
4548c2ecf20Sopenharmony_ci	} else {
4558c2ecf20Sopenharmony_ci		mt76x2_get_power_info_2g(dev, t, chan, 0,
4568c2ecf20Sopenharmony_ci					 MT_EE_TX_POWER_0_START_2G);
4578c2ecf20Sopenharmony_ci		mt76x2_get_power_info_2g(dev, t, chan, 1,
4588c2ecf20Sopenharmony_ci					 MT_EE_TX_POWER_1_START_2G);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	if (mt76x2_tssi_enabled(dev) ||
4628c2ecf20Sopenharmony_ci	    !mt76x02_field_valid(t->target_power))
4638c2ecf20Sopenharmony_ci		t->target_power = t->chain[0].target_power;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	t->delta_bw40 = mt76x02_rate_power_val(bw40);
4668c2ecf20Sopenharmony_ci	t->delta_bw80 = mt76x02_rate_power_val(bw80);
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_get_power_info);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ciint mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	enum nl80211_band band = dev->mphy.chandef.chan->band;
4738c2ecf20Sopenharmony_ci	u16 val, slope;
4748c2ecf20Sopenharmony_ci	u8 bounds;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	memset(t, 0, sizeof(*t));
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	if (!mt76x2_temp_tx_alc_enabled(dev))
4798c2ecf20Sopenharmony_ci		return -EINVAL;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (!mt76x02_ext_pa_enabled(dev, band))
4828c2ecf20Sopenharmony_ci		return -EINVAL;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8;
4858c2ecf20Sopenharmony_ci	t->temp_25_ref = val & 0x7f;
4868c2ecf20Sopenharmony_ci	if (band == NL80211_BAND_5GHZ) {
4878c2ecf20Sopenharmony_ci		slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G);
4888c2ecf20Sopenharmony_ci		bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
4898c2ecf20Sopenharmony_ci	} else {
4908c2ecf20Sopenharmony_ci		slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G);
4918c2ecf20Sopenharmony_ci		bounds = mt76x02_eeprom_get(dev,
4928c2ecf20Sopenharmony_ci					    MT_EE_TX_POWER_DELTA_BW80) >> 8;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	t->high_slope = slope & 0xff;
4968c2ecf20Sopenharmony_ci	t->low_slope = slope >> 8;
4978c2ecf20Sopenharmony_ci	t->lower_bound = 0 - (bounds & 0xf);
4988c2ecf20Sopenharmony_ci	t->upper_bound = (bounds >> 4) & 0xf;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	return 0;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_get_temp_comp);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ciint mt76x2_eeprom_init(struct mt76x02_dev *dev)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	int ret;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	ret = mt76x2_eeprom_load(dev);
5098c2ecf20Sopenharmony_ci	if (ret)
5108c2ecf20Sopenharmony_ci		return ret;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	mt76x02_eeprom_parse_hw_cap(dev);
5138c2ecf20Sopenharmony_ci	mt76x2_eeprom_get_macaddr(dev);
5148c2ecf20Sopenharmony_ci	mt76_eeprom_override(&dev->mt76);
5158c2ecf20Sopenharmony_ci	dev->mt76.macaddr[0] &= ~BIT(1);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	return 0;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_eeprom_init);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
522