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