1014 lines · c
1/*2 * Copyright (c) 2010-2011 Atheros Communications Inc.3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15 */16 17#include <linux/export.h>18#include "hw.h"19#include "ar9003_phy.h"20 21void ar9003_paprd_enable(struct ath_hw *ah, bool val)22{23 struct ath9k_channel *chan = ah->curchan;24 bool is2ghz = IS_CHAN_2GHZ(chan);25 26 /*27 * 3 bits for modalHeader5G.papdRateMaskHt2028 * is used for sub-band disabling of PAPRD.29 * 5G band is divided into 3 sub-bands -- upper,30 * middle, lower.31 * if bit 30 of modalHeader5G.papdRateMaskHt20 is set32 * -- disable PAPRD for upper band 5GHz33 * if bit 29 of modalHeader5G.papdRateMaskHt20 is set34 * -- disable PAPRD for middle band 5GHz35 * if bit 28 of modalHeader5G.papdRateMaskHt20 is set36 * -- disable PAPRD for lower band 5GHz37 */38 39 if (!is2ghz) {40 if (chan->channel >= UPPER_5G_SUB_BAND_START) {41 if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz)42 & BIT(30))43 val = false;44 } else if (chan->channel >= MID_5G_SUB_BAND_START) {45 if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz)46 & BIT(29))47 val = false;48 } else {49 if (ar9003_get_paprd_rate_mask_ht20(ah, is2ghz)50 & BIT(28))51 val = false;52 }53 }54 55 if (val) {56 ah->paprd_table_write_done = true;57 ath9k_hw_apply_txpower(ah, chan, false);58 }59 60 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0,61 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);62 if (ah->caps.tx_chainmask & BIT(1))63 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1,64 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);65 if (ah->caps.tx_chainmask & BIT(2))66 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2,67 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val);68}69EXPORT_SYMBOL(ar9003_paprd_enable);70 71static int ar9003_get_training_power_2g(struct ath_hw *ah)72{73 struct ath9k_channel *chan = ah->curchan;74 unsigned int power, scale, delta;75 76 scale = ar9003_get_paprd_scale_factor(ah, chan);77 78 if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||79 AR_SREV_9462(ah) || AR_SREV_9565(ah)) {80 power = ah->paprd_target_power + 2;81 } else if (AR_SREV_9485(ah)) {82 power = 25;83 } else {84 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,85 AR_PHY_POWERTX_RATE5_POWERTXHT20_0);86 87 delta = abs((int) ah->paprd_target_power - (int) power);88 if (delta > scale)89 return -1;90 91 if (delta < 4)92 power -= 4 - delta;93 }94 95 return power;96}97 98static int ar9003_get_training_power_5g(struct ath_hw *ah)99{100 struct ath_common *common = ath9k_hw_common(ah);101 struct ath9k_channel *chan = ah->curchan;102 unsigned int power, scale, delta;103 104 scale = ar9003_get_paprd_scale_factor(ah, chan);105 106 if (IS_CHAN_HT40(chan))107 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,108 AR_PHY_POWERTX_RATE8_POWERTXHT40_5);109 else110 power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,111 AR_PHY_POWERTX_RATE6_POWERTXHT20_5);112 113 power += scale;114 delta = abs((int) ah->paprd_target_power - (int) power);115 if (delta > scale)116 return -1;117 118 switch (get_streams(ah->txchainmask)) {119 case 1:120 delta = 6;121 break;122 case 2:123 delta = 4;124 break;125 case 3:126 delta = 2;127 break;128 default:129 delta = 0;130 ath_dbg(common, CALIBRATE, "Invalid tx-chainmask: %u\n",131 ah->txchainmask);132 }133 134 power += delta;135 return power;136}137 138static int ar9003_paprd_setup_single_table(struct ath_hw *ah)139{140 struct ath_common *common = ath9k_hw_common(ah);141 static const u32 ctrl0[3] = {142 AR_PHY_PAPRD_CTRL0_B0,143 AR_PHY_PAPRD_CTRL0_B1,144 AR_PHY_PAPRD_CTRL0_B2145 };146 static const u32 ctrl1[3] = {147 AR_PHY_PAPRD_CTRL1_B0,148 AR_PHY_PAPRD_CTRL1_B1,149 AR_PHY_PAPRD_CTRL1_B2150 };151 int training_power;152 int i, val;153 u32 am2pm_mask = ah->paprd_ratemask;154 155 if (IS_CHAN_2GHZ(ah->curchan))156 training_power = ar9003_get_training_power_2g(ah);157 else158 training_power = ar9003_get_training_power_5g(ah);159 160 ath_dbg(common, CALIBRATE, "Training power: %d, Target power: %d\n",161 training_power, ah->paprd_target_power);162 163 if (training_power < 0) {164 ath_dbg(common, CALIBRATE,165 "PAPRD target power delta out of range\n");166 return -ERANGE;167 }168 ah->paprd_training_power = training_power;169 170 if (AR_SREV_9330(ah))171 am2pm_mask = 0;172 173 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,174 ah->paprd_ratemask);175 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK,176 am2pm_mask);177 REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK,178 ah->paprd_ratemask_ht40);179 180 ath_dbg(common, CALIBRATE, "PAPRD HT20 mask: 0x%x, HT40 mask: 0x%x\n",181 ah->paprd_ratemask, ah->paprd_ratemask_ht40);182 183 for (i = 0; i < ah->caps.max_txchains; i++) {184 REG_RMW_FIELD(ah, ctrl0[i],185 AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);186 REG_RMW_FIELD(ah, ctrl1[i],187 AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1);188 REG_RMW_FIELD(ah, ctrl1[i],189 AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1);190 REG_RMW_FIELD(ah, ctrl1[i],191 AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);192 REG_RMW_FIELD(ah, ctrl1[i],193 AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181);194 REG_RMW_FIELD(ah, ctrl1[i],195 AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361);196 REG_RMW_FIELD(ah, ctrl1[i],197 AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0);198 REG_RMW_FIELD(ah, ctrl0[i],199 AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3);200 }201 202 ar9003_paprd_enable(ah, false);203 204 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah),205 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30);206 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah),207 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1);208 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah),209 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1);210 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah),211 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0);212 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah),213 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0);214 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah),215 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28);216 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1(ah),217 AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1);218 219 if (AR_SREV_9485(ah)) {220 val = 148;221 } else {222 if (IS_CHAN_2GHZ(ah->curchan)) {223 if (AR_SREV_9462(ah) || AR_SREV_9565(ah))224 val = 145;225 else226 val = 147;227 } else {228 val = 137;229 }230 }231 232 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2(ah),233 AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val);234 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),235 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4);236 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),237 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4);238 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),239 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);240 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),241 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);242 243 if (AR_SREV_9485(ah) ||244 AR_SREV_9462(ah) ||245 AR_SREV_9565(ah) ||246 AR_SREV_9550(ah) ||247 AR_SREV_9330(ah) ||248 AR_SREV_9340(ah))249 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),250 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3);251 else252 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),253 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6);254 255 val = -10;256 257 if (IS_CHAN_2GHZ(ah->curchan) && !AR_SREV_9462(ah) && !AR_SREV_9565(ah))258 val = -15;259 260 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),261 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE,262 val);263 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),264 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1);265 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah),266 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0);267 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah),268 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400);269 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4(ah),270 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES,271 100);272 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0,273 AR_PHY_PAPRD_PRE_POST_SCALING, 261376);274 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0,275 AR_PHY_PAPRD_PRE_POST_SCALING, 248079);276 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0,277 AR_PHY_PAPRD_PRE_POST_SCALING, 233759);278 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0,279 AR_PHY_PAPRD_PRE_POST_SCALING, 220464);280 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0,281 AR_PHY_PAPRD_PRE_POST_SCALING, 208194);282 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0,283 AR_PHY_PAPRD_PRE_POST_SCALING, 196949);284 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0,285 AR_PHY_PAPRD_PRE_POST_SCALING, 185706);286 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,287 AR_PHY_PAPRD_PRE_POST_SCALING, 175487);288 return 0;289}290 291static void ar9003_paprd_get_gain_table(struct ath_hw *ah)292{293 u32 *entry = ah->paprd_gain_table_entries;294 u8 *index = ah->paprd_gain_table_index;295 u32 reg = AR_PHY_TXGAIN_TABLE;296 int i;297 298 for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) {299 entry[i] = REG_READ(ah, reg);300 index[i] = (entry[i] >> 24) & 0xff;301 reg += 4;302 }303}304 305static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain,306 int target_power)307{308 int olpc_gain_delta = 0, cl_gain_mod;309 int alpha_therm, alpha_volt;310 int therm_cal_value, volt_cal_value;311 int therm_value, volt_value;312 int thermal_gain_corr, voltage_gain_corr;313 int desired_scale, desired_gain = 0;314 u32 reg_olpc = 0, reg_cl_gain = 0;315 316 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah),317 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);318 desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12,319 AR_PHY_TPC_12_DESIRED_SCALE_HT40_5);320 alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19,321 AR_PHY_TPC_19_ALPHA_THERM);322 alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19,323 AR_PHY_TPC_19_ALPHA_VOLT);324 therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,325 AR_PHY_TPC_18_THERM_CAL_VALUE);326 volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18,327 AR_PHY_TPC_18_VOLT_CAL_VALUE);328 therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,329 AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE);330 volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4,331 AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE);332 333 switch (chain) {334 case 0:335 reg_olpc = AR_PHY_TPC_11_B0;336 reg_cl_gain = AR_PHY_CL_TAB_0;337 break;338 case 1:339 reg_olpc = AR_PHY_TPC_11_B1;340 reg_cl_gain = AR_PHY_CL_TAB_1;341 break;342 case 2:343 reg_olpc = AR_PHY_TPC_11_B2;344 reg_cl_gain = AR_PHY_CL_TAB_2;345 break;346 default:347 ath_dbg(ath9k_hw_common(ah), CALIBRATE,348 "Invalid chainmask: %d\n", chain);349 break;350 }351 352 olpc_gain_delta = REG_READ_FIELD(ah, reg_olpc,353 AR_PHY_TPC_11_OLPC_GAIN_DELTA);354 cl_gain_mod = REG_READ_FIELD(ah, reg_cl_gain,355 AR_PHY_CL_TAB_CL_GAIN_MOD);356 357 if (olpc_gain_delta >= 128)358 olpc_gain_delta = olpc_gain_delta - 256;359 360 thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) +361 (256 / 2)) / 256;362 voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) +363 (128 / 2)) / 128;364 desired_gain = target_power - olpc_gain_delta - thermal_gain_corr -365 voltage_gain_corr + desired_scale + cl_gain_mod;366 367 return desired_gain;368}369 370static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index)371{372 int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain;373 int padrvgnA, padrvgnB, padrvgnC, padrvgnD;374 u32 *gain_table_entries = ah->paprd_gain_table_entries;375 376 selected_gain_entry = gain_table_entries[gain_index];377 txbb1dbgain = selected_gain_entry & 0x7;378 txbb6dbgain = (selected_gain_entry >> 3) & 0x3;379 txmxrgain = (selected_gain_entry >> 5) & 0xf;380 padrvgnA = (selected_gain_entry >> 9) & 0xf;381 padrvgnB = (selected_gain_entry >> 13) & 0xf;382 padrvgnC = (selected_gain_entry >> 17) & 0xf;383 padrvgnD = (selected_gain_entry >> 21) & 0x3;384 385 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,386 AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain);387 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,388 AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain);389 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,390 AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain);391 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,392 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA);393 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,394 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB);395 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,396 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC);397 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,398 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD);399 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,400 AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0);401 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,402 AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0);403 REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0);404 REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0);405}406 407static inline int find_expn(int num)408{409 return fls(num) - 1;410}411 412static inline int find_proper_scale(int expn, int N)413{414 return (expn > N) ? expn - 10 : 0;415}416 417#define NUM_BIN 23418 419static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)420{421 unsigned int thresh_accum_cnt;422 int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1];423 int PA_in[NUM_BIN + 1];424 int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1];425 unsigned int B1_abs_max, B2_abs_max;426 int max_index, scale_factor;427 int y_est[NUM_BIN + 1];428 int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1];429 unsigned int x_tilde_abs;430 int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad;431 int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B;432 int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2;433 int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem;434 int y5, y3, tmp;435 int theta_low_bin = 0;436 int i;437 438 /* disregard any bin that contains <= 16 samples */439 thresh_accum_cnt = 16;440 scale_factor = 5;441 max_index = 0;442 memset(theta, 0, sizeof(theta));443 memset(x_est, 0, sizeof(x_est));444 memset(Y, 0, sizeof(Y));445 memset(y_est, 0, sizeof(y_est));446 memset(x_tilde, 0, sizeof(x_tilde));447 448 for (i = 0; i < NUM_BIN; i++) {449 s32 accum_cnt, accum_tx, accum_rx, accum_ang;450 451 /* number of samples */452 accum_cnt = data_L[i] & 0xffff;453 454 if (accum_cnt <= thresh_accum_cnt)455 continue;456 457 max_index++;458 459 /* sum(tx amplitude) */460 accum_tx = ((data_L[i] >> 16) & 0xffff) |461 ((data_U[i] & 0x7ff) << 16);462 463 /* sum(rx amplitude distance to lower bin edge) */464 accum_rx = ((data_U[i] >> 11) & 0x1f) |465 ((data_L[i + 23] & 0xffff) << 5);466 467 /* sum(angles) */468 accum_ang = ((data_L[i + 23] >> 16) & 0xffff) |469 ((data_U[i + 23] & 0x7ff) << 16);470 471 accum_tx <<= scale_factor;472 accum_rx <<= scale_factor;473 x_est[max_index] =474 (((accum_tx + accum_cnt) / accum_cnt) + 32) >>475 scale_factor;476 477 Y[max_index] =478 ((((accum_rx + accum_cnt) / accum_cnt) + 32) >>479 scale_factor) +480 (1 << scale_factor) * i + 16;481 482 if (accum_ang >= (1 << 26))483 accum_ang -= 1 << 27;484 485 theta[max_index] =486 ((accum_ang * (1 << scale_factor)) + accum_cnt) /487 accum_cnt;488 }489 490 /*491 * Find average theta of first 5 bin and all of those to same value.492 * Curve is linear at that range.493 */494 for (i = 1; i < 6; i++)495 theta_low_bin += theta[i];496 497 theta_low_bin = theta_low_bin / 5;498 for (i = 1; i < 6; i++)499 theta[i] = theta_low_bin;500 501 /* Set values at origin */502 theta[0] = theta_low_bin;503 for (i = 0; i <= max_index; i++)504 theta[i] -= theta_low_bin;505 506 x_est[0] = 0;507 Y[0] = 0;508 scale_factor = 8;509 510 /* low signal gain */511 if (x_est[6] == x_est[3])512 return false;513 514 G_fxp =515 (((Y[6] - Y[3]) * 1 << scale_factor) +516 (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]);517 518 /* prevent division by zero */519 if (G_fxp == 0)520 return false;521 522 Y_intercept =523 (G_fxp * (x_est[0] - x_est[3]) +524 (1 << scale_factor)) / (1 << scale_factor) + Y[3];525 526 for (i = 0; i <= max_index; i++)527 y_est[i] = Y[i] - Y_intercept;528 529 for (i = 0; i <= 3; i++) {530 y_est[i] = i * 32;531 x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp;532 }533 534 if (y_est[max_index] == 0)535 return false;536 537 x_est_fxp1_nonlin =538 x_est[max_index] - ((1 << scale_factor) * y_est[max_index] +539 G_fxp) / G_fxp;540 541 order_x_by_y =542 (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index];543 544 if (order_x_by_y == 0)545 M = 10;546 else if (order_x_by_y == 1)547 M = 9;548 else549 M = 8;550 551 I = (max_index > 15) ? 7 : max_index >> 1;552 L = max_index - I;553 scale_factor = 8;554 sum_y_sqr = 0;555 sum_y_quad = 0;556 x_tilde_abs = 0;557 558 for (i = 0; i <= L; i++) {559 unsigned int y_sqr;560 unsigned int y_quad;561 unsigned int tmp_abs;562 563 /* prevent division by zero */564 if (y_est[i + I] == 0)565 return false;566 567 x_est_fxp1_nonlin =568 x_est[i + I] - ((1 << scale_factor) * y_est[i + I] +569 G_fxp) / G_fxp;570 571 x_tilde[i] =572 (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i +573 I];574 x_tilde[i] =575 (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];576 x_tilde[i] =577 (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I];578 y_sqr =579 (y_est[i + I] * y_est[i + I] +580 (scale_factor * scale_factor)) / (scale_factor *581 scale_factor);582 tmp_abs = abs(x_tilde[i]);583 if (tmp_abs > x_tilde_abs)584 x_tilde_abs = tmp_abs;585 586 y_quad = y_sqr * y_sqr;587 sum_y_sqr = sum_y_sqr + y_sqr;588 sum_y_quad = sum_y_quad + y_quad;589 B1_tmp[i] = y_sqr * (L + 1);590 B2_tmp[i] = y_sqr;591 }592 593 B1_abs_max = 0;594 B2_abs_max = 0;595 for (i = 0; i <= L; i++) {596 int abs_val;597 598 B1_tmp[i] -= sum_y_sqr;599 B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i];600 601 abs_val = abs(B1_tmp[i]);602 if (abs_val > B1_abs_max)603 B1_abs_max = abs_val;604 605 abs_val = abs(B2_tmp[i]);606 if (abs_val > B2_abs_max)607 B2_abs_max = abs_val;608 }609 610 Q_x = find_proper_scale(find_expn(x_tilde_abs), 10);611 Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10);612 Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10);613 614 beta_raw = 0;615 alpha_raw = 0;616 for (i = 0; i <= L; i++) {617 x_tilde[i] = x_tilde[i] / (1 << Q_x);618 B1_tmp[i] = B1_tmp[i] / (1 << Q_B1);619 B2_tmp[i] = B2_tmp[i] / (1 << Q_B2);620 beta_raw = beta_raw + B1_tmp[i] * x_tilde[i];621 alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i];622 }623 624 scale_B =625 ((sum_y_quad / scale_factor) * (L + 1) -626 (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor;627 628 Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10);629 scale_B = scale_B / (1 << Q_scale_B);630 if (scale_B == 0)631 return false;632 Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);633 Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);634 beta_raw = beta_raw / (1 << Q_beta);635 alpha_raw = alpha_raw / (1 << Q_alpha);636 alpha = (alpha_raw << 10) / scale_B;637 beta = (beta_raw << 10) / scale_B;638 order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B;639 order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B;640 order1_5x = order_1 / 5;641 order2_3x = order_2 / 3;642 order1_5x_rem = order_1 - 5 * order1_5x;643 order2_3x_rem = order_2 - 3 * order2_3x;644 645 for (i = 0; i < PAPRD_TABLE_SZ; i++) {646 tmp = i * 32;647 y5 = ((beta * tmp) >> 6) >> order1_5x;648 y5 = (y5 * tmp) >> order1_5x;649 y5 = (y5 * tmp) >> order1_5x;650 y5 = (y5 * tmp) >> order1_5x;651 y5 = (y5 * tmp) >> order1_5x;652 y5 = y5 >> order1_5x_rem;653 y3 = (alpha * tmp) >> order2_3x;654 y3 = (y3 * tmp) >> order2_3x;655 y3 = (y3 * tmp) >> order2_3x;656 y3 = y3 >> order2_3x_rem;657 PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp;658 659 if (i >= 2) {660 tmp = PA_in[i] - PA_in[i - 1];661 if (tmp < 0)662 PA_in[i] =663 PA_in[i - 1] + (PA_in[i - 1] -664 PA_in[i - 2]);665 }666 667 PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400;668 }669 670 beta_raw = 0;671 alpha_raw = 0;672 673 for (i = 0; i <= L; i++) {674 int theta_tilde =675 ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I];676 theta_tilde =677 ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];678 theta_tilde =679 ((theta_tilde << M) + y_est[i + I]) / y_est[i + I];680 beta_raw = beta_raw + B1_tmp[i] * theta_tilde;681 alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde;682 }683 684 Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10);685 Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10);686 beta_raw = beta_raw / (1 << Q_beta);687 alpha_raw = alpha_raw / (1 << Q_alpha);688 689 alpha = (alpha_raw << 10) / scale_B;690 beta = (beta_raw << 10) / scale_B;691 order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5;692 order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5;693 order1_5x = order_1 / 5;694 order2_3x = order_2 / 3;695 order1_5x_rem = order_1 - 5 * order1_5x;696 order2_3x_rem = order_2 - 3 * order2_3x;697 698 for (i = 0; i < PAPRD_TABLE_SZ; i++) {699 int PA_angle;700 701 /* pa_table[4] is calculated from PA_angle for i=5 */702 if (i == 4)703 continue;704 705 tmp = i * 32;706 if (beta > 0)707 y5 = (((beta * tmp - 64) >> 6) -708 (1 << order1_5x)) / (1 << order1_5x);709 else710 y5 = ((((beta * tmp - 64) >> 6) +711 (1 << order1_5x)) / (1 << order1_5x));712 713 y5 = (y5 * tmp) / (1 << order1_5x);714 y5 = (y5 * tmp) / (1 << order1_5x);715 y5 = (y5 * tmp) / (1 << order1_5x);716 y5 = (y5 * tmp) / (1 << order1_5x);717 y5 = y5 / (1 << order1_5x_rem);718 719 if (beta > 0)720 y3 = (alpha * tmp -721 (1 << order2_3x)) / (1 << order2_3x);722 else723 y3 = (alpha * tmp +724 (1 << order2_3x)) / (1 << order2_3x);725 y3 = (y3 * tmp) / (1 << order2_3x);726 y3 = (y3 * tmp) / (1 << order2_3x);727 y3 = y3 / (1 << order2_3x_rem);728 729 if (i < 4) {730 PA_angle = 0;731 } else {732 PA_angle = y5 + y3;733 if (PA_angle < -150)734 PA_angle = -150;735 else if (PA_angle > 150)736 PA_angle = 150;737 }738 739 pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff);740 if (i == 5) {741 PA_angle = (PA_angle + 2) >> 1;742 pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) +743 (PA_angle & 0x7ff);744 }745 }746 747 *gain = G_fxp;748 return true;749}750 751void ar9003_paprd_populate_single_table(struct ath_hw *ah,752 struct ath9k_hw_cal_data *caldata,753 int chain)754{755 u32 *paprd_table_val = caldata->pa_table[chain];756 u32 small_signal_gain = caldata->small_signal_gain[chain];757 u32 training_power = ah->paprd_training_power;758 u32 reg = 0;759 int i;760 761 if (chain == 0)762 reg = AR_PHY_PAPRD_MEM_TAB_B0;763 else if (chain == 1)764 reg = AR_PHY_PAPRD_MEM_TAB_B1;765 else if (chain == 2)766 reg = AR_PHY_PAPRD_MEM_TAB_B2;767 768 for (i = 0; i < PAPRD_TABLE_SZ; i++) {769 REG_WRITE(ah, reg, paprd_table_val[i]);770 reg = reg + 4;771 }772 773 if (chain == 0)774 reg = AR_PHY_PA_GAIN123_B0;775 else if (chain == 1)776 reg = AR_PHY_PA_GAIN123_B1;777 else778 reg = AR_PHY_PA_GAIN123_B2;779 780 REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain);781 782 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0,783 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,784 training_power);785 786 if (ah->caps.tx_chainmask & BIT(1))787 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1,788 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,789 training_power);790 791 if (ah->caps.tx_chainmask & BIT(2))792 /* val AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL correct? */793 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2,794 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL,795 training_power);796}797EXPORT_SYMBOL(ar9003_paprd_populate_single_table);798 799void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)800{801 unsigned int i, desired_gain, gain_index;802 unsigned int train_power = ah->paprd_training_power;803 804 desired_gain = ar9003_get_desired_gain(ah, chain, train_power);805 806 gain_index = 0;807 for (i = 0; i < PAPRD_GAIN_TABLE_ENTRIES; i++) {808 if (ah->paprd_gain_table_index[i] >= desired_gain)809 break;810 gain_index++;811 }812 813 ar9003_tx_force_gain(ah, gain_index);814 815 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah),816 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);817}818EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);819 820static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah,821 struct ath9k_hw_cal_data *caldata,822 int chain)823{824 u32 *pa_in = caldata->pa_table[chain];825 int capdiv_offset, quick_drop_offset;826 int capdiv2g, quick_drop;827 int count = 0;828 int i;829 830 if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah))831 return false;832 833 capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,834 AR_PHY_65NM_CH0_TXRF3_CAPDIV2G);835 836 quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),837 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);838 839 if (quick_drop)840 quick_drop -= 0x40;841 842 for (i = 0; i < NUM_BIN + 1; i++) {843 if (pa_in[i] == 1400)844 count++;845 }846 847 if (AR_SREV_9485(ah)) {848 if (pa_in[23] < 800) {849 capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150);850 capdiv2g += capdiv_offset;851 if (capdiv2g > 7) {852 capdiv2g = 7;853 if (pa_in[23] < 600) {854 quick_drop++;855 if (quick_drop > 0)856 quick_drop = 0;857 }858 }859 } else if (pa_in[23] == 1400) {860 quick_drop_offset = min_t(int, count / 3, 2);861 quick_drop += quick_drop_offset;862 capdiv2g += quick_drop_offset / 2;863 864 if (capdiv2g > 7)865 capdiv2g = 7;866 867 if (quick_drop > 0) {868 quick_drop = 0;869 capdiv2g -= quick_drop_offset;870 if (capdiv2g < 0)871 capdiv2g = 0;872 }873 } else {874 return false;875 }876 } else if (AR_SREV_9330(ah)) {877 if (pa_in[23] < 1000) {878 capdiv_offset = (1000 - pa_in[23]) / 100;879 capdiv2g += capdiv_offset;880 if (capdiv_offset > 3) {881 capdiv_offset = 1;882 quick_drop--;883 }884 885 capdiv2g += capdiv_offset;886 if (capdiv2g > 6)887 capdiv2g = 6;888 if (quick_drop < -4)889 quick_drop = -4;890 } else if (pa_in[23] == 1400) {891 if (count > 3) {892 quick_drop++;893 capdiv2g -= count / 4;894 if (quick_drop > -2)895 quick_drop = -2;896 } else {897 capdiv2g--;898 }899 900 if (capdiv2g < 0)901 capdiv2g = 0;902 } else {903 return false;904 }905 }906 907 REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,908 AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g);909 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3(ah),910 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,911 quick_drop);912 913 return true;914}915 916int ar9003_paprd_create_curve(struct ath_hw *ah,917 struct ath9k_hw_cal_data *caldata, int chain)918{919 u16 *small_signal_gain = &caldata->small_signal_gain[chain];920 u32 *pa_table = caldata->pa_table[chain];921 u32 *data_L, *data_U;922 int i, status = 0;923 u32 *buf;924 u32 reg;925 926 memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain]));927 928 buf = kmalloc_array(2 * 48, sizeof(u32), GFP_KERNEL);929 if (!buf)930 return -ENOMEM;931 932 data_L = &buf[0];933 data_U = &buf[48];934 935 REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY(ah),936 AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);937 938 reg = AR_PHY_CHAN_INFO_TAB_0;939 for (i = 0; i < 48; i++)940 data_L[i] = REG_READ(ah, reg + (i << 2));941 942 REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY(ah),943 AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ);944 945 for (i = 0; i < 48; i++)946 data_U[i] = REG_READ(ah, reg + (i << 2));947 948 if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain))949 status = -2;950 951 if (ar9003_paprd_retrain_pa_in(ah, caldata, chain))952 status = -EINPROGRESS;953 954 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah),955 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);956 957 kfree(buf);958 959 return status;960}961EXPORT_SYMBOL(ar9003_paprd_create_curve);962 963int ar9003_paprd_init_table(struct ath_hw *ah)964{965 int ret;966 967 ret = ar9003_paprd_setup_single_table(ah);968 if (ret < 0)969 return ret;970 971 ar9003_paprd_get_gain_table(ah);972 return 0;973}974EXPORT_SYMBOL(ar9003_paprd_init_table);975 976bool ar9003_paprd_is_done(struct ath_hw *ah)977{978 int paprd_done, agc2_pwr;979 980 paprd_done = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah),981 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);982 983 if (AR_SREV_9485(ah))984 goto exit;985 986 if (paprd_done == 0x1) {987 agc2_pwr = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1(ah),988 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR);989 990 ath_dbg(ath9k_hw_common(ah), CALIBRATE,991 "AGC2_PWR = 0x%x training done = 0x%x\n",992 agc2_pwr, paprd_done);993 /*994 * agc2_pwr range should not be less than 'IDEAL_AGC2_PWR_CHANGE'995 * when the training is completely done, otherwise retraining is996 * done to make sure the value is in ideal range997 */998 if (agc2_pwr <= PAPRD_IDEAL_AGC2_PWR_RANGE)999 paprd_done = 0;1000 }1001exit:1002 return !!paprd_done;1003}1004EXPORT_SYMBOL(ar9003_paprd_is_done);1005 1006bool 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}1013EXPORT_SYMBOL(ar9003_is_paprd_enabled);1014