10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
21613c621SLorenzo Bianconi /*
31613c621SLorenzo Bianconi  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
41613c621SLorenzo Bianconi  */
51613c621SLorenzo Bianconi 
61613c621SLorenzo Bianconi #include <linux/module.h>
79a865741SFelix Fietkau #include <linux/of.h>
81613c621SLorenzo Bianconi #include <asm/unaligned.h>
91613c621SLorenzo Bianconi #include "mt76x2.h"
101613c621SLorenzo Bianconi #include "eeprom.h"
111613c621SLorenzo Bianconi 
121613c621SLorenzo Bianconi #define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1
131613c621SLorenzo Bianconi 
141613c621SLorenzo Bianconi static int
mt76x2_eeprom_get_macaddr(struct mt76x02_dev * dev)15e40803f2SLorenzo Bianconi mt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev)
161613c621SLorenzo Bianconi {
171613c621SLorenzo Bianconi 	void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR;
181613c621SLorenzo Bianconi 
1998df2baeSLorenzo Bianconi 	memcpy(dev->mphy.macaddr, src, ETH_ALEN);
201613c621SLorenzo Bianconi 	return 0;
211613c621SLorenzo Bianconi }
221613c621SLorenzo Bianconi 
231613c621SLorenzo Bianconi static bool
mt76x2_has_cal_free_data(struct mt76x02_dev * dev,u8 * efuse)24e40803f2SLorenzo Bianconi mt76x2_has_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
251613c621SLorenzo Bianconi {
261613c621SLorenzo Bianconi 	u16 *efuse_w = (u16 *)efuse;
271613c621SLorenzo Bianconi 
281613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_NIC_CONF_0] != 0)
291613c621SLorenzo Bianconi 		return false;
301613c621SLorenzo Bianconi 
311613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff)
321613c621SLorenzo Bianconi 		return false;
331613c621SLorenzo Bianconi 
341613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0)
351613c621SLorenzo Bianconi 		return false;
361613c621SLorenzo Bianconi 
371613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff)
381613c621SLorenzo Bianconi 		return false;
391613c621SLorenzo Bianconi 
401613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0)
411613c621SLorenzo Bianconi 		return false;
421613c621SLorenzo Bianconi 
431613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff)
441613c621SLorenzo Bianconi 		return false;
451613c621SLorenzo Bianconi 
461613c621SLorenzo Bianconi 	return true;
471613c621SLorenzo Bianconi }
481613c621SLorenzo Bianconi 
491613c621SLorenzo Bianconi static void
mt76x2_apply_cal_free_data(struct mt76x02_dev * dev,u8 * efuse)50e40803f2SLorenzo Bianconi mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
511613c621SLorenzo Bianconi {
521613c621SLorenzo Bianconi #define GROUP_5G(_id)							   \
531613c621SLorenzo Bianconi 	MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id),	   \
541613c621SLorenzo Bianconi 	MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \
551613c621SLorenzo Bianconi 	MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id),	   \
561613c621SLorenzo Bianconi 	MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1
571613c621SLorenzo Bianconi 
581613c621SLorenzo Bianconi 	static const u8 cal_free_bytes[] = {
591613c621SLorenzo Bianconi 		MT_EE_XTAL_TRIM_1,
601613c621SLorenzo Bianconi 		MT_EE_TX_POWER_EXT_PA_5G + 1,
611613c621SLorenzo Bianconi 		MT_EE_TX_POWER_0_START_2G,
621613c621SLorenzo Bianconi 		MT_EE_TX_POWER_0_START_2G + 1,
631613c621SLorenzo Bianconi 		MT_EE_TX_POWER_1_START_2G,
641613c621SLorenzo Bianconi 		MT_EE_TX_POWER_1_START_2G + 1,
651613c621SLorenzo Bianconi 		GROUP_5G(0),
661613c621SLorenzo Bianconi 		GROUP_5G(1),
671613c621SLorenzo Bianconi 		GROUP_5G(2),
681613c621SLorenzo Bianconi 		GROUP_5G(3),
691613c621SLorenzo Bianconi 		GROUP_5G(4),
701613c621SLorenzo Bianconi 		GROUP_5G(5),
711613c621SLorenzo Bianconi 		MT_EE_RF_2G_TSSI_OFF_TXPOWER,
721613c621SLorenzo Bianconi 		MT_EE_RF_2G_RX_HIGH_GAIN + 1,
731613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN,
741613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1,
751613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN,
761613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1,
771613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN,
781613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1,
791613c621SLorenzo Bianconi 	};
809a865741SFelix Fietkau 	struct device_node *np = dev->mt76.dev->of_node;
811613c621SLorenzo Bianconi 	u8 *eeprom = dev->mt76.eeprom.data;
821613c621SLorenzo Bianconi 	u8 prev_grp0[4] = {
831613c621SLorenzo Bianconi 		eeprom[MT_EE_TX_POWER_0_START_5G],
841613c621SLorenzo Bianconi 		eeprom[MT_EE_TX_POWER_0_START_5G + 1],
851613c621SLorenzo Bianconi 		eeprom[MT_EE_TX_POWER_1_START_5G],
861613c621SLorenzo Bianconi 		eeprom[MT_EE_TX_POWER_1_START_5G + 1]
871613c621SLorenzo Bianconi 	};
881613c621SLorenzo Bianconi 	u16 val;
891613c621SLorenzo Bianconi 	int i;
901613c621SLorenzo Bianconi 
919a865741SFelix Fietkau 	if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp"))
929a865741SFelix Fietkau 		return;
939a865741SFelix Fietkau 
941613c621SLorenzo Bianconi 	if (!mt76x2_has_cal_free_data(dev, efuse))
951613c621SLorenzo Bianconi 		return;
961613c621SLorenzo Bianconi 
971613c621SLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) {
981613c621SLorenzo Bianconi 		int offset = cal_free_bytes[i];
991613c621SLorenzo Bianconi 
1001613c621SLorenzo Bianconi 		eeprom[offset] = efuse[offset];
1011613c621SLorenzo Bianconi 	}
1021613c621SLorenzo Bianconi 
1031613c621SLorenzo Bianconi 	if (!(efuse[MT_EE_TX_POWER_0_START_5G] |
1041613c621SLorenzo Bianconi 	      efuse[MT_EE_TX_POWER_0_START_5G + 1]))
1051613c621SLorenzo Bianconi 		memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2);
1061613c621SLorenzo Bianconi 	if (!(efuse[MT_EE_TX_POWER_1_START_5G] |
1071613c621SLorenzo Bianconi 	      efuse[MT_EE_TX_POWER_1_START_5G + 1]))
1081613c621SLorenzo Bianconi 		memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2);
1091613c621SLorenzo Bianconi 
1101613c621SLorenzo Bianconi 	val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT);
1111613c621SLorenzo Bianconi 	if (val != 0xffff)
1121613c621SLorenzo Bianconi 		eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff;
1131613c621SLorenzo Bianconi 
1141613c621SLorenzo Bianconi 	val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION);
1151613c621SLorenzo Bianconi 	if (val != 0xffff)
1161613c621SLorenzo Bianconi 		eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8;
1171613c621SLorenzo Bianconi 
1181613c621SLorenzo Bianconi 	val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG);
1191613c621SLorenzo Bianconi 	if (val != 0xffff)
1201613c621SLorenzo Bianconi 		eeprom[MT_EE_BT_PMUCFG] = val & 0xff;
1211613c621SLorenzo Bianconi }
1221613c621SLorenzo Bianconi 
mt76x2_check_eeprom(struct mt76x02_dev * dev)123e40803f2SLorenzo Bianconi static int mt76x2_check_eeprom(struct mt76x02_dev *dev)
1241613c621SLorenzo Bianconi {
1251613c621SLorenzo Bianconi 	u16 val = get_unaligned_le16(dev->mt76.eeprom.data);
1261613c621SLorenzo Bianconi 
1271613c621SLorenzo Bianconi 	if (!val)
1281613c621SLorenzo Bianconi 		val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID);
1291613c621SLorenzo Bianconi 
1301613c621SLorenzo Bianconi 	switch (val) {
1311613c621SLorenzo Bianconi 	case 0x7662:
1321613c621SLorenzo Bianconi 	case 0x7612:
1331613c621SLorenzo Bianconi 		return 0;
1341613c621SLorenzo Bianconi 	default:
1351613c621SLorenzo Bianconi 		dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val);
1361613c621SLorenzo Bianconi 		return -EINVAL;
1371613c621SLorenzo Bianconi 	}
1381613c621SLorenzo Bianconi }
1391613c621SLorenzo Bianconi 
1401613c621SLorenzo Bianconi static int
mt76x2_eeprom_load(struct mt76x02_dev * dev)141e40803f2SLorenzo Bianconi mt76x2_eeprom_load(struct mt76x02_dev *dev)
1421613c621SLorenzo Bianconi {
1431613c621SLorenzo Bianconi 	void *efuse;
1441613c621SLorenzo Bianconi 	bool found;
1451613c621SLorenzo Bianconi 	int ret;
1461613c621SLorenzo Bianconi 
1471613c621SLorenzo Bianconi 	ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE);
1481613c621SLorenzo Bianconi 	if (ret < 0)
1491613c621SLorenzo Bianconi 		return ret;
1501613c621SLorenzo Bianconi 
1511613c621SLorenzo Bianconi 	found = ret;
1521613c621SLorenzo Bianconi 	if (found)
1531613c621SLorenzo Bianconi 		found = !mt76x2_check_eeprom(dev);
1541613c621SLorenzo Bianconi 
1551613c621SLorenzo Bianconi 	dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE,
1561613c621SLorenzo Bianconi 					  GFP_KERNEL);
1571613c621SLorenzo Bianconi 	dev->mt76.otp.size = MT7662_EEPROM_SIZE;
1581613c621SLorenzo Bianconi 	if (!dev->mt76.otp.data)
1591613c621SLorenzo Bianconi 		return -ENOMEM;
1601613c621SLorenzo Bianconi 
1611613c621SLorenzo Bianconi 	efuse = dev->mt76.otp.data;
1621613c621SLorenzo Bianconi 
16326a9daa6SLorenzo Bianconi 	if (mt76x02_get_efuse_data(dev, 0, efuse, MT7662_EEPROM_SIZE,
16426a9daa6SLorenzo Bianconi 				   MT_EE_READ))
1651613c621SLorenzo Bianconi 		goto out;
1661613c621SLorenzo Bianconi 
1671613c621SLorenzo Bianconi 	if (found) {
1681613c621SLorenzo Bianconi 		mt76x2_apply_cal_free_data(dev, efuse);
1691613c621SLorenzo Bianconi 	} else {
1701613c621SLorenzo Bianconi 		/* FIXME: check if efuse data is complete */
1711613c621SLorenzo Bianconi 		found = true;
1721613c621SLorenzo Bianconi 		memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE);
1731613c621SLorenzo Bianconi 	}
1741613c621SLorenzo Bianconi 
1751613c621SLorenzo Bianconi out:
1761613c621SLorenzo Bianconi 	if (!found)
1771613c621SLorenzo Bianconi 		return -ENOENT;
1781613c621SLorenzo Bianconi 
1791613c621SLorenzo Bianconi 	return 0;
1801613c621SLorenzo Bianconi }
1811613c621SLorenzo Bianconi 
1821613c621SLorenzo Bianconi static void
mt76x2_set_rx_gain_group(struct mt76x02_dev * dev,u8 val)183e40803f2SLorenzo Bianconi mt76x2_set_rx_gain_group(struct mt76x02_dev *dev, u8 val)
1841613c621SLorenzo Bianconi {
1851613c621SLorenzo Bianconi 	s8 *dest = dev->cal.rx.high_gain;
1861613c621SLorenzo Bianconi 
1871613c621SLorenzo Bianconi 	if (!mt76x02_field_valid(val)) {
1881613c621SLorenzo Bianconi 		dest[0] = 0;
1891613c621SLorenzo Bianconi 		dest[1] = 0;
1901613c621SLorenzo Bianconi 		return;
1911613c621SLorenzo Bianconi 	}
1921613c621SLorenzo Bianconi 
1931613c621SLorenzo Bianconi 	dest[0] = mt76x02_sign_extend(val, 4);
1941613c621SLorenzo Bianconi 	dest[1] = mt76x02_sign_extend(val >> 4, 4);
1951613c621SLorenzo Bianconi }
1961613c621SLorenzo Bianconi 
1971613c621SLorenzo Bianconi static void
mt76x2_set_rssi_offset(struct mt76x02_dev * dev,int chain,u8 val)198e40803f2SLorenzo Bianconi mt76x2_set_rssi_offset(struct mt76x02_dev *dev, int chain, u8 val)
1991613c621SLorenzo Bianconi {
2001613c621SLorenzo Bianconi 	s8 *dest = dev->cal.rx.rssi_offset;
2011613c621SLorenzo Bianconi 
2021613c621SLorenzo Bianconi 	if (!mt76x02_field_valid(val)) {
2031613c621SLorenzo Bianconi 		dest[chain] = 0;
2041613c621SLorenzo Bianconi 		return;
2051613c621SLorenzo Bianconi 	}
2061613c621SLorenzo Bianconi 
2071613c621SLorenzo Bianconi 	dest[chain] = mt76x02_sign_extend_optional(val, 7);
2081613c621SLorenzo Bianconi }
2091613c621SLorenzo Bianconi 
2101613c621SLorenzo Bianconi static enum mt76x2_cal_channel_group
mt76x2_get_cal_channel_group(int channel)2111613c621SLorenzo Bianconi mt76x2_get_cal_channel_group(int channel)
2121613c621SLorenzo Bianconi {
2131613c621SLorenzo Bianconi 	if (channel >= 184 && channel <= 196)
2141613c621SLorenzo Bianconi 		return MT_CH_5G_JAPAN;
2151613c621SLorenzo Bianconi 	if (channel <= 48)
2161613c621SLorenzo Bianconi 		return MT_CH_5G_UNII_1;
2171613c621SLorenzo Bianconi 	if (channel <= 64)
2181613c621SLorenzo Bianconi 		return MT_CH_5G_UNII_2;
2191613c621SLorenzo Bianconi 	if (channel <= 114)
2201613c621SLorenzo Bianconi 		return MT_CH_5G_UNII_2E_1;
2211613c621SLorenzo Bianconi 	if (channel <= 144)
2221613c621SLorenzo Bianconi 		return MT_CH_5G_UNII_2E_2;
2231613c621SLorenzo Bianconi 	return MT_CH_5G_UNII_3;
2241613c621SLorenzo Bianconi }
2251613c621SLorenzo Bianconi 
2261613c621SLorenzo Bianconi static u8
mt76x2_get_5g_rx_gain(struct mt76x02_dev * dev,u8 channel)227e40803f2SLorenzo Bianconi mt76x2_get_5g_rx_gain(struct mt76x02_dev *dev, u8 channel)
2281613c621SLorenzo Bianconi {
2291613c621SLorenzo Bianconi 	enum mt76x2_cal_channel_group group;
2301613c621SLorenzo Bianconi 
2311613c621SLorenzo Bianconi 	group = mt76x2_get_cal_channel_group(channel);
2321613c621SLorenzo Bianconi 	switch (group) {
2331613c621SLorenzo Bianconi 	case MT_CH_5G_JAPAN:
23426a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2351613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN);
2361613c621SLorenzo Bianconi 	case MT_CH_5G_UNII_1:
23726a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2381613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8;
2391613c621SLorenzo Bianconi 	case MT_CH_5G_UNII_2:
24026a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2411613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN);
2421613c621SLorenzo Bianconi 	case MT_CH_5G_UNII_2E_1:
24326a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2441613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8;
2451613c621SLorenzo Bianconi 	case MT_CH_5G_UNII_2E_2:
24626a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2471613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN);
2481613c621SLorenzo Bianconi 	default:
24926a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2501613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8;
2511613c621SLorenzo Bianconi 	}
2521613c621SLorenzo Bianconi }
2531613c621SLorenzo Bianconi 
mt76x2_read_rx_gain(struct mt76x02_dev * dev)254e40803f2SLorenzo Bianconi void mt76x2_read_rx_gain(struct mt76x02_dev *dev)
2551613c621SLorenzo Bianconi {
25696747a51SFelix Fietkau 	struct ieee80211_channel *chan = dev->mphy.chandef.chan;
2571613c621SLorenzo Bianconi 	int channel = chan->hw_value;
2581613c621SLorenzo Bianconi 	s8 lna_5g[3], lna_2g;
259*684e45e1SFelix Fietkau 	bool use_lna;
260*684e45e1SFelix Fietkau 	u8 lna = 0;
2611613c621SLorenzo Bianconi 	u16 val;
2621613c621SLorenzo Bianconi 
2631613c621SLorenzo Bianconi 	if (chan->band == NL80211_BAND_2GHZ)
26426a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8;
2651613c621SLorenzo Bianconi 	else
2661613c621SLorenzo Bianconi 		val = mt76x2_get_5g_rx_gain(dev, channel);
2671613c621SLorenzo Bianconi 
2681613c621SLorenzo Bianconi 	mt76x2_set_rx_gain_group(dev, val);
2691613c621SLorenzo Bianconi 
27026a9daa6SLorenzo Bianconi 	mt76x02_get_rx_gain(dev, chan->band, &val, &lna_2g, lna_5g);
2711613c621SLorenzo Bianconi 	mt76x2_set_rssi_offset(dev, 0, val);
2721613c621SLorenzo Bianconi 	mt76x2_set_rssi_offset(dev, 1, val >> 8);
2731613c621SLorenzo Bianconi 
2741613c621SLorenzo Bianconi 	dev->cal.rx.mcu_gain =  (lna_2g & 0xff);
2751613c621SLorenzo Bianconi 	dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8;
2761613c621SLorenzo Bianconi 	dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16;
2771613c621SLorenzo Bianconi 	dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24;
2781613c621SLorenzo Bianconi 
279*684e45e1SFelix Fietkau 	val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1);
280*684e45e1SFelix Fietkau 	if (chan->band == NL80211_BAND_2GHZ)
281*684e45e1SFelix Fietkau 		use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_2G);
282*684e45e1SFelix Fietkau 	else
283*684e45e1SFelix Fietkau 		use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_5G);
284*684e45e1SFelix Fietkau 
285*684e45e1SFelix Fietkau 	if (use_lna)
28626a9daa6SLorenzo Bianconi 		lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan);
287*684e45e1SFelix Fietkau 
2881613c621SLorenzo Bianconi 	dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8);
2891613c621SLorenzo Bianconi }
2901613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain);
2911613c621SLorenzo Bianconi 
mt76x2_get_rate_power(struct mt76x02_dev * dev,struct mt76x02_rate_power * t,struct ieee80211_channel * chan)292b376d963SFelix Fietkau void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76x02_rate_power *t,
2931613c621SLorenzo Bianconi 			   struct ieee80211_channel *chan)
2941613c621SLorenzo Bianconi {
2951613c621SLorenzo Bianconi 	bool is_5ghz;
2961613c621SLorenzo Bianconi 	u16 val;
2971613c621SLorenzo Bianconi 
2981613c621SLorenzo Bianconi 	is_5ghz = chan->band == NL80211_BAND_5GHZ;
2991613c621SLorenzo Bianconi 
3001613c621SLorenzo Bianconi 	memset(t, 0, sizeof(*t));
3011613c621SLorenzo Bianconi 
30226a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_CCK);
3031613c621SLorenzo Bianconi 	t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val);
3041613c621SLorenzo Bianconi 	t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8);
3051613c621SLorenzo Bianconi 
3061613c621SLorenzo Bianconi 	if (is_5ghz)
30726a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M);
3081613c621SLorenzo Bianconi 	else
30926a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M);
3101613c621SLorenzo Bianconi 	t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val);
3111613c621SLorenzo Bianconi 	t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8);
3121613c621SLorenzo Bianconi 
3131613c621SLorenzo Bianconi 	if (is_5ghz)
31426a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M);
3151613c621SLorenzo Bianconi 	else
31626a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M);
3171613c621SLorenzo Bianconi 	t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val);
3181613c621SLorenzo Bianconi 	t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8);
3191613c621SLorenzo Bianconi 
32026a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0);
3211613c621SLorenzo Bianconi 	t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val);
3221613c621SLorenzo Bianconi 	t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8);
3231613c621SLorenzo Bianconi 
32426a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4);
3251613c621SLorenzo Bianconi 	t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val);
3261613c621SLorenzo Bianconi 	t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8);
3271613c621SLorenzo Bianconi 
32826a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8);
3291613c621SLorenzo Bianconi 	t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val);
3301613c621SLorenzo Bianconi 	t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8);
3311613c621SLorenzo Bianconi 
33226a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12);
3331613c621SLorenzo Bianconi 	t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val);
3341613c621SLorenzo Bianconi 	t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8);
3351613c621SLorenzo Bianconi 
33626a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8);
3371613c621SLorenzo Bianconi 	if (!is_5ghz)
3381613c621SLorenzo Bianconi 		val >>= 8;
339ba45841cSFelix Fietkau 	t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val >> 8);
3401613c621SLorenzo Bianconi }
3411613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_get_rate_power);
3421613c621SLorenzo Bianconi 
3431613c621SLorenzo Bianconi static void
mt76x2_get_power_info_2g(struct mt76x02_dev * dev,struct mt76x2_tx_power_info * t,struct ieee80211_channel * chan,int chain,int offset)344e40803f2SLorenzo Bianconi mt76x2_get_power_info_2g(struct mt76x02_dev *dev,
345e40803f2SLorenzo Bianconi 			 struct mt76x2_tx_power_info *t,
346e40803f2SLorenzo Bianconi 			 struct ieee80211_channel *chan,
347e40803f2SLorenzo Bianconi 			 int chain, int offset)
3481613c621SLorenzo Bianconi {
3491613c621SLorenzo Bianconi 	int channel = chan->hw_value;
3501613c621SLorenzo Bianconi 	int delta_idx;
3511613c621SLorenzo Bianconi 	u8 data[6];
3521613c621SLorenzo Bianconi 	u16 val;
3531613c621SLorenzo Bianconi 
3541613c621SLorenzo Bianconi 	if (channel < 6)
3551613c621SLorenzo Bianconi 		delta_idx = 3;
3561613c621SLorenzo Bianconi 	else if (channel < 11)
3571613c621SLorenzo Bianconi 		delta_idx = 4;
3581613c621SLorenzo Bianconi 	else
3591613c621SLorenzo Bianconi 		delta_idx = 5;
3601613c621SLorenzo Bianconi 
361693792ecSLorenzo Bianconi 	mt76x02_eeprom_copy(dev, offset, data, sizeof(data));
3621613c621SLorenzo Bianconi 
3631613c621SLorenzo Bianconi 	t->chain[chain].tssi_slope = data[0];
3641613c621SLorenzo Bianconi 	t->chain[chain].tssi_offset = data[1];
3651613c621SLorenzo Bianconi 	t->chain[chain].target_power = data[2];
366ff97c52aSRyder Lee 	t->chain[chain].delta =
367ff97c52aSRyder Lee 		mt76x02_sign_extend_optional(data[delta_idx], 7);
3681613c621SLorenzo Bianconi 
36926a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER);
3701613c621SLorenzo Bianconi 	t->target_power = val >> 8;
3711613c621SLorenzo Bianconi }
3721613c621SLorenzo Bianconi 
3731613c621SLorenzo Bianconi static void
mt76x2_get_power_info_5g(struct mt76x02_dev * dev,struct mt76x2_tx_power_info * t,struct ieee80211_channel * chan,int chain,int offset)374e40803f2SLorenzo Bianconi mt76x2_get_power_info_5g(struct mt76x02_dev *dev,
375e40803f2SLorenzo Bianconi 			 struct mt76x2_tx_power_info *t,
376e40803f2SLorenzo Bianconi 			 struct ieee80211_channel *chan,
377e40803f2SLorenzo Bianconi 			 int chain, int offset)
3781613c621SLorenzo Bianconi {
3791613c621SLorenzo Bianconi 	int channel = chan->hw_value;
3801613c621SLorenzo Bianconi 	enum mt76x2_cal_channel_group group;
3811613c621SLorenzo Bianconi 	int delta_idx;
3821613c621SLorenzo Bianconi 	u16 val;
3831613c621SLorenzo Bianconi 	u8 data[5];
3841613c621SLorenzo Bianconi 
3851613c621SLorenzo Bianconi 	group = mt76x2_get_cal_channel_group(channel);
3861613c621SLorenzo Bianconi 	offset += group * MT_TX_POWER_GROUP_SIZE_5G;
3871613c621SLorenzo Bianconi 
3881613c621SLorenzo Bianconi 	if (channel >= 192)
3891613c621SLorenzo Bianconi 		delta_idx = 4;
3901613c621SLorenzo Bianconi 	else if (channel >= 184)
3911613c621SLorenzo Bianconi 		delta_idx = 3;
3921613c621SLorenzo Bianconi 	else if (channel < 44)
3931613c621SLorenzo Bianconi 		delta_idx = 3;
3941613c621SLorenzo Bianconi 	else if (channel < 52)
3951613c621SLorenzo Bianconi 		delta_idx = 4;
3961613c621SLorenzo Bianconi 	else if (channel < 58)
3971613c621SLorenzo Bianconi 		delta_idx = 3;
3981613c621SLorenzo Bianconi 	else if (channel < 98)
3991613c621SLorenzo Bianconi 		delta_idx = 4;
4001613c621SLorenzo Bianconi 	else if (channel < 106)
4011613c621SLorenzo Bianconi 		delta_idx = 3;
4021613c621SLorenzo Bianconi 	else if (channel < 116)
4031613c621SLorenzo Bianconi 		delta_idx = 4;
4041613c621SLorenzo Bianconi 	else if (channel < 130)
4051613c621SLorenzo Bianconi 		delta_idx = 3;
4061613c621SLorenzo Bianconi 	else if (channel < 149)
4071613c621SLorenzo Bianconi 		delta_idx = 4;
4081613c621SLorenzo Bianconi 	else if (channel < 157)
4091613c621SLorenzo Bianconi 		delta_idx = 3;
4101613c621SLorenzo Bianconi 	else
4111613c621SLorenzo Bianconi 		delta_idx = 4;
4121613c621SLorenzo Bianconi 
413693792ecSLorenzo Bianconi 	mt76x02_eeprom_copy(dev, offset, data, sizeof(data));
4141613c621SLorenzo Bianconi 
4151613c621SLorenzo Bianconi 	t->chain[chain].tssi_slope = data[0];
4161613c621SLorenzo Bianconi 	t->chain[chain].tssi_offset = data[1];
4171613c621SLorenzo Bianconi 	t->chain[chain].target_power = data[2];
418ff97c52aSRyder Lee 	t->chain[chain].delta =
419ff97c52aSRyder Lee 		mt76x02_sign_extend_optional(data[delta_idx], 7);
4201613c621SLorenzo Bianconi 
42126a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN);
4221613c621SLorenzo Bianconi 	t->target_power = val & 0xff;
4231613c621SLorenzo Bianconi }
4241613c621SLorenzo Bianconi 
mt76x2_get_power_info(struct mt76x02_dev * dev,struct mt76x2_tx_power_info * t,struct ieee80211_channel * chan)425e40803f2SLorenzo Bianconi void mt76x2_get_power_info(struct mt76x02_dev *dev,
4261613c621SLorenzo Bianconi 			   struct mt76x2_tx_power_info *t,
4271613c621SLorenzo Bianconi 			   struct ieee80211_channel *chan)
4281613c621SLorenzo Bianconi {
4291613c621SLorenzo Bianconi 	u16 bw40, bw80;
4301613c621SLorenzo Bianconi 
4311613c621SLorenzo Bianconi 	memset(t, 0, sizeof(*t));
4321613c621SLorenzo Bianconi 
43326a9daa6SLorenzo Bianconi 	bw40 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40);
43426a9daa6SLorenzo Bianconi 	bw80 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80);
4351613c621SLorenzo Bianconi 
4361613c621SLorenzo Bianconi 	if (chan->band == NL80211_BAND_5GHZ) {
4371613c621SLorenzo Bianconi 		bw40 >>= 8;
4381613c621SLorenzo Bianconi 		mt76x2_get_power_info_5g(dev, t, chan, 0,
4391613c621SLorenzo Bianconi 					 MT_EE_TX_POWER_0_START_5G);
4401613c621SLorenzo Bianconi 		mt76x2_get_power_info_5g(dev, t, chan, 1,
4411613c621SLorenzo Bianconi 					 MT_EE_TX_POWER_1_START_5G);
4421613c621SLorenzo Bianconi 	} else {
4431613c621SLorenzo Bianconi 		mt76x2_get_power_info_2g(dev, t, chan, 0,
4441613c621SLorenzo Bianconi 					 MT_EE_TX_POWER_0_START_2G);
4451613c621SLorenzo Bianconi 		mt76x2_get_power_info_2g(dev, t, chan, 1,
4461613c621SLorenzo Bianconi 					 MT_EE_TX_POWER_1_START_2G);
4471613c621SLorenzo Bianconi 	}
4481613c621SLorenzo Bianconi 
4494afeb396SLorenzo Bianconi 	if (mt76x2_tssi_enabled(dev) ||
4501613c621SLorenzo Bianconi 	    !mt76x02_field_valid(t->target_power))
4511613c621SLorenzo Bianconi 		t->target_power = t->chain[0].target_power;
4521613c621SLorenzo Bianconi 
4531613c621SLorenzo Bianconi 	t->delta_bw40 = mt76x02_rate_power_val(bw40);
4541613c621SLorenzo Bianconi 	t->delta_bw80 = mt76x02_rate_power_val(bw80);
4551613c621SLorenzo Bianconi }
4561613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_get_power_info);
4571613c621SLorenzo Bianconi 
mt76x2_get_temp_comp(struct mt76x02_dev * dev,struct mt76x2_temp_comp * t)458e40803f2SLorenzo Bianconi int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t)
4591613c621SLorenzo Bianconi {
46096747a51SFelix Fietkau 	enum nl80211_band band = dev->mphy.chandef.chan->band;
4611613c621SLorenzo Bianconi 	u16 val, slope;
4621613c621SLorenzo Bianconi 	u8 bounds;
4631613c621SLorenzo Bianconi 
4641613c621SLorenzo Bianconi 	memset(t, 0, sizeof(*t));
4651613c621SLorenzo Bianconi 
4664afeb396SLorenzo Bianconi 	if (!mt76x2_temp_tx_alc_enabled(dev))
4671613c621SLorenzo Bianconi 		return -EINVAL;
4681613c621SLorenzo Bianconi 
46926a9daa6SLorenzo Bianconi 	if (!mt76x02_ext_pa_enabled(dev, band))
4701613c621SLorenzo Bianconi 		return -EINVAL;
4711613c621SLorenzo Bianconi 
47226a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8;
4731613c621SLorenzo Bianconi 	t->temp_25_ref = val & 0x7f;
4741613c621SLorenzo Bianconi 	if (band == NL80211_BAND_5GHZ) {
47526a9daa6SLorenzo Bianconi 		slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G);
47626a9daa6SLorenzo Bianconi 		bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
4771613c621SLorenzo Bianconi 	} else {
47826a9daa6SLorenzo Bianconi 		slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G);
47926a9daa6SLorenzo Bianconi 		bounds = mt76x02_eeprom_get(dev,
4801613c621SLorenzo Bianconi 					    MT_EE_TX_POWER_DELTA_BW80) >> 8;
4811613c621SLorenzo Bianconi 	}
4821613c621SLorenzo Bianconi 
4831613c621SLorenzo Bianconi 	t->high_slope = slope & 0xff;
4841613c621SLorenzo Bianconi 	t->low_slope = slope >> 8;
4851613c621SLorenzo Bianconi 	t->lower_bound = 0 - (bounds & 0xf);
4861613c621SLorenzo Bianconi 	t->upper_bound = (bounds >> 4) & 0xf;
4871613c621SLorenzo Bianconi 
4881613c621SLorenzo Bianconi 	return 0;
4891613c621SLorenzo Bianconi }
4901613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp);
4911613c621SLorenzo Bianconi 
mt76x2_eeprom_init(struct mt76x02_dev * dev)492e40803f2SLorenzo Bianconi int mt76x2_eeprom_init(struct mt76x02_dev *dev)
4931613c621SLorenzo Bianconi {
4941613c621SLorenzo Bianconi 	int ret;
4951613c621SLorenzo Bianconi 
4961613c621SLorenzo Bianconi 	ret = mt76x2_eeprom_load(dev);
4971613c621SLorenzo Bianconi 	if (ret)
4981613c621SLorenzo Bianconi 		return ret;
4991613c621SLorenzo Bianconi 
50026a9daa6SLorenzo Bianconi 	mt76x02_eeprom_parse_hw_cap(dev);
5011613c621SLorenzo Bianconi 	mt76x2_eeprom_get_macaddr(dev);
50298df2baeSLorenzo Bianconi 	mt76_eeprom_override(&dev->mphy);
50398df2baeSLorenzo Bianconi 	dev->mphy.macaddr[0] &= ~BIT(1);
5041613c621SLorenzo Bianconi 
5051613c621SLorenzo Bianconi 	return 0;
5061613c621SLorenzo Bianconi }
5071613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_eeprom_init);
5081613c621SLorenzo Bianconi 
5091613c621SLorenzo Bianconi MODULE_LICENSE("Dual BSD/GPL");
510