11613c621SLorenzo Bianconi /*
21613c621SLorenzo Bianconi  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
31613c621SLorenzo Bianconi  *
41613c621SLorenzo Bianconi  * Permission to use, copy, modify, and/or distribute this software for any
51613c621SLorenzo Bianconi  * purpose with or without fee is hereby granted, provided that the above
61613c621SLorenzo Bianconi  * copyright notice and this permission notice appear in all copies.
71613c621SLorenzo Bianconi  *
81613c621SLorenzo Bianconi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
91613c621SLorenzo Bianconi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
101613c621SLorenzo Bianconi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
111613c621SLorenzo Bianconi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
121613c621SLorenzo Bianconi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
131613c621SLorenzo Bianconi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
141613c621SLorenzo Bianconi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
151613c621SLorenzo Bianconi  */
161613c621SLorenzo Bianconi 
171613c621SLorenzo Bianconi #include <linux/module.h>
181613c621SLorenzo Bianconi #include <asm/unaligned.h>
191613c621SLorenzo Bianconi #include "mt76x2.h"
201613c621SLorenzo Bianconi #include "eeprom.h"
211613c621SLorenzo Bianconi 
221613c621SLorenzo Bianconi #define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1
231613c621SLorenzo Bianconi 
241613c621SLorenzo Bianconi static int
25e40803f2SLorenzo Bianconi mt76x2_eeprom_copy(struct mt76x02_dev *dev, enum mt76x02_eeprom_field field,
261613c621SLorenzo Bianconi 		   void *dest, int len)
271613c621SLorenzo Bianconi {
281613c621SLorenzo Bianconi 	if (field + len > dev->mt76.eeprom.size)
291613c621SLorenzo Bianconi 		return -1;
301613c621SLorenzo Bianconi 
311613c621SLorenzo Bianconi 	memcpy(dest, dev->mt76.eeprom.data + field, len);
321613c621SLorenzo Bianconi 	return 0;
331613c621SLorenzo Bianconi }
341613c621SLorenzo Bianconi 
351613c621SLorenzo Bianconi static int
36e40803f2SLorenzo Bianconi mt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev)
371613c621SLorenzo Bianconi {
381613c621SLorenzo Bianconi 	void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR;
391613c621SLorenzo Bianconi 
401613c621SLorenzo Bianconi 	memcpy(dev->mt76.macaddr, src, ETH_ALEN);
411613c621SLorenzo Bianconi 	return 0;
421613c621SLorenzo Bianconi }
431613c621SLorenzo Bianconi 
441613c621SLorenzo Bianconi static bool
45e40803f2SLorenzo Bianconi mt76x2_has_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
461613c621SLorenzo Bianconi {
471613c621SLorenzo Bianconi 	u16 *efuse_w = (u16 *) efuse;
481613c621SLorenzo Bianconi 
491613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_NIC_CONF_0] != 0)
501613c621SLorenzo Bianconi 		return false;
511613c621SLorenzo Bianconi 
521613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff)
531613c621SLorenzo Bianconi 		return false;
541613c621SLorenzo Bianconi 
551613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0)
561613c621SLorenzo Bianconi 		return false;
571613c621SLorenzo Bianconi 
581613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff)
591613c621SLorenzo Bianconi 		return false;
601613c621SLorenzo Bianconi 
611613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0)
621613c621SLorenzo Bianconi 		return false;
631613c621SLorenzo Bianconi 
641613c621SLorenzo Bianconi 	if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff)
651613c621SLorenzo Bianconi 		return false;
661613c621SLorenzo Bianconi 
671613c621SLorenzo Bianconi 	return true;
681613c621SLorenzo Bianconi }
691613c621SLorenzo Bianconi 
701613c621SLorenzo Bianconi static void
71e40803f2SLorenzo Bianconi mt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse)
721613c621SLorenzo Bianconi {
731613c621SLorenzo Bianconi #define GROUP_5G(_id)							   \
741613c621SLorenzo Bianconi 	MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id),	   \
751613c621SLorenzo Bianconi 	MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \
761613c621SLorenzo Bianconi 	MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id),	   \
771613c621SLorenzo Bianconi 	MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1
781613c621SLorenzo Bianconi 
791613c621SLorenzo Bianconi 	static const u8 cal_free_bytes[] = {
801613c621SLorenzo Bianconi 		MT_EE_XTAL_TRIM_1,
811613c621SLorenzo Bianconi 		MT_EE_TX_POWER_EXT_PA_5G + 1,
821613c621SLorenzo Bianconi 		MT_EE_TX_POWER_0_START_2G,
831613c621SLorenzo Bianconi 		MT_EE_TX_POWER_0_START_2G + 1,
841613c621SLorenzo Bianconi 		MT_EE_TX_POWER_1_START_2G,
851613c621SLorenzo Bianconi 		MT_EE_TX_POWER_1_START_2G + 1,
861613c621SLorenzo Bianconi 		GROUP_5G(0),
871613c621SLorenzo Bianconi 		GROUP_5G(1),
881613c621SLorenzo Bianconi 		GROUP_5G(2),
891613c621SLorenzo Bianconi 		GROUP_5G(3),
901613c621SLorenzo Bianconi 		GROUP_5G(4),
911613c621SLorenzo Bianconi 		GROUP_5G(5),
921613c621SLorenzo Bianconi 		MT_EE_RF_2G_TSSI_OFF_TXPOWER,
931613c621SLorenzo Bianconi 		MT_EE_RF_2G_RX_HIGH_GAIN + 1,
941613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN,
951613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1,
961613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN,
971613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1,
981613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN,
991613c621SLorenzo Bianconi 		MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1,
1001613c621SLorenzo Bianconi 	};
1011613c621SLorenzo Bianconi 	u8 *eeprom = dev->mt76.eeprom.data;
1021613c621SLorenzo Bianconi 	u8 prev_grp0[4] = {
1031613c621SLorenzo Bianconi 		eeprom[MT_EE_TX_POWER_0_START_5G],
1041613c621SLorenzo Bianconi 		eeprom[MT_EE_TX_POWER_0_START_5G + 1],
1051613c621SLorenzo Bianconi 		eeprom[MT_EE_TX_POWER_1_START_5G],
1061613c621SLorenzo Bianconi 		eeprom[MT_EE_TX_POWER_1_START_5G + 1]
1071613c621SLorenzo Bianconi 	};
1081613c621SLorenzo Bianconi 	u16 val;
1091613c621SLorenzo Bianconi 	int i;
1101613c621SLorenzo Bianconi 
1111613c621SLorenzo Bianconi 	if (!mt76x2_has_cal_free_data(dev, efuse))
1121613c621SLorenzo Bianconi 		return;
1131613c621SLorenzo Bianconi 
1141613c621SLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) {
1151613c621SLorenzo Bianconi 		int offset = cal_free_bytes[i];
1161613c621SLorenzo Bianconi 
1171613c621SLorenzo Bianconi 		eeprom[offset] = efuse[offset];
1181613c621SLorenzo Bianconi 	}
1191613c621SLorenzo Bianconi 
1201613c621SLorenzo Bianconi 	if (!(efuse[MT_EE_TX_POWER_0_START_5G] |
1211613c621SLorenzo Bianconi 	      efuse[MT_EE_TX_POWER_0_START_5G + 1]))
1221613c621SLorenzo Bianconi 		memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2);
1231613c621SLorenzo Bianconi 	if (!(efuse[MT_EE_TX_POWER_1_START_5G] |
1241613c621SLorenzo Bianconi 	      efuse[MT_EE_TX_POWER_1_START_5G + 1]))
1251613c621SLorenzo Bianconi 		memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2);
1261613c621SLorenzo Bianconi 
1271613c621SLorenzo Bianconi 	val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT);
1281613c621SLorenzo Bianconi 	if (val != 0xffff)
1291613c621SLorenzo Bianconi 		eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff;
1301613c621SLorenzo Bianconi 
1311613c621SLorenzo Bianconi 	val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION);
1321613c621SLorenzo Bianconi 	if (val != 0xffff)
1331613c621SLorenzo Bianconi 		eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8;
1341613c621SLorenzo Bianconi 
1351613c621SLorenzo Bianconi 	val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG);
1361613c621SLorenzo Bianconi 	if (val != 0xffff)
1371613c621SLorenzo Bianconi 		eeprom[MT_EE_BT_PMUCFG] = val & 0xff;
1381613c621SLorenzo Bianconi }
1391613c621SLorenzo Bianconi 
140e40803f2SLorenzo Bianconi static int mt76x2_check_eeprom(struct mt76x02_dev *dev)
1411613c621SLorenzo Bianconi {
1421613c621SLorenzo Bianconi 	u16 val = get_unaligned_le16(dev->mt76.eeprom.data);
1431613c621SLorenzo Bianconi 
1441613c621SLorenzo Bianconi 	if (!val)
1451613c621SLorenzo Bianconi 		val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID);
1461613c621SLorenzo Bianconi 
1471613c621SLorenzo Bianconi 	switch (val) {
1481613c621SLorenzo Bianconi 	case 0x7662:
1491613c621SLorenzo Bianconi 	case 0x7612:
1501613c621SLorenzo Bianconi 		return 0;
1511613c621SLorenzo Bianconi 	default:
1521613c621SLorenzo Bianconi 		dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val);
1531613c621SLorenzo Bianconi 		return -EINVAL;
1541613c621SLorenzo Bianconi 	}
1551613c621SLorenzo Bianconi }
1561613c621SLorenzo Bianconi 
1571613c621SLorenzo Bianconi static int
158e40803f2SLorenzo Bianconi mt76x2_eeprom_load(struct mt76x02_dev *dev)
1591613c621SLorenzo Bianconi {
1601613c621SLorenzo Bianconi 	void *efuse;
1611613c621SLorenzo Bianconi 	bool found;
1621613c621SLorenzo Bianconi 	int ret;
1631613c621SLorenzo Bianconi 
1641613c621SLorenzo Bianconi 	ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE);
1651613c621SLorenzo Bianconi 	if (ret < 0)
1661613c621SLorenzo Bianconi 		return ret;
1671613c621SLorenzo Bianconi 
1681613c621SLorenzo Bianconi 	found = ret;
1691613c621SLorenzo Bianconi 	if (found)
1701613c621SLorenzo Bianconi 		found = !mt76x2_check_eeprom(dev);
1711613c621SLorenzo Bianconi 
1721613c621SLorenzo Bianconi 	dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE,
1731613c621SLorenzo Bianconi 					  GFP_KERNEL);
1741613c621SLorenzo Bianconi 	dev->mt76.otp.size = MT7662_EEPROM_SIZE;
1751613c621SLorenzo Bianconi 	if (!dev->mt76.otp.data)
1761613c621SLorenzo Bianconi 		return -ENOMEM;
1771613c621SLorenzo Bianconi 
1781613c621SLorenzo Bianconi 	efuse = dev->mt76.otp.data;
1791613c621SLorenzo Bianconi 
18026a9daa6SLorenzo Bianconi 	if (mt76x02_get_efuse_data(dev, 0, efuse, MT7662_EEPROM_SIZE,
18126a9daa6SLorenzo Bianconi 				   MT_EE_READ))
1821613c621SLorenzo Bianconi 		goto out;
1831613c621SLorenzo Bianconi 
1841613c621SLorenzo Bianconi 	if (found) {
1851613c621SLorenzo Bianconi 		mt76x2_apply_cal_free_data(dev, efuse);
1861613c621SLorenzo Bianconi 	} else {
1871613c621SLorenzo Bianconi 		/* FIXME: check if efuse data is complete */
1881613c621SLorenzo Bianconi 		found = true;
1891613c621SLorenzo Bianconi 		memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE);
1901613c621SLorenzo Bianconi 	}
1911613c621SLorenzo Bianconi 
1921613c621SLorenzo Bianconi out:
1931613c621SLorenzo Bianconi 	if (!found)
1941613c621SLorenzo Bianconi 		return -ENOENT;
1951613c621SLorenzo Bianconi 
1961613c621SLorenzo Bianconi 	return 0;
1971613c621SLorenzo Bianconi }
1981613c621SLorenzo Bianconi 
1991613c621SLorenzo Bianconi static void
200e40803f2SLorenzo Bianconi mt76x2_set_rx_gain_group(struct mt76x02_dev *dev, u8 val)
2011613c621SLorenzo Bianconi {
2021613c621SLorenzo Bianconi 	s8 *dest = dev->cal.rx.high_gain;
2031613c621SLorenzo Bianconi 
2041613c621SLorenzo Bianconi 	if (!mt76x02_field_valid(val)) {
2051613c621SLorenzo Bianconi 		dest[0] = 0;
2061613c621SLorenzo Bianconi 		dest[1] = 0;
2071613c621SLorenzo Bianconi 		return;
2081613c621SLorenzo Bianconi 	}
2091613c621SLorenzo Bianconi 
2101613c621SLorenzo Bianconi 	dest[0] = mt76x02_sign_extend(val, 4);
2111613c621SLorenzo Bianconi 	dest[1] = mt76x02_sign_extend(val >> 4, 4);
2121613c621SLorenzo Bianconi }
2131613c621SLorenzo Bianconi 
2141613c621SLorenzo Bianconi static void
215e40803f2SLorenzo Bianconi mt76x2_set_rssi_offset(struct mt76x02_dev *dev, int chain, u8 val)
2161613c621SLorenzo Bianconi {
2171613c621SLorenzo Bianconi 	s8 *dest = dev->cal.rx.rssi_offset;
2181613c621SLorenzo Bianconi 
2191613c621SLorenzo Bianconi 	if (!mt76x02_field_valid(val)) {
2201613c621SLorenzo Bianconi 		dest[chain] = 0;
2211613c621SLorenzo Bianconi 		return;
2221613c621SLorenzo Bianconi 	}
2231613c621SLorenzo Bianconi 
2241613c621SLorenzo Bianconi 	dest[chain] = mt76x02_sign_extend_optional(val, 7);
2251613c621SLorenzo Bianconi }
2261613c621SLorenzo Bianconi 
2271613c621SLorenzo Bianconi static enum mt76x2_cal_channel_group
2281613c621SLorenzo Bianconi mt76x2_get_cal_channel_group(int channel)
2291613c621SLorenzo Bianconi {
2301613c621SLorenzo Bianconi 	if (channel >= 184 && channel <= 196)
2311613c621SLorenzo Bianconi 		return MT_CH_5G_JAPAN;
2321613c621SLorenzo Bianconi 	if (channel <= 48)
2331613c621SLorenzo Bianconi 		return MT_CH_5G_UNII_1;
2341613c621SLorenzo Bianconi 	if (channel <= 64)
2351613c621SLorenzo Bianconi 		return MT_CH_5G_UNII_2;
2361613c621SLorenzo Bianconi 	if (channel <= 114)
2371613c621SLorenzo Bianconi 		return MT_CH_5G_UNII_2E_1;
2381613c621SLorenzo Bianconi 	if (channel <= 144)
2391613c621SLorenzo Bianconi 		return MT_CH_5G_UNII_2E_2;
2401613c621SLorenzo Bianconi 	return MT_CH_5G_UNII_3;
2411613c621SLorenzo Bianconi }
2421613c621SLorenzo Bianconi 
2431613c621SLorenzo Bianconi static u8
244e40803f2SLorenzo Bianconi mt76x2_get_5g_rx_gain(struct mt76x02_dev *dev, u8 channel)
2451613c621SLorenzo Bianconi {
2461613c621SLorenzo Bianconi 	enum mt76x2_cal_channel_group group;
2471613c621SLorenzo Bianconi 
2481613c621SLorenzo Bianconi 	group = mt76x2_get_cal_channel_group(channel);
2491613c621SLorenzo Bianconi 	switch (group) {
2501613c621SLorenzo Bianconi 	case MT_CH_5G_JAPAN:
25126a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2521613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN);
2531613c621SLorenzo Bianconi 	case MT_CH_5G_UNII_1:
25426a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2551613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8;
2561613c621SLorenzo Bianconi 	case MT_CH_5G_UNII_2:
25726a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2581613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN);
2591613c621SLorenzo Bianconi 	case MT_CH_5G_UNII_2E_1:
26026a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2611613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8;
2621613c621SLorenzo Bianconi 	case MT_CH_5G_UNII_2E_2:
26326a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2641613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN);
2651613c621SLorenzo Bianconi 	default:
26626a9daa6SLorenzo Bianconi 		return mt76x02_eeprom_get(dev,
2671613c621SLorenzo Bianconi 					  MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8;
2681613c621SLorenzo Bianconi 	}
2691613c621SLorenzo Bianconi }
2701613c621SLorenzo Bianconi 
271e40803f2SLorenzo Bianconi void mt76x2_read_rx_gain(struct mt76x02_dev *dev)
2721613c621SLorenzo Bianconi {
2731613c621SLorenzo Bianconi 	struct ieee80211_channel *chan = dev->mt76.chandef.chan;
2741613c621SLorenzo Bianconi 	int channel = chan->hw_value;
2751613c621SLorenzo Bianconi 	s8 lna_5g[3], lna_2g;
2761613c621SLorenzo Bianconi 	u8 lna;
2771613c621SLorenzo Bianconi 	u16 val;
2781613c621SLorenzo Bianconi 
2791613c621SLorenzo Bianconi 	if (chan->band == NL80211_BAND_2GHZ)
28026a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8;
2811613c621SLorenzo Bianconi 	else
2821613c621SLorenzo Bianconi 		val = mt76x2_get_5g_rx_gain(dev, channel);
2831613c621SLorenzo Bianconi 
2841613c621SLorenzo Bianconi 	mt76x2_set_rx_gain_group(dev, val);
2851613c621SLorenzo Bianconi 
28626a9daa6SLorenzo Bianconi 	mt76x02_get_rx_gain(dev, chan->band, &val, &lna_2g, lna_5g);
2871613c621SLorenzo Bianconi 	mt76x2_set_rssi_offset(dev, 0, val);
2881613c621SLorenzo Bianconi 	mt76x2_set_rssi_offset(dev, 1, val >> 8);
2891613c621SLorenzo Bianconi 
2901613c621SLorenzo Bianconi 	dev->cal.rx.mcu_gain =  (lna_2g & 0xff);
2911613c621SLorenzo Bianconi 	dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8;
2921613c621SLorenzo Bianconi 	dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16;
2931613c621SLorenzo Bianconi 	dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24;
2941613c621SLorenzo Bianconi 
29526a9daa6SLorenzo Bianconi 	lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan);
2961613c621SLorenzo Bianconi 	dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8);
2971613c621SLorenzo Bianconi }
2981613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain);
2991613c621SLorenzo Bianconi 
300e40803f2SLorenzo Bianconi void mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76_rate_power *t,
3011613c621SLorenzo Bianconi 			   struct ieee80211_channel *chan)
3021613c621SLorenzo Bianconi {
3031613c621SLorenzo Bianconi 	bool is_5ghz;
3041613c621SLorenzo Bianconi 	u16 val;
3051613c621SLorenzo Bianconi 
3061613c621SLorenzo Bianconi 	is_5ghz = chan->band == NL80211_BAND_5GHZ;
3071613c621SLorenzo Bianconi 
3081613c621SLorenzo Bianconi 	memset(t, 0, sizeof(*t));
3091613c621SLorenzo Bianconi 
31026a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_CCK);
3111613c621SLorenzo Bianconi 	t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val);
3121613c621SLorenzo Bianconi 	t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8);
3131613c621SLorenzo Bianconi 
3141613c621SLorenzo Bianconi 	if (is_5ghz)
31526a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M);
3161613c621SLorenzo Bianconi 	else
31726a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M);
3181613c621SLorenzo Bianconi 	t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val);
3191613c621SLorenzo Bianconi 	t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8);
3201613c621SLorenzo Bianconi 
3211613c621SLorenzo Bianconi 	if (is_5ghz)
32226a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M);
3231613c621SLorenzo Bianconi 	else
32426a9daa6SLorenzo Bianconi 		val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M);
3251613c621SLorenzo Bianconi 	t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val);
3261613c621SLorenzo Bianconi 	t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8);
3271613c621SLorenzo Bianconi 
32826a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0);
3291613c621SLorenzo Bianconi 	t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val);
3301613c621SLorenzo Bianconi 	t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8);
3311613c621SLorenzo Bianconi 
33226a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4);
3331613c621SLorenzo Bianconi 	t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val);
3341613c621SLorenzo Bianconi 	t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8);
3351613c621SLorenzo Bianconi 
33626a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8);
3371613c621SLorenzo Bianconi 	t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val);
3381613c621SLorenzo Bianconi 	t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8);
3391613c621SLorenzo Bianconi 
34026a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12);
3411613c621SLorenzo Bianconi 	t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val);
3421613c621SLorenzo Bianconi 	t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8);
3431613c621SLorenzo Bianconi 
34426a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0);
3451613c621SLorenzo Bianconi 	t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val);
3461613c621SLorenzo Bianconi 	t->vht[2] = t->vht[3] = mt76x02_rate_power_val(val >> 8);
3471613c621SLorenzo Bianconi 
34826a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4);
3491613c621SLorenzo Bianconi 	t->vht[4] = t->vht[5] = mt76x02_rate_power_val(val);
3501613c621SLorenzo Bianconi 	t->vht[6] = t->vht[7] = mt76x02_rate_power_val(val >> 8);
3511613c621SLorenzo Bianconi 
35226a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8);
3531613c621SLorenzo Bianconi 	if (!is_5ghz)
3541613c621SLorenzo Bianconi 		val >>= 8;
3551613c621SLorenzo Bianconi 	t->vht[8] = t->vht[9] = mt76x02_rate_power_val(val >> 8);
3561613c621SLorenzo Bianconi 
3571613c621SLorenzo Bianconi 	memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8);
3581613c621SLorenzo Bianconi 	t->stbc[8] = t->vht[8];
3591613c621SLorenzo Bianconi 	t->stbc[9] = t->vht[9];
3601613c621SLorenzo Bianconi }
3611613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_get_rate_power);
3621613c621SLorenzo Bianconi 
3631613c621SLorenzo Bianconi static void
364e40803f2SLorenzo Bianconi mt76x2_get_power_info_2g(struct mt76x02_dev *dev,
365e40803f2SLorenzo Bianconi 			 struct mt76x2_tx_power_info *t,
366e40803f2SLorenzo Bianconi 			 struct ieee80211_channel *chan,
367e40803f2SLorenzo Bianconi 			 int chain, int offset)
3681613c621SLorenzo Bianconi {
3691613c621SLorenzo Bianconi 	int channel = chan->hw_value;
3701613c621SLorenzo Bianconi 	int delta_idx;
3711613c621SLorenzo Bianconi 	u8 data[6];
3721613c621SLorenzo Bianconi 	u16 val;
3731613c621SLorenzo Bianconi 
3741613c621SLorenzo Bianconi 	if (channel < 6)
3751613c621SLorenzo Bianconi 		delta_idx = 3;
3761613c621SLorenzo Bianconi 	else if (channel < 11)
3771613c621SLorenzo Bianconi 		delta_idx = 4;
3781613c621SLorenzo Bianconi 	else
3791613c621SLorenzo Bianconi 		delta_idx = 5;
3801613c621SLorenzo Bianconi 
3811613c621SLorenzo Bianconi 	mt76x2_eeprom_copy(dev, offset, data, sizeof(data));
3821613c621SLorenzo Bianconi 
3831613c621SLorenzo Bianconi 	t->chain[chain].tssi_slope = data[0];
3841613c621SLorenzo Bianconi 	t->chain[chain].tssi_offset = data[1];
3851613c621SLorenzo Bianconi 	t->chain[chain].target_power = data[2];
3861613c621SLorenzo Bianconi 	t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7);
3871613c621SLorenzo Bianconi 
38826a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER);
3891613c621SLorenzo Bianconi 	t->target_power = val >> 8;
3901613c621SLorenzo Bianconi }
3911613c621SLorenzo Bianconi 
3921613c621SLorenzo Bianconi static void
393e40803f2SLorenzo Bianconi mt76x2_get_power_info_5g(struct mt76x02_dev *dev,
394e40803f2SLorenzo Bianconi 			 struct mt76x2_tx_power_info *t,
395e40803f2SLorenzo Bianconi 		         struct ieee80211_channel *chan,
396e40803f2SLorenzo Bianconi 			 int chain, int offset)
3971613c621SLorenzo Bianconi {
3981613c621SLorenzo Bianconi 	int channel = chan->hw_value;
3991613c621SLorenzo Bianconi 	enum mt76x2_cal_channel_group group;
4001613c621SLorenzo Bianconi 	int delta_idx;
4011613c621SLorenzo Bianconi 	u16 val;
4021613c621SLorenzo Bianconi 	u8 data[5];
4031613c621SLorenzo Bianconi 
4041613c621SLorenzo Bianconi 	group = mt76x2_get_cal_channel_group(channel);
4051613c621SLorenzo Bianconi 	offset += group * MT_TX_POWER_GROUP_SIZE_5G;
4061613c621SLorenzo Bianconi 
4071613c621SLorenzo Bianconi 	if (channel >= 192)
4081613c621SLorenzo Bianconi 		delta_idx = 4;
4091613c621SLorenzo Bianconi 	else if (channel >= 184)
4101613c621SLorenzo Bianconi 		delta_idx = 3;
4111613c621SLorenzo Bianconi 	else if (channel < 44)
4121613c621SLorenzo Bianconi 		delta_idx = 3;
4131613c621SLorenzo Bianconi 	else if (channel < 52)
4141613c621SLorenzo Bianconi 		delta_idx = 4;
4151613c621SLorenzo Bianconi 	else if (channel < 58)
4161613c621SLorenzo Bianconi 		delta_idx = 3;
4171613c621SLorenzo Bianconi 	else if (channel < 98)
4181613c621SLorenzo Bianconi 		delta_idx = 4;
4191613c621SLorenzo Bianconi 	else if (channel < 106)
4201613c621SLorenzo Bianconi 		delta_idx = 3;
4211613c621SLorenzo Bianconi 	else if (channel < 116)
4221613c621SLorenzo Bianconi 		delta_idx = 4;
4231613c621SLorenzo Bianconi 	else if (channel < 130)
4241613c621SLorenzo Bianconi 		delta_idx = 3;
4251613c621SLorenzo Bianconi 	else if (channel < 149)
4261613c621SLorenzo Bianconi 		delta_idx = 4;
4271613c621SLorenzo Bianconi 	else if (channel < 157)
4281613c621SLorenzo Bianconi 		delta_idx = 3;
4291613c621SLorenzo Bianconi 	else
4301613c621SLorenzo Bianconi 		delta_idx = 4;
4311613c621SLorenzo Bianconi 
4321613c621SLorenzo Bianconi 	mt76x2_eeprom_copy(dev, offset, data, sizeof(data));
4331613c621SLorenzo Bianconi 
4341613c621SLorenzo Bianconi 	t->chain[chain].tssi_slope = data[0];
4351613c621SLorenzo Bianconi 	t->chain[chain].tssi_offset = data[1];
4361613c621SLorenzo Bianconi 	t->chain[chain].target_power = data[2];
4371613c621SLorenzo Bianconi 	t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7);
4381613c621SLorenzo Bianconi 
43926a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN);
4401613c621SLorenzo Bianconi 	t->target_power = val & 0xff;
4411613c621SLorenzo Bianconi }
4421613c621SLorenzo Bianconi 
443e40803f2SLorenzo Bianconi void mt76x2_get_power_info(struct mt76x02_dev *dev,
4441613c621SLorenzo Bianconi 			   struct mt76x2_tx_power_info *t,
4451613c621SLorenzo Bianconi 			   struct ieee80211_channel *chan)
4461613c621SLorenzo Bianconi {
4471613c621SLorenzo Bianconi 	u16 bw40, bw80;
4481613c621SLorenzo Bianconi 
4491613c621SLorenzo Bianconi 	memset(t, 0, sizeof(*t));
4501613c621SLorenzo Bianconi 
45126a9daa6SLorenzo Bianconi 	bw40 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40);
45226a9daa6SLorenzo Bianconi 	bw80 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80);
4531613c621SLorenzo Bianconi 
4541613c621SLorenzo Bianconi 	if (chan->band == NL80211_BAND_5GHZ) {
4551613c621SLorenzo Bianconi 		bw40 >>= 8;
4561613c621SLorenzo Bianconi 		mt76x2_get_power_info_5g(dev, t, chan, 0,
4571613c621SLorenzo Bianconi 					 MT_EE_TX_POWER_0_START_5G);
4581613c621SLorenzo Bianconi 		mt76x2_get_power_info_5g(dev, t, chan, 1,
4591613c621SLorenzo Bianconi 					 MT_EE_TX_POWER_1_START_5G);
4601613c621SLorenzo Bianconi 	} else {
4611613c621SLorenzo Bianconi 		mt76x2_get_power_info_2g(dev, t, chan, 0,
4621613c621SLorenzo Bianconi 					 MT_EE_TX_POWER_0_START_2G);
4631613c621SLorenzo Bianconi 		mt76x2_get_power_info_2g(dev, t, chan, 1,
4641613c621SLorenzo Bianconi 					 MT_EE_TX_POWER_1_START_2G);
4651613c621SLorenzo Bianconi 	}
4661613c621SLorenzo Bianconi 
4674afeb396SLorenzo Bianconi 	if (mt76x2_tssi_enabled(dev) ||
4681613c621SLorenzo Bianconi 	    !mt76x02_field_valid(t->target_power))
4691613c621SLorenzo Bianconi 		t->target_power = t->chain[0].target_power;
4701613c621SLorenzo Bianconi 
4711613c621SLorenzo Bianconi 	t->delta_bw40 = mt76x02_rate_power_val(bw40);
4721613c621SLorenzo Bianconi 	t->delta_bw80 = mt76x02_rate_power_val(bw80);
4731613c621SLorenzo Bianconi }
4741613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_get_power_info);
4751613c621SLorenzo Bianconi 
476e40803f2SLorenzo Bianconi int mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t)
4771613c621SLorenzo Bianconi {
4781613c621SLorenzo Bianconi 	enum nl80211_band band = dev->mt76.chandef.chan->band;
4791613c621SLorenzo Bianconi 	u16 val, slope;
4801613c621SLorenzo Bianconi 	u8 bounds;
4811613c621SLorenzo Bianconi 
4821613c621SLorenzo Bianconi 	memset(t, 0, sizeof(*t));
4831613c621SLorenzo Bianconi 
4844afeb396SLorenzo Bianconi 	if (!mt76x2_temp_tx_alc_enabled(dev))
4851613c621SLorenzo Bianconi 		return -EINVAL;
4861613c621SLorenzo Bianconi 
48726a9daa6SLorenzo Bianconi 	if (!mt76x02_ext_pa_enabled(dev, band))
4881613c621SLorenzo Bianconi 		return -EINVAL;
4891613c621SLorenzo Bianconi 
49026a9daa6SLorenzo Bianconi 	val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8;
4911613c621SLorenzo Bianconi 	t->temp_25_ref = val & 0x7f;
4921613c621SLorenzo Bianconi 	if (band == NL80211_BAND_5GHZ) {
49326a9daa6SLorenzo Bianconi 		slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G);
49426a9daa6SLorenzo Bianconi 		bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G);
4951613c621SLorenzo Bianconi 	} else {
49626a9daa6SLorenzo Bianconi 		slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G);
49726a9daa6SLorenzo Bianconi 		bounds = mt76x02_eeprom_get(dev,
4981613c621SLorenzo Bianconi 					    MT_EE_TX_POWER_DELTA_BW80) >> 8;
4991613c621SLorenzo Bianconi 	}
5001613c621SLorenzo Bianconi 
5011613c621SLorenzo Bianconi 	t->high_slope = slope & 0xff;
5021613c621SLorenzo Bianconi 	t->low_slope = slope >> 8;
5031613c621SLorenzo Bianconi 	t->lower_bound = 0 - (bounds & 0xf);
5041613c621SLorenzo Bianconi 	t->upper_bound = (bounds >> 4) & 0xf;
5051613c621SLorenzo Bianconi 
5061613c621SLorenzo Bianconi 	return 0;
5071613c621SLorenzo Bianconi }
5081613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp);
5091613c621SLorenzo Bianconi 
510e40803f2SLorenzo Bianconi int mt76x2_eeprom_init(struct mt76x02_dev *dev)
5111613c621SLorenzo Bianconi {
5121613c621SLorenzo Bianconi 	int ret;
5131613c621SLorenzo Bianconi 
5141613c621SLorenzo Bianconi 	ret = mt76x2_eeprom_load(dev);
5151613c621SLorenzo Bianconi 	if (ret)
5161613c621SLorenzo Bianconi 		return ret;
5171613c621SLorenzo Bianconi 
51826a9daa6SLorenzo Bianconi 	mt76x02_eeprom_parse_hw_cap(dev);
5191613c621SLorenzo Bianconi 	mt76x2_eeprom_get_macaddr(dev);
5201613c621SLorenzo Bianconi 	mt76_eeprom_override(&dev->mt76);
5211613c621SLorenzo Bianconi 	dev->mt76.macaddr[0] &= ~BIT(1);
5221613c621SLorenzo Bianconi 
5231613c621SLorenzo Bianconi 	return 0;
5241613c621SLorenzo Bianconi }
5251613c621SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x2_eeprom_init);
5261613c621SLorenzo Bianconi 
5271613c621SLorenzo Bianconi MODULE_LICENSE("Dual BSD/GPL");
528