calib.c 36.7 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"
18
#include "ar9002_phy.h"
S
Sujith 已提交
19 20 21

/* We can tune this as we go by monitoring really low values */
#define ATH9K_NF_TOO_LOW	-60
22
#define AR9285_CLCAL_REDO_THRESH    1
S
Sujith 已提交
23 24 25 26 27

/* 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 */

28
static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
S
Sujith 已提交
29 30
{
	if (nf > ATH9K_NF_TOO_LOW) {
31 32 33 34 35
		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 已提交
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 89 90
		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;
}

91
static void ath9k_hw_do_getnf(struct ath_hw *ah,
S
Sujith 已提交
92 93
			      int16_t nfarray[NUM_NF_READINGS])
{
94
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
95 96 97 98 99 100 101 102 103
	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);
104 105
	ath_print(common, ATH_DBG_CALIBRATE,
		  "NF calibrated [ctl] [chain 0] is %d\n", nf);
106 107 108 109

	if (AR_SREV_9271(ah) && (nf >= -114))
		nf = -116;

S
Sujith 已提交
110 111
	nfarray[0] = nf;

112
	if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
113 114 115 116 117 118
		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 已提交
119 120 121

		if (nf & 0x100)
			nf = 0 - ((nf ^ 0x1ff) + 1);
122 123
		ath_print(common, ATH_DBG_CALIBRATE,
			  "NF calibrated [ctl] [chain 1] is %d\n", nf);
124 125
		nfarray[1] = nf;

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

	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);
146 147
	ath_print(common, ATH_DBG_CALIBRATE,
		  "NF calibrated [ext] [chain 0] is %d\n", nf);
148 149 150 151

	if (AR_SREV_9271(ah) && (nf >= -114))
		nf = -116;

S
Sujith 已提交
152 153
	nfarray[3] = nf;

154
	if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
155 156 157 158 159 160
		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 已提交
161 162 163

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

168
		if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
169 170 171 172
			nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
					AR_PHY_CH2_EXT_MINCCA_PWR);
			if (nf & 0x100)
				nf = 0 - ((nf ^ 0x1ff) + 1);
173 174
			ath_print(common, ATH_DBG_CALIBRATE,
				  "NF calibrated [ext] [chain 2] is %d\n", nf);
175 176
			nfarray[5] = nf;
		}
S
Sujith 已提交
177 178 179
	}
}

180
static bool getNoiseFloorThresh(struct ath_hw *ah,
181
				enum ieee80211_band band,
S
Sujith 已提交
182 183
				int16_t *nft)
{
184 185
	switch (band) {
	case IEEE80211_BAND_5GHZ:
S
Sujith 已提交
186
		*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
S
Sujith 已提交
187
		break;
188
	case IEEE80211_BAND_2GHZ:
S
Sujith 已提交
189
		*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
S
Sujith 已提交
190 191
		break;
	default:
192
		BUG_ON(1);
S
Sujith 已提交
193 194 195 196 197 198
		return false;
	}

	return true;
}

199
static void ath9k_hw_setup_calibration(struct ath_hw *ah,
200
				       struct ath9k_cal_list *currCal)
S
Sujith 已提交
201
{
202 203
	struct ath_common *common = ath9k_hw_common(ah);

S
Sujith 已提交
204 205 206 207 208 209 210
	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);
211 212
		ath_print(common, ATH_DBG_CALIBRATE,
			  "starting IQ Mismatch Calibration\n");
S
Sujith 已提交
213 214 215
		break;
	case ADC_GAIN_CAL:
		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
216 217
		ath_print(common, ATH_DBG_CALIBRATE,
			  "starting ADC Gain Calibration\n");
S
Sujith 已提交
218 219 220
		break;
	case ADC_DC_CAL:
		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
221 222
		ath_print(common, ATH_DBG_CALIBRATE,
			  "starting ADC DC Calibration\n");
S
Sujith 已提交
223 224 225
		break;
	case ADC_DC_INIT_CAL:
		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
226 227
		ath_print(common, ATH_DBG_CALIBRATE,
			  "starting Init ADC DC Calibration\n");
