xref: /freebsd/sys/dev/rtwn/rtl8188e/r88e_calib.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
17453645fSAndriy Voskoboinyk /*-
2*58d3c148SAndriy Voskoboinyk  * Copyright (c) 2016-2019 Andriy Voskoboinyk <avos@FreeBSD.org>
37453645fSAndriy Voskoboinyk  *
47453645fSAndriy Voskoboinyk  * Permission to use, copy, modify, and distribute this software for any
57453645fSAndriy Voskoboinyk  * purpose with or without fee is hereby granted, provided that the above
67453645fSAndriy Voskoboinyk  * copyright notice and this permission notice appear in all copies.
77453645fSAndriy Voskoboinyk  *
87453645fSAndriy Voskoboinyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
97453645fSAndriy Voskoboinyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
107453645fSAndriy Voskoboinyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
117453645fSAndriy Voskoboinyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
127453645fSAndriy Voskoboinyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
137453645fSAndriy Voskoboinyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
147453645fSAndriy Voskoboinyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
157453645fSAndriy Voskoboinyk  */
167453645fSAndriy Voskoboinyk 
177453645fSAndriy Voskoboinyk #include <sys/cdefs.h>
187453645fSAndriy Voskoboinyk #include "opt_wlan.h"
197453645fSAndriy Voskoboinyk 
207453645fSAndriy Voskoboinyk #include <sys/param.h>
217453645fSAndriy Voskoboinyk #include <sys/lock.h>
227453645fSAndriy Voskoboinyk #include <sys/mutex.h>
237453645fSAndriy Voskoboinyk #include <sys/mbuf.h>
247453645fSAndriy Voskoboinyk #include <sys/kernel.h>
257453645fSAndriy Voskoboinyk #include <sys/socket.h>
267453645fSAndriy Voskoboinyk #include <sys/systm.h>
277453645fSAndriy Voskoboinyk #include <sys/malloc.h>
287453645fSAndriy Voskoboinyk #include <sys/queue.h>
297453645fSAndriy Voskoboinyk #include <sys/taskqueue.h>
307453645fSAndriy Voskoboinyk #include <sys/bus.h>
317453645fSAndriy Voskoboinyk #include <sys/endian.h>
327453645fSAndriy Voskoboinyk #include <sys/linker.h>
337453645fSAndriy Voskoboinyk 
347453645fSAndriy Voskoboinyk #include <net/if.h>
357453645fSAndriy Voskoboinyk #include <net/ethernet.h>
367453645fSAndriy Voskoboinyk #include <net/if_media.h>
377453645fSAndriy Voskoboinyk 
387453645fSAndriy Voskoboinyk #include <net80211/ieee80211_var.h>
397453645fSAndriy Voskoboinyk #include <net80211/ieee80211_radiotap.h>
407453645fSAndriy Voskoboinyk 
417453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnreg.h>
427453645fSAndriy Voskoboinyk #include <dev/rtwn/if_rtwnvar.h>
43*58d3c148SAndriy Voskoboinyk #include <dev/rtwn/if_rtwn_debug.h>
447453645fSAndriy Voskoboinyk 
457453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8188e/r88e.h>
467453645fSAndriy Voskoboinyk #include <dev/rtwn/rtl8188e/r88e_reg.h>
477453645fSAndriy Voskoboinyk 
48*58d3c148SAndriy Voskoboinyk /* Registers to save and restore during IQ calibration. */
49*58d3c148SAndriy Voskoboinyk struct r88e_iq_cal_reg_vals {
50*58d3c148SAndriy Voskoboinyk 	uint32_t	adda[16];
51*58d3c148SAndriy Voskoboinyk 	uint8_t		txpause;
52*58d3c148SAndriy Voskoboinyk 	uint8_t		bcn_ctrl[2];
53*58d3c148SAndriy Voskoboinyk 	uint32_t	gpio_muxcfg;
54*58d3c148SAndriy Voskoboinyk 	uint32_t	cck0_afesetting;
55*58d3c148SAndriy Voskoboinyk 	uint32_t	ofdm0_trxpathena;
56*58d3c148SAndriy Voskoboinyk 	uint32_t	ofdm0_trmuxpar;
57*58d3c148SAndriy Voskoboinyk 	uint32_t	fpga0_rfifacesw0;
58*58d3c148SAndriy Voskoboinyk 	uint32_t	fpga0_rfifacesw1;
59*58d3c148SAndriy Voskoboinyk 	uint32_t	fpga0_rfifaceoe0;
60*58d3c148SAndriy Voskoboinyk 	uint32_t	fpga0_rfifaceoe1;
61*58d3c148SAndriy Voskoboinyk 	uint32_t	config_ant0;
62*58d3c148SAndriy Voskoboinyk 	uint32_t	config_ant1;
63*58d3c148SAndriy Voskoboinyk };
64*58d3c148SAndriy Voskoboinyk 
65*58d3c148SAndriy Voskoboinyk static int
r88e_iq_calib_chain(struct rtwn_softc * sc,uint16_t tx[2],uint16_t rx[2])66*58d3c148SAndriy Voskoboinyk r88e_iq_calib_chain(struct rtwn_softc *sc, uint16_t tx[2], uint16_t rx[2])
67*58d3c148SAndriy Voskoboinyk {
68*58d3c148SAndriy Voskoboinyk 	uint32_t status;
69*58d3c148SAndriy Voskoboinyk 
70*58d3c148SAndriy Voskoboinyk 	/* Set Rx IQ calibration mode table. */
71*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_IQK, 0);
72*58d3c148SAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R88E_RF_WE_LUT, 0x800a0);
73*58d3c148SAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x30000);
74*58d3c148SAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0xf);
75*58d3c148SAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0xf117b);
76*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_IQK, 0x80800000);
77*58d3c148SAndriy Voskoboinyk 
78*58d3c148SAndriy Voskoboinyk 	/* IQ calibration settings. */
79*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_TX_IQK, 0x01007c00);
80*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_RX_IQK, 0x81004800);
81*58d3c148SAndriy Voskoboinyk 
82*58d3c148SAndriy Voskoboinyk 	/* IQ calibration settings for chain 0. */
83*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_TX_IQK_TONE(0), 0x10008c1c);
84*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_RX_IQK_TONE(0), 0x30008c1c);
85*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_TX_IQK_PI(0), 0x82160804);
86*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_RX_IQK_PI(0), 0x28160000);
87*58d3c148SAndriy Voskoboinyk 
88*58d3c148SAndriy Voskoboinyk 	/* LO calibration settings. */
89*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_IQK_AGC_RSP, 0x0046a911);
90*58d3c148SAndriy Voskoboinyk 
91*58d3c148SAndriy Voskoboinyk 	/* We're doing LO and IQ calibration in one shot. */
92*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf9000000);
93*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf8000000);
94*58d3c148SAndriy Voskoboinyk 
95*58d3c148SAndriy Voskoboinyk 	/* Give LO and IQ calibrations the time to complete. */
96*58d3c148SAndriy Voskoboinyk 	rtwn_delay(sc, 10000);
97*58d3c148SAndriy Voskoboinyk 
98*58d3c148SAndriy Voskoboinyk 	/* Read IQ calibration status. */
99*58d3c148SAndriy Voskoboinyk 	status = rtwn_bb_read(sc, R92C_RX_POWER_IQK_AFTER(0));
100*58d3c148SAndriy Voskoboinyk 	if (status & (1 << 28))
101*58d3c148SAndriy Voskoboinyk 		return (0);	/* Tx failed. */
102*58d3c148SAndriy Voskoboinyk 
103*58d3c148SAndriy Voskoboinyk 	/* Read Tx IQ calibration results. */
104*58d3c148SAndriy Voskoboinyk 	tx[0] = MS(rtwn_bb_read(sc, R92C_TX_POWER_IQK_BEFORE(0)),
105*58d3c148SAndriy Voskoboinyk 	    R92C_POWER_IQK_RESULT);
106*58d3c148SAndriy Voskoboinyk 	tx[1] = MS(rtwn_bb_read(sc, R92C_TX_POWER_IQK_AFTER(0)),
107*58d3c148SAndriy Voskoboinyk 	    R92C_POWER_IQK_RESULT);
108*58d3c148SAndriy Voskoboinyk 	if (tx[0] == 0x142 || tx[1] == 0x042)
109*58d3c148SAndriy Voskoboinyk 		return (0);	/* Tx failed. */
110*58d3c148SAndriy Voskoboinyk 
111*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_TX_IQK, 0x80007c00 | (tx[0] << 16) | tx[1]);
112*58d3c148SAndriy Voskoboinyk 
113*58d3c148SAndriy Voskoboinyk 	/* Set Rx IQ calibration mode table. */
114*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_IQK, 0);
115*58d3c148SAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R88E_RF_WE_LUT, 0x800a0);
116*58d3c148SAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R92C_RF_RCK_OS, 0x30000);
117*58d3c148SAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(0), 0xf);
118*58d3c148SAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R92C_RF_TXPA_G(1), 0xf7ffa);
119*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_IQK, 0x80800000);
120*58d3c148SAndriy Voskoboinyk 
121*58d3c148SAndriy Voskoboinyk 	/* IQ calibration settings. */
122*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_RX_IQK, 0x01004800);
123*58d3c148SAndriy Voskoboinyk 
124*58d3c148SAndriy Voskoboinyk 	/* IQ calibration settings for chain 0. */
125*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_TX_IQK_TONE(0), 0x30008c1c);
126*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_RX_IQK_TONE(0), 0x10008c1c);
127*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_TX_IQK_PI(0), 0x82160c05);
128*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_RX_IQK_PI(0), 0x28160c05);
129*58d3c148SAndriy Voskoboinyk 
130*58d3c148SAndriy Voskoboinyk 	/* LO calibration settings. */
131*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_IQK_AGC_RSP, 0x0046a911);
132*58d3c148SAndriy Voskoboinyk 
133*58d3c148SAndriy Voskoboinyk 	/* We're doing LO and IQ calibration in one shot. */
134*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf9000000);
135*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_IQK_AGC_PTS, 0xf8000000);
136*58d3c148SAndriy Voskoboinyk 
137*58d3c148SAndriy Voskoboinyk 	/* Give LO and IQ calibrations the time to complete. */
138*58d3c148SAndriy Voskoboinyk 	rtwn_delay(sc, 10000);
139*58d3c148SAndriy Voskoboinyk 
140*58d3c148SAndriy Voskoboinyk 	/* Read IQ calibration status. */
141*58d3c148SAndriy Voskoboinyk 	status = rtwn_bb_read(sc, R92C_RX_POWER_IQK_AFTER(0));
142*58d3c148SAndriy Voskoboinyk 	if (status & (1 << 27))
143*58d3c148SAndriy Voskoboinyk 		return (1);	/* Rx failed. */
144*58d3c148SAndriy Voskoboinyk 
145*58d3c148SAndriy Voskoboinyk 	/* Read Rx IQ calibration results. */
146*58d3c148SAndriy Voskoboinyk 	rx[0] = MS(rtwn_bb_read(sc, R92C_RX_POWER_IQK_BEFORE(0)),
147*58d3c148SAndriy Voskoboinyk 	    R92C_POWER_IQK_RESULT);
148*58d3c148SAndriy Voskoboinyk 	rx[1] = MS(status, R92C_POWER_IQK_RESULT);
149*58d3c148SAndriy Voskoboinyk 	if (rx[0] == 0x132 || rx[1] == 0x036)
150*58d3c148SAndriy Voskoboinyk 		return (1);	/* Rx failed. */
151*58d3c148SAndriy Voskoboinyk 
152*58d3c148SAndriy Voskoboinyk 	return (3);	/* Both Tx and Rx succeeded. */
153*58d3c148SAndriy Voskoboinyk }
154*58d3c148SAndriy Voskoboinyk 
155*58d3c148SAndriy Voskoboinyk static void
r88e_iq_calib_run(struct rtwn_softc * sc,int n,uint16_t tx[2],uint16_t rx[2],struct r88e_iq_cal_reg_vals * vals)156*58d3c148SAndriy Voskoboinyk r88e_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2],
157*58d3c148SAndriy Voskoboinyk      uint16_t rx[2], struct r88e_iq_cal_reg_vals *vals)
158*58d3c148SAndriy Voskoboinyk {
159*58d3c148SAndriy Voskoboinyk 	/* Registers to save and restore during IQ calibration. */
160*58d3c148SAndriy Voskoboinyk 	static const uint16_t reg_adda[16] = {
161*58d3c148SAndriy Voskoboinyk 		0x85c, 0xe6c, 0xe70, 0xe74,
162*58d3c148SAndriy Voskoboinyk 		0xe78, 0xe7c, 0xe80, 0xe84,
163*58d3c148SAndriy Voskoboinyk 		0xe88, 0xe8c, 0xed0, 0xed4,
164*58d3c148SAndriy Voskoboinyk 		0xed8, 0xedc, 0xee0, 0xeec
165*58d3c148SAndriy Voskoboinyk 	};
166*58d3c148SAndriy Voskoboinyk 	int i;
167*58d3c148SAndriy Voskoboinyk 	uint32_t hssi_param1;
168*58d3c148SAndriy Voskoboinyk 
169*58d3c148SAndriy Voskoboinyk 	if (n == 0) {
170*58d3c148SAndriy Voskoboinyk 		for (i = 0; i < nitems(reg_adda); i++)
171*58d3c148SAndriy Voskoboinyk 			vals->adda[i] = rtwn_bb_read(sc, reg_adda[i]);
172*58d3c148SAndriy Voskoboinyk 
173*58d3c148SAndriy Voskoboinyk 		vals->txpause = rtwn_read_1(sc, R92C_TXPAUSE);
174*58d3c148SAndriy Voskoboinyk 		vals->bcn_ctrl[0] = rtwn_read_1(sc, R92C_BCN_CTRL(0));
175*58d3c148SAndriy Voskoboinyk 		vals->bcn_ctrl[1] = rtwn_read_1(sc, R92C_BCN_CTRL(1));
176*58d3c148SAndriy Voskoboinyk 		vals->gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG);
177*58d3c148SAndriy Voskoboinyk 	}
178*58d3c148SAndriy Voskoboinyk 
179*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0);
180*58d3c148SAndriy Voskoboinyk 	for (i = 1; i < nitems(reg_adda); i++)
181*58d3c148SAndriy Voskoboinyk 		rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0);
182*58d3c148SAndriy Voskoboinyk 
183*58d3c148SAndriy Voskoboinyk 	hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0));
184*58d3c148SAndriy Voskoboinyk 	if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
185*58d3c148SAndriy Voskoboinyk 		rtwn_bb_write(sc, R92C_HSSI_PARAM1(0),
186*58d3c148SAndriy Voskoboinyk 		    hssi_param1 | R92C_HSSI_PARAM1_PI);
187*58d3c148SAndriy Voskoboinyk 		rtwn_bb_write(sc, R92C_HSSI_PARAM1(1),
188*58d3c148SAndriy Voskoboinyk 		    hssi_param1 | R92C_HSSI_PARAM1_PI);
189*58d3c148SAndriy Voskoboinyk 	}
190*58d3c148SAndriy Voskoboinyk 
191*58d3c148SAndriy Voskoboinyk 	if (n == 0) {
192*58d3c148SAndriy Voskoboinyk 		vals->cck0_afesetting = rtwn_bb_read(sc, R92C_CCK0_AFESETTING);
193*58d3c148SAndriy Voskoboinyk 		vals->ofdm0_trxpathena =
194*58d3c148SAndriy Voskoboinyk 		    rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
195*58d3c148SAndriy Voskoboinyk 		vals->ofdm0_trmuxpar = rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR);
196*58d3c148SAndriy Voskoboinyk 		vals->fpga0_rfifacesw0 =
197*58d3c148SAndriy Voskoboinyk 		    rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(0));
198*58d3c148SAndriy Voskoboinyk 		vals->fpga0_rfifacesw1 =
199*58d3c148SAndriy Voskoboinyk 		    rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1));
200*58d3c148SAndriy Voskoboinyk 		vals->fpga0_rfifaceoe0 =
201*58d3c148SAndriy Voskoboinyk 		    rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(0));
202*58d3c148SAndriy Voskoboinyk 		vals->fpga0_rfifaceoe1 =
203*58d3c148SAndriy Voskoboinyk 		    rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(1));
204*58d3c148SAndriy Voskoboinyk 		vals->config_ant0 = rtwn_bb_read(sc, R92C_CONFIG_ANT(0));
205*58d3c148SAndriy Voskoboinyk 		vals->config_ant1 = rtwn_bb_read(sc, R92C_CONFIG_ANT(1));
206*58d3c148SAndriy Voskoboinyk 	}
207*58d3c148SAndriy Voskoboinyk 
208*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_CCK0_AFESETTING, 0, 0x0f000000);
209*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600);
210*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4);
211*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000);
212*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACESW(0), 0, 0x04000400);
213*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(0), 0x400, 0);
214*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(1), 0x400, 0);
215*58d3c148SAndriy Voskoboinyk 
216*58d3c148SAndriy Voskoboinyk 	rtwn_write_1(sc, R92C_TXPAUSE,
217*58d3c148SAndriy Voskoboinyk 	    R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH);
218*58d3c148SAndriy Voskoboinyk 	rtwn_write_1(sc, R92C_BCN_CTRL(0),
219*58d3c148SAndriy Voskoboinyk 	    vals->bcn_ctrl[0] & ~R92C_BCN_CTRL_EN_BCN);
220*58d3c148SAndriy Voskoboinyk 	rtwn_write_1(sc, R92C_BCN_CTRL(1),
221*58d3c148SAndriy Voskoboinyk 	    vals->bcn_ctrl[1] & ~R92C_BCN_CTRL_EN_BCN);
222*58d3c148SAndriy Voskoboinyk 	rtwn_write_1(sc, R92C_GPIO_MUXCFG,
223*58d3c148SAndriy Voskoboinyk 	    vals->gpio_muxcfg & ~R92C_GPIO_MUXCFG_ENBT);
224*58d3c148SAndriy Voskoboinyk 
225*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_CONFIG_ANT(0), 0x0f600000);
226*58d3c148SAndriy Voskoboinyk 
227*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_IQK, 0x80800000);
228*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_TX_IQK, 0x01007c00);
229*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_RX_IQK, 0x01004800);
230*58d3c148SAndriy Voskoboinyk 
231*58d3c148SAndriy Voskoboinyk 	/* Run IQ calibration twice. */
232*58d3c148SAndriy Voskoboinyk 	for (i = 0; i < 2; i++) {
233*58d3c148SAndriy Voskoboinyk 		int ret;
234*58d3c148SAndriy Voskoboinyk 
235*58d3c148SAndriy Voskoboinyk 		ret = r88e_iq_calib_chain(sc, tx, rx);
236*58d3c148SAndriy Voskoboinyk 		if (ret == 0) {
237*58d3c148SAndriy Voskoboinyk 			RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: Tx failed.\n",
238*58d3c148SAndriy Voskoboinyk 			    __func__);
239*58d3c148SAndriy Voskoboinyk 			tx[0] = 0xff;
240*58d3c148SAndriy Voskoboinyk 			tx[1] = 0xff;
241*58d3c148SAndriy Voskoboinyk 			rx[0] = 0xff;
242*58d3c148SAndriy Voskoboinyk 			rx[1] = 0xff;
243*58d3c148SAndriy Voskoboinyk 		} else if (ret == 1) {
244*58d3c148SAndriy Voskoboinyk 			RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: Rx failed.\n",
245*58d3c148SAndriy Voskoboinyk 			    __func__);
246*58d3c148SAndriy Voskoboinyk 			rx[0] = 0xff;
247*58d3c148SAndriy Voskoboinyk 			rx[1] = 0xff;
248*58d3c148SAndriy Voskoboinyk 		} else if (ret == 3) {
249*58d3c148SAndriy Voskoboinyk 			RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: Both Tx and Rx"
250*58d3c148SAndriy Voskoboinyk 			    " succeeded.\n", __func__);
251*58d3c148SAndriy Voskoboinyk 		}
252*58d3c148SAndriy Voskoboinyk 	}
253*58d3c148SAndriy Voskoboinyk 
254*58d3c148SAndriy Voskoboinyk 	RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB,
255*58d3c148SAndriy Voskoboinyk 	    "%s: results for run %d: tx[0] 0x%x, tx[1] 0x%x, rx[0] 0x%x, "
256*58d3c148SAndriy Voskoboinyk 	    "rx[1] 0x%x\n", __func__, n, tx[0], tx[1], rx[0], rx[1]);
257*58d3c148SAndriy Voskoboinyk 
258*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_CCK0_AFESETTING, vals->cck0_afesetting);
259*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, vals->ofdm0_trxpathena);
260*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(0), vals->fpga0_rfifacesw0);
261*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), vals->fpga0_rfifacesw1);
262*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, vals->ofdm0_trmuxpar);
263*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(0), vals->fpga0_rfifaceoe0);
264*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(1), vals->fpga0_rfifaceoe1);
265*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_CONFIG_ANT(0), vals->config_ant0);
266*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_CONFIG_ANT(1), vals->config_ant1);
267*58d3c148SAndriy Voskoboinyk 
268*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_FPGA0_IQK, 0);
269*58d3c148SAndriy Voskoboinyk 	rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3);
270*58d3c148SAndriy Voskoboinyk 
271*58d3c148SAndriy Voskoboinyk 	if (n != 0) {
272*58d3c148SAndriy Voskoboinyk 		if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
273*58d3c148SAndriy Voskoboinyk 			rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1);
274*58d3c148SAndriy Voskoboinyk 			rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1);
275*58d3c148SAndriy Voskoboinyk 		}
276*58d3c148SAndriy Voskoboinyk 
277*58d3c148SAndriy Voskoboinyk 		for (i = 0; i < nitems(reg_adda); i++)
278*58d3c148SAndriy Voskoboinyk 			rtwn_bb_write(sc, reg_adda[i], vals->adda[i]);
279*58d3c148SAndriy Voskoboinyk 
280*58d3c148SAndriy Voskoboinyk 		rtwn_write_1(sc, R92C_TXPAUSE, vals->txpause);
281*58d3c148SAndriy Voskoboinyk 		rtwn_write_1(sc, R92C_BCN_CTRL(0), vals->bcn_ctrl[0]);
282*58d3c148SAndriy Voskoboinyk 		rtwn_write_1(sc, R92C_BCN_CTRL(1), vals->bcn_ctrl[1]);
283*58d3c148SAndriy Voskoboinyk 		rtwn_write_4(sc, R92C_GPIO_MUXCFG, vals->gpio_muxcfg);
284*58d3c148SAndriy Voskoboinyk 	}
285*58d3c148SAndriy Voskoboinyk }
286*58d3c148SAndriy Voskoboinyk 
287*58d3c148SAndriy Voskoboinyk #define RTWN_IQ_CAL_MAX_TOLERANCE 5
288*58d3c148SAndriy Voskoboinyk static int
r88e_iq_calib_compare_results(struct rtwn_softc * sc,uint16_t tx1[2],uint16_t rx1[2],uint16_t tx2[2],uint16_t rx2[2])289*58d3c148SAndriy Voskoboinyk r88e_iq_calib_compare_results(struct rtwn_softc *sc, uint16_t tx1[2],
290*58d3c148SAndriy Voskoboinyk     uint16_t rx1[2], uint16_t tx2[2], uint16_t rx2[2])
291*58d3c148SAndriy Voskoboinyk {
292*58d3c148SAndriy Voskoboinyk 	int i, tx_ok, rx_ok;
293*58d3c148SAndriy Voskoboinyk 
294*58d3c148SAndriy Voskoboinyk 	tx_ok = rx_ok = 0;
295*58d3c148SAndriy Voskoboinyk 	for (i = 0; i < 2; i++)	{
296*58d3c148SAndriy Voskoboinyk 		if (tx1[i] == 0xff || tx2[i] == 0xff ||
297*58d3c148SAndriy Voskoboinyk 		    rx1[i] == 0xff || rx2[i] == 0xff)
298*58d3c148SAndriy Voskoboinyk 			continue;
299*58d3c148SAndriy Voskoboinyk 
300*58d3c148SAndriy Voskoboinyk 		tx_ok = (abs(tx1[i] - tx2[i]) <= RTWN_IQ_CAL_MAX_TOLERANCE);
301*58d3c148SAndriy Voskoboinyk 		rx_ok = (abs(rx1[i] - rx2[i]) <= RTWN_IQ_CAL_MAX_TOLERANCE);
302*58d3c148SAndriy Voskoboinyk 	}
303*58d3c148SAndriy Voskoboinyk 
304*58d3c148SAndriy Voskoboinyk 	return (tx_ok && rx_ok);
305*58d3c148SAndriy Voskoboinyk }
306*58d3c148SAndriy Voskoboinyk #undef RTWN_IQ_CAL_MAX_TOLERANCE
307*58d3c148SAndriy Voskoboinyk 
308*58d3c148SAndriy Voskoboinyk static void
r88e_iq_calib_write_results(struct rtwn_softc * sc,uint16_t tx[2],uint16_t rx[2])309*58d3c148SAndriy Voskoboinyk r88e_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2],
310*58d3c148SAndriy Voskoboinyk     uint16_t rx[2])
311*58d3c148SAndriy Voskoboinyk {
312*58d3c148SAndriy Voskoboinyk 	uint32_t reg, val, x;
313*58d3c148SAndriy Voskoboinyk 	long y, tx_c;
314*58d3c148SAndriy Voskoboinyk 
315*58d3c148SAndriy Voskoboinyk 	if (tx[0] == 0xff || tx[1] == 0xff)
316*58d3c148SAndriy Voskoboinyk 		return;
317*58d3c148SAndriy Voskoboinyk 
318*58d3c148SAndriy Voskoboinyk 	reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(0));
319*58d3c148SAndriy Voskoboinyk 	val = ((reg >> 22) & 0x3ff);
320*58d3c148SAndriy Voskoboinyk 	x = tx[0];
321*58d3c148SAndriy Voskoboinyk 	if (x & 0x00000200)
322*58d3c148SAndriy Voskoboinyk 		x |= 0xfffffc00;
323*58d3c148SAndriy Voskoboinyk 	reg = (((x * val) >> 8) & 0x3ff);
324*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(0), 0x3ff, reg);
325*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x80000000,
326*58d3c148SAndriy Voskoboinyk 	    ((x * val) & 0x80) << 24);
327*58d3c148SAndriy Voskoboinyk 
328*58d3c148SAndriy Voskoboinyk 	y = tx[1];
329*58d3c148SAndriy Voskoboinyk 	if (y & 0x00000200)
330*58d3c148SAndriy Voskoboinyk 		y |= 0xfffffc00;
331*58d3c148SAndriy Voskoboinyk 	tx_c = (y * val) >> 8;
332*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_OFDM0_TXAFE(0), 0xf0000000,
333*58d3c148SAndriy Voskoboinyk 	    (tx_c & 0x3c0) << 22);
334*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(0), 0x003f0000,
335*58d3c148SAndriy Voskoboinyk 	    (tx_c & 0x3f) << 16);
336*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x20000000,
337*58d3c148SAndriy Voskoboinyk 	    ((y * val) & 0x80) << 22);
338*58d3c148SAndriy Voskoboinyk 
339*58d3c148SAndriy Voskoboinyk 	if (rx[0] == 0xff || rx[1] == 0xff)
340*58d3c148SAndriy Voskoboinyk 		return;
341*58d3c148SAndriy Voskoboinyk 
342*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(0), 0x3ff,
343*58d3c148SAndriy Voskoboinyk 	    rx[0] & 0x3ff);
344*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(0), 0xfc00,
345*58d3c148SAndriy Voskoboinyk 	    (rx[1] & 0x3f) << 10);
346*58d3c148SAndriy Voskoboinyk 	rtwn_bb_setbits(sc, R92C_OFDM0_RXIQEXTANTA, 0xf0000000,
347*58d3c148SAndriy Voskoboinyk 	    (rx[1] & 0x3c0) << 22);
348*58d3c148SAndriy Voskoboinyk }
349*58d3c148SAndriy Voskoboinyk 
350*58d3c148SAndriy Voskoboinyk #define RTWN_IQ_CAL_NRUN	3
3517453645fSAndriy Voskoboinyk void
r88e_iq_calib(struct rtwn_softc * sc)3527453645fSAndriy Voskoboinyk r88e_iq_calib(struct rtwn_softc *sc)
3537453645fSAndriy Voskoboinyk {
354*58d3c148SAndriy Voskoboinyk 	struct r88e_iq_cal_reg_vals vals;
355*58d3c148SAndriy Voskoboinyk 	uint16_t tx[RTWN_IQ_CAL_NRUN][2], rx[RTWN_IQ_CAL_NRUN][2];
356*58d3c148SAndriy Voskoboinyk 	int n, valid;
357*58d3c148SAndriy Voskoboinyk 
358*58d3c148SAndriy Voskoboinyk 	KASSERT(sc->ntxchains == 1,
359*58d3c148SAndriy Voskoboinyk 	    ("%s: only 1T1R configuration is supported!\n", __func__));
360*58d3c148SAndriy Voskoboinyk 
361*58d3c148SAndriy Voskoboinyk 	valid = 0;
362*58d3c148SAndriy Voskoboinyk 	for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) {
363*58d3c148SAndriy Voskoboinyk 		r88e_iq_calib_run(sc, n, tx[n], rx[n], &vals);
364*58d3c148SAndriy Voskoboinyk 
365*58d3c148SAndriy Voskoboinyk 		if (n == 0)
366*58d3c148SAndriy Voskoboinyk 			continue;
367*58d3c148SAndriy Voskoboinyk 
368*58d3c148SAndriy Voskoboinyk 		/* Valid results remain stable after consecutive runs. */
369*58d3c148SAndriy Voskoboinyk 		valid = r88e_iq_calib_compare_results(sc, tx[n - 1],
370*58d3c148SAndriy Voskoboinyk 		    rx[n - 1], tx[n], rx[n]);
371*58d3c148SAndriy Voskoboinyk 		if (valid)
372*58d3c148SAndriy Voskoboinyk 			break;
3737453645fSAndriy Voskoboinyk 	}
3747453645fSAndriy Voskoboinyk 
375*58d3c148SAndriy Voskoboinyk 	if (valid)
376*58d3c148SAndriy Voskoboinyk 		r88e_iq_calib_write_results(sc, tx[n], rx[n]);
377*58d3c148SAndriy Voskoboinyk }
378*58d3c148SAndriy Voskoboinyk #undef RTWN_IQ_CAL_NRUN
379*58d3c148SAndriy Voskoboinyk 
3807453645fSAndriy Voskoboinyk void
r88e_temp_measure(struct rtwn_softc * sc)3817453645fSAndriy Voskoboinyk r88e_temp_measure(struct rtwn_softc *sc)
3827453645fSAndriy Voskoboinyk {
3837453645fSAndriy Voskoboinyk 	rtwn_rf_write(sc, 0, R88E_RF_T_METER, R88E_RF_T_METER_START);
3847453645fSAndriy Voskoboinyk }
3857453645fSAndriy Voskoboinyk 
3867453645fSAndriy Voskoboinyk uint8_t
r88e_temp_read(struct rtwn_softc * sc)3877453645fSAndriy Voskoboinyk r88e_temp_read(struct rtwn_softc *sc)
3887453645fSAndriy Voskoboinyk {
3897453645fSAndriy Voskoboinyk 	return (MS(rtwn_rf_read(sc, 0, R88E_RF_T_METER),
3907453645fSAndriy Voskoboinyk 	    R88E_RF_T_METER_VAL));
3917453645fSAndriy Voskoboinyk }
392