calib.c 34.6 KB
Newer Older
S
Sujith 已提交
1
/*
2
 * Copyright (c) 2008-2009 Atheros Communications Inc.
S
Sujith 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

17
#include "hw.h"
S
Sujith 已提交
18 19 20 21 22 23 24 25

/* We can tune this as we go by monitoring really low values */
#define ATH9K_NF_TOO_LOW	-60

/* AR5416 may return very high value (like -31 dBm), in those cases the nf
 * is incorrect and we should use the static NF value. Later we can try to
 * find out why they are reporting these values */

26
static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
S
Sujith 已提交
27 28
{
	if (nf > ATH9K_NF_TOO_LOW) {
29 30 31 32 33
		ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
			  "noise floor value detected (%d) is "
			  "lower than what we think is a "
			  "reasonable value (%d)\n",
			  nf, ATH9K_NF_TOO_LOW);
S
Sujith 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
		return false;
	}
	return true;
}

static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
{
	int16_t nfval;
	int16_t sort[ATH9K_NF_CAL_HIST_MAX];
	int i, j;

	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
		sort[i] = nfCalBuffer[i];

	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
		for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
			if (sort[j] > sort[j - 1]) {
				nfval = sort[j];
				sort[j] = sort[j - 1];
				sort[j - 1] = nfval;
			}
		}
	}
	nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];

	return nfval;
}

static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
					      int16_t *nfarray)
{
	int i;

	for (i = 0; i < NUM_NF_READINGS; i++) {
		h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];

		if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
			h[i].currIndex = 0;

		if (h[i].invalidNFcount > 0) {
			if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
			    nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
				h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
			} else {
				h[i].invalidNFcount--;
				h[i].privNF = nfarray[i];
			}
		} else {
			h[i].privNF =
				ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
		}
	}
	return;
}

89
static void ath9k_hw_do_getnf(struct ath_hw *ah,
S
Sujith 已提交
90 91
			      int16_t nfarray[NUM_NF_READINGS])
{
92
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
93 94 95 96 97 98 99 100 101
	int16_t nf;

	if (AR_SREV_9280_10_OR_LATER(ah))
		nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
	else
		nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);

	if (nf & 0x100)
		nf = 0 - ((nf ^ 0x1ff) + 1);
102 103
	ath_print(common, ATH_DBG_CALIBRATE,
		  "NF calibrated [ctl] [chain 0] is %d\n", nf);
S
Sujith 已提交
104 105
	nfarray[0] = nf;

106 107 108 109 110 111 112
	if (!AR_SREV_9285(ah)) {
		if (AR_SREV_9280_10_OR_LATER(ah))
			nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
					AR9280_PHY_CH1_MINCCA_PWR);
		else
			nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
					AR_PHY_CH1_MINCCA_PWR);
S
Sujith 已提交
113 114 115

		if (nf & 0x100)
			nf = 0 - ((nf ^ 0x1ff) + 1);
116 117
		ath_print(common, ATH_DBG_CALIBRATE,
			  "NF calibrated [ctl] [chain 1] is %d\n", nf);
118 119
		nfarray[1] = nf;

120
		if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
121 122 123 124
			nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
					AR_PHY_CH2_MINCCA_PWR);
			if (nf & 0x100)
				nf = 0 - ((nf ^ 0x1ff) + 1);
125 126
			ath_print(common, ATH_DBG_CALIBRATE,
				  "NF calibrated [ctl] [chain 2] is %d\n", nf);
127 128
			nfarray[2] = nf;
		}
S
Sujith 已提交
129 130 131 132 133 134 135 136 137 138 139
	}

	if (AR_SREV_9280_10_OR_LATER(ah))
		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
			AR9280_PHY_EXT_MINCCA_PWR);
	else
		nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
			AR_PHY_EXT_MINCCA_PWR);

	if (nf & 0x100)
		nf = 0 - ((nf ^ 0x1ff) + 1);
140 141
	ath_print(common, ATH_DBG_CALIBRATE,
		  "NF calibrated [ext] [chain 0] is %d\n", nf);
S
Sujith 已提交
142 143
	nfarray[3] = nf;

144 145 146 147 148 149 150
	if (!AR_SREV_9285(ah)) {
		if (AR_SREV_9280_10_OR_LATER(ah))
			nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
					AR9280_PHY_CH1_EXT_MINCCA_PWR);
		else
			nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
					AR_PHY_CH1_EXT_MINCCA_PWR);
S
Sujith 已提交
151 152 153

		if (nf & 0x100)
			nf = 0 - ((nf ^ 0x1ff) + 1);
154 155
		ath_print(common, ATH_DBG_CALIBRATE,
			  "NF calibrated [ext] [chain 1] is %d\n", nf);
156 157
		nfarray[4] = nf;

158
		if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
159 160 161 162
			nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
					AR_PHY_CH2_EXT_MINCCA_PWR);
			if (nf & 0x100)
				nf = 0 - ((nf ^ 0x1ff) + 1);
163 164
			ath_print(common, ATH_DBG_CALIBRATE,
				  "NF calibrated [ext] [chain 2] is %d\n", nf);
165 166
			nfarray[5] = nf;
		}
S
Sujith 已提交
167 168 169
	}
}

