ath9k: Fix bugs in handling TX power

* Get power table offset from the EEPROM instead of using
  a hardcoded value of -5 if the EEPROM rev is >= 21.
* Add support in the 4k eeprom code for tx power offset
  in case we have a 4k AR9280 implementation.
* Fix tx power accuracy at high powers.

Signed-off-by: Senthil Balasubramanian <senthilkumar@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Senthil Balasubramanian 2009-09-18 15:08:20 +05:30 committed by John W. Linville
parent ebb90cfc32
commit e41f0bfcb1
3 changed files with 104 additions and 7 deletions

View File

@ -134,6 +134,7 @@
#define AR5416_EEP_MINOR_VER_17 0x11 #define AR5416_EEP_MINOR_VER_17 0x11
#define AR5416_EEP_MINOR_VER_19 0x13 #define AR5416_EEP_MINOR_VER_19 0x13
#define AR5416_EEP_MINOR_VER_20 0x14 #define AR5416_EEP_MINOR_VER_20 0x14
#define AR5416_EEP_MINOR_VER_21 0x15
#define AR5416_EEP_MINOR_VER_22 0x16 #define AR5416_EEP_MINOR_VER_22 0x16
#define AR5416_NUM_5G_CAL_PIERS 8 #define AR5416_NUM_5G_CAL_PIERS 8
@ -154,7 +155,7 @@
#define AR5416_BCHAN_UNUSED 0xFF #define AR5416_BCHAN_UNUSED 0xFF
#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 #define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
#define AR5416_MAX_CHAINS 3 #define AR5416_MAX_CHAINS 3
#define AR5416_PWR_TABLE_OFFSET -5 #define AR5416_PWR_TABLE_OFFSET_DB -5
/* Rx gain type values */ /* Rx gain type values */
#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 #define AR5416_EEP_RXGAIN_23DB_BACKOFF 0
@ -302,7 +303,7 @@ struct base_eep_header {
u8 txGainType; u8 txGainType;
u8 rcChainMask; u8 rcChainMask;
u8 desiredScaleCCK; u8 desiredScaleCCK;
u8 power_table_offset; u8 pwr_table_offset;
u8 frac_n_5g; u8 frac_n_5g;
u8 futureBase_3[21]; u8 futureBase_3[21];
} __packed; } __packed;

View File

@ -210,6 +210,8 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
return pBase->rxMask; return pBase->rxMask;
case EEP_FRAC_N_5G: case EEP_FRAC_N_5G:
return 0; return 0;
case EEP_PWR_TABLE_OFFSET:
return AR5416_PWR_TABLE_OFFSET_DB;
default: default:
return 0; return 0;
} }
@ -753,7 +755,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
if (AR_SREV_9280_10_OR_LATER(ah)) { if (AR_SREV_9280_10_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++) for (i = 0; i < Ar5416RateSize; i++)
ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
} }
/* OFDM power per rate */ /* OFDM power per rate */

View File

@ -291,6 +291,11 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
return pBase->frac_n_5g; return pBase->frac_n_5g;
else else
return 0; return 0;
case EEP_PWR_TABLE_OFFSET:
if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_21)
return pBase->pwr_table_offset;
else
return AR5416_PWR_TABLE_OFFSET_DB;
default: default:
return 0; return 0;
} }
@ -741,6 +746,76 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
return; return;
} }
static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah,
u16 *gb,
u16 numXpdGain,
u16 pdGainOverlap_t2,
int8_t pwr_table_offset,
int16_t *diff)
{
u16 k;
/* Prior to writing the boundaries or the pdadc vs. power table
* into the chip registers the default starting point on the pdadc
* vs. power table needs to be checked and the curve boundaries
* adjusted accordingly
*/
if (AR_SREV_9280_20_OR_LATER(ah)) {
u16 gb_limit;
if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
/* get the difference in dB */
*diff = (u16)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB);
/* get the number of half dB steps */
*diff *= 2;
/* change the original gain boundary settings
* by the number of half dB steps
*/
for (k = 0; k < numXpdGain; k++)
gb[k] = (u16)(gb[k] - *diff);
}
/* Because of a hardware limitation, ensure the gain boundary
* is not larger than (63 - overlap)
*/
gb_limit = (u16)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2);
for (k = 0; k < numXpdGain; k++)
gb[k] = (u16)min(gb_limit, gb[k]);
}
return *diff;
}
static void ath9k_adjust_pdadc_values(struct ath_hw *ah,
int8_t pwr_table_offset,
int16_t diff,
u8 *pdadcValues)
{
#define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff)
u16 k;
/* If this is a board that has a pwrTableOffset that differs from
* the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
* pdadc vs pwr table needs to be adjusted prior to writing to the
* chip.
*/
if (AR_SREV_9280_20_OR_LATER(ah)) {
if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
/* shift the table to start at the new offset */
for (k = 0; k < (u16)NUM_PDADC(diff); k++ ) {
pdadcValues[k] = pdadcValues[k + diff];
}
/* fill the back of the table */
for (k = (u16)NUM_PDADC(diff); k < NUM_PDADC(0); k++) {
pdadcValues[k] = pdadcValues[NUM_PDADC(diff)];
}
}
}
#undef NUM_PDADC
}
static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan, struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset) int16_t *pTxPowerIndexOffset)
@ -756,15 +831,18 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
u16 numPiers, i, j; u16 numPiers, i, j;
int16_t tMinCalPower; int16_t tMinCalPower, diff = 0;
u16 numXpdGain, xpdMask; u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
u32 reg32, regOffset, regChainOffset; u32 reg32, regOffset, regChainOffset;
int16_t modalIdx; int16_t modalIdx;
int8_t pwr_table_offset;
modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
xpdMask = pEepData->modalHeader[modalIdx].xpdGain; xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
pwr_table_offset = ah->eep_ops->get_eeprom(ah, EEP_PWR_TABLE_OFFSET);
if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
AR5416_EEP_MINOR_VER_2) { AR5416_EEP_MINOR_VER_2) {
pdGainOverlap_t2 = pdGainOverlap_t2 =
@ -844,6 +922,13 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
numXpdGain); numXpdGain);
} }
diff = ath9k_change_gain_boundary_setting(ah,
gainBoundaries,
numXpdGain,
pdGainOverlap_t2,
pwr_table_offset,
&diff);
if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
if (OLC_FOR_AR9280_20_LATER) { if (OLC_FOR_AR9280_20_LATER) {
REG_WRITE(ah, REG_WRITE(ah,
@ -864,6 +949,10 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
} }
} }
ath9k_adjust_pdadc_values(ah, pwr_table_offset,
diff, pdadcValues);
regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
for (j = 0; j < 32; j++) { for (j = 0; j < 32; j++) {
reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
@ -1199,8 +1288,13 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
} }
if (AR_SREV_9280_10_OR_LATER(ah)) { if (AR_SREV_9280_10_OR_LATER(ah)) {
for (i = 0; i < Ar5416RateSize; i++) for (i = 0; i < Ar5416RateSize; i++) {
ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; int8_t pwr_table_offset;
pwr_table_offset = ah->eep_ops->get_eeprom(ah,
EEP_PWR_TABLE_OFFSET);
ratesArray[i] -= pwr_table_offset * 2;
}
} }
REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
@ -1299,7 +1393,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
if (AR_SREV_9280_10_OR_LATER(ah)) if (AR_SREV_9280_10_OR_LATER(ah))
regulatory->max_power_level = regulatory->max_power_level =
ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2;
else else
regulatory->max_power_level = ratesArray[i]; regulatory->max_power_level = ratesArray[i];