xref: /illumos-gate/usr/src/uts/common/io/arn/arn_calib.c (revision fd7c5980)
1 /*
2  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2008 Atheros Communications Inc.
8  *
9  * Permission to use, copy, modify, and/or distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include "arn_core.h"
23 #include "arn_hw.h"
24 #include "arn_reg.h"
25 #include "arn_phy.h"
26 
27 static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
28 
29 /* We can tune this as we go by monitoring really low values */
30 #define	ATH9K_NF_TOO_LOW	-60
31 
32 /*
33  * AR5416 may return very high value (like -31 dBm), in those cases the nf
34  * is incorrect and we should use the static NF value. Later we can try to
35  * find out why they are reporting these values
36  */
37 
38 /* ARGSUSED */
39 static boolean_t
ath9k_hw_nf_in_range(struct ath_hal * ah,signed short nf)40 ath9k_hw_nf_in_range(struct ath_hal *ah, signed short nf)
41 {
42 	if (nf > ATH9K_NF_TOO_LOW) {
43 		ARN_DBG((ARN_DBG_CALIBRATE,
44 		    "%s: noise floor value detected (%d) is "
45 		    "lower than what we think is a "
46 		    "reasonable value (%d)\n",
47 		    __func__, nf, ATH9K_NF_TOO_LOW));
48 
49 		return (B_FALSE);
50 	}
51 	return (B_TRUE);
52 }
53 
54 static int16_t
ath9k_hw_get_nf_hist_mid(int16_t * nfCalBuffer)55 ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
56 {
57 	int16_t nfval;
58 	int16_t sort[ATH9K_NF_CAL_HIST_MAX];
59 	int i, j;
60 
61 	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
62 		sort[i] = nfCalBuffer[i];
63 
64 	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
65 		for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
66 			if (sort[j] > sort[j - 1]) {
67 				nfval = sort[j];
68 				sort[j] = sort[j - 1];
69 				sort[j - 1] = nfval;
70 			}
71 		}
72 	}
73 	nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
74 
75 	return (nfval);
76 }
77 
78 static void
ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist * h,int16_t * nfarray)79 ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
80     int16_t *nfarray)
81 {
82 	int i;
83 
84 	for (i = 0; i < NUM_NF_READINGS; i++) {
85 		h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
86 
87 		if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
88 			h[i].currIndex = 0;
89 
90 		if (h[i].invalidNFcount > 0) {
91 			if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
92 			    nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
93 				h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
94 			} else {
95 				h[i].invalidNFcount--;
96 				h[i].privNF = nfarray[i];
97 			}
98 		} else {
99 			h[i].privNF =
100 			    ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
101 		}
102 	}
103 }
104 
105 static void
ath9k_hw_do_getnf(struct ath_hal * ah,int16_t nfarray[NUM_NF_READINGS])106 ath9k_hw_do_getnf(struct ath_hal *ah,
107     int16_t nfarray[NUM_NF_READINGS])
108 {
109 	int16_t nf;
110 
111 	if (AR_SREV_9280_10_OR_LATER(ah))
112 		nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
113 	else
114 		nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
115 
116 	if (nf & 0x100)
117 		nf = 0 - ((nf ^ 0x1ff) + 1);
118 	ARN_DBG((ARN_DBG_CALIBRATE,
119 	    "NF calibrated [ctl] [chain 0] is %d\n", nf));
120 	nfarray[0] = nf;
121 
122 	if (AR_SREV_9280_10_OR_LATER(ah))
123 		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
124 		    AR9280_PHY_CH1_MINCCA_PWR);
125 	else
126 		nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
127 		    AR_PHY_CH1_MINCCA_PWR);
128 
129 	if (nf & 0x100)
130 		nf = 0 - ((nf ^ 0x1ff) + 1);
131 	ARN_DBG((ARN_DBG_CALIBRATE,
132 	    "NF calibrated [ctl] [chain 1] is %d\n", nf));
133 	nfarray[1] = nf;
134 
135 	if (!AR_SREV_9280(ah)) {
136 		nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
137 		    AR_PHY_CH2_MINCCA_PWR);
138 		if (nf & 0x100)
139 			nf = 0 - ((nf ^ 0x1ff) + 1);
140 		ARN_DBG((ARN_DBG_CALIBRATE,
141 		    "NF calibrated [ctl] [chain 2] is %d\n", nf));
142 		nfarray[2] = nf;
143 	}
144 
145 	if (AR_SREV_9280_10_OR_LATER(ah))
146 		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
147 		    AR9280_PHY_EXT_MINCCA_PWR);
148 	else
149 		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
150 		    AR_PHY_EXT_MINCCA_PWR);
151 
152 	if (nf & 0x100)
153 		nf = 0 - ((nf ^ 0x1ff) + 1);
154 	ARN_DBG((ARN_DBG_CALIBRATE,
155 	    "NF calibrated [ext] [chain 0] is %d\n", nf));
156 	nfarray[3] = nf;
157 
158 	if (AR_SREV_9280_10_OR_LATER(ah))
159 		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
160 		    AR9280_PHY_CH1_EXT_MINCCA_PWR);
161 	else
162 		nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
163 		    AR_PHY_CH1_EXT_MINCCA_PWR);
164 
165 	if (nf & 0x100)
166 		nf = 0 - ((nf ^ 0x1ff) + 1);
167 	ARN_DBG((ARN_DBG_CALIBRATE,
168 	    "NF calibrated [ext] [chain 1] is %d\n", nf));
169 	nfarray[4] = nf;
170 
171 	if (!AR_SREV_9280(ah)) {
172 		nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
173 		    AR_PHY_CH2_EXT_MINCCA_PWR);
174 		if (nf & 0x100)
175 			nf = 0 - ((nf ^ 0x1ff) + 1);
176 		ARN_DBG((ARN_DBG_CALIBRATE,
177 		    "NF calibrated [ext] [chain 2] is %d\n", nf));
178 		nfarray[5] = nf;
179 	}
180 }
181 
182 static boolean_t
getNoiseFloorThresh(struct ath_hal * ah,const struct ath9k_channel * chan,int16_t * nft)183 getNoiseFloorThresh(struct ath_hal *ah,
184     const struct ath9k_channel *chan,
185     int16_t *nft)
186 {
187 	switch (chan->chanmode) {
188 	case CHANNEL_A:
189 	case CHANNEL_A_HT20:
190 	case CHANNEL_A_HT40PLUS:
191 	case CHANNEL_A_HT40MINUS:
192 		*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5);
193 		break;
194 	case CHANNEL_B:
195 	case CHANNEL_G:
196 	case CHANNEL_G_HT20:
197 	case CHANNEL_G_HT40PLUS:
198 	case CHANNEL_G_HT40MINUS:
199 		*nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2);
200 		break;
201 	default:
202 		ARN_DBG((ARN_DBG_CHANNEL,
203 		    "%s: invalid channel flags 0x%x\n", __func__,
204 		    chan->channelFlags));
205 		return (B_FALSE);
206 	}
207 
208 	return (B_TRUE);
209 }
210 
211 static void
ath9k_hw_setup_calibration(struct ath_hal * ah,struct hal_cal_list * currCal)212 ath9k_hw_setup_calibration(struct ath_hal *ah,
213     struct hal_cal_list *currCal)
214 {
215 	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
216 	    AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
217 	    currCal->calData->calCountMax);
218 
219 	switch (currCal->calData->calType) {
220 	case IQ_MISMATCH_CAL:
221 		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
222 		ARN_DBG((ARN_DBG_CALIBRATE,
223 		    "%s: starting IQ Mismatch Calibration\n",
224 		    __func__));
225 		break;
226 	case ADC_GAIN_CAL:
227 		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
228 		ARN_DBG((ARN_DBG_CALIBRATE,
229 		    "%s: starting ADC Gain Calibration\n", __func__));
230 		break;
231 	case ADC_DC_CAL:
232 		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
233 		ARN_DBG((ARN_DBG_CALIBRATE,
234 		    "%s: starting ADC DC Calibration\n", __func__));
235 		break;
236 	case ADC_DC_INIT_CAL:
237 		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
238 		ARN_DBG((ARN_DBG_CALIBRATE,
239 		    "%s: starting Init ADC DC Calibration\n",
240 		    __func__));
241 		break;
242 	}
243 
244 	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
245 	    AR_PHY_TIMING_CTRL4_DO_CAL);
246 }
247 
248 static void
ath9k_hw_reset_calibration(struct ath_hal * ah,struct hal_cal_list * currCal)249 ath9k_hw_reset_calibration(struct ath_hal *ah,
250     struct hal_cal_list *currCal)
251 {
252 	struct ath_hal_5416 *ahp = AH5416(ah);
253 	int i;
254 
255 	ath9k_hw_setup_calibration(ah, currCal);
256 
257 	currCal->calState = CAL_RUNNING;
258 
259 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
260 		ahp->ah_Meas0.sign[i] = 0;
261 		ahp->ah_Meas1.sign[i] = 0;
262 		ahp->ah_Meas2.sign[i] = 0;
263 		ahp->ah_Meas3.sign[i] = 0;
264 	}
265 
266 	ahp->ah_CalSamples = 0;
267 }
268 
269 static void
ath9k_hw_per_calibration(struct ath_hal * ah,struct ath9k_channel * ichan,uint8_t rxchainmask,struct hal_cal_list * currCal,boolean_t * isCalDone)270 ath9k_hw_per_calibration(struct ath_hal *ah,
271     struct ath9k_channel *ichan,
272     uint8_t rxchainmask,
273     struct hal_cal_list *currCal,
274     boolean_t *isCalDone)
275 {
276 	struct ath_hal_5416 *ahp = AH5416(ah);
277 
278 	*isCalDone = B_FALSE;
279 
280 	if (currCal->calState == CAL_RUNNING) {
281 		if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
282 		    AR_PHY_TIMING_CTRL4_DO_CAL)) {
283 
284 			currCal->calData->calCollect(ah);
285 			ahp->ah_CalSamples++;
286 
287 			if (ahp->ah_CalSamples >=
288 			    currCal->calData->calNumSamples) {
289 				int i, numChains = 0;
290 				for (i = 0; i < AR5416_MAX_CHAINS; i++) {
291 					if (rxchainmask & (1 << i))
292 						numChains++;
293 				}
294 
295 				currCal->calData->calPostProc(ah, numChains);
296 				ichan->CalValid |= currCal->calData->calType;
297 				currCal->calState = CAL_DONE;
298 				*isCalDone = B_TRUE;
299 			} else {
300 				ath9k_hw_setup_calibration(ah, currCal);
301 			}
302 		}
303 	} else if (!(ichan->CalValid & currCal->calData->calType)) {
304 		ath9k_hw_reset_calibration(ah, currCal);
305 	}
306 }
307 
308 static boolean_t
ath9k_hw_iscal_supported(struct ath_hal * ah,struct ath9k_channel * chan,enum hal_cal_types calType)309 ath9k_hw_iscal_supported(struct ath_hal *ah,
310     struct ath9k_channel *chan,
311     enum hal_cal_types calType)
312 {
313 	struct ath_hal_5416 *ahp = AH5416(ah);
314 	boolean_t retval = B_FALSE;
315 
316 	switch (calType & ahp->ah_suppCals) {
317 	case IQ_MISMATCH_CAL:
318 		if (!IS_CHAN_B(chan))
319 			retval = B_TRUE;
320 		break;
321 	case ADC_GAIN_CAL:
322 	case ADC_DC_CAL:
323 		if (!IS_CHAN_B(chan) &&
324 		    !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
325 			retval = B_TRUE;
326 		break;
327 	}
328 
329 	return (retval);
330 }
331 
332 static void
ath9k_hw_iqcal_collect(struct ath_hal * ah)333 ath9k_hw_iqcal_collect(struct ath_hal *ah)
334 {
335 	struct ath_hal_5416 *ahp = AH5416(ah);
336 	int i;
337 
338 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
339 		ahp->ah_totalPowerMeasI[i] +=
340 		    REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
341 		ahp->ah_totalPowerMeasQ[i] +=
342 		    REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
343 		ahp->ah_totalIqCorrMeas[i] +=
344 		    (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
345 		ARN_DBG((ARN_DBG_CALIBRATE,
346 		    "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
347 		    ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
348 		    ahp->ah_totalPowerMeasQ[i],
349 		    ahp->ah_totalIqCorrMeas[i]));
350 	}
351 }
352 
353 static void
ath9k_hw_adc_gaincal_collect(struct ath_hal * ah)354 ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
355 {
356 	struct ath_hal_5416 *ahp = AH5416(ah);
357 	int i;
358 
359 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
360 		ahp->ah_totalAdcIOddPhase[i] +=
361 		    REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
362 		ahp->ah_totalAdcIEvenPhase[i] +=
363 		    REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
364 		ahp->ah_totalAdcQOddPhase[i] +=
365 		    REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
366 		ahp->ah_totalAdcQEvenPhase[i] +=
367 		    REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
368 		ARN_DBG((ARN_DBG_CALIBRATE,
369 		    "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
370 		    "oddq=0x%08x; evenq=0x%08x;\n",
371 		    ahp->ah_CalSamples, i,
372 		    ahp->ah_totalAdcIOddPhase[i],
373 		    ahp->ah_totalAdcIEvenPhase[i],
374 		    ahp->ah_totalAdcQOddPhase[i],
375 		    ahp->ah_totalAdcQEvenPhase[i]));
376 	}
377 }
378 
379 static void
ath9k_hw_adc_dccal_collect(struct ath_hal * ah)380 ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
381 {
382 	struct ath_hal_5416 *ahp = AH5416(ah);
383 	int i;
384 
385 	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
386 		ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
387 		    (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
388 		ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
389 		    (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
390 		ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
391 		    (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
392 		ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
393 		    (int32_t)REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
394 		ARN_DBG((ARN_DBG_CALIBRATE,
395 		    "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
396 		    "oddq=0x%08x; evenq=0x%08x;\n",
397 		    ahp->ah_CalSamples, i,
398 		    ahp->ah_totalAdcDcOffsetIOddPhase[i],
399 		    ahp->ah_totalAdcDcOffsetIEvenPhase[i],
400 		    ahp->ah_totalAdcDcOffsetQOddPhase[i],
401 		    ahp->ah_totalAdcDcOffsetQEvenPhase[i]));
402 	}
403 }
404 
405 static void
ath9k_hw_iqcalibrate(struct ath_hal * ah,uint8_t numChains)406 ath9k_hw_iqcalibrate(struct ath_hal *ah, uint8_t numChains)
407 {
408 	struct ath_hal_5416 *ahp = AH5416(ah);
409 	uint32_t powerMeasQ, powerMeasI, iqCorrMeas;
410 	uint32_t qCoffDenom, iCoffDenom;
411 	int32_t qCoff, iCoff;
412 	int iqCorrNeg, i;
413 
414 	for (i = 0; i < numChains; i++) {
415 		powerMeasI = ahp->ah_totalPowerMeasI[i];
416 		powerMeasQ = ahp->ah_totalPowerMeasQ[i];
417 		iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
418 		ARN_DBG((ARN_DBG_CALIBRATE,
419 		    "Starting IQ Cal and Correction for Chain %d\n",
420 		    i));
421 
422 		ARN_DBG((ARN_DBG_CALIBRATE,
423 		    "Orignal: Chn %diq_corr_meas = 0x%08x\n",
424 		    i, ahp->ah_totalIqCorrMeas[i]));
425 
426 		iqCorrNeg = 0;
427 
428 		if (iqCorrMeas > 0x80000000) {
429 			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
430 			iqCorrNeg = 1;
431 		}
432 
433 		ARN_DBG((ARN_DBG_CALIBRATE,
434 		    "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI));
435 		ARN_DBG((ARN_DBG_CALIBRATE,
436 		    "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ));
437 		ARN_DBG((ARN_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
438 		    iqCorrNeg));
439 
440 		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
441 		qCoffDenom = powerMeasQ / 64;
442 
443 		if (powerMeasQ != 0) {
444 			iCoff = iqCorrMeas / iCoffDenom;
445 			qCoff = powerMeasI / qCoffDenom - 64;
446 
447 			ARN_DBG((ARN_DBG_CALIBRATE,
448 			    "Chn %d iCoff = 0x%08x\n", i, iCoff));
449 			ARN_DBG((ARN_DBG_CALIBRATE,
450 			    "Chn %d qCoff = 0x%08x\n", i, qCoff));
451 
452 			iCoff = iCoff & 0x3f;
453 
454 			ARN_DBG((ARN_DBG_CALIBRATE,
455 			    "New: Chn %d iCoff = 0x%08x\n", i, iCoff));
456 
457 			if (iqCorrNeg == 0x0)
458 				iCoff = 0x40 - iCoff;
459 
460 			if (qCoff > 15)
461 				qCoff = 15;
462 			else if (qCoff <= -16)
463 				qCoff = 16;
464 
465 			ARN_DBG((ARN_DBG_CALIBRATE,
466 			    "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
467 			    i, iCoff, qCoff));
468 
469 			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
470 			    AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
471 			    iCoff);
472 			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
473 			    AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
474 			    qCoff);
475 
476 			ARN_DBG((ARN_DBG_CALIBRATE,
477 			    "IQ Cal and Correction done for Chain %d\n",
478 			    i));
479 		}
480 	}
481 
482 	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
483 	    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
484 }
485 
486 static void
ath9k_hw_adc_gaincal_calibrate(struct ath_hal * ah,uint8_t numChains)487 ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, uint8_t numChains)
488 {
489 	struct ath_hal_5416 *ahp = AH5416(ah);
490 	uint32_t iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset,
491 	    qEvenMeasOffset;
492 	uint32_t qGainMismatch, iGainMismatch, val, i;
493 
494 	for (i = 0; i < numChains; i++) {
495 		iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
496 		iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
497 		qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
498 		qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
499 
500 		ARN_DBG((ARN_DBG_CALIBRATE,
501 		    "Starting ADC Gain Cal for Chain %d\n", i));
502 
503 		ARN_DBG((ARN_DBG_CALIBRATE,
504 		    "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
505 		    iOddMeasOffset));
506 		ARN_DBG((ARN_DBG_CALIBRATE,
507 		    "Chn %d pwr_meas_even_i = 0x%08x\n", i,
508 		    iEvenMeasOffset));
509 		ARN_DBG((ARN_DBG_CALIBRATE,
510 		    "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
511 		    qOddMeasOffset));
512 		ARN_DBG((ARN_DBG_CALIBRATE,
513 		    "Chn %d pwr_meas_even_q = 0x%08x\n", i,
514 		    qEvenMeasOffset));
515 
516 		if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
517 			iGainMismatch =
518 			    ((iEvenMeasOffset * 32) /
519 			    iOddMeasOffset) & 0x3f;
520 			qGainMismatch =
521 			    ((qOddMeasOffset * 32) /
522 			    qEvenMeasOffset) & 0x3f;
523 
524 			ARN_DBG((ARN_DBG_CALIBRATE,
525 			    "Chn %d gain_mismatch_i = 0x%08x\n", i,
526 			    iGainMismatch));
527 			ARN_DBG((ARN_DBG_CALIBRATE,
528 			    "Chn %d gain_mismatch_q = 0x%08x\n", i,
529 			    qGainMismatch));
530 
531 			val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
532 			val &= 0xfffff000;
533 			val |= (qGainMismatch) | (iGainMismatch << 6);
534 			REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
535 
536 			ARN_DBG((ARN_DBG_CALIBRATE,
537 			    "ADC Gain Cal done for Chain %d\n", i));
538 		}
539 	}
540 
541 	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
542 	    REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
543 	    AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
544 }
545 
546 static void
ath9k_hw_adc_dccal_calibrate(struct ath_hal * ah,uint8_t numChains)547 ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, uint8_t numChains)
548 {
549 	struct ath_hal_5416 *ahp = AH5416(ah);
550 	uint32_t iOddMeasOffset, iEvenMeasOffset, val, i;
551 	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
552 	const struct hal_percal_data *calData =
553 	    ahp->ah_cal_list_curr->calData;
554 	uint32_t numSamples =
555 	    (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
556 
557 	for (i = 0; i < numChains; i++) {
558 		iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
559 		iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
560 		qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
561 		qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
562 
563 		ARN_DBG((ARN_DBG_CALIBRATE,
564 		    "Starting ADC DC Offset Cal for Chain %d\n", i));
565 
566 		ARN_DBG((ARN_DBG_CALIBRATE,
567 		    "Chn %d pwr_meas_odd_i = %d\n", i,
568 		    iOddMeasOffset));
569 		ARN_DBG((ARN_DBG_CALIBRATE,
570 		    "Chn %d pwr_meas_even_i = %d\n", i,
571 		    iEvenMeasOffset));
572 		ARN_DBG((ARN_DBG_CALIBRATE,
573 		    "Chn %d pwr_meas_odd_q = %d\n", i,
574 		    qOddMeasOffset));
575 		ARN_DBG((ARN_DBG_CALIBRATE,
576 		    "Chn %d pwr_meas_even_q = %d\n", i,
577 		    qEvenMeasOffset));
578 
579 		iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
580 		    numSamples) & 0x1ff;
581 		qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
582 		    numSamples) & 0x1ff;
583 
584 		ARN_DBG((ARN_DBG_CALIBRATE,
585 		    "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
586 		    iDcMismatch));
587 		ARN_DBG((ARN_DBG_CALIBRATE,
588 		    "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
589 		    qDcMismatch));
590 
591 		val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
592 		val &= 0xc0000fff;
593 		val |= (qDcMismatch << 12) | (iDcMismatch << 21);
594 		REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
595 
596 		ARN_DBG((ARN_DBG_CALIBRATE,
597 		    "ADC DC Offset Cal done for Chain %d\n", i));
598 	}
599 
600 	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
601 	    REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
602 	    AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
603 }
604 
605 void
ath9k_hw_reset_calvalid(struct ath_hal * ah,struct ath9k_channel * chan,boolean_t * isCalDone)606 ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
607     boolean_t *isCalDone)
608 {
609 	struct ath_hal_5416 *ahp = AH5416(ah);
610 	struct ath9k_channel *ichan =
611 	    ath9k_regd_check_channel(ah, chan);
612 	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
613 
614 	*isCalDone = B_TRUE;
615 
616 	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
617 		return;
618 
619 	if (currCal == NULL)
620 		return;
621 
622 	if (ichan == NULL) {
623 		ARN_DBG((ARN_DBG_CALIBRATE,
624 		    "%s: invalid channel %u/0x%x; no mapping\n",
625 		    __func__, chan->channel, chan->channelFlags));
626 		return;
627 	}
628 
629 
630 	if (currCal->calState != CAL_DONE) {
631 		ARN_DBG((ARN_DBG_CALIBRATE,
632 		    "%s: Calibration state incorrect, %d\n",
633 		    __func__, currCal->calState));
634 		return;
635 	}
636 
637 
638 	if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
639 		return;
640 	ARN_DBG((ARN_DBG_CALIBRATE,
641 	    "%s: Resetting Cal %d state for channel %u/0x%x\n",
642 	    __func__, currCal->calData->calType, chan->channel,
643 	    chan->channelFlags));
644 
645 	ichan->CalValid &= ~currCal->calData->calType;
646 	currCal->calState = CAL_WAITING;
647 
648 	*isCalDone = B_FALSE;
649 }
650 
651 void
ath9k_hw_start_nfcal(struct ath_hal * ah)652 ath9k_hw_start_nfcal(struct ath_hal *ah)
653 {
654 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
655 	    AR_PHY_AGC_CONTROL_ENABLE_NF);
656 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
657 	    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
658 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
659 }
660 
661 /* ARGSUSED */
662 void
ath9k_hw_loadnf(struct ath_hal * ah,struct ath9k_channel * chan)663 ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
664 {
665 	struct ath9k_nfcal_hist *h;
666 	int i, j;
667 	int32_t val;
668 	const uint32_t ar5416_cca_regs[6] = {
669 		AR_PHY_CCA,
670 		AR_PHY_CH1_CCA,
671 		AR_PHY_CH2_CCA,
672 		AR_PHY_EXT_CCA,
673 		AR_PHY_CH1_EXT_CCA,
674 		AR_PHY_CH2_EXT_CCA
675 	};
676 	uint8_t chainmask;
677 
678 	if (AR_SREV_9280(ah))
679 		chainmask = 0x1B;
680 	else
681 		chainmask = 0x3F;
682 
683 #ifdef ARN_NF_PER_CHAN
684 	h = chan->nfCalHist;
685 #else
686 	h = ah->nfCalHist;
687 #endif
688 
689 	for (i = 0; i < NUM_NF_READINGS; i++) {
690 		if (chainmask & (1 << i)) {
691 			val = REG_READ(ah, ar5416_cca_regs[i]);
692 			val &= 0xFFFFFE00;
693 			val |= (((uint32_t)(h[i].privNF) << 1) & 0x1ff);
694 			REG_WRITE(ah, ar5416_cca_regs[i], val);
695 		}
696 	}
697 
698 	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
699 	    AR_PHY_AGC_CONTROL_ENABLE_NF);
700 	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
701 	    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
702 	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
703 
704 	for (j = 0; j < 1000; j++) {
705 		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
706 		    AR_PHY_AGC_CONTROL_NF) == 0)
707 			break;
708 		drv_usecwait(10);
709 	}
710 
711 	for (i = 0; i < NUM_NF_READINGS; i++) {
712 		if (chainmask & (1 << i)) {
713 			val = REG_READ(ah, ar5416_cca_regs[i]);
714 			val &= 0xFFFFFE00;
715 			val |= (((uint32_t)(-50) << 1) & 0x1ff);
716 			REG_WRITE(ah, ar5416_cca_regs[i], val);
717 		}
718 	}
719 }
720 
721 int16_t
ath9k_hw_getnf(struct ath_hal * ah,struct ath9k_channel * chan)722 ath9k_hw_getnf(struct ath_hal *ah, struct ath9k_channel *chan)
723 {
724 	int16_t nf, nfThresh;
725 	int16_t nfarray[NUM_NF_READINGS] = { 0 };
726 	struct ath9k_nfcal_hist *h;
727 
728 	chan->channelFlags &= (~CHANNEL_CW_INT);
729 	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
730 		ARN_DBG((ARN_DBG_CALIBRATE, "arn: "
731 		    "%s: NF did not complete in calibration window\n",
732 		    __func__));
733 		nf = 0;
734 		chan->rawNoiseFloor = nf;
735 		return (chan->rawNoiseFloor);
736 	} else {
737 		ath9k_hw_do_getnf(ah, nfarray);
738 		nf = nfarray[0];
739 		if (getNoiseFloorThresh(ah, chan, &nfThresh) &&
740 		    nf > nfThresh) {
741 			ARN_DBG((ARN_DBG_CALIBRATE, "arn: "
742 			    "%s: noise floor failed detected; "
743 			    "detected %d, threshold %d\n", __func__,
744 			    nf, nfThresh));
745 			chan->channelFlags |= CHANNEL_CW_INT;
746 		}
747 	}
748 
749 #ifdef ARN_NF_PER_CHAN
750 	h = chan->nfCalHist;
751 #else
752 	h = ah->nfCalHist;
753 #endif
754 
755 	ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
756 	chan->rawNoiseFloor = h[0].privNF;
757 
758 	return (chan->rawNoiseFloor);
759 }
760 
761 void
ath9k_init_nfcal_hist_buffer(struct ath_hal * ah)762 ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
763 {
764 	int i, j;
765 	int16_t noise_floor;
766 
767 	if (AR_SREV_9280(ah))
768 		noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
769 	else if (AR_SREV_9285(ah))
770 		noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
771 	else
772 		noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
773 
774 	for (i = 0; i < NUM_NF_READINGS; i++) {
775 		ah->nfCalHist[i].currIndex = 0;
776 		ah->nfCalHist[i].privNF = noise_floor;
777 		ah->nfCalHist[i].invalidNFcount =
778 		    AR_PHY_CCA_FILTERWINDOW_LENGTH;
779 		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
780 			ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
781 		}
782 	}
783 }
784 
785 signed short
ath9k_hw_getchan_noise(struct ath_hal * ah,struct ath9k_channel * chan)786 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
787 {
788 	struct ath9k_channel *ichan;
789 	signed short nf;
790 
791 	ichan = ath9k_regd_check_channel(ah, chan);
792 	if (ichan == NULL) {
793 		ARN_DBG((ARN_DBG_CALIBRATE,
794 		    "%s: invalid channel %u/0x%x; no mapping\n",
795 		    __func__, chan->channel, chan->channelFlags));
796 		return (ATH_DEFAULT_NOISE_FLOOR);
797 	}
798 	if (ichan->rawNoiseFloor == 0) {
799 		enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
800 		nf = NOISE_FLOOR[mode];
801 	} else
802 		nf = ichan->rawNoiseFloor;
803 
804 	if (!ath9k_hw_nf_in_range(ah, nf))
805 		nf = ATH_DEFAULT_NOISE_FLOOR;
806 
807 	return (nf);
808 }
809 
810 boolean_t
ath9k_hw_calibrate(struct ath_hal * ah,struct ath9k_channel * chan,uint8_t rxchainmask,boolean_t longcal,boolean_t * isCalDone)811 ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
812     uint8_t rxchainmask, boolean_t longcal,
813     boolean_t *isCalDone)
814 {
815 	struct ath_hal_5416 *ahp = AH5416(ah);
816 	struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
817 	struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
818 
819 	*isCalDone = B_TRUE;
820 
821 	if (ichan == NULL) {
822 		ARN_DBG((ARN_DBG_CHANNEL,
823 		    "%s: invalid channel %u/0x%x; no mapping\n",
824 		    __func__, chan->channel, chan->channelFlags));
825 		return (B_FALSE);
826 	}
827 
828 	if (currCal &&
829 	    (currCal->calState == CAL_RUNNING ||
830 	    currCal->calState == CAL_WAITING)) {
831 		ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
832 		    isCalDone);
833 		if (*isCalDone) {
834 			ahp->ah_cal_list_curr = currCal = currCal->calNext;
835 
836 			if (currCal->calState == CAL_WAITING) {
837 				*isCalDone = B_FALSE;
838 				ath9k_hw_reset_calibration(ah, currCal);
839 			}
840 		}
841 	}
842 
843 	if (longcal) {
844 		(void) ath9k_hw_getnf(ah, ichan);
845 		ath9k_hw_loadnf(ah, ah->ah_curchan);
846 		ath9k_hw_start_nfcal(ah);
847 
848 		if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
849 			chan->channelFlags |= CHANNEL_CW_INT;
850 			ichan->channelFlags &= ~CHANNEL_CW_INT;
851 		}
852 	}
853 
854 	return (B_TRUE);
855 }
856 
857 /* AR9285 */
858 static inline void
ath9k_hw_9285_pa_cal(struct ath_hal * ah)859 ath9k_hw_9285_pa_cal(struct ath_hal *ah)
860 {
861 
862 	uint32_t regVal;
863 	int i, offset, offs_6_1, offs_0;
864 	uint32_t ccomp_org, reg_field;
865 	uint32_t regList[][2] = {
866 	    { 0x786c, 0 },
867 	    { 0x7854, 0 },
868 	    { 0x7820, 0 },
869 	    { 0x7824, 0 },
870 	    { 0x7868, 0 },
871 	    { 0x783c, 0 },
872 	    { 0x7838, 0 },
873 	};
874 
875 	if (AR_SREV_9285_11(ah)) {
876 		REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
877 		drv_usecwait(10);
878 	}
879 
880 	for (i = 0; i < ARRAY_SIZE(regList); i++)
881 		regList[i][1] = REG_READ(ah, regList[i][0]);
882 
883 	regVal = REG_READ(ah, 0x7834);
884 	regVal &= (~(0x1));
885 	REG_WRITE(ah, 0x7834, regVal);
886 	regVal = REG_READ(ah, 0x9808);
887 	regVal |= (0x1 << 27);
888 	REG_WRITE(ah, 0x9808, regVal);
889 
890 	REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
891 	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
892 	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
893 	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
894 	REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
895 	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
896 	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
897 	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1);
898 	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
899 	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
900 	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
901 	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
902 	ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
903 	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7);
904 
905 	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
906 	drv_usecwait(30);
907 	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
908 	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
909 
910 	for (i = 6; i > 0; i--) {
911 		regVal = REG_READ(ah, 0x7834);
912 		regVal |= (1 << (19 + i));
913 		REG_WRITE(ah, 0x7834, regVal);
914 		drv_usecwait(1);
915 		regVal = REG_READ(ah, 0x7834);
916 		regVal &= (~(0x1 << (19 + i)));
917 		reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
918 		regVal |= (reg_field << (19 + i));
919 		REG_WRITE(ah, 0x7834, regVal);
920 	}
921 
922 	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
923 	drv_usecwait(1);
924 	reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
925 	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
926 	offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
927 	offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
928 
929 	offset = (offs_6_1<<1) | offs_0;
930 	offset = offset - 0;
931 	offs_6_1 = offset>>1;
932 	offs_0 = offset & 1;
933 
934 	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
935 	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
936 
937 	regVal = REG_READ(ah, 0x7834);
938 	regVal |= 0x1;
939 	REG_WRITE(ah, 0x7834, regVal);
940 	regVal = REG_READ(ah, 0x9808);
941 	regVal &= (~(0x1 << 27));
942 	REG_WRITE(ah, 0x9808, regVal);
943 
944 	for (i = 0; i < ARRAY_SIZE(regList); i++)
945 		REG_WRITE(ah, regList[i][0], regList[i][1]);
946 
947 	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
948 
949 	if (AR_SREV_9285_11(ah))
950 		REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
951 
952 }
953 
954 boolean_t
ath9k_hw_init_cal(struct ath_hal * ah,struct ath9k_channel * chan)955 ath9k_hw_init_cal(struct ath_hal *ah,
956     struct ath9k_channel *chan)
957 {
958 	struct ath_hal_5416 *ahp = AH5416(ah);
959 	struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);
960 
961 	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
962 	    REG_READ(ah, AR_PHY_AGC_CONTROL) |
963 	    AR_PHY_AGC_CONTROL_CAL);
964 
965 	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
966 		ARN_DBG((ARN_DBG_CALIBRATE,
967 		    "%s: offset calibration failed to complete in 1ms; "
968 		    "noisy environment?\n", __func__));
969 		return (B_FALSE);
970 	}
971 
972 	if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
973 			ath9k_hw_9285_pa_cal(ah);
974 
975 	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
976 	    REG_READ(ah, AR_PHY_AGC_CONTROL) |
977 	    AR_PHY_AGC_CONTROL_NF);
978 
979 	ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
980 
981 	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
982 		if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
983 			/* LINTED: E_CONSTANT_CONDITION */
984 			INIT_CAL(&ahp->ah_adcGainCalData);
985 			/* LINTED: E_CONSTANT_CONDITION */
986 			INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
987 			ARN_DBG((ARN_DBG_CALIBRATE,
988 			    "%s: enabling ADC Gain Calibration.\n",
989 			    __func__));
990 		}
991 		if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
992 			/* LINTED: E_CONSTANT_CONDITION */
993 			INIT_CAL(&ahp->ah_adcDcCalData);
994 			/* LINTED: E_CONSTANT_CONDITION */
995 			INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
996 			ARN_DBG((ARN_DBG_CALIBRATE,
997 			    "%s: enabling ADC DC Calibration.\n",
998 			    __func__));
999 		}
1000 		if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
1001 			/* LINTED: E_CONSTANT_CONDITION */
1002 			INIT_CAL(&ahp->ah_iqCalData);
1003 			/* LINTED: E_CONSTANT_CONDITION */
1004 			INSERT_CAL(ahp, &ahp->ah_iqCalData);
1005 			ARN_DBG((ARN_DBG_CALIBRATE,
1006 			    "%s: enabling IQ Calibration.\n",
1007 			    __func__));
1008 		}
1009 
1010 		ahp->ah_cal_list_curr = ahp->ah_cal_list;
1011 
1012 		if (ahp->ah_cal_list_curr)
1013 			ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
1014 	}
1015 
1016 	ichan->CalValid = 0;
1017 
1018 	return (B_TRUE);
1019 }
1020 
1021 const struct hal_percal_data iq_cal_multi_sample = {
1022 	IQ_MISMATCH_CAL,
1023 	MAX_CAL_SAMPLES,
1024 	PER_MIN_LOG_COUNT,
1025 	ath9k_hw_iqcal_collect,
1026 	ath9k_hw_iqcalibrate
1027 };
1028 const struct hal_percal_data iq_cal_single_sample = {
1029 	IQ_MISMATCH_CAL,
1030 	MIN_CAL_SAMPLES,
1031 	PER_MAX_LOG_COUNT,
1032 	ath9k_hw_iqcal_collect,
1033 	ath9k_hw_iqcalibrate
1034 };
1035 const struct hal_percal_data adc_gain_cal_multi_sample = {
1036 	ADC_GAIN_CAL,
1037 	MAX_CAL_SAMPLES,
1038 	PER_MIN_LOG_COUNT,
1039 	ath9k_hw_adc_gaincal_collect,
1040 	ath9k_hw_adc_gaincal_calibrate
1041 };
1042 const struct hal_percal_data adc_gain_cal_single_sample = {
1043 	ADC_GAIN_CAL,
1044 	MIN_CAL_SAMPLES,
1045 	PER_MAX_LOG_COUNT,
1046 	ath9k_hw_adc_gaincal_collect,
1047 	ath9k_hw_adc_gaincal_calibrate
1048 };
1049 const struct hal_percal_data adc_dc_cal_multi_sample = {
1050 	ADC_DC_CAL,
1051 	MAX_CAL_SAMPLES,
1052 	PER_MIN_LOG_COUNT,
1053 	ath9k_hw_adc_dccal_collect,
1054 	ath9k_hw_adc_dccal_calibrate
1055 };
1056 const struct hal_percal_data adc_dc_cal_single_sample = {
1057 	ADC_DC_CAL,
1058 	MIN_CAL_SAMPLES,
1059 	PER_MAX_LOG_COUNT,
1060 	ath9k_hw_adc_dccal_collect,
1061 	ath9k_hw_adc_dccal_calibrate
1062 };
1063 const struct hal_percal_data adc_init_dc_cal = {
1064 	ADC_DC_INIT_CAL,
1065 	MIN_CAL_SAMPLES,
1066 	INIT_LOG_COUNT,
1067 	ath9k_hw_adc_dccal_collect,
1068 	ath9k_hw_adc_dccal_calibrate
1069 };
1070