S
Sujith 已提交
228 229 230 231 232 233 234
		break;
	}

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

235
static void ath9k_hw_reset_calibration(struct ath_hw *ah,
236
				       struct ath9k_cal_list *currCal)
S
Sujith 已提交
237 238 239 240 241 242 243 244
{
	int i;

	ath9k_hw_setup_calibration(ah, currCal);

	currCal->calState = CAL_RUNNING;

	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
245 246 247 248
		ah->meas0.sign[i] = 0;
		ah->meas1.sign[i] = 0;
		ah->meas2.sign[i] = 0;
		ah->meas3.sign[i] = 0;
S
Sujith 已提交
249 250
	}

251
	ah->cal_samples = 0;
S
Sujith 已提交
252 253
}

S
Sujith 已提交
254
static bool ath9k_hw_per_calibration(struct ath_hw *ah,
S
Sujith 已提交
255 256
				     struct ath9k_channel *ichan,
				     u8 rxchainmask,
257
				     struct ath9k_cal_list *currCal)
S
Sujith 已提交
258
{
S
Sujith 已提交
259
	bool iscaldone = false;
S
Sujith 已提交
260 261 262 263 264 265

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

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

268
			if (ah->cal_samples >= currCal->calData->calNumSamples) {
S
Sujith 已提交
269 270 271 272 273 274 275 276 277
				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 已提交
278
				iscaldone = true;
S
Sujith 已提交
279 280 281 282 283 284 285
			} else {
				ath9k_hw_setup_calibration(ah, currCal);
			}
		}
	} else if (!(ichan->CalValid & currCal->calData->calType)) {
		ath9k_hw_reset_calibration(ah, currCal);
	}
S
Sujith 已提交
286 287

	return iscaldone;
S
Sujith 已提交
288 289
}

290
/* Assumes you are talking about the currently configured channel */
291
static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
292
				     enum ath9k_cal_types calType)
S
Sujith 已提交
293
{
294
	struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
S
Sujith 已提交
295

296
	switch (calType & ah->supp_cals) {
297 298
	case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
		return true;
S
Sujith 已提交
299 300
	case ADC_GAIN_CAL:
	case ADC_DC_CAL:
301 302
		if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
		      conf_is_ht20(conf)))
303
			return true;
S
Sujith 已提交
304 305
		break;
	}
306
	return false;
S
Sujith 已提交
307 308
}

309
static void ath9k_hw_iqcal_collect(struct ath_hw *ah)
S
Sujith 已提交
310 311 312 313
{
	int i;

	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
314
		ah->totalPowerMeasI[i] +=
S
Sujith 已提交
315
			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
316
		ah->totalPowerMeasQ[i] +=
S
Sujith 已提交
317
			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
318
		ah->totalIqCorrMeas[i] +=
S
Sujith 已提交
319
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
320 321 322 323 324
		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 已提交
325 326 327
	}
}

328
static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah)
S
Sujith 已提交
329 330 331 332
{
	int i;

	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
333
		ah->totalAdcIOddPhase[i] +=
S
Sujith 已提交
334
			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
335
		ah->totalAdcIEvenPhase[i] +=
S
Sujith 已提交
336
			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
337
		ah->totalAdcQOddPhase[i] +=
S
Sujith 已提交
338
			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
339
		ah->totalAdcQEvenPhase[i] +=
S
Sujith 已提交
340 341
			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));

342 343 344 345 346 347 348 349
		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 已提交
350 351 352
	}
}

353
static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah)
S
Sujith 已提交
354 355 356 357
{
	int i;

	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
358
		ah->totalAdcDcOffsetIOddPhase[i] +=
S
Sujith 已提交
359
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
360
		ah->totalAdcDcOffsetIEvenPhase[i] +=
S
Sujith 已提交
361
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
362
		ah->totalAdcDcOffsetQOddPhase[i] +=
S
Sujith 已提交
363
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
364
		ah->totalAdcDcOffsetQEvenPhase[i] +=
S
Sujith 已提交
365 366
			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));

367 368 369 370 371 372 373 374
		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 已提交
375 376 377
	}
}

