Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2010-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <linux/export.h>
0018 #include "hw.h"
0019 #include "ar9003_phy.h"
0020 
0021 void ar9003_paprd_enable(struct ath_hw *ah, bool val)
0022 {
0023     struct ath9k_channel *chan = ah->curchan;
0024     bool is2ghz = IS_CHAN_2GHZ(chan);
0025 
0026     /*
0027      * 3 bits for modalHeader5G.papdRateMaskHt20
0028      * is used for sub-band disabling of PAPRD.
0029      * 5G band is divided into 3 sub-bands -- upper,
0030      * middle, lower.
0031      * if bit 30 of modalHeader5G.papdRateMaskHt20 is set
0032      * -- disable PAPRD for upper band 5GHz
0033      * if bit 29 of modalHeader5G.papdRateMaskHt20 is set
0034      * -- disable PAPRD for middle band 5GHz
0035      * if bit 28 of modalHeader5G.papdRateMaskHt20 is set
0036      * -- disable PAPRD for lower band 5GHz
0037      */
0038 
0039     if (!is2ghz) {
0040         if (chan->channel >= UPPER_5G_SUB_BAND_START) {
0041             if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz)
0042                                   & BIT(30))
0043                 val = false;
0044         } else if (chan->channel >= MID_5G_SUB_BAND_START) {
0045             if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz)
0046                                   & BIT(29))
0047                 val = false;
0048         } else {
0049             if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz)
0050                                   & BIT(28))
0051                 val = false;
0052         }
0053     }
0054 
0055     if (val) {
0056         ah->paprd_table_write_done = true;
0057         ath9k_hw_apply_txpower(ah, chan, false);
0058     }
0059 
0060     REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,
0061               AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
0062     if (ah->caps.tx_chainmask & BIT(1))
0063         REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,
0064                   AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
0065     if (ah->caps.tx_chainmask & BIT(2))
0066         REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,
0067                   AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);
0068 }
0069 EXPORT_SYMBOL(ar9003_paprd_enable);
0070 
0071 static int ar9003_get_training_power_2g(struct ath_hw *ah)
0072 {
0073     struct ath9k_channel *chan = ah->curchan;
0074     unsigned int power, scale, delta;
0075 
0076     scale = ar9003_get_paprd_scale_factor(ah, chan);
0077 
0078     if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
0079         AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
0080         power = ah->paprd_target_power + 2;
0081     } else if (AR_SREV_9485(ah)) {
0082         power = 25;
0083     } else {
0084         power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
0085                        AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
0086 
0087         delta = abs((int) ah->paprd_target_power - (int) power);
0088         if (delta > scale)
0089             return -1;
0090 
0091         if (delta < 4)
0092             power -= 4 - delta;
0093     }
0094 
0095     return power;
0096 }
0097 
0098 static int ar9003_get_training_power_5g(struct ath_hw *ah)
0099 {
0100     struct ath_common *common = ath9k_hw_common(ah);
0101     struct ath9k_channel *chan = ah->curchan;
0102     unsigned int power, scale, delta;
0103 
0104     scale = ar9003_get_paprd_scale_factor(ah, chan);
0105 
0106     if (IS_CHAN_HT40(chan))
0107         power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
0108             AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
0109     else
0110         power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,
0111             AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
0112 
0113     power += scale;
0114     delta = abs((int) ah->paprd_target_power - (int) power);
0115     if (delta > scale)
0116         return -1;
0117 
0118     switch (get_streams(ah->txchainmask)) {
0119     case 1:
0120         delta = 6;
0121         break;
0122     case 2:
0123         delta = 4;
0124         break;
0125     case 3:
0126         delta = 2;
0127         break;
0128     default:
0129         delta = 0;
0130         ath_dbg(common, CALIBRATE, "Invalid tx-chainmask: %u\n",
0131             ah->txchainmask);
0132     }
0133 
0134     power += delta;
0135     return power;
0136 }
0137 
0138 static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
0139 {
0140     struct ath_common *common = ath9k_hw_common(ah);
0141     static const u32 ctrl0[3] = {
0142         AR_PHY_PAPRD_CTRL0_B0,
0143         AR_PHY_PAPRD_CTRL0_B1,
0144         AR_PHY_PAPRD_CTRL0_B2
0145     };
0146     static const u32 ctrl1[3] = {
0147         AR_PHY_PAPRD_CTRL1_B0,
0148         AR_PHY_PAPRD_CTRL1_B1,
0149         AR_PHY_PAPRD_CTRL1_B2
0150     };
0151     int training_power;
0152     int i, val;
0153     u32 am2pm_mask = ah->paprd_ratemask;
0154 
0155     if (IS_CHAN_2GHZ(ah->curchan))
0156         training_power = ar9003_get_training_power_2g(ah);
0157     else
0158         training_power = ar9003_get_training_power_5g(ah);
0159 
0160     ath_dbg(common, CALIBRATE, "Training power: %d, Target power: %d\n",
0161         training_power, ah->paprd_target_power);
0162 
0163     if (training_power < 0) {
0164         ath_dbg(common, CALIBRATE,
0165             "PAPRD target power delta out of range\n");
0166         return -ERANGE;
0167     }
0168     ah->paprd_training_power = training_power;
0169 
0170     if (AR_SREV_9330(ah))
0171         am2pm_mask = 0;
0172 
0173     REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
0174               ah->paprd_ratemask);
0175     REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,
0176               am2pm_mask);
0177     REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,
0178               ah->paprd_ratemask_ht40);
0179 
0180     ath_dbg(common, CALIBRATE, "PAPRD HT20 mask: 0x%x, HT40 mask: 0x%x\n",
0181         ah->paprd_ratemask, ah->paprd_ratemask_ht40);
0182 
0183     for (i = 0; i < ah->caps.max_txchains; i++) {
0184         REG_RMW_FIELD(ah, ctrl0[i],
0185                   AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
0186         REG_RMW_FIELD(ah, ctrl1[i],
0187                   AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1);
0188         REG_RMW_FIELD(ah, ctrl1[i],
0189                   AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1);
0190         REG_RMW_FIELD(ah, ctrl1[i],
0191                   AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);
0192         REG_RMW_FIELD(ah, ctrl1[i],
0193                   AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181);
0194         REG_RMW_FIELD(ah, ctrl1[i],
0195                   AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361);
0196         REG_RMW_FIELD(ah, ctrl1[i],
0197                   AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);
0198         REG_RMW_FIELD(ah, ctrl0[i],
0199                   AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3);
0200     }
0201 
0202     ar9003_paprd_enable(ah, false);
0203 
0204     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
0205               AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30);
0206     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
0207               AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1);
0208     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
0209               AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1);
0210     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
0211               AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0);
0212     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
0213               AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0);
0214     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
0215               AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28);
0216     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1,
0217               AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1);
0218 
0219     if (AR_SREV_9485(ah)) {
0220         val = 148;
0221     } else {
0222         if (IS_CHAN_2GHZ(ah->curchan)) {
0223             if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
0224                 val = 145;
0225             else
0226                 val = 147;
0227         } else {
0228             val = 137;
0229         }
0230     }
0231 
0232     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2,
0233               AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val);
0234     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0235               AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4);
0236     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0237               AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4);
0238     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0239               AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
0240     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0241               AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
0242 
0243     if (AR_SREV_9485(ah) ||
0244         AR_SREV_9462(ah) ||
0245         AR_SREV_9565(ah) ||
0246         AR_SREV_9550(ah) ||
0247         AR_SREV_9330(ah) ||
0248         AR_SREV_9340(ah))
0249         REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0250                   AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3);
0251     else
0252         REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0253                   AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6);
0254 
0255     val = -10;
0256 
0257     if (IS_CHAN_2GHZ(ah->curchan) && !AR_SREV_9462(ah) && !AR_SREV_9565(ah))
0258         val = -15;
0259 
0260     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0261               AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE,
0262               val);
0263     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0264               AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1);
0265     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
0266               AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0);
0267     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
0268               AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400);
0269     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4,
0270               AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES,
0271               100);
0272     REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0,
0273               AR_PHY_PAPRD_PRE_POST_SCALING, 261376);
0274     REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0,
0275               AR_PHY_PAPRD_PRE_POST_SCALING, 248079);
0276     REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0,
0277               AR_PHY_PAPRD_PRE_POST_SCALING, 233759);
0278     REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0,
0279               AR_PHY_PAPRD_PRE_POST_SCALING, 220464);
0280     REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0,
0281               AR_PHY_PAPRD_PRE_POST_SCALING, 208194);
0282     REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0,
0283               AR_PHY_PAPRD_PRE_POST_SCALING, 196949);
0284     REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0,
0285               AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
0286     REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
0287               AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
0288     return 0;
0289 }
0290 
0291 static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
0292 {
0293     u32 *entry = ah->paprd_gain_table_entries;
0294     u8 *index = ah->paprd_gain_table_index;
0295     u32 reg = AR_PHY_TXGAIN_TABLE;
0296     int i;
0297 
0298     for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) {
0299         entry[i] = REG_READ(ah, reg);
0300         index[i] = (entry[i] >> 24) & 0xff;
0301         reg += 4;
0302     }
0303 }
0304 
0305 static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain,
0306                         int target_power)
0307 {
0308     int olpc_gain_delta = 0, cl_gain_mod;
0309     int alpha_therm, alpha_volt;
0310     int therm_cal_value, volt_cal_value;
0311     int therm_value, volt_value;
0312     int thermal_gain_corr, voltage_gain_corr;
0313     int desired_scale, desired_gain = 0;
0314     u32 reg_olpc  = 0, reg_cl_gain  = 0;
0315 
0316     REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
0317             AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
0318     desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12,
0319                        AR_PHY_TPC_12_DESIRED_SCALE_HT40_5);
0320     alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19,
0321                      AR_PHY_TPC_19_ALPHA_THERM);
0322     alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19,
0323                     AR_PHY_TPC_19_ALPHA_VOLT);
0324     therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,
0325                      AR_PHY_TPC_18_THERM_CAL_VALUE);
0326     volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,
0327                     AR_PHY_TPC_18_VOLT_CAL_VALUE);
0328     therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,
0329                      AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE);
0330     volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,
0331                     AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE);
0332 
0333     switch (chain) {
0334     case 0:
0335         reg_olpc = AR_PHY_TPC_11_B0;
0336         reg_cl_gain = AR_PHY_CL_TAB_0;
0337         break;
0338     case 1:
0339         reg_olpc = AR_PHY_TPC_11_B1;
0340         reg_cl_gain = AR_PHY_CL_TAB_1;
0341         break;
0342     case 2:
0343         reg_olpc = AR_PHY_TPC_11_B2;
0344         reg_cl_gain = AR_PHY_CL_TAB_2;
0345         break;
0346     default:
0347         ath_dbg(ath9k_hw_common(ah), CALIBRATE,
0348             "Invalid chainmask: %d\n", chain);
0349         break;
0350     }
0351 
0352     olpc_gain_delta = REG_READ_FIELD(ah, reg_olpc,
0353                      AR_PHY_TPC_11_OLPC_GAIN_DELTA);
0354     cl_gain_mod = REG_READ_FIELD(ah, reg_cl_gain,
0355                      AR_PHY_CL_TAB_CL_GAIN_MOD);
0356 
0357     if (olpc_gain_delta >= 128)
0358         olpc_gain_delta = olpc_gain_delta - 256;
0359 
0360     thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) +
0361                  (256 / 2)) / 256;
0362     voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) +
0363                  (128 / 2)) / 128;
0364     desired_gain = target_power - olpc_gain_delta - thermal_gain_corr -
0365         voltage_gain_corr + desired_scale + cl_gain_mod;
0366 
0367     return desired_gain;
0368 }
0369 
0370 static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index)
0371 {
0372     int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain;
0373     int padrvgnA, padrvgnB, padrvgnC, padrvgnD;
0374     u32 *gain_table_entries = ah->paprd_gain_table_entries;
0375 
0376     selected_gain_entry = gain_table_entries[gain_index];
0377     txbb1dbgain = selected_gain_entry & 0x7;
0378     txbb6dbgain = (selected_gain_entry >> 3) & 0x3;
0379     txmxrgain = (selected_gain_entry >> 5) & 0xf;
0380     padrvgnA = (selected_gain_entry >> 9) & 0xf;
0381     padrvgnB = (selected_gain_entry >> 13) & 0xf;
0382     padrvgnC = (selected_gain_entry >> 17) & 0xf;
0383     padrvgnD = (selected_gain_entry >> 21) & 0x3;
0384 
0385     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0386               AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain);
0387     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0388               AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain);
0389     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0390               AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain);
0391     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0392               AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA);
0393     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0394               AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB);
0395     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0396               AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC);
0397     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0398               AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD);
0399     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0400               AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0);
0401     REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
0402               AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0);
0403     REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0);
0404     REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0);
0405 }
0406 
0407 static inline int find_expn(int num)
0408 {
0409     return fls(num) - 1;
0410 }
0411 
0412 static inline int find_proper_scale(int expn, int N)
0413 {
0414     return (expn > N) ? expn - 10 : 0;
0415 }
0416 
0417 #define NUM_BIN 23
0418 
0419 static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
0420 {
0421     unsigned int thresh_accum_cnt;
0422     int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1];
0423     int PA_in[NUM_BIN + 1];
0424     int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1];
0425     unsigned int B1_abs_max, B2_abs_max;
0426     int max_index, scale_factor;
0427     int y_est[NUM_BIN + 1];
0428     int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1];
0429     unsigned int x_tilde_abs;
0430     int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad;
0431     int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B;
0432     int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2;
0433     int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem;
0434     int y5, y3, tmp;
0435     int theta_low_bin = 0;
0436     int i;
0437 
0438     /* disregard any bin that contains <= 16 samples */
0439     thresh_accum_cnt = 16;
0440     scale_factor = 5;
0441     max_index = 0;
0442     memset(theta, 0, sizeof(theta));
0443     memset(x_est, 0, sizeof(x_est));
0444     memset(Y, 0, sizeof(Y));
0445     memset(y_est, 0, sizeof(y_est));
0446     memset(x_tilde, 0, sizeof(x_tilde));
0447 
0448     for (i = 0; i < NUM_BIN; i++) {
0449         s32 accum_cnt, accum_tx, accum_rx, accum_ang;
0450 
0451         /* number of samples */
0452         accum_cnt = data_L[i] & 0xffff;
0453 
0454         if (accum_cnt <= thresh_accum_cnt)
0455             continue;
0456 
0457         max_index++;
0458 
0459         /* sum(tx amplitude) */
0460         accum_tx = ((data_L[i] >> 16) & 0xffff) |
0461             ((data_U[i] & 0x7ff) << 16);
0462 
0463         /* sum(rx amplitude distance to lower bin edge) */
0464         accum_rx = ((data_U[i] >> 11) & 0x1f) |
0465             ((data_L[i + 23] & 0xffff) << 5);
0466 
0467         /* sum(angles) */
0468         accum_ang = ((data_L[i + 23] >> 16) & 0xffff) |
0469             ((data_U[i + 23] & 0x7ff) << 16);
0470 
0471         accum_tx <<= scale_factor;
0472         accum_rx <<= scale_factor;
0473         x_est[max_index] =
0474             (((accum_tx + accum_cnt) / accum_cnt) + 32) >>
0475             scale_factor;
0476 
0477         Y[max_index] =
0478             ((((accum_rx + accum_cnt) / accum_cnt) + 32) >>
0479                 scale_factor) +
0480             (1 << scale_factor) * i + 16;
0481 
0482         if (accum_ang >= (1 << 26))
0483             accum_ang -= 1 << 27;
0484 
0485         theta[max_index] =
0486             ((accum_ang * (1 << scale_factor)) + accum_cnt) /
0487             accum_cnt;
0488     }
0489 
0490     /*
0491      * Find average theta of first 5 bin and all of those to same value.
0492      * Curve is linear at that range.
0493      */
0494     for (i = 1; i < 6; i++)
0495         theta_low_bin += theta[i];
0496 
0497     theta_low_bin = theta_low_bin / 5;
0498     for (i = 1; i < 6; i++)
0499         theta[i] = theta_low_bin;
0500 
0501     /* Set values at origin */
0502     theta[0] = theta_low_bin;
0503     for (i = 0; i <= max_index; i++)
0504         theta[i] -= theta_low_bin;
0505 
0506     x_est[0] = 0;
0507     Y[0] = 0;
0508     scale_factor = 8;
0509 
0510     /* low signal gain */
0511     if (x_est[6] == x_est[3])
0512         return false;
0513 
0514     G_fxp =
0515         (((Y[6] - Y[3]) * 1 << scale_factor) +
0516          (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]);
0517 
0518     /* prevent division by zero */
0519     if (G_fxp == 0)
0520         return false;
0521 
0522     Y_intercept =
0523         (G_fxp * (x_est[0] - x_est[3]) +
0524          (1 << scale_factor)) / (1 << scale_factor) + Y[3];
0525 
0526     for (i = 0; i <= max_index; i++)
0527         y_est[i] = Y[i] - Y_intercept;
0528 
0529     for (i = 0; i <= 3; i++) {
0530         y_est[i] = i * 32;
0531         x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp;
0532     }
0533 
0534     if (y_est[max_index] == 0)
0535         return false;
0536 
0537     x_est_fxp1_nonlin =
0538         x_est[max_index] - ((1 << scale_factor) * y_est[max_index] +
0539                 G_fxp) / G_fxp;
0540 
0541     order_x_by_y =
0542         (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index];
0543 
0544     if (order_x_by_y == 0)
0545         M = 10;
0546     else if (order_x_by_y == 1)
0547         M = 9;
0548     else
0549         M = 8;
0550 
0551     I = (max_index > 15) ? 7 : max_index >> 1;
0552     L = max_index - I;
0553     scale_factor = 8;
0554     sum_y_sqr = 0;
0555     sum_y_quad = 0;
0556     x_tilde_abs = 0;
0557 
0558     for (i = 0; i <= L; i++) {
0559         unsigned int y_sqr;
0560         unsigned int y_quad;
0561         unsigned int tmp_abs;
0562 
0563         /* prevent division by zero */
0564         if (y_est[i + I] == 0)
0565             return false;
0566 
0567         x_est_fxp1_nonlin =
0568             x_est[i + I] - ((1 << scale_factor) * y_est[i + I] +
0569                     G_fxp) / G_fxp;
0570 
0571         x_tilde[i] =
0572             (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i +
0573                                       I];
0574         x_tilde[i] =
0575             (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];
0576         x_tilde[i] =
0577             (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];
0578         y_sqr =
0579             (y_est[i + I] * y_est[i + I] +
0580              (scale_factor * scale_factor)) / (scale_factor *
0581                                scale_factor);
0582         tmp_abs = abs(x_tilde[i]);
0583         if (tmp_abs > x_tilde_abs)
0584             x_tilde_abs = tmp_abs;
0585 
0586         y_quad = y_sqr * y_sqr;
0587         sum_y_sqr = sum_y_sqr + y_sqr;
0588         sum_y_quad = sum_y_quad + y_quad;
0589         B1_tmp[i] = y_sqr * (L + 1);
0590         B2_tmp[i] = y_sqr;
0591     }
0592 
0593     B1_abs_max = 0;
0594     B2_abs_max = 0;
0595     for (i = 0; i <= L; i++) {
0596         int abs_val;
0597 
0598         B1_tmp[i] -= sum_y_sqr;
0599         B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i];
0600 
0601         abs_val = abs(B1_tmp[i]);
0602         if (abs_val > B1_abs_max)
0603             B1_abs_max = abs_val;
0604 
0605         abs_val = abs(B2_tmp[i]);
0606         if (abs_val > B2_abs_max)
0607             B2_abs_max = abs_val;
0608     }
0609 
0610     Q_x = find_proper_scale(find_expn(x_tilde_abs), 10);
0611     Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10);
0612     Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10);
0613 
0614     beta_raw = 0;
0615     alpha_raw = 0;
0616     for (i = 0; i <= L; i++) {
0617         x_tilde[i] = x_tilde[i] / (1 << Q_x);
0618         B1_tmp[i] = B1_tmp[i] / (1 << Q_B1);
0619         B2_tmp[i] = B2_tmp[i] / (1 << Q_B2);
0620         beta_raw = beta_raw + B1_tmp[i] * x_tilde[i];
0621         alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i];
0622     }
0623 
0624     scale_B =
0625         ((sum_y_quad / scale_factor) * (L + 1) -
0626          (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor;
0627 
0628     Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10);
0629     scale_B = scale_B / (1 << Q_scale_B);
0630     if (scale_B == 0)
0631         return false;
0632     Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
0633     Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
0634     beta_raw = beta_raw / (1 << Q_beta);
0635     alpha_raw = alpha_raw / (1 << Q_alpha);
0636     alpha = (alpha_raw << 10) / scale_B;
0637     beta = (beta_raw << 10) / scale_B;
0638     order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B;
0639     order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B;
0640     order1_5x = order_1 / 5;
0641     order2_3x = order_2 / 3;
0642     order1_5x_rem = order_1 - 5 * order1_5x;
0643     order2_3x_rem = order_2 - 3 * order2_3x;
0644 
0645     for (i = 0; i < PAPRD_TABLE_SZ; i++) {
0646         tmp = i * 32;
0647         y5 = ((beta * tmp) >> 6) >> order1_5x;
0648         y5 = (y5 * tmp) >> order1_5x;
0649         y5 = (y5 * tmp) >> order1_5x;
0650         y5 = (y5 * tmp) >> order1_5x;
0651         y5 = (y5 * tmp) >> order1_5x;
0652         y5 = y5 >> order1_5x_rem;
0653         y3 = (alpha * tmp) >> order2_3x;
0654         y3 = (y3 * tmp) >> order2_3x;
0655         y3 = (y3 * tmp) >> order2_3x;
0656         y3 = y3 >> order2_3x_rem;
0657         PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp;
0658 
0659         if (i >= 2) {
0660             tmp = PA_in[i] - PA_in[i - 1];
0661             if (tmp < 0)
0662                 PA_in[i] =
0663                     PA_in[i - 1] + (PA_in[i - 1] -
0664                             PA_in[i - 2]);
0665         }
0666 
0667         PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400;
0668     }
0669 
0670     beta_raw = 0;
0671     alpha_raw = 0;
0672 
0673     for (i = 0; i <= L; i++) {
0674         int theta_tilde =
0675             ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I];
0676         theta_tilde =
0677             ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];
0678         theta_tilde =
0679             ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];
0680         beta_raw = beta_raw + B1_tmp[i] * theta_tilde;
0681         alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde;
0682     }
0683 
0684     Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);
0685     Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);
0686     beta_raw = beta_raw / (1 << Q_beta);
0687     alpha_raw = alpha_raw / (1 << Q_alpha);
0688 
0689     alpha = (alpha_raw << 10) / scale_B;
0690     beta = (beta_raw << 10) / scale_B;
0691     order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5;
0692     order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5;
0693     order1_5x = order_1 / 5;
0694     order2_3x = order_2 / 3;
0695     order1_5x_rem = order_1 - 5 * order1_5x;
0696     order2_3x_rem = order_2 - 3 * order2_3x;
0697 
0698     for (i = 0; i < PAPRD_TABLE_SZ; i++) {
0699         int PA_angle;
0700 
0701         /* pa_table[4] is calculated from PA_angle for i=5 */
0702         if (i == 4)
0703             continue;
0704 
0705         tmp = i * 32;
0706         if (beta > 0)
0707             y5 = (((beta * tmp - 64) >> 6) -
0708                   (1 << order1_5x)) / (1 << order1_5x);
0709         else
0710             y5 = ((((beta * tmp - 64) >> 6) +
0711                    (1 << order1_5x)) / (1 << order1_5x));
0712 
0713         y5 = (y5 * tmp) / (1 << order1_5x);
0714         y5 = (y5 * tmp) / (1 << order1_5x);
0715         y5 = (y5 * tmp) / (1 << order1_5x);
0716         y5 = (y5 * tmp) / (1 << order1_5x);
0717         y5 = y5 / (1 << order1_5x_rem);
0718 
0719         if (beta > 0)
0720             y3 = (alpha * tmp -
0721                   (1 << order2_3x)) / (1 << order2_3x);
0722         else
0723             y3 = (alpha * tmp +
0724                   (1 << order2_3x)) / (1 << order2_3x);
0725         y3 = (y3 * tmp) / (1 << order2_3x);
0726         y3 = (y3 * tmp) / (1 << order2_3x);
0727         y3 = y3 / (1 << order2_3x_rem);
0728 
0729         if (i < 4) {
0730             PA_angle = 0;
0731         } else {
0732             PA_angle = y5 + y3;
0733             if (PA_angle < -150)
0734                 PA_angle = -150;
0735             else if (PA_angle > 150)
0736                 PA_angle = 150;
0737         }
0738 
0739         pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff);
0740         if (i == 5) {
0741             PA_angle = (PA_angle + 2) >> 1;
0742             pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) +
0743                 (PA_angle & 0x7ff);
0744         }
0745     }
0746 
0747     *gain = G_fxp;
0748     return true;
0749 }
0750 
0751 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
0752                     struct ath9k_hw_cal_data *caldata,
0753                     int chain)
0754 {
0755     u32 *paprd_table_val = caldata->pa_table[chain];
0756     u32 small_signal_gain = caldata->small_signal_gain[chain];
0757     u32 training_power = ah->paprd_training_power;
0758     u32 reg = 0;
0759     int i;
0760 
0761     if (chain == 0)
0762         reg = AR_PHY_PAPRD_MEM_TAB_B0;
0763     else if (chain == 1)
0764         reg = AR_PHY_PAPRD_MEM_TAB_B1;
0765     else if (chain == 2)
0766         reg = AR_PHY_PAPRD_MEM_TAB_B2;
0767 
0768     for (i = 0; i < PAPRD_TABLE_SZ; i++) {
0769         REG_WRITE(ah, reg, paprd_table_val[i]);
0770         reg = reg + 4;
0771     }
0772 
0773     if (chain == 0)
0774         reg = AR_PHY_PA_GAIN123_B0;
0775     else if (chain == 1)
0776         reg = AR_PHY_PA_GAIN123_B1;
0777     else
0778         reg = AR_PHY_PA_GAIN123_B2;
0779 
0780     REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain);
0781 
0782     REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0,
0783               AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
0784               training_power);
0785 
0786     if (ah->caps.tx_chainmask & BIT(1))
0787         REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,
0788                   AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
0789                   training_power);
0790 
0791     if (ah->caps.tx_chainmask & BIT(2))
0792         /* val AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL correct? */
0793         REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,
0794                   AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,
0795                   training_power);
0796 }
0797 EXPORT_SYMBOL(ar9003_paprd_populate_single_table);
0798 
0799 void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
0800 {
0801     unsigned int i, desired_gain, gain_index;
0802     unsigned int train_power = ah->paprd_training_power;
0803 
0804     desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
0805 
0806     gain_index = 0;
0807     for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) {
0808         if (ah->paprd_gain_table_index[i] >= desired_gain)
0809             break;
0810         gain_index++;
0811     }
0812 
0813     ar9003_tx_force_gain(ah, gain_index);
0814 
0815     REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
0816             AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
0817 }
0818 EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
0819 
0820 static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah,
0821                        struct ath9k_hw_cal_data *caldata,
0822                        int chain)
0823 {
0824     u32 *pa_in = caldata->pa_table[chain];
0825     int capdiv_offset, quick_drop_offset;
0826     int capdiv2g, quick_drop;
0827     int count = 0;
0828     int i;
0829 
0830     if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah))
0831         return false;
0832 
0833     capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
0834                   AR_PHY_65NM_CH0_TXRF3_CAPDIV2G);
0835 
0836     quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0837                     AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);
0838 
0839     if (quick_drop)
0840         quick_drop -= 0x40;
0841 
0842     for (i = 0; i < NUM_BIN + 1; i++) {
0843         if (pa_in[i] == 1400)
0844             count++;
0845     }
0846 
0847     if (AR_SREV_9485(ah)) {
0848         if (pa_in[23] < 800) {
0849             capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150);
0850             capdiv2g += capdiv_offset;
0851             if (capdiv2g > 7) {
0852                 capdiv2g = 7;
0853                 if (pa_in[23] < 600) {
0854                     quick_drop++;
0855                     if (quick_drop > 0)
0856                         quick_drop = 0;
0857                 }
0858             }
0859         } else if (pa_in[23] == 1400) {
0860             quick_drop_offset = min_t(int, count / 3, 2);
0861             quick_drop += quick_drop_offset;
0862             capdiv2g += quick_drop_offset / 2;
0863 
0864             if (capdiv2g > 7)
0865                 capdiv2g = 7;
0866 
0867             if (quick_drop > 0) {
0868                 quick_drop = 0;
0869                 capdiv2g -= quick_drop_offset;
0870                 if (capdiv2g < 0)
0871                     capdiv2g = 0;
0872             }
0873         } else {
0874             return false;
0875         }
0876     } else if (AR_SREV_9330(ah)) {
0877         if (pa_in[23] < 1000) {
0878             capdiv_offset = (1000 - pa_in[23]) / 100;
0879             capdiv2g += capdiv_offset;
0880             if (capdiv_offset > 3) {
0881                 capdiv_offset = 1;
0882                 quick_drop--;
0883             }
0884 
0885             capdiv2g += capdiv_offset;
0886             if (capdiv2g > 6)
0887                 capdiv2g = 6;
0888             if (quick_drop < -4)
0889                 quick_drop = -4;
0890         } else if (pa_in[23] == 1400) {
0891             if (count > 3) {
0892                 quick_drop++;
0893                 capdiv2g -= count / 4;
0894                 if (quick_drop > -2)
0895                     quick_drop = -2;
0896             } else {
0897                 capdiv2g--;
0898             }
0899 
0900             if (capdiv2g < 0)
0901                 capdiv2g = 0;
0902         } else {
0903             return false;
0904         }
0905     }
0906 
0907     REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
0908               AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g);
0909     REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
0910               AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
0911               quick_drop);
0912 
0913     return true;
0914 }
0915 
0916 int ar9003_paprd_create_curve(struct ath_hw *ah,
0917                   struct ath9k_hw_cal_data *caldata, int chain)
0918 {
0919     u16 *small_signal_gain = &caldata->small_signal_gain[chain];
0920     u32 *pa_table = caldata->pa_table[chain];
0921     u32 *data_L, *data_U;
0922     int i, status = 0;
0923     u32 *buf;
0924     u32 reg;
0925 
0926     memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain]));
0927 
0928     buf = kmalloc_array(2 * 48, sizeof(u32), GFP_KERNEL);
0929     if (!buf)
0930         return -ENOMEM;
0931 
0932     data_L = &buf[0];
0933     data_U = &buf[48];
0934 
0935     REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY,
0936             AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);
0937 
0938     reg = AR_PHY_CHAN_INFO_TAB_0;
0939     for (i = 0; i < 48; i++)
0940         data_L[i] = REG_READ(ah, reg + (i << 2));
0941 
0942     REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY,
0943             AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);
0944 
0945     for (i = 0; i < 48; i++)
0946         data_U[i] = REG_READ(ah, reg + (i << 2));
0947 
0948     if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain))
0949         status = -2;
0950 
0951     if (ar9003_paprd_retrain_pa_in(ah, caldata, chain))
0952         status = -EINPROGRESS;
0953 
0954     REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
0955             AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
0956 
0957     kfree(buf);
0958 
0959     return status;
0960 }
0961 EXPORT_SYMBOL(ar9003_paprd_create_curve);
0962 
0963 int ar9003_paprd_init_table(struct ath_hw *ah)
0964 {
0965     int ret;
0966 
0967     ret = ar9003_paprd_setup_single_table(ah);
0968     if (ret < 0)
0969         return ret;
0970 
0971     ar9003_paprd_get_gain_table(ah);
0972     return 0;
0973 }
0974 EXPORT_SYMBOL(ar9003_paprd_init_table);
0975 
0976 bool ar9003_paprd_is_done(struct ath_hw *ah)
0977 {
0978     int paprd_done, agc2_pwr;
0979 
0980     paprd_done = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1,
0981                 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);
0982 
0983     if (AR_SREV_9485(ah))
0984         goto exit;
0985 
0986     if (paprd_done == 0x1) {
0987         agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1,
0988                 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR);
0989 
0990         ath_dbg(ath9k_hw_common(ah), CALIBRATE,
0991             "AGC2_PWR = 0x%x training done = 0x%x\n",
0992             agc2_pwr, paprd_done);
0993     /*
0994      * agc2_pwr range should not be less than 'IDEAL_AGC2_PWR_CHANGE'
0995      * when the training is completely done, otherwise retraining is
0996      * done to make sure the value is in ideal range
0997      */
0998         if (agc2_pwr <= PAPRD_IDEAL_AGC2_PWR_RANGE)
0999             paprd_done = 0;
1000     }
1001 exit:
1002     return !!paprd_done;
1003 }
1004 EXPORT_SYMBOL(ar9003_paprd_is_done);
1005 
1006 bool ar9003_is_paprd_enabled(struct ath_hw *ah)
1007 {
1008     if ((ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && ah->config.enable_paprd)
1009         return true;
1010 
1011     return false;
1012 }
1013 EXPORT_SYMBOL(ar9003_is_paprd_enabled);