1/* 2 * Copyright (c) 2010 Atheros Communications Inc. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include "hw.h" 18#include "ar9003_phy.h" 19 20void ar9003_paprd_enable(struct ath_hw *ah, bool val) 21{ 22 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0, 23 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 24 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B1, 25 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 26 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B2, 27 AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE, !!val); 28} 29EXPORT_SYMBOL(ar9003_paprd_enable); 30 31static void ar9003_paprd_setup_single_table(struct ath_hw *ah) 32{ 33 struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; 34 struct ar9300_modal_eep_header *hdr; 35 const u32 ctrl0[3] = { 36 AR_PHY_PAPRD_CTRL0_B0, 37 AR_PHY_PAPRD_CTRL0_B1, 38 AR_PHY_PAPRD_CTRL0_B2 39 }; 40 const u32 ctrl1[3] = { 41 AR_PHY_PAPRD_CTRL1_B0, 42 AR_PHY_PAPRD_CTRL1_B1, 43 AR_PHY_PAPRD_CTRL1_B2 44 }; 45 u32 am_mask, ht40_mask; 46 int i; 47 48 if (ah->curchan && IS_CHAN_5GHZ(ah->curchan)) 49 hdr = &eep->modalHeader5G; 50 else 51 hdr = &eep->modalHeader2G; 52 53 am_mask = le32_to_cpu(hdr->papdRateMaskHt20); 54 ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40); 55 56 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask); 57 REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask); 58 REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask); 59 60 for (i = 0; i < 3; i++) { 61 REG_RMW_FIELD(ah, ctrl0[i], 62 AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1); 63 REG_RMW_FIELD(ah, ctrl1[i], 64 AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE, 1); 65 REG_RMW_FIELD(ah, ctrl1[i], 66 AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE, 1); 67 REG_RMW_FIELD(ah, ctrl1[i], 68 AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 69 REG_RMW_FIELD(ah, ctrl1[i], 70 AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK, 181); 71 REG_RMW_FIELD(ah, ctrl1[i], 72 AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT, 361); 73 REG_RMW_FIELD(ah, ctrl1[i], 74 AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA, 0); 75 REG_RMW_FIELD(ah, ctrl0[i], 76 AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH, 3); 77 } 78 79 ar9003_paprd_enable(ah, false); 80 81 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 82 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP, 0x30); 83 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 84 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE, 1); 85 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 86 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE, 1); 87 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 88 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE, 0); 89 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 90 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE, 0); 91 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 92 AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28); 93 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, 94 AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1); 95 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2, 96 AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147); 97 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 98 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4); 99 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 100 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN, 4); 101 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 102 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); 103 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 104 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); 105 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 106 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6); 107 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 108 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, 109 -15); 110 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, 111 AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1); 112 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 113 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA, 0); 114 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 115 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR, 400); 116 REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, 117 AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES, 118 100); 119 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_0_B0, 120 AR_PHY_PAPRD_PRE_POST_SCALING, 261376); 121 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_1_B0, 122 AR_PHY_PAPRD_PRE_POST_SCALING, 248079); 123 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_2_B0, 124 AR_PHY_PAPRD_PRE_POST_SCALING, 233759); 125 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_3_B0, 126 AR_PHY_PAPRD_PRE_POST_SCALING, 220464); 127 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_4_B0, 128 AR_PHY_PAPRD_PRE_POST_SCALING, 208194); 129 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_5_B0, 130 AR_PHY_PAPRD_PRE_POST_SCALING, 196949); 131 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_6_B0, 132 AR_PHY_PAPRD_PRE_POST_SCALING, 185706); 133 REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0, 134 AR_PHY_PAPRD_PRE_POST_SCALING, 175487); 135} 136 137static void ar9003_paprd_get_gain_table(struct ath_hw *ah) 138{ 139 u32 *entry = ah->paprd_gain_table_entries; 140 u8 *index = ah->paprd_gain_table_index; 141 u32 reg = AR_PHY_TXGAIN_TABLE; 142 int i; 143 144 memset(entry, 0, sizeof(ah->paprd_gain_table_entries)); 145 memset(index, 0, sizeof(ah->paprd_gain_table_index)); 146 147 for (i = 0; i < 32; i++) { 148 entry[i] = REG_READ(ah, reg); 149 index[i] = (entry[i] >> 24) & 0xff; 150 reg += 4; 151 } 152} 153 154static unsigned int ar9003_get_desired_gain(struct ath_hw *ah, int chain, 155 int target_power) 156{ 157 int olpc_gain_delta = 0; 158 int alpha_therm, alpha_volt; 159 int therm_cal_value, volt_cal_value; 160 int therm_value, volt_value; 161 int thermal_gain_corr, voltage_gain_corr; 162 int desired_scale, desired_gain = 0; 163 u32 reg; 164 165 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 166 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 167 desired_scale = REG_READ_FIELD(ah, AR_PHY_TPC_12, 168 AR_PHY_TPC_12_DESIRED_SCALE_HT40_5); 169 alpha_therm = REG_READ_FIELD(ah, AR_PHY_TPC_19, 170 AR_PHY_TPC_19_ALPHA_THERM); 171 alpha_volt = REG_READ_FIELD(ah, AR_PHY_TPC_19, 172 AR_PHY_TPC_19_ALPHA_VOLT); 173 therm_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 174 AR_PHY_TPC_18_THERM_CAL_VALUE); 175 volt_cal_value = REG_READ_FIELD(ah, AR_PHY_TPC_18, 176 AR_PHY_TPC_18_VOLT_CAL_VALUE); 177 therm_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 178 AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE); 179 volt_value = REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, 180 AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE); 181 182 if (chain == 0) 183 reg = AR_PHY_TPC_11_B0; 184 else if (chain == 1) 185 reg = AR_PHY_TPC_11_B1; 186 else 187 reg = AR_PHY_TPC_11_B2; 188 189 olpc_gain_delta = REG_READ_FIELD(ah, reg, 190 AR_PHY_TPC_11_OLPC_GAIN_DELTA); 191 192 if (olpc_gain_delta >= 128) 193 olpc_gain_delta = olpc_gain_delta - 256; 194 195 thermal_gain_corr = (alpha_therm * (therm_value - therm_cal_value) + 196 (256 / 2)) / 256; 197 voltage_gain_corr = (alpha_volt * (volt_value - volt_cal_value) + 198 (128 / 2)) / 128; 199 desired_gain = target_power - olpc_gain_delta - thermal_gain_corr - 200 voltage_gain_corr + desired_scale; 201 202 return desired_gain; 203} 204 205static void ar9003_tx_force_gain(struct ath_hw *ah, unsigned int gain_index) 206{ 207 int selected_gain_entry, txbb1dbgain, txbb6dbgain, txmxrgain; 208 int padrvgnA, padrvgnB, padrvgnC, padrvgnD; 209 u32 *gain_table_entries = ah->paprd_gain_table_entries; 210 211 selected_gain_entry = gain_table_entries[gain_index]; 212 txbb1dbgain = selected_gain_entry & 0x7; 213 txbb6dbgain = (selected_gain_entry >> 3) & 0x3; 214 txmxrgain = (selected_gain_entry >> 5) & 0xf; 215 padrvgnA = (selected_gain_entry >> 9) & 0xf; 216 padrvgnB = (selected_gain_entry >> 13) & 0xf; 217 padrvgnC = (selected_gain_entry >> 17) & 0xf; 218 padrvgnD = (selected_gain_entry >> 21) & 0x3; 219 220 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 221 AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN, txbb1dbgain); 222 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 223 AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN, txbb6dbgain); 224 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 225 AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN, txmxrgain); 226 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 227 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA, padrvgnA); 228 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 229 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB, padrvgnB); 230 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 231 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC, padrvgnC); 232 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 233 AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND, padrvgnD); 234 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 235 AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL, 0); 236 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 237 AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN, 0); 238 REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCED_DAC_GAIN, 0); 239 REG_RMW_FIELD(ah, AR_PHY_TPC_1, AR_PHY_TPC_1_FORCE_DAC_GAIN, 0); 240} 241 242static inline int find_expn(int num) 243{ 244 return fls(num) - 1; 245} 246 247static inline int find_proper_scale(int expn, int N) 248{ 249 return (expn > N) ? expn - 10 : 0; 250} 251 252#define NUM_BIN 23 253 254static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) 255{ 256 unsigned int thresh_accum_cnt; 257 int x_est[NUM_BIN + 1], Y[NUM_BIN + 1], theta[NUM_BIN + 1]; 258 int PA_in[NUM_BIN + 1]; 259 int B1_tmp[NUM_BIN + 1], B2_tmp[NUM_BIN + 1]; 260 unsigned int B1_abs_max, B2_abs_max; 261 int max_index, scale_factor; 262 int y_est[NUM_BIN + 1]; 263 int x_est_fxp1_nonlin, x_tilde[NUM_BIN + 1]; 264 unsigned int x_tilde_abs; 265 int G_fxp, Y_intercept, order_x_by_y, M, I, L, sum_y_sqr, sum_y_quad; 266 int Q_x, Q_B1, Q_B2, beta_raw, alpha_raw, scale_B; 267 int Q_scale_B, Q_beta, Q_alpha, alpha, beta, order_1, order_2; 268 int order1_5x, order2_3x, order1_5x_rem, order2_3x_rem; 269 int y5, y3, tmp; 270 int theta_low_bin = 0; 271 int i; 272 273 /* disregard any bin that contains <= 16 samples */ 274 thresh_accum_cnt = 16; 275 scale_factor = 5; 276 max_index = 0; 277 memset(theta, 0, sizeof(theta)); 278 memset(x_est, 0, sizeof(x_est)); 279 memset(Y, 0, sizeof(Y)); 280 memset(y_est, 0, sizeof(y_est)); 281 memset(x_tilde, 0, sizeof(x_tilde)); 282 283 for (i = 0; i < NUM_BIN; i++) { 284 s32 accum_cnt, accum_tx, accum_rx, accum_ang; 285 286 /* number of samples */ 287 accum_cnt = data_L[i] & 0xffff; 288 289 if (accum_cnt <= thresh_accum_cnt) 290 continue; 291 292 /* sum(tx amplitude) */ 293 accum_tx = ((data_L[i] >> 16) & 0xffff) | 294 ((data_U[i] & 0x7ff) << 16); 295 296 /* sum(rx amplitude distance to lower bin edge) */ 297 accum_rx = ((data_U[i] >> 11) & 0x1f) | 298 ((data_L[i + 23] & 0xffff) << 5); 299 300 /* sum(angles) */ 301 accum_ang = ((data_L[i + 23] >> 16) & 0xffff) | 302 ((data_U[i + 23] & 0x7ff) << 16); 303 304 accum_tx <<= scale_factor; 305 accum_rx <<= scale_factor; 306 x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >> 307 scale_factor; 308 309 Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >> 310 scale_factor) + 311 (1 << scale_factor) * max_index + 16; 312 313 if (accum_ang >= (1 << 26)) 314 accum_ang -= 1 << 27; 315 316 theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) / 317 accum_cnt; 318 319 max_index++; 320 } 321 322 /* 323 * Find average theta of first 5 bin and all of those to same value. 324 * Curve is linear at that range. 325 */ 326 for (i = 1; i < 6; i++) 327 theta_low_bin += theta[i]; 328 329 theta_low_bin = theta_low_bin / 5; 330 for (i = 1; i < 6; i++) 331 theta[i] = theta_low_bin; 332 333 /* Set values at origin */ 334 theta[0] = theta_low_bin; 335 for (i = 0; i <= max_index; i++) 336 theta[i] -= theta_low_bin; 337 338 x_est[0] = 0; 339 Y[0] = 0; 340 scale_factor = 8; 341 342 /* low signal gain */ 343 if (x_est[6] == x_est[3]) 344 return false; 345 346 G_fxp = 347 (((Y[6] - Y[3]) * 1 << scale_factor) + 348 (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]); 349 350 /* prevent division by zero */ 351 if (G_fxp == 0) 352 return false; 353 354 Y_intercept = 355 (G_fxp * (x_est[0] - x_est[3]) + 356 (1 << scale_factor)) / (1 << scale_factor) + Y[3]; 357 358 for (i = 0; i <= max_index; i++) 359 y_est[i] = Y[i] - Y_intercept; 360 361 for (i = 0; i <= 3; i++) { 362 y_est[i] = i * 32; 363 x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp; 364 } 365 366 if (y_est[max_index] == 0) 367 return false; 368 369 x_est_fxp1_nonlin = 370 x_est[max_index] - ((1 << scale_factor) * y_est[max_index] + 371 G_fxp) / G_fxp; 372 373 order_x_by_y = 374 (x_est_fxp1_nonlin + y_est[max_index]) / y_est[max_index]; 375 376 if (order_x_by_y == 0) 377 M = 10; 378 else if (order_x_by_y == 1) 379 M = 9; 380 else 381 M = 8; 382 383 I = (max_index > 15) ? 7 : max_index >> 1; 384 L = max_index - I; 385 scale_factor = 8; 386 sum_y_sqr = 0; 387 sum_y_quad = 0; 388 x_tilde_abs = 0; 389 390 for (i = 0; i <= L; i++) { 391 unsigned int y_sqr; 392 unsigned int y_quad; 393 unsigned int tmp_abs; 394 395 /* prevent division by zero */ 396 if (y_est[i + I] == 0) 397 return false; 398 399 x_est_fxp1_nonlin = 400 x_est[i + I] - ((1 << scale_factor) * y_est[i + I] + 401 G_fxp) / G_fxp; 402 403 x_tilde[i] = 404 (x_est_fxp1_nonlin * (1 << M) + y_est[i + I]) / y_est[i + 405 I]; 406 x_tilde[i] = 407 (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 408 x_tilde[i] = 409 (x_tilde[i] * (1 << M) + y_est[i + I]) / y_est[i + I]; 410 y_sqr = 411 (y_est[i + I] * y_est[i + I] + 412 (scale_factor * scale_factor)) / (scale_factor * 413 scale_factor); 414 tmp_abs = abs(x_tilde[i]); 415 if (tmp_abs > x_tilde_abs) 416 x_tilde_abs = tmp_abs; 417 418 y_quad = y_sqr * y_sqr; 419 sum_y_sqr = sum_y_sqr + y_sqr; 420 sum_y_quad = sum_y_quad + y_quad; 421 B1_tmp[i] = y_sqr * (L + 1); 422 B2_tmp[i] = y_sqr; 423 } 424 425 B1_abs_max = 0; 426 B2_abs_max = 0; 427 for (i = 0; i <= L; i++) { 428 int abs_val; 429 430 B1_tmp[i] -= sum_y_sqr; 431 B2_tmp[i] = sum_y_quad - sum_y_sqr * B2_tmp[i]; 432 433 abs_val = abs(B1_tmp[i]); 434 if (abs_val > B1_abs_max) 435 B1_abs_max = abs_val; 436 437 abs_val = abs(B2_tmp[i]); 438 if (abs_val > B2_abs_max) 439 B2_abs_max = abs_val; 440 } 441 442 Q_x = find_proper_scale(find_expn(x_tilde_abs), 10); 443 Q_B1 = find_proper_scale(find_expn(B1_abs_max), 10); 444 Q_B2 = find_proper_scale(find_expn(B2_abs_max), 10); 445 446 beta_raw = 0; 447 alpha_raw = 0; 448 for (i = 0; i <= L; i++) { 449 x_tilde[i] = x_tilde[i] / (1 << Q_x); 450 B1_tmp[i] = B1_tmp[i] / (1 << Q_B1); 451 B2_tmp[i] = B2_tmp[i] / (1 << Q_B2); 452 beta_raw = beta_raw + B1_tmp[i] * x_tilde[i]; 453 alpha_raw = alpha_raw + B2_tmp[i] * x_tilde[i]; 454 } 455 456 scale_B = 457 ((sum_y_quad / scale_factor) * (L + 1) - 458 (sum_y_sqr / scale_factor) * sum_y_sqr) * scale_factor; 459 460 Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10); 461 scale_B = scale_B / (1 << Q_scale_B); 462 if (scale_B == 0) 463 return false; 464 Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 465 Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 466 beta_raw = beta_raw / (1 << Q_beta); 467 alpha_raw = alpha_raw / (1 << Q_alpha); 468 alpha = (alpha_raw << 10) / scale_B; 469 beta = (beta_raw << 10) / scale_B; 470 order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B; 471 order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B; 472 order1_5x = order_1 / 5; 473 order2_3x = order_2 / 3; 474 order1_5x_rem = order_1 - 5 * order1_5x; 475 order2_3x_rem = order_2 - 3 * order2_3x; 476 477 for (i = 0; i < PAPRD_TABLE_SZ; i++) { 478 tmp = i * 32; 479 y5 = ((beta * tmp) >> 6) >> order1_5x; 480 y5 = (y5 * tmp) >> order1_5x; 481 y5 = (y5 * tmp) >> order1_5x; 482 y5 = (y5 * tmp) >> order1_5x; 483 y5 = (y5 * tmp) >> order1_5x; 484 y5 = y5 >> order1_5x_rem; 485 y3 = (alpha * tmp) >> order2_3x; 486 y3 = (y3 * tmp) >> order2_3x; 487 y3 = (y3 * tmp) >> order2_3x; 488 y3 = y3 >> order2_3x_rem; 489 PA_in[i] = y5 + y3 + (256 * tmp) / G_fxp; 490 491 if (i >= 2) { 492 tmp = PA_in[i] - PA_in[i - 1]; 493 if (tmp < 0) 494 PA_in[i] = 495 PA_in[i - 1] + (PA_in[i - 1] - 496 PA_in[i - 2]); 497 } 498 499 PA_in[i] = (PA_in[i] < 1400) ? PA_in[i] : 1400; 500 } 501 502 beta_raw = 0; 503 alpha_raw = 0; 504 505 for (i = 0; i <= L; i++) { 506 int theta_tilde = 507 ((theta[i + I] << M) + y_est[i + I]) / y_est[i + I]; 508 theta_tilde = 509 ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 510 theta_tilde = 511 ((theta_tilde << M) + y_est[i + I]) / y_est[i + I]; 512 beta_raw = beta_raw + B1_tmp[i] * theta_tilde; 513 alpha_raw = alpha_raw + B2_tmp[i] * theta_tilde; 514 } 515 516 Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); 517 Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); 518 beta_raw = beta_raw / (1 << Q_beta); 519 alpha_raw = alpha_raw / (1 << Q_alpha); 520 521 alpha = (alpha_raw << 10) / scale_B; 522 beta = (beta_raw << 10) / scale_B; 523 order_1 = 3 * M - Q_x - Q_B1 - Q_beta + 10 + Q_scale_B + 5; 524 order_2 = 3 * M - Q_x - Q_B2 - Q_alpha + 10 + Q_scale_B + 5; 525 order1_5x = order_1 / 5; 526 order2_3x = order_2 / 3; 527 order1_5x_rem = order_1 - 5 * order1_5x; 528 order2_3x_rem = order_2 - 3 * order2_3x; 529 530 for (i = 0; i < PAPRD_TABLE_SZ; i++) { 531 int PA_angle; 532 533 /* pa_table[4] is calculated from PA_angle for i=5 */ 534 if (i == 4) 535 continue; 536 537 tmp = i * 32; 538 if (beta > 0) 539 y5 = (((beta * tmp - 64) >> 6) - 540 (1 << order1_5x)) / (1 << order1_5x); 541 else 542 y5 = ((((beta * tmp - 64) >> 6) + 543 (1 << order1_5x)) / (1 << order1_5x)); 544 545 y5 = (y5 * tmp) / (1 << order1_5x); 546 y5 = (y5 * tmp) / (1 << order1_5x); 547 y5 = (y5 * tmp) / (1 << order1_5x); 548 y5 = (y5 * tmp) / (1 << order1_5x); 549 y5 = y5 / (1 << order1_5x_rem); 550 551 if (beta > 0) 552 y3 = (alpha * tmp - 553 (1 << order2_3x)) / (1 << order2_3x); 554 else 555 y3 = (alpha * tmp + 556 (1 << order2_3x)) / (1 << order2_3x); 557 y3 = (y3 * tmp) / (1 << order2_3x); 558 y3 = (y3 * tmp) / (1 << order2_3x); 559 y3 = y3 / (1 << order2_3x_rem); 560 561 if (i < 4) { 562 PA_angle = 0; 563 } else { 564 PA_angle = y5 + y3; 565 if (PA_angle < -150) 566 PA_angle = -150; 567 else if (PA_angle > 150) 568 PA_angle = 150; 569 } 570 571 pa_table[i] = ((PA_in[i] & 0x7ff) << 11) + (PA_angle & 0x7ff); 572 if (i == 5) { 573 PA_angle = (PA_angle + 2) >> 1; 574 pa_table[i - 1] = ((PA_in[i - 1] & 0x7ff) << 11) + 575 (PA_angle & 0x7ff); 576 } 577 } 578 579 *gain = G_fxp; 580 return true; 581} 582 583void ar9003_paprd_populate_single_table(struct ath_hw *ah, 584 struct ath9k_hw_cal_data *caldata, 585 int chain) 586{ 587 u32 *paprd_table_val = caldata->pa_table[chain]; 588 u32 small_signal_gain = caldata->small_signal_gain[chain]; 589 u32 training_power; 590 u32 reg = 0; 591 int i; 592 593 training_power = 594 REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, 595 AR_PHY_POWERTX_RATE5_POWERTXHT20_0); 596 training_power -= 4; 597 598 if (chain == 0) 599 reg = AR_PHY_PAPRD_MEM_TAB_B0; 600 else if (chain == 1) 601 reg = AR_PHY_PAPRD_MEM_TAB_B1; 602 else if (chain == 2) 603 reg = AR_PHY_PAPRD_MEM_TAB_B2; 604 605 for (i = 0; i < PAPRD_TABLE_SZ; i++) { 606 REG_WRITE(ah, reg, paprd_table_val[i]); 607 reg = reg + 4; 608 } 609 610 if (chain == 0) 611 reg = AR_PHY_PA_GAIN123_B0; 612 else if (chain == 1) 613 reg = AR_PHY_PA_GAIN123_B1; 614 else 615 reg = AR_PHY_PA_GAIN123_B2; 616 617 REG_RMW_FIELD(ah, reg, AR_PHY_PA_GAIN123_PA_GAIN1, small_signal_gain); 618 619 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B0, 620 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 621 training_power); 622 623 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B1, 624 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 625 training_power); 626 627 REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2, 628 AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, 629 training_power); 630} 631EXPORT_SYMBOL(ar9003_paprd_populate_single_table); 632 633int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) 634{ 635 636 unsigned int i, desired_gain, gain_index; 637 unsigned int train_power; 638 639 train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5, 640 AR_PHY_POWERTX_RATE5_POWERTXHT20_0); 641 642 train_power = train_power - 4; 643 644 desired_gain = ar9003_get_desired_gain(ah, chain, train_power); 645 646 gain_index = 0; 647 for (i = 0; i < 32; i++) { 648 if (ah->paprd_gain_table_index[i] >= desired_gain) 649 break; 650 gain_index++; 651 } 652 653 ar9003_tx_force_gain(ah, gain_index); 654 655 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 656 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 657 658 return 0; 659} 660EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); 661 662int ar9003_paprd_create_curve(struct ath_hw *ah, 663 struct ath9k_hw_cal_data *caldata, int chain) 664{ 665 u16 *small_signal_gain = &caldata->small_signal_gain[chain]; 666 u32 *pa_table = caldata->pa_table[chain]; 667 u32 *data_L, *data_U; 668 int i, status = 0; 669 u32 *buf; 670 u32 reg; 671 672 memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); 673 674 buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC); 675 if (!buf) 676 return -ENOMEM; 677 678 data_L = &buf[0]; 679 data_U = &buf[48]; 680 681 REG_CLR_BIT(ah, AR_PHY_CHAN_INFO_MEMORY, 682 AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 683 684 reg = AR_PHY_CHAN_INFO_TAB_0; 685 for (i = 0; i < 48; i++) 686 data_L[i] = REG_READ(ah, reg + (i << 2)); 687 688 REG_SET_BIT(ah, AR_PHY_CHAN_INFO_MEMORY, 689 AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ); 690 691 for (i = 0; i < 48; i++) 692 data_U[i] = REG_READ(ah, reg + (i << 2)); 693 694 if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain)) 695 status = -2; 696 697 REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1, 698 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 699 700 kfree(buf); 701 702 return status; 703} 704EXPORT_SYMBOL(ar9003_paprd_create_curve); 705 706int ar9003_paprd_init_table(struct ath_hw *ah) 707{ 708 ar9003_paprd_setup_single_table(ah); 709 ar9003_paprd_get_gain_table(ah); 710 return 0; 711} 712EXPORT_SYMBOL(ar9003_paprd_init_table); 713 714bool ar9003_paprd_is_done(struct ath_hw *ah) 715{ 716 return !!REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_STAT1, 717 AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE); 718} 719EXPORT_SYMBOL(ar9003_paprd_is_done); 720