brintos

brintos / linux-shallow public Read only

0
0
Text · 29.5 KiB · c8b3f3a Raw
1020 lines · c
1/*2 * Copyright (c) 2008-2011 Atheros Communications Inc.3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15 */16 17#include "hw.h"18#include "hw-ops.h"19#include "ar9002_phy.h"20 21#define AR9285_CLCAL_REDO_THRESH    122/* AGC & I/Q calibrations time limit, ms */23#define AR9002_CAL_MAX_TIME		3000024 25enum ar9002_cal_types {26	ADC_GAIN_CAL = BIT(0),27	ADC_DC_CAL = BIT(1),28	IQ_MISMATCH_CAL = BIT(2),29};30 31static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,32				struct ath9k_channel *chan,33				enum ar9002_cal_types cal_type)34{35	bool supported = false;36	switch (ah->supp_cals & cal_type) {37	case IQ_MISMATCH_CAL:38		supported = true;39		break;40	case ADC_GAIN_CAL:41	case ADC_DC_CAL:42		/* Run even/odd ADCs calibrations for HT40 channels only */43		if (IS_CHAN_HT40(chan))44			supported = true;45		break;46	}47	return supported;48}49 50static void ar9002_hw_setup_calibration(struct ath_hw *ah,51					struct ath9k_cal_list *currCal)52{53	struct ath_common *common = ath9k_hw_common(ah);54 55	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),56		      AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,57		      currCal->calData->calCountMax);58 59	switch (currCal->calData->calType) {60	case IQ_MISMATCH_CAL:61		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);62		ath_dbg(common, CALIBRATE,63			"starting IQ Mismatch Calibration\n");64		break;65	case ADC_GAIN_CAL:66		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);67		ath_dbg(common, CALIBRATE, "starting ADC Gain Calibration\n");68		break;69	case ADC_DC_CAL:70		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);71		ath_dbg(common, CALIBRATE, "starting ADC DC Calibration\n");72		break;73	}74 75	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),76		    AR_PHY_TIMING_CTRL4_DO_CAL);77}78 79static bool ar9002_hw_per_calibration(struct ath_hw *ah,80				      struct ath9k_channel *ichan,81				      u8 rxchainmask,82				      struct ath9k_cal_list *currCal)83{84	struct ath9k_hw_cal_data *caldata = ah->caldata;85	bool iscaldone = false;86 87	if (currCal->calState == CAL_RUNNING) {88		if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &89		      AR_PHY_TIMING_CTRL4_DO_CAL)) {90 91			currCal->calData->calCollect(ah);92			ah->cal_samples++;93 94			if (ah->cal_samples >=95			    currCal->calData->calNumSamples) {96				int i, numChains = 0;97				for (i = 0; i < AR5416_MAX_CHAINS; i++) {98					if (rxchainmask & (1 << i))99						numChains++;100				}101 102				currCal->calData->calPostProc(ah, numChains);103				caldata->CalValid |= currCal->calData->calType;104				currCal->calState = CAL_DONE;105				iscaldone = true;106			} else {107				ar9002_hw_setup_calibration(ah, currCal);108			}109		} else if (time_after(jiffies, ah->cal_start_time +110				      msecs_to_jiffies(AR9002_CAL_MAX_TIME))) {111			REG_CLR_BIT(ah, AR_PHY_TIMING_CTRL4(0),112				    AR_PHY_TIMING_CTRL4_DO_CAL);113			ath_dbg(ath9k_hw_common(ah), CALIBRATE,114				"calibration timeout\n");115			currCal->calState = CAL_WAITING;	/* Try later */116			iscaldone = true;117		}118	} else if (!(caldata->CalValid & currCal->calData->calType)) {119		ath9k_hw_reset_calibration(ah, currCal);120	}121 122	return iscaldone;123}124 125static void ar9002_hw_iqcal_collect(struct ath_hw *ah)126{127	int i;128 129	for (i = 0; i < AR5416_MAX_CHAINS; i++) {130		ah->totalPowerMeasI[i] +=131			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));132		ah->totalPowerMeasQ[i] +=133			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));134		ah->totalIqCorrMeas[i] +=135			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));136		ath_dbg(ath9k_hw_common(ah), CALIBRATE,137			"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",138			ah->cal_samples, i, ah->totalPowerMeasI[i],139			ah->totalPowerMeasQ[i],140			ah->totalIqCorrMeas[i]);141	}142}143 144static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah)145{146	int i;147 148	for (i = 0; i < AR5416_MAX_CHAINS; i++) {149		ah->totalAdcIOddPhase[i] +=150			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));151		ah->totalAdcIEvenPhase[i] +=152			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));153		ah->totalAdcQOddPhase[i] +=154			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));155		ah->totalAdcQEvenPhase[i] +=156			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));157 158		ath_dbg(ath9k_hw_common(ah), CALIBRATE,159			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",160			ah->cal_samples, i,161			ah->totalAdcIOddPhase[i],162			ah->totalAdcIEvenPhase[i],163			ah->totalAdcQOddPhase[i],164			ah->totalAdcQEvenPhase[i]);165	}166}167 168static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah)169{170	int i;171 172	for (i = 0; i < AR5416_MAX_CHAINS; i++) {173		ah->totalAdcDcOffsetIOddPhase[i] +=174			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));175		ah->totalAdcDcOffsetIEvenPhase[i] +=176			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));177		ah->totalAdcDcOffsetQOddPhase[i] +=178			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));179		ah->totalAdcDcOffsetQEvenPhase[i] +=180			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));181 182		ath_dbg(ath9k_hw_common(ah), CALIBRATE,183			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",184			ah->cal_samples, i,185			ah->totalAdcDcOffsetIOddPhase[i],186			ah->totalAdcDcOffsetIEvenPhase[i],187			ah->totalAdcDcOffsetQOddPhase[i],188			ah->totalAdcDcOffsetQEvenPhase[i]);189	}190}191 192static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)193{194	struct ath_common *common = ath9k_hw_common(ah);195	u32 powerMeasQ, powerMeasI, iqCorrMeas;196	u32 qCoffDenom, iCoffDenom;197	int32_t qCoff, iCoff;198	int iqCorrNeg, i;199 200	for (i = 0; i < numChains; i++) {201		powerMeasI = ah->totalPowerMeasI[i];202		powerMeasQ = ah->totalPowerMeasQ[i];203		iqCorrMeas = ah->totalIqCorrMeas[i];204 205		ath_dbg(common, CALIBRATE,206			"Starting IQ Cal and Correction for Chain %d\n",207			i);208 209		ath_dbg(common, CALIBRATE,210			"Original: Chn %d iq_corr_meas = 0x%08x\n",211			i, ah->totalIqCorrMeas[i]);212 213		iqCorrNeg = 0;214 215		if (iqCorrMeas > 0x80000000) {216			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;217			iqCorrNeg = 1;218		}219 220		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n",221			i, powerMeasI);222		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n",223			i, powerMeasQ);224		ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg);225 226		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;227		qCoffDenom = powerMeasQ / 64;228 229		if ((powerMeasQ != 0) && (iCoffDenom != 0) &&230		    (qCoffDenom != 0)) {231			iCoff = iqCorrMeas / iCoffDenom;232			qCoff = powerMeasI / qCoffDenom - 64;233			ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n",234				i, iCoff);235			ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n",236				i, qCoff);237 238			iCoff = iCoff & 0x3f;239			ath_dbg(common, CALIBRATE,240				"New: Chn %d iCoff = 0x%08x\n", i, iCoff);241			if (iqCorrNeg == 0x0)242				iCoff = 0x40 - iCoff;243 244			if (qCoff > 15)245				qCoff = 15;246			else if (qCoff <= -16)247				qCoff = -16;248 249			ath_dbg(common, CALIBRATE,250				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",251				i, iCoff, qCoff);252 253			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),254				      AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,255				      iCoff);256			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),257				      AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,258				      qCoff);259			ath_dbg(common, CALIBRATE,260				"IQ Cal and Correction done for Chain %d\n",261				i);262		}263	}264 265	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),266		    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);267}268 269static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)270{271	struct ath_common *common = ath9k_hw_common(ah);272	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;273	u32 qGainMismatch, iGainMismatch, val, i;274 275	for (i = 0; i < numChains; i++) {276		iOddMeasOffset = ah->totalAdcIOddPhase[i];277		iEvenMeasOffset = ah->totalAdcIEvenPhase[i];278		qOddMeasOffset = ah->totalAdcQOddPhase[i];279		qEvenMeasOffset = ah->totalAdcQEvenPhase[i];280 281		ath_dbg(common, CALIBRATE,282			"Starting ADC Gain Cal for Chain %d\n", i);283 284		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = 0x%08x\n",285			i, iOddMeasOffset);286		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = 0x%08x\n",287			i, iEvenMeasOffset);288		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = 0x%08x\n",289			i, qOddMeasOffset);290		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = 0x%08x\n",291			i, qEvenMeasOffset);292 293		if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {294			iGainMismatch =295				((iEvenMeasOffset * 32) /296				 iOddMeasOffset) & 0x3f;297			qGainMismatch =298				((qOddMeasOffset * 32) /299				 qEvenMeasOffset) & 0x3f;300 301			ath_dbg(common, CALIBRATE,302				"Chn %d gain_mismatch_i = 0x%08x\n",303				i, iGainMismatch);304			ath_dbg(common, CALIBRATE,305				"Chn %d gain_mismatch_q = 0x%08x\n",306				i, qGainMismatch);307 308			val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));309			val &= 0xfffff000;310			val |= (qGainMismatch) | (iGainMismatch << 6);311			REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);312 313			ath_dbg(common, CALIBRATE,314				"ADC Gain Cal done for Chain %d\n", i);315		}316	}317 318	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),319		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |320		  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);321}322 323static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)324{325	struct ath_common *common = ath9k_hw_common(ah);326	u32 iOddMeasOffset, iEvenMeasOffset, val, i;327	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;328	const struct ath9k_percal_data *calData =329		ah->cal_list_curr->calData;330	u32 numSamples =331		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;332 333	for (i = 0; i < numChains; i++) {334		iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];335		iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];336		qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];337		qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];338 339		ath_dbg(common, CALIBRATE,340			"Starting ADC DC Offset Cal for Chain %d\n", i);341 342		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = %d\n",343			i, iOddMeasOffset);344		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = %d\n",345			i, iEvenMeasOffset);346		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = %d\n",347			i, qOddMeasOffset);348		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = %d\n",349			i, qEvenMeasOffset);350 351		iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /352			       numSamples) & 0x1ff;353		qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /354			       numSamples) & 0x1ff;355 356		ath_dbg(common, CALIBRATE,357			"Chn %d dc_offset_mismatch_i = 0x%08x\n",358			i, iDcMismatch);359		ath_dbg(common, CALIBRATE,360			"Chn %d dc_offset_mismatch_q = 0x%08x\n",361			i, qDcMismatch);362 363		val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));364		val &= 0xc0000fff;365		val |= (qDcMismatch << 12) | (iDcMismatch << 21);366		REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);367 368		ath_dbg(common, CALIBRATE,369			"ADC DC Offset Cal done for Chain %d\n", i);370	}371 372	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),373		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |374		  AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);375}376 377static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah)378{379	u32 rddata;380	int32_t delta, currPDADC, slope;381 382	rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);383	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);384 385	if (ah->initPDADC == 0 || currPDADC == 0) {386		/*387		 * Zero value indicates that no frames have been transmitted388		 * yet, can't do temperature compensation until frames are389		 * transmitted.390		 */391		return;392	} else {393		slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);394 395		if (slope == 0) { /* to avoid divide by zero case */396			delta = 0;397		} else {398			delta = ((currPDADC - ah->initPDADC)*4) / slope;399		}400		REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,401			      AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);402		REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,403			      AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);404	}405}406 407static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah)408{409	u32 rddata, i;410	int delta, currPDADC, regval;411 412	rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);413	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);414 415	if (ah->initPDADC == 0 || currPDADC == 0)416		return;417 418	if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))419		delta = (currPDADC - ah->initPDADC + 4) / 8;420	else421		delta = (currPDADC - ah->initPDADC + 5) / 10;422 423	if (delta != ah->PDADCdelta) {424		ah->PDADCdelta = delta;425		for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {426			regval = ah->originalGain[i] - delta;427			if (regval < 0)428				regval = 0;429 430			REG_RMW_FIELD(ah,431				      AR_PHY_TX_GAIN_TBL1 + i * 4,432				      AR_PHY_TX_GAIN, regval);433		}434	}435}436 437static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)438{439	u32 regVal;440	unsigned int i;441	u32 regList[][2] = {442		{ AR9285_AN_TOP3, 0 },443		{ AR9285_AN_RXTXBB1, 0 },444		{ AR9285_AN_RF2G1, 0 },445		{ AR9285_AN_RF2G2, 0 },446		{ AR9285_AN_TOP2, 0 },447		{ AR9285_AN_RF2G8, 0 },448		{ AR9285_AN_RF2G7, 0 },449		{ AR9285_AN_RF2G3, 0 },450	};451 452	REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList));453 454	ENABLE_REG_RMW_BUFFER(ah);455	/* 7834, b1=0 */456	REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0);457	/* 9808, b27=1 */458	REG_SET_BIT(ah, 0x9808, 1 << 27);459	/* 786c,b23,1, pwddac=1 */460	REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC);461	/* 7854, b5,1, pdrxtxbb=1 */462	REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1);463	/* 7854, b7,1, pdv2i=1 */464	REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I);465	/* 7854, b8,1, pddacinterface=1 */466	REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF);467	/* 7824,b12,0, offcal=0 */468	REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL);469	/* 7838, b1,0, pwddb=0 */470	REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB);471	/* 7820,b11,0, enpacal=0 */472	REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL);473	/* 7820,b25,1, pdpadrv1=0 */474	REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1);475	/* 7820,b24,0, pdpadrv2=0 */476	REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2);477	/* 7820,b23,0, pdpaout=0 */478	REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT);479	/* 783c,b14-16,7, padrvgn2tab_0=7 */480	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);481	/*482	 * 7838,b29-31,0, padrvgn1tab_0=0483	 * does not matter since we turn it off484	 */485	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);486	/* 7828, b0-11, ccom=fff */487	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);488	REG_RMW_BUFFER_FLUSH(ah);489 490	/* Set:491	 * localmode=1,bmode=1,bmoderxtx=1,synthon=1,492	 * txon=1,paon=1,oscon=1,synthon_force=1493	 */494	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);495	udelay(30);496	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);497 498	/* find off_6_1; */499	for (i = 6; i > 0; i--) {500		regVal = REG_READ(ah, AR9285_AN_RF2G6);501		regVal |= (1 << (20 + i));502		REG_WRITE(ah, AR9285_AN_RF2G6, regVal);503		udelay(1);504		/* regVal = REG_READ(ah, 0x7834); */505		regVal &= (~(0x1 << (20 + i)));506		regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9),507			      AR9285_AN_RXTXBB1_SPARE9)508			    << (20 + i));509		REG_WRITE(ah, AR9285_AN_RF2G6, regVal);510	}511 512	regVal = (regVal >> 20) & 0x7f;513 514	/* Update PA cal info */515	if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {516		if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)517			ah->pacal_info.max_skipcount =518				2 * ah->pacal_info.max_skipcount;519		ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;520	} else {521		ah->pacal_info.max_skipcount = 1;522		ah->pacal_info.skipcount = 0;523		ah->pacal_info.prev_offset = regVal;524	}525 526 527	ENABLE_REG_RMW_BUFFER(ah);528	/* 7834, b1=1 */529	REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0);530	/* 9808, b27=0 */531	REG_CLR_BIT(ah, 0x9808, 1 << 27);532	REG_RMW_BUFFER_FLUSH(ah);533 534	ENABLE_REGWRITE_BUFFER(ah);535	for (i = 0; i < ARRAY_SIZE(regList); i++)536		REG_WRITE(ah, regList[i][0], regList[i][1]);537 538	REGWRITE_BUFFER_FLUSH(ah);539}540 541static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)542{543	struct ath_common *common = ath9k_hw_common(ah);544	u32 regVal;545	int i, offset, offs_6_1, offs_0;546	u32 ccomp_org, reg_field;547	u32 regList[][2] = {548		{ 0x786c, 0 },549		{ 0x7854, 0 },550		{ 0x7820, 0 },551		{ 0x7824, 0 },552		{ 0x7868, 0 },553		{ 0x783c, 0 },554		{ 0x7838, 0 },555	};556 557	ath_dbg(common, CALIBRATE, "Running PA Calibration\n");558 559	/* PA CAL is not needed for high power solution */560	if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==561	    AR5416_EEP_TXGAIN_HIGH_POWER)562		return;563 564	for (i = 0; i < ARRAY_SIZE(regList); i++)565		regList[i][1] = REG_READ(ah, regList[i][0]);566 567	regVal = REG_READ(ah, 0x7834);568	regVal &= (~(0x1));569	REG_WRITE(ah, 0x7834, regVal);570	regVal = REG_READ(ah, 0x9808);571	regVal |= (0x1 << 27);572	REG_WRITE(ah, 0x9808, regVal);573 574	REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);575	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);576	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);577	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);578	REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);579	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);580	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);581	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);582	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);583	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);584	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);585	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);586	ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);587	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);588 589	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);590	udelay(30);591	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);592	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);593 594	for (i = 6; i > 0; i--) {595		regVal = REG_READ(ah, 0x7834);596		regVal |= (1 << (19 + i));597		REG_WRITE(ah, 0x7834, regVal);598		udelay(1);599		regVal = REG_READ(ah, 0x7834);600		regVal &= (~(0x1 << (19 + i)));601		reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);602		regVal |= (reg_field << (19 + i));603		REG_WRITE(ah, 0x7834, regVal);604	}605 606	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);607	udelay(1);608	reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);609	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);610	offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);611	offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);612 613	offset = (offs_6_1<<1) | offs_0;614	offset = offset - 0;615	offs_6_1 = offset>>1;616	offs_0 = offset & 1;617 618	if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {619		if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)620			ah->pacal_info.max_skipcount =621				2 * ah->pacal_info.max_skipcount;622		ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;623	} else {624		ah->pacal_info.max_skipcount = 1;625		ah->pacal_info.skipcount = 0;626		ah->pacal_info.prev_offset = offset;627	}628 629	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);630	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);631 632	regVal = REG_READ(ah, 0x7834);633	regVal |= 0x1;634	REG_WRITE(ah, 0x7834, regVal);635	regVal = REG_READ(ah, 0x9808);636	regVal &= (~(0x1 << 27));637	REG_WRITE(ah, 0x9808, regVal);638 639	for (i = 0; i < ARRAY_SIZE(regList); i++)640		REG_WRITE(ah, regList[i][0], regList[i][1]);641 642	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);643}644 645static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset)646{647	if (AR_SREV_9271(ah)) {648		if (is_reset || !ah->pacal_info.skipcount)649			ar9271_hw_pa_cal(ah, is_reset);650		else651			ah->pacal_info.skipcount--;652	} else if (AR_SREV_9285_12_OR_LATER(ah)) {653		if (is_reset || !ah->pacal_info.skipcount)654			ar9285_hw_pa_cal(ah, is_reset);655		else656			ah->pacal_info.skipcount--;657	}658}659 660static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)661{662	if (OLC_FOR_AR9287_10_LATER(ah))663		ar9287_hw_olc_temp_compensation(ah);664	else if (OLC_FOR_AR9280_20_LATER(ah))665		ar9280_hw_olc_temp_compensation(ah);666}667 668static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,669			       u8 rxchainmask, bool longcal)670{671	struct ath9k_cal_list *currCal = ah->cal_list_curr;672	bool nfcal, nfcal_pending = false, percal_pending;673	int ret;674 675	nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) & AR_PHY_AGC_CONTROL_NF);676	if (ah->caldata) {677		nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);678		if (longcal)		/* Remember to not miss */679			set_bit(LONGCAL_PENDING, &ah->caldata->cal_flags);680		else if (test_bit(LONGCAL_PENDING, &ah->caldata->cal_flags))681			longcal = true;	/* Respin a previous one */682	}683 684	percal_pending = (currCal &&685			  (currCal->calState == CAL_RUNNING ||686			   currCal->calState == CAL_WAITING));687 688	if (percal_pending && !nfcal) {689		if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal))690			return 0;691 692		/* Looking for next waiting calibration if any */693		for (currCal = currCal->calNext; currCal != ah->cal_list_curr;694		     currCal = currCal->calNext) {695			if (currCal->calState == CAL_WAITING)696				break;697		}698		if (currCal->calState == CAL_WAITING) {699			percal_pending = true;700			ah->cal_list_curr = currCal;701		} else {702			percal_pending = false;703			ah->cal_list_curr = ah->cal_list;704		}705	}706 707	/* Do not start a next calibration if the longcal is in action */708	if (percal_pending && !nfcal && !longcal) {709		ath9k_hw_reset_calibration(ah, currCal);710 711		return 0;712	}713 714	/* Do NF cal only at longer intervals */715	if (longcal || nfcal_pending) {716		/*717		 * Get the value from the previous NF cal and update718		 * history buffer.719		 */720		if (ath9k_hw_getnf(ah, chan)) {721			/*722			 * Load the NF from history buffer of the current723			 * channel.724			 * NF is slow time-variant, so it is OK to use a725			 * historical value.726			 */727			ret = ath9k_hw_loadnf(ah, ah->curchan);728			if (ret < 0)729				return ret;730		}731 732		if (longcal) {733			if (ah->caldata)734				clear_bit(LONGCAL_PENDING,735					  &ah->caldata->cal_flags);736			ath9k_hw_start_nfcal(ah, false);737			/* Do periodic PAOffset Cal */738			ar9002_hw_pa_cal(ah, false);739			ar9002_hw_olc_temp_compensation(ah);740		}741	}742 743	return !percal_pending;744}745 746/* Carrier leakage Calibration fix */747static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)748{749	struct ath_common *common = ath9k_hw_common(ah);750 751	REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);752	if (IS_CHAN_HT20(chan)) {753		REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);754		REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);755		REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah),756			    AR_PHY_AGC_CONTROL_FLTR_CAL);757		REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);758		REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL);759		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah),760				  AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {761			ath_dbg(common, CALIBRATE,762				"offset calibration failed to complete in %d ms; noisy environment?\n",763				AH_WAIT_TIMEOUT / 1000);764			return false;765		}766		REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);767		REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);768		REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);769	}770	REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);771	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL);772	REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);773	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL);774	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL,775			  0, AH_WAIT_TIMEOUT)) {776		ath_dbg(common, CALIBRATE,777			"offset calibration failed to complete in %d ms; noisy environment?\n",778			AH_WAIT_TIMEOUT / 1000);779		return false;780	}781 782	REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);783	REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);784	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL);785 786	return true;787}788 789static bool ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan)790{791	int i;792	u_int32_t txgain_max;793	u_int32_t clc_gain, gain_mask = 0, clc_num = 0;794	u_int32_t reg_clc_I0, reg_clc_Q0;795	u_int32_t i0_num = 0;796	u_int32_t q0_num = 0;797	u_int32_t total_num = 0;798	u_int32_t reg_rf2g5_org;799	bool retv = true;800 801	if (!(ar9285_hw_cl_cal(ah, chan)))802		return false;803 804	txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),805			AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);806 807	for (i = 0; i < (txgain_max+1); i++) {808		clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &809			   AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;810		if (!(gain_mask & (1 << clc_gain))) {811			gain_mask |= (1 << clc_gain);812			clc_num++;813		}814	}815 816	for (i = 0; i < clc_num; i++) {817		reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))818			      & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;819		reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))820			      & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;821		if (reg_clc_I0 == 0)822			i0_num++;823 824		if (reg_clc_Q0 == 0)825			q0_num++;826	}827	total_num = i0_num + q0_num;828	if (total_num > AR9285_CLCAL_REDO_THRESH) {829		reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);830		if (AR_SREV_9285E_20(ah)) {831			REG_WRITE(ah, AR9285_RF2G5,832				  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |833				  AR9285_RF2G5_IC50TX_XE_SET);834		} else {835			REG_WRITE(ah, AR9285_RF2G5,836				  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |837				  AR9285_RF2G5_IC50TX_SET);838		}839		retv = ar9285_hw_cl_cal(ah, chan);840		REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);841	}842	return retv;843}844 845static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)846{847	struct ath_common *common = ath9k_hw_common(ah);848 849	if (AR_SREV_9271(ah)) {850		if (!ar9285_hw_cl_cal(ah, chan))851			return false;852	} else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {853		if (!ar9285_hw_clc(ah, chan))854			return false;855	} else {856		if (AR_SREV_9280_20_OR_LATER(ah)) {857			if (!AR_SREV_9287_11_OR_LATER(ah))858				REG_CLR_BIT(ah, AR_PHY_ADC_CTL,859					    AR_PHY_ADC_CTL_OFF_PWDADC);860			REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah),861				    AR_PHY_AGC_CONTROL_FLTR_CAL);862		}863 864		/* Calibrate the AGC */865		REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah),866			  REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) |867			  AR_PHY_AGC_CONTROL_CAL);868 869		/* Poll for offset calibration complete */870		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah),871				   AR_PHY_AGC_CONTROL_CAL,872				   0, AH_WAIT_TIMEOUT)) {873			ath_dbg(common, CALIBRATE,874				"offset calibration failed to complete in %d ms; noisy environment?\n",875				AH_WAIT_TIMEOUT / 1000);876			return false;877		}878 879		if (AR_SREV_9280_20_OR_LATER(ah)) {880			if (!AR_SREV_9287_11_OR_LATER(ah))881				REG_SET_BIT(ah, AR_PHY_ADC_CTL,882					    AR_PHY_ADC_CTL_OFF_PWDADC);883			REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah),884				    AR_PHY_AGC_CONTROL_FLTR_CAL);885		}886	}887 888	/* Do PA Calibration */889	ar9002_hw_pa_cal(ah, true);890	ath9k_hw_loadnf(ah, chan);891	ath9k_hw_start_nfcal(ah, true);892 893	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;894 895	/* Enable IQ, ADC Gain and ADC DC offset CALs */896	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {897		ah->supp_cals = IQ_MISMATCH_CAL;898 899		if (AR_SREV_9160_10_OR_LATER(ah))900			ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;901 902		if (AR_SREV_9287(ah))903			ah->supp_cals &= ~ADC_GAIN_CAL;904 905		if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) {906			INIT_CAL(&ah->adcgain_caldata);907			INSERT_CAL(ah, &ah->adcgain_caldata);908			ath_dbg(common, CALIBRATE,909					"enabling ADC Gain Calibration\n");910		}911 912		if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) {913			INIT_CAL(&ah->adcdc_caldata);914			INSERT_CAL(ah, &ah->adcdc_caldata);915			ath_dbg(common, CALIBRATE,916					"enabling ADC DC Calibration\n");917		}918 919		if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) {920			INIT_CAL(&ah->iq_caldata);921			INSERT_CAL(ah, &ah->iq_caldata);922			ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");923		}924 925		ah->cal_list_curr = ah->cal_list;926 927		if (ah->cal_list_curr)928			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);929	}930 931	if (ah->caldata)932		ah->caldata->CalValid = 0;933 934	return true;935}936 937static const struct ath9k_percal_data iq_cal_multi_sample = {938	IQ_MISMATCH_CAL,939	MAX_CAL_SAMPLES,940	PER_MIN_LOG_COUNT,941	ar9002_hw_iqcal_collect,942	ar9002_hw_iqcalibrate943};944static const struct ath9k_percal_data iq_cal_single_sample = {945	IQ_MISMATCH_CAL,946	MIN_CAL_SAMPLES,947	PER_MAX_LOG_COUNT,948	ar9002_hw_iqcal_collect,949	ar9002_hw_iqcalibrate950};951static const struct ath9k_percal_data adc_gain_cal_multi_sample = {952	ADC_GAIN_CAL,953	MAX_CAL_SAMPLES,954	PER_MIN_LOG_COUNT,955	ar9002_hw_adc_gaincal_collect,956	ar9002_hw_adc_gaincal_calibrate957};958static const struct ath9k_percal_data adc_gain_cal_single_sample = {959	ADC_GAIN_CAL,960	MIN_CAL_SAMPLES,961	PER_MAX_LOG_COUNT,962	ar9002_hw_adc_gaincal_collect,963	ar9002_hw_adc_gaincal_calibrate964};965static const struct ath9k_percal_data adc_dc_cal_multi_sample = {966	ADC_DC_CAL,967	MAX_CAL_SAMPLES,968	PER_MIN_LOG_COUNT,969	ar9002_hw_adc_dccal_collect,970	ar9002_hw_adc_dccal_calibrate971};972static const struct ath9k_percal_data adc_dc_cal_single_sample = {973	ADC_DC_CAL,974	MIN_CAL_SAMPLES,975	PER_MAX_LOG_COUNT,976	ar9002_hw_adc_dccal_collect,977	ar9002_hw_adc_dccal_calibrate978};979 980static void ar9002_hw_init_cal_settings(struct ath_hw *ah)981{982	if (AR_SREV_9100(ah)) {983		ah->iq_caldata.calData = &iq_cal_multi_sample;984		ah->supp_cals = IQ_MISMATCH_CAL;985		return;986	}987 988	if (AR_SREV_9160_10_OR_LATER(ah)) {989		if (AR_SREV_9280_20_OR_LATER(ah)) {990			ah->iq_caldata.calData = &iq_cal_single_sample;991			ah->adcgain_caldata.calData =992				&adc_gain_cal_single_sample;993			ah->adcdc_caldata.calData =994				&adc_dc_cal_single_sample;995		} else {996			ah->iq_caldata.calData = &iq_cal_multi_sample;997			ah->adcgain_caldata.calData =998				&adc_gain_cal_multi_sample;999			ah->adcdc_caldata.calData =1000				&adc_dc_cal_multi_sample;1001		}1002		ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;1003 1004		if (AR_SREV_9287(ah))1005			ah->supp_cals &= ~ADC_GAIN_CAL;1006	}1007}1008 1009void ar9002_hw_attach_calib_ops(struct ath_hw *ah)1010{1011	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);1012	struct ath_hw_ops *ops = ath9k_hw_ops(ah);1013 1014	priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;1015	priv_ops->init_cal = ar9002_hw_init_cal;1016	priv_ops->setup_calibration = ar9002_hw_setup_calibration;1017 1018	ops->calibrate = ar9002_hw_calibrate;1019}1020