Flesh out the TX power calibration for the AR9287.

I'm assuming for now that the AR9287 is only open-loop TX power control
(as mine is) so I've hard-coded the attach path to fail if the NIC is
not open-loop.

This greatly simplifies the TX calibration path and the amount of code
which needs to be ported over.

This still isn't complete - the rate calculation code still needs to be
ported and it all needs to be glued together.

Obtained from:	Linux ath9k
This commit is contained in:
Adrian Chadd 2011-05-26 14:29:05 +00:00
parent 141fa00b5f
commit 4551052dbe
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=222308
4 changed files with 179 additions and 0 deletions

View file

@ -276,6 +276,17 @@ ar9287Attach(uint16_t devid, HAL_SOFTC sc,
goto bad;
}
/*
* We only implement open-loop TX power control
* for the AR9287 in this codebase.
*/
if (! ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
ath_hal_printf(ah, "[ath] AR9287 w/ closed-loop TX power control"
" isn't supported.\n");
ecode = HAL_ENOTSUPP;
goto bad;
}
/*
* Check whether the power table offset isn't the default.
* This can occur with eeprom minor V21 or greater on Merlin.

View file

@ -30,6 +30,7 @@
#include "ah_internal.h"
#include "ah_eeprom_v14.h"
#include "ah_eeprom_9287.h"
#include "ar9002/ar9280.h"
#include "ar5416/ar5416reg.h"
@ -92,3 +93,74 @@ ar9287olcTemperatureCompensation(struct ath_hal *ah)
AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
}
}
void
ar9287olcGetTxGainIndex(struct ath_hal *ah,
const struct ieee80211_channel *chan,
struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
uint8_t *pCalChans, uint16_t availPiers, int8_t *pPwr)
{
uint16_t idxL = 0, idxR = 0, numPiers;
HAL_BOOL match;
CHAN_CENTERS centers;
ar5416GetChannelCenters(ah, chan, &centers);
for (numPiers = 0; numPiers < availPiers; numPiers++) {
if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED)
break;
}
match = ath_ee_getLowerUpperIndex(
(uint8_t)FREQ2FBIN(centers.synth_center, IEEE80211_IS_CHAN_2GHZ(chan)),
pCalChans, numPiers, &idxL, &idxR);
if (match) {
*pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
} else {
*pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
(int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
}
}
void
ar9287olcSetPDADCs(struct ath_hal *ah, int32_t txPower,
uint16_t chain)
{
uint32_t tmpVal;
uint32_t a;
/* Enable OLPC for chain 0 */
tmpVal = OS_REG_READ(ah, 0xa270);
tmpVal = tmpVal & 0xFCFFFFFF;
tmpVal = tmpVal | (0x3 << 24);
OS_REG_WRITE(ah, 0xa270, tmpVal);
/* Enable OLPC for chain 1 */
tmpVal = OS_REG_READ(ah, 0xb270);
tmpVal = tmpVal & 0xFCFFFFFF;
tmpVal = tmpVal | (0x3 << 24);
OS_REG_WRITE(ah, 0xb270, tmpVal);
/* Write the OLPC ref power for chain 0 */
if (chain == 0) {
tmpVal = OS_REG_READ(ah, 0xa398);
tmpVal = tmpVal & 0xff00ffff;
a = (txPower)&0xff;
tmpVal = tmpVal | (a << 16);
OS_REG_WRITE(ah, 0xa398, tmpVal);
}
/* Write the OLPC ref power for chain 1 */
if (chain == 1) {
tmpVal = OS_REG_READ(ah, 0xb398);
tmpVal = tmpVal & 0xff00ffff;
a = (txPower)&0xff;
tmpVal = tmpVal | (a << 16);
OS_REG_WRITE(ah, 0xb398, tmpVal);
}
}

View file

@ -21,5 +21,11 @@
extern void ar9287olcInit(struct ath_hal *ah);
extern void ar9287olcTemperatureCompensation(struct ath_hal *ah);
extern void ar9287olcGetTxGainIndex(struct ath_hal *ah,
const struct ieee80211_channel *chan,
struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
uint8_t *pCalChans, uint16_t availPiers, int8_t *pPwr);
extern void ar9287olcSetPDADCs(struct ath_hal *ah,
int32_t txPower, uint16_t chain);
#endif /* __AR9287_OLC_H__ */

View file

@ -33,13 +33,103 @@
#include "ar9002/ar9287phy.h"
#include "ar9002/ar9287an.h"
#include "ar9002/ar9287_olc.h"
#include "ar9002/ar9287_reset.h"
/*
* Set the TX power calibration table per-chain.
*
* This only supports open-loop TX power control for the AR9287.
*/
static void
ar9287SetPowerCalTable(struct ath_hal *ah,
const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset)
{
struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
uint8_t *pCalBChans = NULL;
uint16_t pdGainOverlap_t2;
uint16_t numPiers = 0, i;
uint16_t numXpdGain, xpdMask;
uint16_t xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
uint32_t regChainOffset;
HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom;
struct ar9287_eeprom *pEepData = &ee->ee_base;
xpdMask = pEepData->modalHeader.xpdGain;
if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
AR9287_EEP_MINOR_VER_2)
pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
else
pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5),
AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
/* Note: Kiwi should only be 2ghz.. */
if (IEEE80211_IS_CHAN_2GHZ(chan)) {
pCalBChans = pEepData->calFreqPier2G;
numPiers = AR9287_NUM_2G_CAL_PIERS;
pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
AH5416(ah)->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
}
numXpdGain = 0;
/* Calculate the value of xpdgains from the xpdGain Mask */
for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
if (numXpdGain >= AR5416_NUM_PD_GAINS)
break;
xpdGainValues[numXpdGain] =
(uint16_t)(AR5416_PD_GAINS_IN_MASK-i);
numXpdGain++;
}
}
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
(numXpdGain - 1) & 0x3);
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
xpdGainValues[0]);
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
xpdGainValues[1]);
OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
xpdGainValues[2]);
for (i = 0; i < AR9287_MAX_CHAINS; i++) {
regChainOffset = i * 0x1000;
if (pEepData->baseEepHeader.txMask & (1 << i)) {
int8_t txPower;
pRawDatasetOpenLoop =
(struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
ar9287olcGetTxGainIndex(ah, chan,
pRawDatasetOpenLoop,
pCalBChans, numPiers,
&txPower);
ar9287olcSetPDADCs(ah, txPower, i);
}
}
*pTxPowerIndexOffset = 0;
}
HAL_BOOL
ar9287SetTransmitPower(struct ath_hal *ah,
const struct ieee80211_channel *chan, uint16_t *rfXpdGain)
{
int16_t txPowerIndexOffset = 0;
/* XXX TODO */
/* Fetch per-rate power table for the given channel */
/* Set open-loop TX power control calibration */
ar9287SetPowerCalTable(ah, chan, &txPowerIndexOffset);
/* Calculate regulatory maximum power level */
/* Kiwi TX power starts at -5 dBm */
/* Write TX power registers */
return AH_TRUE;
}