xref: /freebsd/sys/dev/rtwn/rtl8723b/r23b_calib.c (revision 551b7c5e12bfea623a47edf97ad5689732a1233f)
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