378
static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
S
Sujith 已提交
379
{
380
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
381 382 383 384 385 386
	u32 powerMeasQ, powerMeasI, iqCorrMeas;
	u32 qCoffDenom, iCoffDenom;
	int32_t qCoff, iCoff;
	int iqCorrNeg, i;

	for (i = 0; i < numChains; i++) {
387 388 389
		powerMeasI = ah->totalPowerMeasI[i];
		powerMeasQ = ah->totalPowerMeasQ[i];
		iqCorrMeas = ah->totalIqCorrMeas[i];
S
Sujith 已提交
390

391 392 393
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Starting IQ Cal and Correction for Chain %d\n",
			  i);
S
Sujith 已提交
394

395 396 397
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Orignal: Chn %diq_corr_meas = 0x%08x\n",
			  i, ah->totalIqCorrMeas[i]);
S
Sujith 已提交
398 399 400 401 402 403 404 405

		iqCorrNeg = 0;

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

406 407 408 409 410 411
		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 已提交
412 413 414 415

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

V
Vivek Natarajan 已提交
416 417
		if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
		    (qCoffDenom != 0)) {
S
Sujith 已提交
418 419
			iCoff = iqCorrMeas / iCoffDenom;
			qCoff = powerMeasI / qCoffDenom - 64;
420 421 422 423
			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 已提交
424 425

			iCoff = iCoff & 0x3f;
426 427
			ath_print(common, ATH_DBG_CALIBRATE,
				  "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
S
Sujith 已提交
428 429 430 431 432 433 434 435
			if (iqCorrNeg == 0x0)
				iCoff = 0x40 - iCoff;

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

436 437 438
			ath_print(common, ATH_DBG_CALIBRATE,
				  "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
				  i, iCoff, qCoff);
S
Sujith 已提交
439 440 441 442 443 444 445

			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);
446 447 448
			ath_print(common, ATH_DBG_CALIBRATE,
				  "IQ Cal and Correction done for Chain %d\n",
				  i);
S
Sujith 已提交
449 450 451 452 453 454 455
		}
	}

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

456
static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
S
Sujith 已提交
457
{
458
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
459 460 461 462
	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
	u32 qGainMismatch, iGainMismatch, val, i;

	for (i = 0; i < numChains; i++) {
463 464 465 466
		iOddMeasOffset = ah->totalAdcIOddPhase[i];
		iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
		qOddMeasOffset = ah->totalAdcQOddPhase[i];
		qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
S
Sujith 已提交
467

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
		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 已提交
483 484 485 486 487 488 489 490 491

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

492 493 494 495 496 497
			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 已提交
498 499 500 501 502 503

			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);

504 505
			ath_print(common, ATH_DBG_CALIBRATE,
				  "ADC Gain Cal done for Chain %d\n", i);
S
Sujith 已提交
506 507 508 509 510 511 512 513
		}
	}

	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);
}

514
static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
S
Sujith 已提交
515
{
516
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
517 518
	u32 iOddMeasOffset, iEvenMeasOffset, val, i;
	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
519
	const struct ath9k_percal_data *calData =
520
		ah->cal_list_curr->calData;
S
Sujith 已提交
521 522 523 524
	u32 numSamples =
		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;

	for (i = 0; i < numChains; i++) {
525 526 527 528
		iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
		iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
		qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
		qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
S
Sujith 已提交
529

530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
		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 已提交
545 546 547 548 549 550

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

551 552 553 554 555 556
		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 已提交
557 558 559 560 561 562

		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);

563 564
		ath_print(common, ATH_DBG_CALIBRATE,
			  "ADC DC Offset Cal done for Chain %d\n", i);
S
Sujith 已提交
565 566 567 568 569 570 571
	}

	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);
}

