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 "mt76.h" 21 #include "mt76x02_eeprom.h" 22 #include "mt76x02_regs.h" 23 24 static int 25 mt76x02_efuse_read(struct mt76_dev *dev, u16 addr, u8 *data, 26 enum mt76x02_eeprom_modes mode) 27 { 28 u32 val; 29 int i; 30 31 val = __mt76_rr(dev, MT_EFUSE_CTRL); 32 val &= ~(MT_EFUSE_CTRL_AIN | 33 MT_EFUSE_CTRL_MODE); 34 val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); 35 val |= FIELD_PREP(MT_EFUSE_CTRL_MODE, mode); 36 val |= MT_EFUSE_CTRL_KICK; 37 __mt76_wr(dev, MT_EFUSE_CTRL, val); 38 39 if (!__mt76_poll_msec(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 40 0, 1000)) 41 return -ETIMEDOUT; 42 43 udelay(2); 44 45 val = __mt76_rr(dev, MT_EFUSE_CTRL); 46 if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { 47 memset(data, 0xff, 16); 48 return 0; 49 } 50 51 for (i = 0; i < 4; i++) { 52 val = __mt76_rr(dev, MT_EFUSE_DATA(i)); 53 put_unaligned_le32(val, data + 4 * i); 54 } 55 56 return 0; 57 } 58 59 int mt76x02_get_efuse_data(struct mt76_dev *dev, u16 base, void *buf, 60 int len, enum mt76x02_eeprom_modes mode) 61 { 62 int ret, i; 63 64 for (i = 0; i + 16 <= len; i += 16) { 65 ret = mt76x02_efuse_read(dev, base + i, buf + i, mode); 66 if (ret) 67 return ret; 68 } 69 70 return 0; 71 } 72 EXPORT_SYMBOL_GPL(mt76x02_get_efuse_data); 73 74 void mt76x02_eeprom_parse_hw_cap(struct mt76_dev *dev) 75 { 76 u16 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 77 78 switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { 79 case BOARD_TYPE_5GHZ: 80 dev->cap.has_5ghz = true; 81 break; 82 case BOARD_TYPE_2GHZ: 83 dev->cap.has_2ghz = true; 84 break; 85 default: 86 dev->cap.has_2ghz = true; 87 dev->cap.has_5ghz = true; 88 break; 89 } 90 } 91 EXPORT_SYMBOL_GPL(mt76x02_eeprom_parse_hw_cap); 92 93 bool mt76x02_ext_pa_enabled(struct mt76_dev *dev, enum nl80211_band band) 94 { 95 u16 conf0 = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_0); 96 97 if (band == NL80211_BAND_5GHZ) 98 return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); 99 else 100 return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); 101 } 102 EXPORT_SYMBOL_GPL(mt76x02_ext_pa_enabled); 103 104 void mt76x02_get_rx_gain(struct mt76_dev *dev, enum nl80211_band band, 105 u16 *rssi_offset, s8 *lna_2g, s8 *lna_5g) 106 { 107 u16 val; 108 109 val = mt76x02_eeprom_get(dev, MT_EE_LNA_GAIN); 110 *lna_2g = val & 0xff; 111 lna_5g[0] = val >> 8; 112 113 val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); 114 lna_5g[1] = val >> 8; 115 116 val = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); 117 lna_5g[2] = val >> 8; 118 119 if (!mt76x02_field_valid(lna_5g[1])) 120 lna_5g[1] = lna_5g[0]; 121 122 if (!mt76x02_field_valid(lna_5g[2])) 123 lna_5g[2] = lna_5g[0]; 124 125 if (band == NL80211_BAND_2GHZ) 126 *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); 127 else 128 *rssi_offset = mt76x02_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); 129 } 130 EXPORT_SYMBOL_GPL(mt76x02_get_rx_gain); 131 132 u8 mt76x02_get_lna_gain(struct mt76_dev *dev, 133 s8 *lna_2g, s8 *lna_5g, 134 struct ieee80211_channel *chan) 135 { 136 u16 val; 137 u8 lna; 138 139 val = mt76x02_eeprom_get(dev, MT_EE_NIC_CONF_1); 140 if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) 141 *lna_2g = 0; 142 if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) 143 memset(lna_5g, 0, sizeof(s8) * 3); 144 145 if (chan->band == NL80211_BAND_2GHZ) 146 lna = *lna_2g; 147 else if (chan->hw_value <= 64) 148 lna = lna_5g[0]; 149 else if (chan->hw_value <= 128) 150 lna = lna_5g[1]; 151 else 152 lna = lna_5g[2]; 153 154 return lna != 0xff ? lna : 0; 155 } 156 EXPORT_SYMBOL_GPL(mt76x02_get_lna_gain); 157