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, p: 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, addr: base + i, data: 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, field: 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, field: 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 *, s8 *lna_2g, s8 *lna_5g) |
104 | { |
105 | u16 val; |
106 | |
107 | val = mt76x02_eeprom_get(dev, field: MT_EE_LNA_GAIN); |
108 | *lna_2g = val & 0xff; |
109 | lna_5g[0] = val >> 8; |
110 | |
111 | val = mt76x02_eeprom_get(dev, field: MT_EE_RSSI_OFFSET_2G_1); |
112 | lna_5g[1] = val >> 8; |
113 | |
114 | val = mt76x02_eeprom_get(dev, field: MT_EE_RSSI_OFFSET_5G_1); |
115 | lna_5g[2] = val >> 8; |
116 | |
117 | if (!mt76x02_field_valid(val: lna_5g[1])) |
118 | lna_5g[1] = lna_5g[0]; |
119 | |
120 | if (!mt76x02_field_valid(val: lna_5g[2])) |
121 | lna_5g[2] = lna_5g[0]; |
122 | |
123 | if (band == NL80211_BAND_2GHZ) |
124 | *rssi_offset = mt76x02_eeprom_get(dev, field: MT_EE_RSSI_OFFSET_2G_0); |
125 | else |
126 | *rssi_offset = mt76x02_eeprom_get(dev, field: 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 | |