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