572
/* This is done for the currently configured channel */
573
bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
S
Sujith 已提交
574
{
575 576
	struct ath_common *common = ath9k_hw_common(ah);
	struct ieee80211_conf *conf = &common->hw->conf;
577
	struct ath9k_cal_list *currCal = ah->cal_list_curr;
S
Sujith 已提交
578

579
	if (!ah->curchan)
580
		return true;
S
Sujith 已提交
581 582

	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
583
		return true;
S
Sujith 已提交
584 585

	if (currCal == NULL)
586
		return true;
S
Sujith 已提交
587 588

	if (currCal->calState != CAL_DONE) {
589 590 591
		ath_print(common, ATH_DBG_CALIBRATE,
			  "Calibration state incorrect, %d\n",
			  currCal->calState);
592
		return true;
S
Sujith 已提交
593 594
	}

595 596
	if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
		return true;
S
Sujith 已提交
597

598 599 600
	ath_print(common, ATH_DBG_CALIBRATE,
		  "Resetting Cal %d state for channel %u\n",
		  currCal->calData->calType, conf->channel->center_freq);
S
Sujith 已提交
601

602
	ah->curchan->CalValid &= ~currCal->calData->calType;
S
Sujith 已提交
603 604
	currCal->calState = CAL_WAITING;

605
	return false;
S
Sujith 已提交
606
}
607
EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
S
Sujith 已提交
608

609
void ath9k_hw_start_nfcal(struct ath_hw *ah)
S
Sujith 已提交
610 611 612 613 614 615 616 617
{
	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);
}

618
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
S
Sujith 已提交
619 620 621 622 623 624 625 626 627 628 629 630
{
	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
	};
631
	u8 chainmask, rx_chain_status;
S
Sujith 已提交
632

633
	rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
634
	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
S
Sujith 已提交
635
		chainmask = 0x9;
636 637 638 639 640 641 642 643 644 645 646 647 648
	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 已提交
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666

	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);

667
	for (j = 0; j < 5; j++) {
S
Sujith 已提交
668 669 670
		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
		     AR_PHY_AGC_CONTROL_NF) == 0)
			break;
671
		udelay(50);
S
Sujith 已提交
672 673 674 675 676 677 678 679 680 681 682 683
	}

	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);
		}
	}
}

684
int16_t ath9k_hw_getnf(struct ath_hw *ah,
S
Sujith 已提交
685 686
		       struct ath9k_channel *chan)
{
687
	struct ath_common *common = ath9k_hw_common(ah);
S
Sujith 已提交
688 689 690
	int16_t nf, nfThresh;
	int16_t nfarray[NUM_NF_READINGS] = { 0 };
	struct ath9k_nfcal_hist *h;
691
	struct ieee80211_channel *c = chan->chan;
S
Sujith 已提交
692 693 694

	chan->channelFlags &= (~CHANNEL_CW_INT);
	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
695 696
		ath_print(common, ATH_DBG_CALIBRATE,
			  "NF did not complete in calibration window\n");
S
Sujith 已提交
697 698 699 700 701 702
		nf = 0;
		chan->rawNoiseFloor = nf;
		return chan->rawNoiseFloor;
	} else {
		ath9k_hw_do_getnf(ah, nfarray);
		nf = nfarray[0];
703
		if (getNoiseFloorThresh(ah, c->band, &nfThresh)
S
Sujith 已提交
704
		    && nf > nfThresh) {
705 706 707 708
			ath_print(common, ATH_DBG_CALIBRATE,
				  "noise floor failed detected; "
				  "detected %d, threshold %d\n",
				  nf, nfThresh);
S
Sujith 已提交
709 710 711 712 713 714 715 716 717 718 719 720
			chan->channelFlags |= CHANNEL_CW_INT;
		}
	}

	h = ah->nfCalHist;

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

	return chan->rawNoiseFloor;
}

721
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
S
Sujith 已提交
722 723
{
	int i, j;
724 725 726 727
	s16 noise_floor;

	if (AR_SREV_9280(ah))
		noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
728
	else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
729
		noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
730 731
	else if (AR_SREV_9287(ah))
		noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
732 733
	else
		noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
S
Sujith 已提交
734 735 736

	for (i = 0; i < NUM_NF_READINGS; i++) {
		ah->nfCalHist[i].currIndex = 0;
737
		ah->nfCalHist[i].privNF = noise_floor;
S
Sujith 已提交
738 739 740
		ah->nfCalHist[i].invalidNFcount =
			AR_PHY_CCA_FILTERWINDOW_LENGTH;
		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
741
			ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
S
Sujith 已提交
742 743 744 745
		}
	}
}

