23 #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
24 #define MAX_MAG_DELTA 11
25 #define MAX_PHS_DELTA 10
38 static void ar9003_hw_setup_calibration(
struct ath_hw *
ah,
44 switch (currCal->
calData->calType) {
56 "starting IQ Mismatch Calibration\n");
68 "starting Temperature Compensation Calibration\n");
78 static bool ar9003_hw_per_calibration(
struct ath_hw *
ah,
85 bool iscaldone =
false;
94 currCal->
calData->calCollect(ah);
98 currCal->
calData->calNumSamples) {
99 unsigned int i, numChains = 0;
101 if (rxchainmask & (1 << i))
108 currCal->
calData->calPostProc(ah, numChains);
119 ar9003_hw_setup_calibration(ah, currCal);
130 static bool ar9003_hw_calibrate(
struct ath_hw *ah,
135 bool iscaldone =
true;
150 iscaldone = ar9003_hw_per_calibration(ah, chan,
151 rxchainmask, currCal);
181 static void ar9003_hw_iqcal_collect(
struct ath_hw *ah)
188 ah->totalPowerMeasI[
i] +=
190 ah->totalPowerMeasQ[
i] +=
192 ah->totalIqCorrMeas[
i] +=
194 ath_dbg(ath9k_hw_common(ah), CALIBRATE,
195 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
197 ah->totalPowerMeasQ[i],
198 ah->totalIqCorrMeas[i]);
203 static void ar9003_hw_iqcalibrate(
struct ath_hw *ah,
u8 numChains)
206 u32 powerMeasQ, powerMeasI, iqCorrMeas;
207 u32 qCoffDenom, iCoffDenom;
210 static const u_int32_t offset_array[3] = {
216 for (i = 0; i < numChains; i++) {
217 powerMeasI = ah->totalPowerMeasI[
i];
218 powerMeasQ = ah->totalPowerMeasQ[
i];
219 iqCorrMeas = ah->totalIqCorrMeas[
i];
222 "Starting IQ Cal and Correction for Chain %d\n", i);
225 "Original: Chn %d iq_corr_meas = 0x%08x\n",
226 i, ah->totalIqCorrMeas[i]);
230 if (iqCorrMeas > 0x80000000) {
231 iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
235 ath_dbg(common, CALIBRATE,
"Chn %d pwr_meas_i = 0x%08x\n",
237 ath_dbg(common, CALIBRATE,
"Chn %d pwr_meas_q = 0x%08x\n",
239 ath_dbg(common, CALIBRATE,
"iqCorrNeg is 0x%08x\n", iqCorrNeg);
241 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
242 qCoffDenom = powerMeasQ / 64;
244 if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
245 iCoff = iqCorrMeas / iCoffDenom;
246 qCoff = powerMeasI / qCoffDenom - 64;
247 ath_dbg(common, CALIBRATE,
"Chn %d iCoff = 0x%08x\n",
249 ath_dbg(common, CALIBRATE,
"Chn %d qCoff = 0x%08x\n",
255 else if (iCoff <= -63)
259 if (iqCorrNeg == 0x0)
265 else if (qCoff <= -63)
268 iCoff = iCoff & 0x7f;
269 qCoff = qCoff & 0x7f;
272 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
275 "Register offset (0x%04x) before update = 0x%x\n",
286 "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
291 "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
297 "IQ Cal and Correction done for Chain %d\n", i);
304 "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
314 ar9003_hw_iqcal_collect,
315 ar9003_hw_iqcalibrate
318 static void ar9003_hw_init_cal_settings(
struct ath_hw *ah)
320 ah->
iq_caldata.calData = &iq_cal_single_sample;
326 static bool ar9003_hw_solve_iq_cal(
struct ath_hw *ah,
337 s32 f1 = cos_2phi_1 - cos_2phi_2,
338 f3 = sin_2phi_1 - sin_2phi_2,
340 s32 mag_tx, phs_tx, mag_rx, phs_rx;
341 const s32 result_shift = 1 << 15;
342 struct ath_common *common = ath9k_hw_common(ah);
344 f2 = (f1 * f1 + f3 *
f3) / result_shift;
347 ath_dbg(common, CALIBRATE,
"Divide by 0\n");
352 mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
354 phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
356 mag_tx = (mag_tx /
f2);
357 phs_tx = (phs_tx /
f2);
360 mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
363 phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
366 solved_eq[0] = mag_tx;
367 solved_eq[1] = phs_tx;
368 solved_eq[2] = mag_rx;
369 solved_eq[3] = phs_rx;
374 static s32 ar9003_hw_find_mag_approx(
struct ath_hw *ah,
s32 in_re,
s32 in_im)
388 return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
393 static bool ar9003_hw_calc_iq_corr(
struct ath_hw *ah,
398 s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
399 i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
400 i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
401 i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
402 s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
403 phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
404 sin_2phi_1, cos_2phi_1,
405 sin_2phi_2, cos_2phi_2;
406 s32 mag_tx, phs_tx, mag_rx, phs_rx;
407 s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
409 const s32 res_scale = 1 << 15;
410 const s32 delpt_shift = 1 << 8;
412 struct ath_common *common = ath9k_hw_common(ah);
414 i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
415 i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
416 iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
418 if (i2_m_q2_a0_d0 > 0x800)
419 i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
421 if (i2_p_q2_a0_d0 > 0x800)
422 i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
424 if (iq_corr_a0_d0 > 0x800)
425 iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
427 i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
428 i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
429 iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
431 if (i2_m_q2_a0_d1 > 0x800)
432 i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
434 if (i2_p_q2_a0_d1 > 0x800)
435 i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1);
437 if (iq_corr_a0_d1 > 0x800)
438 iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
440 i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
441 i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
442 iq_corr_a1_d0 = iq_res[4] & 0xfff;
444 if (i2_m_q2_a1_d0 > 0x800)
445 i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
447 if (i2_p_q2_a1_d0 > 0x800)
448 i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
450 if (iq_corr_a1_d0 > 0x800)
451 iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
453 i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
454 i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
455 iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
457 if (i2_m_q2_a1_d1 > 0x800)
458 i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
460 if (i2_p_q2_a1_d1 > 0x800)
461 i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
463 if (iq_corr_a1_d1 > 0x800)
464 iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
466 if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
467 (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
474 i2_p_q2_a0_d0, i2_p_q2_a0_d1,
475 i2_p_q2_a1_d0, i2_p_q2_a1_d1);
479 mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
480 phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
482 mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
483 phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
485 mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
486 phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
488 mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
489 phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
492 sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) /
DELPT);
494 cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) /
DELPT);
496 sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) /
DELPT);
498 cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) /
DELPT);
504 mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
505 mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
507 if ((mag1 == 0) || (mag2 == 0)) {
508 ath_dbg(common, CALIBRATE,
"Divide by 0: mag1=%d, mag2=%d\n",
514 sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
515 cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
516 sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
517 cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
520 if (!ar9003_hw_solve_iq_cal(ah,
521 sin_2phi_1, cos_2phi_1,
522 sin_2phi_2, cos_2phi_2,
523 mag_a0_d0, phs_a0_d0,
525 phs_a1_d0, solved_eq)) {
527 "Call to ar9003_hw_solve_iq_cal() failed\n");
531 mag_tx = solved_eq[0];
532 phs_tx = solved_eq[1];
533 mag_rx = solved_eq[2];
534 phs_rx = solved_eq[3];
537 "chain %d: mag mismatch=%d phase mismatch=%d\n",
538 chain_idx, mag_tx/res_scale, phs_tx/res_scale);
540 if (res_scale == mag_tx) {
542 "Divide by 0: mag_tx=%d, res_scale=%d\n",
548 mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
549 phs_corr_tx = -phs_tx;
551 q_q_coff = (mag_corr_tx * 128 / res_scale);
552 q_i_coff = (phs_corr_tx * 256 / res_scale);
554 ath_dbg(common, CALIBRATE,
"tx chain %d: mag corr=%d phase corr=%d\n",
555 chain_idx, q_q_coff, q_i_coff);
566 iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
568 ath_dbg(common, CALIBRATE,
"tx chain %d: iq corr coeff=%x\n",
569 chain_idx, iqc_coeff[0]);
571 if (-mag_rx == res_scale) {
573 "Divide by 0: mag_rx=%d, res_scale=%d\n",
579 mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
580 phs_corr_rx = -phs_rx;
582 q_q_coff = (mag_corr_rx * 128 / res_scale);
583 q_i_coff = (phs_corr_rx * 256 / res_scale);
585 ath_dbg(common, CALIBRATE,
"rx chain %d: mag corr=%d phase corr=%d\n",
586 chain_idx, q_q_coff, q_i_coff);
597 iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
599 ath_dbg(common, CALIBRATE,
"rx chain %d: iq corr coeff=%x\n",
600 chain_idx, iqc_coeff[1]);
605 static void ar9003_hw_detect_outlier(
int *mp_coeff,
int nmeasurement,
609 int mp_min = 63, min_idx = 0;
610 int mp_avg = 0,
i, outlier_idx = 0, mp_count = 0;
613 for (i = 0; i < nmeasurement; i++) {
614 if (mp_coeff[i] > mp_max) {
615 mp_max = mp_coeff[
i];
617 }
else if (mp_coeff[i] < mp_min) {
618 mp_min = mp_coeff[
i];
624 for (i = 0; i < nmeasurement; i++) {
625 if ((
abs(mp_coeff[i]) <
abs(mp_max)) ||
626 (
abs(mp_coeff[i]) <
abs(mp_min))) {
627 mp_avg += mp_coeff[
i];
639 mp_avg = mp_coeff[nmeasurement - 1];
642 if (
abs(mp_max - mp_min) > max_delta) {
643 if (
abs(mp_max - mp_avg) >
abs(mp_min - mp_avg))
646 outlier_idx = min_idx;
648 mp_coeff[outlier_idx] = mp_avg;
652 static void ar9003_hw_tx_iqcal_load_avg_2_passes(
struct ath_hw *ah,
656 int i, im, nmeasurement;
660 memset(tx_corr_coeff, 0,
sizeof(tx_corr_coeff));
662 tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
665 tx_corr_coeff[i * 2][1] =
666 tx_corr_coeff[(i * 2) + 1][1] =
669 tx_corr_coeff[i * 2][2] =
670 tx_corr_coeff[(i * 2) + 1][2] =
687 if (nmeasurement > 1) {
689 ar9003_hw_detect_outlier(coeff->
mag_coeff[i],
693 ar9003_hw_detect_outlier(coeff->
phs_coeff[i],
697 for (im = 0; im < nmeasurement; im++) {
730 static bool ar9003_hw_tx_iq_cal_run(
struct ath_hw *ah)
732 struct ath_common *common = ath9k_hw_common(ah);
747 ath_dbg(common, CALIBRATE,
"Tx IQ Cal is not completed\n");
753 static void ar9003_hw_tx_iq_cal_post_proc(
struct ath_hw *ah,
bool is_reusable)
755 struct ath_common *common = ath9k_hw_common(ah);
781 for (im = 0; im < nmeasurement; im++) {
783 "Doing Tx IQ Cal for chain %d\n", i);
785 if (
REG_READ(ah, txiqcal_status[i]) &
788 "Tx IQ Cal failed for chain %d\n", i);
792 for (j = 0; j < 3; j++) {
811 iq_res[idx + 1] = 0xffff &
REG_READ(ah,
812 chan_info_tab[i] + offset);
815 "IQ_RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
816 idx, iq_res[idx], idx + 1,
820 if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
823 "Failed in calculation of IQ correction\n");
837 ar9003_hw_tx_iqcal_load_avg_2_passes(ah, &coeff, is_reusable);
842 ath_dbg(common, CALIBRATE,
"Tx IQ Cal failed\n");
846 static void ar9003_hw_tx_iq_cal_reload(
struct ath_hw *ah)
852 memset(tx_corr_coeff, 0,
sizeof(tx_corr_coeff));
854 tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
857 tx_corr_coeff[i * 2][1] =
858 tx_corr_coeff[(i * 2) + 1][1] =
861 tx_corr_coeff[i * 2][2] =
862 tx_corr_coeff[(i * 2) + 1][2] =
889 static bool ar9003_hw_init_cal(
struct ath_hw *ah,
892 struct ath_common *common = ath9k_hw_common(ah);
894 bool txiqcal_done =
false, txclcal_done =
false;
895 bool is_reusable =
true,
status =
true;
896 bool run_rtt_cal =
false, run_agc_cal;
911 ath_dbg(common, CALIBRATE,
"RTT calibration to be done\n");
914 run_agc_cal = run_rtt_cal;
922 if (rtt && !run_rtt_cal) {
924 agc_supp_cals &= agc_ctrl;
961 txiqcal_done = run_agc_cal =
true;
966 if (ath9k_hw_mci_is_enabled(ah) &&
IS_CHAN_2GHZ(chan) && run_agc_cal)
970 txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
989 if (ath9k_hw_mci_is_enabled(ah) &&
IS_CHAN_2GHZ(chan) && run_agc_cal)
992 if (rtt && !run_rtt_cal) {
993 agc_ctrl |= agc_supp_cals;
1002 "offset calibration failed to complete in 1ms; noisy environment?\n");
1007 ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
1009 ar9003_hw_tx_iq_cal_reload(ah);
1011 #define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
1023 }
else if (is_reusable && txclcal_done) {
1037 if (run_rtt_cal && caldata) {
1039 if (!ath9k_hw_rfbus_req(ah))
1041 "Could not stop baseband\n");
1045 ath9k_hw_rfbus_done(ah);
1058 ath_dbg(common, CALIBRATE,
"enabling IQ Calibration\n");
1065 "enabling Temperature Compensation Calibration\n");
1086 priv_ops->
init_cal = ar9003_hw_init_cal;