brintos

brintos / linux-shallow public Read only

0
0
Text · 46.0 KiB · 2224cb7 Raw
1699 lines · c
1/*2 * Copyright (c) 2010-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 "ar9003_phy.h"20#include "ar9003_rtt.h"21#include "ar9003_mci.h"22 23#define MAX_MEASUREMENT	MAX_IQCAL_MEASUREMENT24#define MAX_MAG_DELTA	1125#define MAX_PHS_DELTA	1026#define MAXIQCAL        327 28struct coeff {29	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];30	int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];31	int iqc_coeff[2];32};33 34enum ar9003_cal_types {35	IQ_MISMATCH_CAL = BIT(0),36};37 38static void ar9003_hw_setup_calibration(struct ath_hw *ah,39					struct ath9k_cal_list *currCal)40{41	struct ath_common *common = ath9k_hw_common(ah);42 43	/* Select calibration to run */44	switch (currCal->calData->calType) {45	case IQ_MISMATCH_CAL:46		/*47		 * Start calibration with48		 * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples49		 */50		REG_RMW_FIELD(ah, AR_PHY_TIMING4,51			      AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,52			      currCal->calData->calCountMax);53		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);54 55		ath_dbg(common, CALIBRATE,56			"starting IQ Mismatch Calibration\n");57 58		/* Kick-off cal */59		REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);60		break;61	default:62		ath_err(common, "Invalid calibration type\n");63		break;64	}65}66 67/*68 * Generic calibration routine.69 * Recalibrate the lower PHY chips to account for temperature/environment70 * changes.71 */72static bool ar9003_hw_per_calibration(struct ath_hw *ah,73				      struct ath9k_channel *ichan,74				      u8 rxchainmask,75				      struct ath9k_cal_list *currCal)76{77	struct ath9k_hw_cal_data *caldata = ah->caldata;78	const struct ath9k_percal_data *cur_caldata = currCal->calData;79 80	/* Calibration in progress. */81	if (currCal->calState == CAL_RUNNING) {82		/* Check to see if it has finished. */83		if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)84			return false;85 86		/*87		* Accumulate cal measures for active chains88		*/89		cur_caldata->calCollect(ah);90		ah->cal_samples++;91 92		if (ah->cal_samples >= cur_caldata->calNumSamples) {93			unsigned int i, numChains = 0;94			for (i = 0; i < AR9300_MAX_CHAINS; i++) {95				if (rxchainmask & (1 << i))96					numChains++;97			}98 99			/*100			* Process accumulated data101			*/102			cur_caldata->calPostProc(ah, numChains);103 104			/* Calibration has finished. */105			caldata->CalValid |= cur_caldata->calType;106			currCal->calState = CAL_DONE;107			return true;108		} else {109			/*110			 * Set-up collection of another sub-sample until we111			 * get desired number112			 */113			ar9003_hw_setup_calibration(ah, currCal);114		}115	} else if (!(caldata->CalValid & cur_caldata->calType)) {116		/* If current cal is marked invalid in channel, kick it off */117		ath9k_hw_reset_calibration(ah, currCal);118	}119 120	return false;121}122 123static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,124			       u8 rxchainmask, bool longcal)125{126	bool iscaldone = true;127	struct ath9k_cal_list *currCal = ah->cal_list_curr;128	int ret;129 130	/*131	 * For given calibration:132	 * 1. Call generic cal routine133	 * 2. When this cal is done (isCalDone) if we have more cals waiting134	 *    (eg after reset), mask this to upper layers by not propagating135	 *    isCalDone if it is set to TRUE.136	 *    Instead, change isCalDone to FALSE and setup the waiting cal(s)137	 *    to be run.138	 */139	if (currCal &&140	    (currCal->calState == CAL_RUNNING ||141	     currCal->calState == CAL_WAITING)) {142		iscaldone = ar9003_hw_per_calibration(ah, chan,143						      rxchainmask, currCal);144		if (iscaldone) {145			ah->cal_list_curr = currCal = currCal->calNext;146 147			if (currCal->calState == CAL_WAITING) {148				iscaldone = false;149				ath9k_hw_reset_calibration(ah, currCal);150			}151		}152	}153 154	/*155	 * Do NF cal only at longer intervals. Get the value from156	 * the previous NF cal and update history buffer.157	 */158	if (longcal && ath9k_hw_getnf(ah, chan)) {159		/*160		 * Load the NF from history buffer of the current channel.161		 * NF is slow time-variant, so it is OK to use a historical162		 * value.163		 */164		ret = ath9k_hw_loadnf(ah, ah->curchan);165		if (ret < 0)166			return ret;167 168		/* start NF calibration, without updating BB NF register */169		ath9k_hw_start_nfcal(ah, false);170	}171 172	return iscaldone;173}174 175static void ar9003_hw_iqcal_collect(struct ath_hw *ah)176{177	int i;178 179	/* Accumulate IQ cal measures for active chains */180	for (i = 0; i < AR9300_MAX_CHAINS; i++) {181		if (ah->txchainmask & BIT(i)) {182			ah->totalPowerMeasI[i] +=183				REG_READ(ah, AR_PHY_CAL_MEAS_0(i));184			ah->totalPowerMeasQ[i] +=185				REG_READ(ah, AR_PHY_CAL_MEAS_1(i));186			ah->totalIqCorrMeas[i] +=187				(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));188			ath_dbg(ath9k_hw_common(ah), CALIBRATE,189				"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",190				ah->cal_samples, i, ah->totalPowerMeasI[i],191				ah->totalPowerMeasQ[i],192				ah->totalIqCorrMeas[i]);193		}194	}195}196 197static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)198{199	struct ath_common *common = ath9k_hw_common(ah);200	u32 powerMeasQ, powerMeasI, iqCorrMeas;201	u32 qCoffDenom, iCoffDenom;202	int32_t qCoff, iCoff;203	int iqCorrNeg, i;204	static const u_int32_t offset_array[3] = {205		AR_PHY_RX_IQCAL_CORR_B0,206		AR_PHY_RX_IQCAL_CORR_B1,207		AR_PHY_RX_IQCAL_CORR_B2,208	};209 210	for (i = 0; i < numChains; i++) {211		powerMeasI = ah->totalPowerMeasI[i];212		powerMeasQ = ah->totalPowerMeasQ[i];213		iqCorrMeas = ah->totalIqCorrMeas[i];214 215		ath_dbg(common, CALIBRATE,216			"Starting IQ Cal and Correction for Chain %d\n", i);217 218		ath_dbg(common, CALIBRATE,219			"Original: Chn %d iq_corr_meas = 0x%08x\n",220			i, ah->totalIqCorrMeas[i]);221 222		iqCorrNeg = 0;223 224		if (iqCorrMeas > 0x80000000) {225			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;226			iqCorrNeg = 1;227		}228 229		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n",230			i, powerMeasI);231		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n",232			i, powerMeasQ);233		ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg);234 235		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;236		qCoffDenom = powerMeasQ / 64;237 238		if ((iCoffDenom != 0) && (qCoffDenom != 0)) {239			iCoff = iqCorrMeas / iCoffDenom;240			qCoff = powerMeasI / qCoffDenom - 64;241			ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n",242				i, iCoff);243			ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n",244				i, qCoff);245 246			/* Force bounds on iCoff */247			if (iCoff >= 63)248				iCoff = 63;249			else if (iCoff <= -63)250				iCoff = -63;251 252			/* Negate iCoff if iqCorrNeg == 0 */253			if (iqCorrNeg == 0x0)254				iCoff = -iCoff;255 256			/* Force bounds on qCoff */257			if (qCoff >= 63)258				qCoff = 63;259			else if (qCoff <= -63)260				qCoff = -63;261 262			iCoff = iCoff & 0x7f;263			qCoff = qCoff & 0x7f;264 265			ath_dbg(common, CALIBRATE,266				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",267				i, iCoff, qCoff);268			ath_dbg(common, CALIBRATE,269				"Register offset (0x%04x) before update = 0x%x\n",270				offset_array[i],271				REG_READ(ah, offset_array[i]));272 273			if (AR_SREV_9565(ah) &&274			    (iCoff == 63 || qCoff == 63 ||275			     iCoff == -63 || qCoff == -63))276				return;277 278			REG_RMW_FIELD(ah, offset_array[i],279				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,280				      iCoff);281			REG_RMW_FIELD(ah, offset_array[i],282				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,283				      qCoff);284			ath_dbg(common, CALIBRATE,285				"Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",286				offset_array[i],287				AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,288				REG_READ(ah, offset_array[i]));289			ath_dbg(common, CALIBRATE,290				"Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",291				offset_array[i],292				AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,293				REG_READ(ah, offset_array[i]));294 295			ath_dbg(common, CALIBRATE,296				"IQ Cal and Correction done for Chain %d\n", i);297		}298	}299 300	REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,301		    AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);302	ath_dbg(common, CALIBRATE,303		"IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",304		(unsigned) (AR_PHY_RX_IQCAL_CORR_B0),305		AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,306		REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));307}308 309static const struct ath9k_percal_data iq_cal_single_sample = {310	IQ_MISMATCH_CAL,311	MIN_CAL_SAMPLES,312	PER_MAX_LOG_COUNT,313	ar9003_hw_iqcal_collect,314	ar9003_hw_iqcalibrate315};316 317static void ar9003_hw_init_cal_settings(struct ath_hw *ah)318{319	ah->iq_caldata.calData = &iq_cal_single_sample;320 321	if (AR_SREV_9300_20_OR_LATER(ah)) {322		ah->enabled_cals |= TX_IQ_CAL;323		if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah))324			ah->enabled_cals |= TX_IQ_ON_AGC_CAL;325	}326 327	ah->supp_cals = IQ_MISMATCH_CAL;328}329 330#define OFF_UPPER_LT 24331#define OFF_LOWER_LT 7332 333static bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah,334					      bool txiqcal_done)335{336	struct ath_common *common = ath9k_hw_common(ah);337	int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2,338		dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3;339	int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2,340		dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3;341	int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2,342		dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3;343	bool status;344	u32 temp, val;345 346	/*347	 * Clear offset and IQ calibration, run AGC cal.348	 */349	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah),350		    AR_PHY_AGC_CONTROL_OFFSET_CAL);351	REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),352		    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);353	REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah),354		  REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | AR_PHY_AGC_CONTROL_CAL);355 356	status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah),357			       AR_PHY_AGC_CONTROL_CAL,358			       0, AH_WAIT_TIMEOUT);359	if (!status) {360		ath_dbg(common, CALIBRATE,361			"AGC cal without offset cal failed to complete in 1ms");362		return false;363	}364 365	/*366	 * Allow only offset calibration and disable the others367	 * (Carrier Leak calibration, TX Filter calibration and368	 *  Peak Detector offset calibration).369	 */370	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah),371		    AR_PHY_AGC_CONTROL_OFFSET_CAL);372	REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,373		    AR_PHY_CL_CAL_ENABLE);374	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah),375		    AR_PHY_AGC_CONTROL_FLTR_CAL);376	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah),377		    AR_PHY_AGC_CONTROL_PKDET_CAL);378 379	ch0_done = 0;380	ch1_done = 0;381	ch2_done = 0;382 383	while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) {384		osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3;385		osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3;386		osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3;387 388		REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);389 390		REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah),391			  REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | AR_PHY_AGC_CONTROL_CAL);392 393		status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah),394				       AR_PHY_AGC_CONTROL_CAL,395				       0, AH_WAIT_TIMEOUT);396		if (!status) {397			ath_dbg(common, CALIBRATE,398				"DC offset cal failed to complete in 1ms");399			return false;400		}401 402		REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);403 404		/*405		 * High gain.406		 */407		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,408			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8)));409		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,410			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8)));411		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,412			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8)));413 414		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);415		dc_off_ch0_i1 = (temp >> 26) & 0x1f;416		dc_off_ch0_q1 = (temp >> 21) & 0x1f;417 418		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);419		dc_off_ch1_i1 = (temp >> 26) & 0x1f;420		dc_off_ch1_q1 = (temp >> 21) & 0x1f;421 422		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);423		dc_off_ch2_i1 = (temp >> 26) & 0x1f;424		dc_off_ch2_q1 = (temp >> 21) & 0x1f;425 426		/*427		 * Low gain.428		 */429		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,430			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8)));431		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,432			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8)));433		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,434			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8)));435 436		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);437		dc_off_ch0_i2 = (temp >> 26) & 0x1f;438		dc_off_ch0_q2 = (temp >> 21) & 0x1f;439 440		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);441		dc_off_ch1_i2 = (temp >> 26) & 0x1f;442		dc_off_ch1_q2 = (temp >> 21) & 0x1f;443 444		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);445		dc_off_ch2_i2 = (temp >> 26) & 0x1f;446		dc_off_ch2_q2 = (temp >> 21) & 0x1f;447 448		/*449		 * Loopback.450		 */451		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,452			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8)));453		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,454			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8)));455		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,456			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8)));457 458		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);459		dc_off_ch0_i3 = (temp >> 26) & 0x1f;460		dc_off_ch0_q3 = (temp >> 21) & 0x1f;461 462		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);463		dc_off_ch1_i3 = (temp >> 26) & 0x1f;464		dc_off_ch1_q3 = (temp >> 21) & 0x1f;465 466		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);467		dc_off_ch2_i3 = (temp >> 26) & 0x1f;468		dc_off_ch2_q3 = (temp >> 21) & 0x1f;469 470		if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) ||471		    (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) ||472		    (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) ||473		    (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) ||474		    (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) ||475		    (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) {476			if (osdac_ch0 == 3) {477				ch0_done = 1;478			} else {479				osdac_ch0++;480 481				val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff;482				val |= (osdac_ch0 << 30);483				REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val);484 485				ch0_done = 0;486			}487		} else {488			ch0_done = 1;489		}490 491		if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) ||492		    (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) ||493		    (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) ||494		    (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) ||495		    (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) ||496		    (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) {497			if (osdac_ch1 == 3) {498				ch1_done = 1;499			} else {500				osdac_ch1++;501 502				val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff;503				val |= (osdac_ch1 << 30);504				REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val);505 506				ch1_done = 0;507			}508		} else {509			ch1_done = 1;510		}511 512		if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) ||513		    (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) ||514		    (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) ||515		    (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) ||516		    (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) ||517		    (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) {518			if (osdac_ch2 == 3) {519				ch2_done = 1;520			} else {521				osdac_ch2++;522 523				val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff;524				val |= (osdac_ch2 << 30);525				REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val);526 527				ch2_done = 0;528			}529		} else {530			ch2_done = 1;531		}532	}533 534	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah),535		    AR_PHY_AGC_CONTROL_OFFSET_CAL);536	REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);537 538	/*539	 * We don't need to check txiqcal_done here since it is always540	 * set for AR9550.541	 */542	REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),543		    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);544 545	return true;546}547 548/*549 * solve 4x4 linear equation used in loopback iq cal.550 */551static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah,552				   s32 sin_2phi_1,553				   s32 cos_2phi_1,554				   s32 sin_2phi_2,555				   s32 cos_2phi_2,556				   s32 mag_a0_d0,557				   s32 phs_a0_d0,558				   s32 mag_a1_d0,559				   s32 phs_a1_d0,560				   s32 solved_eq[])561{562	s32 f1 = cos_2phi_1 - cos_2phi_2,563	    f3 = sin_2phi_1 - sin_2phi_2,564	    f2;565	s32 mag_tx, phs_tx, mag_rx, phs_rx;566	const s32 result_shift = 1 << 15;567	struct ath_common *common = ath9k_hw_common(ah);568 569	f2 = ((f1 >> 3) * (f1 >> 3) + (f3 >> 3) * (f3 >> 3)) >> 9;570 571	if (!f2) {572		ath_dbg(common, CALIBRATE, "Divide by 0\n");573		return false;574	}575 576	/* mag mismatch, tx */577	mag_tx = f1 * (mag_a0_d0  - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);578	/* phs mismatch, tx */579	phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);580 581	mag_tx = (mag_tx / f2);582	phs_tx = (phs_tx / f2);583 584	/* mag mismatch, rx */585	mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /586		 result_shift;587	/* phs mismatch, rx */588	phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /589		 result_shift;590 591	solved_eq[0] = mag_tx;592	solved_eq[1] = phs_tx;593	solved_eq[2] = mag_rx;594	solved_eq[3] = phs_rx;595 596	return true;597}598 599static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im)600{601	s32 abs_i = abs(in_re),602	    abs_q = abs(in_im),603	    max_abs, min_abs;604 605	if (abs_i > abs_q) {606		max_abs = abs_i;607		min_abs = abs_q;608	} else {609		max_abs = abs_q;610		min_abs = abs_i;611	}612 613	return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);614}615 616#define DELPT 32617 618static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,619				   s32 chain_idx,620				   const s32 iq_res[],621				   s32 iqc_coeff[])622{623	s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,624	    i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,625	    i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,626	    i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;627	s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,628	    phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,629	    sin_2phi_1, cos_2phi_1,630	    sin_2phi_2, cos_2phi_2;631	s32 mag_tx, phs_tx, mag_rx, phs_rx;632	s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,633	    q_q_coff, q_i_coff;634	const s32 res_scale = 1 << 15;635	const s32 delpt_shift = 1 << 8;636	s32 mag1, mag2;637	struct ath_common *common = ath9k_hw_common(ah);638 639	i2_m_q2_a0_d0 = iq_res[0] & 0xfff;640	i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;641	iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);642 643	if (i2_m_q2_a0_d0 > 0x800)644		i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);645 646	if (i2_p_q2_a0_d0 > 0x800)647		i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);648 649	if (iq_corr_a0_d0 > 0x800)650		iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);651 652	i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;653	i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);654	iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;655 656	if (i2_m_q2_a0_d1 > 0x800)657		i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);658 659	if (iq_corr_a0_d1 > 0x800)660		iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);661 662	i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);663	i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;664	iq_corr_a1_d0 = iq_res[4] & 0xfff;665 666	if (i2_m_q2_a1_d0 > 0x800)667		i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);668 669	if (i2_p_q2_a1_d0 > 0x800)670		i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);671 672	if (iq_corr_a1_d0 > 0x800)673		iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);674 675	i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;676	i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);677	iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;678 679	if (i2_m_q2_a1_d1 > 0x800)680		i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);681 682	if (i2_p_q2_a1_d1 > 0x800)683		i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);684 685	if (iq_corr_a1_d1 > 0x800)686		iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);687 688	if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||689	    (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {690		ath_dbg(common, CALIBRATE,691			"Divide by 0:\n"692			"a0_d0=%d\n"693			"a0_d1=%d\n"694			"a2_d0=%d\n"695			"a1_d1=%d\n",696			i2_p_q2_a0_d0, i2_p_q2_a0_d1,697			i2_p_q2_a1_d0, i2_p_q2_a1_d1);698		return false;699	}700 701	if ((i2_p_q2_a0_d0 < 1024) || (i2_p_q2_a0_d0 > 2047) ||702            (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||703            (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||704            (i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||705            (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||706            (i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||707            (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||708            (i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||709            (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||710            (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {711		return false;712	}713 714	mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;715	phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;716 717	mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;718	phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;719 720	mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;721	phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;722 723	mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;724	phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;725 726	/* w/o analog phase shift */727	sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);728	/* w/o analog phase shift */729	cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);730	/* w/  analog phase shift */731	sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);732	/* w/  analog phase shift */733	cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);734 735	/*736	 * force sin^2 + cos^2 = 1;737	 * find magnitude by approximation738	 */739	mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);740	mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);741 742	if ((mag1 == 0) || (mag2 == 0)) {743		ath_dbg(common, CALIBRATE, "Divide by 0: mag1=%d, mag2=%d\n",744			mag1, mag2);745		return false;746	}747 748	/* normalization sin and cos by mag */749	sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);750	cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);751	sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);752	cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);753 754	/* calculate IQ mismatch */755	if (!ar9003_hw_solve_iq_cal(ah,756			     sin_2phi_1, cos_2phi_1,757			     sin_2phi_2, cos_2phi_2,758			     mag_a0_d0, phs_a0_d0,759			     mag_a1_d0,760			     phs_a1_d0, solved_eq)) {761		ath_dbg(common, CALIBRATE,762			"Call to ar9003_hw_solve_iq_cal() failed\n");763		return false;764	}765 766	mag_tx = solved_eq[0];767	phs_tx = solved_eq[1];768	mag_rx = solved_eq[2];769	phs_rx = solved_eq[3];770 771	ath_dbg(common, CALIBRATE,772		"chain %d: mag mismatch=%d phase mismatch=%d\n",773		chain_idx, mag_tx/res_scale, phs_tx/res_scale);774 775	if (res_scale == mag_tx) {776		ath_dbg(common, CALIBRATE,777			"Divide by 0: mag_tx=%d, res_scale=%d\n",778			mag_tx, res_scale);779		return false;780	}781 782	/* calculate and quantize Tx IQ correction factor */783	mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);784	phs_corr_tx = -phs_tx;785 786	q_q_coff = (mag_corr_tx * 128 / res_scale);787	q_i_coff = (phs_corr_tx * 256 / res_scale);788 789	ath_dbg(common, CALIBRATE, "tx chain %d: mag corr=%d  phase corr=%d\n",790		chain_idx, q_q_coff, q_i_coff);791 792	if (q_i_coff < -63)793		q_i_coff = -63;794	if (q_i_coff > 63)795		q_i_coff = 63;796	if (q_q_coff < -63)797		q_q_coff = -63;798	if (q_q_coff > 63)799		q_q_coff = 63;800 801	iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);802 803	ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",804		chain_idx, iqc_coeff[0]);805 806	if (-mag_rx == res_scale) {807		ath_dbg(common, CALIBRATE,808			"Divide by 0: mag_rx=%d, res_scale=%d\n",809			mag_rx, res_scale);810		return false;811	}812 813	/* calculate and quantize Rx IQ correction factors */814	mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);815	phs_corr_rx = -phs_rx;816 817	q_q_coff = (mag_corr_rx * 128 / res_scale);818	q_i_coff = (phs_corr_rx * 256 / res_scale);819 820	ath_dbg(common, CALIBRATE, "rx chain %d: mag corr=%d  phase corr=%d\n",821		chain_idx, q_q_coff, q_i_coff);822 823	if (q_i_coff < -63)824		q_i_coff = -63;825	if (q_i_coff > 63)826		q_i_coff = 63;827	if (q_q_coff < -63)828		q_q_coff = -63;829	if (q_q_coff > 63)830		q_q_coff = 63;831 832	iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);833 834	ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",835		chain_idx, iqc_coeff[1]);836 837	return true;838}839 840static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL],841				     int nmeasurement,842				     int max_delta)843{844	int mp_max = -64, max_idx = 0;845	int mp_min = 63, min_idx = 0;846	int mp_avg = 0, i, outlier_idx = 0, mp_count = 0;847 848	/* find min/max mismatch across all calibrated gains */849	for (i = 0; i < nmeasurement; i++) {850		if (mp_coeff[i][0] > mp_max) {851			mp_max = mp_coeff[i][0];852			max_idx = i;853		} else if (mp_coeff[i][0] < mp_min) {854			mp_min = mp_coeff[i][0];855			min_idx = i;856		}857	}858 859	/* find average (exclude max abs value) */860	for (i = 0; i < nmeasurement; i++) {861		if ((abs(mp_coeff[i][0]) < abs(mp_max)) ||862		    (abs(mp_coeff[i][0]) < abs(mp_min))) {863			mp_avg += mp_coeff[i][0];864			mp_count++;865		}866	}867 868	/*869	 * finding mean magnitude/phase if possible, otherwise870	 * just use the last value as the mean871	 */872	if (mp_count)873		mp_avg /= mp_count;874	else875		mp_avg = mp_coeff[nmeasurement - 1][0];876 877	/* detect outlier */878	if (abs(mp_max - mp_min) > max_delta) {879		if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))880			outlier_idx = max_idx;881		else882			outlier_idx = min_idx;883 884		mp_coeff[outlier_idx][0] = mp_avg;885	}886}887 888static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah,889						  struct coeff *coeff,890						  bool is_reusable)891{892	int i, im, nmeasurement;893	int magnitude, phase;894	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];895	struct ath9k_hw_cal_data *caldata = ah->caldata;896 897	memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));898	for (i = 0; i < MAX_MEASUREMENT / 2; i++) {899		tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =900					AR_PHY_TX_IQCAL_CORR_COEFF_B0(ah, i);901		if (!AR_SREV_9485(ah)) {902			tx_corr_coeff[i * 2][1] =903			tx_corr_coeff[(i * 2) + 1][1] =904					AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);905 906			tx_corr_coeff[i * 2][2] =907			tx_corr_coeff[(i * 2) + 1][2] =908					AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);909		}910	}911 912	/* Load the average of 2 passes */913	for (i = 0; i < AR9300_MAX_CHAINS; i++) {914		if (!(ah->txchainmask & (1 << i)))915			continue;916		nmeasurement = REG_READ_FIELD(ah,917				AR_PHY_TX_IQCAL_STATUS_B0(ah),918				AR_PHY_CALIBRATED_GAINS_0);919 920		if (nmeasurement > MAX_MEASUREMENT)921			nmeasurement = MAX_MEASUREMENT;922 923		/*924		 * Skip normal outlier detection for AR9550.925		 */926		if (!AR_SREV_9550(ah)) {927			/* detect outlier only if nmeasurement > 1 */928			if (nmeasurement > 1) {929				/* Detect magnitude outlier */930				ar9003_hw_detect_outlier(coeff->mag_coeff[i],931							 nmeasurement,932							 MAX_MAG_DELTA);933 934				/* Detect phase outlier */935				ar9003_hw_detect_outlier(coeff->phs_coeff[i],936							 nmeasurement,937							 MAX_PHS_DELTA);938			}939		}940 941		for (im = 0; im < nmeasurement; im++) {942			magnitude = coeff->mag_coeff[i][im][0];943			phase = coeff->phs_coeff[i][im][0];944 945			coeff->iqc_coeff[0] =946				(phase & 0x7f) | ((magnitude & 0x7f) << 7);947 948			if ((im % 2) == 0)949				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],950					AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,951					coeff->iqc_coeff[0]);952			else953				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],954					AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,955					coeff->iqc_coeff[0]);956 957			if (caldata)958				caldata->tx_corr_coeff[im][i] =959					coeff->iqc_coeff[0];960		}961		if (caldata)962			caldata->num_measures[i] = nmeasurement;963	}964 965	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,966		      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);967	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,968		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);969 970	if (caldata) {971		if (is_reusable)972			set_bit(TXIQCAL_DONE, &caldata->cal_flags);973		else974			clear_bit(TXIQCAL_DONE, &caldata->cal_flags);975	}976 977	return;978}979 980static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)981{982	struct ath_common *common = ath9k_hw_common(ah);983	u8 tx_gain_forced;984 985	tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,986					AR_PHY_TXGAIN_FORCE);987	if (tx_gain_forced)988		REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,989			      AR_PHY_TXGAIN_FORCE, 0);990 991	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah),992		      AR_PHY_TX_IQCAL_START_DO_CAL, 1);993 994	if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START(ah),995			AR_PHY_TX_IQCAL_START_DO_CAL, 0,996			AH_WAIT_TIMEOUT)) {997		ath_dbg(common, CALIBRATE, "Tx IQ Cal is not completed\n");998		return false;999	}1000	return true;1001}1002 1003static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah,1004				    struct coeff *coeff,1005				    int i, int nmeasurement)1006{1007	struct ath_common *common = ath9k_hw_common(ah);1008	int im, ix, iy;1009 1010	for (im = 0; im < nmeasurement; im++) {1011		for (ix = 0; ix < MAXIQCAL - 1; ix++) {1012			for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) {1013				if (coeff->mag_coeff[i][im][iy] <1014				    coeff->mag_coeff[i][im][ix]) {1015					swap(coeff->mag_coeff[i][im][ix],1016					     coeff->mag_coeff[i][im][iy]);1017				}1018				if (coeff->phs_coeff[i][im][iy] <1019				    coeff->phs_coeff[i][im][ix]) {1020					swap(coeff->phs_coeff[i][im][ix],1021					     coeff->phs_coeff[i][im][iy]);1022				}1023			}1024		}1025		coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2];1026		coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2];1027 1028		ath_dbg(common, CALIBRATE,1029			"IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n",1030			i, im,1031			coeff->mag_coeff[i][im][0],1032			coeff->phs_coeff[i][im][0]);1033	}1034}1035 1036static bool ar955x_tx_iq_cal_median(struct ath_hw *ah,1037				    struct coeff *coeff,1038				    int iqcal_idx,1039				    int nmeasurement)1040{1041	int i;1042 1043	if ((iqcal_idx + 1) != MAXIQCAL)1044		return false;1045 1046	for (i = 0; i < AR9300_MAX_CHAINS; i++) {1047		__ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement);1048	}1049 1050	return true;1051}1052 1053static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,1054					  int iqcal_idx,1055					  bool is_reusable)1056{1057	struct ath_common *common = ath9k_hw_common(ah);1058	const u32 txiqcal_status[AR9300_MAX_CHAINS] = {1059		AR_PHY_TX_IQCAL_STATUS_B0(ah),1060		AR_PHY_TX_IQCAL_STATUS_B1,1061		AR_PHY_TX_IQCAL_STATUS_B2,1062	};1063	const u_int32_t chan_info_tab[] = {1064		AR_PHY_CHAN_INFO_TAB_0,1065		AR_PHY_CHAN_INFO_TAB_1,1066		AR_PHY_CHAN_INFO_TAB_2,1067	};1068	static struct coeff coeff;1069	s32 iq_res[6];1070	int i, im, j;1071	int nmeasurement = 0;1072	bool outlier_detect = true;1073 1074	for (i = 0; i < AR9300_MAX_CHAINS; i++) {1075		if (!(ah->txchainmask & (1 << i)))1076			continue;1077 1078		nmeasurement = REG_READ_FIELD(ah,1079				AR_PHY_TX_IQCAL_STATUS_B0(ah),1080				AR_PHY_CALIBRATED_GAINS_0);1081		if (nmeasurement > MAX_MEASUREMENT)1082			nmeasurement = MAX_MEASUREMENT;1083 1084		for (im = 0; im < nmeasurement; im++) {1085			ath_dbg(common, CALIBRATE,1086				"Doing Tx IQ Cal for chain %d\n", i);1087 1088			if (REG_READ(ah, txiqcal_status[i]) &1089					AR_PHY_TX_IQCAL_STATUS_FAILED) {1090				ath_dbg(common, CALIBRATE,1091					"Tx IQ Cal failed for chain %d\n", i);1092				goto tx_iqcal_fail;1093			}1094 1095			for (j = 0; j < 3; j++) {1096				u32 idx = 2 * j, offset = 4 * (3 * im + j);1097 1098				REG_RMW_FIELD(ah,1099						AR_PHY_CHAN_INFO_MEMORY(ah),1100						AR_PHY_CHAN_INFO_TAB_S2_READ,1101						0);1102 1103				/* 32 bits */1104				iq_res[idx] = REG_READ(ah,1105						chan_info_tab[i] +1106						offset);1107 1108				REG_RMW_FIELD(ah,1109						AR_PHY_CHAN_INFO_MEMORY(ah),1110						AR_PHY_CHAN_INFO_TAB_S2_READ,1111						1);1112 1113				/* 16 bits */1114				iq_res[idx + 1] = 0xffff & REG_READ(ah,1115						chan_info_tab[i] + offset);1116 1117				ath_dbg(common, CALIBRATE,1118					"IQ_RES[%d]=0x%x IQ_RES[%d]=0x%x\n",1119					idx, iq_res[idx], idx + 1,1120					iq_res[idx + 1]);1121			}1122 1123			if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,1124						coeff.iqc_coeff)) {1125				ath_dbg(common, CALIBRATE,1126					"Failed in calculation of IQ correction\n");1127				goto tx_iqcal_fail;1128			}1129 1130			coeff.phs_coeff[i][im][iqcal_idx] =1131				coeff.iqc_coeff[0] & 0x7f;1132			coeff.mag_coeff[i][im][iqcal_idx] =1133				(coeff.iqc_coeff[0] >> 7) & 0x7f;1134 1135			if (coeff.mag_coeff[i][im][iqcal_idx] > 63)1136				coeff.mag_coeff[i][im][iqcal_idx] -= 128;1137			if (coeff.phs_coeff[i][im][iqcal_idx] > 63)1138				coeff.phs_coeff[i][im][iqcal_idx] -= 128;1139		}1140	}1141 1142	if (AR_SREV_9550(ah))1143		outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff,1144							 iqcal_idx, nmeasurement);1145	if (outlier_detect)1146		ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);1147 1148	return;1149 1150tx_iqcal_fail:1151	ath_dbg(common, CALIBRATE, "Tx IQ Cal failed\n");1152	return;1153}1154 1155static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)1156{1157	struct ath9k_hw_cal_data *caldata = ah->caldata;1158	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];1159	int i, im;1160 1161	memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));1162	for (i = 0; i < MAX_MEASUREMENT / 2; i++) {1163		tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =1164					AR_PHY_TX_IQCAL_CORR_COEFF_B0(ah, i);1165		if (!AR_SREV_9485(ah)) {1166			tx_corr_coeff[i * 2][1] =1167			tx_corr_coeff[(i * 2) + 1][1] =1168					AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);1169 1170			tx_corr_coeff[i * 2][2] =1171			tx_corr_coeff[(i * 2) + 1][2] =1172					AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);1173		}1174	}1175 1176	for (i = 0; i < AR9300_MAX_CHAINS; i++) {1177		if (!(ah->txchainmask & (1 << i)))1178			continue;1179 1180		for (im = 0; im < caldata->num_measures[i]; im++) {1181			if ((im % 2) == 0)1182				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],1183				     AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,1184				     caldata->tx_corr_coeff[im][i]);1185			else1186				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],1187				     AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,1188				     caldata->tx_corr_coeff[im][i]);1189		}1190	}1191 1192	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,1193		      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);1194	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,1195		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);1196}1197 1198static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)1199{1200	int offset[8] = {0}, total = 0, test;1201	int agc_out, i, peak_detect_threshold = 0;1202 1203	if (AR_SREV_9550(ah) || AR_SREV_9531(ah))1204		peak_detect_threshold = 8;1205	else if (AR_SREV_9561(ah))1206		peak_detect_threshold = 11;1207 1208	/*1209	 * Turn off LNA/SW.1210	 */1211	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),1212		      AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1);1213	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),1214		      AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0);1215 1216	if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9330_11(ah)) {1217		if (is_2g)1218			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),1219				      AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);1220		else1221			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),1222				      AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);1223	}1224 1225	/*1226	 * Turn off RXON.1227	 */1228	REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),1229		      AR_PHY_65NM_RXTX2_RXON_OVR, 0x1);1230	REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),1231		      AR_PHY_65NM_RXTX2_RXON, 0x0);1232 1233	/*1234	 * Turn on AGC for cal.1235	 */1236	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1237		      AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);1238	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1239		      AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1);1240	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1241		      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1);1242 1243	if (AR_SREV_9330_11(ah))1244		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1245			      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0);1246 1247	if (is_2g)1248		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1249			      AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,1250			      peak_detect_threshold);1251	else1252		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1253			      AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR,1254			      peak_detect_threshold);1255 1256	for (i = 6; i > 0; i--) {1257		offset[i] = BIT(i - 1);1258		test = total + offset[i];1259 1260		if (is_2g)1261			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1262				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,1263				      test);1264		else1265			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1266				      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,1267				      test);1268		udelay(100);1269		agc_out = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1270					 AR_PHY_65NM_RXRF_AGC_AGC_OUT);1271		offset[i] = (agc_out) ? 0 : 1;1272		total += (offset[i] << (i - 1));1273	}1274 1275	if (is_2g)1276		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1277			      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, total);1278	else1279		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1280			      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total);1281 1282	/*1283	 * Turn on LNA.1284	 */1285	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),1286		      AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0);1287	/*1288	 * Turn off RXON.1289	 */1290	REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),1291		      AR_PHY_65NM_RXTX2_RXON_OVR, 0);1292	/*1293	 * Turn off peak detect calibration.1294	 */1295	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),1296		      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);1297}1298 1299static void ar9003_hw_do_pcoem_manual_peak_cal(struct ath_hw *ah,1300					       struct ath9k_channel *chan,1301					       bool run_rtt_cal)1302{1303	struct ath9k_hw_cal_data *caldata = ah->caldata;1304	int i;1305 1306	if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && !run_rtt_cal)1307		return;1308 1309	for (i = 0; i < AR9300_MAX_CHAINS; i++) {1310		if (!(ah->rxchainmask & (1 << i)))1311			continue;1312		ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));1313	}1314 1315	if (caldata)1316		set_bit(SW_PKDET_DONE, &caldata->cal_flags);1317 1318	if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && caldata) {1319		if (IS_CHAN_2GHZ(chan)){1320			caldata->caldac[0] = REG_READ_FIELD(ah,1321						    AR_PHY_65NM_RXRF_AGC(0),1322						    AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);1323			caldata->caldac[1] = REG_READ_FIELD(ah,1324						    AR_PHY_65NM_RXRF_AGC(1),1325						    AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);1326		} else {1327			caldata->caldac[0] = REG_READ_FIELD(ah,1328						    AR_PHY_65NM_RXRF_AGC(0),1329						    AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);1330			caldata->caldac[1] = REG_READ_FIELD(ah,1331						    AR_PHY_65NM_RXRF_AGC(1),1332						    AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);1333		}1334	}1335}1336 1337static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)1338{1339	u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,1340					  AR_PHY_CL_TAB_1,1341					  AR_PHY_CL_TAB_2 };1342	struct ath9k_hw_cal_data *caldata = ah->caldata;1343	bool txclcal_done = false;1344	int i, j;1345 1346	if (!caldata || !(ah->enabled_cals & TX_CL_CAL))1347		return;1348 1349	txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) &1350			  AR_PHY_AGC_CONTROL_CLC_SUCCESS);1351 1352	if (test_bit(TXCLCAL_DONE, &caldata->cal_flags)) {1353		for (i = 0; i < AR9300_MAX_CHAINS; i++) {1354			if (!(ah->txchainmask & (1 << i)))1355				continue;1356			for (j = 0; j < MAX_CL_TAB_ENTRY; j++)1357				REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),1358					  caldata->tx_clcal[i][j]);1359		}1360	} else if (is_reusable && txclcal_done) {1361		for (i = 0; i < AR9300_MAX_CHAINS; i++) {1362			if (!(ah->txchainmask & (1 << i)))1363				continue;1364			for (j = 0; j < MAX_CL_TAB_ENTRY; j++)1365				caldata->tx_clcal[i][j] =1366					REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));1367		}1368		set_bit(TXCLCAL_DONE, &caldata->cal_flags);1369	}1370}1371 1372static void ar9003_hw_init_cal_common(struct ath_hw *ah)1373{1374	struct ath9k_hw_cal_data *caldata = ah->caldata;1375 1376	/* Initialize list pointers */1377	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;1378 1379	INIT_CAL(&ah->iq_caldata);1380	INSERT_CAL(ah, &ah->iq_caldata);1381 1382	/* Initialize current pointer to first element in list */1383	ah->cal_list_curr = ah->cal_list;1384 1385	if (ah->cal_list_curr)1386		ath9k_hw_reset_calibration(ah, ah->cal_list_curr);1387 1388	if (caldata)1389		caldata->CalValid = 0;1390}1391 1392static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,1393				     struct ath9k_channel *chan)1394{1395	struct ath_common *common = ath9k_hw_common(ah);1396	struct ath9k_hw_cal_data *caldata = ah->caldata;1397	bool txiqcal_done = false;1398	bool is_reusable = true, status = true;1399	bool run_rtt_cal = false, run_agc_cal;1400	bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);1401	u32 rx_delay = 0;1402	u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |1403					  AR_PHY_AGC_CONTROL_FLTR_CAL   |1404					  AR_PHY_AGC_CONTROL_PKDET_CAL;1405 1406	/* Use chip chainmask only for calibration */1407	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);1408 1409	if (rtt) {1410		if (!ar9003_hw_rtt_restore(ah, chan))1411			run_rtt_cal = true;1412 1413		if (run_rtt_cal)1414			ath_dbg(common, CALIBRATE, "RTT calibration to be done\n");1415	}1416 1417	run_agc_cal = run_rtt_cal;1418 1419	if (run_rtt_cal) {1420		ar9003_hw_rtt_enable(ah);1421		ar9003_hw_rtt_set_mask(ah, 0x00);1422		ar9003_hw_rtt_clear_hist(ah);1423	}1424 1425	if (rtt) {1426		if (!run_rtt_cal) {1427			agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL(ah));1428			agc_supp_cals &= agc_ctrl;1429			agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |1430				      AR_PHY_AGC_CONTROL_FLTR_CAL |1431				      AR_PHY_AGC_CONTROL_PKDET_CAL);1432			REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), agc_ctrl);1433		} else {1434			if (ah->ah_flags & AH_FASTCC)1435				run_agc_cal = true;1436		}1437	}1438 1439	if (ah->enabled_cals & TX_CL_CAL) {1440		if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags))1441			REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,1442				    AR_PHY_CL_CAL_ENABLE);1443		else {1444			REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL,1445				    AR_PHY_CL_CAL_ENABLE);1446			run_agc_cal = true;1447		}1448	}1449 1450	if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ||1451	    !(ah->enabled_cals & TX_IQ_CAL))1452		goto skip_tx_iqcal;1453 1454	/* Do Tx IQ Calibration */1455	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah),1456		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,1457		      DELPT);1458 1459	/*1460	 * For AR9485 or later chips, TxIQ cal runs as part of1461	 * AGC calibration1462	 */1463	if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {1464		if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags))1465			REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),1466				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);1467		else1468			REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),1469				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);1470		txiqcal_done = run_agc_cal = true;1471	}1472 1473skip_tx_iqcal:1474	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)1475		ar9003_mci_init_cal_req(ah, &is_reusable);1476 1477	if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {1478		rx_delay = REG_READ(ah, AR_PHY_RX_DELAY);1479		/* Disable BB_active */1480		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);1481		udelay(5);1482		REG_WRITE(ah, AR_PHY_RX_DELAY, AR_PHY_RX_DELAY_DELAY);1483		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);1484	}1485 1486	if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {1487		/* Calibrate the AGC */1488		REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah),1489			  REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) |1490			  AR_PHY_AGC_CONTROL_CAL);1491 1492		/* Poll for offset calibration complete */1493		status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah),1494				       AR_PHY_AGC_CONTROL_CAL,1495				       0, AH_WAIT_TIMEOUT);1496 1497		ar9003_hw_do_pcoem_manual_peak_cal(ah, chan, run_rtt_cal);1498	}1499 1500	if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {1501		REG_WRITE(ah, AR_PHY_RX_DELAY, rx_delay);1502		udelay(5);1503	}1504 1505	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)1506		ar9003_mci_init_cal_done(ah);1507 1508	if (rtt && !run_rtt_cal) {1509		agc_ctrl |= agc_supp_cals;1510		REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), agc_ctrl);1511	}1512 1513	if (!status) {1514		if (run_rtt_cal)1515			ar9003_hw_rtt_disable(ah);1516 1517		ath_dbg(common, CALIBRATE,1518			"offset calibration failed to complete in %d ms; noisy environment?\n",1519			AH_WAIT_TIMEOUT / 1000);1520		return false;1521	}1522 1523	if (txiqcal_done)1524		ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);1525	else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))1526		ar9003_hw_tx_iq_cal_reload(ah);1527 1528	ar9003_hw_cl_cal_post_proc(ah, is_reusable);1529 1530	if (run_rtt_cal && caldata) {1531		if (is_reusable) {1532			if (!ath9k_hw_rfbus_req(ah)) {1533				ath_err(ath9k_hw_common(ah),1534					"Could not stop baseband\n");1535			} else {1536				ar9003_hw_rtt_fill_hist(ah);1537 1538				if (test_bit(SW_PKDET_DONE, &caldata->cal_flags))1539					ar9003_hw_rtt_load_hist(ah);1540			}1541 1542			ath9k_hw_rfbus_done(ah);1543		}1544 1545		ar9003_hw_rtt_disable(ah);1546	}1547 1548	/* Revert chainmask to runtime parameters */1549	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);1550 1551	ar9003_hw_init_cal_common(ah);1552 1553	return true;1554}1555 1556static bool do_ar9003_agc_cal(struct ath_hw *ah)1557{1558	struct ath_common *common = ath9k_hw_common(ah);1559	bool status;1560 1561	REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah),1562		  REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) |1563		  AR_PHY_AGC_CONTROL_CAL);1564 1565	status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah),1566			       AR_PHY_AGC_CONTROL_CAL,1567			       0, AH_WAIT_TIMEOUT);1568	if (!status) {1569		ath_dbg(common, CALIBRATE,1570			"offset calibration failed to complete in %d ms,"1571			"noisy environment?\n",1572			AH_WAIT_TIMEOUT / 1000);1573		return false;1574	}1575 1576	return true;1577}1578 1579static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,1580				   struct ath9k_channel *chan)1581{1582	bool txiqcal_done = false;1583	bool status = true;1584	bool run_agc_cal = false, sep_iq_cal = false;1585	int i = 0;1586 1587	/* Use chip chainmask only for calibration */1588	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);1589 1590	if (ah->enabled_cals & TX_CL_CAL) {1591		REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);1592		run_agc_cal = true;1593	}1594 1595	if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))1596		goto skip_tx_iqcal;1597 1598	/* Do Tx IQ Calibration */1599	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah),1600		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,1601		      DELPT);1602 1603	/*1604	 * For AR9485 or later chips, TxIQ cal runs as part of1605	 * AGC calibration. Specifically, AR9550 in SoC chips.1606	 */1607	if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {1608		if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah),1609				   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) {1610				txiqcal_done = true;1611		} else {1612			txiqcal_done = false;1613		}1614		run_agc_cal = true;1615	} else {1616		sep_iq_cal = true;1617		run_agc_cal = true;1618	}1619 1620	/*1621	 * In the SoC family, this will run for AR9300, AR9331 and AR9340.1622	 */1623	if (sep_iq_cal) {1624		txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);1625		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);1626		udelay(5);1627		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);1628	}1629 1630	if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) {1631		if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done))1632			return false;1633	}1634 1635skip_tx_iqcal:1636	if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {1637		for (i = 0; i < AR9300_MAX_CHAINS; i++) {1638			if (!(ah->rxchainmask & (1 << i)))1639				continue;1640 1641			ar9003_hw_manual_peak_cal(ah, i,1642						  IS_CHAN_2GHZ(chan));1643		}1644 1645		/*1646		 * For non-AR9550 chips, we just trigger AGC calibration1647		 * in the HW, poll for completion and then process1648		 * the results.1649		 *1650		 * For AR955x, we run it multiple times and use1651		 * median IQ correction.1652		 */1653		if (!AR_SREV_9550(ah)) {1654			status = do_ar9003_agc_cal(ah);1655			if (!status)1656				return false;1657 1658			if (txiqcal_done)1659				ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);1660		} else {1661			if (!txiqcal_done) {1662				status = do_ar9003_agc_cal(ah);1663				if (!status)1664					return false;1665			} else {1666				for (i = 0; i < MAXIQCAL; i++) {1667					status = do_ar9003_agc_cal(ah);1668					if (!status)1669						return false;1670					ar9003_hw_tx_iq_cal_post_proc(ah, i, false);1671				}1672			}1673		}1674	}1675 1676	/* Revert chainmask to runtime parameters */1677	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);1678 1679	ar9003_hw_init_cal_common(ah);1680 1681	return true;1682}1683 1684void ar9003_hw_attach_calib_ops(struct ath_hw *ah)1685{1686	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);1687	struct ath_hw_ops *ops = ath9k_hw_ops(ah);1688 1689	if (AR_SREV_9003_PCOEM(ah))1690		priv_ops->init_cal = ar9003_hw_init_cal_pcoem;1691	else1692		priv_ops->init_cal = ar9003_hw_init_cal_soc;1693 1694	priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;1695	priv_ops->setup_calibration = ar9003_hw_setup_calibration;1696 1697	ops->calibrate = ar9003_hw_calibrate;1698}1699