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

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

ath9k: merge noisefloor load implementations



AR5008+ and AR9003 currently use two separate implementations of the
ath9k_hw_loadnf function. There are three main differences:

 - PHY registers for AR9003 are different
 - AR9003 always uses 3 chains, earlier versions are more selective
 - The AR9003 variant contains a fix for NF load timeouts

This patch merges the two implementations into one, storing the
register array in the ath_hw struct. The fix for NF load timeouts is
not just relevant for AR9003, but also important for earlier hardware,
so it's better to just keep one common implementation.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b11b160d
Loading
Loading
Loading
Loading
+9 −72
Original line number Diff line number Diff line
@@ -1516,77 +1516,6 @@ static void ar5008_hw_do_getnf(struct ath_hw *ah,
	nfarray[5] = sign_extend(nf, 9);
}

static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
{
	struct ath9k_nfcal_hist *h;
	int i, j;
	int32_t val;
	const u32 ar5416_cca_regs[6] = {
		AR_PHY_CCA,
		AR_PHY_CH1_CCA,
		AR_PHY_CH2_CCA,
		AR_PHY_EXT_CCA,
		AR_PHY_CH1_EXT_CCA,
		AR_PHY_CH2_EXT_CCA
	};
	u8 chainmask, rx_chain_status;

	rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
		chainmask = 0x9;
	else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
		if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
			chainmask = 0x1B;
		else
			chainmask = 0x09;
	} else {
		if (rx_chain_status & 0x4)
			chainmask = 0x3F;
		else if (rx_chain_status & 0x2)
			chainmask = 0x1B;
		else
			chainmask = 0x09;
	}

	h = ah->nfCalHist;

	for (i = 0; i < NUM_NF_READINGS; i++) {
		if (chainmask & (1 << i)) {
			val = REG_READ(ah, ar5416_cca_regs[i]);
			val &= 0xFFFFFE00;
			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
			REG_WRITE(ah, ar5416_cca_regs[i], val);
		}
	}

	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_ENABLE_NF);
	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);

	for (j = 0; j < 5; j++) {
		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
		     AR_PHY_AGC_CONTROL_NF) == 0)
			break;
		udelay(50);
	}

	ENABLE_REGWRITE_BUFFER(ah);

	for (i = 0; i < NUM_NF_READINGS; i++) {
		if (chainmask & (1 << i)) {
			val = REG_READ(ah, ar5416_cca_regs[i]);
			val &= 0xFFFFFE00;
			val |= (((u32) (-50) << 1) & 0x1ff);
			REG_WRITE(ah, ar5416_cca_regs[i], val);
		}
	}

	REGWRITE_BUFFER_FLUSH(ah);
	DISABLE_REGWRITE_BUFFER(ah);
}

/*
 * Initialize the ANI register values with default (ini) values.
 * This routine is called during a (full) hardware reset after
@@ -1664,6 +1593,14 @@ static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
	const u32 ar5416_cca_regs[6] = {
		AR_PHY_CCA,
		AR_PHY_CH1_CCA,
		AR_PHY_CH2_CCA,
		AR_PHY_EXT_CCA,
		AR_PHY_CH1_EXT_CCA,
		AR_PHY_CH2_EXT_CCA
	};

	priv_ops->rf_set_freq = ar5008_hw_set_channel;
	priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
@@ -1683,7 +1620,6 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
	priv_ops->restore_chainmask = ar5008_restore_chainmask;
	priv_ops->set_diversity = ar5008_set_diversity;
	priv_ops->do_getnf = ar5008_hw_do_getnf;
	priv_ops->loadnf = ar5008_hw_loadnf;

	if (modparam_force_new_ani) {
		priv_ops->ani_control = ar5008_hw_ani_control_new;
@@ -1699,4 +1635,5 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
		priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;

	ar5008_hw_set_nf_limits(ah);
	memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
}
+9 −101
Original line number Diff line number Diff line
@@ -1049,106 +1049,6 @@ static void ar9003_hw_set_nf_limits(struct ath_hw *ah)
	ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ;
}

/*
 * Find out which of the RX chains are enabled
 */
