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

Commit c08267dc authored by Lorenzo Bianconi's avatar Lorenzo Bianconi Committed by Kalle Valo
Browse files

ath9k: add power per-rate tables for AR9002 chips



Add TX power per-rate tables for MIMO/legacy modes for AR9002 based chips
in order to cap the maximum TX power value per-rate in the TX descriptor path.
Add TX power adjustments for HT40 mode, open loop CCK rates and eeprom power
bias for AR9280 and later chips

Signed-off-by: default avatarLorenzo Bianconi <lorenzo.bianconi83@gmail.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 72e12119
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
@@ -22,6 +22,21 @@

/* All code below is for AR5008, AR9001, AR9002 */

#define AR5008_OFDM_RATES		8
#define AR5008_HT_SS_RATES		8
#define AR5008_HT_DS_RATES		8

#define AR5008_HT20_SHIFT		16
#define AR5008_HT40_SHIFT		24

#define AR5008_11NA_OFDM_SHIFT		0
#define AR5008_11NA_HT_SS_SHIFT		8
#define AR5008_11NA_HT_DS_SHIFT		16

#define AR5008_11NG_OFDM_SHIFT		4
#define AR5008_11NG_HT_SS_SHIFT		12
#define AR5008_11NG_HT_DS_SHIFT		20

static const int firstep_table[] =
/* level:  0   1   2   3   4   5   6   7   8  */
	{ -4, -2,  0,  2,  4,  6,  8, 10, 12 }; /* lvl 0-8, default 2 */
@@ -1235,6 +1250,71 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
	conf->radar_inband = 8;
}

static void ar5008_hw_init_txpower_cck(struct ath_hw *ah, int16_t *rate_array)
{
#define CCK_DELTA(x) ((OLC_FOR_AR9280_20_LATER) ? max((x) - 2, 0) : (x))
	ah->tx_power[0] = CCK_DELTA(rate_array[rate1l]);
	ah->tx_power[1] = CCK_DELTA(min(rate_array[rate2l],
					rate_array[rate2s]));
	ah->tx_power[2] = CCK_DELTA(min(rate_array[rate5_5l],
					rate_array[rate5_5s]));
	ah->tx_power[3] = CCK_DELTA(min(rate_array[rate11l],
					rate_array[rate11s]));
#undef CCK_DELTA
}

static void ar5008_hw_init_txpower_ofdm(struct ath_hw *ah, int16_t *rate_array,
					int offset)
{
	int i, idx = 0;

	for (i = offset; i < offset + AR5008_OFDM_RATES; i++) {
		ah->tx_power[i] = rate_array[idx];
		idx++;
	}
}

static void ar5008_hw_init_txpower_ht(struct ath_hw *ah, int16_t *rate_array,
				      int ss_offset, int ds_offset,
				      bool is_40, int ht40_delta)
{
	int i, mcs_idx = (is_40) ? AR5008_HT40_SHIFT : AR5008_HT20_SHIFT;

	for (i = ss_offset; i < ss_offset + AR5008_HT_SS_RATES; i++) {
		ah->tx_power[i] = rate_array[mcs_idx] + ht40_delta;
		mcs_idx++;
	}
	memcpy(&ah->tx_power[ds_offset], &ah->tx_power[ss_offset],
	       AR5008_HT_SS_RATES);
}

void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array,
				 struct ath9k_channel *chan, int ht40_delta)
{
	if (IS_CHAN_5GHZ(chan)) {
		ar5008_hw_init_txpower_ofdm(ah, rate_array,
					    AR5008_11NA_OFDM_SHIFT);
		if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
			ar5008_hw_init_txpower_ht(ah, rate_array,
						  AR5008_11NA_HT_SS_SHIFT,
						  AR5008_11NA_HT_DS_SHIFT,
						  IS_CHAN_HT40(chan),
						  ht40_delta);
		}
	} else {
		ar5008_hw_init_txpower_cck(ah, rate_array);
		ar5008_hw_init_txpower_ofdm(ah, rate_array,
					    AR5008_11NG_OFDM_SHIFT);
		if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
			ar5008_hw_init_txpower_ht(ah, rate_array,
						  AR5008_11NG_HT_SS_SHIFT,
						  AR5008_11NG_HT_DS_SHIFT,
						  IS_CHAN_HT40(chan),
						  ht40_delta);
		}
	}
}

int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+14 −0
Original line number Diff line number Diff line
@@ -748,6 +748,20 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
	}

	/* TPC initializations */
	if (ah->tpc_enabled) {
		int ht40_delta;

		ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
		ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
		/* Enable TPC */
		REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
			MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
	} else {
		/* Disable TPC */
		REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
	}

	REGWRITE_BUFFER_FLUSH(ah);
}

+15 −0
Original line number Diff line number Diff line
@@ -886,6 +886,21 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
	}

	/* TPC initializations */
	if (ah->tpc_enabled) {
		int ht40_delta;

		ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
		ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
		/* Enable TPC */
		REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
			MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
	} else {
		/* Disable TPC */
		REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
	}

	REGWRITE_BUFFER_FLUSH(ah);
}

+14 −0
Original line number Diff line number Diff line
@@ -1332,6 +1332,20 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));

	/* TPC initializations */
	if (ah->tpc_enabled) {
		int ht40_delta;

		ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
		ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
		/* Enable TPC */
		REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
			MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
	} else {
		/* Disable TPC */
		REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
	}

	REGWRITE_BUFFER_FLUSH(ah);
}

+2 −0
Original line number Diff line number Diff line
@@ -1087,6 +1087,8 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah);
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array,
				 struct ath9k_channel *chan);
void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array,
				 struct ath9k_channel *chan, int ht40_delta);

/* Hardware family op attach helpers */
int ar5008_hw_attach_phy_ops(struct ath_hw *ah);