26 #define MAX_MEASUREMENT 8 27 #define MAX_MAG_DELTA 11 28 #define MAX_PHS_DELTA 10 57 "starting IQ Mismatch Calibration\n");
69 "starting Temperature Compensation Calibration\n");
98 if (
ah->cal_samples >=
100 unsigned int i, numChains = 0;
102 if (rxchainmask & (1 << i))
152 rxchainmask, currCal);
154 ah->cal_list_curr = currCal = currCal->
calNext;
191 if (
ah->txchainmask &
BIT(i)) {
192 ah->totalPowerMeasI[i] +=
194 ah->totalPowerMeasQ[i] +=
196 ah->totalIqCorrMeas[i] +=
199 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
200 ah->cal_samples, i,
ah->totalPowerMeasI[i],
201 ah->totalPowerMeasQ[i],
202 ah->totalIqCorrMeas[i]);
209 u32 powerMeasQ, powerMeasI, iqCorrMeas;
210 u32 qCoffDenom, iCoffDenom;
213 static const uint32_t offset_array[3] = {
219 for (i = 0; i < numChains; i++) {
220 powerMeasI =
ah->totalPowerMeasI[i];
221 powerMeasQ =
ah->totalPowerMeasQ[i];
222 iqCorrMeas =
ah->totalIqCorrMeas[i];
225 "Starting IQ Cal and Correction for Chain %d\n",
229 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
230 i,
ah->totalIqCorrMeas[i]);
234 if (iqCorrMeas > 0x80000000) {
235 iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
240 "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
242 "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
243 DBG2(
"ath9k: iqCorrNeg is 0x%08x\n",
246 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
247 qCoffDenom = powerMeasQ / 64;
249 if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
250 iCoff = iqCorrMeas / iCoffDenom;
251 qCoff = powerMeasI / qCoffDenom - 64;
253 "Chn %d iCoff = 0x%08x\n", i, iCoff);
255 "Chn %d qCoff = 0x%08x\n", i, qCoff);
260 else if (iCoff <= -63)
264 if (iqCorrNeg == 0x0)
270 else if (qCoff <= -63)
273 iCoff = iCoff & 0x7f;
274 qCoff = qCoff & 0x7f;
277 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
280 "Register offset (0x%04x) before update = 0x%x\n",
291 "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
296 "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
302 "IQ Cal and Correction done for Chain %d\n", i);
309 "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
342 s32 f1 = cos_2phi_1 - cos_2phi_2,
343 f3 = sin_2phi_1 - sin_2phi_2,
345 s32 mag_tx, phs_tx, mag_rx, phs_rx;
346 const s32 result_shift = 1 << 15;
348 f2 = (f1 * f1 + f3 * f3) / result_shift;
351 DBG(
"ath9k: Divide by 0\n");
356 mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
358 phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
360 mag_tx = (mag_tx / f2);
361 phs_tx = (phs_tx / f2);
364 mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
367 phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
370 solved_eq[0] = mag_tx;
371 solved_eq[1] = phs_tx;
372 solved_eq[2] = mag_rx;
373 solved_eq[3] = phs_rx;
392 return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
402 s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
403 i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
404 i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
405 i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
406 s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
407 phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
408 sin_2phi_1, cos_2phi_1,
409 sin_2phi_2, cos_2phi_2;
410 s32 mag_tx, phs_tx, mag_rx, phs_rx;
411 s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
413 const s32 res_scale = 1 << 15;
414 const s32 delpt_shift = 1 << 8;
417 i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
418 i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
419 iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
421 if (i2_m_q2_a0_d0 > 0x800)
422 i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
424 if (i2_p_q2_a0_d0 > 0x800)
425 i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
427 if (iq_corr_a0_d0 > 0x800)
428 iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
430 i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
431 i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
432 iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
434 if (i2_m_q2_a0_d1 > 0x800)
435 i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
437 if (i2_p_q2_a0_d1 > 0x800)
438 i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1);
440 if (iq_corr_a0_d1 > 0x800)
441 iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
443 i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
444 i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
445 iq_corr_a1_d0 = iq_res[4] & 0xfff;
447 if (i2_m_q2_a1_d0 > 0x800)
448 i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
450 if (i2_p_q2_a1_d0 > 0x800)
451 i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
453 if (iq_corr_a1_d0 > 0x800)
454 iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
456 i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
457 i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
458 iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
460 if (i2_m_q2_a1_d1 > 0x800)
461 i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
463 if (i2_p_q2_a1_d1 > 0x800)
464 i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
466 if (iq_corr_a1_d1 > 0x800)
467 iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
469 if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
470 (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
477 i2_p_q2_a0_d0, i2_p_q2_a0_d1,
478 i2_p_q2_a1_d0, i2_p_q2_a1_d1);
482 mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
483 phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
485 mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
486 phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
488 mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
489 phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
491 mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
492 phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
495 sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) /
DELPT);
497 cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) /
DELPT);
499 sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) /
DELPT);
501 cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) /
DELPT);
510 if ((mag1 == 0) || (mag2 == 0)) {
512 "Divide by 0: mag1=%d, mag2=%d\n",
518 sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
519 cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
520 sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
521 cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
525 sin_2phi_1, cos_2phi_1,
526 sin_2phi_2, cos_2phi_2,
527 mag_a0_d0, phs_a0_d0,
529 phs_a1_d0, solved_eq)) {
531 "Call to ar9003_hw_solve_iq_cal() failed.\n");
535 mag_tx = solved_eq[0];
536 phs_tx = solved_eq[1];
537 mag_rx = solved_eq[2];
538 phs_rx = solved_eq[3];
541 "chain %d: mag mismatch=%d phase mismatch=%d\n",
542 chain_idx, mag_tx/res_scale, phs_tx/res_scale);
544 if (res_scale == mag_tx) {
546 "Divide by 0: mag_tx=%d, res_scale=%d\n",
552 mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
553 phs_corr_tx = -phs_tx;
555 q_q_coff = (mag_corr_tx * 128 / res_scale);
556 q_i_coff = (phs_corr_tx * 256 / res_scale);
559 "tx chain %d: mag corr=%d phase corr=%d\n",
560 chain_idx, q_q_coff, q_i_coff);
571 iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
574 "tx chain %d: iq corr coeff=%x\n",
575 chain_idx, iqc_coeff[0]);
577 if (-mag_rx == res_scale) {
579 "Divide by 0: mag_rx=%d, res_scale=%d\n",
585 mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
586 phs_corr_rx = -phs_rx;
588 q_q_coff = (mag_corr_rx * 128 / res_scale);
589 q_i_coff = (phs_corr_rx * 256 / res_scale);
592 "rx chain %d: mag corr=%d phase corr=%d\n",
593 chain_idx, q_q_coff, q_i_coff);
604 iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
607 "rx chain %d: iq corr coeff=%x\n",
608 chain_idx, iqc_coeff[1]);
616 int mp_max = -64, max_idx = 0;
617 int mp_min = 63, min_idx = 0;
618 int mp_avg = 0, i, outlier_idx = 0;
621 for (i = 0; i < nmeasurement; i++) {
622 mp_avg += mp_coeff[i];
623 if (mp_coeff[i] > mp_max) {
624 mp_max = mp_coeff[i];
626 }
else if (mp_coeff[i] < mp_min) {
627 mp_min = mp_coeff[i];
633 for (i = 0; i < nmeasurement; i++) {
634 if ((
abs(mp_coeff[i]) <
abs(mp_max)) ||
635 (
abs(mp_coeff[i]) <
abs(mp_min)))
636 mp_avg += mp_coeff[i];
638 mp_avg /= (nmeasurement - 1);
641 if (
abs(mp_max - mp_min) > max_delta) {
642 if (
abs(mp_max - mp_avg) >
abs(mp_min - mp_avg))
643 outlier_idx = max_idx;
645 outlier_idx = min_idx;
647 mp_coeff[outlier_idx] = mp_avg;
654 int i, im, nmeasurement;
657 memset(tx_corr_coeff, 0,
sizeof(tx_corr_coeff));
659 tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
662 tx_corr_coeff[i * 2][1] =
663 tx_corr_coeff[(i * 2) + 1][1] =
666 tx_corr_coeff[i * 2][2] =
667 tx_corr_coeff[(i * 2) + 1][2] =
673 for (i = 0; i < num_chains; i++) {
682 if (nmeasurement > 1) {
692 for (im = 0; im < nmeasurement; im++) {
734 "Tx IQ Cal is not completed.\n");
759 if (
ah->txchainmask & (1 << i))
763 for (i = 0; i < num_chains; i++) {
770 for (im = 0; im < nmeasurement; im++) {
772 "Doing Tx IQ Cal for chain %d.\n", i);
777 "Tx IQ Cal failed for chain %d.\n", i);
781 for (j = 0; j < 3; j++) {
782 u32 idx = 2 * j,
offset = 4 * (3 * im + j);
801 chan_info_tab[i] +
offset);
806 idx, iq_res[idx], idx + 1,
813 "Failed in calculation of \ 833 DBG(
"ath9k: Tx IQ Cal failed\n");
841 int txiqcal_done = 0;
844 DBG2(
"ath9k: ath9k: AR_ENT_OTP 0x%x\n",
val);
880 "offset calibration failed to complete in 1ms; noisy environment?\n");
893 ah->cal_list =
ah->cal_list_last =
ah->cal_list_curr =
NULL;
900 "enabling IQ Calibration.\n");
907 "enabling Temperature Compensation Calibration.\n");
911 ah->cal_list_curr =
ah->cal_list;
913 if (
ah->cal_list_curr)
917 ah->caldata->CalValid = 0;
#define AR9300_MAX_CHAINS
int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]
static int ar9003_hw_per_calibration(struct ath_hw *ah, struct ath9k_channel *ichan __unused, u8 rxchainmask, struct ath9k_cal_list *currCal)
static void ar9003_hw_setup_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal)
#define AR_PHY_CHAN_INFO_TAB_S2_READ
static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
#define AR_PHY_RX_IQCAL_CORR_B1
void(* calPostProc)(struct ath_hw *, u8)
void ath9k_hw_start_nfcal(struct ath_hw *ah, int update)
static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
static int ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
void(* init_cal_settings)(struct ath_hw *ah)
#define AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN
#define AR_PHY_TX_IQCAL_CONTROL_1
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
struct ath9k_cal_list * calNext
#define AR_SREV_9485(_ah)
#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT
struct ath_hw_private_ops - callbacks used internally by hardware code
#define AR_PHY_TX_FORCED_GAIN
#define AR_PHY_RX_IQCAL_CORR_B2
void(* setup_calibration)(struct ath_hw *ah, struct ath9k_cal_list *currCal)
#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF
static int ar9003_hw_solve_iq_cal(struct ath_hw *ah __unused, s32 sin_2phi_1, s32 cos_2phi_1, s32 sin_2phi_2, s32 cos_2phi_2, s32 mag_a0_d0, s32 phs_a0_d0, s32 mag_a1_d0, s32 phs_a1_d0, s32 solved_eq[])
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE
#define AR_PHY_AGC_CONTROL_CAL
#define REG_RMW_FIELD(_a, _r, _f, _v)
#define AR_PHY_ACTIVE_DIS
#define AR_PHY_65NM_CH0_THERM_START
int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]
#define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i)
static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
#define AR_PHY_CHAN_INFO_TAB_0
#define AR_PHY_TX_IQCAL_STATUS_B2
#define AR_PHY_CHAN_INFO_TAB_2
#define AR_PHY_CHAN_INFO_TAB_1
#define AR_PHY_TXGAIN_FORCE
#define INIT_CAL(_perCal)
#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i)
#define AR_PHY_TX_IQCAL_CONTROL_3
#define __unused
Declare a variable or data structure as unused.
#define AR_PHY_65NM_CH0_THERM_LOCAL
void udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
#define AR_PHY_AGC_CONTROL
#define AR_PHY_TX_IQCAL_START_DO_CAL
void(* calCollect)(struct ath_hw *)
#define AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX
static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, int max_delta)
#define AR_PHY_TX_IQCAL_START
#define AR_PHY_65NM_CH0_THERM
#define AR_PHY_CAL_MEAS_2(_i)
#define AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE
struct ath_hw_ops - callbacks used by hardware code and driver code
int(* calibrate)(struct ath_hw *ah, struct ath9k_channel *chan, u8 rxchainmask, int longcal)
#define INSERT_CAL(_ahp, _perCal)
#define AR_PHY_TIMING4_DO_CAL
#define AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN
const struct ath9k_percal_data * calData
void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
#define PER_MAX_LOG_COUNT
#define AR_PHY_TX_IQCAL_STATUS_B0
static int ar9003_hw_calc_iq_corr(struct ath_hw *ah, s32 chain_idx, const s32 iq_res[], s32 iqc_coeff[])
#define REG_READ(_ah, _reg)
#define AR5416_MAX_CHAINS
#define REG_SET_BIT(_a, _r, _f)
static struct ath_hw_ops * ath9k_hw_ops(struct ath_hw *ah)
#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF
int ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
#define REG_WRITE(_ah, _reg, _val)
static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, u8 rxchainmask, int longcal)
#define AR_PHY_CHAN_INFO_MEMORY
static const struct ath9k_percal_data iq_cal_single_sample
#define REG_READ_FIELD(_a, _r, _f)
#define AR_PHY_CALIBRATED_GAINS_0
#define AR_PHY_CAL_MEAS_1(_i)
int ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
uint16_t offset
Offset to command line.
#define AR_PHY_TX_IQCAL_STATUS_FAILED
static struct ath_hw_private_ops * ath9k_hw_private_ops(struct ath_hw *ah)
#define AR_PHY_RX_IQCAL_CORR_B0
#define DBG(...)
Print a debugging message.
#define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i)
void ath9k_hw_reset_calibration(struct ath_hw *ah, struct ath9k_cal_list *currCal)
#define NULL
NULL pointer (VOID *)
#define AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE
#define AR_PHY_CAL_MEAS_0(_i)
static int ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan __unused)
static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, u8 num_chains, struct coeff *coeff)
#define AR_PHY_TX_IQCAL_STATUS_B1
enum ath9k_cal_state calState
int(* init_cal)(struct ath_hw *ah, struct ath9k_channel *chan)
#define AR_ENT_OTP_CHAIN2_DISABLE
#define AR_PHY_CALMODE_IQ
void * memset(void *dest, int character, size_t len) __nonnull
static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah __unused, s32 in_re, s32 in_im)
#define AR_SREV_9485_OR_LATER(_ah)