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