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 "hw-ops.h" 19 #include "ar9003_phy.h" 20 21 #define MPASS 3 22 #define MAX_MEASUREMENT 8 23 #define MAX_DIFFERENCE 10 24 25 struct coeff { 26 int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; 27 int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; 28 int iqc_coeff[2]; 29 }; 30 31 enum ar9003_cal_types { 32 IQ_MISMATCH_CAL = BIT(0), 33 TEMP_COMP_CAL = BIT(1), 34 }; 35 36 static void ar9003_hw_setup_calibration(struct ath_hw *ah, 37 struct ath9k_cal_list *currCal) 38 { 39 struct ath_common *common = ath9k_hw_common(ah); 40 41 /* Select calibration to run */ 42 switch (currCal->calData->calType) { 43 case IQ_MISMATCH_CAL: 44 /* 45 * Start calibration with 46 * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples 47 */ 48 REG_RMW_FIELD(ah, AR_PHY_TIMING4, 49 AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, 50 currCal->calData->calCountMax); 51 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 52 53 ath_dbg(common, ATH_DBG_CALIBRATE, 54 "starting IQ Mismatch Calibration\n"); 55 56 /* Kick-off cal */ 57 REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); 58 break; 59 case TEMP_COMP_CAL: 60 REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, 61 AR_PHY_65NM_CH0_THERM_LOCAL, 1); 62 REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, 63 AR_PHY_65NM_CH0_THERM_START, 1); 64 65 ath_dbg(common, ATH_DBG_CALIBRATE, 66 "starting Temperature Compensation Calibration\n"); 67 break; 68 } 69 } 70 71 /* 72 * Generic calibration routine. 73 * Recalibrate the lower PHY chips to account for temperature/environment 74 * changes. 75 */ 76 static bool ar9003_hw_per_calibration(struct ath_hw *ah, 77 struct ath9k_channel *ichan, 78 u8 rxchainmask, 79 struct ath9k_cal_list *currCal) 80 { 81 struct ath9k_hw_cal_data *caldata = ah->caldata; 82 /* Cal is assumed not done until explicitly set below */ 83 bool iscaldone = false; 84 85 /* Calibration in progress. */ 86 if (currCal->calState == CAL_RUNNING) { 87 /* Check to see if it has finished. */ 88 if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { 89 /* 90 * Accumulate cal measures for active chains 91 */ 92 currCal->calData->calCollect(ah); 93 ah->cal_samples++; 94 95 if (ah->cal_samples >= 96 currCal->calData->calNumSamples) { 97 unsigned int i, numChains = 0; 98 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 99 if (rxchainmask & (1 << i)) 100 numChains++; 101 } 102 103 /* 104 * Process accumulated data 105 */ 106 currCal->calData->calPostProc(ah, numChains); 107 108 /* Calibration has finished. */ 109 caldata->CalValid |= currCal->calData->calType; 110 currCal->calState = CAL_DONE; 111 iscaldone = true; 112 } else { 113 /* 114 * Set-up collection of another sub-sample until we 115 * get desired number 116 */ 117 ar9003_hw_setup_calibration(ah, currCal); 118 } 119 } 120 } else if (!(caldata->CalValid & currCal->calData->calType)) { 121 /* If current cal is marked invalid in channel, kick it off */ 122 ath9k_hw_reset_calibration(ah, currCal); 123 } 124 125 return iscaldone; 126 } 127 128 static bool ar9003_hw_calibrate(struct ath_hw *ah, 129 struct ath9k_channel *chan, 130 u8 rxchainmask, 131 bool longcal) 132 { 133 bool iscaldone = true; 134 struct ath9k_cal_list *currCal = ah->cal_list_curr; 135 136 /* 137 * For given calibration: 138 * 1. Call generic cal routine 139 * 2. When this cal is done (isCalDone) if we have more cals waiting 140 * (eg after reset), mask this to upper layers by not propagating 141 * isCalDone if it is set to TRUE. 142 * Instead, change isCalDone to FALSE and setup the waiting cal(s) 143 * to be run. 144 */ 145 if (currCal && 146 (currCal->calState == CAL_RUNNING || 147 currCal->calState == CAL_WAITING)) { 148 iscaldone = ar9003_hw_per_calibration(ah, chan, 149 rxchainmask, currCal); 150 if (iscaldone) { 151 ah->cal_list_curr = currCal = currCal->calNext; 152 153 if (currCal->calState == CAL_WAITING) { 154 iscaldone = false; 155 ath9k_hw_reset_calibration(ah, currCal); 156 } 157 } 158 } 159 160 /* Do NF cal only at longer intervals */ 161 if (longcal) { 162 /* 163 * Get the value from the previous NF cal and update 164 * history buffer. 165 */ 166 ath9k_hw_getnf(ah, chan); 167 168 /* 169 * Load the NF from history buffer of the current channel. 170 * NF is slow time-variant, so it is OK to use a historical 171 * value. 172 */ 173 ath9k_hw_loadnf(ah, ah->curchan); 174 175 /* start NF calibration, without updating BB NF register */ 176 ath9k_hw_start_nfcal(ah, false); 177 } 178 179 return iscaldone; 180 } 181 182 static void ar9003_hw_iqcal_collect(struct ath_hw *ah) 183 { 184 int i; 185 186 /* Accumulate IQ cal measures for active chains */ 187 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 188 ah->totalPowerMeasI[i] += 189 REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 190 ah->totalPowerMeasQ[i] += 191 REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 192 ah->totalIqCorrMeas[i] += 193 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 194 ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, 195 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", 196 ah->cal_samples, i, ah->totalPowerMeasI[i], 197 ah->totalPowerMeasQ[i], 198 ah->totalIqCorrMeas[i]); 199 } 200 } 201 202 static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) 203 { 204 struct ath_common *common = ath9k_hw_common(ah); 205 u32 powerMeasQ, powerMeasI, iqCorrMeas; 206 u32 qCoffDenom, iCoffDenom; 207 int32_t qCoff, iCoff; 208 int iqCorrNeg, i; 209 static const u_int32_t offset_array[3] = { 210 AR_PHY_RX_IQCAL_CORR_B0, 211 AR_PHY_RX_IQCAL_CORR_B1, 212 AR_PHY_RX_IQCAL_CORR_B2, 213 }; 214 215 for (i = 0; i < numChains; i++) { 216 powerMeasI = ah->totalPowerMeasI[i]; 217 powerMeasQ = ah->totalPowerMeasQ[i]; 218 iqCorrMeas = ah->totalIqCorrMeas[i]; 219 220 ath_dbg(common, ATH_DBG_CALIBRATE, 221 "Starting IQ Cal and Correction for Chain %d\n", 222 i); 223 224 ath_dbg(common, ATH_DBG_CALIBRATE, 225 "Orignal: Chn %diq_corr_meas = 0x%08x\n", 226 i, ah->totalIqCorrMeas[i]); 227 228 iqCorrNeg = 0; 229 230 if (iqCorrMeas > 0x80000000) { 231 iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; 232 iqCorrNeg = 1; 233 } 234 235 ath_dbg(common, ATH_DBG_CALIBRATE, 236 "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); 237 ath_dbg(common, ATH_DBG_CALIBRATE, 238 "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); 239 ath_dbg(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", 240 iqCorrNeg); 241 242 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256; 243 qCoffDenom = powerMeasQ / 64; 244 245 if ((iCoffDenom != 0) && (qCoffDenom != 0)) { 246 iCoff = iqCorrMeas / iCoffDenom; 247 qCoff = powerMeasI / qCoffDenom - 64; 248 ath_dbg(common, ATH_DBG_CALIBRATE, 249 "Chn %d iCoff = 0x%08x\n", i, iCoff); 250 ath_dbg(common, ATH_DBG_CALIBRATE, 251 "Chn %d qCoff = 0x%08x\n", i, qCoff); 252 253 /* Force bounds on iCoff */ 254 if (iCoff >= 63) 255 iCoff = 63; 256 else if (iCoff <= -63) 257 iCoff = -63; 258 259 /* Negate iCoff if iqCorrNeg == 0 */ 260 if (iqCorrNeg == 0x0) 261 iCoff = -iCoff; 262 263 /* Force bounds on qCoff */ 264 if (qCoff >= 63) 265 qCoff = 63; 266 else if (qCoff <= -63) 267 qCoff = -63; 268 269 iCoff = iCoff & 0x7f; 270 qCoff = qCoff & 0x7f; 271 272 ath_dbg(common, ATH_DBG_CALIBRATE, 273 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", 274 i, iCoff, qCoff); 275 ath_dbg(common, ATH_DBG_CALIBRATE, 276 "Register offset (0x%04x) before update = 0x%x\n", 277 offset_array[i], 278 REG_READ(ah, offset_array[i])); 279 280 REG_RMW_FIELD(ah, offset_array[i], 281 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 282 iCoff); 283 REG_RMW_FIELD(ah, offset_array[i], 284 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 285 qCoff); 286 ath_dbg(common, ATH_DBG_CALIBRATE, 287 "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n", 288 offset_array[i], 289 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 290 REG_READ(ah, offset_array[i])); 291 ath_dbg(common, ATH_DBG_CALIBRATE, 292 "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n", 293 offset_array[i], 294 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 295 REG_READ(ah, offset_array[i])); 296 297 ath_dbg(common, ATH_DBG_CALIBRATE, 298 "IQ Cal and Correction done for Chain %d\n", i); 299 } 300 } 301 302 REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0, 303 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); 304 ath_dbg(common, ATH_DBG_CALIBRATE, 305 "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n", 306 (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), 307 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, 308 REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 309 } 310 311 static const struct ath9k_percal_data iq_cal_single_sample = { 312 IQ_MISMATCH_CAL, 313 MIN_CAL_SAMPLES, 314 PER_MAX_LOG_COUNT, 315 ar9003_hw_iqcal_collect, 316 ar9003_hw_iqcalibrate 317 }; 318 319 static void ar9003_hw_init_cal_settings(struct ath_hw *ah) 320 { 321 ah->iq_caldata.calData = &iq_cal_single_sample; 322 } 323 324 /* 325 * solve 4x4 linear equation used in loopback iq cal. 326 */ 327 static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah, 328 s32 sin_2phi_1, 329 s32 cos_2phi_1, 330 s32 sin_2phi_2, 331 s32 cos_2phi_2, 332 s32 mag_a0_d0, 333 s32 phs_a0_d0, 334 s32 mag_a1_d0, 335 s32 phs_a1_d0, 336 s32 solved_eq[]) 337 { 338 s32 f1 = cos_2phi_1 - cos_2phi_2, 339 f3 = sin_2phi_1 - sin_2phi_2, 340 f2; 341 s32 mag_tx, phs_tx, mag_rx, phs_rx; 342 const s32 result_shift = 1 << 15; 343 struct ath_common *common = ath9k_hw_common(ah); 344 345 f2 = (f1 * f1 + f3 * f3) / result_shift; 346 347 if (!f2) { 348 ath_dbg(common, ATH_DBG_CALIBRATE, "Divide by 0\n"); 349 return false; 350 } 351 352 /* mag mismatch, tx */ 353 mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0); 354 /* phs mismatch, tx */ 355 phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0); 356 357 mag_tx = (mag_tx / f2); 358 phs_tx = (phs_tx / f2); 359 360 /* mag mismatch, rx */ 361 mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / 362 result_shift; 363 /* phs mismatch, rx */ 364 phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / 365 result_shift; 366 367 solved_eq[0] = mag_tx; 368 solved_eq[1] = phs_tx; 369 solved_eq[2] = mag_rx; 370 solved_eq[3] = phs_rx; 371 372 return true; 373 } 374 375 static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im) 376 { 377 s32 abs_i = abs(in_re), 378 abs_q = abs(in_im), 379 max_abs, min_abs; 380 381 if (abs_i > abs_q) { 382 max_abs = abs_i; 383 min_abs = abs_q; 384 } else { 385 max_abs = abs_q; 386 min_abs = abs_i; 387 } 388 389 return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4); 390 } 391 392 #define DELPT 32 393 394 static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, 395 s32 chain_idx, 396 const s32 iq_res[], 397 s32 iqc_coeff[]) 398 { 399 s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0, 400 i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1, 401 i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0, 402 i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1; 403 s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1, 404 phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1, 405 sin_2phi_1, cos_2phi_1, 406 sin_2phi_2, cos_2phi_2; 407 s32 mag_tx, phs_tx, mag_rx, phs_rx; 408 s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx, 409 q_q_coff, q_i_coff; 410 const s32 res_scale = 1 << 15; 411 const s32 delpt_shift = 1 << 8; 412 s32 mag1, mag2; 413 struct ath_common *common = ath9k_hw_common(ah); 414 415 i2_m_q2_a0_d0 = iq_res[0] & 0xfff; 416 i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff; 417 iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8); 418 419 if (i2_m_q2_a0_d0 > 0x800) 420 i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1); 421 422 if (i2_p_q2_a0_d0 > 0x800) 423 i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1); 424 425 if (iq_corr_a0_d0 > 0x800) 426 iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1); 427 428 i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff; 429 i2_p_q2_a0_d1 = (iq_res[2] & 0xfff); 430 iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff; 431 432 if (i2_m_q2_a0_d1 > 0x800) 433 i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); 434 435 if (i2_p_q2_a0_d1 > 0x800) 436 i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1); 437 438 if (iq_corr_a0_d1 > 0x800) 439 iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); 440 441 i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8); 442 i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff; 443 iq_corr_a1_d0 = iq_res[4] & 0xfff; 444 445 if (i2_m_q2_a1_d0 > 0x800) 446 i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1); 447 448 if (i2_p_q2_a1_d0 > 0x800) 449 i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1); 450 451 if (iq_corr_a1_d0 > 0x800) 452 iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1); 453 454 i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff; 455 i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8); 456 iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff; 457 458 if (i2_m_q2_a1_d1 > 0x800) 459 i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1); 460 461 if (i2_p_q2_a1_d1 > 0x800) 462 i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1); 463 464 if (iq_corr_a1_d1 > 0x800) 465 iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1); 466 467 if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) || 468 (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) { 469 ath_dbg(common, ATH_DBG_CALIBRATE, 470 "Divide by 0:\n" 471 "a0_d0=%d\n" 472 "a0_d1=%d\n" 473 "a2_d0=%d\n" 474 "a1_d1=%d\n", 475 i2_p_q2_a0_d0, i2_p_q2_a0_d1, 476 i2_p_q2_a1_d0, i2_p_q2_a1_d1); 477 return false; 478 } 479 480 mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; 481 phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; 482 483 mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1; 484 phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1; 485 486 mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0; 487 phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0; 488 489 mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1; 490 phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1; 491 492 /* w/o analog phase shift */ 493 sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT); 494 /* w/o analog phase shift */ 495 cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT); 496 /* w/ analog phase shift */ 497 sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT); 498 /* w/ analog phase shift */ 499 cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT); 500 501 /* 502 * force sin^2 + cos^2 = 1; 503 * find magnitude by approximation 504 */ 505 mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1); 506 mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); 507 508 if ((mag1 == 0) || (mag2 == 0)) { 509 ath_dbg(common, ATH_DBG_CALIBRATE, 510 "Divide by 0: mag1=%d, mag2=%d\n", 511 mag1, mag2); 512 return false; 513 } 514 515 /* normalization sin and cos by mag */ 516 sin_2phi_1 = (sin_2phi_1 * res_scale / mag1); 517 cos_2phi_1 = (cos_2phi_1 * res_scale / mag1); 518 sin_2phi_2 = (sin_2phi_2 * res_scale / mag2); 519 cos_2phi_2 = (cos_2phi_2 * res_scale / mag2); 520 521 /* calculate IQ mismatch */ 522 if (!ar9003_hw_solve_iq_cal(ah, 523 sin_2phi_1, cos_2phi_1, 524 sin_2phi_2, cos_2phi_2, 525 mag_a0_d0, phs_a0_d0, 526 mag_a1_d0, 527 phs_a1_d0, solved_eq)) { 528 ath_dbg(common, ATH_DBG_CALIBRATE, 529 "Call to ar9003_hw_solve_iq_cal() failed.\n"); 530 return false; 531 } 532 533 mag_tx = solved_eq[0]; 534 phs_tx = solved_eq[1]; 535 mag_rx = solved_eq[2]; 536 phs_rx = solved_eq[3]; 537 538 ath_dbg(common, ATH_DBG_CALIBRATE, 539 "chain %d: mag mismatch=%d phase mismatch=%d\n", 540 chain_idx, mag_tx/res_scale, phs_tx/res_scale); 541 542 if (res_scale == mag_tx) { 543 ath_dbg(common, ATH_DBG_CALIBRATE, 544 "Divide by 0: mag_tx=%d, res_scale=%d\n", 545 mag_tx, res_scale); 546 return false; 547 } 548 549 /* calculate and quantize Tx IQ correction factor */ 550 mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx); 551 phs_corr_tx = -phs_tx; 552 553 q_q_coff = (mag_corr_tx * 128 / res_scale); 554 q_i_coff = (phs_corr_tx * 256 / res_scale); 555 556 ath_dbg(common, ATH_DBG_CALIBRATE, 557 "tx chain %d: mag corr=%d phase corr=%d\n", 558 chain_idx, q_q_coff, q_i_coff); 559 560 if (q_i_coff < -63) 561 q_i_coff = -63; 562 if (q_i_coff > 63) 563 q_i_coff = 63; 564 if (q_q_coff < -63) 565 q_q_coff = -63; 566 if (q_q_coff > 63) 567 q_q_coff = 63; 568 569 iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; 570 571 ath_dbg(common, ATH_DBG_CALIBRATE, 572 "tx chain %d: iq corr coeff=%x\n", 573 chain_idx, iqc_coeff[0]); 574 575 if (-mag_rx == res_scale) { 576 ath_dbg(common, ATH_DBG_CALIBRATE, 577 "Divide by 0: mag_rx=%d, res_scale=%d\n", 578 mag_rx, res_scale); 579 return false; 580 } 581 582 /* calculate and quantize Rx IQ correction factors */ 583 mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx); 584 phs_corr_rx = -phs_rx; 585 586 q_q_coff = (mag_corr_rx * 128 / res_scale); 587 q_i_coff = (phs_corr_rx * 256 / res_scale); 588 589 ath_dbg(common, ATH_DBG_CALIBRATE, 590 "rx chain %d: mag corr=%d phase corr=%d\n", 591 chain_idx, q_q_coff, q_i_coff); 592 593 if (q_i_coff < -63) 594 q_i_coff = -63; 595 if (q_i_coff > 63) 596 q_i_coff = 63; 597 if (q_q_coff < -63) 598 q_q_coff = -63; 599 if (q_q_coff > 63) 600 q_q_coff = 63; 601 602 iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; 603 604 ath_dbg(common, ATH_DBG_CALIBRATE, 605 "rx chain %d: iq corr coeff=%x\n", 606 chain_idx, iqc_coeff[1]); 607 608 return true; 609 } 610 611 static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) 612 { 613 int diff[MPASS]; 614 615 diff[0] = abs(mp_coeff[0] - mp_coeff[1]); 616 diff[1] = abs(mp_coeff[1] - mp_coeff[2]); 617 diff[2] = abs(mp_coeff[2] - mp_coeff[0]); 618 619 if (diff[0] > MAX_DIFFERENCE && 620 diff[1] > MAX_DIFFERENCE && 621 diff[2] > MAX_DIFFERENCE) 622 return false; 623 624 if (diff[0] <= diff[1] && diff[0] <= diff[2]) 625 *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2; 626 else if (diff[1] <= diff[2]) 627 *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2; 628 else 629 *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2; 630 631 return true; 632 } 633 634 static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, 635 u8 num_chains, 636 struct coeff *coeff) 637 { 638 struct ath_common *common = ath9k_hw_common(ah); 639 int i, im, nmeasurement; 640 int magnitude, phase; 641 u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; 642 643 memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); 644 for (i = 0; i < MAX_MEASUREMENT / 2; i++) { 645 tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] = 646 AR_PHY_TX_IQCAL_CORR_COEFF_B0(i); 647 if (!AR_SREV_9485(ah)) { 648 tx_corr_coeff[i * 2][1] = 649 tx_corr_coeff[(i * 2) + 1][1] = 650 AR_PHY_TX_IQCAL_CORR_COEFF_B1(i); 651 652 tx_corr_coeff[i * 2][2] = 653 tx_corr_coeff[(i * 2) + 1][2] = 654 AR_PHY_TX_IQCAL_CORR_COEFF_B2(i); 655 } 656 } 657 658 /* Load the average of 2 passes */ 659 for (i = 0; i < num_chains; i++) { 660 if (AR_SREV_9485(ah)) 661 nmeasurement = REG_READ_FIELD(ah, 662 AR_PHY_TX_IQCAL_STATUS_B0_9485, 663 AR_PHY_CALIBRATED_GAINS_0); 664 else 665 nmeasurement = REG_READ_FIELD(ah, 666 AR_PHY_TX_IQCAL_STATUS_B0, 667 AR_PHY_CALIBRATED_GAINS_0); 668 669 if (nmeasurement > MAX_MEASUREMENT) 670 nmeasurement = MAX_MEASUREMENT; 671 672 for (im = 0; im < nmeasurement; im++) { 673 /* 674 * Determine which 2 passes are closest and compute avg 675 * magnitude 676 */ 677 if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im], 678 &magnitude)) 679 goto disable_txiqcal; 680 681 /* 682 * Determine which 2 passes are closest and compute avg 683 * phase 684 */ 685 if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im], 686 &phase)) 687 goto disable_txiqcal; 688 689 coeff->iqc_coeff[0] = (magnitude & 0x7f) | 690 ((phase & 0x7f) << 7); 691 692 if ((im % 2) == 0) 693 REG_RMW_FIELD(ah, tx_corr_coeff[im][i], 694 AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 695 coeff->iqc_coeff[0]); 696 else 697 REG_RMW_FIELD(ah, tx_corr_coeff[im][i], 698 AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 699 coeff->iqc_coeff[0]); 700 } 701 } 702 703 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 704 AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 705 REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 706 AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 707 708 return; 709 710 disable_txiqcal: 711 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 712 AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0); 713 REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 714 AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0); 715 716 ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); 717 } 718 719 static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) 720 { 721 struct ath_common *common = ath9k_hw_common(ah); 722 static const u32 txiqcal_status[AR9300_MAX_CHAINS] = { 723 AR_PHY_TX_IQCAL_STATUS_B0, 724 AR_PHY_TX_IQCAL_STATUS_B1, 725 AR_PHY_TX_IQCAL_STATUS_B2, 726 }; 727 static const u32 chan_info_tab[] = { 728 AR_PHY_CHAN_INFO_TAB_0, 729 AR_PHY_CHAN_INFO_TAB_1, 730 AR_PHY_CHAN_INFO_TAB_2, 731 }; 732 struct coeff coeff; 733 s32 iq_res[6]; 734 s32 i, j, ip, im, nmeasurement; 735 u8 nchains = get_streams(common->tx_chainmask); 736 737 for (ip = 0; ip < MPASS; ip++) { 738 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, 739 AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, 740 DELPT); 741 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, 742 AR_PHY_TX_IQCAL_START_DO_CAL, 743 AR_PHY_TX_IQCAL_START_DO_CAL); 744 745 if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, 746 AR_PHY_TX_IQCAL_START_DO_CAL, 747 0, AH_WAIT_TIMEOUT)) { 748 ath_dbg(common, ATH_DBG_CALIBRATE, 749 "Tx IQ Cal not complete.\n"); 750 goto TX_IQ_CAL_FAILED; 751 } 752 753 nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0, 754 AR_PHY_CALIBRATED_GAINS_0); 755 if (nmeasurement > MAX_MEASUREMENT) 756 nmeasurement = MAX_MEASUREMENT; 757 758 for (i = 0; i < nchains; i++) { 759 ath_dbg(common, ATH_DBG_CALIBRATE, 760 "Doing Tx IQ Cal for chain %d.\n", i); 761 for (im = 0; im < nmeasurement; im++) { 762 if (REG_READ(ah, txiqcal_status[i]) & 763 AR_PHY_TX_IQCAL_STATUS_FAILED) { 764 ath_dbg(common, ATH_DBG_CALIBRATE, 765 "Tx IQ Cal failed for chain %d.\n", i); 766 goto TX_IQ_CAL_FAILED; 767 } 768 769 for (j = 0; j < 3; j++) { 770 u8 idx = 2 * j, 771 offset = 4 * (3 * im + j); 772 773 REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, 774 AR_PHY_CHAN_INFO_TAB_S2_READ, 775 0); 776 777 /* 32 bits */ 778 iq_res[idx] = REG_READ(ah, 779 chan_info_tab[i] + 780 offset); 781 782 REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, 783 AR_PHY_CHAN_INFO_TAB_S2_READ, 784 1); 785 786 /* 16 bits */ 787 iq_res[idx+1] = 0xffff & REG_READ(ah, 788 chan_info_tab[i] + 789 offset); 790 791 ath_dbg(common, ATH_DBG_CALIBRATE, 792 "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", 793 idx, iq_res[idx], idx+1, iq_res[idx+1]); 794 } 795 796 if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, 797 coeff.iqc_coeff)) { 798 ath_dbg(common, ATH_DBG_CALIBRATE, 799 "Failed in calculation of IQ correction.\n"); 800 goto TX_IQ_CAL_FAILED; 801 } 802 coeff.mag_coeff[i][im][ip] = 803 coeff.iqc_coeff[0] & 0x7f; 804 coeff.phs_coeff[i][im][ip] = 805 (coeff.iqc_coeff[0] >> 7) & 0x7f; 806 807 if (coeff.mag_coeff[i][im][ip] > 63) 808 coeff.mag_coeff[i][im][ip] -= 128; 809 if (coeff.phs_coeff[i][im][ip] > 63) 810 coeff.phs_coeff[i][im][ip] -= 128; 811 812 } 813 } 814 } 815 816 ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff); 817 818 return; 819 820 TX_IQ_CAL_FAILED: 821 ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); 822 } 823 824 static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) 825 { 826 u8 tx_gain_forced; 827 828 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485, 829 AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); 830 tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 831 AR_PHY_TXGAIN_FORCE); 832 if (tx_gain_forced) 833 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 834 AR_PHY_TXGAIN_FORCE, 0); 835 836 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485, 837 AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1); 838 } 839 840 static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) 841 { 842 struct ath_common *common = ath9k_hw_common(ah); 843 const u32 txiqcal_status[AR9300_MAX_CHAINS] = { 844 AR_PHY_TX_IQCAL_STATUS_B0_9485, 845 AR_PHY_TX_IQCAL_STATUS_B1, 846 AR_PHY_TX_IQCAL_STATUS_B2, 847 }; 848 const u_int32_t chan_info_tab[] = { 849 AR_PHY_CHAN_INFO_TAB_0, 850 AR_PHY_CHAN_INFO_TAB_1, 851 AR_PHY_CHAN_INFO_TAB_2, 852 }; 853 struct coeff coeff; 854 s32 iq_res[6]; 855 u8 num_chains = 0; 856 int i, ip, im, j; 857 int nmeasurement; 858 859 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 860 if (ah->txchainmask & (1 << i)) 861 num_chains++; 862 } 863 864 for (ip = 0; ip < MPASS; ip++) { 865 for (i = 0; i < num_chains; i++) { 866 nmeasurement = REG_READ_FIELD(ah, 867 AR_PHY_TX_IQCAL_STATUS_B0_9485, 868 AR_PHY_CALIBRATED_GAINS_0); 869 if (nmeasurement > MAX_MEASUREMENT) 870 nmeasurement = MAX_MEASUREMENT; 871 872 for (im = 0; im < nmeasurement; im++) { 873 ath_dbg(common, ATH_DBG_CALIBRATE, 874 "Doing Tx IQ Cal for chain %d.\n", i); 875 876 if (REG_READ(ah, txiqcal_status[i]) & 877 AR_PHY_TX_IQCAL_STATUS_FAILED) { 878 ath_dbg(common, ATH_DBG_CALIBRATE, 879 "Tx IQ Cal failed for chain %d.\n", i); 880 goto tx_iqcal_fail; 881 } 882 883 for (j = 0; j < 3; j++) { 884 u32 idx = 2 * j, offset = 4 * (3 * im + j); 885 886 REG_RMW_FIELD(ah, 887 AR_PHY_CHAN_INFO_MEMORY, 888 AR_PHY_CHAN_INFO_TAB_S2_READ, 889 0); 890 891 /* 32 bits */ 892 iq_res[idx] = REG_READ(ah, 893 chan_info_tab[i] + 894 offset); 895 896 REG_RMW_FIELD(ah, 897 AR_PHY_CHAN_INFO_MEMORY, 898 AR_PHY_CHAN_INFO_TAB_S2_READ, 899 1); 900 901 /* 16 bits */ 902 iq_res[idx + 1] = 0xffff & REG_READ(ah, 903 chan_info_tab[i] + offset); 904 905 ath_dbg(common, ATH_DBG_CALIBRATE, 906 "IQ RES[%d]=0x%x" 907 "IQ_RES[%d]=0x%x\n", 908 idx, iq_res[idx], idx + 1, 909 iq_res[idx + 1]); 910 } 911 912 if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, 913 coeff.iqc_coeff)) { 914 ath_dbg(common, ATH_DBG_CALIBRATE, 915 "Failed in calculation of IQ correction.\n"); 916 goto tx_iqcal_fail; 917 } 918 919 coeff.mag_coeff[i][im][ip] = 920 coeff.iqc_coeff[0] & 0x7f; 921 coeff.phs_coeff[i][im][ip] = 922 (coeff.iqc_coeff[0] >> 7) & 0x7f; 923 924 if (coeff.mag_coeff[i][im][ip] > 63) 925 coeff.mag_coeff[i][im][ip] -= 128; 926 if (coeff.phs_coeff[i][im][ip] > 63) 927 coeff.phs_coeff[i][im][ip] -= 128; 928 } 929 } 930 } 931 ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff); 932 933 return; 934 935 tx_iqcal_fail: 936 ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); 937 return; 938 } 939 static bool ar9003_hw_init_cal(struct ath_hw *ah, 940 struct ath9k_channel *chan) 941 { 942 struct ath_common *common = ath9k_hw_common(ah); 943 int val; 944 945 val = REG_READ(ah, AR_ENT_OTP); 946 ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); 947 948 if (AR_SREV_9485(ah)) 949 ar9003_hw_set_chain_masks(ah, 0x1, 0x1); 950 else if (val & AR_ENT_OTP_CHAIN2_DISABLE) 951 ar9003_hw_set_chain_masks(ah, 0x3, 0x3); 952 else 953 /* 954 * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain 955 * mode before running AGC/TxIQ cals 956 */ 957 ar9003_hw_set_chain_masks(ah, 0x7, 0x7); 958 959 /* Do Tx IQ Calibration */ 960 if (AR_SREV_9485(ah)) 961 ar9003_hw_tx_iq_cal_run(ah); 962 else 963 ar9003_hw_tx_iq_cal(ah); 964 965 REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); 966 udelay(5); 967 REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 968 969 /* Calibrate the AGC */ 970 REG_WRITE(ah, AR_PHY_AGC_CONTROL, 971 REG_READ(ah, AR_PHY_AGC_CONTROL) | 972 AR_PHY_AGC_CONTROL_CAL); 973 974 /* Poll for offset calibration complete */ 975 if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 976 0, AH_WAIT_TIMEOUT)) { 977 ath_dbg(common, ATH_DBG_CALIBRATE, 978 "offset calibration failed to complete in 1ms; noisy environment?\n"); 979 return false; 980 } 981 982 if (AR_SREV_9485(ah)) 983 ar9003_hw_tx_iq_cal_post_proc(ah); 984 985 /* Revert chainmasks to their original values before NF cal */ 986 ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); 987 988 ath9k_hw_start_nfcal(ah, true); 989 990 /* Initialize list pointers */ 991 ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; 992 ah->supp_cals = IQ_MISMATCH_CAL; 993 994 if (ah->supp_cals & IQ_MISMATCH_CAL) { 995 INIT_CAL(&ah->iq_caldata); 996 INSERT_CAL(ah, &ah->iq_caldata); 997 ath_dbg(common, ATH_DBG_CALIBRATE, 998 "enabling IQ Calibration.\n"); 999 } 1000 1001 if (ah->supp_cals & TEMP_COMP_CAL) { 1002 INIT_CAL(&ah->tempCompCalData); 1003 INSERT_CAL(ah, &ah->tempCompCalData); 1004 ath_dbg(common, ATH_DBG_CALIBRATE, 1005 "enabling Temperature Compensation Calibration.\n"); 1006 } 1007 1008 /* Initialize current pointer to first element in list */ 1009 ah->cal_list_curr = ah->cal_list; 1010 1011 if (ah->cal_list_curr) 1012 ath9k_hw_reset_calibration(ah, ah->cal_list_curr); 1013 1014 if (ah->caldata) 1015 ah->caldata->CalValid = 0; 1016 1017 return true; 1018 } 1019 1020 void ar9003_hw_attach_calib_ops(struct ath_hw *ah) 1021 { 1022 struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); 1023 struct ath_hw_ops *ops = ath9k_hw_ops(ah); 1024 1025 priv_ops->init_cal_settings = ar9003_hw_init_cal_settings; 1026 priv_ops->init_cal = ar9003_hw_init_cal; 1027 priv_ops->setup_calibration = ar9003_hw_setup_calibration; 1028 1029 ops->calibrate = ar9003_hw_calibrate; 1030 } 1031