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

Commit 381c726c authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

ath9k_hw: calibrate PA input for PA predistortion



Re-train if the calibrated PA linearization curve is out of bounds
(affects AR933x and AR9485).

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 26228959
Loading
Loading
Loading
Loading
+99 −0
Original line number Diff line number Diff line
@@ -786,6 +786,102 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
}
EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);

static bool ar9003_paprd_retrain_pa_in(struct ath_hw *ah,
				       struct ath9k_hw_cal_data *caldata,
				       int chain)
{
	u32 *pa_in = caldata->pa_table[chain];
	int capdiv_offset, quick_drop_offset;
	int capdiv2g, quick_drop;
	int count = 0;
	int i;

	if (!AR_SREV_9485(ah) && !AR_SREV_9330(ah))
		return false;

	capdiv2g = REG_READ_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
				  AR_PHY_65NM_CH0_TXRF3_CAPDIV2G);

	quick_drop = REG_READ_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
				    AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP);

	if (quick_drop)
		quick_drop -= 0x40;

	for (i = 0; i < NUM_BIN + 1; i++) {
		if (pa_in[i] == 1400)
			count++;
	}

	if (AR_SREV_9485(ah)) {
		if (pa_in[23] < 800) {
			capdiv_offset = (int)((1000 - pa_in[23] + 75) / 150);
			capdiv2g += capdiv_offset;
			if (capdiv2g > 7) {
				capdiv2g = 7;
				if (pa_in[23] < 600) {
					quick_drop++;
					if (quick_drop > 0)
						quick_drop = 0;
				}
			}
		} else if (pa_in[23] == 1400) {
			quick_drop_offset = min_t(int, count / 3, 2);
			quick_drop += quick_drop_offset;
			capdiv2g += quick_drop_offset / 2;

			if (capdiv2g > 7)
				capdiv2g = 7;

			if (quick_drop > 0) {
				quick_drop = 0;
				capdiv2g -= quick_drop_offset;
				if (capdiv2g < 0)
					capdiv2g = 0;
			}
		} else {
			return false;
		}
	} else if (AR_SREV_9330(ah)) {
		if (pa_in[23] < 1000) {
			capdiv_offset = (1000 - pa_in[23]) / 100;
			capdiv2g += capdiv_offset;
			if (capdiv_offset > 3) {
				capdiv_offset = 1;
				quick_drop--;
			}

			capdiv2g += capdiv_offset;
			if (capdiv2g > 6)
				capdiv2g = 6;
			if (quick_drop < -4)
				quick_drop = -4;
		} else if (pa_in[23] == 1400) {
			if (count > 3) {
				quick_drop++;
				capdiv2g -= count / 4;
				if (quick_drop > -2)
					quick_drop = -2;
			} else {
				capdiv2g--;
			}

			if (capdiv2g < 0)
				capdiv2g = 0;
		} else {
			return false;
		}
	}

	REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_TXRF3,
		      AR_PHY_65NM_CH0_TXRF3_CAPDIV2G, capdiv2g);
	REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
		      AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
		      quick_drop);

	return true;
}

int ar9003_paprd_create_curve(struct ath_hw *ah,
			      struct ath9k_hw_cal_data *caldata, int chain)
{
@@ -821,6 +917,9 @@ int ar9003_paprd_create_curve(struct ath_hw *ah,
	if (!create_pa_curve(data_L, data_U, pa_table, small_signal_gain))
		status = -2;

	if (ar9003_paprd_retrain_pa_in(ah, caldata, chain))
		status = -EINPROGRESS;

	REG_CLR_BIT(ah, AR_PHY_PAPRD_TRAINER_STAT1,
		    AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE);

+4 −0
Original line number Diff line number Diff line
@@ -625,6 +625,10 @@
#define AR_PHY_AIC_CTRL_4_B0	(AR_SM_BASE + 0x4c0)
#define AR_PHY_AIC_STAT_2_B0	(AR_SM_BASE + 0x4cc)

#define AR_PHY_65NM_CH0_TXRF3       0x16048
#define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G		0x0000001e
#define AR_PHY_65NM_CH0_TXRF3_CAPDIV2G_S	1

#define AR_PHY_65NM_CH0_SYNTH4      0x1608c
#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   (AR_SREV_9462(ah) ? 0x00000001 : 0x00000002)
#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S (AR_SREV_9462(ah) ? 0 : 1)
+8 −1
Original line number Diff line number Diff line
@@ -254,6 +254,7 @@ void ath_paprd_calibrate(struct work_struct *work)
	int chain_ok = 0;
	int chain;
	int len = 1800;
	int ret;

	if (!caldata)
		return;
@@ -302,7 +303,13 @@ void ath_paprd_calibrate(struct work_struct *work)
			break;
		}

		if (ar9003_paprd_create_curve(ah, caldata, chain)) {
		ret = ar9003_paprd_create_curve(ah, caldata, chain);
		if (ret == -EINPROGRESS) {
			ath_dbg(common, CALIBRATE,
				"PAPRD curve on chain %d needs to be re-trained\n",
				chain);
			break;
		} else if (ret) {
			ath_dbg(common, CALIBRATE,
				"PAPRD create curve failed on chain %d\n",
				chain);