170
static bool getNoiseFloorThresh(struct ath_hw *ah,
171
				enum ieee80211_band band,
S
Sujith 已提交
172 173
				int16_t *nft)
{
174 175
	switch (band) {
	case IEEE80211_BAND_5GHZ:
S
Sujith 已提交
176
		*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
S
Sujith 已提交
177
		break;
178
	case IEEE80211_BAND_2GHZ:
S
Sujith 已提交
179
		*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
S
Sujith 已提交
180 181
		break;
	default:
182
		BUG_ON(1);
S
Sujith 已提交
183 184 185 186 187 188
		return false;
	}

	return true;
}

189
static void ath9k_hw_setup_calibration(struct ath_hw *ah,
190
				       struct ath9k_cal_list *currCal)
S
Sujith 已提交
191
{
192 193
	struct ath_common *common = ath9k_hw_common(ah);

S
Sujith 已提交
194 195 196 197 198 199 200
	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
		      AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
		      currCal->calData->calCountMax);

	switch (currCal->calData->calType) {
	case IQ_MISMATCH_CAL:
		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
201 202
		ath_print(common, ATH_DBG_CALIBRATE,
			  "starting IQ Mismatch Calibration\n");
S
Sujith 已提交
203 204 205
		break;
	case ADC_GAIN_CAL:
		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
206 207
		ath_print(common, ATH_DBG_CALIBRATE,
			  "starting ADC Gain Calibration\n");
S
Sujith 已提交
208 209 210
		break;
	case ADC_DC_CAL:
		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
211 212
		ath_print(common, ATH_DBG_CALIBRATE,
			  "starting ADC DC Calibration\n");
S
Sujith 已提交
213 214 215
		break;
	case ADC_DC_INIT_CAL:
		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
216 217
		ath_print(common, ATH_DBG_CALIBRATE,
			  "starting Init ADC DC Calibration\n");
S
Sujith 已提交
218 219 220 221 222 223 224
		break;
	}

	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
		    AR_PHY_TIMING_CTRL4_DO_CAL);
}

225
static void ath9k_hw_reset_calibration(struct ath_hw *ah,
226
				       struct ath9k_cal_list *currCal)
S
Sujith 已提交
227 228 229 230 231 232 233 234
{
	int i;

	ath9k_hw_setup_calibration(ah, currCal);

	currCal->calState = CAL_RUNNING;

	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
235 236 237 238
		ah->meas0.sign[i] = 0;
		ah->meas1.sign[i] = 0;
		ah->meas2.sign[i] = 0;
		ah->meas3.sign[i] = 0;
S
Sujith 已提交
239 240
	}

241
	ah->cal_samples = 0;
S
Sujith 已提交
242 243
}

S
Sujith 已提交
244
static bool ath9k_hw_per_calibration(struct ath_hw *ah,
S
Sujith 已提交
245 246
				     struct ath9k_channel *ichan,
				     u8 rxchainmask,
247
				     struct ath9k_cal_list *currCal)
S
Sujith 已提交
248
{
S
Sujith 已提交
249
	bool iscaldone = false;
S
Sujith 已提交
250 251 252 253 254 255

	if (currCal->calState == CAL_RUNNING) {
		if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
		      AR_PHY_TIMING_CTRL4_DO_CAL)) {

			currCal->calData->calCollect(ah);
256
			ah->cal_samples++;
S
Sujith 已提交
257

258
			if (ah->cal_samples >= currCal->calData->calNumSamples) {
S
Sujith 已提交
259 260 261 262 263 264 265 266 267
				int i, numChains = 0;
				for (i = 0; i < AR5416_MAX_CHAINS; i++) {
					if (rxchainmask & (1 << i))
						numChains++;
				}

				currCal->calData->calPostProc(ah, numChains);
				ichan->CalValid |= currCal->calData->calType;
				currCal->calState = CAL_DONE;
S
Sujith 已提交
268
				iscaldone = true;
S
Sujith 已提交
269 270 271 272 273 274 275
			} else {
				ath9k_hw_setup_calibration(ah, currCal);
			}
		}
	} else if (!(ichan->CalValid & currCal->calData->calType)) {
		ath9k_hw_reset_calibration(ah, currCal);
	}
S
Sujith 已提交
276 277

	return iscaldone;
S
Sujith 已提交
278 279
}

280
/* Assumes you are talking about the currently configured channel */
281
static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
282
				     enum ath9k_cal_types calType)
S
Sujith 已提交
283
{
284
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
S
Sujith 已提交
285

286
	switch (calType & ah->supp_cals) {
287 288
	case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
		return true;
S
Sujith 已提交
289 290
	case ADC_GAIN_CAL:
	case ADC_DC_CAL:
291 292
		if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
		      conf_is_ht20(conf)))
293
			return true;
S
Sujith 已提交
294 295
		break;
	}
296
	return false;
S
Sujith 已提交
297 298
}

299
static void ath9k_hw_iqcal_collect(struct ath_hw *ah)
S
Sujith 已提交
300 301 302 303
{
	int i;

	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
304
		ah->totalPowerMeasI[i] +=
S
Sujith 已提交
305
			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
306
		ah->totalPowerMeasQ[i] +=
S
Sujith 已提交
307
			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
308
		ah->totalIqCorrMeas[i] +=
S
Sujith 已提交
309
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
310 311 312 313 314
		ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
			  "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
			  ah->cal_samples, i, ah->totalPowerMeasI[i],
			  ah->totalPowerMeasQ[i],
			  ah->totalIqCorrMeas[i]);