746
s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
S
Sujith 已提交
747 748 749
{
	s16 nf;

750
	if (chan->rawNoiseFloor == 0)
751 752
		nf = -96;
	else
753
		nf = chan->rawNoiseFloor;
S
Sujith 已提交
754 755 756 757 758 759

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

	return nf;
}
760
EXPORT_SYMBOL(ath9k_hw_getchan_noise);
S
Sujith 已提交
761

V
Vivek Natarajan 已提交
762
static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah)
763
{
V
Vivek Natarajan 已提交
764 765
	u32 rddata;
	int32_t delta, currPDADC, slope;
766 767 768 769

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

V
Vivek Natarajan 已提交
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
	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;
795

796
	if (OLC_FOR_AR9287_10_LATER) {
V
Vivek Natarajan 已提交
797 798 799 800 801
		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);

802 803 804
		if (ah->initPDADC == 0 || currPDADC == 0) {
			return;
		} else {
V
Vivek Natarajan 已提交
805 806
			if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
				delta = (currPDADC - ah->initPDADC + 4) / 8;
807
			else
V
Vivek Natarajan 已提交
808 809 810 811 812 813 814 815 816 817 818 819 820
				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);
				}
821
			}
822 823 824 825
		}
	}
}

826
static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset)
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
{
	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; */
890
	for (i = 6; i > 0; i--) {
891 892 893 894 895 896 897 898 899 900 901
		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);
	}

902 903 904 905 906 907 908 909 910 911 912 913 914
	regVal = (regVal >>20) & 0x7f;

	/* Update PA cal info */
	if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
		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 = regVal;
	}
915 916 917 918 919 920 921 922 923 924 925 926

	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]);
}

927
static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
928
{
929
	struct ath_common *common = ath9k_hw_common(ah);
930 931 932 933 934 935 936 937 938 939 940 941 942
	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 },
	};

943
	ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
944

S
Sujith 已提交
945 946 947 948 949
	/* 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;

950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
	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);
972
	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
973 974 975 976 977
	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);
978
	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
979 980 981 982 983 984 985 986 987 988 989

	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 已提交
990
		regVal = REG_READ(ah, 0x7834);
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
		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;

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
	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;
	}

1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
	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);

}

1040
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
S
Sujith 已提交
1041
			u8 rxchainmask, bool longcal)
1042
{
S
Sujith 已提交
1043
	bool iscaldone = true;
1044
	struct ath9k_cal_list *currCal = ah->cal_list_curr;
1045 1046 1047 1048

	if (currCal &&
	    (currCal->calState == CAL_RUNNING ||
	     currCal->calState == CAL_WAITING)) {
S
Sujith 已提交
1049 1050 1051
		iscaldone = ath9k_hw_per_calibration(ah, chan,
						     rxchainmask, currCal);
		if (iscaldone) {
1052 1053 1054
			ah->cal_list_curr = currCal = currCal->calNext;

			if (currCal->calState == CAL_WAITING) {
S
Sujith 已提交
1055
				iscaldone = false;
1056 1057 1058 1059 1060
				ath9k_hw_reset_calibration(ah, currCal);
			}
		}
	}

1061
	/* Do NF cal only at longer intervals */
1062
	if (longcal) {
1063
		/* Do periodic PAOffset Cal */
1064 1065 1066 1067 1068 1069
		if (AR_SREV_9271(ah)) {
			if (!ah->pacal_info.skipcount)
				ath9k_hw_9271_pa_cal(ah, false);
			else
				ah->pacal_info.skipcount--;
		} else if (AR_SREV_9285_11_OR_LATER(ah)) {
1070 1071 1072 1073 1074
			if (!ah->pacal_info.skipcount)
				ath9k_hw_9285_pa_cal(ah, false);
			else
				ah->pacal_info.skipcount--;
		}
1075

1076
		if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
1077
			ath9k_olc_temp_compensation(ah);
1078 1079

		/* Get the value from the previous NF cal and update history buffer */
1080
		ath9k_hw_getnf(ah, chan);
1081 1082 1083 1084 1085

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

1088 1089 1090
		ath9k_hw_start_nfcal(ah);
	}

