1 /*
2 * Copyright (c) 2026 Ahmad Khalifa <vexeduxr@FreeBSD.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 #include <sys/param.h>
8 #include <sys/lock.h>
9 #include <sys/mutex.h>
10 #include <sys/mbuf.h>
11 #include <sys/kernel.h>
12 #include <sys/socket.h>
13 #include <sys/systm.h>
14 #include <sys/malloc.h>
15 #include <sys/queue.h>
16 #include <sys/taskqueue.h>
17 #include <sys/bus.h>
18 #include <sys/endian.h>
19 #include <sys/linker.h>
20
21 #include <net/if.h>
22 #include <net/ethernet.h>
23 #include <net/if_media.h>
24
25 #include <net80211/ieee80211_var.h>
26 #include <net80211/ieee80211_radiotap.h>
27
28 #include <dev/rtwn/if_rtwnreg.h>
29 #include <dev/rtwn/if_rtwnvar.h>
30
31 #include <dev/rtwn/if_rtwn_debug.h>
32
33 #include <dev/rtwn/rtl8188e/r88e.h>
34 #include <dev/rtwn/rtl8188e/r88e_reg.h>
35
36 #include <dev/rtwn/rtl8192c/r92c_reg.h>
37
38 #include <dev/rtwn/rtl8192e/r92e_var.h>
39
40 #include <dev/rtwn/rtl8723b/r23b.h>
41 #include <dev/rtwn/rtl8723b/r23b_var.h>
42 #include <dev/rtwn/rtl8723b/r23b_reg.h>
43 #include <dev/rtwn/rtl8723b/r23b_fw_cmd.h>
44
45 struct r23b_iqk_reg_vals {
46 uint32_t adaa[16];
47 uint32_t iqk_bb[9];
48 uint8_t txpause;
49 uint8_t bcn_ctrl[2];
50 uint8_t gpio_muxcfg;
51 };
52
53 struct r23b_iqk_result {
54 int32_t iqk_before;
55 int32_t iqk_after;
56 };
57
58 enum r23b_iqk_stage {
59 R23B_IQK_TX,
60 R23B_IQK_TX_RX,
61 R23B_IQK_RX
62 };
63
64 static const uint16_t r23b_iq_calib_reg_adaa[16] = {
65 0x85c, 0xe6c, 0xe70, 0xe74,
66 0xe78, 0xe7c, 0xe80, 0xe84,
67 0xe88, 0xe8c, 0xed0, 0xed4,
68 0xed8, 0xedc, 0xee0, 0xeec
69 };
70
71 static const uint16_t r23b_iq_calib_reg_iqk_bb[9] = {
72 0xc04, 0xc08, 0x874, 0xb68,
73 0xb6c, 0x870, 0x860, 0x864,
74 0xa04
75 };
76
77 #define R23B_IQK_MAX_TOLERANCE 5
78 #define R23B_IQK_SIGN(r) (((r) & 0x200) ? (0xfffffc00 | (r)) : (r))
79
80 /* XXX
81 * Same as r92c_lc_calib except for LDO on and LDO off
82 */
83 void
r23b_lc_calib(struct rtwn_softc * sc)84 r23b_lc_calib(struct rtwn_softc *sc)
85 {
86 uint32_t rf_ac[2];
87 uint8_t txmode;
88 int i;
89
90 txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3);
91 if ((txmode & 0x70) != 0) {
92 /* Disable all continuous Tx. */
93 rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70);
94
95 /* Set RF mode to standby mode. */
96 for (i = 0; i < sc->nrxchains; i++) {
97 rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC);
98 rtwn_rf_write(sc, i, R92C_RF_AC,
99 RW(rf_ac[i], R92C_RF_AC_MODE,
100 R92C_RF_AC_MODE_STANDBY));
101 }
102 } else {
103 /* Block all Tx queues. */
104 rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL);
105 }
106
107 /* LDO on */
108 rtwn_rf_write(sc, 0, R23B_RF_S0S1, 0xdfbe0);
109
110 /* Start calibration. */
111 rtwn_rf_setbits(sc, 0, R92C_RF_CHNLBW, 0, R92C_RF_CHNLBW_LCSTART);
112
113 /* Give calibration the time to complete. */
114 rtwn_delay(sc, 100000); /* 100ms */
115
116 /* LDO off */
117 rtwn_rf_write(sc, 0, R23B_RF_S0S1, 0xdffe0);
118
119 /* Restore configuration. */
120 if ((txmode & 0x70) != 0) {
121 /* Restore Tx mode. */
122 rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode);
123 /* Restore RF mode. */
124 for (i = 0; i < sc->nrxchains; i++)
125 rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]);
126 } else {
127 /* Unblock all Tx queues. */
128 rtwn_write_1(sc, R92C_TXPAUSE, 0x00);
129 }
130 }
131
132 static void
r23b_iq_calib_chain(struct rtwn_softc * sc,enum r23b_iqk_stage stage)133 r23b_iq_calib_chain(struct rtwn_softc *sc, enum r23b_iqk_stage stage)
134 {
135 struct r23b_softc *rs = sc->sc_priv;
136 uint32_t rf_path;
137
138 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: starting stage: %s\n",
139 __func__, stage == R23B_IQK_TX ? "R23B_IQK_TX" :
140 stage == R23B_IQK_TX_RX ? "R23B_IQK_TX_RX" : "R23B_IQK_RX");
141
142 /* Save RF path. */
143 rf_path = rtwn_read_4(sc, R23B_ANT_SEL);
144
145 /* Leave IQK mode. */
146 rtwn_setbits_4(sc, R92C_FPGA0_IQK, ~0xff, 0);
147
148 rtwn_rf_setbits(sc, 0, R88E_RF_WE_LUT, 0, 0x80000);
149 switch (stage) {
150 case R23B_IQK_TX:
151 rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x20000);
152 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0x0003f);
153 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0xc7f87);
154
155 rtwn_write_4(sc, R92C_TX_IQK, 0x01007c00);
156 break;
157 case R23B_IQK_TX_RX:
158 rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x30000);
159 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0x0001f);
160 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0xf7fb7);
161
162 rtwn_write_4(sc, R92C_TX_IQK, 0x01007c00);
163 break;
164 case R23B_IQK_RX:
165 rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x30000);
166 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0x0001f);
167 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0xf7d77);
168
169 rtwn_rf_write(sc, 0, 0xdf, 0xf80);
170 rtwn_rf_write(sc, 0, 0x55, 0x4021f);
171 break;
172 default:
173 KASSERT(0, ("%s: Invalid stage %d", __func__, stage));
174 }
175
176 rtwn_write_4(sc, R92C_RX_IQK, 0x01004800);
177
178 switch (stage) {
179 case R23B_IQK_TX:
180 case R23B_IQK_TX_RX:
181 rtwn_write_4(sc, R92C_TX_IQK_TONE(0), 0x18008c1c);
182 rtwn_write_4(sc, R92C_RX_IQK_TONE(0), 0x38008c1c);
183 break;
184 case R23B_IQK_RX:
185 rtwn_write_4(sc, R92C_TX_IQK_TONE(0), 0x38008c1c);
186 rtwn_write_4(sc, R92C_RX_IQK_TONE(0), 0x18008c1c);
187 break;
188 }
189 rtwn_write_4(sc, R92C_TX_IQK_TONE(1), 0x38008c1c);
190 rtwn_write_4(sc, R92C_RX_IQK_TONE(1), 0x38008c1c);
191
192 switch (stage) {
193 case R23B_IQK_TX:
194 rtwn_write_4(sc, R92C_TX_IQK_PI(0), 0x821403ea);
195 rtwn_write_4(sc, R92C_RX_IQK_PI(0), 0x28110000);
196 break;
197 case R23B_IQK_TX_RX:
198 rtwn_write_4(sc, R92C_TX_IQK_PI(0), 0x82160ff0);
199 rtwn_write_4(sc, R92C_RX_IQK_PI(0), 0x28110000);
200 break;
201 case R23B_IQK_RX:
202 rtwn_write_4(sc, R92C_TX_IQK_PI(0), 0x82110000);
203 rtwn_write_4(sc, R92C_RX_IQK_PI(0), 0x2816001f);
204 break;
205 }
206
207 rtwn_write_4(sc, R92C_TX_IQK_PI(1), 0x82110000);
208 rtwn_write_4(sc, R92C_RX_IQK_PI(1), 0x28110000);
209
210 switch (stage) {
211 case R23B_IQK_TX:
212 rtwn_write_4(sc, R92C_IQK_AGC_RSP, 0x00462911);
213 break;
214 case R23B_IQK_TX_RX:
215 rtwn_write_4(sc, R92C_IQK_AGC_RSP, 0x0046a911);
216 break;
217 case R23B_IQK_RX:
218 rtwn_write_4(sc, R92C_IQK_AGC_RSP, 0x0046a8d1);
219 break;
220 }
221
222 /* Enter IQK mode. */
223 rtwn_setbits_4(sc, R92C_FPGA0_IQK, ~0xff, 0x80800000);
224
225 rtwn_write_4(sc, R23B_ANT_SEL, rs->bt_antnum == 0 ?
226 R23B_ANT_SEL_S0 : R23B_ANT_SEL_S1);
227
228 /* GNT_BT = 0 */
229 rtwn_write_4(sc, R23B_GNT_BT, 0x00000800);
230
231 /* We're doing LO and IQ calibration in one shot. */
232 rtwn_write_4(sc, R92C_IQK_AGC_PTS, 0xf9000000);
233 rtwn_write_4(sc, R92C_IQK_AGC_PTS, 0xf8000000);
234
235 rtwn_delay(sc, 20000); /* 20ms */
236
237 /* Restore RF path. */
238 rtwn_write_4(sc, R23B_ANT_SEL, rf_path);
239
240 /* GNT_BT = 1 */
241 rtwn_write_4(sc, R23B_GNT_BT, 0x00001800);
242
243 /* Leave IQK mode. */
244 rtwn_setbits_4(sc, R92C_FPGA0_IQK, ~0xff, 0);
245 }
246
247 static bool
r23b_iq_calib_get_tx_result(struct rtwn_softc * sc,struct r23b_iqk_result * tx_result)248 r23b_iq_calib_get_tx_result(struct rtwn_softc *sc,
249 struct r23b_iqk_result *tx_result)
250 {
251 uint32_t val;
252
253 val = rtwn_read_4(sc, R92C_RX_POWER_IQK_AFTER(0));
254 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: rx_after (%#x): %#x\n",
255 __func__, R92C_RX_POWER_IQK_AFTER(0), val);
256 if (val & 0x10000000)
257 return (false);
258
259 val = rtwn_read_4(sc, R92C_TX_POWER_IQK_BEFORE(0));
260 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: tx_before (%#x): %#x\n",
261 __func__, R92C_TX_POWER_IQK_BEFORE(0), val);
262 val = MS(val, R92C_POWER_IQK_RESULT);
263 if (val == 0x142 || val >= 0x110 || val <= 0xf0)
264 return (false);
265 tx_result->iqk_before = val;
266
267 val = rtwn_read_4(sc, R92C_TX_POWER_IQK_AFTER(0));
268 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: tx_after (%#x): %#x\n",
269 __func__, R92C_TX_POWER_IQK_AFTER(0), val);
270
271 val = MS(val, R92C_POWER_IQK_RESULT);
272 if (val == 0x42)
273 return (false);
274 tx_result->iqk_after = val;
275
276 if ((val & 0x200) != 0)
277 val = 0x400 - val;
278 return (val < 0xf);
279 }
280
281 static bool
r23b_iq_calib_get_rx_result(struct rtwn_softc * sc,struct r23b_iqk_result * rx_result)282 r23b_iq_calib_get_rx_result(struct rtwn_softc *sc,
283 struct r23b_iqk_result *rx_result)
284 {
285 uint32_t iqk_before, iqk_after, val;
286
287 iqk_after = rtwn_read_4(sc, R92C_RX_POWER_IQK_AFTER(0));
288 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: rx_after (%#x): %#x\n",
289 __func__, R92C_RX_POWER_IQK_AFTER(0), iqk_after);
290
291 iqk_after = MS(iqk_after, R92C_POWER_IQK_RESULT);
292
293 iqk_before = rtwn_read_4(sc, R92C_RX_POWER_IQK_BEFORE(0));
294 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: rx_before (%#x): %#x\n",
295 __func__, R92C_RX_POWER_IQK_BEFORE(0), iqk_before);
296
297 iqk_before = MS(iqk_before, R92C_POWER_IQK_RESULT);
298
299 /* Leave IQK mode. */
300 rtwn_setbits_4(sc, R92C_FPGA0_IQK, ~0xff, 0);
301 rtwn_rf_write(sc, 0, 0xdf, 0x780);
302
303 val = (iqk_after & 0x200) != 0 ? 0x400 - iqk_after : iqk_after;
304 if (iqk_after & 0x8000000)
305 return (false);
306
307 if (iqk_before == 0x132 || iqk_before >= 0x110 || iqk_before <= 0xf0)
308 return (false);
309
310 if (iqk_after == 0x36)
311 return (false);
312
313 if (val >= 0xf)
314 return (false);
315
316 rx_result->iqk_before = iqk_before;
317 rx_result->iqk_after = iqk_after;
318 return (true);
319 }
320
321 static inline void
r23b_iq_calib_save_regs(struct rtwn_softc * sc,struct r23b_iqk_reg_vals * vals)322 r23b_iq_calib_save_regs(struct rtwn_softc *sc,
323 struct r23b_iqk_reg_vals *vals)
324 {
325 for (int i = 0; i < nitems(r23b_iq_calib_reg_adaa); i++)
326 vals->adaa[i] = rtwn_read_4(sc, r23b_iq_calib_reg_adaa[i]);
327
328 vals->txpause = rtwn_read_1(sc, R92C_TXPAUSE);
329
330 for (int i = 0; i < sizeof(vals->bcn_ctrl); i++)
331 vals->bcn_ctrl[i] = rtwn_read_1(sc, R92C_BCN_CTRL(i));
332
333 vals->gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG);
334
335 for (int i = 0; i < nitems(r23b_iq_calib_reg_iqk_bb); i++)
336 vals->iqk_bb[i] = rtwn_read_4(sc, r23b_iq_calib_reg_iqk_bb[i]);
337 }
338
339 static inline void
r23b_iq_calib_restore_regs(struct rtwn_softc * sc,const struct r23b_iqk_reg_vals * vals)340 r23b_iq_calib_restore_regs(struct rtwn_softc *sc,
341 const struct r23b_iqk_reg_vals *vals)
342 {
343 for (int i = 0; i < nitems(r23b_iq_calib_reg_adaa); i++)
344 rtwn_write_4(sc, r23b_iq_calib_reg_adaa[i], vals->adaa[i]);
345
346 rtwn_write_1(sc, R92C_TXPAUSE, vals->txpause);
347
348 for (int i = 0; i < sizeof(vals->bcn_ctrl); i++)
349 rtwn_write_1(sc, R92C_BCN_CTRL(i), vals->bcn_ctrl[i]);
350
351 rtwn_write_4(sc, R92C_GPIO_MUXCFG, vals->gpio_muxcfg);
352
353 for (int i = 0; i < nitems(r23b_iq_calib_reg_iqk_bb); i++)
354 rtwn_write_4(sc, r23b_iq_calib_reg_iqk_bb[i], vals->iqk_bb[i]);
355 }
356
357 static void
r23b_iq_calib_run(struct rtwn_softc * sc,struct r23b_iqk_result * tx_result,struct r23b_iqk_result * rx_result,const struct r23b_iqk_reg_vals * vals)358 r23b_iq_calib_run(struct rtwn_softc *sc, struct r23b_iqk_result *tx_result,
359 struct r23b_iqk_result *rx_result, const struct r23b_iqk_reg_vals *vals)
360 {
361 struct r23b_softc *rs = sc->sc_priv;
362
363 for (int i = 0; i < nitems(r23b_iq_calib_reg_adaa); i++)
364 rtwn_write_4(sc, r23b_iq_calib_reg_adaa[i], 0x01c00014);
365
366 /* MAC settings */
367
368 rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_AC |
369 R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH);
370
371 for (int i = 0; i < sizeof(vals->bcn_ctrl); i++) {
372 rtwn_write_1(sc, R92C_BCN_CTRL(i),
373 vals->bcn_ctrl[i] & ~R92C_BCN_CTRL_EN_BCN);
374 }
375
376 rtwn_write_1(sc, R92C_GPIO_MUXCFG,
377 vals->gpio_muxcfg & ~R92C_GPIO_MUXCFG_ENBT);
378
379 /* BB settings */
380
381 rtwn_setbits_4(sc, R92C_CCK0_AFESETTING, 0, 0x0f000000);
382 rtwn_write_4(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600);
383 rtwn_write_4(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4);
384 rtwn_write_4(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000);
385
386 /* IQ calibration settings */
387
388 rtwn_setbits_4(sc, R92C_FPGA0_IQK, ~0xff, 0);
389 rtwn_rf_setbits(sc, 0, R88E_RF_WE_LUT, 0, 0x80000);
390 rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x30000);
391 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0x0001f);
392 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0xf7fb7);
393 rtwn_rf_setbits(sc, 0, 0xed, 0, 0x20);
394 rtwn_rf_write(sc, 0, 0x43, 0x60fbd);
395
396 /* Path A Tx IQ calibration. */
397 for (int retry = 0; retry < 2; retry++) {
398 r23b_iq_calib_chain(sc, R23B_IQK_TX);
399
400 if (r23b_iq_calib_get_tx_result(sc, tx_result)) {
401 rtwn_setbits_4(sc, R92C_FPGA0_IQK, ~0xff, 0);
402 break;
403 }
404
405 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
406 "%s: Tx failed, retry=%d\n", __func__, retry);
407 }
408
409 /* Path A Rx IQ calibration. */
410 for (int retry = 0; retry < 2; retry++) {
411 struct r23b_iqk_result result;
412
413 r23b_iq_calib_chain(sc, R23B_IQK_TX_RX);
414 if (!r23b_iq_calib_get_tx_result(sc, &result)) {
415 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
416 "%s: Rx (Tx) failed, retry=%d\n", __func__, retry);
417 continue;
418 }
419
420 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
421 "%s: writing %#x to TX_IQK\n", __func__,
422 0x80007c00 | (result.iqk_before << 16) | result.iqk_after);
423
424 rtwn_write_4(sc, R92C_TX_IQK,
425 0x80007c00 | (result.iqk_before << 16) | result.iqk_after);
426
427 r23b_iq_calib_chain(sc, R23B_IQK_RX);
428 if (!r23b_iq_calib_get_rx_result(sc, rx_result)) {
429 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
430 "%s: Rx failed, retry=%d\n", __func__, retry);
431 continue;
432 }
433
434 break;
435 }
436
437 if (rs->bt_antnum == 0) {
438 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
439 "%s: path B IQK not implemented!\n", __func__);
440 }
441
442 rtwn_setbits_4(sc, R92C_FPGA0_IQK, ~0xff, 0);
443 }
444
445 static bool
r23b_iq_calib_compare_results(struct r23b_iqk_result * tx_result1,struct r23b_iqk_result * rx_result1,struct r23b_iqk_result * tx_result2,struct r23b_iqk_result * rx_result2,struct r23b_iqk_result ** tx_candidate,struct r23b_iqk_result ** rx_candidate)446 r23b_iq_calib_compare_results(
447 struct r23b_iqk_result *tx_result1, struct r23b_iqk_result *rx_result1,
448 struct r23b_iqk_result *tx_result2, struct r23b_iqk_result *rx_result2,
449 struct r23b_iqk_result **tx_candidate,
450 struct r23b_iqk_result **rx_candidate) {
451 uint32_t diff;
452 bool tx_good = false;
453
454 diff = abs(tx_result1->iqk_before - tx_result2->iqk_before);
455 if (diff > R23B_IQK_MAX_TOLERANCE)
456 goto rx_compare;
457
458 diff = abs(R23B_IQK_SIGN(tx_result1->iqk_after) -
459 R23B_IQK_SIGN(tx_result2->iqk_after));
460 if (diff <= R23B_IQK_MAX_TOLERANCE) {
461 *tx_candidate = tx_result1;
462 tx_good = true;
463 }
464
465 rx_compare:
466 diff = abs(rx_result1->iqk_before - rx_result2->iqk_before);
467 if (diff > R23B_IQK_MAX_TOLERANCE) {
468 if (tx_good &&
469 rx_result1->iqk_before + rx_result1->iqk_after == 0)
470 *tx_candidate = tx_result2;
471
472 return (false);
473 }
474
475 diff = abs(R23B_IQK_SIGN(rx_result1->iqk_after) -
476 R23B_IQK_SIGN(rx_result2->iqk_after));
477 if (diff > R23B_IQK_MAX_TOLERANCE)
478 return (false);
479
480 *rx_candidate = rx_result1;
481 return (tx_good);
482 }
483
484 void
r23b_iq_calib(struct rtwn_softc * sc)485 r23b_iq_calib(struct rtwn_softc *sc)
486 {
487 struct r23b_iqk_reg_vals vals;
488 struct r23b_iqk_result tx_result[3] = { 0 };
489 struct r23b_iqk_result rx_result[3] = { 0 };
490 struct r23b_iqk_result *tx_candidate = NULL, *rx_candidate = NULL;
491 uint32_t oldval, val;
492 uint32_t gnt_bt;
493
494 #ifndef RTWN_WITHOUT_UCODE
495 /* Inform firmware that we're begininng IQK. */
496 r88e_fw_cmd(sc, R23B_CMD_WLAN_CALIB, R23B_CMD_WLAN_CALIB_BEGIN,
497 sizeof(R23B_CMD_WLAN_CALIB_BEGIN));
498 #endif
499
500 /* Save GNT_BT. */
501 gnt_bt = rtwn_read_4(sc, R23B_GNT_BT);
502
503 r23b_iq_calib_save_regs(sc, &vals);
504 r23b_iq_calib_run(sc, &tx_result[0], &rx_result[0], &vals);
505 r23b_iq_calib_run(sc, &tx_result[1], &rx_result[1], &vals);
506 r23b_iq_calib_restore_regs(sc, &vals);
507
508 if (r23b_iq_calib_compare_results(&tx_result[0], &rx_result[0],
509 &tx_result[1], &rx_result[1], &tx_candidate, &rx_candidate)) {
510 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
511 "%s: comparing 0 and 1 succeeded\n", __func__);
512 goto write;
513 }
514
515 r23b_iq_calib_run(sc, &tx_result[2], &rx_result[2], &vals);
516 r23b_iq_calib_restore_regs(sc, &vals);
517
518 if (r23b_iq_calib_compare_results(&tx_result[0], &rx_result[0],
519 &tx_result[2], &rx_result[2], &tx_candidate, &rx_candidate)) {
520 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
521 "%s: comparing 0 and 2 succeeded\n", __func__);
522 goto write;
523 }
524
525 if (!r23b_iq_calib_compare_results(&tx_result[1], &rx_result[1],
526 &tx_result[2], &rx_result[2], &tx_candidate, &rx_candidate)) {
527 /* If no candidate was assigned, set the result to zero. */
528 if (tx_candidate == NULL) {
529 tx_result[0] = (struct r23b_iqk_result){ 0 };
530 tx_candidate = &tx_result[0];
531 }
532
533 if (rx_candidate == NULL) {
534 rx_result[0] = (struct r23b_iqk_result){ 0 };
535 rx_candidate = &rx_result[0];
536 }
537
538 if (tx_candidate->iqk_before == 0 &&
539 tx_candidate->iqk_after == 0 &&
540 rx_candidate->iqk_before == 0 &&
541 rx_candidate->iqk_after == 0) {
542 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
543 "%s: IQK failed\n", __func__);
544 goto done;
545 }
546
547 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
548 "%s: comparison failed but a candidate was assigned\n",
549 __func__);
550 } else {
551 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
552 "%s: comparing 1 and 2 succeeded\n", __func__);
553 }
554
555 write:
556 RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: IQK candidate dump:\n"
557 "\ttx_candidate->iqk_before 0x%x\ttx_candidate->iqk_after 0x%x\n"
558 "\trx_candidate->iqk_before 0x%x\trx_candidate->iqk_after 0x%x\n",
559 __func__, tx_candidate->iqk_before, tx_candidate->iqk_after,
560 rx_candidate->iqk_before, rx_candidate->iqk_after);
561
562 /*
563 * Don't write both the tx and rx configuration
564 * values if tx IQK failed.
565 */
566 if (tx_candidate->iqk_before == 0)
567 goto done;
568
569 /* Write path A values */
570
571 oldval = rtwn_read_4(sc, R92C_OFDM0_TXIQIMBALANCE(0));
572 oldval = (oldval >> 22) & 0x3ff;
573
574 val = (R23B_IQK_SIGN(tx_candidate->iqk_before) * oldval) >> 7;
575 rtwn_setbits_4(sc, R92C_OFDM0_TXIQIMBALANCE(0), 0x3ff,
576 (val >> 1) & 0x3ff);
577 rtwn_setbits_4(sc, R92C_OFDM0_ECCATHRESHOLD, 0x80000000, val << 31);
578
579 val = (R23B_IQK_SIGN(tx_candidate->iqk_after) * oldval) >> 7;
580 rtwn_setbits_4(sc, R92C_TX_POWER_IQK_BEFORE(0),
581 0xf0000000, (((val >> 1) & 0x3c0) >> 6) << 28);
582 rtwn_setbits_4(sc, R92C_OFDM0_TXIQIMBALANCE(0),
583 0x3f0000, ((val >> 1) & 0x3f) << 16);
584 rtwn_setbits_4(sc, R92C_OFDM0_ECCATHRESHOLD,
585 0x10000000, (val << 29) & 0x1);
586
587 /* Skip the rx configuration values if rx IQK failed. */
588 if (rx_candidate->iqk_before == 0)
589 goto done;
590
591 val = rx_candidate->iqk_after & 0x3f;
592 rtwn_setbits_4(sc, R92C_OFDM0_RXIQIMBALANCE(0), 0x3ff,
593 rx_candidate->iqk_before);
594 rtwn_setbits_4(sc, R92C_OFDM0_RXIQIMBALANCE(0), 0xfc00, val << 10);
595
596 val = (rx_candidate->iqk_after >> 6) & 0xf;
597 rtwn_setbits_4(sc, R92C_OFDM0_RXIQEXTANTA, 0xf0000000, val << 28);
598 done:
599 /* Restore GNT_BT. */
600 rtwn_write_4(sc, R23B_GNT_BT, gnt_bt);
601
602 rtwn_rf_setbits(sc, 0, R88E_RF_WE_LUT, 0, 0x80000);
603 rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x18000);
604 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0x0001f);
605 rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0xe6177);
606 rtwn_rf_setbits(sc, 0, 0xed, 0, 0x20);
607 rtwn_rf_write(sc, 0, 0x43, 0x300bd);
608
609 #ifndef RTWN_WITHOUT_UCODE
610 /* Inform firmware that we're done. */
611 r88e_fw_cmd(sc, R23B_CMD_WLAN_CALIB, R23B_CMD_WLAN_CALIB_END,
612 sizeof(R23B_CMD_WLAN_CALIB_END));
613 #endif
614 }
615
616 void
r23b_temp_measure(struct rtwn_softc * sc)617 r23b_temp_measure(struct rtwn_softc *sc)
618 {
619 rtwn_rf_setbits(sc, 0, R88E_RF_T_METER, 0, R88E_RF_T_METER_START);
620 }
621