S
Sujith 已提交
315 316 317
	}
}

318
static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah)
S
Sujith 已提交
319 320 321 322
{
	int i;

	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
323
		ah->totalAdcIOddPhase[i] +=
S
Sujith 已提交
324
			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
325
		ah->totalAdcIEvenPhase[i] +=
S
Sujith 已提交
326
			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
327
		ah->totalAdcQOddPhase[i] +=
S
Sujith 已提交
328
			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
329
		ah->totalAdcQEvenPhase[i] +=
S
Sujith 已提交
330 331
			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));

332 333 334 335 336 337 338 339
		ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
			  "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
			  "oddq=0x%08x; evenq=0x%08x;\n",
			  ah->cal_samples, i,
			  ah->totalAdcIOddPhase[i],
			  ah->totalAdcIEvenPhase[i],
			  ah->totalAdcQOddPhase[i],
			  ah->totalAdcQEvenPhase[i]);
S
Sujith 已提交
340 341 342
	}
}

343
static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah)
S
Sujith 已提交
344 345 346 347
{
	int i;

	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
348
		ah->totalAdcDcOffsetIOddPhase[i] +=
S
Sujith 已提交
349
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
350
		ah->totalAdcDcOffsetIEvenPhase[i] +=
S
Sujith 已提交
351
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
352
		ah->totalAdcDcOffsetQOddPhase[i] +=
S
Sujith 已提交
353
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
354
		ah->totalAdcDcOffsetQEvenPhase[i] +=
S
Sujith 已提交
355 356
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));

357 358 359 360 361 362 363 364
		ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
			  "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
			  "oddq=0x%08x; evenq=0x%08x;\n",
			  ah->cal_samples, i,
			  ah->totalAdcDcOffsetIOddPhase[i],
			  ah->totalAdcDcOffsetIEvenPhase[i],
			  ah->totalAdcDcOffsetQOddPhase[i],
			  ah->totalAdcDcOffsetQEvenPhase[i]);
S
Sujith 已提交
365 366 367
	}
}

368
static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
S
Sujith 已提交
369
{
370
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
371 372 373 374 375 376
	u32 powerMeasQ, powerMeasI, iqCorrMeas;
	u32 qCoffDenom, iCoffDenom;
	int32_t qCoff, iCoff;
	int iqCorrNeg, i;

	for (i = 0; i < numChains; i++) {
377 378 379
		powerMeasI = ah->totalPowerMeasI[i];
		powerMeasQ = ah->totalPowerMeasQ[i];
		iqCorrMeas = ah->totalIqCorrMeas[i];
S
Sujith 已提交
380

381 382 383
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Starting IQ Cal and Correction for Chain %d\n",
			  i);
S
Sujith 已提交
384

385 386 387
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Orignal: Chn %diq_corr_meas = 0x%08x\n",
			  i, ah->totalIqCorrMeas[i]);
S
Sujith 已提交
388 389 390 391 392 393 394 395

		iqCorrNeg = 0;

		if (iqCorrMeas > 0x80000000) {
			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
			iqCorrNeg = 1;
		}

396 397 398 399 400 401
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
		ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
			  iqCorrNeg);
S
Sujith 已提交
402 403 404 405

		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
		qCoffDenom = powerMeasQ / 64;

V
Vivek Natarajan 已提交
406 407
		if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
		    (qCoffDenom != 0)) {
S
Sujith 已提交
408 409
			iCoff = iqCorrMeas / iCoffDenom;
			qCoff = powerMeasI / qCoffDenom - 64;
410 411 412 413
			ath_print(common, ATH_DBG_CALIBRATE,
				  "Chn %d iCoff = 0x%08x\n", i, iCoff);
			ath_print(common, ATH_DBG_CALIBRATE,
				  "Chn %d qCoff = 0x%08x\n", i, qCoff);
S
Sujith 已提交
414 415

			iCoff = iCoff & 0x3f;
416 417
			ath_print(common, ATH_DBG_CALIBRATE,
				  "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
S
Sujith 已提交
418 419 420 421 422 423 424 425
			if (iqCorrNeg == 0x0)
				iCoff = 0x40 - iCoff;

			if (qCoff > 15)
				qCoff = 15;
			else if (qCoff <= -16)
				qCoff = 16;

426 427 428
			ath_print(common, ATH_DBG_CALIBRATE,
				  "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
				  i, iCoff, qCoff);
S
Sujith 已提交
429 430 431 432 433 434 435

			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
				      AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
				      iCoff);
			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
				      AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
				      qCoff);
436 437 438
			ath_print(common, ATH_DBG_CALIBRATE,
				  "IQ Cal and Correction done for Chain %d\n",
				  i);
S
Sujith 已提交
439 440 441 442 443 444 445
		}
	}

	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
		    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
}

446
static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
S
Sujith 已提交
447
{
448
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
449 450 451 452
	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
	u32 qGainMismatch, iGainMismatch, val, i;

	for (i = 0; i < numChains; i++) {
453 454 455 456
		iOddMeasOffset = ah->totalAdcIOddPhase[i];
		iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
		qOddMeasOffset = ah->totalAdcQOddPhase[i];
		qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
S
Sujith 已提交
457

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Starting ADC Gain Cal for Chain %d\n", i);

		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
			  iOddMeasOffset);
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_even_i = 0x%08x\n", i,
			  iEvenMeasOffset);
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
			  qOddMeasOffset);
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_even_q = 0x%08x\n", i,
			  qEvenMeasOffset);