S
Sujith 已提交
1091
	return iscaldone;
1092
}
1093
EXPORT_SYMBOL(ath9k_hw_calibrate);
1094

1095
/* Carrier leakage Calibration fix */
1096
static bool ar9285_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
1097
{
1098 1099
	struct ath_common *common = ath9k_hw_common(ah);

1100
	REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
S
Sujith 已提交
1101
	if (IS_CHAN_HT20(chan)) {
1102 1103 1104 1105 1106 1107 1108 1109
		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)) {
1110 1111 1112
			ath_print(common, ATH_DBG_CALIBRATE, "offset "
				  "calibration failed to complete in "
				  "1ms; noisy ??\n");
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
			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)) {
1125 1126
		ath_print(common, ATH_DBG_CALIBRATE, "offset calibration "
			  "failed to complete in 1ms; noisy ??\n");
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
		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;
}

1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
{
	int i;
	u_int32_t txgain_max;
	u_int32_t clc_gain, gain_mask = 0, clc_num = 0;
	u_int32_t reg_clc_I0, reg_clc_Q0;
	u_int32_t i0_num = 0;
	u_int32_t q0_num = 0;
	u_int32_t total_num = 0;
	u_int32_t reg_rf2g5_org;
	bool retv = true;

	if (!(ar9285_cl_cal(ah, chan)))
		return false;

	txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
			AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);

	for (i = 0; i < (txgain_max+1); i++) {
		clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
			   AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
		if (!(gain_mask & (1 << clc_gain))) {
			gain_mask |= (1 << clc_gain);
			clc_num++;
		}
	}

	for (i = 0; i < clc_num; i++) {
		reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
			      & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
		reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
			      & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
		if (reg_clc_I0 == 0)
			i0_num++;

		if (reg_clc_Q0 == 0)
			q0_num++;
	}
	total_num = i0_num + q0_num;
	if (total_num > AR9285_CLCAL_REDO_THRESH) {
		reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
		if (AR_SREV_9285E_20(ah)) {
			REG_WRITE(ah, AR9285_RF2G5,
				  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
				  AR9285_RF2G5_IC50TX_XE_SET);
		} else {
			REG_WRITE(ah, AR9285_RF2G5,
				  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
				  AR9285_RF2G5_IC50TX_SET);
		}
		retv = ar9285_cl_cal(ah, chan);
		REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
	}
	return retv;
}

1193
bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
S
Sujith 已提交
1194
{
1195 1196
	struct ath_common *common = ath9k_hw_common(ah);

1197
	if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
1198 1199
		if (!ar9285_clc(ah, chan))
			return false;
1200 1201
	} else {
		if (AR_SREV_9280_10_OR_LATER(ah)) {
1202 1203 1204 1205 1206
			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);
1207
		}
1208

1209
		/* Calibrate the AGC */
1210
		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
1211 1212
			  REG_READ(ah, AR_PHY_AGC_CONTROL) |
			  AR_PHY_AGC_CONTROL_CAL);
1213

1214 1215 1216
		/* Poll for offset calibration complete */
		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
				   0, AH_WAIT_TIMEOUT)) {
1217 1218 1219
			ath_print(common, ATH_DBG_CALIBRATE,
				  "offset calibration failed to "
				  "complete in 1ms; noisy environment?\n");
1220 1221 1222
			return false;
		}

1223
		if (AR_SREV_9280_10_OR_LATER(ah)) {
1224 1225 1226 1227 1228
			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);
1229
		}
1230 1231 1232
	}

	/* Do PA Calibration */
1233 1234 1235
	if (AR_SREV_9271(ah))
		ath9k_hw_9271_pa_cal(ah, true);
	else if (AR_SREV_9285_11_OR_LATER(ah))
1236
		ath9k_hw_9285_pa_cal(ah, true);
1237

1238
	/* Do NF Calibration after DC offset and other calibrations */
S
Sujith 已提交
1239
	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
1240
		  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
S
Sujith 已提交
1241

1242
	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
