1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * (c) Copyright 2002-2010, Ralink Technology, Inc. |
4 | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
5 | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
6 | */ |
7 | |
8 | #include "mt7601u.h" |
9 | #include "mcu.h" |
10 | #include "eeprom.h" |
11 | #include "trace.h" |
12 | #include "initvals_phy.h" |
13 | |
14 | #include <linux/etherdevice.h> |
15 | |
16 | static void mt7601u_agc_reset(struct mt7601u_dev *dev); |
17 | |
18 | static int |
19 | mt7601u_rf_wr(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 value) |
20 | { |
21 | int ret = 0; |
22 | |
23 | if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || |
24 | WARN_ON(offset > 63)) |
25 | return -EINVAL; |
26 | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
27 | return 0; |
28 | |
29 | mutex_lock(&dev->reg_atomic_mutex); |
30 | |
31 | if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, val: 0, timeout: 100)) { |
32 | ret = -ETIMEDOUT; |
33 | goto out; |
34 | } |
35 | |
36 | mt7601u_wr(dev, MT_RF_CSR_CFG, |
37 | FIELD_PREP(MT_RF_CSR_CFG_DATA, value) | |
38 | FIELD_PREP(MT_RF_CSR_CFG_REG_BANK, bank) | |
39 | FIELD_PREP(MT_RF_CSR_CFG_REG_ID, offset) | |
40 | MT_RF_CSR_CFG_WR | |
41 | MT_RF_CSR_CFG_KICK); |
42 | trace_rf_write(dev, bank, reg: offset, val: value); |
43 | out: |
44 | mutex_unlock(lock: &dev->reg_atomic_mutex); |
45 | |
46 | if (ret < 0) |
47 | dev_err(dev->dev, "Error: RF write %02hhx:%02hhx failed:%d!!\n" , |
48 | bank, offset, ret); |
49 | |
50 | return ret; |
51 | } |
52 | |
53 | static int |
54 | mt7601u_rf_rr(struct mt7601u_dev *dev, u8 bank, u8 offset) |
55 | { |
56 | int ret = -ETIMEDOUT; |
57 | u32 val; |
58 | |
59 | if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || |
60 | WARN_ON(offset > 63)) |
61 | return -EINVAL; |
62 | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
63 | return 0xff; |
64 | |
65 | mutex_lock(&dev->reg_atomic_mutex); |
66 | |
67 | if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, val: 0, timeout: 100)) |
68 | goto out; |
69 | |
70 | mt7601u_wr(dev, MT_RF_CSR_CFG, |
71 | FIELD_PREP(MT_RF_CSR_CFG_REG_BANK, bank) | |
72 | FIELD_PREP(MT_RF_CSR_CFG_REG_ID, offset) | |
73 | MT_RF_CSR_CFG_KICK); |
74 | |
75 | if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, val: 0, timeout: 100)) |
76 | goto out; |
77 | |
78 | val = mt7601u_rr(dev, MT_RF_CSR_CFG); |
79 | if (FIELD_GET(MT_RF_CSR_CFG_REG_ID, val) == offset && |
80 | FIELD_GET(MT_RF_CSR_CFG_REG_BANK, val) == bank) { |
81 | ret = FIELD_GET(MT_RF_CSR_CFG_DATA, val); |
82 | trace_rf_read(dev, bank, reg: offset, val: ret); |
83 | } |
84 | out: |
85 | mutex_unlock(lock: &dev->reg_atomic_mutex); |
86 | |
87 | if (ret < 0) |
88 | dev_err(dev->dev, "Error: RF read %02hhx:%02hhx failed:%d!!\n" , |
89 | bank, offset, ret); |
90 | |
91 | return ret; |
92 | } |
93 | |
94 | static int |
95 | mt7601u_rf_rmw(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask, u8 val) |
96 | { |
97 | int ret; |
98 | |
99 | ret = mt7601u_rf_rr(dev, bank, offset); |
100 | if (ret < 0) |
101 | return ret; |
102 | val |= ret & ~mask; |
103 | ret = mt7601u_rf_wr(dev, bank, offset, value: val); |
104 | if (ret) |
105 | return ret; |
106 | |
107 | return val; |
108 | } |
109 | |
110 | static int |
111 | mt7601u_rf_set(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 val) |
112 | { |
113 | return mt7601u_rf_rmw(dev, bank, offset, mask: 0, val); |
114 | } |
115 | |
116 | static int |
117 | mt7601u_rf_clear(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask) |
118 | { |
119 | return mt7601u_rf_rmw(dev, bank, offset, mask, val: 0); |
120 | } |
121 | |
122 | static void mt7601u_bbp_wr(struct mt7601u_dev *dev, u8 offset, u8 val) |
123 | { |
124 | if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || |
125 | test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
126 | return; |
127 | |
128 | mutex_lock(&dev->reg_atomic_mutex); |
129 | |
130 | if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, val: 0, timeout: 1000)) { |
131 | dev_err(dev->dev, "Error: BBP write %02hhx failed!!\n" , offset); |
132 | goto out; |
133 | } |
134 | |
135 | mt7601u_wr(dev, MT_BBP_CSR_CFG, |
136 | FIELD_PREP(MT_BBP_CSR_CFG_VAL, val) | |
137 | FIELD_PREP(MT_BBP_CSR_CFG_REG_NUM, offset) | |
138 | MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY); |
139 | trace_bbp_write(dev, reg: offset, val); |
140 | out: |
141 | mutex_unlock(lock: &dev->reg_atomic_mutex); |
142 | } |
143 | |
144 | static int mt7601u_bbp_rr(struct mt7601u_dev *dev, u8 offset) |
145 | { |
146 | u32 val; |
147 | int ret = -ETIMEDOUT; |
148 | |
149 | if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state))) |
150 | return -EINVAL; |
151 | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
152 | return 0xff; |
153 | |
154 | mutex_lock(&dev->reg_atomic_mutex); |
155 | |
156 | if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, val: 0, timeout: 1000)) |
157 | goto out; |
158 | |
159 | mt7601u_wr(dev, MT_BBP_CSR_CFG, |
160 | FIELD_PREP(MT_BBP_CSR_CFG_REG_NUM, offset) | |
161 | MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY | |
162 | MT_BBP_CSR_CFG_READ); |
163 | |
164 | if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, val: 0, timeout: 1000)) |
165 | goto out; |
166 | |
167 | val = mt7601u_rr(dev, MT_BBP_CSR_CFG); |
168 | if (FIELD_GET(MT_BBP_CSR_CFG_REG_NUM, val) == offset) { |
169 | ret = FIELD_GET(MT_BBP_CSR_CFG_VAL, val); |
170 | trace_bbp_read(dev, reg: offset, val: ret); |
171 | } |
172 | out: |
173 | mutex_unlock(lock: &dev->reg_atomic_mutex); |
174 | |
175 | if (ret < 0) |
176 | dev_err(dev->dev, "Error: BBP read %02hhx failed:%d!!\n" , |
177 | offset, ret); |
178 | |
179 | return ret; |
180 | } |
181 | |
182 | static int mt7601u_bbp_rmw(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val) |
183 | { |
184 | int ret; |
185 | |
186 | ret = mt7601u_bbp_rr(dev, offset); |
187 | if (ret < 0) |
188 | return ret; |
189 | val |= ret & ~mask; |
190 | mt7601u_bbp_wr(dev, offset, val); |
191 | |
192 | return val; |
193 | } |
194 | |
195 | static u8 mt7601u_bbp_rmc(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val) |
196 | { |
197 | int ret; |
198 | |
199 | ret = mt7601u_bbp_rr(dev, offset); |
200 | if (ret < 0) |
201 | return ret; |
202 | val |= ret & ~mask; |
203 | if (ret != val) |
204 | mt7601u_bbp_wr(dev, offset, val); |
205 | |
206 | return val; |
207 | } |
208 | |
209 | int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) |
210 | { |
211 | int i = 20; |
212 | u8 val; |
213 | |
214 | do { |
215 | val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); |
216 | if (val && val != 0xff) |
217 | break; |
218 | } while (--i); |
219 | |
220 | if (!i) { |
221 | dev_err(dev->dev, "Error: BBP is not ready\n" ); |
222 | return -EIO; |
223 | } |
224 | |
225 | return 0; |
226 | } |
227 | |
228 | u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below) |
229 | { |
230 | return mt7601u_bbp_rmc(dev, offset: 3, mask: 0x20, val: below ? 0x20 : 0); |
231 | } |
232 | |
233 | int (struct mt7601u_dev *dev, |
234 | struct mt7601u_rxwi *rxwi, u16 rate) |
235 | { |
236 | static const s8 lna[2][2][3] = { |
237 | /* main LNA */ { |
238 | /* bw20 */ { -2, 15, 33 }, |
239 | /* bw40 */ { 0, 16, 34 } |
240 | }, |
241 | /* aux LNA */ { |
242 | /* bw20 */ { -2, 15, 33 }, |
243 | /* bw40 */ { -2, 16, 34 } |
244 | } |
245 | }; |
246 | int bw = FIELD_GET(MT_RXWI_RATE_BW, rate); |
247 | int aux_lna = FIELD_GET(MT_RXWI_ANT_AUX_LNA, rxwi->ant); |
248 | int lna_id = FIELD_GET(MT_RXWI_GAIN_RSSI_LNA_ID, rxwi->gain); |
249 | int val; |
250 | |
251 | if (lna_id) /* LNA id can be 0, 2, 3. */ |
252 | lna_id--; |
253 | |
254 | val = 8; |
255 | val -= lna[aux_lna][bw][lna_id]; |
256 | val -= FIELD_GET(MT_RXWI_GAIN_RSSI_VAL, rxwi->gain); |
257 | val -= dev->ee->lna_gain; |
258 | val -= dev->ee->rssi_offset[0]; |
259 | |
260 | return val; |
261 | } |
262 | |
263 | static void mt7601u_vco_cal(struct mt7601u_dev *dev) |
264 | { |
265 | mt7601u_rf_wr(dev, bank: 0, offset: 4, value: 0x0a); |
266 | mt7601u_rf_wr(dev, bank: 0, offset: 5, value: 0x20); |
267 | mt7601u_rf_set(dev, bank: 0, offset: 4, BIT(7)); |
268 | msleep(msecs: 2); |
269 | } |
270 | |
271 | static int mt7601u_set_bw_filter(struct mt7601u_dev *dev, bool cal) |
272 | { |
273 | u32 filter = 0; |
274 | int ret; |
275 | |
276 | if (!cal) |
277 | filter |= 0x10000; |
278 | if (dev->bw != MT_BW_20) |
279 | filter |= 0x00100; |
280 | |
281 | /* TX */ |
282 | ret = mt7601u_mcu_calibrate(dev, cal: MCU_CAL_BW, val: filter | 1); |
283 | if (ret) |
284 | return ret; |
285 | /* RX */ |
286 | return mt7601u_mcu_calibrate(dev, cal: MCU_CAL_BW, val: filter); |
287 | } |
288 | |
289 | static int mt7601u_load_bbp_temp_table_bw(struct mt7601u_dev *dev) |
290 | { |
291 | const struct reg_table *t; |
292 | |
293 | if (WARN_ON(dev->temp_mode > MT_TEMP_MODE_LOW)) |
294 | return -EINVAL; |
295 | |
296 | t = &bbp_mode_table[dev->temp_mode][dev->bw]; |
297 | |
298 | return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, data: t->regs, len: t->n); |
299 | } |
300 | |
301 | static int mt7601u_bbp_temp(struct mt7601u_dev *dev, int mode, const char *name) |
302 | { |
303 | const struct reg_table *t; |
304 | int ret; |
305 | |
306 | if (dev->temp_mode == mode) |
307 | return 0; |
308 | |
309 | dev->temp_mode = mode; |
310 | trace_temp_mode(dev, val: mode); |
311 | |
312 | t = bbp_mode_table[dev->temp_mode]; |
313 | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
314 | data: t[2].regs, len: t[2].n); |
315 | if (ret) |
316 | return ret; |
317 | |
318 | return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
319 | data: t[dev->bw].regs, len: t[dev->bw].n); |
320 | } |
321 | |
322 | static void mt7601u_apply_ch14_fixup(struct mt7601u_dev *dev, int hw_chan) |
323 | { |
324 | struct mt7601u_rate_power *t = &dev->ee->power_rate_table; |
325 | |
326 | if (hw_chan != 14 || dev->bw != MT_BW_20) { |
327 | mt7601u_bbp_rmw(dev, offset: 4, mask: 0x20, val: 0); |
328 | mt7601u_bbp_wr(dev, offset: 178, val: 0xff); |
329 | |
330 | t->cck[0].bw20 = dev->ee->real_cck_bw20[0]; |
331 | t->cck[1].bw20 = dev->ee->real_cck_bw20[1]; |
332 | } else { /* Apply CH14 OBW fixup */ |
333 | mt7601u_bbp_wr(dev, offset: 4, val: 0x60); |
334 | mt7601u_bbp_wr(dev, offset: 178, val: 0); |
335 | |
336 | /* Note: vendor code is buggy here for negative values */ |
337 | t->cck[0].bw20 = dev->ee->real_cck_bw20[0] - 2; |
338 | t->cck[1].bw20 = dev->ee->real_cck_bw20[1] - 2; |
339 | } |
340 | } |
341 | |
342 | static int __mt7601u_phy_set_channel(struct mt7601u_dev *dev, |
343 | struct cfg80211_chan_def *chandef) |
344 | { |
345 | #define FREQ_PLAN_REGS 4 |
346 | static const u8 freq_plan[14][FREQ_PLAN_REGS] = { |
347 | { 0x99, 0x99, 0x09, 0x50 }, |
348 | { 0x46, 0x44, 0x0a, 0x50 }, |
349 | { 0xec, 0xee, 0x0a, 0x50 }, |
350 | { 0x99, 0x99, 0x0b, 0x50 }, |
351 | { 0x46, 0x44, 0x08, 0x51 }, |
352 | { 0xec, 0xee, 0x08, 0x51 }, |
353 | { 0x99, 0x99, 0x09, 0x51 }, |
354 | { 0x46, 0x44, 0x0a, 0x51 }, |
355 | { 0xec, 0xee, 0x0a, 0x51 }, |
356 | { 0x99, 0x99, 0x0b, 0x51 }, |
357 | { 0x46, 0x44, 0x08, 0x52 }, |
358 | { 0xec, 0xee, 0x08, 0x52 }, |
359 | { 0x99, 0x99, 0x09, 0x52 }, |
360 | { 0x33, 0x33, 0x0b, 0x52 }, |
361 | }; |
362 | struct mt76_reg_pair channel_freq_plan[FREQ_PLAN_REGS] = { |
363 | { 17, 0 }, { 18, 0 }, { 19, 0 }, { 20, 0 }, |
364 | }; |
365 | struct mt76_reg_pair bbp_settings[3] = { |
366 | { 62, 0x37 - dev->ee->lna_gain }, |
367 | { 63, 0x37 - dev->ee->lna_gain }, |
368 | { 64, 0x37 - dev->ee->lna_gain }, |
369 | }; |
370 | |
371 | struct ieee80211_channel *chan = chandef->chan; |
372 | enum nl80211_channel_type chan_type = |
373 | cfg80211_get_chandef_type(chandef); |
374 | struct mt7601u_rate_power *t = &dev->ee->power_rate_table; |
375 | int chan_idx; |
376 | bool chan_ext_below; |
377 | u8 bw; |
378 | int i, ret; |
379 | |
380 | bw = MT_BW_20; |
381 | chan_ext_below = (chan_type == NL80211_CHAN_HT40MINUS); |
382 | chan_idx = chan->hw_value - 1; |
383 | |
384 | if (chandef->width == NL80211_CHAN_WIDTH_40) { |
385 | bw = MT_BW_40; |
386 | |
387 | if (chan_idx > 1 && chan_type == NL80211_CHAN_HT40MINUS) |
388 | chan_idx -= 2; |
389 | else if (chan_idx < 12 && chan_type == NL80211_CHAN_HT40PLUS) |
390 | chan_idx += 2; |
391 | else |
392 | dev_err(dev->dev, "Error: invalid 40MHz channel!!\n" ); |
393 | } |
394 | |
395 | if (bw != dev->bw || chan_ext_below != dev->chan_ext_below) { |
396 | dev_dbg(dev->dev, "Info: switching HT mode bw:%d below:%d\n" , |
397 | bw, chan_ext_below); |
398 | |
399 | mt7601u_bbp_set_bw(dev, bw); |
400 | |
401 | mt7601u_bbp_set_ctrlch(dev, below: chan_ext_below); |
402 | mt7601u_mac_set_ctrlch(dev, below: chan_ext_below); |
403 | dev->chan_ext_below = chan_ext_below; |
404 | } |
405 | |
406 | for (i = 0; i < FREQ_PLAN_REGS; i++) |
407 | channel_freq_plan[i].value = freq_plan[chan_idx][i]; |
408 | |
409 | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, |
410 | data: channel_freq_plan, FREQ_PLAN_REGS); |
411 | if (ret) |
412 | return ret; |
413 | |
414 | mt7601u_rmw(dev, MT_TX_ALC_CFG_0, mask: 0x3f3f, |
415 | val: dev->ee->chan_pwr[chan_idx] & 0x3f); |
416 | |
417 | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
418 | data: bbp_settings, ARRAY_SIZE(bbp_settings)); |
419 | if (ret) |
420 | return ret; |
421 | |
422 | mt7601u_vco_cal(dev); |
423 | mt7601u_bbp_set_bw(dev, bw); |
424 | ret = mt7601u_set_bw_filter(dev, cal: false); |
425 | if (ret) |
426 | return ret; |
427 | |
428 | mt7601u_apply_ch14_fixup(dev, hw_chan: chan->hw_value); |
429 | mt7601u_wr(dev, MT_TX_PWR_CFG_0, val: int_to_s6(val: t->ofdm[1].bw20) << 24 | |
430 | int_to_s6(val: t->ofdm[0].bw20) << 16 | |
431 | int_to_s6(val: t->cck[1].bw20) << 8 | |
432 | int_to_s6(val: t->cck[0].bw20)); |
433 | |
434 | if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) |
435 | mt7601u_agc_reset(dev); |
436 | |
437 | dev->chandef = *chandef; |
438 | |
439 | return 0; |
440 | } |
441 | |
442 | int mt7601u_phy_set_channel(struct mt7601u_dev *dev, |
443 | struct cfg80211_chan_def *chandef) |
444 | { |
445 | int ret; |
446 | |
447 | cancel_delayed_work_sync(dwork: &dev->cal_work); |
448 | cancel_delayed_work_sync(dwork: &dev->freq_cal.work); |
449 | |
450 | mutex_lock(&dev->hw_atomic_mutex); |
451 | ret = __mt7601u_phy_set_channel(dev, chandef); |
452 | mutex_unlock(lock: &dev->hw_atomic_mutex); |
453 | if (ret) |
454 | return ret; |
455 | |
456 | if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) |
457 | return 0; |
458 | |
459 | ieee80211_queue_delayed_work(hw: dev->hw, dwork: &dev->cal_work, |
460 | MT_CALIBRATE_INTERVAL); |
461 | if (dev->freq_cal.enabled) |
462 | ieee80211_queue_delayed_work(hw: dev->hw, dwork: &dev->freq_cal.work, |
463 | MT_FREQ_CAL_INIT_DELAY); |
464 | return 0; |
465 | } |
466 | |
467 | #define BBP_R47_FLAG GENMASK(2, 0) |
468 | #define BBP_R47_F_TSSI 0 |
469 | #define BBP_R47_F_PKT_T 1 |
470 | #define BBP_R47_F_TX_RATE 2 |
471 | #define BBP_R47_F_TEMP 4 |
472 | /** |
473 | * mt7601u_bbp_r47_get - read value through BBP R47/R49 pair |
474 | * @dev: pointer to adapter structure |
475 | * @reg: value of BBP R47 before the operation |
476 | * @flag: one of the BBP_R47_F_* flags |
477 | * |
478 | * Convenience helper for reading values through BBP R47/R49 pair. |
479 | * Takes old value of BBP R47 as @reg, because callers usually have it |
480 | * cached already. |
481 | * |
482 | * Return: value of BBP R49. |
483 | */ |
484 | static u8 mt7601u_bbp_r47_get(struct mt7601u_dev *dev, u8 reg, u8 flag) |
485 | { |
486 | flag |= reg & ~BBP_R47_FLAG; |
487 | mt7601u_bbp_wr(dev, offset: 47, val: flag); |
488 | usleep_range(min: 500, max: 700); |
489 | return mt7601u_bbp_rr(dev, offset: 49); |
490 | } |
491 | |
492 | static s8 mt7601u_read_bootup_temp(struct mt7601u_dev *dev) |
493 | { |
494 | u8 bbp_val, temp; |
495 | u32 rf_bp, rf_set; |
496 | int i; |
497 | |
498 | rf_set = mt7601u_rr(dev, MT_RF_SETTING_0); |
499 | rf_bp = mt7601u_rr(dev, MT_RF_BYPASS_0); |
500 | |
501 | mt7601u_wr(dev, MT_RF_BYPASS_0, val: 0); |
502 | mt7601u_wr(dev, MT_RF_SETTING_0, val: 0x00000010); |
503 | mt7601u_wr(dev, MT_RF_BYPASS_0, val: 0x00000010); |
504 | |
505 | bbp_val = mt7601u_bbp_rmw(dev, offset: 47, mask: 0, val: 0x10); |
506 | |
507 | mt7601u_bbp_wr(dev, offset: 22, val: 0x40); |
508 | |
509 | for (i = 100; i && (bbp_val & 0x10); i--) |
510 | bbp_val = mt7601u_bbp_rr(dev, offset: 47); |
511 | |
512 | temp = mt7601u_bbp_r47_get(dev, reg: bbp_val, BBP_R47_F_TEMP); |
513 | |
514 | mt7601u_bbp_wr(dev, offset: 22, val: 0); |
515 | |
516 | bbp_val = mt7601u_bbp_rr(dev, offset: 21); |
517 | bbp_val |= 0x02; |
518 | mt7601u_bbp_wr(dev, offset: 21, val: bbp_val); |
519 | bbp_val &= ~0x02; |
520 | mt7601u_bbp_wr(dev, offset: 21, val: bbp_val); |
521 | |
522 | mt7601u_wr(dev, MT_RF_BYPASS_0, val: 0); |
523 | mt7601u_wr(dev, MT_RF_SETTING_0, val: rf_set); |
524 | mt7601u_wr(dev, MT_RF_BYPASS_0, val: rf_bp); |
525 | |
526 | trace_read_temp(dev, val: temp); |
527 | return temp; |
528 | } |
529 | |
530 | static s8 mt7601u_read_temp(struct mt7601u_dev *dev) |
531 | { |
532 | int i; |
533 | u8 val; |
534 | s8 temp; |
535 | |
536 | val = mt7601u_bbp_rmw(dev, offset: 47, mask: 0x7f, val: 0x10); |
537 | |
538 | /* Note: this rarely succeeds, temp can change even if it fails. */ |
539 | for (i = 100; i && (val & 0x10); i--) |
540 | val = mt7601u_bbp_rr(dev, offset: 47); |
541 | |
542 | temp = mt7601u_bbp_r47_get(dev, reg: val, BBP_R47_F_TEMP); |
543 | |
544 | trace_read_temp(dev, val: temp); |
545 | return temp; |
546 | } |
547 | |
548 | static void mt7601u_rxdc_cal(struct mt7601u_dev *dev) |
549 | { |
550 | static const struct mt76_reg_pair intro[] = { |
551 | { 158, 0x8d }, { 159, 0xfc }, |
552 | { 158, 0x8c }, { 159, 0x4c }, |
553 | }, outro[] = { |
554 | { 158, 0x8d }, { 159, 0xe0 }, |
555 | }; |
556 | u32 mac_ctrl; |
557 | int i, ret; |
558 | |
559 | mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL); |
560 | mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX); |
561 | |
562 | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
563 | data: intro, ARRAY_SIZE(intro)); |
564 | if (ret) |
565 | dev_err(dev->dev, "%s intro failed:%d\n" , __func__, ret); |
566 | |
567 | for (i = 20; i; i--) { |
568 | usleep_range(min: 300, max: 500); |
569 | |
570 | mt7601u_bbp_wr(dev, offset: 158, val: 0x8c); |
571 | if (mt7601u_bbp_rr(dev, offset: 159) == 0x0c) |
572 | break; |
573 | } |
574 | if (!i) |
575 | dev_err(dev->dev, "%s timed out\n" , __func__); |
576 | |
577 | mt7601u_wr(dev, MT_MAC_SYS_CTRL, val: 0); |
578 | |
579 | ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, |
580 | data: outro, ARRAY_SIZE(outro)); |
581 | if (ret) |
582 | dev_err(dev->dev, "%s outro failed:%d\n" , __func__, ret); |
583 | |
584 | mt7601u_wr(dev, MT_MAC_SYS_CTRL, val: mac_ctrl); |
585 | } |
586 | |
587 | void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev) |
588 | { |
589 | if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) |
590 | return; |
591 | |
592 | mt7601u_mcu_calibrate(dev, cal: MCU_CAL_DPD, val: dev->curr_temp); |
593 | |
594 | mt7601u_rxdc_cal(dev); |
595 | } |
596 | |
597 | /* Note: function copied from vendor driver */ |
598 | static s16 lin2dBd(u16 linear) |
599 | { |
600 | short exp = 0; |
601 | unsigned int mantisa; |
602 | int app, dBd; |
603 | |
604 | if (WARN_ON(!linear)) |
605 | return -10000; |
606 | |
607 | mantisa = linear; |
608 | |
609 | exp = fls(x: mantisa) - 16; |
610 | if (exp > 0) |
611 | mantisa >>= exp; |
612 | else |
613 | mantisa <<= abs(exp); |
614 | |
615 | if (mantisa <= 0xb800) |
616 | app = (mantisa + (mantisa >> 3) + (mantisa >> 4) - 0x9600); |
617 | else |
618 | app = (mantisa - (mantisa >> 3) - (mantisa >> 6) - 0x5a00); |
619 | if (app < 0) |
620 | app = 0; |
621 | |
622 | dBd = ((15 + exp) << 15) + app; |
623 | dBd = (dBd << 2) + (dBd << 1) + (dBd >> 6) + (dBd >> 7); |
624 | dBd = (dBd >> 10); |
625 | |
626 | return dBd; |
627 | } |
628 | |
629 | static void |
630 | mt7601u_set_initial_tssi(struct mt7601u_dev *dev, s16 tssi_db, s16 tssi_hvga_db) |
631 | { |
632 | struct tssi_data *d = &dev->ee->tssi_data; |
633 | int init_offset; |
634 | |
635 | init_offset = -((tssi_db * d->slope + d->offset[1]) / 4096) + 10; |
636 | |
637 | mt76_rmw(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, |
638 | val: int_to_s6(val: init_offset) & MT_TX_ALC_CFG_1_TEMP_COMP); |
639 | } |
640 | |
641 | static void mt7601u_tssi_dc_gain_cal(struct mt7601u_dev *dev) |
642 | { |
643 | u8 rf_vga, rf_mixer, bbp_r47; |
644 | int i, j; |
645 | s8 res[4]; |
646 | s16 tssi_init_db, tssi_init_hvga_db; |
647 | |
648 | mt7601u_wr(dev, MT_RF_SETTING_0, val: 0x00000030); |
649 | mt7601u_wr(dev, MT_RF_BYPASS_0, val: 0x000c0030); |
650 | mt7601u_wr(dev, MT_MAC_SYS_CTRL, val: 0); |
651 | |
652 | mt7601u_bbp_wr(dev, offset: 58, val: 0); |
653 | mt7601u_bbp_wr(dev, offset: 241, val: 0x2); |
654 | mt7601u_bbp_wr(dev, offset: 23, val: 0x8); |
655 | bbp_r47 = mt7601u_bbp_rr(dev, offset: 47); |
656 | |
657 | /* Set VGA gain */ |
658 | rf_vga = mt7601u_rf_rr(dev, bank: 5, offset: 3); |
659 | mt7601u_rf_wr(dev, bank: 5, offset: 3, value: 8); |
660 | |
661 | /* Mixer disable */ |
662 | rf_mixer = mt7601u_rf_rr(dev, bank: 4, offset: 39); |
663 | mt7601u_rf_wr(dev, bank: 4, offset: 39, value: 0); |
664 | |
665 | for (i = 0; i < 4; i++) { |
666 | mt7601u_rf_wr(dev, bank: 4, offset: 39, value: (i & 1) ? rf_mixer : 0); |
667 | |
668 | mt7601u_bbp_wr(dev, offset: 23, val: (i < 2) ? 0x08 : 0x02); |
669 | mt7601u_rf_wr(dev, bank: 5, offset: 3, value: (i < 2) ? 0x08 : 0x11); |
670 | |
671 | /* BBP TSSI initial and soft reset */ |
672 | mt7601u_bbp_wr(dev, offset: 22, val: 0); |
673 | mt7601u_bbp_wr(dev, offset: 244, val: 0); |
674 | |
675 | mt7601u_bbp_wr(dev, offset: 21, val: 1); |
676 | udelay(1); |
677 | mt7601u_bbp_wr(dev, offset: 21, val: 0); |
678 | |
679 | /* TSSI measurement */ |
680 | mt7601u_bbp_wr(dev, offset: 47, val: 0x50); |
681 | mt7601u_bbp_wr(dev, offset: (i & 1) ? 244 : 22, val: (i & 1) ? 0x31 : 0x40); |
682 | |
683 | for (j = 20; j; j--) |
684 | if (!(mt7601u_bbp_rr(dev, offset: 47) & 0x10)) |
685 | break; |
686 | if (!j) |
687 | dev_err(dev->dev, "%s timed out\n" , __func__); |
688 | |
689 | /* TSSI read */ |
690 | mt7601u_bbp_wr(dev, offset: 47, val: 0x40); |
691 | res[i] = mt7601u_bbp_rr(dev, offset: 49); |
692 | } |
693 | |
694 | tssi_init_db = lin2dBd(linear: (short)res[1] - res[0]); |
695 | tssi_init_hvga_db = lin2dBd(linear: ((short)res[3] - res[2]) * 4); |
696 | dev->tssi_init = res[0]; |
697 | dev->tssi_init_hvga = res[2]; |
698 | dev->tssi_init_hvga_offset_db = tssi_init_hvga_db - tssi_init_db; |
699 | |
700 | dev_dbg(dev->dev, |
701 | "TSSI_init:%hhx db:%hx hvga:%hhx hvga_db:%hx off_db:%hx\n" , |
702 | dev->tssi_init, tssi_init_db, dev->tssi_init_hvga, |
703 | tssi_init_hvga_db, dev->tssi_init_hvga_offset_db); |
704 | |
705 | mt7601u_bbp_wr(dev, offset: 22, val: 0); |
706 | mt7601u_bbp_wr(dev, offset: 244, val: 0); |
707 | |
708 | mt7601u_bbp_wr(dev, offset: 21, val: 1); |
709 | udelay(1); |
710 | mt7601u_bbp_wr(dev, offset: 21, val: 0); |
711 | |
712 | mt7601u_wr(dev, MT_RF_BYPASS_0, val: 0); |
713 | mt7601u_wr(dev, MT_RF_SETTING_0, val: 0); |
714 | |
715 | mt7601u_rf_wr(dev, bank: 5, offset: 3, value: rf_vga); |
716 | mt7601u_rf_wr(dev, bank: 4, offset: 39, value: rf_mixer); |
717 | mt7601u_bbp_wr(dev, offset: 47, val: bbp_r47); |
718 | |
719 | mt7601u_set_initial_tssi(dev, tssi_db: tssi_init_db, tssi_hvga_db: tssi_init_hvga_db); |
720 | } |
721 | |
722 | static int mt7601u_temp_comp(struct mt7601u_dev *dev, bool on) |
723 | { |
724 | int ret, temp, hi_temp = 400, lo_temp = -200; |
725 | |
726 | temp = (dev->raw_temp - dev->ee->ref_temp) * MT_EE_TEMPERATURE_SLOPE; |
727 | dev->curr_temp = temp; |
728 | |
729 | /* DPD Calibration */ |
730 | if (temp - dev->dpd_temp > 450 || temp - dev->dpd_temp < -450) { |
731 | dev->dpd_temp = temp; |
732 | |
733 | ret = mt7601u_mcu_calibrate(dev, cal: MCU_CAL_DPD, val: dev->dpd_temp); |
734 | if (ret) |
735 | return ret; |
736 | |
737 | mt7601u_vco_cal(dev); |
738 | |
739 | dev_dbg(dev->dev, "Recalibrate DPD\n" ); |
740 | } |
741 | |
742 | /* PLL Lock Protect */ |
743 | if (temp < -50 && !dev->pll_lock_protect) { /* < 20C */ |
744 | dev->pll_lock_protect = true; |
745 | |
746 | mt7601u_rf_wr(dev, bank: 4, offset: 4, value: 6); |
747 | mt7601u_rf_clear(dev, bank: 4, offset: 10, mask: 0x30); |
748 | |
749 | dev_dbg(dev->dev, "PLL lock protect on - too cold\n" ); |
750 | } else if (temp > 50 && dev->pll_lock_protect) { /* > 30C */ |
751 | dev->pll_lock_protect = false; |
752 | |
753 | mt7601u_rf_wr(dev, bank: 4, offset: 4, value: 0); |
754 | mt7601u_rf_rmw(dev, bank: 4, offset: 10, mask: 0x30, val: 0x10); |
755 | |
756 | dev_dbg(dev->dev, "PLL lock protect off\n" ); |
757 | } |
758 | |
759 | if (on) { |
760 | hi_temp -= 50; |
761 | lo_temp -= 50; |
762 | } |
763 | |
764 | /* BBP CR for H, L, N temperature */ |
765 | if (temp > hi_temp) |
766 | return mt7601u_bbp_temp(dev, mode: MT_TEMP_MODE_HIGH, name: "high" ); |
767 | else if (temp > lo_temp) |
768 | return mt7601u_bbp_temp(dev, mode: MT_TEMP_MODE_NORMAL, name: "normal" ); |
769 | else |
770 | return mt7601u_bbp_temp(dev, mode: MT_TEMP_MODE_LOW, name: "low" ); |
771 | } |
772 | |
773 | /* Note: this is used only with TSSI, we can just use trgt_pwr from eeprom. */ |
774 | static int mt7601u_current_tx_power(struct mt7601u_dev *dev) |
775 | { |
776 | return dev->ee->chan_pwr[dev->chandef.chan->hw_value - 1]; |
777 | } |
778 | |
779 | static bool mt7601u_use_hvga(struct mt7601u_dev *dev) |
780 | { |
781 | return !(mt7601u_current_tx_power(dev) > 20); |
782 | } |
783 | |
784 | static s16 |
785 | mt7601u_phy_rf_pa_mode_val(struct mt7601u_dev *dev, int phy_mode, int tx_rate) |
786 | { |
787 | static const s16 decode_tb[] = { 0, 8847, -5734, -5734 }; |
788 | u32 reg; |
789 | |
790 | switch (phy_mode) { |
791 | case MT_PHY_TYPE_OFDM: |
792 | tx_rate += 4; |
793 | fallthrough; |
794 | case MT_PHY_TYPE_CCK: |
795 | reg = dev->rf_pa_mode[0]; |
796 | break; |
797 | default: |
798 | reg = dev->rf_pa_mode[1]; |
799 | break; |
800 | } |
801 | |
802 | return decode_tb[(reg >> (tx_rate * 2)) & 0x3]; |
803 | } |
804 | |
805 | static struct mt7601u_tssi_params |
806 | mt7601u_tssi_params_get(struct mt7601u_dev *dev) |
807 | { |
808 | static const u8 ofdm_pkt2rate[8] = { 6, 4, 2, 0, 7, 5, 3, 1 }; |
809 | static const int static_power[4] = { 0, -49152, -98304, 49152 }; |
810 | struct mt7601u_tssi_params p; |
811 | u8 bbp_r47, pkt_type, tx_rate; |
812 | struct power_per_rate *rate_table; |
813 | |
814 | bbp_r47 = mt7601u_bbp_rr(dev, offset: 47); |
815 | |
816 | p.tssi0 = mt7601u_bbp_r47_get(dev, reg: bbp_r47, BBP_R47_F_TSSI); |
817 | dev->raw_temp = mt7601u_bbp_r47_get(dev, reg: bbp_r47, BBP_R47_F_TEMP); |
818 | pkt_type = mt7601u_bbp_r47_get(dev, reg: bbp_r47, BBP_R47_F_PKT_T); |
819 | |
820 | p.trgt_power = mt7601u_current_tx_power(dev); |
821 | |
822 | switch (pkt_type & 0x03) { |
823 | case MT_PHY_TYPE_CCK: |
824 | tx_rate = (pkt_type >> 4) & 0x03; |
825 | rate_table = dev->ee->power_rate_table.cck; |
826 | break; |
827 | |
828 | case MT_PHY_TYPE_OFDM: |
829 | tx_rate = ofdm_pkt2rate[(pkt_type >> 4) & 0x07]; |
830 | rate_table = dev->ee->power_rate_table.ofdm; |
831 | break; |
832 | |
833 | default: |
834 | tx_rate = mt7601u_bbp_r47_get(dev, reg: bbp_r47, BBP_R47_F_TX_RATE); |
835 | tx_rate &= 0x7f; |
836 | rate_table = dev->ee->power_rate_table.ht; |
837 | break; |
838 | } |
839 | |
840 | if (dev->bw == MT_BW_20) |
841 | p.trgt_power += rate_table[tx_rate / 2].bw20; |
842 | else |
843 | p.trgt_power += rate_table[tx_rate / 2].bw40; |
844 | |
845 | p.trgt_power <<= 12; |
846 | |
847 | dev_dbg(dev->dev, "tx_rate:%02hhx pwr:%08x\n" , tx_rate, p.trgt_power); |
848 | |
849 | p.trgt_power += mt7601u_phy_rf_pa_mode_val(dev, phy_mode: pkt_type & 0x03, |
850 | tx_rate); |
851 | |
852 | /* Channel 14, cck, bw20 */ |
853 | if ((pkt_type & 0x03) == MT_PHY_TYPE_CCK) { |
854 | if (mt7601u_bbp_rr(dev, offset: 4) & 0x20) |
855 | p.trgt_power += mt7601u_bbp_rr(dev, offset: 178) ? 18022 : 9830; |
856 | else |
857 | p.trgt_power += mt7601u_bbp_rr(dev, offset: 178) ? 819 : 24576; |
858 | } |
859 | |
860 | p.trgt_power += static_power[mt7601u_bbp_rr(dev, offset: 1) & 0x03]; |
861 | |
862 | p.trgt_power += dev->ee->tssi_data.tx0_delta_offset; |
863 | |
864 | dev_dbg(dev->dev, |
865 | "tssi:%02hhx t_power:%08x temp:%02hhx pkt_type:%02hhx\n" , |
866 | p.tssi0, p.trgt_power, dev->raw_temp, pkt_type); |
867 | |
868 | return p; |
869 | } |
870 | |
871 | static bool mt7601u_tssi_read_ready(struct mt7601u_dev *dev) |
872 | { |
873 | return !(mt7601u_bbp_rr(dev, offset: 47) & 0x10); |
874 | } |
875 | |
876 | static int mt7601u_tssi_cal(struct mt7601u_dev *dev) |
877 | { |
878 | struct mt7601u_tssi_params params; |
879 | int curr_pwr, diff_pwr; |
880 | char tssi_offset; |
881 | s8 tssi_init; |
882 | s16 tssi_m_dc, tssi_db; |
883 | bool hvga; |
884 | u32 val; |
885 | |
886 | if (!dev->ee->tssi_enabled) |
887 | return 0; |
888 | |
889 | hvga = mt7601u_use_hvga(dev); |
890 | if (!dev->tssi_read_trig) |
891 | return mt7601u_mcu_tssi_read_kick(dev, use_hvga: hvga); |
892 | |
893 | if (!mt7601u_tssi_read_ready(dev)) |
894 | return 0; |
895 | |
896 | params = mt7601u_tssi_params_get(dev); |
897 | |
898 | tssi_init = (hvga ? dev->tssi_init_hvga : dev->tssi_init); |
899 | tssi_m_dc = params.tssi0 - tssi_init; |
900 | tssi_db = lin2dBd(linear: tssi_m_dc); |
901 | dev_dbg(dev->dev, "tssi dc:%04hx db:%04hx hvga:%d\n" , |
902 | tssi_m_dc, tssi_db, hvga); |
903 | |
904 | if (dev->chandef.chan->hw_value < 5) |
905 | tssi_offset = dev->ee->tssi_data.offset[0]; |
906 | else if (dev->chandef.chan->hw_value < 9) |
907 | tssi_offset = dev->ee->tssi_data.offset[1]; |
908 | else |
909 | tssi_offset = dev->ee->tssi_data.offset[2]; |
910 | |
911 | if (hvga) |
912 | tssi_db -= dev->tssi_init_hvga_offset_db; |
913 | |
914 | curr_pwr = tssi_db * dev->ee->tssi_data.slope + (tssi_offset << 9); |
915 | diff_pwr = params.trgt_power - curr_pwr; |
916 | dev_dbg(dev->dev, "Power curr:%08x diff:%08x\n" , curr_pwr, diff_pwr); |
917 | |
918 | if (params.tssi0 > 126 && diff_pwr > 0) { |
919 | dev_err(dev->dev, "Error: TSSI upper saturation\n" ); |
920 | diff_pwr = 0; |
921 | } |
922 | if (params.tssi0 - tssi_init < 1 && diff_pwr < 0) { |
923 | dev_err(dev->dev, "Error: TSSI lower saturation\n" ); |
924 | diff_pwr = 0; |
925 | } |
926 | |
927 | if ((dev->prev_pwr_diff ^ diff_pwr) < 0 && abs(diff_pwr) < 4096 && |
928 | (abs(diff_pwr) > abs(dev->prev_pwr_diff) || |
929 | (diff_pwr > 0 && diff_pwr == -dev->prev_pwr_diff))) |
930 | diff_pwr = 0; |
931 | else |
932 | dev->prev_pwr_diff = diff_pwr; |
933 | |
934 | diff_pwr += (diff_pwr > 0) ? 2048 : -2048; |
935 | diff_pwr /= 4096; |
936 | |
937 | dev_dbg(dev->dev, "final diff: %08x\n" , diff_pwr); |
938 | |
939 | val = mt7601u_rr(dev, MT_TX_ALC_CFG_1); |
940 | curr_pwr = s6_to_int(FIELD_GET(MT_TX_ALC_CFG_1_TEMP_COMP, val)); |
941 | diff_pwr += curr_pwr; |
942 | val = (val & ~MT_TX_ALC_CFG_1_TEMP_COMP) | int_to_s6(val: diff_pwr); |
943 | mt7601u_wr(dev, MT_TX_ALC_CFG_1, val); |
944 | |
945 | return mt7601u_mcu_tssi_read_kick(dev, use_hvga: hvga); |
946 | } |
947 | |
948 | static u8 mt7601u_agc_default(struct mt7601u_dev *dev) |
949 | { |
950 | return (dev->ee->lna_gain - 8) * 2 + 0x34; |
951 | } |
952 | |
953 | static void mt7601u_agc_reset(struct mt7601u_dev *dev) |
954 | { |
955 | u8 agc = mt7601u_agc_default(dev); |
956 | |
957 | mt7601u_bbp_wr(dev, offset: 66, val: agc); |
958 | } |
959 | |
960 | void mt7601u_agc_save(struct mt7601u_dev *dev) |
961 | { |
962 | dev->agc_save = mt7601u_bbp_rr(dev, offset: 66); |
963 | } |
964 | |
965 | void mt7601u_agc_restore(struct mt7601u_dev *dev) |
966 | { |
967 | mt7601u_bbp_wr(dev, offset: 66, val: dev->agc_save); |
968 | } |
969 | |
970 | static void mt7601u_agc_tune(struct mt7601u_dev *dev) |
971 | { |
972 | u8 val = mt7601u_agc_default(dev); |
973 | long ; |
974 | |
975 | if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) |
976 | return; |
977 | |
978 | /* Note: only in STA mode and not dozing; perhaps do this only if |
979 | * there is enough rssi updates since last run? |
980 | * Rssi updates are only on beacons and U2M so should work... |
981 | */ |
982 | spin_lock_bh(lock: &dev->con_mon_lock); |
983 | avg_rssi = ewma_rssi_read(e: &dev->avg_rssi); |
984 | spin_unlock_bh(lock: &dev->con_mon_lock); |
985 | if (avg_rssi == 0) |
986 | return; |
987 | |
988 | avg_rssi = -avg_rssi; |
989 | if (avg_rssi <= -70) |
990 | val -= 0x20; |
991 | else if (avg_rssi <= -60) |
992 | val -= 0x10; |
993 | |
994 | if (val != mt7601u_bbp_rr(dev, offset: 66)) |
995 | mt7601u_bbp_wr(dev, offset: 66, val); |
996 | |
997 | /* TODO: also if lost a lot of beacons try resetting |
998 | * (see RTMPSetAGCInitValue() call in mlme.c). |
999 | */ |
1000 | } |
1001 | |
1002 | static void mt7601u_phy_calibrate(struct work_struct *work) |
1003 | { |
1004 | struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, |
1005 | cal_work.work); |
1006 | |
1007 | mt7601u_agc_tune(dev); |
1008 | mt7601u_tssi_cal(dev); |
1009 | /* If TSSI calibration was run it already updated temperature. */ |
1010 | if (!dev->ee->tssi_enabled) |
1011 | dev->raw_temp = mt7601u_read_temp(dev); |
1012 | mt7601u_temp_comp(dev, on: true); /* TODO: find right value for @on */ |
1013 | |
1014 | ieee80211_queue_delayed_work(hw: dev->hw, dwork: &dev->cal_work, |
1015 | MT_CALIBRATE_INTERVAL); |
1016 | } |
1017 | |
1018 | static unsigned long |
1019 | __mt7601u_phy_freq_cal(struct mt7601u_dev *dev, s8 last_offset, u8 phy_mode) |
1020 | { |
1021 | u8 activate_threshold, deactivate_threshold; |
1022 | |
1023 | trace_freq_cal_offset(dev, phy_mode, freq_off: last_offset); |
1024 | |
1025 | /* No beacons received - reschedule soon */ |
1026 | if (last_offset == MT_FREQ_OFFSET_INVALID) |
1027 | return MT_FREQ_CAL_ADJ_INTERVAL; |
1028 | |
1029 | switch (phy_mode) { |
1030 | case MT_PHY_TYPE_CCK: |
1031 | activate_threshold = 19; |
1032 | deactivate_threshold = 5; |
1033 | break; |
1034 | case MT_PHY_TYPE_OFDM: |
1035 | activate_threshold = 102; |
1036 | deactivate_threshold = 32; |
1037 | break; |
1038 | case MT_PHY_TYPE_HT: |
1039 | case MT_PHY_TYPE_HT_GF: |
1040 | activate_threshold = 82; |
1041 | deactivate_threshold = 20; |
1042 | break; |
1043 | default: |
1044 | WARN_ON(1); |
1045 | return MT_FREQ_CAL_CHECK_INTERVAL; |
1046 | } |
1047 | |
1048 | if (abs(last_offset) >= activate_threshold) |
1049 | dev->freq_cal.adjusting = true; |
1050 | else if (abs(last_offset) <= deactivate_threshold) |
1051 | dev->freq_cal.adjusting = false; |
1052 | |
1053 | if (!dev->freq_cal.adjusting) |
1054 | return MT_FREQ_CAL_CHECK_INTERVAL; |
1055 | |
1056 | if (last_offset > deactivate_threshold) { |
1057 | if (dev->freq_cal.freq > 0) |
1058 | dev->freq_cal.freq--; |
1059 | else |
1060 | dev->freq_cal.adjusting = false; |
1061 | } else if (last_offset < -deactivate_threshold) { |
1062 | if (dev->freq_cal.freq < 0xbf) |
1063 | dev->freq_cal.freq++; |
1064 | else |
1065 | dev->freq_cal.adjusting = false; |
1066 | } |
1067 | |
1068 | trace_freq_cal_adjust(dev, val: dev->freq_cal.freq); |
1069 | mt7601u_rf_wr(dev, bank: 0, offset: 12, value: dev->freq_cal.freq); |
1070 | mt7601u_vco_cal(dev); |
1071 | |
1072 | return dev->freq_cal.adjusting ? MT_FREQ_CAL_ADJ_INTERVAL : |
1073 | MT_FREQ_CAL_CHECK_INTERVAL; |
1074 | } |
1075 | |
1076 | static void mt7601u_phy_freq_cal(struct work_struct *work) |
1077 | { |
1078 | struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, |
1079 | freq_cal.work.work); |
1080 | s8 last_offset; |
1081 | u8 phy_mode; |
1082 | unsigned long delay; |
1083 | |
1084 | spin_lock_bh(lock: &dev->con_mon_lock); |
1085 | last_offset = dev->bcn_freq_off; |
1086 | phy_mode = dev->bcn_phy_mode; |
1087 | spin_unlock_bh(lock: &dev->con_mon_lock); |
1088 | |
1089 | delay = __mt7601u_phy_freq_cal(dev, last_offset, phy_mode); |
1090 | ieee80211_queue_delayed_work(hw: dev->hw, dwork: &dev->freq_cal.work, delay); |
1091 | |
1092 | spin_lock_bh(lock: &dev->con_mon_lock); |
1093 | dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; |
1094 | spin_unlock_bh(lock: &dev->con_mon_lock); |
1095 | } |
1096 | |
1097 | void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, |
1098 | struct ieee80211_bss_conf *info) |
1099 | { |
1100 | struct ieee80211_vif *vif = container_of(info, struct ieee80211_vif, |
1101 | bss_conf); |
1102 | |
1103 | if (!vif->cfg.assoc) |
1104 | cancel_delayed_work_sync(dwork: &dev->freq_cal.work); |
1105 | |
1106 | /* Start/stop collecting beacon data */ |
1107 | spin_lock_bh(lock: &dev->con_mon_lock); |
1108 | ether_addr_copy(dst: dev->ap_bssid, src: info->bssid); |
1109 | ewma_rssi_init(e: &dev->avg_rssi); |
1110 | dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; |
1111 | spin_unlock_bh(lock: &dev->con_mon_lock); |
1112 | |
1113 | dev->freq_cal.freq = dev->ee->rf_freq_off; |
1114 | dev->freq_cal.enabled = vif->cfg.assoc; |
1115 | dev->freq_cal.adjusting = false; |
1116 | |
1117 | if (vif->cfg.assoc) |
1118 | ieee80211_queue_delayed_work(hw: dev->hw, dwork: &dev->freq_cal.work, |
1119 | MT_FREQ_CAL_INIT_DELAY); |
1120 | } |
1121 | |
1122 | static int mt7601u_init_cal(struct mt7601u_dev *dev) |
1123 | { |
1124 | u32 mac_ctrl; |
1125 | int ret; |
1126 | |
1127 | dev->raw_temp = mt7601u_read_bootup_temp(dev); |
1128 | dev->curr_temp = (dev->raw_temp - dev->ee->ref_temp) * |
1129 | MT_EE_TEMPERATURE_SLOPE; |
1130 | dev->dpd_temp = dev->curr_temp; |
1131 | |
1132 | mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL); |
1133 | |
1134 | ret = mt7601u_mcu_calibrate(dev, cal: MCU_CAL_R, val: 0); |
1135 | if (ret) |
1136 | return ret; |
1137 | |
1138 | ret = mt7601u_rf_rr(dev, bank: 0, offset: 4); |
1139 | if (ret < 0) |
1140 | return ret; |
1141 | ret |= 0x80; |
1142 | ret = mt7601u_rf_wr(dev, bank: 0, offset: 4, value: ret); |
1143 | if (ret) |
1144 | return ret; |
1145 | msleep(msecs: 2); |
1146 | |
1147 | ret = mt7601u_mcu_calibrate(dev, cal: MCU_CAL_TXDCOC, val: 0); |
1148 | if (ret) |
1149 | return ret; |
1150 | |
1151 | mt7601u_rxdc_cal(dev); |
1152 | |
1153 | ret = mt7601u_set_bw_filter(dev, cal: true); |
1154 | if (ret) |
1155 | return ret; |
1156 | ret = mt7601u_mcu_calibrate(dev, cal: MCU_CAL_LOFT, val: 0); |
1157 | if (ret) |
1158 | return ret; |
1159 | ret = mt7601u_mcu_calibrate(dev, cal: MCU_CAL_TXIQ, val: 0); |
1160 | if (ret) |
1161 | return ret; |
1162 | ret = mt7601u_mcu_calibrate(dev, cal: MCU_CAL_RXIQ, val: 0); |
1163 | if (ret) |
1164 | return ret; |
1165 | ret = mt7601u_mcu_calibrate(dev, cal: MCU_CAL_DPD, val: dev->dpd_temp); |
1166 | if (ret) |
1167 | return ret; |
1168 | |
1169 | mt7601u_rxdc_cal(dev); |
1170 | |
1171 | mt7601u_tssi_dc_gain_cal(dev); |
1172 | |
1173 | mt7601u_wr(dev, MT_MAC_SYS_CTRL, val: mac_ctrl); |
1174 | |
1175 | mt7601u_temp_comp(dev, on: true); |
1176 | |
1177 | return 0; |
1178 | } |
1179 | |
1180 | int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw) |
1181 | { |
1182 | u32 val, old; |
1183 | |
1184 | if (bw == dev->bw) { |
1185 | /* Vendor driver does the rmc even when no change is needed. */ |
1186 | mt7601u_bbp_rmc(dev, offset: 4, mask: 0x18, val: bw == MT_BW_20 ? 0 : 0x10); |
1187 | |
1188 | return 0; |
1189 | } |
1190 | dev->bw = bw; |
1191 | |
1192 | /* Stop MAC for the time of bw change */ |
1193 | old = mt7601u_rr(dev, MT_MAC_SYS_CTRL); |
1194 | val = old & ~(MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); |
1195 | mt7601u_wr(dev, MT_MAC_SYS_CTRL, val); |
1196 | mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, |
1197 | val: 0, timeout: 500000); |
1198 | |
1199 | mt7601u_bbp_rmc(dev, offset: 4, mask: 0x18, val: bw == MT_BW_20 ? 0 : 0x10); |
1200 | |
1201 | mt7601u_wr(dev, MT_MAC_SYS_CTRL, val: old); |
1202 | |
1203 | return mt7601u_load_bbp_temp_table_bw(dev); |
1204 | } |
1205 | |
1206 | /** |
1207 | * mt7601u_set_rx_path - set rx path in BBP |
1208 | * @dev: pointer to adapter structure |
1209 | * @path: rx path to set values are 0-based |
1210 | */ |
1211 | void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path) |
1212 | { |
1213 | mt7601u_bbp_rmw(dev, offset: 3, mask: 0x18, val: path << 3); |
1214 | } |
1215 | |
1216 | /** |
1217 | * mt7601u_set_tx_dac - set which tx DAC to use |
1218 | * @dev: pointer to adapter structure |
1219 | * @dac: DAC index, values are 0-based |
1220 | */ |
1221 | void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 dac) |
1222 | { |
1223 | mt7601u_bbp_rmc(dev, offset: 1, mask: 0x18, val: dac << 3); |
1224 | } |
1225 | |
1226 | int mt7601u_phy_init(struct mt7601u_dev *dev) |
1227 | { |
1228 | int ret; |
1229 | |
1230 | dev->rf_pa_mode[0] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG0); |
1231 | dev->rf_pa_mode[1] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG1); |
1232 | |
1233 | ret = mt7601u_rf_wr(dev, bank: 0, offset: 12, value: dev->ee->rf_freq_off); |
1234 | if (ret) |
1235 | return ret; |
1236 | ret = mt7601u_write_reg_pairs(dev, base: 0, data: rf_central, |
1237 | ARRAY_SIZE(rf_central)); |
1238 | if (ret) |
1239 | return ret; |
1240 | ret = mt7601u_write_reg_pairs(dev, base: 0, data: rf_channel, |
1241 | ARRAY_SIZE(rf_channel)); |
1242 | if (ret) |
1243 | return ret; |
1244 | ret = mt7601u_write_reg_pairs(dev, base: 0, data: rf_vga, ARRAY_SIZE(rf_vga)); |
1245 | if (ret) |
1246 | return ret; |
1247 | |
1248 | ret = mt7601u_init_cal(dev); |
1249 | if (ret) |
1250 | return ret; |
1251 | |
1252 | dev->prev_pwr_diff = 100; |
1253 | |
1254 | INIT_DELAYED_WORK(&dev->cal_work, mt7601u_phy_calibrate); |
1255 | INIT_DELAYED_WORK(&dev->freq_cal.work, mt7601u_phy_freq_cal); |
1256 | |
1257 | return 0; |
1258 | } |
1259 | |