28 #define MAX_MEASUREMENT 8 29 #define MAX_MAG_DELTA 11 30 #define MAX_PHS_DELTA 10 59 "starting IQ Mismatch Calibration\n");
71 "starting Temperature Compensation Calibration\n");
100 if (
ah->cal_samples >=
102 unsigned int i, numChains = 0;
104 if (rxchainmask & (1 << i))
154 rxchainmask, currCal);
156 ah->cal_list_curr = currCal = currCal->
calNext;
193 if (
ah->txchainmask &
BIT(i)) {
194 ah->totalPowerMeasI[i] +=
196 ah->totalPowerMeasQ[i] +=
198 ah->totalIqCorrMeas[i] +=
201 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
202 ah->cal_samples, i,
ah->totalPowerMeasI[i],
203 ah->totalPowerMeasQ[i],
204 ah->totalIqCorrMeas[i]);
211 u32 powerMeasQ, powerMeasI, iqCorrMeas;
212 u32 qCoffDenom, iCoffDenom;
215 static const uint32_t offset_array[3] = {
221 for (i = 0; i < numChains; i++) {
222 powerMeasI =
ah->totalPowerMeasI[i];
223 powerMeasQ =
ah->totalPowerMeasQ[i];
224 iqCorrMeas =
ah->totalIqCorrMeas[i];
227 "Starting IQ Cal and Correction for Chain %d\n",
231 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
232 i,
ah->totalIqCorrMeas[i]);
236 if (iqCorrMeas > 0x80000000) {
237 iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
242 "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
244 "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
245 DBG2(
"ath9k: iqCorrNeg is 0x%08x\n",
248 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
249 qCoffDenom = powerMeasQ / 64;
251 if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
252 iCoff = iqCorrMeas / iCoffDenom;
253 qCoff = powerMeasI / qCoffDenom - 64;
255 "Chn %d iCoff = 0x%08x\n", i, iCoff);
257 "Chn %d qCoff = 0x%08x\n", i, qCoff);
262 else if (iCoff <= -63)
266 if (iqCorrNeg == 0x0)
272 else if (qCoff <= -63)
275 iCoff = iCoff & 0x7f;
276 qCoff = qCoff & 0x7f;
279 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
282 "Register offset (0x%04x) before update = 0x%x\n",
293 "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
298 "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
304 "IQ Cal and Correction done for Chain %d\n", i);
311 "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
344 s32 f1 = cos_2phi_1 - cos_2phi_2,
345 f3 = sin_2phi_1 - sin_2phi_2,
347 s32 mag_tx, phs_tx, mag_rx, phs_rx;
348 const s32 result_shift = 1 << 15;
350 f2 = (f1 * f1 + f3 * f3) / result_shift;
353 DBG(
"ath9k: Divide by 0\n");
358 mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
360 phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
362 mag_tx = (mag_tx / f2);
363 phs_tx = (phs_tx / f2);
366 mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
369 phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
372 solved_eq[0] = mag_tx;
373 solved_eq[1] = phs_tx;
374 solved_eq[2] = mag_rx;
375 solved_eq[3] = phs_rx;
394 return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
404 s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
405 i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
406 i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
407 i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
408 s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
409 phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
410 sin_2phi_1, cos_2phi_1,
411 sin_2phi_2, cos_2phi_2;
412 s32 mag_tx, phs_tx, mag_rx, phs_rx;
413 s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
415 const s32 res_scale = 1 << 15;
416 const s32 delpt_shift = 1 << 8;
419 i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
420 i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
421 iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
423 if (i2_m_q2_a0_d0 > 0x800)
424 i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
426 if (i2_p_q2_a0_d0 > 0x800)
427 i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
429 if (iq_corr_a0_d0 > 0x800)
430 iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
432 i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
433 i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
434 iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
436 if (i2_m_q2_a0_d1 > 0x800)
437 i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
439 if (i2_p_q2_a0_d1 > 0x800)
440 i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1);
442 if (iq_corr_a0_d1 > 0x800)
443 iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
445 i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
446 i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
447 iq_corr_a1_d0 = iq_res[4] & 0xfff;
449 if (i2_m_q2_a1_d0 > 0x800)
450 i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
452 if (i2_p_q2_a1_d0 > 0x800)
453 i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
455 if (iq_corr_a1_d0 > 0x800)
456 iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
458 i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
459 i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
460 iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
462 if (i2_m_q2_a1_d1 > 0x800)
463 i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
465 if (i2_p_q2_a1_d1 > 0x800)
466 i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
468 if (iq_corr_a1_d1 > 0x800)
469 iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
471 if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
472 (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
479 i2_p_q2_a0_d0, i2_p_q2_a0_d1,
480 i2_p_q2_a1_d0, i2_p_q2_a1_d1);
484 mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
485 phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
487 mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
488 phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
490 mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
491 phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
493 mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
494 phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
497 sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) /
DELPT);
499 cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) /
DELPT);
501 sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) /
DELPT);
503 cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) /
DELPT);
512 if ((mag1 == 0) || (mag2 == 0)) {
514 "Divide by 0: mag1=%d, mag2=%d\n",
520 sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
521 cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
522 sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
523 cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
527 sin_2phi_1, cos_2phi_1,
528 sin_2phi_2, cos_2phi_2,
529 mag_a0_d0, phs_a0_d0,
531 phs_a1_d0, solved_eq)) {
533 "Call to ar9003_hw_solve_iq_cal() failed.\n");
537 mag_tx = solved_eq[0];
538 phs_tx = solved_eq[1];
539 mag_rx = solved_eq[2];
540 phs_rx = solved_eq[3];
543 "chain %d: mag mismatch=%d phase mismatch=%d\n",
544 chain_idx, mag_tx/res_scale, phs_tx/res_scale);
546 if (res_scale == mag_tx) {
548 "Divide by 0: mag_tx=%d, res_scale=%d\n",
554 mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
555 phs_corr_tx = -phs_tx;
557 q_q_coff = (mag_corr_tx * 128 / res_scale);
558 q_i_coff = (phs_corr_tx * 256 / res_scale);
561 "tx chain %d: mag corr=%d phase corr=%d\n",
562 chain_idx, q_q_coff, q_i_coff);
573 iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
576 "tx chain %d: iq corr coeff=%x\n",
577 chain_idx, iqc_coeff[0]);
579 if (-mag_rx == res_scale) {
581 "Divide by 0: mag_rx=%d, res_scale=%d\n",
587 mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
588 phs_corr_rx = -phs_rx;
590 q_q_coff = (mag_corr_rx * 128 / res_scale);
591 q_i_coff = (phs_corr_rx * 256 / res_scale);
594 "rx chain %d: mag corr=%d phase corr=%d\n",
595 chain_idx, q_q_coff, q_i_coff);
606 iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
609 "rx chain %d: iq corr coeff=%x\n",
610 chain_idx, iqc_coeff[1]);
618 int mp_max = -64, max_idx = 0;
619 int mp_min = 63, min_idx = 0;
620 int mp_avg = 0, i, outlier_idx = 0;
623 for (i = 0; i < nmeasurement; i++) {
624 mp_avg += mp_coeff[i];
625 if (mp_coeff[i] > mp_max) {
626 mp_max = mp_coeff[i];
628 }
else if (mp_coeff[i] < mp_min) {
629 mp_min = mp_coeff[i];
635 for (i = 0; i < nmeasurement; i++) {
636 if ((
abs(mp_coeff[i]) <
abs(mp_max)) ||
637 (
abs(mp_coeff[i]) <
abs(mp_min)))
638 mp_avg += mp_coeff[i];
640 mp_avg /= (nmeasurement - 1);
643 if (
abs(mp_max - mp_min) > max_delta) {
644 if (
abs(mp_max - mp_avg) >
abs(mp_min - mp_avg))
645 outlier_idx = max_idx;
647 outlier_idx = min_idx;
649 mp_coeff[outlier_idx] = mp_avg;
656 int i, im, nmeasurement;
659 memset(tx_corr_coeff, 0,
sizeof(tx_corr_coeff));
661 tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
664 tx_corr_coeff[i * 2][1] =
665 tx_corr_coeff[(i * 2) + 1][1] =
668 tx_corr_coeff[i * 2][2] =
669 tx_corr_coeff[(i * 2) + 1][2] =
675 for (i = 0; i < num_chains; i++) {
684 if (nmeasurement > 1) {
694 for (im = 0; im < nmeasurement; im++) {
736 "Tx IQ Cal is not completed.\n");
761 if (
ah->txchainmask & (1 << i))
765 for (i = 0; i < num_chains; i++) {
772 for (im = 0; im < nmeasurement; im++) {
774 "Doing Tx IQ Cal for chain %d.\n", i);
779 "Tx IQ Cal failed for chain %d.\n", i);
783 for (j = 0; j < 3; j++) {
784 u32 idx = 2 * j,
offset = 4 * (3 * im + j);
803 chan_info_tab[i] +
offset);
808 idx, iq_res[idx], idx + 1,
815 "Failed in calculation of \ 835 DBG(
"ath9k: Tx IQ Cal failed\n");
843 int txiqcal_done = 0;
846 DBG2(
"ath9k: ath9k: AR_ENT_OTP 0x%x\n",
val);
882 "offset calibration failed to complete in 1ms; noisy environment?\n");
895 ah->cal_list =
ah->cal_list_last =
ah->cal_list_curr =
NULL;
902 "enabling IQ Calibration.\n");
909 "enabling Temperature Compensation Calibration.\n");
913 ah->cal_list_curr =
ah->cal_list;
915 if (
ah->cal_list_curr)
919 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)
#define AR_PHY_TX_IQCAL_STATUS_FAILED
static struct ath_hw_private_ops * ath9k_hw_private_ops(struct ath_hw *ah)
uint16_t offset
Offset to command line.
#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)