18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "hw.h" 188c2ecf20Sopenharmony_ci#include "hw-ops.h" 198c2ecf20Sopenharmony_ci#include "ar9002_phy.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define AR9285_CLCAL_REDO_THRESH 1 228c2ecf20Sopenharmony_ci/* AGC & I/Q calibrations time limit, ms */ 238c2ecf20Sopenharmony_ci#define AR9002_CAL_MAX_TIME 30000 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cienum ar9002_cal_types { 268c2ecf20Sopenharmony_ci ADC_GAIN_CAL = BIT(0), 278c2ecf20Sopenharmony_ci ADC_DC_CAL = BIT(1), 288c2ecf20Sopenharmony_ci IQ_MISMATCH_CAL = BIT(2), 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic bool ar9002_hw_is_cal_supported(struct ath_hw *ah, 328c2ecf20Sopenharmony_ci struct ath9k_channel *chan, 338c2ecf20Sopenharmony_ci enum ar9002_cal_types cal_type) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci bool supported = false; 368c2ecf20Sopenharmony_ci switch (ah->supp_cals & cal_type) { 378c2ecf20Sopenharmony_ci case IQ_MISMATCH_CAL: 388c2ecf20Sopenharmony_ci supported = true; 398c2ecf20Sopenharmony_ci break; 408c2ecf20Sopenharmony_ci case ADC_GAIN_CAL: 418c2ecf20Sopenharmony_ci case ADC_DC_CAL: 428c2ecf20Sopenharmony_ci /* Run even/odd ADCs calibrations for HT40 channels only */ 438c2ecf20Sopenharmony_ci if (IS_CHAN_HT40(chan)) 448c2ecf20Sopenharmony_ci supported = true; 458c2ecf20Sopenharmony_ci break; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci return supported; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void ar9002_hw_setup_calibration(struct ath_hw *ah, 518c2ecf20Sopenharmony_ci struct ath9k_cal_list *currCal) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), 568c2ecf20Sopenharmony_ci AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, 578c2ecf20Sopenharmony_ci currCal->calData->calCountMax); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci switch (currCal->calData->calType) { 608c2ecf20Sopenharmony_ci case IQ_MISMATCH_CAL: 618c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 628c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 638c2ecf20Sopenharmony_ci "starting IQ Mismatch Calibration\n"); 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case ADC_GAIN_CAL: 668c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); 678c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "starting ADC Gain Calibration\n"); 688c2ecf20Sopenharmony_ci break; 698c2ecf20Sopenharmony_ci case ADC_DC_CAL: 708c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); 718c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "starting ADC DC Calibration\n"); 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 768c2ecf20Sopenharmony_ci AR_PHY_TIMING_CTRL4_DO_CAL); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic bool ar9002_hw_per_calibration(struct ath_hw *ah, 808c2ecf20Sopenharmony_ci struct ath9k_channel *ichan, 818c2ecf20Sopenharmony_ci u8 rxchainmask, 828c2ecf20Sopenharmony_ci struct ath9k_cal_list *currCal) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct ath9k_hw_cal_data *caldata = ah->caldata; 858c2ecf20Sopenharmony_ci bool iscaldone = false; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (currCal->calState == CAL_RUNNING) { 888c2ecf20Sopenharmony_ci if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & 898c2ecf20Sopenharmony_ci AR_PHY_TIMING_CTRL4_DO_CAL)) { 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci currCal->calData->calCollect(ah); 928c2ecf20Sopenharmony_ci ah->cal_samples++; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (ah->cal_samples >= 958c2ecf20Sopenharmony_ci currCal->calData->calNumSamples) { 968c2ecf20Sopenharmony_ci int i, numChains = 0; 978c2ecf20Sopenharmony_ci for (i = 0; i < AR5416_MAX_CHAINS; i++) { 988c2ecf20Sopenharmony_ci if (rxchainmask & (1 << i)) 998c2ecf20Sopenharmony_ci numChains++; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci currCal->calData->calPostProc(ah, numChains); 1038c2ecf20Sopenharmony_ci caldata->CalValid |= currCal->calData->calType; 1048c2ecf20Sopenharmony_ci currCal->calState = CAL_DONE; 1058c2ecf20Sopenharmony_ci iscaldone = true; 1068c2ecf20Sopenharmony_ci } else { 1078c2ecf20Sopenharmony_ci ar9002_hw_setup_calibration(ah, currCal); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci } else if (time_after(jiffies, ah->cal_start_time + 1108c2ecf20Sopenharmony_ci msecs_to_jiffies(AR9002_CAL_MAX_TIME))) { 1118c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_TIMING_CTRL4(0), 1128c2ecf20Sopenharmony_ci AR_PHY_TIMING_CTRL4_DO_CAL); 1138c2ecf20Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 1148c2ecf20Sopenharmony_ci "calibration timeout\n"); 1158c2ecf20Sopenharmony_ci currCal->calState = CAL_WAITING; /* Try later */ 1168c2ecf20Sopenharmony_ci iscaldone = true; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci } else if (!(caldata->CalValid & currCal->calData->calType)) { 1198c2ecf20Sopenharmony_ci ath9k_hw_reset_calibration(ah, currCal); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return iscaldone; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void ar9002_hw_iqcal_collect(struct ath_hw *ah) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci int i; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci for (i = 0; i < AR5416_MAX_CHAINS; i++) { 1308c2ecf20Sopenharmony_ci ah->totalPowerMeasI[i] += 1318c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 1328c2ecf20Sopenharmony_ci ah->totalPowerMeasQ[i] += 1338c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 1348c2ecf20Sopenharmony_ci ah->totalIqCorrMeas[i] += 1358c2ecf20Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 1368c2ecf20Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 1378c2ecf20Sopenharmony_ci "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", 1388c2ecf20Sopenharmony_ci ah->cal_samples, i, ah->totalPowerMeasI[i], 1398c2ecf20Sopenharmony_ci ah->totalPowerMeasQ[i], 1408c2ecf20Sopenharmony_ci ah->totalIqCorrMeas[i]); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int i; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci for (i = 0; i < AR5416_MAX_CHAINS; i++) { 1498c2ecf20Sopenharmony_ci ah->totalAdcIOddPhase[i] += 1508c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 1518c2ecf20Sopenharmony_ci ah->totalAdcIEvenPhase[i] += 1528c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 1538c2ecf20Sopenharmony_ci ah->totalAdcQOddPhase[i] += 1548c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 1558c2ecf20Sopenharmony_ci ah->totalAdcQEvenPhase[i] += 1568c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 1598c2ecf20Sopenharmony_ci "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", 1608c2ecf20Sopenharmony_ci ah->cal_samples, i, 1618c2ecf20Sopenharmony_ci ah->totalAdcIOddPhase[i], 1628c2ecf20Sopenharmony_ci ah->totalAdcIEvenPhase[i], 1638c2ecf20Sopenharmony_ci ah->totalAdcQOddPhase[i], 1648c2ecf20Sopenharmony_ci ah->totalAdcQEvenPhase[i]); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void ar9002_hw_adc_dccal_collect(struct ath_hw *ah) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci int i; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci for (i = 0; i < AR5416_MAX_CHAINS; i++) { 1738c2ecf20Sopenharmony_ci ah->totalAdcDcOffsetIOddPhase[i] += 1748c2ecf20Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 1758c2ecf20Sopenharmony_ci ah->totalAdcDcOffsetIEvenPhase[i] += 1768c2ecf20Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 1778c2ecf20Sopenharmony_ci ah->totalAdcDcOffsetQOddPhase[i] += 1788c2ecf20Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 1798c2ecf20Sopenharmony_ci ah->totalAdcDcOffsetQEvenPhase[i] += 1808c2ecf20Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 1838c2ecf20Sopenharmony_ci "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", 1848c2ecf20Sopenharmony_ci ah->cal_samples, i, 1858c2ecf20Sopenharmony_ci ah->totalAdcDcOffsetIOddPhase[i], 1868c2ecf20Sopenharmony_ci ah->totalAdcDcOffsetIEvenPhase[i], 1878c2ecf20Sopenharmony_ci ah->totalAdcDcOffsetQOddPhase[i], 1888c2ecf20Sopenharmony_ci ah->totalAdcDcOffsetQEvenPhase[i]); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 1958c2ecf20Sopenharmony_ci u32 powerMeasQ, powerMeasI, iqCorrMeas; 1968c2ecf20Sopenharmony_ci u32 qCoffDenom, iCoffDenom; 1978c2ecf20Sopenharmony_ci int32_t qCoff, iCoff; 1988c2ecf20Sopenharmony_ci int iqCorrNeg, i; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci for (i = 0; i < numChains; i++) { 2018c2ecf20Sopenharmony_ci powerMeasI = ah->totalPowerMeasI[i]; 2028c2ecf20Sopenharmony_ci powerMeasQ = ah->totalPowerMeasQ[i]; 2038c2ecf20Sopenharmony_ci iqCorrMeas = ah->totalIqCorrMeas[i]; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 2068c2ecf20Sopenharmony_ci "Starting IQ Cal and Correction for Chain %d\n", 2078c2ecf20Sopenharmony_ci i); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 2108c2ecf20Sopenharmony_ci "Original: Chn %d iq_corr_meas = 0x%08x\n", 2118c2ecf20Sopenharmony_ci i, ah->totalIqCorrMeas[i]); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci iqCorrNeg = 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (iqCorrMeas > 0x80000000) { 2168c2ecf20Sopenharmony_ci iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; 2178c2ecf20Sopenharmony_ci iqCorrNeg = 1; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n", 2218c2ecf20Sopenharmony_ci i, powerMeasI); 2228c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n", 2238c2ecf20Sopenharmony_ci i, powerMeasQ); 2248c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; 2278c2ecf20Sopenharmony_ci qCoffDenom = powerMeasQ / 64; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if ((powerMeasQ != 0) && (iCoffDenom != 0) && 2308c2ecf20Sopenharmony_ci (qCoffDenom != 0)) { 2318c2ecf20Sopenharmony_ci iCoff = iqCorrMeas / iCoffDenom; 2328c2ecf20Sopenharmony_ci qCoff = powerMeasI / qCoffDenom - 64; 2338c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n", 2348c2ecf20Sopenharmony_ci i, iCoff); 2358c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n", 2368c2ecf20Sopenharmony_ci i, qCoff); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci iCoff = iCoff & 0x3f; 2398c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 2408c2ecf20Sopenharmony_ci "New: Chn %d iCoff = 0x%08x\n", i, iCoff); 2418c2ecf20Sopenharmony_ci if (iqCorrNeg == 0x0) 2428c2ecf20Sopenharmony_ci iCoff = 0x40 - iCoff; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (qCoff > 15) 2458c2ecf20Sopenharmony_ci qCoff = 15; 2468c2ecf20Sopenharmony_ci else if (qCoff <= -16) 2478c2ecf20Sopenharmony_ci qCoff = -16; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 2508c2ecf20Sopenharmony_ci "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", 2518c2ecf20Sopenharmony_ci i, iCoff, qCoff); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 2548c2ecf20Sopenharmony_ci AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, 2558c2ecf20Sopenharmony_ci iCoff); 2568c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 2578c2ecf20Sopenharmony_ci AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, 2588c2ecf20Sopenharmony_ci qCoff); 2598c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 2608c2ecf20Sopenharmony_ci "IQ Cal and Correction done for Chain %d\n", 2618c2ecf20Sopenharmony_ci i); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 2668c2ecf20Sopenharmony_ci AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 2728c2ecf20Sopenharmony_ci u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; 2738c2ecf20Sopenharmony_ci u32 qGainMismatch, iGainMismatch, val, i; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci for (i = 0; i < numChains; i++) { 2768c2ecf20Sopenharmony_ci iOddMeasOffset = ah->totalAdcIOddPhase[i]; 2778c2ecf20Sopenharmony_ci iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; 2788c2ecf20Sopenharmony_ci qOddMeasOffset = ah->totalAdcQOddPhase[i]; 2798c2ecf20Sopenharmony_ci qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 2828c2ecf20Sopenharmony_ci "Starting ADC Gain Cal for Chain %d\n", i); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = 0x%08x\n", 2858c2ecf20Sopenharmony_ci i, iOddMeasOffset); 2868c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = 0x%08x\n", 2878c2ecf20Sopenharmony_ci i, iEvenMeasOffset); 2888c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = 0x%08x\n", 2898c2ecf20Sopenharmony_ci i, qOddMeasOffset); 2908c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = 0x%08x\n", 2918c2ecf20Sopenharmony_ci i, qEvenMeasOffset); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { 2948c2ecf20Sopenharmony_ci iGainMismatch = 2958c2ecf20Sopenharmony_ci ((iEvenMeasOffset * 32) / 2968c2ecf20Sopenharmony_ci iOddMeasOffset) & 0x3f; 2978c2ecf20Sopenharmony_ci qGainMismatch = 2988c2ecf20Sopenharmony_ci ((qOddMeasOffset * 32) / 2998c2ecf20Sopenharmony_ci qEvenMeasOffset) & 0x3f; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 3028c2ecf20Sopenharmony_ci "Chn %d gain_mismatch_i = 0x%08x\n", 3038c2ecf20Sopenharmony_ci i, iGainMismatch); 3048c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 3058c2ecf20Sopenharmony_ci "Chn %d gain_mismatch_q = 0x%08x\n", 3068c2ecf20Sopenharmony_ci i, qGainMismatch); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 3098c2ecf20Sopenharmony_ci val &= 0xfffff000; 3108c2ecf20Sopenharmony_ci val |= (qGainMismatch) | (iGainMismatch << 6); 3118c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 3148c2ecf20Sopenharmony_ci "ADC Gain Cal done for Chain %d\n", i); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 3198c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 3208c2ecf20Sopenharmony_ci AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 3268c2ecf20Sopenharmony_ci u32 iOddMeasOffset, iEvenMeasOffset, val, i; 3278c2ecf20Sopenharmony_ci int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; 3288c2ecf20Sopenharmony_ci const struct ath9k_percal_data *calData = 3298c2ecf20Sopenharmony_ci ah->cal_list_curr->calData; 3308c2ecf20Sopenharmony_ci u32 numSamples = 3318c2ecf20Sopenharmony_ci (1 << (calData->calCountMax + 5)) * calData->calNumSamples; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci for (i = 0; i < numChains; i++) { 3348c2ecf20Sopenharmony_ci iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; 3358c2ecf20Sopenharmony_ci iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; 3368c2ecf20Sopenharmony_ci qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; 3378c2ecf20Sopenharmony_ci qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 3408c2ecf20Sopenharmony_ci "Starting ADC DC Offset Cal for Chain %d\n", i); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = %d\n", 3438c2ecf20Sopenharmony_ci i, iOddMeasOffset); 3448c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = %d\n", 3458c2ecf20Sopenharmony_ci i, iEvenMeasOffset); 3468c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = %d\n", 3478c2ecf20Sopenharmony_ci i, qOddMeasOffset); 3488c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = %d\n", 3498c2ecf20Sopenharmony_ci i, qEvenMeasOffset); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / 3528c2ecf20Sopenharmony_ci numSamples) & 0x1ff; 3538c2ecf20Sopenharmony_ci qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / 3548c2ecf20Sopenharmony_ci numSamples) & 0x1ff; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 3578c2ecf20Sopenharmony_ci "Chn %d dc_offset_mismatch_i = 0x%08x\n", 3588c2ecf20Sopenharmony_ci i, iDcMismatch); 3598c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 3608c2ecf20Sopenharmony_ci "Chn %d dc_offset_mismatch_q = 0x%08x\n", 3618c2ecf20Sopenharmony_ci i, qDcMismatch); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 3648c2ecf20Sopenharmony_ci val &= 0xc0000fff; 3658c2ecf20Sopenharmony_ci val |= (qDcMismatch << 12) | (iDcMismatch << 21); 3668c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 3698c2ecf20Sopenharmony_ci "ADC DC Offset Cal done for Chain %d\n", i); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 3738c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 3748c2ecf20Sopenharmony_ci AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void ar9287_hw_olc_temp_compensation(struct ath_hw *ah) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci u32 rddata; 3808c2ecf20Sopenharmony_ci int32_t delta, currPDADC, slope; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); 3838c2ecf20Sopenharmony_ci currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (ah->initPDADC == 0 || currPDADC == 0) { 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * Zero value indicates that no frames have been transmitted 3888c2ecf20Sopenharmony_ci * yet, can't do temperature compensation until frames are 3898c2ecf20Sopenharmony_ci * transmitted. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci return; 3928c2ecf20Sopenharmony_ci } else { 3938c2ecf20Sopenharmony_ci slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (slope == 0) { /* to avoid divide by zero case */ 3968c2ecf20Sopenharmony_ci delta = 0; 3978c2ecf20Sopenharmony_ci } else { 3988c2ecf20Sopenharmony_ci delta = ((currPDADC - ah->initPDADC)*4) / slope; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, 4018c2ecf20Sopenharmony_ci AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 4028c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, 4038c2ecf20Sopenharmony_ci AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic void ar9280_hw_olc_temp_compensation(struct ath_hw *ah) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci u32 rddata, i; 4108c2ecf20Sopenharmony_ci int delta, currPDADC, regval; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); 4138c2ecf20Sopenharmony_ci currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (ah->initPDADC == 0 || currPDADC == 0) 4168c2ecf20Sopenharmony_ci return; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) 4198c2ecf20Sopenharmony_ci delta = (currPDADC - ah->initPDADC + 4) / 8; 4208c2ecf20Sopenharmony_ci else 4218c2ecf20Sopenharmony_ci delta = (currPDADC - ah->initPDADC + 5) / 10; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (delta != ah->PDADCdelta) { 4248c2ecf20Sopenharmony_ci ah->PDADCdelta = delta; 4258c2ecf20Sopenharmony_ci for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { 4268c2ecf20Sopenharmony_ci regval = ah->originalGain[i] - delta; 4278c2ecf20Sopenharmony_ci if (regval < 0) 4288c2ecf20Sopenharmony_ci regval = 0; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, 4318c2ecf20Sopenharmony_ci AR_PHY_TX_GAIN_TBL1 + i * 4, 4328c2ecf20Sopenharmony_ci AR_PHY_TX_GAIN, regval); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci u32 regVal; 4408c2ecf20Sopenharmony_ci unsigned int i; 4418c2ecf20Sopenharmony_ci u32 regList[][2] = { 4428c2ecf20Sopenharmony_ci { AR9285_AN_TOP3, 0 }, 4438c2ecf20Sopenharmony_ci { AR9285_AN_RXTXBB1, 0 }, 4448c2ecf20Sopenharmony_ci { AR9285_AN_RF2G1, 0 }, 4458c2ecf20Sopenharmony_ci { AR9285_AN_RF2G2, 0 }, 4468c2ecf20Sopenharmony_ci { AR9285_AN_TOP2, 0 }, 4478c2ecf20Sopenharmony_ci { AR9285_AN_RF2G8, 0 }, 4488c2ecf20Sopenharmony_ci { AR9285_AN_RF2G7, 0 }, 4498c2ecf20Sopenharmony_ci { AR9285_AN_RF2G3, 0 }, 4508c2ecf20Sopenharmony_ci }; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList)); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci ENABLE_REG_RMW_BUFFER(ah); 4558c2ecf20Sopenharmony_ci /* 7834, b1=0 */ 4568c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0); 4578c2ecf20Sopenharmony_ci /* 9808, b27=1 */ 4588c2ecf20Sopenharmony_ci REG_SET_BIT(ah, 0x9808, 1 << 27); 4598c2ecf20Sopenharmony_ci /* 786c,b23,1, pwddac=1 */ 4608c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC); 4618c2ecf20Sopenharmony_ci /* 7854, b5,1, pdrxtxbb=1 */ 4628c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1); 4638c2ecf20Sopenharmony_ci /* 7854, b7,1, pdv2i=1 */ 4648c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I); 4658c2ecf20Sopenharmony_ci /* 7854, b8,1, pddacinterface=1 */ 4668c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF); 4678c2ecf20Sopenharmony_ci /* 7824,b12,0, offcal=0 */ 4688c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL); 4698c2ecf20Sopenharmony_ci /* 7838, b1,0, pwddb=0 */ 4708c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB); 4718c2ecf20Sopenharmony_ci /* 7820,b11,0, enpacal=0 */ 4728c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL); 4738c2ecf20Sopenharmony_ci /* 7820,b25,1, pdpadrv1=0 */ 4748c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1); 4758c2ecf20Sopenharmony_ci /* 7820,b24,0, pdpadrv2=0 */ 4768c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2); 4778c2ecf20Sopenharmony_ci /* 7820,b23,0, pdpaout=0 */ 4788c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT); 4798c2ecf20Sopenharmony_ci /* 783c,b14-16,7, padrvgn2tab_0=7 */ 4808c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 4818c2ecf20Sopenharmony_ci /* 4828c2ecf20Sopenharmony_ci * 7838,b29-31,0, padrvgn1tab_0=0 4838c2ecf20Sopenharmony_ci * does not matter since we turn it off 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 4868c2ecf20Sopenharmony_ci /* 7828, b0-11, ccom=fff */ 4878c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); 4888c2ecf20Sopenharmony_ci REG_RMW_BUFFER_FLUSH(ah); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* Set: 4918c2ecf20Sopenharmony_ci * localmode=1,bmode=1,bmoderxtx=1,synthon=1, 4928c2ecf20Sopenharmony_ci * txon=1,paon=1,oscon=1,synthon_force=1 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_ci REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 4958c2ecf20Sopenharmony_ci udelay(30); 4968c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* find off_6_1; */ 4998c2ecf20Sopenharmony_ci for (i = 6; i > 0; i--) { 5008c2ecf20Sopenharmony_ci regVal = REG_READ(ah, AR9285_AN_RF2G6); 5018c2ecf20Sopenharmony_ci regVal |= (1 << (20 + i)); 5028c2ecf20Sopenharmony_ci REG_WRITE(ah, AR9285_AN_RF2G6, regVal); 5038c2ecf20Sopenharmony_ci udelay(1); 5048c2ecf20Sopenharmony_ci /* regVal = REG_READ(ah, 0x7834); */ 5058c2ecf20Sopenharmony_ci regVal &= (~(0x1 << (20 + i))); 5068c2ecf20Sopenharmony_ci regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9), 5078c2ecf20Sopenharmony_ci AR9285_AN_RXTXBB1_SPARE9) 5088c2ecf20Sopenharmony_ci << (20 + i)); 5098c2ecf20Sopenharmony_ci REG_WRITE(ah, AR9285_AN_RF2G6, regVal); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci regVal = (regVal >> 20) & 0x7f; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* Update PA cal info */ 5158c2ecf20Sopenharmony_ci if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) { 5168c2ecf20Sopenharmony_ci if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) 5178c2ecf20Sopenharmony_ci ah->pacal_info.max_skipcount = 5188c2ecf20Sopenharmony_ci 2 * ah->pacal_info.max_skipcount; 5198c2ecf20Sopenharmony_ci ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; 5208c2ecf20Sopenharmony_ci } else { 5218c2ecf20Sopenharmony_ci ah->pacal_info.max_skipcount = 1; 5228c2ecf20Sopenharmony_ci ah->pacal_info.skipcount = 0; 5238c2ecf20Sopenharmony_ci ah->pacal_info.prev_offset = regVal; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci ENABLE_REG_RMW_BUFFER(ah); 5288c2ecf20Sopenharmony_ci /* 7834, b1=1 */ 5298c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0); 5308c2ecf20Sopenharmony_ci /* 9808, b27=0 */ 5318c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, 0x9808, 1 << 27); 5328c2ecf20Sopenharmony_ci REG_RMW_BUFFER_FLUSH(ah); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci ENABLE_REGWRITE_BUFFER(ah); 5358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regList); i++) 5368c2ecf20Sopenharmony_ci REG_WRITE(ah, regList[i][0], regList[i][1]); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci REGWRITE_BUFFER_FLUSH(ah); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 5448c2ecf20Sopenharmony_ci u32 regVal; 5458c2ecf20Sopenharmony_ci int i, offset, offs_6_1, offs_0; 5468c2ecf20Sopenharmony_ci u32 ccomp_org, reg_field; 5478c2ecf20Sopenharmony_ci u32 regList[][2] = { 5488c2ecf20Sopenharmony_ci { 0x786c, 0 }, 5498c2ecf20Sopenharmony_ci { 0x7854, 0 }, 5508c2ecf20Sopenharmony_ci { 0x7820, 0 }, 5518c2ecf20Sopenharmony_ci { 0x7824, 0 }, 5528c2ecf20Sopenharmony_ci { 0x7868, 0 }, 5538c2ecf20Sopenharmony_ci { 0x783c, 0 }, 5548c2ecf20Sopenharmony_ci { 0x7838, 0 }, 5558c2ecf20Sopenharmony_ci }; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "Running PA Calibration\n"); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* PA CAL is not needed for high power solution */ 5608c2ecf20Sopenharmony_ci if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 5618c2ecf20Sopenharmony_ci AR5416_EEP_TXGAIN_HIGH_POWER) 5628c2ecf20Sopenharmony_ci return; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regList); i++) 5658c2ecf20Sopenharmony_ci regList[i][1] = REG_READ(ah, regList[i][0]); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci regVal = REG_READ(ah, 0x7834); 5688c2ecf20Sopenharmony_ci regVal &= (~(0x1)); 5698c2ecf20Sopenharmony_ci REG_WRITE(ah, 0x7834, regVal); 5708c2ecf20Sopenharmony_ci regVal = REG_READ(ah, 0x9808); 5718c2ecf20Sopenharmony_ci regVal |= (0x1 << 27); 5728c2ecf20Sopenharmony_ci REG_WRITE(ah, 0x9808, regVal); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); 5758c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); 5768c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); 5778c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); 5788c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); 5798c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); 5808c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); 5818c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); 5828c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); 5838c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); 5848c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 5858c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 5868c2ecf20Sopenharmony_ci ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); 5878c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 5908c2ecf20Sopenharmony_ci udelay(30); 5918c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); 5928c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci for (i = 6; i > 0; i--) { 5958c2ecf20Sopenharmony_ci regVal = REG_READ(ah, 0x7834); 5968c2ecf20Sopenharmony_ci regVal |= (1 << (19 + i)); 5978c2ecf20Sopenharmony_ci REG_WRITE(ah, 0x7834, regVal); 5988c2ecf20Sopenharmony_ci udelay(1); 5998c2ecf20Sopenharmony_ci regVal = REG_READ(ah, 0x7834); 6008c2ecf20Sopenharmony_ci regVal &= (~(0x1 << (19 + i))); 6018c2ecf20Sopenharmony_ci reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); 6028c2ecf20Sopenharmony_ci regVal |= (reg_field << (19 + i)); 6038c2ecf20Sopenharmony_ci REG_WRITE(ah, 0x7834, regVal); 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); 6078c2ecf20Sopenharmony_ci udelay(1); 6088c2ecf20Sopenharmony_ci reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); 6098c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); 6108c2ecf20Sopenharmony_ci offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); 6118c2ecf20Sopenharmony_ci offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci offset = (offs_6_1<<1) | offs_0; 6148c2ecf20Sopenharmony_ci offset = offset - 0; 6158c2ecf20Sopenharmony_ci offs_6_1 = offset>>1; 6168c2ecf20Sopenharmony_ci offs_0 = offset & 1; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) { 6198c2ecf20Sopenharmony_ci if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) 6208c2ecf20Sopenharmony_ci ah->pacal_info.max_skipcount = 6218c2ecf20Sopenharmony_ci 2 * ah->pacal_info.max_skipcount; 6228c2ecf20Sopenharmony_ci ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; 6238c2ecf20Sopenharmony_ci } else { 6248c2ecf20Sopenharmony_ci ah->pacal_info.max_skipcount = 1; 6258c2ecf20Sopenharmony_ci ah->pacal_info.skipcount = 0; 6268c2ecf20Sopenharmony_ci ah->pacal_info.prev_offset = offset; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); 6308c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci regVal = REG_READ(ah, 0x7834); 6338c2ecf20Sopenharmony_ci regVal |= 0x1; 6348c2ecf20Sopenharmony_ci REG_WRITE(ah, 0x7834, regVal); 6358c2ecf20Sopenharmony_ci regVal = REG_READ(ah, 0x9808); 6368c2ecf20Sopenharmony_ci regVal &= (~(0x1 << 27)); 6378c2ecf20Sopenharmony_ci REG_WRITE(ah, 0x9808, regVal); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regList); i++) 6408c2ecf20Sopenharmony_ci REG_WRITE(ah, regList[i][0], regList[i][1]); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci if (AR_SREV_9271(ah)) { 6488c2ecf20Sopenharmony_ci if (is_reset || !ah->pacal_info.skipcount) 6498c2ecf20Sopenharmony_ci ar9271_hw_pa_cal(ah, is_reset); 6508c2ecf20Sopenharmony_ci else 6518c2ecf20Sopenharmony_ci ah->pacal_info.skipcount--; 6528c2ecf20Sopenharmony_ci } else if (AR_SREV_9285_12_OR_LATER(ah)) { 6538c2ecf20Sopenharmony_ci if (is_reset || !ah->pacal_info.skipcount) 6548c2ecf20Sopenharmony_ci ar9285_hw_pa_cal(ah, is_reset); 6558c2ecf20Sopenharmony_ci else 6568c2ecf20Sopenharmony_ci ah->pacal_info.skipcount--; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic void ar9002_hw_olc_temp_compensation(struct ath_hw *ah) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci if (OLC_FOR_AR9287_10_LATER) 6638c2ecf20Sopenharmony_ci ar9287_hw_olc_temp_compensation(ah); 6648c2ecf20Sopenharmony_ci else if (OLC_FOR_AR9280_20_LATER) 6658c2ecf20Sopenharmony_ci ar9280_hw_olc_temp_compensation(ah); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, 6698c2ecf20Sopenharmony_ci u8 rxchainmask, bool longcal) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct ath9k_cal_list *currCal = ah->cal_list_curr; 6728c2ecf20Sopenharmony_ci bool nfcal, nfcal_pending = false, percal_pending; 6738c2ecf20Sopenharmony_ci int ret; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF); 6768c2ecf20Sopenharmony_ci if (ah->caldata) { 6778c2ecf20Sopenharmony_ci nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags); 6788c2ecf20Sopenharmony_ci if (longcal) /* Remember to not miss */ 6798c2ecf20Sopenharmony_ci set_bit(LONGCAL_PENDING, &ah->caldata->cal_flags); 6808c2ecf20Sopenharmony_ci else if (test_bit(LONGCAL_PENDING, &ah->caldata->cal_flags)) 6818c2ecf20Sopenharmony_ci longcal = true; /* Respin a previous one */ 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci percal_pending = (currCal && 6858c2ecf20Sopenharmony_ci (currCal->calState == CAL_RUNNING || 6868c2ecf20Sopenharmony_ci currCal->calState == CAL_WAITING)); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (percal_pending && !nfcal) { 6898c2ecf20Sopenharmony_ci if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal)) 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* Looking for next waiting calibration if any */ 6938c2ecf20Sopenharmony_ci for (currCal = currCal->calNext; currCal != ah->cal_list_curr; 6948c2ecf20Sopenharmony_ci currCal = currCal->calNext) { 6958c2ecf20Sopenharmony_ci if (currCal->calState == CAL_WAITING) 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci if (currCal->calState == CAL_WAITING) { 6998c2ecf20Sopenharmony_ci percal_pending = true; 7008c2ecf20Sopenharmony_ci ah->cal_list_curr = currCal; 7018c2ecf20Sopenharmony_ci } else { 7028c2ecf20Sopenharmony_ci percal_pending = false; 7038c2ecf20Sopenharmony_ci ah->cal_list_curr = ah->cal_list; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Do not start a next calibration if the longcal is in action */ 7088c2ecf20Sopenharmony_ci if (percal_pending && !nfcal && !longcal) { 7098c2ecf20Sopenharmony_ci ath9k_hw_reset_calibration(ah, currCal); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return 0; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Do NF cal only at longer intervals */ 7158c2ecf20Sopenharmony_ci if (longcal || nfcal_pending) { 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * Get the value from the previous NF cal and update 7188c2ecf20Sopenharmony_ci * history buffer. 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci if (ath9k_hw_getnf(ah, chan)) { 7218c2ecf20Sopenharmony_ci /* 7228c2ecf20Sopenharmony_ci * Load the NF from history buffer of the current 7238c2ecf20Sopenharmony_ci * channel. 7248c2ecf20Sopenharmony_ci * NF is slow time-variant, so it is OK to use a 7258c2ecf20Sopenharmony_ci * historical value. 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_ci ret = ath9k_hw_loadnf(ah, ah->curchan); 7288c2ecf20Sopenharmony_ci if (ret < 0) 7298c2ecf20Sopenharmony_ci return ret; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (longcal) { 7338c2ecf20Sopenharmony_ci if (ah->caldata) 7348c2ecf20Sopenharmony_ci clear_bit(LONGCAL_PENDING, 7358c2ecf20Sopenharmony_ci &ah->caldata->cal_flags); 7368c2ecf20Sopenharmony_ci ath9k_hw_start_nfcal(ah, false); 7378c2ecf20Sopenharmony_ci /* Do periodic PAOffset Cal */ 7388c2ecf20Sopenharmony_ci ar9002_hw_pa_cal(ah, false); 7398c2ecf20Sopenharmony_ci ar9002_hw_olc_temp_compensation(ah); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci return !percal_pending; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci/* Carrier leakage Calibration fix */ 7478c2ecf20Sopenharmony_cistatic bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 7528c2ecf20Sopenharmony_ci if (IS_CHAN_HT20(chan)) { 7538c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 7548c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 7558c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 7568c2ecf20Sopenharmony_ci AR_PHY_AGC_CONTROL_FLTR_CAL); 7578c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 7588c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 7598c2ecf20Sopenharmony_ci if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, 7608c2ecf20Sopenharmony_ci AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { 7618c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 7628c2ecf20Sopenharmony_ci "offset calibration failed to complete in %d ms; noisy environment?\n", 7638c2ecf20Sopenharmony_ci AH_WAIT_TIMEOUT / 1000); 7648c2ecf20Sopenharmony_ci return false; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 7678c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 7688c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 7718c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 7728c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 7738c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 7748c2ecf20Sopenharmony_ci if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 7758c2ecf20Sopenharmony_ci 0, AH_WAIT_TIMEOUT)) { 7768c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 7778c2ecf20Sopenharmony_ci "offset calibration failed to complete in %d ms; noisy environment?\n", 7788c2ecf20Sopenharmony_ci AH_WAIT_TIMEOUT / 1000); 7798c2ecf20Sopenharmony_ci return false; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 7838c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 7848c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci return true; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic bool ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci int i; 7928c2ecf20Sopenharmony_ci u_int32_t txgain_max; 7938c2ecf20Sopenharmony_ci u_int32_t clc_gain, gain_mask = 0, clc_num = 0; 7948c2ecf20Sopenharmony_ci u_int32_t reg_clc_I0, reg_clc_Q0; 7958c2ecf20Sopenharmony_ci u_int32_t i0_num = 0; 7968c2ecf20Sopenharmony_ci u_int32_t q0_num = 0; 7978c2ecf20Sopenharmony_ci u_int32_t total_num = 0; 7988c2ecf20Sopenharmony_ci u_int32_t reg_rf2g5_org; 7998c2ecf20Sopenharmony_ci bool retv = true; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (!(ar9285_hw_cl_cal(ah, chan))) 8028c2ecf20Sopenharmony_ci return false; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7), 8058c2ecf20Sopenharmony_ci AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci for (i = 0; i < (txgain_max+1); i++) { 8088c2ecf20Sopenharmony_ci clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) & 8098c2ecf20Sopenharmony_ci AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S; 8108c2ecf20Sopenharmony_ci if (!(gain_mask & (1 << clc_gain))) { 8118c2ecf20Sopenharmony_ci gain_mask |= (1 << clc_gain); 8128c2ecf20Sopenharmony_ci clc_num++; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci for (i = 0; i < clc_num; i++) { 8178c2ecf20Sopenharmony_ci reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 8188c2ecf20Sopenharmony_ci & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S; 8198c2ecf20Sopenharmony_ci reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 8208c2ecf20Sopenharmony_ci & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S; 8218c2ecf20Sopenharmony_ci if (reg_clc_I0 == 0) 8228c2ecf20Sopenharmony_ci i0_num++; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (reg_clc_Q0 == 0) 8258c2ecf20Sopenharmony_ci q0_num++; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci total_num = i0_num + q0_num; 8288c2ecf20Sopenharmony_ci if (total_num > AR9285_CLCAL_REDO_THRESH) { 8298c2ecf20Sopenharmony_ci reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5); 8308c2ecf20Sopenharmony_ci if (AR_SREV_9285E_20(ah)) { 8318c2ecf20Sopenharmony_ci REG_WRITE(ah, AR9285_RF2G5, 8328c2ecf20Sopenharmony_ci (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 8338c2ecf20Sopenharmony_ci AR9285_RF2G5_IC50TX_XE_SET); 8348c2ecf20Sopenharmony_ci } else { 8358c2ecf20Sopenharmony_ci REG_WRITE(ah, AR9285_RF2G5, 8368c2ecf20Sopenharmony_ci (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 8378c2ecf20Sopenharmony_ci AR9285_RF2G5_IC50TX_SET); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci retv = ar9285_hw_cl_cal(ah, chan); 8408c2ecf20Sopenharmony_ci REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci return retv; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (AR_SREV_9271(ah)) { 8508c2ecf20Sopenharmony_ci if (!ar9285_hw_cl_cal(ah, chan)) 8518c2ecf20Sopenharmony_ci return false; 8528c2ecf20Sopenharmony_ci } else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { 8538c2ecf20Sopenharmony_ci if (!ar9285_hw_clc(ah, chan)) 8548c2ecf20Sopenharmony_ci return false; 8558c2ecf20Sopenharmony_ci } else { 8568c2ecf20Sopenharmony_ci if (AR_SREV_9280_20_OR_LATER(ah)) { 8578c2ecf20Sopenharmony_ci if (!AR_SREV_9287_11_OR_LATER(ah)) 8588c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_ADC_CTL, 8598c2ecf20Sopenharmony_ci AR_PHY_ADC_CTL_OFF_PWDADC); 8608c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 8618c2ecf20Sopenharmony_ci AR_PHY_AGC_CONTROL_FLTR_CAL); 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* Calibrate the AGC */ 8658c2ecf20Sopenharmony_ci REG_WRITE(ah, AR_PHY_AGC_CONTROL, 8668c2ecf20Sopenharmony_ci REG_READ(ah, AR_PHY_AGC_CONTROL) | 8678c2ecf20Sopenharmony_ci AR_PHY_AGC_CONTROL_CAL); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* Poll for offset calibration complete */ 8708c2ecf20Sopenharmony_ci if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, 8718c2ecf20Sopenharmony_ci AR_PHY_AGC_CONTROL_CAL, 8728c2ecf20Sopenharmony_ci 0, AH_WAIT_TIMEOUT)) { 8738c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 8748c2ecf20Sopenharmony_ci "offset calibration failed to complete in %d ms; noisy environment?\n", 8758c2ecf20Sopenharmony_ci AH_WAIT_TIMEOUT / 1000); 8768c2ecf20Sopenharmony_ci return false; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (AR_SREV_9280_20_OR_LATER(ah)) { 8808c2ecf20Sopenharmony_ci if (!AR_SREV_9287_11_OR_LATER(ah)) 8818c2ecf20Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_ADC_CTL, 8828c2ecf20Sopenharmony_ci AR_PHY_ADC_CTL_OFF_PWDADC); 8838c2ecf20Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 8848c2ecf20Sopenharmony_ci AR_PHY_AGC_CONTROL_FLTR_CAL); 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* Do PA Calibration */ 8898c2ecf20Sopenharmony_ci ar9002_hw_pa_cal(ah, true); 8908c2ecf20Sopenharmony_ci ath9k_hw_loadnf(ah, chan); 8918c2ecf20Sopenharmony_ci ath9k_hw_start_nfcal(ah, true); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* Enable IQ, ADC Gain and ADC DC offset CALs */ 8968c2ecf20Sopenharmony_ci if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { 8978c2ecf20Sopenharmony_ci ah->supp_cals = IQ_MISMATCH_CAL; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (AR_SREV_9160_10_OR_LATER(ah)) 9008c2ecf20Sopenharmony_ci ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (AR_SREV_9287(ah)) 9038c2ecf20Sopenharmony_ci ah->supp_cals &= ~ADC_GAIN_CAL; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { 9068c2ecf20Sopenharmony_ci INIT_CAL(&ah->adcgain_caldata); 9078c2ecf20Sopenharmony_ci INSERT_CAL(ah, &ah->adcgain_caldata); 9088c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 9098c2ecf20Sopenharmony_ci "enabling ADC Gain Calibration\n"); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { 9138c2ecf20Sopenharmony_ci INIT_CAL(&ah->adcdc_caldata); 9148c2ecf20Sopenharmony_ci INSERT_CAL(ah, &ah->adcdc_caldata); 9158c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, 9168c2ecf20Sopenharmony_ci "enabling ADC DC Calibration\n"); 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { 9208c2ecf20Sopenharmony_ci INIT_CAL(&ah->iq_caldata); 9218c2ecf20Sopenharmony_ci INSERT_CAL(ah, &ah->iq_caldata); 9228c2ecf20Sopenharmony_ci ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci ah->cal_list_curr = ah->cal_list; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (ah->cal_list_curr) 9288c2ecf20Sopenharmony_ci ath9k_hw_reset_calibration(ah, ah->cal_list_curr); 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (ah->caldata) 9328c2ecf20Sopenharmony_ci ah->caldata->CalValid = 0; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci return true; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic const struct ath9k_percal_data iq_cal_multi_sample = { 9388c2ecf20Sopenharmony_ci IQ_MISMATCH_CAL, 9398c2ecf20Sopenharmony_ci MAX_CAL_SAMPLES, 9408c2ecf20Sopenharmony_ci PER_MIN_LOG_COUNT, 9418c2ecf20Sopenharmony_ci ar9002_hw_iqcal_collect, 9428c2ecf20Sopenharmony_ci ar9002_hw_iqcalibrate 9438c2ecf20Sopenharmony_ci}; 9448c2ecf20Sopenharmony_cistatic const struct ath9k_percal_data iq_cal_single_sample = { 9458c2ecf20Sopenharmony_ci IQ_MISMATCH_CAL, 9468c2ecf20Sopenharmony_ci MIN_CAL_SAMPLES, 9478c2ecf20Sopenharmony_ci PER_MAX_LOG_COUNT, 9488c2ecf20Sopenharmony_ci ar9002_hw_iqcal_collect, 9498c2ecf20Sopenharmony_ci ar9002_hw_iqcalibrate 9508c2ecf20Sopenharmony_ci}; 9518c2ecf20Sopenharmony_cistatic const struct ath9k_percal_data adc_gain_cal_multi_sample = { 9528c2ecf20Sopenharmony_ci ADC_GAIN_CAL, 9538c2ecf20Sopenharmony_ci MAX_CAL_SAMPLES, 9548c2ecf20Sopenharmony_ci PER_MIN_LOG_COUNT, 9558c2ecf20Sopenharmony_ci ar9002_hw_adc_gaincal_collect, 9568c2ecf20Sopenharmony_ci ar9002_hw_adc_gaincal_calibrate 9578c2ecf20Sopenharmony_ci}; 9588c2ecf20Sopenharmony_cistatic const struct ath9k_percal_data adc_gain_cal_single_sample = { 9598c2ecf20Sopenharmony_ci ADC_GAIN_CAL, 9608c2ecf20Sopenharmony_ci MIN_CAL_SAMPLES, 9618c2ecf20Sopenharmony_ci PER_MAX_LOG_COUNT, 9628c2ecf20Sopenharmony_ci ar9002_hw_adc_gaincal_collect, 9638c2ecf20Sopenharmony_ci ar9002_hw_adc_gaincal_calibrate 9648c2ecf20Sopenharmony_ci}; 9658c2ecf20Sopenharmony_cistatic const struct ath9k_percal_data adc_dc_cal_multi_sample = { 9668c2ecf20Sopenharmony_ci ADC_DC_CAL, 9678c2ecf20Sopenharmony_ci MAX_CAL_SAMPLES, 9688c2ecf20Sopenharmony_ci PER_MIN_LOG_COUNT, 9698c2ecf20Sopenharmony_ci ar9002_hw_adc_dccal_collect, 9708c2ecf20Sopenharmony_ci ar9002_hw_adc_dccal_calibrate 9718c2ecf20Sopenharmony_ci}; 9728c2ecf20Sopenharmony_cistatic const struct ath9k_percal_data adc_dc_cal_single_sample = { 9738c2ecf20Sopenharmony_ci ADC_DC_CAL, 9748c2ecf20Sopenharmony_ci MIN_CAL_SAMPLES, 9758c2ecf20Sopenharmony_ci PER_MAX_LOG_COUNT, 9768c2ecf20Sopenharmony_ci ar9002_hw_adc_dccal_collect, 9778c2ecf20Sopenharmony_ci ar9002_hw_adc_dccal_calibrate 9788c2ecf20Sopenharmony_ci}; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic void ar9002_hw_init_cal_settings(struct ath_hw *ah) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci if (AR_SREV_9100(ah)) { 9838c2ecf20Sopenharmony_ci ah->iq_caldata.calData = &iq_cal_multi_sample; 9848c2ecf20Sopenharmony_ci ah->supp_cals = IQ_MISMATCH_CAL; 9858c2ecf20Sopenharmony_ci return; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci if (AR_SREV_9160_10_OR_LATER(ah)) { 9898c2ecf20Sopenharmony_ci if (AR_SREV_9280_20_OR_LATER(ah)) { 9908c2ecf20Sopenharmony_ci ah->iq_caldata.calData = &iq_cal_single_sample; 9918c2ecf20Sopenharmony_ci ah->adcgain_caldata.calData = 9928c2ecf20Sopenharmony_ci &adc_gain_cal_single_sample; 9938c2ecf20Sopenharmony_ci ah->adcdc_caldata.calData = 9948c2ecf20Sopenharmony_ci &adc_dc_cal_single_sample; 9958c2ecf20Sopenharmony_ci } else { 9968c2ecf20Sopenharmony_ci ah->iq_caldata.calData = &iq_cal_multi_sample; 9978c2ecf20Sopenharmony_ci ah->adcgain_caldata.calData = 9988c2ecf20Sopenharmony_ci &adc_gain_cal_multi_sample; 9998c2ecf20Sopenharmony_ci ah->adcdc_caldata.calData = 10008c2ecf20Sopenharmony_ci &adc_dc_cal_multi_sample; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (AR_SREV_9287(ah)) 10058c2ecf20Sopenharmony_ci ah->supp_cals &= ~ADC_GAIN_CAL; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_civoid ar9002_hw_attach_calib_ops(struct ath_hw *ah) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); 10128c2ecf20Sopenharmony_ci struct ath_hw_ops *ops = ath9k_hw_ops(ah); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci priv_ops->init_cal_settings = ar9002_hw_init_cal_settings; 10158c2ecf20Sopenharmony_ci priv_ops->init_cal = ar9002_hw_init_cal; 10168c2ecf20Sopenharmony_ci priv_ops->setup_calibration = ar9002_hw_setup_calibration; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci ops->calibrate = ar9002_hw_calibrate; 10198c2ecf20Sopenharmony_ci} 1020