S
Sujith 已提交
473 474 475 476 477 478 479 480 481

		if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
			iGainMismatch =
				((iEvenMeasOffset * 32) /
				 iOddMeasOffset) & 0x3f;
			qGainMismatch =
				((qOddMeasOffset * 32) /
				 qEvenMeasOffset) & 0x3f;

482 483 484 485 486 487
			ath_print(common, ATH_DBG_CALIBRATE,
				  "Chn %d gain_mismatch_i = 0x%08x\n", i,
				  iGainMismatch);
			ath_print(common, ATH_DBG_CALIBRATE,
				  "Chn %d gain_mismatch_q = 0x%08x\n", i,
				  qGainMismatch);
S
Sujith 已提交
488 489 490 491 492 493

			val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
			val &= 0xfffff000;
			val |= (qGainMismatch) | (iGainMismatch << 6);
			REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);

494 495
			ath_print(common, ATH_DBG_CALIBRATE,
				  "ADC Gain Cal done for Chain %d\n", i);
S
Sujith 已提交
496 497 498 499 500 501 502 503
		}
	}

	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
		  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
}

504
static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
S
Sujith 已提交
505
{
506
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
507 508
	u32 iOddMeasOffset, iEvenMeasOffset, val, i;
	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
509
	const struct ath9k_percal_data *calData =
510
		ah->cal_list_curr->calData;
S
Sujith 已提交
511 512 513 514
	u32 numSamples =
		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;

	for (i = 0; i < numChains; i++) {
515 516 517 518
		iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
		iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
		qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
		qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
S
Sujith 已提交
519

520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
		ath_print(common, ATH_DBG_CALIBRATE,
			   "Starting ADC DC Offset Cal for Chain %d\n", i);

		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_odd_i = %d\n", i,
			  iOddMeasOffset);
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_even_i = %d\n", i,
			  iEvenMeasOffset);
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_odd_q = %d\n", i,
			  qOddMeasOffset);
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d pwr_meas_even_q = %d\n", i,
			  qEvenMeasOffset);
S
Sujith 已提交
535 536 537 538 539 540

		iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
			       numSamples) & 0x1ff;
		qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
			       numSamples) & 0x1ff;

541 542 543 544 545 546
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
			  iDcMismatch);
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
			  qDcMismatch);
S
Sujith 已提交
547 548 549 550 551 552

		val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
		val &= 0xc0000fff;
		val |= (qDcMismatch << 12) | (iDcMismatch << 21);
		REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);

553 554
		ath_print(common, ATH_DBG_CALIBRATE,
			  "ADC DC Offset Cal done for Chain %d\n", i);
S
Sujith 已提交
555 556 557 558 559 560 561
	}

	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
		  AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
}

562
/* This is done for the currently configured channel */
563
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
S
Sujith 已提交
564
{
565 566
	struct ath_common *common = ath9k_hw_common(ah);
	struct ieee80211_conf *conf = &common->hw->conf;
567
	struct ath9k_cal_list *currCal = ah->cal_list_curr;
S
Sujith 已提交
568

569
	if (!ah->curchan)
570
		return true;
S
Sujith 已提交
571 572

	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
573
		return true;
S
Sujith 已提交
574 575

	if (currCal == NULL)
576
		return true;
S
Sujith 已提交
577 578

	if (currCal->calState != CAL_DONE) {
579 580 581
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Calibration state incorrect, %d\n",
			  currCal->calState);
582
		return true;
S
Sujith 已提交
583 584
	}

585 586
	if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
		return true;
S
Sujith 已提交
587

588 589 590
	ath_print(common, ATH_DBG_CALIBRATE,
		  "Resetting Cal %d state for channel %u\n",
		  currCal->calData->calType, conf->channel->center_freq);
S
Sujith 已提交
591

592
	ah->curchan->CalValid &= ~currCal->calData->calType;
S
Sujith 已提交
593 594
	currCal->calState = CAL_WAITING;

595
	return false;
S
Sujith 已提交
596
}
597
EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
S
Sujith 已提交
598

599
void ath9k_hw_start_nfcal(struct ath_hw *ah)
S
Sujith 已提交
600 601 602 603 604 605 606 607
{
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_ENABLE_NF);
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
}

608
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
S
Sujith 已提交
609 610 611 612 613 614 615 616 617 618 619 620
{
	struct ath9k_nfcal_hist *h;
	int i, j;
	int32_t val;
	const u32 ar5416_cca_regs[6] = {
		AR_PHY_CCA,
		AR_PHY_CH1_CCA,
		AR_PHY_CH2_CCA,
		AR_PHY_EXT_CCA,
		AR_PHY_CH1_EXT_CCA,
		AR_PHY_CH2_EXT_CCA
	};
621
	u8 chainmask, rx_chain_status;
S
Sujith 已提交
622

623
	rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
S
Sujith 已提交
624 625
	if (AR_SREV_9285(ah))
		chainmask = 0x9;
626 627 628 629 630 631 632 633 634 635 636 637 638
	else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
		if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
			chainmask = 0x1B;
		else
			chainmask = 0x09;
	} else {
		if (rx_chain_status & 0x4)
			chainmask = 0x3F;
		else if (rx_chain_status & 0x2)
			chainmask = 0x1B;
		else
			chainmask = 0x09;
	}
