1 /* 2 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 3 * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <asm/unaligned.h> 19 20 #include "mt76x02_eeprom.h" 21 22 static int 23 mt76x02_efuse_read(struct mt76x02_dev *dev, u16 addr, u8 *data, 24 enum mt76x02_eeprom_modes mode) 25 { 26 u32 val; 27 int i; 28 29 val = mt76_rr(dev, MT_EFUSE_CTRL); 30 val &= ~(MT_EFUSE_CTRL_AIN | 31 MT_EFUSE_CTRL_MODE); 32 val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); 33 val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode); 34 val |= MT_EFUSE_CTRL_KICK; 35 mt76_wr(dev, MT_EFUSE_CTRL, val); 36 37 if (!mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) 38 return -ETIMEDOUT; 39 40 udelay(2); 41 42 val = mt76_rr(dev, MT_EFUSE_CTRL); 43 if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { 44 memset(data, 0xff, 16); 45 return 0; 46 } 47 48 for (i = 0; i < 4; i++) { 49 val = mt76_rr(dev, MT_EFUSE_DATA(i)); 50 put_unaligned_le32(val, data + 4 * i); 51 } 52 53 return 0; 54 } 55 56 int mt76x02_eeprom_copy(struct mt76x02_dev *dev, 57 enum mt76x02_eeprom_field field, 58 void *dest, int len) 59 { 60 if (field + len > dev->mt76.eeprom.size) 61 return -1; 62 63 memcpy(dest, dev->mt76.eeprom.data + field, len); 64 return 0; 65 } 66 EXPORT_SYMBOL_GPL(mt76x02_eeprom_copy); 67 68 int mt76x02_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf, 69 int len, enum mt76x02_eeprom_modes mode) 70 { 71 int ret, i; 72 73 for (i = 0; i + 16 <= len; i += 16) { 74 ret = mt76x02_efuse_read(dev, base + i, buf + i, mode); 75 if (ret) 76 return ret; 77 } 78 79 return 0; 80 } 81 EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); 82 83 void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev) 84 { 85 u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 86 87 switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { 88 case BOARD_TYPE_5GHZ: 89 dev->mt76.cap.has_5ghz = true; 90 break; 91 case BOARD_TYPE_2GHZ: 92 dev->mt76.cap.has_2ghz = true; 93 break; 94 default: 95 dev->mt76.cap.has_2ghz = true; 96 dev->mt76.cap.has_5ghz = true; 97 break; 98 } 99 } 100 EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap); 101 102 bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band) 103 { 104 u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 105 106 if (band == NL80211_BAND_5GHZ) 107 return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); 108 else 109 return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); 110 } 111 EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); 112 113 void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band, 114 u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g) 115 { 116 u16 val; 117 118 val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN); 119 *lna_2g = val & 0xff; 120 lna_5g[0] = val >> 8; 121 122 val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); 123 lna_5g[1] = val >> 8; 124 125 val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); 126 lna_5g[2] = val >> 8; 127 128 if (!mt76x02_field_valid(lna_5g[1])) 129 lna_5g[1] = lna_5g[0]; 130 131 if (!mt76x02_field_valid(lna_5g[2])) 132 lna_5g[2] = lna_5g[0]; 133 134 if (band == NL80211_BAND_2GHZ) 135 *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); 136 else 137 *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); 138 } 139 EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain); 140 141 u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev, 142 s8 *lna_2g, s8 *lna_5g, 143 struct ieee80211_channel *chan) 144 { 145 u16 val; 146 u8 lna; 147 148 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); 149 if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) 150 *lna_2g = 0; 151 if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) 152 memset(lna_5g, 0, sizeof(s8) * 3); 153 154 if (chan->band == NL80211_BAND_2GHZ) 155 lna = *lna_2g; 156 else if (chan->hw_value <= 64) 157 lna = lna_5g[0]; 158 else if (chan->hw_value <= 128) 159 lna = lna_5g[1]; 160 else 161 lna = lna_5g[2]; 162 163 return lna != 0xff ? lna : 0; 164 } 165 EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain); 166