1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 4 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 5 */ 6 7 #include <asm/unaligned.h> 8 9 #include "mt76x02_eeprom.h" 10 11 static int 12 mt76x02_efuse_read(struct mt76x02_dev *dev, u16 addr, u8 *data, 13 enum mt76x02_eeprom_modes mode) 14 { 15 u32 val; 16 int i; 17 18 val = mt76_rr(dev, MT_EFUSE_CTRL); 19 val &= ~(MT_EFUSE_CTRL_AIN | 20 MT_EFUSE_CTRL_MODE); 21 val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); 22 val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode); 23 val |= MT_EFUSE_CTRL_KICK; 24 mt76_wr(dev, MT_EFUSE_CTRL, val); 25 26 if (!mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) 27 return -ETIMEDOUT; 28 29 udelay(2); 30 31 val = mt76_rr(dev, MT_EFUSE_CTRL); 32 if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { 33 memset(data, 0xff, 16); 34 return 0; 35 } 36 37 for (i = 0; i < 4; i++) { 38 val = mt76_rr(dev, MT_EFUSE_DATA(i)); 39 put_unaligned_le32(val, data + 4 * i); 40 } 41 42 return 0; 43 } 44 45 int mt76x02_eeprom_copy(struct mt76x02_dev *dev, 46 enum mt76x02_eeprom_field field, 47 void *dest, int len) 48 { 49 if (field + len > dev->mt76.eeprom.size) 50 return -1; 51 52 memcpy(dest, dev->mt76.eeprom.data + field, len); 53 return 0; 54 } 55 EXPORT_SYMBOL_GPL(mt76x02_eeprom_copy); 56 57 int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf, 58 int len, enum mt76x02_eeprom_modes mode) 59 { 60 int ret, i; 61 62 for (i = 0; i + 16 <= len; i += 16) { 63 ret = mt76x02_efuse_read(dev, base + i, buf + i, mode); 64 if (ret) 65 return ret; 66 } 67 68 return 0; 69 } 70 EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); 71 72 void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev) 73 { 74 u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 75 76 switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { 77 case BOARD_TYPE_5GHZ: 78 dev->mphy.cap.has_5ghz = true; 79 break; 80 case BOARD_TYPE_2GHZ: 81 dev->mphy.cap.has_2ghz = true; 82 break; 83 default: 84 dev->mphy.cap.has_2ghz = true; 85 dev->mphy.cap.has_5ghz = true; 86 break; 87 } 88 } 89 EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap); 90 91 bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band) 92 { 93 u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 94 95 if (band == NL80211_BAND_5GHZ) 96 return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); 97 else 98 return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); 99 } 100 EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); 101 102 void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band, 103 u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g) 104 { 105 u16 val; 106 107 val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN); 108 *lna_2g = val & 0xff; 109 lna_5g[0] = val >> 8; 110 111 val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); 112 lna_5g[1] = val >> 8; 113 114 val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); 115 lna_5g[2] = val >> 8; 116 117 if (!mt76x02_field_valid(lna_5g[1])) 118 lna_5g[1] = lna_5g[0]; 119 120 if (!mt76x02_field_valid(lna_5g[2])) 121 lna_5g[2] = lna_5g[0]; 122 123 if (band == NL80211_BAND_2GHZ) 124 *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); 125 else 126 *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); 127 } 128 EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain); 129 130 u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev, 131 s8 *lna_2g, s8 *lna_5g, 132 struct ieee80211_channel *chan) 133 { 134 u8 lna; 135 136 if (chan->band == NL80211_BAND_2GHZ) 137 lna = *lna_2g; 138 else if (chan->hw_value <= 64) 139 lna = lna_5g[0]; 140 else if (chan->hw_value <= 128) 141 lna = lna_5g[1]; 142 else 143 lna = lna_5g[2]; 144 145 return lna != 0xff ? lna : 0; 146 } 147 EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain); 148