S
Sujith 已提交
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656

	h = ah->nfCalHist;

	for (i = 0; i < NUM_NF_READINGS; i++) {
		if (chainmask & (1 << i)) {
			val = REG_READ(ah, ar5416_cca_regs[i]);
			val &= 0xFFFFFE00;
			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
			REG_WRITE(ah, ar5416_cca_regs[i], val);
		}
	}

	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_ENABLE_NF);
	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);

657
	for (j = 0; j < 5; j++) {
S
Sujith 已提交
658 659 660
		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
		     AR_PHY_AGC_CONTROL_NF) == 0)
			break;
661
		udelay(50);
S
Sujith 已提交
662 663 664 665 666 667 668 669 670 671 672 673
	}

	for (i = 0; i < NUM_NF_READINGS; i++) {
		if (chainmask & (1 << i)) {
			val = REG_READ(ah, ar5416_cca_regs[i]);
			val &= 0xFFFFFE00;
			val |= (((u32) (-50) << 1) & 0x1ff);
			REG_WRITE(ah, ar5416_cca_regs[i], val);
		}
	}
}

674
int16_t ath9k_hw_getnf(struct ath_hw *ah,
S
Sujith 已提交
675 676
		       struct ath9k_channel *chan)
{
677
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
678 679 680
	int16_t nf, nfThresh;
	int16_t nfarray[NUM_NF_READINGS] = { 0 };
	struct ath9k_nfcal_hist *h;
681
	struct ieee80211_channel *c = chan->chan;
S
Sujith 已提交
682 683 684

	chan->channelFlags &= (~CHANNEL_CW_INT);
	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
685 686
		ath_print(common, ATH_DBG_CALIBRATE,
			  "NF did not complete in calibration window\n");
S
Sujith 已提交
687 688 689 690 691 692
		nf = 0;
		chan->rawNoiseFloor = nf;
		return chan->rawNoiseFloor;
	} else {
		ath9k_hw_do_getnf(ah, nfarray);
		nf = nfarray[0];
693
		if (getNoiseFloorThresh(ah, c->band, &nfThresh)
S
Sujith 已提交
694
		    && nf > nfThresh) {
695 696 697 698
			ath_print(common, ATH_DBG_CALIBRATE,
				  "noise floor failed detected; "
				  "detected %d, threshold %d\n",
				  nf, nfThresh);
S
Sujith 已提交
699 700 701 702 703 704 705 706 707 708 709 710
			chan->channelFlags |= CHANNEL_CW_INT;
		}
	}

	h = ah->nfCalHist;

	ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
	chan->rawNoiseFloor = h[0].privNF;

	return chan->rawNoiseFloor;
}

711
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
S
Sujith 已提交
712 713
{
	int i, j;
714 715 716 717 718 719
	s16 noise_floor;

	if (AR_SREV_9280(ah))
		noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
	else if (AR_SREV_9285(ah))
		noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
720 721
	else if (AR_SREV_9287(ah))
		noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
722 723
	else
		noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
S
Sujith 已提交
724 725 726

	for (i = 0; i < NUM_NF_READINGS; i++) {
		ah->nfCalHist[i].currIndex = 0;
727
		ah->nfCalHist[i].privNF = noise_floor;
S
Sujith 已提交
728 729 730
		ah->nfCalHist[i].invalidNFcount =
			AR_PHY_CCA_FILTERWINDOW_LENGTH;
		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
731
			ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
S
Sujith 已提交
732 733 734 735
		}
	}
}

736
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
S
Sujith 已提交
737 738 739
{
	s16 nf;

740
	if (chan->rawNoiseFloor == 0)
741 742
		nf = -96;
	else
743
		nf = chan->rawNoiseFloor;
S
Sujith 已提交
744 745 746 747 748 749

	if (!ath9k_hw_nf_in_range(ah, nf))
		nf = ATH_DEFAULT_NOISE_FLOOR;

	return nf;
}
750
EXPORT_SYMBOL(ath9k_hw_getchan_noise);
S
Sujith 已提交
751

V
Vivek Natarajan 已提交
752
static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah)
753
{
V
Vivek Natarajan 已提交
754 755
	u32 rddata;
	int32_t delta, currPDADC, slope;
756 757 758 759

	rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);

V
Vivek Natarajan 已提交
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
	if (ah->initPDADC == 0 || currPDADC == 0) {
		/*
		 * Zero value indicates that no frames have been transmitted yet,
		 * can't do temperature compensation until frames are transmitted.
		 */
		return;
	} else {
		slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);

		if (slope == 0) { /* to avoid divide by zero case */
			delta = 0;
		} else {
			delta = ((currPDADC - ah->initPDADC)*4) / slope;
		}
		REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
			      AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
		REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
			      AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
	}
}