static u32 ar9003_hw_get_rx_chainmask(struct ath_hw *ah)
{
	u32 chain = REG_READ(ah, AR_PHY_RX_CHAINMASK);
	/*
	 * The bits [2:0] indicate the rx chain mask and are to be
	 * interpreted as follows:
	 * 00x => Only chain 0 is enabled
	 * 01x => Chain 1 and 0 enabled
	 * 1xx => Chain 2,1 and 0 enabled
	 */
	return chain & 0x7;
}

static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
{
	struct ath9k_nfcal_hist *h;
	unsigned i, j;
	int32_t val;
	const u32 ar9300_cca_regs[6] = {
		AR_PHY_CCA_0,
		AR_PHY_CCA_1,
		AR_PHY_CCA_2,
		AR_PHY_EXT_CCA,
		AR_PHY_EXT_CCA_1,
		AR_PHY_EXT_CCA_2,
	};
	u8 chainmask, rx_chain_status;
	struct ath_common *common = ath9k_hw_common(ah);

	rx_chain_status = ar9003_hw_get_rx_chainmask(ah);

	chainmask = 0x3F;
	h = ah->nfCalHist;

	for (i = 0; i < NUM_NF_READINGS; i++) {
		if (chainmask & (1 << i)) {
			val = REG_READ(ah, ar9300_cca_regs[i]);
			val &= 0xFFFFFE00;
			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
			REG_WRITE(ah, ar9300_cca_regs[i], val);
		}
	}

	/*
	 * Load software filtered NF value into baseband internal minCCApwr
	 * variable.
	 */
	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_ENABLE_NF);
	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);

	/*
	 * Wait for load to complete, should be fast, a few 10s of us.
	 * The max delay was changed from an original 250us to 10000us
	 * since 250us often results in NF load timeout and causes deaf
	 * condition during stress testing 12/12/2009
	 */
	for (j = 0; j < 1000; j++) {
		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
		     AR_PHY_AGC_CONTROL_NF) == 0)
			break;
		udelay(10);
	}

	/*
	 * We timed out waiting for the noisefloor to load, probably due to an
	 * in-progress rx. Simply return here and allow the load plenty of time
	 * to complete before the next calibration interval.  We need to avoid
	 * trying to load -50 (which happens below) while the previous load is
	 * still in progress as this can cause rx deafness. Instead by returning
	 * here, the baseband nf cal will just be capped by our present
	 * noisefloor until the next calibration timer.
	 */
	if (j == 1000) {
		ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
			  "to load: AR_PHY_AGC_CONTROL=0x%x\n",
			  REG_READ(ah, AR_PHY_AGC_CONTROL));
		return;
	}

	/*
	 * Restore maxCCAPower register parameter again so that we're not capped
	 * by the median we just loaded.  This will be initial (and max) value
	 * of next noise floor calibration the baseband does.
	 */
	for (i = 0; i < NUM_NF_READINGS; i++) {
		if (chainmask & (1 << i)) {
			val = REG_READ(ah, ar9300_cca_regs[i]);
			val &= 0xFFFFFE00;
			val |= (((u32) (-50) << 1) & 0x1ff);
			REG_WRITE(ah, ar9300_cca_regs[i], val);
		}
	}
}