S
Sujith 已提交
1243

1244
	/* Enable IQ, ADC Gain and ADC DC offset CALs */
S
Sujith 已提交
1245
	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
1246
		if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
1247 1248
			INIT_CAL(&ah->adcgain_caldata);
			INSERT_CAL(ah, &ah->adcgain_caldata);
1249 1250
			ath_print(common, ATH_DBG_CALIBRATE,
				  "enabling ADC Gain Calibration.\n");
S
Sujith 已提交
1251
		}
1252
		if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
1253 1254
			INIT_CAL(&ah->adcdc_caldata);
			INSERT_CAL(ah, &ah->adcdc_caldata);
1255 1256
			ath_print(common, ATH_DBG_CALIBRATE,
				  "enabling ADC DC Calibration.\n");
S
Sujith 已提交
1257
		}
1258
		if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
1259 1260
			INIT_CAL(&ah->iq_caldata);
			INSERT_CAL(ah, &ah->iq_caldata);
1261 1262
			ath_print(common, ATH_DBG_CALIBRATE,
				  "enabling IQ Calibration.\n");
S
Sujith 已提交
1263 1264
		}

1265
		ah->cal_list_curr = ah->cal_list;
S
Sujith 已提交
1266

1267 1268
		if (ah->cal_list_curr)
			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
S
Sujith 已提交
1269 1270
	}

1271
	chan->CalValid = 0;
S
Sujith 已提交
1272 1273 1274 1275

	return true;
}

1276
const struct ath9k_percal_data iq_cal_multi_sample = {
S
Sujith 已提交
1277 1278 1279 1280 1281 1282
	IQ_MISMATCH_CAL,
	MAX_CAL_SAMPLES,
	PER_MIN_LOG_COUNT,
	ath9k_hw_iqcal_collect,
	ath9k_hw_iqcalibrate
};
1283
const struct ath9k_percal_data iq_cal_single_sample = {
S
Sujith 已提交
1284 1285 1286 1287 1288 1289
	IQ_MISMATCH_CAL,
	MIN_CAL_SAMPLES,
	PER_MAX_LOG_COUNT,
	ath9k_hw_iqcal_collect,
	ath9k_hw_iqcalibrate
};
1290
const struct ath9k_percal_data adc_gain_cal_multi_sample = {
S
Sujith 已提交
1291 1292 1293 1294 1295 1296
	ADC_GAIN_CAL,
	MAX_CAL_SAMPLES,
	PER_MIN_LOG_COUNT,
	ath9k_hw_adc_gaincal_collect,
	ath9k_hw_adc_gaincal_calibrate
};
1297
const struct ath9k_percal_data adc_gain_cal_single_sample = {
S
Sujith 已提交
1298 1299 1300 1301 1302 1303
	ADC_GAIN_CAL,
	MIN_CAL_SAMPLES,
	PER_MAX_LOG_COUNT,
	ath9k_hw_adc_gaincal_collect,
	ath9k_hw_adc_gaincal_calibrate
};
1304
const struct ath9k_percal_data adc_dc_cal_multi_sample = {
S
Sujith 已提交
1305 1306 1307 1308 1309 1310
	ADC_DC_CAL,
	MAX_CAL_SAMPLES,
	PER_MIN_LOG_COUNT,
	ath9k_hw_adc_dccal_collect,
	ath9k_hw_adc_dccal_calibrate
};
1311
const struct ath9k_percal_data adc_dc_cal_single_sample = {
S
Sujith 已提交
1312 1313 1314 1315 1316 1317
	ADC_DC_CAL,
	MIN_CAL_SAMPLES,
	PER_MAX_LOG_COUNT,
	ath9k_hw_adc_dccal_collect,
	ath9k_hw_adc_dccal_calibrate
};
1318
const struct ath9k_percal_data adc_init_dc_cal = {
S
Sujith 已提交
1319 1320 1321 1322 1323 1324
	ADC_DC_INIT_CAL,
	MIN_CAL_SAMPLES,
	INIT_LOG_COUNT,
	ath9k_hw_adc_dccal_collect,
	ath9k_hw_adc_dccal_calibrate
};