static void ath9k_olc_temp_compensation(struct ath_hw *ah)
{
	u32 rddata, i;
	int delta, currPDADC, regval;
785

786
	if (OLC_FOR_AR9287_10_LATER) {
V
Vivek Natarajan 已提交
787 788 789 790 791
		ath9k_olc_temp_compensation_9287(ah);
	} else {
		rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
		currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);

792 793 794
		if (ah->initPDADC == 0 || currPDADC == 0) {
			return;
		} else {
V
Vivek Natarajan 已提交
795 796
			if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
				delta = (currPDADC - ah->initPDADC + 4) / 8;
797
			else
V
Vivek Natarajan 已提交
798 799 800 801 802 803 804 805 806 807 808 809 810
				delta = (currPDADC - ah->initPDADC + 5) / 10;

			if (delta != ah->PDADCdelta) {
				ah->PDADCdelta = delta;
				for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
					regval = ah->originalGain[i] - delta;
					if (regval < 0)
						regval = 0;

					REG_RMW_FIELD(ah,
						      AR_PHY_TX_GAIN_TBL1 + i * 4,
						      AR_PHY_TX_GAIN, regval);
				}
811
			}
812 813 814 815
		}
	}
}

816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
{
	u32 regVal;
	unsigned int i;
	u32 regList [][2] = {
		{ 0x786c, 0 },
		{ 0x7854, 0 },
		{ 0x7820, 0 },
		{ 0x7824, 0 },
		{ 0x7868, 0 },
		{ 0x783c, 0 },
		{ 0x7838, 0 } ,
		{ 0x7828, 0 } ,
	};

	for (i = 0; i < ARRAY_SIZE(regList); i++)
		regList[i][1] = REG_READ(ah, regList[i][0]);

	regVal = REG_READ(ah, 0x7834);
	regVal &= (~(0x1));
	REG_WRITE(ah, 0x7834, regVal);
	regVal = REG_READ(ah, 0x9808);
	regVal |= (0x1 << 27);
	REG_WRITE(ah, 0x9808, regVal);

	/* 786c,b23,1, pwddac=1 */
	REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
	/* 7854, b5,1, pdrxtxbb=1 */
	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
	/* 7854, b7,1, pdv2i=1 */
	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
	/* 7854, b8,1, pddacinterface=1 */
	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
	/* 7824,b12,0, offcal=0 */
	REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
	/* 7838, b1,0, pwddb=0 */
	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
	/* 7820,b11,0, enpacal=0 */
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
	/* 7820,b25,1, pdpadrv1=0 */
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
	/* 7820,b24,0, pdpadrv2=0 */
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0);
	/* 7820,b23,0, pdpaout=0 */
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
	/* 783c,b14-16,7, padrvgn2tab_0=7 */
	REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
	/*
	 * 7838,b29-31,0, padrvgn1tab_0=0
	 * does not matter since we turn it off
	 */
	REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0);

	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);

	/* Set:
	 * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
	 * txon=1,paon=1,oscon=1,synthon_force=1
	 */
	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
	udelay(30);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);

	/* find off_6_1; */
	for (i = 6; i >= 0; i--) {
		regVal = REG_READ(ah, 0x7834);
		regVal |= (1 << (20 + i));
		REG_WRITE(ah, 0x7834, regVal);
		udelay(1);
		//regVal = REG_READ(ah, 0x7834);
		regVal &= (~(0x1 << (20 + i)));
		regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
			    << (20 + i));
		REG_WRITE(ah, 0x7834, regVal);
	}

	/*  Empirical offset correction  */
#if 0
	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20);
#endif

	regVal = REG_READ(ah, 0x7834);
	regVal |= 0x1;
	REG_WRITE(ah, 0x7834, regVal);
	regVal = REG_READ(ah, 0x9808);
	regVal &= (~(0x1 << 27));
	REG_WRITE(ah, 0x9808, regVal);

	for (i = 0; i < ARRAY_SIZE(regList); i++)
		REG_WRITE(ah, regList[i][0], regList[i][1]);
}

908
static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
909
{
910
	struct ath_common *common = ath9k_hw_common(ah);
911 912 913 914 915 916 917 918 919 920 921 922 923
	u32 regVal;
	int i, offset, offs_6_1, offs_0;
	u32 ccomp_org, reg_field;
	u32 regList[][2] = {
		{ 0x786c, 0 },
		{ 0x7854, 0 },
		{ 0x7820, 0 },
		{ 0x7824, 0 },
		{ 0x7868, 0 },
		{ 0x783c, 0 },
		{ 0x7838, 0 },
	};

924
	ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
925

S
Sujith 已提交
926 927 928 929 930
	/* PA CAL is not needed for high power solution */
	if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
	    AR5416_EEP_TXGAIN_HIGH_POWER)
		return;

931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
	if (AR_SREV_9285_11(ah)) {
		REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
		udelay(10);
	}

	for (i = 0; i < ARRAY_SIZE(regList); i++)
		regList[i][1] = REG_READ(ah, regList[i][0]);

	regVal = REG_READ(ah, 0x7834);
	regVal &= (~(0x1));
	REG_WRITE(ah, 0x7834, regVal);
	regVal = REG_READ(ah, 0x9808);
	regVal |= (0x1 << 27);
	REG_WRITE(ah, 0x9808, regVal);

	REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
953
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
954 955 956 957 958
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
	ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
959
	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
