Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97fe6420 authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville
Browse files

ath9k: Modify IQ calibration for AR955x



IQ calibration post-processing for AR955x is different
from other chips - instead of just doing it as part
of AGC calibration once, it is triggered 3 times and
a median is determined. This patch adds initial support
for changing the calibration behavior for AR955x.

Also, to simplify things, a helper routine to issue/poll
AGC calibration is used.

For non-AR955x chips, the iqcal_idx (which will be used
in subsequent patches) is set to zero.

Signed-off-by: default avatarSujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent adddc0d2
Loading
Loading
Loading
Loading
+59 −22
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#define MAX_MEASUREMENT	MAX_IQCAL_MEASUREMENT
#define MAX_MAG_DELTA	11
#define MAX_PHS_DELTA	10
#define MAXIQCAL        3

struct coeff {
	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
@@ -797,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
	if (q_q_coff > 63)
		q_q_coff = 63;

	iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
	iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);

	ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
		chain_idx, iqc_coeff[0]);
@@ -828,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
	if (q_q_coff > 63)
		q_q_coff = 63;

	iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
	iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);

	ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
		chain_idx, iqc_coeff[1]);
@@ -991,7 +992,9 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
	return true;
}

static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,
					  int iqcal_idx,
					  bool is_reusable)
{
	struct ath_common *common = ath9k_hw_common(ah);
	const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
@@ -1410,7 +1413,7 @@ static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
	}

	if (txiqcal_done)
		ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
		ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
	else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
		ar9003_hw_tx_iq_cal_reload(ah);

@@ -1456,6 +1459,29 @@ static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
	return true;
}

static bool do_ar9003_agc_cal(struct ath_hw *ah)
{
	struct ath_common *common = ath9k_hw_common(ah);
	bool status;

	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
		  AR_PHY_AGC_CONTROL_CAL);

	status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
			       AR_PHY_AGC_CONTROL_CAL,
			       0, AH_WAIT_TIMEOUT);
	if (!status) {
		ath_dbg(common, CALIBRATE,
			"offset calibration failed to complete in %d ms,"
			"noisy environment?\n",
			AH_WAIT_TIMEOUT / 1000);
		return false;
	}

	return true;
}

static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
				   struct ath9k_channel *chan)
{
@@ -1464,6 +1490,7 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
	bool txiqcal_done = false;
	bool status = true;
	bool run_agc_cal = false, sep_iq_cal = false;
	int i = 0;

	/* Use chip chainmask only for calibration */
	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
@@ -1518,26 +1545,36 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
		if (AR_SREV_9330_11(ah))
			ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan));

		/* Calibrate the AGC */
		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
			  REG_READ(ah, AR_PHY_AGC_CONTROL) |
			  AR_PHY_AGC_CONTROL_CAL);

		/* Poll for offset calibration complete */
		status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
				       AR_PHY_AGC_CONTROL_CAL,
				       0, AH_WAIT_TIMEOUT);
	}

	if (!status) {
		ath_dbg(common, CALIBRATE,
			"offset calibration failed to complete in %d ms; noisy environment?\n",
			AH_WAIT_TIMEOUT / 1000);
		/*
		 * For non-AR9550 chips, we just trigger AGC calibration
		 * in the HW, poll for completion and then process
		 * the results.
		 *
		 * For AR955x, we run it multiple times and use
		 * median IQ correction.
		 */
		if (!AR_SREV_9550(ah)) {
			status = do_ar9003_agc_cal(ah);
			if (!status)
				return false;
	}

			if (txiqcal_done)
		ar9003_hw_tx_iq_cal_post_proc(ah, false);
				ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);
		} else {
			if (!txiqcal_done) {
				status = do_ar9003_agc_cal(ah);
				if (!status)
					return false;
			} else {
				for (i = 0; i < MAXIQCAL; i++) {
					status = do_ar9003_agc_cal(ah);
					if (!status)
						return false;
					ar9003_hw_tx_iq_cal_post_proc(ah, i, false);
				}
			}
		}
	}

	/* Revert chainmask to runtime parameters */
	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);