/*
 * Initialize the ANI register values with default (ini) values.
 * This routine is called during a (full) hardware reset after
@@ -1216,6 +1116,14 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
	const u32 ar9300_cca_regs[6] = {
		AR_PHY_CCA_0,
		AR_PHY_CCA_1,
		AR_PHY_CCA_2,
		AR_PHY_EXT_CCA,
		AR_PHY_EXT_CCA_1,
		AR_PHY_EXT_CCA_2,
	};

	priv_ops->rf_set_freq = ar9003_hw_set_channel;
	priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
@@ -1232,10 +1140,10 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
	priv_ops->set_diversity = ar9003_hw_set_diversity;
	priv_ops->ani_control = ar9003_hw_ani_control;
	priv_ops->do_getnf = ar9003_hw_do_getnf;
	priv_ops->loadnf = ar9003_hw_loadnf;
	priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;

	ar9003_hw_set_nf_limits(ah);
	memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
}

void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
+94 −0
Original line number Diff line number Diff line
@@ -167,6 +167,100 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah)
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
}

void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
{
	struct ath9k_nfcal_hist *h;
	unsigned i, j;
	int32_t val;
	u8 chainmask;
	struct ath_common *common = ath9k_hw_common(ah);

	if (AR_SREV_9300_20_OR_LATER(ah))
		chainmask = 0x3F;
	else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
		chainmask = 0x9;
	else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
		if ((ah->rxchainmask & 0x2) || (ah->rxchainmask & 0x4))
			chainmask = 0x1B;
		else
			chainmask = 0x09;
	} else {
		if (ah->rxchainmask & 0x4)
			chainmask = 0x3F;
		else if (ah->rxchainmask & 0x2)
			chainmask = 0x1B;
		else
			chainmask = 0x09;
	}
	h = ah->nfCalHist;

	for (i = 0; i < NUM_NF_READINGS; i++) {
		if (chainmask & (1 << i)) {
			val = REG_READ(ah, ah->nf_regs[i]);
			val &= 0xFFFFFE00;
			val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
			REG_WRITE(ah, ah->nf_regs[i], val);
		}
	}

	/*
	 * Load software filtered NF value into baseband internal minCCApwr
	 * variable.
	 */
	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_ENABLE_NF);
	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);

	/*
	 * Wait for load to complete, should be fast, a few 10s of us.
	 * The max delay was changed from an original 250us to 10000us
	 * since 250us often results in NF load timeout and causes deaf
	 * condition during stress testing 12/12/2009
	 */
	for (j = 0; j < 1000; j++) {
		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
		     AR_PHY_AGC_CONTROL_NF) == 0)
			break;
		udelay(10);
	}

	/*
	 * We timed out waiting for the noisefloor to load, probably due to an
	 * in-progress rx. Simply return here and allow the load plenty of time
	 * to complete before the next calibration interval.  We need to avoid
	 * trying to load -50 (which happens below) while the previous load is
	 * still in progress as this can cause rx deafness. Instead by returning
	 * here, the baseband nf cal will just be capped by our present
	 * noisefloor until the next calibration timer.
	 */
	if (j == 1000) {
		ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
			  "to load: AR_PHY_AGC_CONTROL=0x%x\n",
			  REG_READ(ah, AR_PHY_AGC_CONTROL));
		return;
	}

	/*
	 * Restore maxCCAPower register parameter again so that we're not capped
	 * by the median we just loaded.  This will be initial (and max) value
	 * of next noise floor calibration the baseband does.
	 */
	ENABLE_REGWRITE_BUFFER(ah);
	for (i = 0; i < NUM_NF_READINGS; i++) {
		if (chainmask & (1 << i)) {
			val = REG_READ(ah, ah->nf_regs[i]);
			val &= 0xFFFFFE00;
			val |= (((u32) (-50) << 1) & 0x1ff);
			REG_WRITE(ah, ah->nf_regs[i], val);
		}
	}
	REGWRITE_BUFFER_FLUSH(ah);
	DISABLE_REGWRITE_BUFFER(ah);
}


static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
{
	struct ath_common *common = ath9k_hw_common(ah);
+1 −0
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@ struct ath9k_pacal_info{

bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah);
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
int16_t ath9k_hw_getnf(struct ath_hw *ah,
		       struct ath9k_channel *chan);
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
+0 −6
Original line number Diff line number Diff line
@@ -264,12 +264,6 @@ static inline void ath9k_hw_do_getnf(struct ath_hw *ah,
	ath9k_hw_private_ops(ah)->do_getnf(ah, nfarray);
}

static inline void ath9k_hw_loadnf(struct ath_hw *ah,
				   struct ath9k_channel *chan)
{
	ath9k_hw_private_ops(ah)->loadnf(ah, chan);
}

static inline bool ath9k_hw_init_cal(struct ath_hw *ah,
				     struct ath9k_channel *chan)
{
Loading