Commit | Line | Data |
---|---|---|
7bc04215 FF |
1 | /* |
2 | * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include <asm/unaligned.h> | |
18 | #include "mt76x2.h" | |
19 | #include "mt76x2_eeprom.h" | |
20 | ||
21 | #define EE_FIELD(_name, _value) [MT_EE_##_name] = (_value) | 1 | |
22 | ||
23 | static int | |
eef40d20 | 24 | mt76x2_eeprom_copy(struct mt76x2_dev *dev, enum mt76x02_eeprom_field field, |
7bc04215 FF |
25 | void *dest, int len) |
26 | { | |
27 | if (field + len > dev->mt76.eeprom.size) | |
28 | return -1; | |
29 | ||
30 | memcpy(dest, dev->mt76.eeprom.data + field, len); | |
31 | return 0; | |
32 | } | |
33 | ||
34 | static int | |
35 | mt76x2_eeprom_get_macaddr(struct mt76x2_dev *dev) | |
36 | { | |
37 | void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR; | |
38 | ||
39 | memcpy(dev->mt76.macaddr, src, ETH_ALEN); | |
40 | return 0; | |
41 | } | |
42 | ||
d20ad581 | 43 | void mt76x2_eeprom_parse_hw_cap(struct mt76x2_dev *dev) |
7bc04215 FF |
44 | { |
45 | u16 val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0); | |
46 | ||
47 | switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) { | |
48 | case BOARD_TYPE_5GHZ: | |
49 | dev->mt76.cap.has_5ghz = true; | |
50 | break; | |
51 | case BOARD_TYPE_2GHZ: | |
52 | dev->mt76.cap.has_2ghz = true; | |
53 | break; | |
54 | default: | |
55 | dev->mt76.cap.has_2ghz = true; | |
56 | dev->mt76.cap.has_5ghz = true; | |
57 | break; | |
58 | } | |
59 | } | |
d20ad581 | 60 | EXPORT_SYMBOL_GPL(mt76x2_eeprom_parse_hw_cap); |
7bc04215 FF |
61 | |
62 | static int | |
63 | mt76x2_efuse_read(struct mt76x2_dev *dev, u16 addr, u8 *data) | |
64 | { | |
65 | u32 val; | |
66 | int i; | |
67 | ||
68 | val = mt76_rr(dev, MT_EFUSE_CTRL); | |
69 | val &= ~(MT_EFUSE_CTRL_AIN | | |
70 | MT_EFUSE_CTRL_MODE); | |
71 | val |= FIELD_PREP(MT_EFUSE_CTRL_AIN, addr & ~0xf); | |
72 | val |= MT_EFUSE_CTRL_KICK; | |
73 | mt76_wr(dev, MT_EFUSE_CTRL, val); | |
74 | ||
75 | if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) | |
76 | return -ETIMEDOUT; | |
77 | ||
78 | udelay(2); | |
79 | ||
80 | val = mt76_rr(dev, MT_EFUSE_CTRL); | |
81 | if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { | |
82 | memset(data, 0xff, 16); | |
83 | return 0; | |
84 | } | |
85 | ||
86 | for (i = 0; i < 4; i++) { | |
87 | val = mt76_rr(dev, MT_EFUSE_DATA(i)); | |
88 | put_unaligned_le32(val, data + 4 * i); | |
89 | } | |
90 | ||
91 | return 0; | |
92 | } | |
93 | ||
94 | static int | |
95 | mt76x2_get_efuse_data(struct mt76x2_dev *dev, void *buf, int len) | |
96 | { | |
97 | int ret, i; | |
98 | ||
99 | for (i = 0; i + 16 <= len; i += 16) { | |
100 | ret = mt76x2_efuse_read(dev, i, buf + i); | |
101 | if (ret) | |
102 | return ret; | |
103 | } | |
104 | ||
105 | return 0; | |
106 | } | |
107 | ||
108 | static bool | |
109 | mt76x2_has_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) | |
110 | { | |
111 | u16 *efuse_w = (u16 *) efuse; | |
112 | ||
113 | if (efuse_w[MT_EE_NIC_CONF_0] != 0) | |
114 | return false; | |
115 | ||
116 | if (efuse_w[MT_EE_XTAL_TRIM_1] == 0xffff) | |
117 | return false; | |
118 | ||
119 | if (efuse_w[MT_EE_TX_POWER_DELTA_BW40] != 0) | |
120 | return false; | |
121 | ||
122 | if (efuse_w[MT_EE_TX_POWER_0_START_2G] == 0xffff) | |
123 | return false; | |
124 | ||
125 | if (efuse_w[MT_EE_TX_POWER_0_GRP3_TX_POWER_DELTA] != 0) | |
126 | return false; | |
127 | ||
128 | if (efuse_w[MT_EE_TX_POWER_0_GRP4_TSSI_SLOPE] == 0xffff) | |
129 | return false; | |
130 | ||
131 | return true; | |
132 | } | |
133 | ||
134 | static void | |
135 | mt76x2_apply_cal_free_data(struct mt76x2_dev *dev, u8 *efuse) | |
136 | { | |
137 | #define GROUP_5G(_id) \ | |
138 | MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ | |
139 | MT_EE_TX_POWER_0_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1, \ | |
140 | MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id), \ | |
141 | MT_EE_TX_POWER_1_START_5G + MT_TX_POWER_GROUP_SIZE_5G * (_id) + 1 | |
142 | ||
143 | static const u8 cal_free_bytes[] = { | |
144 | MT_EE_XTAL_TRIM_1, | |
145 | MT_EE_TX_POWER_EXT_PA_5G + 1, | |
146 | MT_EE_TX_POWER_0_START_2G, | |
147 | MT_EE_TX_POWER_0_START_2G + 1, | |
148 | MT_EE_TX_POWER_1_START_2G, | |
149 | MT_EE_TX_POWER_1_START_2G + 1, | |
150 | GROUP_5G(0), | |
151 | GROUP_5G(1), | |
152 | GROUP_5G(2), | |
153 | GROUP_5G(3), | |
154 | GROUP_5G(4), | |
155 | GROUP_5G(5), | |
156 | MT_EE_RF_2G_TSSI_OFF_TXPOWER, | |
157 | MT_EE_RF_2G_RX_HIGH_GAIN + 1, | |
158 | MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN, | |
159 | MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN + 1, | |
160 | MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN, | |
161 | MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN + 1, | |
162 | MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN, | |
163 | MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN + 1, | |
164 | }; | |
165 | u8 *eeprom = dev->mt76.eeprom.data; | |
166 | u8 prev_grp0[4] = { | |
167 | eeprom[MT_EE_TX_POWER_0_START_5G], | |
168 | eeprom[MT_EE_TX_POWER_0_START_5G + 1], | |
169 | eeprom[MT_EE_TX_POWER_1_START_5G], | |
170 | eeprom[MT_EE_TX_POWER_1_START_5G + 1] | |
171 | }; | |
172 | u16 val; | |
173 | int i; | |
174 | ||
175 | if (!mt76x2_has_cal_free_data(dev, efuse)) | |
176 | return; | |
177 | ||
178 | for (i = 0; i < ARRAY_SIZE(cal_free_bytes); i++) { | |
179 | int offset = cal_free_bytes[i]; | |
180 | ||
181 | eeprom[offset] = efuse[offset]; | |
182 | } | |
183 | ||
184 | if (!(efuse[MT_EE_TX_POWER_0_START_5G] | | |
185 | efuse[MT_EE_TX_POWER_0_START_5G + 1])) | |
186 | memcpy(eeprom + MT_EE_TX_POWER_0_START_5G, prev_grp0, 2); | |
187 | if (!(efuse[MT_EE_TX_POWER_1_START_5G] | | |
188 | efuse[MT_EE_TX_POWER_1_START_5G + 1])) | |
189 | memcpy(eeprom + MT_EE_TX_POWER_1_START_5G, prev_grp0 + 2, 2); | |
190 | ||
191 | val = get_unaligned_le16(efuse + MT_EE_BT_RCAL_RESULT); | |
192 | if (val != 0xffff) | |
193 | eeprom[MT_EE_BT_RCAL_RESULT] = val & 0xff; | |
194 | ||
195 | val = get_unaligned_le16(efuse + MT_EE_BT_VCDL_CALIBRATION); | |
196 | if (val != 0xffff) | |
197 | eeprom[MT_EE_BT_VCDL_CALIBRATION + 1] = val >> 8; | |
198 | ||
199 | val = get_unaligned_le16(efuse + MT_EE_BT_PMUCFG); | |
200 | if (val != 0xffff) | |
201 | eeprom[MT_EE_BT_PMUCFG] = val & 0xff; | |
202 | } | |
203 | ||
204 | static int mt76x2_check_eeprom(struct mt76x2_dev *dev) | |
205 | { | |
206 | u16 val = get_unaligned_le16(dev->mt76.eeprom.data); | |
207 | ||
208 | if (!val) | |
209 | val = get_unaligned_le16(dev->mt76.eeprom.data + MT_EE_PCI_ID); | |
210 | ||
211 | switch (val) { | |
212 | case 0x7662: | |
213 | case 0x7612: | |
214 | return 0; | |
215 | default: | |
216 | dev_err(dev->mt76.dev, "EEPROM data check failed: %04x\n", val); | |
217 | return -EINVAL; | |
218 | } | |
219 | } | |
220 | ||
221 | static int | |
222 | mt76x2_eeprom_load(struct mt76x2_dev *dev) | |
223 | { | |
224 | void *efuse; | |
7bc04215 FF |
225 | bool found; |
226 | int ret; | |
227 | ||
fbae9c74 | 228 | ret = mt76_eeprom_init(&dev->mt76, MT7662_EEPROM_SIZE); |
7bc04215 FF |
229 | if (ret < 0) |
230 | return ret; | |
231 | ||
232 | found = ret; | |
233 | if (found) | |
234 | found = !mt76x2_check_eeprom(dev); | |
235 | ||
fbae9c74 LB |
236 | dev->mt76.otp.data = devm_kzalloc(dev->mt76.dev, MT7662_EEPROM_SIZE, |
237 | GFP_KERNEL); | |
238 | dev->mt76.otp.size = MT7662_EEPROM_SIZE; | |
7bc04215 FF |
239 | if (!dev->mt76.otp.data) |
240 | return -ENOMEM; | |
241 | ||
242 | efuse = dev->mt76.otp.data; | |
243 | ||
fbae9c74 | 244 | if (mt76x2_get_efuse_data(dev, efuse, MT7662_EEPROM_SIZE)) |
7bc04215 FF |
245 | goto out; |
246 | ||
247 | if (found) { | |
248 | mt76x2_apply_cal_free_data(dev, efuse); | |
249 | } else { | |
250 | /* FIXME: check if efuse data is complete */ | |
251 | found = true; | |
fbae9c74 | 252 | memcpy(dev->mt76.eeprom.data, efuse, MT7662_EEPROM_SIZE); |
7bc04215 FF |
253 | } |
254 | ||
255 | out: | |
256 | if (!found) | |
257 | return -ENOENT; | |
258 | ||
259 | return 0; | |
260 | } | |
261 | ||
7bc04215 FF |
262 | static inline int |
263 | mt76x2_sign_extend_optional(u32 val, unsigned int size) | |
264 | { | |
265 | bool enable = val & BIT(size); | |
266 | ||
86c71d3d | 267 | return enable ? mt76x02_sign_extend(val, size) : 0; |
7bc04215 FF |
268 | } |
269 | ||
270 | static void | |
271 | mt76x2_set_rx_gain_group(struct mt76x2_dev *dev, u8 val) | |
272 | { | |
273 | s8 *dest = dev->cal.rx.high_gain; | |
274 | ||
86c71d3d | 275 | if (!mt76x02_field_valid(val)) { |
7bc04215 FF |
276 | dest[0] = 0; |
277 | dest[1] = 0; | |
278 | return; | |
279 | } | |
280 | ||
86c71d3d LB |
281 | dest[0] = mt76x02_sign_extend(val, 4); |
282 | dest[1] = mt76x02_sign_extend(val >> 4, 4); | |
7bc04215 FF |
283 | } |
284 | ||
285 | static void | |
286 | mt76x2_set_rssi_offset(struct mt76x2_dev *dev, int chain, u8 val) | |
287 | { | |
288 | s8 *dest = dev->cal.rx.rssi_offset; | |
289 | ||
86c71d3d | 290 | if (!mt76x02_field_valid(val)) { |
7bc04215 FF |
291 | dest[chain] = 0; |
292 | return; | |
293 | } | |
294 | ||
295 | dest[chain] = mt76x2_sign_extend_optional(val, 7); | |
296 | } | |
297 | ||
298 | static enum mt76x2_cal_channel_group | |
299 | mt76x2_get_cal_channel_group(int channel) | |
300 | { | |
301 | if (channel >= 184 && channel <= 196) | |
302 | return MT_CH_5G_JAPAN; | |
303 | if (channel <= 48) | |
304 | return MT_CH_5G_UNII_1; | |
305 | if (channel <= 64) | |
306 | return MT_CH_5G_UNII_2; | |
307 | if (channel <= 114) | |
308 | return MT_CH_5G_UNII_2E_1; | |
309 | if (channel <= 144) | |
310 | return MT_CH_5G_UNII_2E_2; | |
311 | return MT_CH_5G_UNII_3; | |
312 | } | |
313 | ||
314 | static u8 | |
315 | mt76x2_get_5g_rx_gain(struct mt76x2_dev *dev, u8 channel) | |
316 | { | |
317 | enum mt76x2_cal_channel_group group; | |
318 | ||
319 | group = mt76x2_get_cal_channel_group(channel); | |
320 | switch (group) { | |
321 | case MT_CH_5G_JAPAN: | |
322 | return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN); | |
323 | case MT_CH_5G_UNII_1: | |
324 | return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP0_1_RX_HIGH_GAIN) >> 8; | |
325 | case MT_CH_5G_UNII_2: | |
326 | return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN); | |
327 | case MT_CH_5G_UNII_2E_1: | |
328 | return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP2_3_RX_HIGH_GAIN) >> 8; | |
329 | case MT_CH_5G_UNII_2E_2: | |
330 | return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN); | |
331 | default: | |
332 | return mt76x2_eeprom_get(dev, MT_EE_RF_5G_GRP4_5_RX_HIGH_GAIN) >> 8; | |
333 | } | |
334 | } | |
335 | ||
336 | void mt76x2_read_rx_gain(struct mt76x2_dev *dev) | |
337 | { | |
338 | struct ieee80211_channel *chan = dev->mt76.chandef.chan; | |
339 | int channel = chan->hw_value; | |
340 | s8 lna_5g[3], lna_2g; | |
341 | u8 lna; | |
342 | u16 val; | |
343 | ||
344 | if (chan->band == NL80211_BAND_2GHZ) | |
345 | val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN) >> 8; | |
346 | else | |
347 | val = mt76x2_get_5g_rx_gain(dev, channel); | |
348 | ||
349 | mt76x2_set_rx_gain_group(dev, val); | |
350 | ||
351 | if (chan->band == NL80211_BAND_2GHZ) { | |
352 | val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_0); | |
353 | mt76x2_set_rssi_offset(dev, 0, val); | |
354 | mt76x2_set_rssi_offset(dev, 1, val >> 8); | |
355 | } else { | |
356 | val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_0); | |
357 | mt76x2_set_rssi_offset(dev, 0, val); | |
358 | mt76x2_set_rssi_offset(dev, 1, val >> 8); | |
359 | } | |
360 | ||
361 | val = mt76x2_eeprom_get(dev, MT_EE_LNA_GAIN); | |
362 | lna_2g = val & 0xff; | |
363 | lna_5g[0] = val >> 8; | |
364 | ||
365 | val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_2G_1); | |
366 | lna_5g[1] = val >> 8; | |
367 | ||
368 | val = mt76x2_eeprom_get(dev, MT_EE_RSSI_OFFSET_5G_1); | |
369 | lna_5g[2] = val >> 8; | |
370 | ||
86c71d3d | 371 | if (!mt76x02_field_valid(lna_5g[1])) |
7bc04215 FF |
372 | lna_5g[1] = lna_5g[0]; |
373 | ||
86c71d3d | 374 | if (!mt76x02_field_valid(lna_5g[2])) |
7bc04215 FF |
375 | lna_5g[2] = lna_5g[0]; |
376 | ||
377 | dev->cal.rx.mcu_gain = (lna_2g & 0xff); | |
378 | dev->cal.rx.mcu_gain |= (lna_5g[0] & 0xff) << 8; | |
379 | dev->cal.rx.mcu_gain |= (lna_5g[1] & 0xff) << 16; | |
380 | dev->cal.rx.mcu_gain |= (lna_5g[2] & 0xff) << 24; | |
381 | ||
382 | val = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_1); | |
383 | if (val & MT_EE_NIC_CONF_1_LNA_EXT_2G) | |
384 | lna_2g = 0; | |
385 | if (val & MT_EE_NIC_CONF_1_LNA_EXT_5G) | |
386 | memset(lna_5g, 0, sizeof(lna_5g)); | |
387 | ||
388 | if (chan->band == NL80211_BAND_2GHZ) | |
389 | lna = lna_2g; | |
390 | else if (channel <= 64) | |
391 | lna = lna_5g[0]; | |
392 | else if (channel <= 128) | |
393 | lna = lna_5g[1]; | |
394 | else | |
395 | lna = lna_5g[2]; | |
396 | ||
397 | if (lna == 0xff) | |
398 | lna = 0; | |
399 | ||
86c71d3d | 400 | dev->cal.rx.lna_gain = mt76x02_sign_extend(lna, 8); |
7bc04215 | 401 | } |
d20ad581 | 402 | EXPORT_SYMBOL_GPL(mt76x2_read_rx_gain); |
7bc04215 FF |
403 | |
404 | static s8 | |
405 | mt76x2_rate_power_val(u8 val) | |
406 | { | |
86c71d3d | 407 | if (!mt76x02_field_valid(val)) |
7bc04215 FF |
408 | return 0; |
409 | ||
410 | return mt76x2_sign_extend_optional(val, 7); | |
411 | } | |
412 | ||
60e2434c FF |
413 | void mt76x2_get_rate_power(struct mt76x2_dev *dev, struct mt76_rate_power *t, |
414 | struct ieee80211_channel *chan) | |
7bc04215 FF |
415 | { |
416 | bool is_5ghz; | |
417 | u16 val; | |
418 | ||
60e2434c | 419 | is_5ghz = chan->band == NL80211_BAND_5GHZ; |
7bc04215 FF |
420 | |
421 | memset(t, 0, sizeof(*t)); | |
422 | ||
423 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_CCK); | |
424 | t->cck[0] = t->cck[1] = mt76x2_rate_power_val(val); | |
425 | t->cck[2] = t->cck[3] = mt76x2_rate_power_val(val >> 8); | |
426 | ||
427 | if (is_5ghz) | |
428 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_6M); | |
429 | else | |
430 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_6M); | |
431 | t->ofdm[0] = t->ofdm[1] = mt76x2_rate_power_val(val); | |
432 | t->ofdm[2] = t->ofdm[3] = mt76x2_rate_power_val(val >> 8); | |
433 | ||
434 | if (is_5ghz) | |
435 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_5G_24M); | |
436 | else | |
437 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_OFDM_2G_24M); | |
438 | t->ofdm[4] = t->ofdm[5] = mt76x2_rate_power_val(val); | |
439 | t->ofdm[6] = t->ofdm[7] = mt76x2_rate_power_val(val >> 8); | |
440 | ||
441 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS0); | |
442 | t->ht[0] = t->ht[1] = mt76x2_rate_power_val(val); | |
443 | t->ht[2] = t->ht[3] = mt76x2_rate_power_val(val >> 8); | |
444 | ||
445 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS4); | |
446 | t->ht[4] = t->ht[5] = mt76x2_rate_power_val(val); | |
447 | t->ht[6] = t->ht[7] = mt76x2_rate_power_val(val >> 8); | |
448 | ||
449 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS8); | |
450 | t->ht[8] = t->ht[9] = mt76x2_rate_power_val(val); | |
451 | t->ht[10] = t->ht[11] = mt76x2_rate_power_val(val >> 8); | |
452 | ||
453 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_HT_MCS12); | |
454 | t->ht[12] = t->ht[13] = mt76x2_rate_power_val(val); | |
455 | t->ht[14] = t->ht[15] = mt76x2_rate_power_val(val >> 8); | |
456 | ||
457 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS0); | |
458 | t->vht[0] = t->vht[1] = mt76x2_rate_power_val(val); | |
459 | t->vht[2] = t->vht[3] = mt76x2_rate_power_val(val >> 8); | |
460 | ||
461 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS4); | |
462 | t->vht[4] = t->vht[5] = mt76x2_rate_power_val(val); | |
463 | t->vht[6] = t->vht[7] = mt76x2_rate_power_val(val >> 8); | |
464 | ||
465 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_VHT_MCS8); | |
466 | if (!is_5ghz) | |
467 | val >>= 8; | |
468 | t->vht[8] = t->vht[9] = mt76x2_rate_power_val(val >> 8); | |
7c4b446c FF |
469 | |
470 | memcpy(t->stbc, t->ht, sizeof(t->stbc[0]) * 8); | |
471 | t->stbc[8] = t->vht[8]; | |
472 | t->stbc[9] = t->vht[9]; | |
7bc04215 | 473 | } |
d20ad581 | 474 | EXPORT_SYMBOL_GPL(mt76x2_get_rate_power); |
7bc04215 | 475 | |
984ea503 FF |
476 | int mt76x2_get_max_rate_power(struct mt76_rate_power *r) |
477 | { | |
478 | int i; | |
479 | s8 ret = 0; | |
480 | ||
481 | for (i = 0; i < sizeof(r->all); i++) | |
482 | ret = max(ret, r->all[i]); | |
483 | ||
484 | return ret; | |
485 | } | |
d20ad581 | 486 | EXPORT_SYMBOL_GPL(mt76x2_get_max_rate_power); |
984ea503 | 487 | |
7bc04215 FF |
488 | static void |
489 | mt76x2_get_power_info_2g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, | |
60e2434c | 490 | struct ieee80211_channel *chan, int chain, int offset) |
7bc04215 | 491 | { |
60e2434c | 492 | int channel = chan->hw_value; |
7bc04215 FF |
493 | int delta_idx; |
494 | u8 data[6]; | |
495 | u16 val; | |
496 | ||
497 | if (channel < 6) | |
498 | delta_idx = 3; | |
499 | else if (channel < 11) | |
500 | delta_idx = 4; | |
501 | else | |
502 | delta_idx = 5; | |
503 | ||
504 | mt76x2_eeprom_copy(dev, offset, data, sizeof(data)); | |
505 | ||
506 | t->chain[chain].tssi_slope = data[0]; | |
507 | t->chain[chain].tssi_offset = data[1]; | |
508 | t->chain[chain].target_power = data[2]; | |
509 | t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); | |
510 | ||
511 | val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER); | |
512 | t->target_power = val >> 8; | |
513 | } | |
514 | ||
515 | static void | |
516 | mt76x2_get_power_info_5g(struct mt76x2_dev *dev, struct mt76x2_tx_power_info *t, | |
60e2434c | 517 | struct ieee80211_channel *chan, int chain, int offset) |
7bc04215 | 518 | { |
60e2434c | 519 | int channel = chan->hw_value; |
7bc04215 FF |
520 | enum mt76x2_cal_channel_group group; |
521 | int delta_idx; | |
522 | u16 val; | |
523 | u8 data[5]; | |
524 | ||
525 | group = mt76x2_get_cal_channel_group(channel); | |
526 | offset += group * MT_TX_POWER_GROUP_SIZE_5G; | |
527 | ||
528 | if (channel >= 192) | |
529 | delta_idx = 4; | |
c3929a98 | 530 | else if (channel >= 184) |
7bc04215 FF |
531 | delta_idx = 3; |
532 | else if (channel < 44) | |
533 | delta_idx = 3; | |
534 | else if (channel < 52) | |
535 | delta_idx = 4; | |
536 | else if (channel < 58) | |
537 | delta_idx = 3; | |
538 | else if (channel < 98) | |
539 | delta_idx = 4; | |
540 | else if (channel < 106) | |
541 | delta_idx = 3; | |
542 | else if (channel < 116) | |
543 | delta_idx = 4; | |
544 | else if (channel < 130) | |
545 | delta_idx = 3; | |
546 | else if (channel < 149) | |
547 | delta_idx = 4; | |
548 | else if (channel < 157) | |
549 | delta_idx = 3; | |
550 | else | |
551 | delta_idx = 4; | |
552 | ||
553 | mt76x2_eeprom_copy(dev, offset, data, sizeof(data)); | |
554 | ||
555 | t->chain[chain].tssi_slope = data[0]; | |
556 | t->chain[chain].tssi_offset = data[1]; | |
557 | t->chain[chain].target_power = data[2]; | |
558 | t->chain[chain].delta = mt76x2_sign_extend_optional(data[delta_idx], 7); | |
559 | ||
560 | val = mt76x2_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN); | |
561 | t->target_power = val & 0xff; | |
562 | } | |
563 | ||
564 | void mt76x2_get_power_info(struct mt76x2_dev *dev, | |
60e2434c FF |
565 | struct mt76x2_tx_power_info *t, |
566 | struct ieee80211_channel *chan) | |
7bc04215 FF |
567 | { |
568 | u16 bw40, bw80; | |
569 | ||
570 | memset(t, 0, sizeof(*t)); | |
571 | ||
572 | bw40 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW40); | |
573 | bw80 = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80); | |
574 | ||
60e2434c | 575 | if (chan->band == NL80211_BAND_5GHZ) { |
7bc04215 | 576 | bw40 >>= 8; |
60e2434c FF |
577 | mt76x2_get_power_info_5g(dev, t, chan, 0, |
578 | MT_EE_TX_POWER_0_START_5G); | |
579 | mt76x2_get_power_info_5g(dev, t, chan, 1, | |
580 | MT_EE_TX_POWER_1_START_5G); | |
7bc04215 | 581 | } else { |
60e2434c FF |
582 | mt76x2_get_power_info_2g(dev, t, chan, 0, |
583 | MT_EE_TX_POWER_0_START_2G); | |
584 | mt76x2_get_power_info_2g(dev, t, chan, 1, | |
585 | MT_EE_TX_POWER_1_START_2G); | |
7bc04215 FF |
586 | } |
587 | ||
86c71d3d LB |
588 | if (mt76x2_tssi_enabled(dev) || |
589 | !mt76x02_field_valid(t->target_power)) | |
7bc04215 FF |
590 | t->target_power = t->chain[0].target_power; |
591 | ||
592 | t->delta_bw40 = mt76x2_rate_power_val(bw40); | |
593 | t->delta_bw80 = mt76x2_rate_power_val(bw80); | |
594 | } | |
d20ad581 | 595 | EXPORT_SYMBOL_GPL(mt76x2_get_power_info); |
7bc04215 FF |
596 | |
597 | int mt76x2_get_temp_comp(struct mt76x2_dev *dev, struct mt76x2_temp_comp *t) | |
598 | { | |
599 | enum nl80211_band band = dev->mt76.chandef.chan->band; | |
600 | u16 val, slope; | |
601 | u8 bounds; | |
602 | ||
603 | memset(t, 0, sizeof(*t)); | |
604 | ||
bcb0f68a | 605 | if (!mt76x2_temp_tx_alc_enabled(dev)) |
7bc04215 FF |
606 | return -EINVAL; |
607 | ||
608 | if (!mt76x2_ext_pa_enabled(dev, band)) | |
609 | return -EINVAL; | |
610 | ||
611 | val = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G) >> 8; | |
7bc04215 FF |
612 | t->temp_25_ref = val & 0x7f; |
613 | if (band == NL80211_BAND_5GHZ) { | |
614 | slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_5G); | |
615 | bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_EXT_PA_5G); | |
616 | } else { | |
617 | slope = mt76x2_eeprom_get(dev, MT_EE_RF_TEMP_COMP_SLOPE_2G); | |
618 | bounds = mt76x2_eeprom_get(dev, MT_EE_TX_POWER_DELTA_BW80) >> 8; | |
619 | } | |
620 | ||
621 | t->high_slope = slope & 0xff; | |
622 | t->low_slope = slope >> 8; | |
623 | t->lower_bound = 0 - (bounds & 0xf); | |
624 | t->upper_bound = (bounds >> 4) & 0xf; | |
625 | ||
626 | return 0; | |
627 | } | |
d20ad581 | 628 | EXPORT_SYMBOL_GPL(mt76x2_get_temp_comp); |
7bc04215 FF |
629 | |
630 | bool mt76x2_ext_pa_enabled(struct mt76x2_dev *dev, enum nl80211_band band) | |
631 | { | |
632 | u16 conf0 = mt76x2_eeprom_get(dev, MT_EE_NIC_CONF_0); | |
633 | ||
634 | if (band == NL80211_BAND_5GHZ) | |
635 | return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_5G); | |
636 | else | |
637 | return !(conf0 & MT_EE_NIC_CONF_0_PA_INT_2G); | |
638 | } | |
d20ad581 | 639 | EXPORT_SYMBOL_GPL(mt76x2_ext_pa_enabled); |
7bc04215 FF |
640 | |
641 | int mt76x2_eeprom_init(struct mt76x2_dev *dev) | |
642 | { | |
643 | int ret; | |
644 | ||
645 | ret = mt76x2_eeprom_load(dev); | |
646 | if (ret) | |
647 | return ret; | |
648 | ||
649 | mt76x2_eeprom_parse_hw_cap(dev); | |
650 | mt76x2_eeprom_get_macaddr(dev); | |
651 | mt76_eeprom_override(&dev->mt76); | |
652 | dev->mt76.macaddr[0] &= ~BIT(1); | |
653 | ||
654 | return 0; | |
655 | } | |
d20ad581 LB |
656 | EXPORT_SYMBOL_GPL(mt76x2_eeprom_init); |
657 | ||
658 | MODULE_LICENSE("Dual BSD/GPL"); |