960 961 962 963 964 965 966 967 968 969 970

	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
	udelay(30);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);

	for (i = 6; i > 0; i--) {
		regVal = REG_READ(ah, 0x7834);
		regVal |= (1 << (19 + i));
		REG_WRITE(ah, 0x7834, regVal);
		udelay(1);
S
Sujith 已提交
971
		regVal = REG_READ(ah, 0x7834);
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
		regVal &= (~(0x1 << (19 + i)));
		reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
		regVal |= (reg_field << (19 + i));
		REG_WRITE(ah, 0x7834, regVal);
	}

	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
	udelay(1);
	reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
	offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
	offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);

	offset = (offs_6_1<<1) | offs_0;
	offset = offset - 0;
	offs_6_1 = offset>>1;
	offs_0 = offset & 1;

990 991 992 993 994 995 996 997 998 999 1000
	if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
		if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
			ah->pacal_info.max_skipcount =
				2 * ah->pacal_info.max_skipcount;
		ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
	} else {
		ah->pacal_info.max_skipcount = 1;
		ah->pacal_info.skipcount = 0;
		ah->pacal_info.prev_offset = offset;
	}

1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);

	regVal = REG_READ(ah, 0x7834);
	regVal |= 0x1;
	REG_WRITE(ah, 0x7834, regVal);
	regVal = REG_READ(ah, 0x9808);
	regVal &= (~(0x1 << 27));
	REG_WRITE(ah, 0x9808, regVal);

	for (i = 0; i < ARRAY_SIZE(regList); i++)
		REG_WRITE(ah, regList[i][0], regList[i][1]);

	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);

	if (AR_SREV_9285_11(ah))
		REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);

}

1021
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
S
Sujith 已提交
1022
			u8 rxchainmask, bool longcal)
1023
{
S
Sujith 已提交
1024
	bool iscaldone = true;
1025
	struct ath9k_cal_list *currCal = ah->cal_list_curr;
1026 1027 1028 1029

	if (currCal &&
	    (currCal->calState == CAL_RUNNING ||
	     currCal->calState == CAL_WAITING)) {
S
Sujith 已提交
1030 1031 1032
		iscaldone = ath9k_hw_per_calibration(ah, chan,
						     rxchainmask, currCal);
		if (iscaldone) {
1033 1034 1035
			ah->cal_list_curr = currCal = currCal->calNext;

			if (currCal->calState == CAL_WAITING) {
S
Sujith 已提交
1036
				iscaldone = false;
1037 1038 1039 1040 1041
				ath9k_hw_reset_calibration(ah, currCal);
			}
		}
	}

1042
	/* Do NF cal only at longer intervals */
1043
	if (longcal) {
1044 1045 1046
		/* Do periodic PAOffset Cal */
		if (AR_SREV_9271(ah))
			ath9k_hw_9271_pa_cal(ah);
1047 1048 1049 1050 1051 1052
		else if (AR_SREV_9285_11_OR_LATER(ah)) {
			if (!ah->pacal_info.skipcount)
				ath9k_hw_9285_pa_cal(ah, false);
			else
				ah->pacal_info.skipcount--;
		}
1053

1054
		if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
1055
			ath9k_olc_temp_compensation(ah);
1056 1057

		/* Get the value from the previous NF cal and update history buffer */
1058
		ath9k_hw_getnf(ah, chan);
1059 1060 1061 1062 1063

		/*
		 * Load the NF from history buffer of the current channel.
		 * NF is slow time-variant, so it is OK to use a historical value.
		 */
1064
		ath9k_hw_loadnf(ah, ah->curchan);
1065

1066 1067 1068
		ath9k_hw_start_nfcal(ah);
	}

S
Sujith 已提交
1069
	return iscaldone;
1070
}
1071
EXPORT_SYMBOL(ath9k_hw_calibrate);
1072

1073
/* Carrier leakage Calibration fix */
1074
static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
1075
{
1076 1077
	struct ath_common *common = ath9k_hw_common(ah);

1078
	REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
S
Sujith 已提交
1079
	if (IS_CHAN_HT20(chan)) {
1080 1081 1082 1083 1084 1085 1086 1087
		REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
		REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
		REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
			    AR_PHY_AGC_CONTROL_FLTR_CAL);
		REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
		REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
				  AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
1088 1089 1090
			ath_print(common, ATH_DBG_CALIBRATE, "offset "
				  "calibration failed to complete in "
				  "1ms; noisy ??\n");
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
			return false;
		}
		REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
		REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
		REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
	}
	REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
	REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
			  0, AH_WAIT_TIMEOUT)) {
1103 1104
		ath_print(common, ATH_DBG_CALIBRATE, "offset calibration "
			  "failed to complete in 1ms; noisy ??\n");
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
		return false;
	}

	REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
	REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);

	return true;
}

1115
bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
S
Sujith 已提交
1116
{
1117 1118
	struct ath_common *common = ath9k_hw_common(ah);

1119
	if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
1120 1121
		if (!ar9285_clc(ah, chan))
			return false;
1122 1123
	} else {
		if (AR_SREV_9280_10_OR_LATER(ah)) {
1124 1125 1126 1127 1128
			if (!AR_SREV_9287_10_OR_LATER(ah))
				REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
					    AR_PHY_ADC_CTL_OFF_PWDADC);
			REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
				    AR_PHY_AGC_CONTROL_FLTR_CAL);
1129
		}
1130

1131
		/* Calibrate the AGC */
1132
		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
1133 1134
			  REG_READ(ah, AR_PHY_AGC_CONTROL) |
			  AR_PHY_AGC_CONTROL_CAL);
