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:
parent
141fa00b5f
commit
4551052dbe
@ -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.
|
||||
|
@ -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, ¢ers);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user