153541Sshin/* 253541Sshin * Copyright (c) 2010-2011 Atheros Communications Inc. 353541Sshin * 453541Sshin * Permission to use, copy, modify, and/or distribute this software for any 553541Sshin * purpose with or without fee is hereby granted, provided that the above 653541Sshin * copyright notice and this permission notice appear in all copies. 753541Sshin * 853541Sshin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 953541Sshin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1053541Sshin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1153541Sshin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1253541Sshin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1353541Sshin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1453541Sshin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1553541Sshin */ 1653541Sshin 1753541Sshin#include "hw.h" 1853541Sshin#include "hw-ops.h" 1953541Sshin#include "ar9003_phy.h" 2053541Sshin#include "ar9003_rtt.h" 2153541Sshin#include "ar9003_mci.h" 2253541Sshin 2353541Sshin#define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT 2453541Sshin#define MAX_MAG_DELTA 11 2553541Sshin#define MAX_PHS_DELTA 10 2653541Sshin#define MAXIQCAL 3 2753541Sshin 2853541Sshinstruct coeff { 2953541Sshin int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; 3053541Sshin int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; 3153541Sshin int iqc_coeff[2]; 3253541Sshin}; 3353541Sshin 3453541Sshinenum ar9003_cal_types { 3553541Sshin IQ_MISMATCH_CAL = BIT(0), 3653541Sshin}; 3753541Sshin 3853541Sshinstatic void ar9003_hw_setup_calibration(struct ath_hw *ah, 3953541Sshin struct ath9k_cal_list *currCal) 4053541Sshin{ 4153541Sshin struct ath_common *common = ath9k_hw_common(ah); 4253541Sshin 4353541Sshin /* Select calibration to run */ 4453541Sshin switch (currCal->calData->calType) { 4553541Sshin case IQ_MISMATCH_CAL: 4653541Sshin /* 4753541Sshin * Start calibration with 4853541Sshin * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples 4953541Sshin */ 5053541Sshin REG_RMW_FIELD(ah, AR_PHY_TIMING4, 5153541Sshin AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, 5253541Sshin currCal->calData->calCountMax); 5353541Sshin REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 5453541Sshin 5553541Sshin ath_dbg(common, CALIBRATE, 5653541Sshin "starting IQ Mismatch Calibration\n"); 5753541Sshin 5853541Sshin /* Kick-off cal */ 5953541Sshin REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); 6053541Sshin break; 6153541Sshin default: 6253541Sshin ath_err(common, "Invalid calibration type\n"); 6355009Sshin break; 6478064Sume } 6555009Sshin} 6653541Sshin 6795759Stanimura/* 6895759Stanimura * Generic calibration routine. 6953541Sshin * Recalibrate the lower PHY chips to account for temperature/environment 7095759Stanimura * changes. 7153541Sshin */ 7295759Stanimurastatic bool ar9003_hw_per_calibration(struct ath_hw *ah, 7395759Stanimura struct ath9k_channel *ichan, 7453541Sshin u8 rxchainmask, 7553541Sshin struct ath9k_cal_list *currCal) 7695759Stanimura{ 7753541Sshin struct ath9k_hw_cal_data *caldata = ah->caldata; 7853541Sshin const struct ath9k_percal_data *cur_caldata = currCal->calData; 7953541Sshin 8095759Stanimura /* Calibration in progress. */ 8153541Sshin if (currCal->calState == CAL_RUNNING) { 8253541Sshin /* Check to see if it has finished. */ 8353541Sshin if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL) 8453541Sshin return false; 8553541Sshin 8695759Stanimura /* 8795759Stanimura * Accumulate cal measures for active chains 8862587Sitojun */ 8995759Stanimura cur_caldata->calCollect(ah); 9056723Sshin ah->cal_samples++; 9153541Sshin 9295759Stanimura if (ah->cal_samples >= cur_caldata->calNumSamples) { 9353541Sshin unsigned int i, numChains = 0; 9495759Stanimura for (i = 0; i < AR9300_MAX_CHAINS; i++) { 9562587Sitojun if (rxchainmask & (1 << i)) 9662587Sitojun numChains++; 9762587Sitojun } 9853541Sshin 9953541Sshin /* 10053541Sshin * Process accumulated data 10153541Sshin */ 10253541Sshin cur_caldata->calPostProc(ah, numChains); 10353541Sshin 104105199Ssam /* Calibration has finished. */ 105105199Ssam caldata->CalValid |= cur_caldata->calType; 106105199Ssam currCal->calState = CAL_DONE; 107105199Ssam return true; 108105199Ssam } else { 10953541Sshin /* 11053541Sshin * Set-up collection of another sub-sample until we 11153541Sshin * get desired number 11253541Sshin */ 11353541Sshin ar9003_hw_setup_calibration(ah, currCal); 11453541Sshin } 11553541Sshin } else if (!(caldata->CalValid & cur_caldata->calType)) { 11653541Sshin /* If current cal is marked invalid in channel, kick it off */ 11753541Sshin ath9k_hw_reset_calibration(ah, currCal); 11853541Sshin } 11953541Sshin 12053541Sshin return false; 12153541Sshin} 12253541Sshin 12378064Sumestatic int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, 12478064Sume u8 rxchainmask, bool longcal) 12553541Sshin{ 12653541Sshin bool iscaldone = true; 12753541Sshin struct ath9k_cal_list *currCal = ah->cal_list_curr; 12853541Sshin int ret; 12953541Sshin 13053541Sshin /* 13153541Sshin * For given calibration: 13253541Sshin * 1. Call generic cal routine 13353541Sshin * 2. When this cal is done (isCalDone) if we have more cals waiting 13453541Sshin * (eg after reset), mask this to upper layers by not propagating 13553541Sshin * isCalDone if it is set to TRUE. 13653541Sshin * Instead, change isCalDone to FALSE and setup the waiting cal(s) 13753541Sshin * to be run. 13853541Sshin */ 13978064Sume if (currCal && 140121901Sume (currCal->calState == CAL_RUNNING || 14153541Sshin currCal->calState == CAL_WAITING)) { 14278064Sume iscaldone = ar9003_hw_per_calibration(ah, chan, 14378064Sume rxchainmask, currCal); 14483934Sbrooks if (iscaldone) { 14578064Sume ah->cal_list_curr = currCal = currCal->calNext; 14678064Sume 14778064Sume if (currCal->calState == CAL_WAITING) { 14853541Sshin iscaldone = false; 14978064Sume ath9k_hw_reset_calibration(ah, currCal); 150121901Sume } 15153541Sshin } 152132714Srwatson } 15353541Sshin 154132714Srwatson /* 155132714Srwatson * Do NF cal only at longer intervals. Get the value from 156132714Srwatson * the previous NF cal and update history buffer. 157132714Srwatson */ 15853541Sshin if (longcal && ath9k_hw_getnf(ah, chan)) { 159132714Srwatson /* 16053541Sshin * Load the NF from history buffer of the current channel. 16153541Sshin * NF is slow time-variant, so it is OK to use a historical 162132714Srwatson * value. 16353541Sshin */ 16453541Sshin ret = ath9k_hw_loadnf(ah, ah->curchan); 165132714Srwatson if (ret < 0) 16653541Sshin return ret; 16753541Sshin 168132714Srwatson /* start NF calibration, without updating BB NF register */ 16978064Sume ath9k_hw_start_nfcal(ah, false); 17078064Sume } 17178064Sume 17278064Sume return iscaldone; 17378064Sume} 174132714Srwatson 17578064Sumestatic void ar9003_hw_iqcal_collect(struct ath_hw *ah) 17653541Sshin{ 17753541Sshin int i; 17853541Sshin 17978064Sume /* Accumulate IQ cal measures for active chains */ 180125941Sume for (i = 0; i < AR9300_MAX_CHAINS; i++) { 18178064Sume if (ah->txchainmask & BIT(i)) { 18278064Sume ah->totalPowerMeasI[i] += 18378064Sume REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 184125396Sume ah->totalPowerMeasQ[i] += 18578064Sume REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 186125941Sume ah->totalIqCorrMeas[i] += 18778064Sume (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 18878064Sume ath_dbg(ath9k_hw_common(ah), CALIBRATE, 189105199Ssam "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", 190105199Ssam ah->cal_samples, i, ah->totalPowerMeasI[i], 191125941Sume ah->totalPowerMeasQ[i], 19253541Sshin ah->totalIqCorrMeas[i]); 19397658Stanimura } 19497658Stanimura } 195121674Sume} 19653541Sshin 19753541Sshinstatic void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) 19853541Sshin{ 199121901Sume struct ath_common *common = ath9k_hw_common(ah); 20053541Sshin u32 powerMeasQ, powerMeasI, iqCorrMeas; 20153541Sshin u32 qCoffDenom, iCoffDenom; 20253541Sshin int32_t qCoff, iCoff; 20353541Sshin int iqCorrNeg, i; 20478064Sume static const u_int32_t offset_array[3] = { 20597658Stanimura AR_PHY_RX_IQCAL_CORR_B0, 20653541Sshin AR_PHY_RX_IQCAL_CORR_B1, 20753541Sshin AR_PHY_RX_IQCAL_CORR_B2, 20853541Sshin }; 209132714Srwatson 21053541Sshin for (i = 0; i < numChains; i++) { 21153541Sshin powerMeasI = ah->totalPowerMeasI[i]; 21253541Sshin powerMeasQ = ah->totalPowerMeasQ[i]; 213125941Sume iqCorrMeas = ah->totalIqCorrMeas[i]; 21478064Sume 21578064Sume ath_dbg(common, CALIBRATE, 21678064Sume "Starting IQ Cal and Correction for Chain %d\n", i); 217125396Sume 21878064Sume ath_dbg(common, CALIBRATE, 219125941Sume "Original: Chn %d iq_corr_meas = 0x%08x\n", 22078064Sume i, ah->totalIqCorrMeas[i]); 22178064Sume 222105199Ssam iqCorrNeg = 0; 223105199Ssam 224105199Ssam if (iqCorrMeas > 0x80000000) { 225125941Sume iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; 22653541Sshin iqCorrNeg = 1; 22797658Stanimura } 22897658Stanimura 229121674Sume ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n", 23053541Sshin i, powerMeasI); 23153541Sshin ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n", 23253541Sshin i, powerMeasQ); 233121901Sume ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg); 23453541Sshin 23553541Sshin iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256; 23653541Sshin qCoffDenom = powerMeasQ / 64; 23778064Sume 23897658Stanimura if ((iCoffDenom != 0) && (qCoffDenom != 0)) { 23953541Sshin iCoff = iqCorrMeas / iCoffDenom; 240132714Srwatson qCoff = powerMeasI / qCoffDenom - 64; 24153541Sshin ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n", 24278064Sume i, iCoff); 24378064Sume ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n", 24478064Sume i, qCoff); 24553541Sshin 24653541Sshin /* Force bounds on iCoff */ 24753541Sshin if (iCoff >= 63) 24853541Sshin iCoff = 63; 24953541Sshin else if (iCoff <= -63) 25053541Sshin iCoff = -63; 25153541Sshin 25253541Sshin /* Negate iCoff if iqCorrNeg == 0 */ 25353541Sshin if (iqCorrNeg == 0x0) 25453541Sshin iCoff = -iCoff; 255134655Srwatson 25653541Sshin /* Force bounds on qCoff */ 25753541Sshin if (qCoff >= 63) 25853541Sshin qCoff = 63; 25962587Sitojun else if (qCoff <= -63) 26062587Sitojun qCoff = -63; 26162587Sitojun 26262587Sitojun iCoff = iCoff & 0x7f; 26362587Sitojun qCoff = qCoff & 0x7f; 26462587Sitojun 26562587Sitojun ath_dbg(common, CALIBRATE, 26662587Sitojun "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", 26762587Sitojun i, iCoff, qCoff); 26878064Sume ath_dbg(common, CALIBRATE, 26978064Sume "Register offset (0x%04x) before update = 0x%x\n", 270125776Sume offset_array[i], 27198211Shsu REG_READ(ah, offset_array[i])); 27262587Sitojun 27362587Sitojun if (AR_SREV_9565(ah) && 27462587Sitojun (iCoff == 63 || qCoff == 63 || 27562587Sitojun iCoff == -63 || qCoff == -63)) 27662587Sitojun return; 27762587Sitojun 27862587Sitojun REG_RMW_FIELD(ah, offset_array[i], 27962587Sitojun AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 28062587Sitojun iCoff); 28162587Sitojun REG_RMW_FIELD(ah, offset_array[i], 28262587Sitojun AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 28362587Sitojun qCoff); 28462587Sitojun ath_dbg(common, CALIBRATE, 28562587Sitojun "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n", 28662587Sitojun offset_array[i], 28762587Sitojun AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 28878064Sume REG_READ(ah, offset_array[i])); 28962587Sitojun ath_dbg(common, CALIBRATE, 29062587Sitojun "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n", 29162587Sitojun offset_array[i], 292125776Sume AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 29378064Sume REG_READ(ah, offset_array[i])); 29462587Sitojun 29562587Sitojun ath_dbg(common, CALIBRATE, 29662587Sitojun "IQ Cal and Correction done for Chain %d\n", i); 297125776Sume } 29878064Sume } 29962587Sitojun 30062587Sitojun REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0, 301133192Srwatson AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); 302133192Srwatson ath_dbg(common, CALIBRATE, 303125776Sume "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n", 30462587Sitojun (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), 30562587Sitojun AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, 30653541Sshin REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 30753541Sshin} 30853541Sshin 30953541Sshinstatic const struct ath9k_percal_data iq_cal_single_sample = { 31053541Sshin IQ_MISMATCH_CAL, 31153541Sshin MIN_CAL_SAMPLES, 31253541Sshin PER_MAX_LOG_COUNT, 31353541Sshin ar9003_hw_iqcal_collect, 31453541Sshin ar9003_hw_iqcalibrate 31553541Sshin}; 31653541Sshin 31753541Sshinstatic void ar9003_hw_init_cal_settings(struct ath_hw *ah) 31853541Sshin{ 319120941Sume ah->iq_caldata.calData = &iq_cal_single_sample; 32053541Sshin 32153541Sshin if (AR_SREV_9300_20_OR_LATER(ah)) { 32253541Sshin ah->enabled_cals |= TX_IQ_CAL; 32353541Sshin if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah)) 32453541Sshin ah->enabled_cals |= TX_IQ_ON_AGC_CAL; 32553541Sshin } 32653541Sshin 327121472Sume ah->supp_cals = IQ_MISMATCH_CAL; 32853541Sshin} 32953541Sshin 33053541Sshin#define OFF_UPPER_LT 24 331121472Sume#define OFF_LOWER_LT 7 33253541Sshin 33353541Sshinstatic bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah, 33453541Sshin bool txiqcal_done) 33553541Sshin{ 33653541Sshin struct ath_common *common = ath9k_hw_common(ah); 33753541Sshin int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2, 33853541Sshin dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3; 33953541Sshin int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2, 34053541Sshin dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3; 341132714Srwatson int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2, 342132714Srwatson dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3; 343132714Srwatson bool status; 344132714Srwatson u32 temp, val; 345132714Srwatson 346132714Srwatson /* 347132714Srwatson * Clear offset and IQ calibration, run AGC cal. 348121472Sume */ 34953541Sshin REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), 35053541Sshin AR_PHY_AGC_CONTROL_OFFSET_CAL); 35153541Sshin REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 35253541Sshin AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 35353541Sshin REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), 35453541Sshin REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | AR_PHY_AGC_CONTROL_CAL); 355121472Sume 356121472Sume status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), 357121472Sume AR_PHY_AGC_CONTROL_CAL, 358121472Sume 0, AH_WAIT_TIMEOUT); 35953541Sshin if (!status) { 360121472Sume ath_dbg(common, CALIBRATE, 361121472Sume "AGC cal without offset cal failed to complete in 1ms"); 362121472Sume return false; 36353541Sshin } 36453541Sshin 36553541Sshin /* 36653541Sshin * Allow only offset calibration and disable the others 36753541Sshin * (Carrier Leak calibration, TX Filter calibration and 36853541Sshin * Peak Detector offset calibration). 36953541Sshin */ 37053541Sshin REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), 37153541Sshin AR_PHY_AGC_CONTROL_OFFSET_CAL); 37253541Sshin REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, 37353541Sshin AR_PHY_CL_CAL_ENABLE); 37453541Sshin REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), 37553541Sshin AR_PHY_AGC_CONTROL_FLTR_CAL); 37653541Sshin REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), 37753541Sshin AR_PHY_AGC_CONTROL_PKDET_CAL); 37853541Sshin 37953541Sshin ch0_done = 0; 380133592Srwatson ch1_done = 0; 381133592Srwatson ch2_done = 0; 382133592Srwatson 383133592Srwatson while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) { 384133592Srwatson osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3; 38553541Sshin osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3; 38653541Sshin osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3; 38753541Sshin 38853541Sshin REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 38953541Sshin 39053541Sshin REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), 39153541Sshin REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | AR_PHY_AGC_CONTROL_CAL); 39253541Sshin 39353541Sshin status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), 39453541Sshin AR_PHY_AGC_CONTROL_CAL, 39553541Sshin 0, AH_WAIT_TIMEOUT); 39653541Sshin if (!status) { 39753541Sshin ath_dbg(common, CALIBRATE, 39853541Sshin "DC offset cal failed to complete in 1ms"); 39953541Sshin return false; 40053541Sshin } 40153541Sshin 40253541Sshin REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 40353541Sshin 40453541Sshin /* 405121472Sume * High gain. 406121472Sume */ 407121472Sume REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, 40853541Sshin ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8))); 40983130Sjlemon REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, 41053541Sshin ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8))); 41153541Sshin REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, 41253541Sshin ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8))); 41353541Sshin 41453541Sshin temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); 41553541Sshin dc_off_ch0_i1 = (temp >> 26) & 0x1f; 41653541Sshin dc_off_ch0_q1 = (temp >> 21) & 0x1f; 417120941Sume 418120941Sume temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); 41953541Sshin dc_off_ch1_i1 = (temp >> 26) & 0x1f; 42053541Sshin dc_off_ch1_q1 = (temp >> 21) & 0x1f; 42153541Sshin 422120941Sume temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); 423120941Sume dc_off_ch2_i1 = (temp >> 26) & 0x1f; 42453541Sshin dc_off_ch2_q1 = (temp >> 21) & 0x1f; 42553541Sshin 42653541Sshin /* 42753541Sshin * Low gain. 42853541Sshin */ 42953541Sshin REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, 430121472Sume ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8))); 431122927Sandre REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, 432121472Sume ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8))); 433121472Sume REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, 434121472Sume ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8))); 43553541Sshin 436121472Sume temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); 43755009Sshin dc_off_ch0_i2 = (temp >> 26) & 0x1f; 43855009Sshin dc_off_ch0_q2 = (temp >> 21) & 0x1f; 43955009Sshin 44055009Sshin temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); 44153541Sshin dc_off_ch1_i2 = (temp >> 26) & 0x1f; 44253541Sshin dc_off_ch1_q2 = (temp >> 21) & 0x1f; 44353541Sshin 44453541Sshin temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); 44553541Sshin dc_off_ch2_i2 = (temp >> 26) & 0x1f; 44653541Sshin dc_off_ch2_q2 = (temp >> 21) & 0x1f; 44753541Sshin 44853541Sshin /* 44953541Sshin * Loopback. 45053541Sshin */ 45153541Sshin REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, 45253541Sshin ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8))); 45353541Sshin REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, 45453541Sshin ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8))); 45553541Sshin REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, 45653541Sshin ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8))); 45753541Sshin 45853541Sshin temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); 45953541Sshin dc_off_ch0_i3 = (temp >> 26) & 0x1f; 46053541Sshin dc_off_ch0_q3 = (temp >> 21) & 0x1f; 46153541Sshin 46253541Sshin temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); 46353541Sshin dc_off_ch1_i3 = (temp >> 26) & 0x1f; 46453541Sshin dc_off_ch1_q3 = (temp >> 21) & 0x1f; 46553541Sshin 46653541Sshin temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); 46753541Sshin dc_off_ch2_i3 = (temp >> 26) & 0x1f; 46853541Sshin dc_off_ch2_q3 = (temp >> 21) & 0x1f; 46953541Sshin 47053541Sshin if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) || 47153541Sshin (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) || 47253541Sshin (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) || 47353541Sshin (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) || 474122927Sandre (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) || 475105194Ssam (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) { 47653541Sshin if (osdac_ch0 == 3) { 47753541Sshin ch0_done = 1; 47853541Sshin } else { 47953541Sshin osdac_ch0++; 48078064Sume 48178064Sume val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff; 48253541Sshin val |= (osdac_ch0 << 30); 48353541Sshin REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val); 48453541Sshin 48553541Sshin ch0_done = 0; 48653541Sshin } 48753541Sshin } else { 48853541Sshin ch0_done = 1; 48953541Sshin } 49078064Sume 491121472Sume if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) || 492121472Sume (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) || 49353541Sshin (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) || 49478064Sume (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) || 495132714Srwatson (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) || 496120856Sume (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) { 49753541Sshin if (osdac_ch1 == 3) { 49853541Sshin ch1_done = 1; 49953541Sshin } else { 50053541Sshin osdac_ch1++; 50153541Sshin 50253541Sshin val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff; 50353541Sshin val |= (osdac_ch1 << 30); 50453541Sshin REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val); 50553541Sshin 50653541Sshin ch1_done = 0; 50753541Sshin } 50853541Sshin } else { 50953541Sshin ch1_done = 1; 51053541Sshin } 51153541Sshin 51253541Sshin if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) || 51353541Sshin (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) || 514120856Sume (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) || 51553541Sshin (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) || 51653541Sshin (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) || 51753541Sshin (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) { 51853541Sshin if (osdac_ch2 == 3) { 51953541Sshin ch2_done = 1; 52053541Sshin } else { 52153541Sshin osdac_ch2++; 52253541Sshin 52356723Sshin val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff; 52456723Sshin val |= (osdac_ch2 << 30); 52556723Sshin REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val); 52656723Sshin 52756723Sshin ch2_done = 0; 52856723Sshin } 52956723Sshin } else { 53056723Sshin ch2_done = 1; 53156723Sshin } 532121578Sume } 533121578Sume 534121578Sume REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), 53553541Sshin AR_PHY_AGC_CONTROL_OFFSET_CAL); 53653541Sshin REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 53753541Sshin 53853541Sshin /* 53953541Sshin * We don't need to check txiqcal_done here since it is always 54053541Sshin * set for AR9550. 54153541Sshin */ 54253541Sshin REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), 54356723Sshin AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 54456723Sshin 54556723Sshin return true; 54656723Sshin} 54756723Sshin 54856723Sshin/* 54956723Sshin * solve 4x4 linear equation used in loopback iq cal. 55056723Sshin */ 55156723Sshinstatic bool ar9003_hw_solve_iq_cal(struct ath_hw *ah, 552121578Sume s32 sin_2phi_1, 553121578Sume s32 cos_2phi_1, 554121578Sume s32 sin_2phi_2, 55553541Sshin s32 cos_2phi_2, 55653541Sshin s32 mag_a0_d0, 55753541Sshin s32 phs_a0_d0, 55853541Sshin s32 mag_a1_d0, 55953541Sshin s32 phs_a1_d0, 56053541Sshin s32 solved_eq[]) 56153541Sshin{ 56253541Sshin s32 f1 = cos_2phi_1 - cos_2phi_2, 56353541Sshin f3 = sin_2phi_1 - sin_2phi_2, 56453541Sshin f2; 56553541Sshin s32 mag_tx, phs_tx, mag_rx, phs_rx; 56683366Sjulian const s32 result_shift = 1 << 15; 56753541Sshin struct ath_common *common = ath9k_hw_common(ah); 56853541Sshin 56953541Sshin f2 = ((f1 >> 3) * (f1 >> 3) + (f3 >> 3) * (f3 >> 3)) >> 9; 57053541Sshin 571132714Srwatson if (!f2) { 57253541Sshin ath_dbg(common, CALIBRATE, "Divide by 0\n"); 573132714Srwatson return false; 574132714Srwatson } 57553541Sshin 576132714Srwatson /* mag mismatch, tx */ 577132714Srwatson mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0); 578132714Srwatson /* phs mismatch, tx */ 57953541Sshin phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0); 580132714Srwatson 58155009Sshin mag_tx = (mag_tx / f2); 582132714Srwatson phs_tx = (phs_tx / f2); 583132714Srwatson 58455009Sshin /* mag mismatch, rx */ 585132714Srwatson mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / 58653541Sshin result_shift; 587127504Spjd /* phs mismatch, rx */ 58853541Sshin phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / 589132714Srwatson result_shift; 590132714Srwatson 59153541Sshin solved_eq[0] = mag_tx; 592132714Srwatson solved_eq[1] = phs_tx; 59353541Sshin solved_eq[2] = mag_rx; 594132714Srwatson solved_eq[3] = phs_rx; 595132714Srwatson 59653541Sshin return true; 59753541Sshin} 59853541Sshin 59953541Sshinstatic s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im) 60053541Sshin{ 60153541Sshin s32 abs_i = abs(in_re), 60253541Sshin abs_q = abs(in_im), 603132714Srwatson max_abs, min_abs; 60453541Sshin 60553541Sshin if (abs_i > abs_q) { 60653541Sshin max_abs = abs_i; 60753541Sshin min_abs = abs_q; 60853541Sshin } else { 60953541Sshin max_abs = abs_q; 61053541Sshin min_abs = abs_i; 61153541Sshin } 612132714Srwatson 61353541Sshin return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4); 614132714Srwatson} 615132714Srwatson 61653541Sshin#define DELPT 32 617132714Srwatson 61853541Sshinstatic bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, 61957535Sshin s32 chain_idx, 62057535Sshin const s32 iq_res[], 62153541Sshin s32 iqc_coeff[]) 62253541Sshin{ 62353541Sshin s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0, 62453541Sshin i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1, 625132714Srwatson i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0, 62653541Sshin i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1; 627132714Srwatson s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1, 62853541Sshin phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1, 62953541Sshin sin_2phi_1, cos_2phi_1, 63053541Sshin sin_2phi_2, cos_2phi_2; 63153541Sshin s32 mag_tx, phs_tx, mag_rx, phs_rx; 63253541Sshin s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx, 63353541Sshin q_q_coff, q_i_coff; 63453541Sshin const s32 res_scale = 1 << 15; 63553541Sshin const s32 delpt_shift = 1 << 8; 63653541Sshin s32 mag1, mag2; 63753541Sshin struct ath_common *common = ath9k_hw_common(ah); 63853541Sshin 63953541Sshin i2_m_q2_a0_d0 = iq_res[0] & 0xfff; 64053541Sshin i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff; 64153541Sshin iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8); 64253541Sshin 64397658Stanimura if (i2_m_q2_a0_d0 > 0x800) 64453541Sshin i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1); 64553541Sshin 64653541Sshin if (i2_p_q2_a0_d0 > 0x800) 64753541Sshin i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1); 64853541Sshin 64953541Sshin if (iq_corr_a0_d0 > 0x800) 65083366Sjulian iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1); 65153541Sshin 65253541Sshin i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff; 65353541Sshin i2_p_q2_a0_d1 = (iq_res[2] & 0xfff); 65453541Sshin iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff; 65553541Sshin 65653541Sshin if (i2_m_q2_a0_d1 > 0x800) 65753541Sshin i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); 65853541Sshin 65953541Sshin if (iq_corr_a0_d1 > 0x800) 66062587Sitojun iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); 66162587Sitojun 66262587Sitojun i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8); 66362587Sitojun i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff; 66462587Sitojun iq_corr_a1_d0 = iq_res[4] & 0xfff; 66553541Sshin 66653541Sshin if (i2_m_q2_a1_d0 > 0x800) 66753541Sshin i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1); 66853541Sshin 66953541Sshin if (i2_p_q2_a1_d0 > 0x800) 67053541Sshin i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1); 67153541Sshin 672120856Sume if (iq_corr_a1_d0 > 0x800) 67353541Sshin iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1); 674132714Srwatson 675132714Srwatson i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff; 67653541Sshin i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8); 677132714Srwatson iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff; 678132714Srwatson 67953541Sshin if (i2_m_q2_a1_d1 > 0x800) 68053541Sshin i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1); 68153541Sshin 68253541Sshin if (i2_p_q2_a1_d1 > 0x800) 68383366Sjulian i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1); 68453541Sshin 68553541Sshin if (iq_corr_a1_d1 > 0x800) 68653541Sshin iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1); 68753541Sshin 68853541Sshin if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) || 68962587Sitojun (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) { 69062587Sitojun ath_dbg(common, CALIBRATE, 69162587Sitojun "Divide by 0:\n" 69253541Sshin "a0_d0=%d\n" 69353541Sshin "a0_d1=%d\n" 69453541Sshin "a2_d0=%d\n" 69553541Sshin "a1_d1=%d\n", 69653541Sshin i2_p_q2_a0_d0, i2_p_q2_a0_d1, 69753541Sshin i2_p_q2_a1_d0, i2_p_q2_a1_d1); 69853541Sshin return false; 69962587Sitojun } 70062587Sitojun 70162587Sitojun if ((i2_p_q2_a0_d0 < 1024) || (i2_p_q2_a0_d0 > 2047) || 70262587Sitojun (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) || 70362587Sitojun (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) || 70462587Sitojun (i2_p_q2_a0_d0 <= iq_corr_a0_d0) || 70562587Sitojun (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) || 70662587Sitojun (i2_p_q2_a0_d1 <= iq_corr_a0_d1) || 707132714Srwatson (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) || 708132714Srwatson (i2_p_q2_a1_d0 <= iq_corr_a1_d0) || 70953541Sshin (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) || 71053541Sshin (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) { 711122927Sandre return false; 71253541Sshin } 713132714Srwatson 714132714Srwatson mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; 715132714Srwatson phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; 71653541Sshin 717132714Srwatson mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1; 71853541Sshin phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1; 71953541Sshin 72053541Sshin mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0; 721132714Srwatson phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0; 722132714Srwatson 72353541Sshin mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1; 72453541Sshin phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1; 72553541Sshin 72653541Sshin /* w/o analog phase shift */ 72753541Sshin sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT); 72853541Sshin /* w/o analog phase shift */ 729132714Srwatson cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT); 730132714Srwatson /* w/ analog phase shift */ 731132714Srwatson sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT); 732132714Srwatson /* w/ analog phase shift */ 733132714Srwatson cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT); 734132714Srwatson 73553541Sshin /* 736132714Srwatson * force sin^2 + cos^2 = 1; 73753541Sshin * find magnitude by approximation 73853541Sshin */ 73953541Sshin mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1); 74053541Sshin mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); 74153541Sshin 74283366Sjulian if ((mag1 == 0) || (mag2 == 0)) { 74353541Sshin ath_dbg(common, CALIBRATE, "Divide by 0: mag1=%d, mag2=%d\n", 74453541Sshin mag1, mag2); 74553541Sshin return false; 74653541Sshin } 747132714Srwatson 74853541Sshin /* normalization sin and cos by mag */ 749132714Srwatson sin_2phi_1 = (sin_2phi_1 * res_scale / mag1); 75062587Sitojun cos_2phi_1 = (cos_2phi_1 * res_scale / mag1); 751132714Srwatson sin_2phi_2 = (sin_2phi_2 * res_scale / mag2); 75253541Sshin cos_2phi_2 = (cos_2phi_2 * res_scale / mag2); 75353541Sshin 754132714Srwatson /* calculate IQ mismatch */ 75553541Sshin if (!ar9003_hw_solve_iq_cal(ah, 75653541Sshin sin_2phi_1, cos_2phi_1, 75753541Sshin sin_2phi_2, cos_2phi_2, 75853541Sshin mag_a0_d0, phs_a0_d0, 75953541Sshin mag_a1_d0, 76053541Sshin phs_a1_d0, solved_eq)) { 76153541Sshin ath_dbg(common, CALIBRATE, 76253541Sshin "Call to ar9003_hw_solve_iq_cal() failed\n"); 76353541Sshin return false; 76453541Sshin } 76553541Sshin 76653541Sshin mag_tx = solved_eq[0]; 767132714Srwatson phs_tx = solved_eq[1]; 76853541Sshin mag_rx = solved_eq[2]; 76953541Sshin phs_rx = solved_eq[3]; 77053541Sshin 77162587Sitojun ath_dbg(common, CALIBRATE, 77262587Sitojun "chain %d: mag mismatch=%d phase mismatch=%d\n", 77353541Sshin chain_idx, mag_tx/res_scale, phs_tx/res_scale); 77462587Sitojun 77562587Sitojun if (res_scale == mag_tx) { 77662587Sitojun ath_dbg(common, CALIBRATE, 77762587Sitojun "Divide by 0: mag_tx=%d, res_scale=%d\n", 77862587Sitojun mag_tx, res_scale); 779132714Srwatson return false; 780132714Srwatson } 781132714Srwatson 78253541Sshin /* calculate and quantize Tx IQ correction factor */ 78353541Sshin mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx); 78453541Sshin phs_corr_tx = -phs_tx; 785137386Sphk 786137386Sphk q_q_coff = (mag_corr_tx * 128 / res_scale); 787137386Sphk q_i_coff = (phs_corr_tx * 256 / res_scale); 788137386Sphk 789137386Sphk ath_dbg(common, CALIBRATE, "tx chain %d: mag corr=%d phase corr=%d\n", 790137386Sphk chain_idx, q_q_coff, q_i_coff); 791137386Sphk 792137386Sphk if (q_i_coff < -63) 793137386Sphk q_i_coff = -63; 794137386Sphk if (q_i_coff > 63) 795137386Sphk q_i_coff = 63; 79653541Sshin 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, otherwise 870 * just use the last value as the mean 871 */ 872 if (mp_count) 873 mp_avg /= mp_count; 874 else 875 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 else 882 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 else 953 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 else 974 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 else 1186 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 else 1221 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 else 1252 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 else 1265 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 else 1279 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 of 1461 * AGC calibration 1462 */ 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 else 1468 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 of 1605 * 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 calibration 1647 * in the HW, poll for completion and then process 1648 * the results. 1649 * 1650 * For AR955x, we run it multiple times and use 1651 * 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 else 1692 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