1135

1136 1137 1138
		/* Poll for offset calibration complete */
		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
				   0, AH_WAIT_TIMEOUT)) {
1139 1140 1141
			ath_print(common, ATH_DBG_CALIBRATE,
				  "offset calibration failed to "
				  "complete in 1ms; noisy environment?\n");
1142 1143 1144
			return false;
		}

1145
		if (AR_SREV_9280_10_OR_LATER(ah)) {
1146 1147 1148 1149 1150
			if (!AR_SREV_9287_10_OR_LATER(ah))
				REG_SET_BIT(ah, AR_PHY_ADC_CTL,
					    AR_PHY_ADC_CTL_OFF_PWDADC);
			REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
				    AR_PHY_AGC_CONTROL_FLTR_CAL);
1151
		}
1152 1153 1154
	}

	/* Do PA Calibration */
1155
	if (AR_SREV_9285_11_OR_LATER(ah))
1156
		ath9k_hw_9285_pa_cal(ah, true);
1157

1158
	/* Do NF Calibration after DC offset and other calibrations */
S
Sujith 已提交
1159
	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
1160
		  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
S
Sujith 已提交
1161

1162
	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
S
Sujith 已提交
1163

1164
	/* Enable IQ, ADC Gain and ADC DC offset CALs */
S
Sujith 已提交
1165
	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
1166
		if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
1167 1168
			INIT_CAL(&ah->adcgain_caldata);
			INSERT_CAL(ah, &ah->adcgain_caldata);
1169 1170
			ath_print(common, ATH_DBG_CALIBRATE,
				  "enabling ADC Gain Calibration.\n");
S
Sujith 已提交
1171
		}
1172
		if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
1173 1174
			INIT_CAL(&ah->adcdc_caldata);
			INSERT_CAL(ah, &ah->adcdc_caldata);
1175 1176
			ath_print(common, ATH_DBG_CALIBRATE,
				  "enabling ADC DC Calibration.\n");
S
Sujith 已提交
1177
		}
1178
		if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
1179 1180
			INIT_CAL(&ah->iq_caldata);
			INSERT_CAL(ah, &ah->iq_caldata);
1181 1182
			ath_print(common, ATH_DBG_CALIBRATE,
				  "enabling IQ Calibration.\n");
S
Sujith 已提交
1183 1184
		}

1185
		ah->cal_list_curr = ah->cal_list;
S
Sujith 已提交
1186

1187 1188
		if (ah->cal_list_curr)
			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
S
Sujith 已提交
1189 1190
	}

1191
	chan->CalValid = 0;
S
Sujith 已提交
1192 1193 1194 1195

	return true;
}

1196
const struct ath9k_percal_data iq_cal_multi_sample = {
S
Sujith 已提交
1197 1198 1199 1200 1201 1202
	IQ_MISMATCH_CAL,
	MAX_CAL_SAMPLES,
	PER_MIN_LOG_COUNT,
	ath9k_hw_iqcal_collect,
	ath9k_hw_iqcalibrate
};
1203
const struct ath9k_percal_data iq_cal_single_sample = {
S
Sujith 已提交
1204 1205 1206 1207 1208 1209
	IQ_MISMATCH_CAL,
	MIN_CAL_SAMPLES,
	PER_MAX_LOG_COUNT,
	ath9k_hw_iqcal_collect,
	ath9k_hw_iqcalibrate
};
1210
const struct ath9k_percal_data adc_gain_cal_multi_sample = {
S
Sujith 已提交
1211 1212 1213 1214 1215 1216
	ADC_GAIN_CAL,
	MAX_CAL_SAMPLES,
	PER_MIN_LOG_COUNT,
	ath9k_hw_adc_gaincal_collect,
	ath9k_hw_adc_gaincal_calibrate
};
1217
const struct ath9k_percal_data adc_gain_cal_single_sample = {
S
Sujith 已提交
1218 1219 1220 1221 1222 1223
	ADC_GAIN_CAL,
	MIN_CAL_SAMPLES,
	PER_MAX_LOG_COUNT,
	ath9k_hw_adc_gaincal_collect,
	ath9k_hw_adc_gaincal_calibrate
};
1224
const struct ath9k_percal_data adc_dc_cal_multi_sample = {
S
Sujith 已提交
1225 1226 1227 1228 1229 1230
	ADC_DC_CAL,
	MAX_CAL_SAMPLES,
	PER_MIN_LOG_COUNT,
	ath9k_hw_adc_dccal_collect,
	ath9k_hw_adc_dccal_calibrate
};
1231
const struct ath9k_percal_data adc_dc_cal_single_sample = {
S
Sujith 已提交
1232 1233 1234 1235 1236 1237
	ADC_DC_CAL,
	MIN_CAL_SAMPLES,
	PER_MAX_LOG_COUNT,
	ath9k_hw_adc_dccal_collect,
	ath9k_hw_adc_dccal_calibrate
};
1238
const struct ath9k_percal_data adc_init_dc_cal = {
S
Sujith 已提交
1239 1240 1241 1242 1243 1244
	ADC_DC_INIT_CAL,
	MIN_CAL_SAMPLES,
	INIT_LOG_COUNT,
	ath9k_hw_adc_dccal_collect,
	ath9k_hw_adc_dccal_calibrate
};