summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2011-05-26 14:29:05 +0000
committeradrian <adrian@FreeBSD.org>2011-05-26 14:29:05 +0000
commitf9522af8abb117678d8c26ca102a05ff2496cd81 (patch)
treeef703e718a15eb16662a68c9921667874bea754d
parentb5a299c358df8a338fef06ebaeed7e09fb31b02b (diff)
downloadFreeBSD-src-f9522af8abb117678d8c26ca102a05ff2496cd81.zip
FreeBSD-src-f9522af8abb117678d8c26ca102a05ff2496cd81.tar.gz
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
-rw-r--r--sys/dev/ath/ath_hal/ar9002/ar9287_attach.c11
-rw-r--r--sys/dev/ath/ath_hal/ar9002/ar9287_olc.c72
-rw-r--r--sys/dev/ath/ath_hal/ar9002/ar9287_olc.h6
-rw-r--r--sys/dev/ath/ath_hal/ar9002/ar9287_reset.c90
4 files changed, 179 insertions, 0 deletions
diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
index 08105606..daee414 100644
--- a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
+++ b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c
@@ -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.
diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c b/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c
index 938ce63..9d65bbd 100644
--- a/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c
+++ b/sys/dev/ath/ath_hal/ar9002/ar9287_olc.c
@@ -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);
+ }
+}
diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h b/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h
index 882f6fe..ff21ce6 100644
--- a/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h
+++ b/sys/dev/ath/ath_hal/ar9002/ar9287_olc.h
@@ -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__ */
diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c b/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c
index 6e0e104..26fb078 100644
--- a/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c
+++ b/sys/dev/ath/ath_hal/ar9002/ar9287_reset.c
@@ -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;
}
OpenPOWER on IntegriCloud