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