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_get_efuse_data(struct mt76x02_dev *dev, u16 base, void *buf, 57 int len, enum mt76x02_eeprom_modes mode) 58 { 59 int ret, i; 60 61 for (i = 0; i + 16 <= len; i += 16) { 62 ret = mt76x02_efuse_read(dev, base + i, buf + i, mode); 63 if (ret) 64 return ret; 65 } 66 67 return 0; 68 } 69 EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); 70 71 void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev) 72 { 73 u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 74 75 switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { 76 case BOARD_TYPE_5GHZ: 77 dev->mt76.cap.has_5ghz = true; 78 break; 79 case BOARD_TYPE_2GHZ: 80 dev->mt76.cap.has_2ghz = true; 81 break; 82 default: 83 dev->mt76.cap.has_2ghz = true; 84 dev->mt76.cap.has_5ghz = true; 85 break; 86 } 87 } 88 EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap); 89 90 bool mt76x02_ext_pa_enabled(struct mt76x02_dev *dev, enum nl80211_band band) 91 { 92 u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 93 94 if (band == NL80211_BAND_5GHZ) 95 return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); 96 else 97 return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); 98 } 99 EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); 100 101 void mt76x02_get_rx_gain(struct mt76x02_dev *dev, enum nl80211_band band, 102 u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g) 103 { 104 u16 val; 105 106 val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN); 107 *lna_2g = val & 0xff; 108 lna_5g[0] = val >> 8; 109 110 val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); 111 lna_5g[1] = val >> 8; 112 113 val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); 114 lna_5g[2] = val >> 8; 115 116 if (!mt76x02_field_valid(lna_5g[1])) 117 lna_5g[1] = lna_5g[0]; 118 119 if (!mt76x02_field_valid(lna_5g[2])) 120 lna_5g[2] = lna_5g[0]; 121 122 if (band == NL80211_BAND_2GHZ) 123 *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); 124 else 125 *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); 126 } 127 EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain); 128 129 u8 mt76x02_get_lna_gain(struct mt76x02_dev *dev, 130 s8 *lna_2g, s8 *lna_5g, 131 struct ieee80211_channel *chan) 132 { 133 u16 val; 134 u8 lna; 135 136 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); 137 if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) 138 *lna_2g = 0; 139 if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) 140 memset(lna_5g, 0, sizeof(s8) * 3); 141 142 if (chan->band == NL80211_BAND_2GHZ) 143 lna = *lna_2g; 144 else if (chan->hw_value <= 64) 145 lna = lna_5g[0]; 146 else if (chan->hw_value <= 128) 147 lna = lna_5g[1]; 148 else 149 lna = lna_5g[2]; 150 151 return lna != 0xff ? lna : 0; 152 } 153 EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain); 154