0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
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
0028
0029
0030
0031
0032
0033
0034
0035
0036
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
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
0452 accum_cnt = data_L[i] & 0xffff;
0453
0454 if (accum_cnt <= thresh_accum_cnt)
0455 continue;
0456
0457 max_index++;
0458
0459
0460 accum_tx = ((data_L[i] >> 16) & 0xffff) |
0461 ((data_U[i] & 0x7ff) << 16);
0462
0463
0464 accum_rx = ((data_U[i] >> 11) & 0x1f) |
0465 ((data_L[i + 23] & 0xffff) << 5);
0466
0467
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
0492
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
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
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
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
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
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
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
0995
0996
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);