162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/of.h> 862306a36Sopenharmony_ci#include <asm/unaligned.h> 962306a36Sopenharmony_ci#include "mt76x2.h" 1062306a36Sopenharmony_ci#include "eeprom.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int 1562306a36Sopenharmony_cimt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci memcpy(dev->mphy.macaddr, src, ETH_ALEN); 2062306a36Sopenharmony_ci return 0; 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic bool 2462306a36Sopenharmony_cimt76x2_has_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci u16 *efuse_w = (u16 *)efuse; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (efuse_w[MT_EE_NIC_CONF_0] != 0) 2962306a36Sopenharmony_ci return false; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff) 3262306a36Sopenharmony_ci return false; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0) 3562306a36Sopenharmony_ci return false; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff) 3862306a36Sopenharmony_ci return false; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0) 4162306a36Sopenharmony_ci return false; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff) 4462306a36Sopenharmony_ci return false; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci return true; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void 5062306a36Sopenharmony_cimt76x2_apply_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci#define GROUP_5G(_id) \ 5362306a36Sopenharmony_ci MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ 5462306a36Sopenharmony_ci MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \ 5562306a36Sopenharmony_ci MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ 5662306a36Sopenharmony_ci MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci static const u8 cal_free_bytes[] = { 5962306a36Sopenharmony_ci MT_EE_XTAL_TRIM_1, 6062306a36Sopenharmony_ci MT_EE_TX_POWER_EXT_PA_5G + 1, 6162306a36Sopenharmony_ci MT_EE_TX_POWER_0_START_2G, 6262306a36Sopenharmony_ci MT_EE_TX_POWER_0_START_2G + 1, 6362306a36Sopenharmony_ci MT_EE_TX_POWER_1_START_2G, 6462306a36Sopenharmony_ci MT_EE_TX_POWER_1_START_2G + 1, 6562306a36Sopenharmony_ci GROUP_5G(0), 6662306a36Sopenharmony_ci GROUP_5G(1), 6762306a36Sopenharmony_ci GROUP_5G(2), 6862306a36Sopenharmony_ci GROUP_5G(3), 6962306a36Sopenharmony_ci GROUP_5G(4), 7062306a36Sopenharmony_ci GROUP_5G(5), 7162306a36Sopenharmony_ci MT_EE_RF_2G_TSSI_OFF_TXPOWER, 7262306a36Sopenharmony_ci MT_EE_RF_2G_RX_HIGH_GAIN + 1, 7362306a36Sopenharmony_ci MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN, 7462306a36Sopenharmony_ci MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1, 7562306a36Sopenharmony_ci MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN, 7662306a36Sopenharmony_ci MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1, 7762306a36Sopenharmony_ci MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN, 7862306a36Sopenharmony_ci MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1, 7962306a36Sopenharmony_ci }; 8062306a36Sopenharmony_ci struct device_node *np = dev->mt76.dev->of_node; 8162306a36Sopenharmony_ci u8 *eeprom = dev->mt76.eeprom.data; 8262306a36Sopenharmony_ci u8 prev_grp0[4] = { 8362306a36Sopenharmony_ci eeprom[MT_EE_TX_POWER_0_START_5G], 8462306a36Sopenharmony_ci eeprom[MT_EE_TX_POWER_0_START_5G + 1], 8562306a36Sopenharmony_ci eeprom[MT_EE_TX_POWER_1_START_5G], 8662306a36Sopenharmony_ci eeprom[MT_EE_TX_POWER_1_START_5G + 1] 8762306a36Sopenharmony_ci }; 8862306a36Sopenharmony_ci u16 val; 8962306a36Sopenharmony_ci int i; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (!np || !of_property_read_bool(np, "mediatek,eeprom-merge-otp")) 9262306a36Sopenharmony_ci return; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (!mt76x2_has_cal_free_data(dev, efuse)) 9562306a36Sopenharmony_ci return; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) { 9862306a36Sopenharmony_ci int offset = cal_free_bytes[i]; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci eeprom[offset] = efuse[offset]; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (!(efuse[MT_EE_TX_POWER_0_START_5G] | 10462306a36Sopenharmony_ci efuse[MT_EE_TX_POWER_0_START_5G + 1])) 10562306a36Sopenharmony_ci memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2); 10662306a36Sopenharmony_ci if (!(efuse[MT_EE_TX_POWER_1_START_5G] | 10762306a36Sopenharmony_ci efuse[MT_EE_TX_POWER_1_START_5G + 1])) 10862306a36Sopenharmony_ci memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT); 11162306a36Sopenharmony_ci if (val != 0xffff) 11262306a36Sopenharmony_ci eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION); 11562306a36Sopenharmony_ci if (val != 0xffff) 11662306a36Sopenharmony_ci eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG); 11962306a36Sopenharmony_ci if (val != 0xffff) 12062306a36Sopenharmony_ci eeprom[MT_EE_BT_PMUCFG] = val & 0xff; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int mt76x2_check_eeprom(struct mt76x02_dev *dev) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci u16 val = get_unaligned_le16(dev->mt76.eeprom.data); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (!val) 12862306a36Sopenharmony_ci val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci switch (val) { 13162306a36Sopenharmony_ci case 0x7662: 13262306a36Sopenharmony_ci case 0x7612: 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci default: 13562306a36Sopenharmony_ci dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val); 13662306a36Sopenharmony_ci return -EINVAL; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int 14162306a36Sopenharmony_cimt76x2_eeprom_load(struct mt76x02_dev *dev) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci void *efuse; 14462306a36Sopenharmony_ci bool found; 14562306a36Sopenharmony_ci int ret; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE); 14862306a36Sopenharmony_ci if (ret < 0) 14962306a36Sopenharmony_ci return ret; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci found = ret; 15262306a36Sopenharmony_ci if (found) 15362306a36Sopenharmony_ci found = !mt76x2_check_eeprom(dev); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE, 15662306a36Sopenharmony_ci GFP_KERNEL); 15762306a36Sopenharmony_ci dev->mt76.otp.size = MT7662_EEPROM_SIZE; 15862306a36Sopenharmony_ci if (!dev->mt76.otp.data) 15962306a36Sopenharmony_ci return -ENOMEM; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci efuse = dev->mt76.otp.data; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (mt76x02_get_efuse_data(dev, 0, efuse, MT7662_EEPROM_SIZE, 16462306a36Sopenharmony_ci MT_EE_READ)) 16562306a36Sopenharmony_ci goto out; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (found) { 16862306a36Sopenharmony_ci mt76x2_apply_cal_free_data(dev, efuse); 16962306a36Sopenharmony_ci } else { 17062306a36Sopenharmony_ci /* FIXME: check if efuse data is complete */ 17162306a36Sopenharmony_ci found = true; 17262306a36Sopenharmony_ci memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ciout: 17662306a36Sopenharmony_ci if (!found) 17762306a36Sopenharmony_ci return -ENOENT; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void 18362306a36Sopenharmony_cimt76x2_set_rx_gain_group(struct mt76x02_dev *dev, u8 val) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci s8 *dest = dev->cal.rx.high_gain; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (!mt76x02_field_valid(val)) { 18862306a36Sopenharmony_ci dest[0] = 0; 18962306a36Sopenharmony_ci dest[1] = 0; 19062306a36Sopenharmony_ci return; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci dest[0] = mt76x02_sign_extend(val, 4); 19462306a36Sopenharmony_ci dest[1] = mt76x02_sign_extend(val >> 4, 4); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void 19862306a36Sopenharmony_cimt76x2_set_rssi_offset(struct mt76x02_dev *dev, int chain, u8 val) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci s8 *dest = dev->cal.rx.rssi_offset; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (!mt76x02_field_valid(val)) { 20362306a36Sopenharmony_ci dest[chain] = 0; 20462306a36Sopenharmony_ci return; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci dest[chain] = mt76x02_sign_extend_optional(val, 7); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic enum mt76x2_cal_channel_group 21162306a36Sopenharmony_cimt76x2_get_cal_channel_group(int channel) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci if (channel >= 184 && channel <= 196) 21462306a36Sopenharmony_ci return MT_CH_5G_JAPAN; 21562306a36Sopenharmony_ci if (channel <= 48) 21662306a36Sopenharmony_ci return MT_CH_5G_UNII_1; 21762306a36Sopenharmony_ci if (channel <= 64) 21862306a36Sopenharmony_ci return MT_CH_5G_UNII_2; 21962306a36Sopenharmony_ci if (channel <= 114) 22062306a36Sopenharmony_ci return MT_CH_5G_UNII_2E_1; 22162306a36Sopenharmony_ci if (channel <= 144) 22262306a36Sopenharmony_ci return MT_CH_5G_UNII_2E_2; 22362306a36Sopenharmony_ci return MT_CH_5G_UNII_3; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic u8 22762306a36Sopenharmony_cimt76x2_get_5g_rx_gain(struct mt76x02_dev *dev, u8 channel) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci enum mt76x2_cal_channel_group group; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci group = mt76x2_get_cal_channel_group(channel); 23262306a36Sopenharmony_ci switch (group) { 23362306a36Sopenharmony_ci case MT_CH_5G_JAPAN: 23462306a36Sopenharmony_ci return mt76x02_eeprom_get(dev, 23562306a36Sopenharmony_ci MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); 23662306a36Sopenharmony_ci case MT_CH_5G_UNII_1: 23762306a36Sopenharmony_ci return mt76x02_eeprom_get(dev, 23862306a36Sopenharmony_ci MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; 23962306a36Sopenharmony_ci case MT_CH_5G_UNII_2: 24062306a36Sopenharmony_ci return mt76x02_eeprom_get(dev, 24162306a36Sopenharmony_ci MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); 24262306a36Sopenharmony_ci case MT_CH_5G_UNII_2E_1: 24362306a36Sopenharmony_ci return mt76x02_eeprom_get(dev, 24462306a36Sopenharmony_ci MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; 24562306a36Sopenharmony_ci case MT_CH_5G_UNII_2E_2: 24662306a36Sopenharmony_ci return mt76x02_eeprom_get(dev, 24762306a36Sopenharmony_ci MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); 24862306a36Sopenharmony_ci default: 24962306a36Sopenharmony_ci return mt76x02_eeprom_get(dev, 25062306a36Sopenharmony_ci MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_civoid mt76x2_read_rx_gain(struct mt76x02_dev *dev) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct ieee80211_channel *chan = dev->mphy.chandef.chan; 25762306a36Sopenharmony_ci int channel = chan->hw_value; 25862306a36Sopenharmony_ci s8 lna_5g[3], lna_2g; 25962306a36Sopenharmony_ci bool use_lna; 26062306a36Sopenharmony_ci u8 lna = 0; 26162306a36Sopenharmony_ci u16 val; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (chan->band == NL80211_BAND_2GHZ) 26462306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; 26562306a36Sopenharmony_ci else 26662306a36Sopenharmony_ci val = mt76x2_get_5g_rx_gain(dev, channel); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci mt76x2_set_rx_gain_group(dev, val); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci mt76x02_get_rx_gain(dev, chan->band, &val, &lna_2g, lna_5g); 27162306a36Sopenharmony_ci mt76x2_set_rssi_offset(dev, 0, val); 27262306a36Sopenharmony_ci mt76x2_set_rssi_offset(dev, 1, val >> 8); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci dev->cal.rx.mcu_gain = (lna_2g & 0xff); 27562306a36Sopenharmony_ci dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8; 27662306a36Sopenharmony_ci dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; 27762306a36Sopenharmony_ci dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); 28062306a36Sopenharmony_ci if (chan->band == NL80211_BAND_2GHZ) 28162306a36Sopenharmony_ci use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_2G); 28262306a36Sopenharmony_ci else 28362306a36Sopenharmony_ci use_lna = !(val & MT_EE_NIC_CONF_1_LNA_EXT_5G); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (use_lna) 28662306a36Sopenharmony_ci lna = mt76x02_get_lna_gain(dev, &lna_2g, lna_5g, chan); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_civoid mt76x2_get_rate_power(struct mt76x02_dev *dev, struct mt76x02_rate_power *t, 29362306a36Sopenharmony_ci struct ieee80211_channel *chan) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci bool is_5ghz; 29662306a36Sopenharmony_ci u16 val; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci is_5ghz = chan->band == NL80211_BAND_5GHZ; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci memset(t, 0, sizeof(*t)); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_CCK); 30362306a36Sopenharmony_ci t->cck[0] = t->cck[1] = mt76x02_rate_power_val(val); 30462306a36Sopenharmony_ci t->cck[2] = t->cck[3] = mt76x02_rate_power_val(val >> 8); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (is_5ghz) 30762306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M); 30862306a36Sopenharmony_ci else 30962306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M); 31062306a36Sopenharmony_ci t->ofdm[0] = t->ofdm[1] = mt76x02_rate_power_val(val); 31162306a36Sopenharmony_ci t->ofdm[2] = t->ofdm[3] = mt76x02_rate_power_val(val >> 8); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (is_5ghz) 31462306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M); 31562306a36Sopenharmony_ci else 31662306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M); 31762306a36Sopenharmony_ci t->ofdm[4] = t->ofdm[5] = mt76x02_rate_power_val(val); 31862306a36Sopenharmony_ci t->ofdm[6] = t->ofdm[7] = mt76x02_rate_power_val(val >> 8); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0); 32162306a36Sopenharmony_ci t->ht[0] = t->ht[1] = mt76x02_rate_power_val(val); 32262306a36Sopenharmony_ci t->ht[2] = t->ht[3] = mt76x02_rate_power_val(val >> 8); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4); 32562306a36Sopenharmony_ci t->ht[4] = t->ht[5] = mt76x02_rate_power_val(val); 32662306a36Sopenharmony_ci t->ht[6] = t->ht[7] = mt76x02_rate_power_val(val >> 8); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8); 32962306a36Sopenharmony_ci t->ht[8] = t->ht[9] = mt76x02_rate_power_val(val); 33062306a36Sopenharmony_ci t->ht[10] = t->ht[11] = mt76x02_rate_power_val(val >> 8); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12); 33362306a36Sopenharmony_ci t->ht[12] = t->ht[13] = mt76x02_rate_power_val(val); 33462306a36Sopenharmony_ci t->ht[14] = t->ht[15] = mt76x02_rate_power_val(val >> 8); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8); 33762306a36Sopenharmony_ci if (!is_5ghz) 33862306a36Sopenharmony_ci val >>= 8; 33962306a36Sopenharmony_ci t->vht[0] = t->vht[1] = mt76x02_rate_power_val(val >> 8); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_get_rate_power); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void 34462306a36Sopenharmony_cimt76x2_get_power_info_2g(struct mt76x02_dev *dev, 34562306a36Sopenharmony_ci struct mt76x2_tx_power_info *t, 34662306a36Sopenharmony_ci struct ieee80211_channel *chan, 34762306a36Sopenharmony_ci int chain, int offset) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci int channel = chan->hw_value; 35062306a36Sopenharmony_ci int delta_idx; 35162306a36Sopenharmony_ci u8 data[6]; 35262306a36Sopenharmony_ci u16 val; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (channel < 6) 35562306a36Sopenharmony_ci delta_idx = 3; 35662306a36Sopenharmony_ci else if (channel < 11) 35762306a36Sopenharmony_ci delta_idx = 4; 35862306a36Sopenharmony_ci else 35962306a36Sopenharmony_ci delta_idx = 5; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci mt76x02_eeprom_copy(dev, offset, data, sizeof(data)); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci t->chain[chain].tssi_slope = data[0]; 36462306a36Sopenharmony_ci t->chain[chain].tssi_offset = data[1]; 36562306a36Sopenharmony_ci t->chain[chain].target_power = data[2]; 36662306a36Sopenharmony_ci t->chain[chain].delta = 36762306a36Sopenharmony_ci mt76x02_sign_extend_optional(data[delta_idx], 7); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER); 37062306a36Sopenharmony_ci t->target_power = val >> 8; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void 37462306a36Sopenharmony_cimt76x2_get_power_info_5g(struct mt76x02_dev *dev, 37562306a36Sopenharmony_ci struct mt76x2_tx_power_info *t, 37662306a36Sopenharmony_ci struct ieee80211_channel *chan, 37762306a36Sopenharmony_ci int chain, int offset) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci int channel = chan->hw_value; 38062306a36Sopenharmony_ci enum mt76x2_cal_channel_group group; 38162306a36Sopenharmony_ci int delta_idx; 38262306a36Sopenharmony_ci u16 val; 38362306a36Sopenharmony_ci u8 data[5]; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci group = mt76x2_get_cal_channel_group(channel); 38662306a36Sopenharmony_ci offset += group * MT_TX_POWER_GROUP_SIZE_5G; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (channel >= 192) 38962306a36Sopenharmony_ci delta_idx = 4; 39062306a36Sopenharmony_ci else if (channel >= 184) 39162306a36Sopenharmony_ci delta_idx = 3; 39262306a36Sopenharmony_ci else if (channel < 44) 39362306a36Sopenharmony_ci delta_idx = 3; 39462306a36Sopenharmony_ci else if (channel < 52) 39562306a36Sopenharmony_ci delta_idx = 4; 39662306a36Sopenharmony_ci else if (channel < 58) 39762306a36Sopenharmony_ci delta_idx = 3; 39862306a36Sopenharmony_ci else if (channel < 98) 39962306a36Sopenharmony_ci delta_idx = 4; 40062306a36Sopenharmony_ci else if (channel < 106) 40162306a36Sopenharmony_ci delta_idx = 3; 40262306a36Sopenharmony_ci else if (channel < 116) 40362306a36Sopenharmony_ci delta_idx = 4; 40462306a36Sopenharmony_ci else if (channel < 130) 40562306a36Sopenharmony_ci delta_idx = 3; 40662306a36Sopenharmony_ci else if (channel < 149) 40762306a36Sopenharmony_ci delta_idx = 4; 40862306a36Sopenharmony_ci else if (channel < 157) 40962306a36Sopenharmony_ci delta_idx = 3; 41062306a36Sopenharmony_ci else 41162306a36Sopenharmony_ci delta_idx = 4; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mt76x02_eeprom_copy(dev, offset, data, sizeof(data)); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci t->chain[chain].tssi_slope = data[0]; 41662306a36Sopenharmony_ci t->chain[chain].tssi_offset = data[1]; 41762306a36Sopenharmony_ci t->chain[chain].target_power = data[2]; 41862306a36Sopenharmony_ci t->chain[chain].delta = 41962306a36Sopenharmony_ci mt76x02_sign_extend_optional(data[delta_idx], 7); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN); 42262306a36Sopenharmony_ci t->target_power = val & 0xff; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_civoid mt76x2_get_power_info(struct mt76x02_dev *dev, 42662306a36Sopenharmony_ci struct mt76x2_tx_power_info *t, 42762306a36Sopenharmony_ci struct ieee80211_channel *chan) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci u16 bw40, bw80; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci memset(t, 0, sizeof(*t)); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci bw40 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); 43462306a36Sopenharmony_ci bw80 = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (chan->band == NL80211_BAND_5GHZ) { 43762306a36Sopenharmony_ci bw40 >>= 8; 43862306a36Sopenharmony_ci mt76x2_get_power_info_5g(dev, t, chan, 0, 43962306a36Sopenharmony_ci MT_EE_TX_POWER_0_START_5G); 44062306a36Sopenharmony_ci mt76x2_get_power_info_5g(dev, t, chan, 1, 44162306a36Sopenharmony_ci MT_EE_TX_POWER_1_START_5G); 44262306a36Sopenharmony_ci } else { 44362306a36Sopenharmony_ci mt76x2_get_power_info_2g(dev, t, chan, 0, 44462306a36Sopenharmony_ci MT_EE_TX_POWER_0_START_2G); 44562306a36Sopenharmony_ci mt76x2_get_power_info_2g(dev, t, chan, 1, 44662306a36Sopenharmony_ci MT_EE_TX_POWER_1_START_2G); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (mt76x2_tssi_enabled(dev) || 45062306a36Sopenharmony_ci !mt76x02_field_valid(t->target_power)) 45162306a36Sopenharmony_ci t->target_power = t->chain[0].target_power; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci t->delta_bw40 = mt76x02_rate_power_val(bw40); 45462306a36Sopenharmony_ci t->delta_bw80 = mt76x02_rate_power_val(bw80); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_get_power_info); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ciint mt76x2_get_temp_comp(struct mt76x02_dev *dev, struct mt76x2_temp_comp *t) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci enum nl80211_band band = dev->mphy.chandef.chan->band; 46162306a36Sopenharmony_ci u16 val, slope; 46262306a36Sopenharmony_ci u8 bounds; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci memset(t, 0, sizeof(*t)); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (!mt76x2_temp_tx_alc_enabled(dev)) 46762306a36Sopenharmony_ci return -EINVAL; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (!mt76x02_ext_pa_enabled(dev, band)) 47062306a36Sopenharmony_ci return -EINVAL; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci val = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8; 47362306a36Sopenharmony_ci t->temp_25_ref = val & 0x7f; 47462306a36Sopenharmony_ci if (band == NL80211_BAND_5GHZ) { 47562306a36Sopenharmony_ci slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G); 47662306a36Sopenharmony_ci bounds = mt76x02_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); 47762306a36Sopenharmony_ci } else { 47862306a36Sopenharmony_ci slope = mt76x02_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G); 47962306a36Sopenharmony_ci bounds = mt76x02_eeprom_get(dev, 48062306a36Sopenharmony_ci MT_EE_TX_POWER_DELTA_BW80) >> 8; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci t->high_slope = slope & 0xff; 48462306a36Sopenharmony_ci t->low_slope = slope >> 8; 48562306a36Sopenharmony_ci t->lower_bound = 0 - (bounds & 0xf); 48662306a36Sopenharmony_ci t->upper_bound = (bounds >> 4) & 0xf; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ciint mt76x2_eeprom_init(struct mt76x02_dev *dev) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci int ret; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci ret = mt76x2_eeprom_load(dev); 49762306a36Sopenharmony_ci if (ret) 49862306a36Sopenharmony_ci return ret; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci mt76x02_eeprom_parse_hw_cap(dev); 50162306a36Sopenharmony_ci mt76x2_eeprom_get_macaddr(dev); 50262306a36Sopenharmony_ci mt76_eeprom_override(&dev->mphy); 50362306a36Sopenharmony_ci dev->mphy.macaddr[0] &= ~BIT(1); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x2_eeprom_init); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 510