📄 ar5112.c
字号:
/* * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting * Copyright (c) 2002-2008 Atheros Communications, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: ar5112.c,v 1.7 2008/11/10 04:08:03 sam Exp $ */#include "opt_ah.h"#include "ah.h"#include "ah_internal.h"#include "ah_eeprom_v3.h"#include "ar5212/ar5212.h"#include "ar5212/ar5212reg.h"#include "ar5212/ar5212phy.h"#define AH_5212_5112#include "ar5212/ar5212.ini"#define N(a) (sizeof(a)/sizeof(a[0]))struct ar5112State { RF_HAL_FUNCS base; /* public state, must be first */ uint16_t pcdacTable[PWR_TABLE_SIZE]; uint32_t Bank1Data[N(ar5212Bank1_5112)]; uint32_t Bank2Data[N(ar5212Bank2_5112)]; uint32_t Bank3Data[N(ar5212Bank3_5112)]; uint32_t Bank6Data[N(ar5212Bank6_5112)]; uint32_t Bank7Data[N(ar5212Bank7_5112)];};#define AR5112(ah) ((struct ar5112State *) AH5212(ah)->ah_rfHal)static void ar5212GetLowerUpperIndex(uint16_t v, uint16_t *lp, uint16_t listSize, uint32_t *vlo, uint32_t *vhi);static HAL_BOOL getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs, int16_t *power, int16_t maxPower, int16_t *retVals);static int16_t getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4, uint16_t retVals[]);static int16_t getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4, int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid);static int16_t interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight, int16_t targetLeft, int16_t targetRight);extern void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32, uint32_t numBits, uint32_t firstBit, uint32_t column);static voidar5112WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex, int writes){ HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5112, modesIndex, writes); HAL_INI_WRITE_ARRAY(ah, ar5212Common_5112, 1, writes); HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5112, freqIndex, writes);}/* * Take the MHz channel value and set the Channel value * * ASSUMES: Writes enabled to analog bus */static HAL_BOOLar5112SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan){ uint32_t channelSel = 0; uint32_t bModeSynth = 0; uint32_t aModeRefSel = 0; uint32_t reg32 = 0; uint16_t freq; OS_MARK(ah, AH_MARK_SETCHANNEL, chan->channel); if (chan->channel < 4800) { uint32_t txctl; if (((chan->channel - 2192) % 5) == 0) { channelSel = ((chan->channel - 672) * 2 - 3040)/10; bModeSynth = 0; } else if (((chan->channel - 2224) % 5) == 0) { channelSel = ((chan->channel - 704) * 2 - 3040) / 10; bModeSynth = 1; } else { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", __func__, chan->channel); return AH_FALSE; } channelSel = (channelSel << 2) & 0xff; channelSel = ath_hal_reverseBits(channelSel, 8); txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL); if (chan->channel == 2484) { /* Enable channel spreading for channel 14 */ OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl | AR_PHY_CCK_TX_CTRL_JAPAN); } else { OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN); } } else if (((chan->channel % 5) == 2) && (chan->channel <= 5435)) { freq = chan->channel - 2; /* Align to even 5MHz raster */ channelSel = ath_hal_reverseBits( (uint32_t)(((freq - 4800)*10)/25 + 1), 8); aModeRefSel = ath_hal_reverseBits(0, 2); } else if ((chan->channel % 20) == 0 && chan->channel >= 5120) { channelSel = ath_hal_reverseBits( ((chan->channel - 4800) / 20 << 2), 8); aModeRefSel = ath_hal_reverseBits(3, 2); } else if ((chan->channel % 10) == 0) { channelSel = ath_hal_reverseBits( ((chan->channel - 4800) / 10 << 1), 8); aModeRefSel = ath_hal_reverseBits(2, 2); } else if ((chan->channel % 5) == 0) { channelSel = ath_hal_reverseBits( (chan->channel - 4800) / 5, 8); aModeRefSel = ath_hal_reverseBits(1, 2); } else { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n", __func__, chan->channel); return AH_FALSE; } reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) | (1 << 12) | 0x1; OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff); reg32 >>= 8; OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f); AH_PRIVATE(ah)->ah_curchan = chan; return AH_TRUE;}/* * Return a reference to the requested RF Bank. */static uint32_t *ar5112GetRfBank(struct ath_hal *ah, int bank){ struct ar5112State *priv = AR5112(ah); HALASSERT(priv != AH_NULL); switch (bank) { case 1: return priv->Bank1Data; case 2: return priv->Bank2Data; case 3: return priv->Bank3Data; case 6: return priv->Bank6Data; case 7: return priv->Bank7Data; } HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n", __func__, bank); return AH_NULL;}/* * Reads EEPROM header info from device structure and programs * all rf registers * * REQUIRES: Access to the analog rf device */static HAL_BOOLar5112SetRfRegs(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, uint16_t modesIndex, uint16_t *rfXpdGain){#define RF_BANK_SETUP(_priv, _ix, _col) do { \ int i; \ for (i = 0; i < N(ar5212Bank##_ix##_5112); i++) \ (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5112[i][_col];\} while (0) struct ath_hal_5212 *ahp = AH5212(ah); const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; uint16_t rfXpdSel, gainI; uint16_t ob5GHz = 0, db5GHz = 0; uint16_t ob2GHz = 0, db2GHz = 0; struct ar5112State *priv = AR5112(ah); GAIN_VALUES *gv = &ahp->ah_gainValues; int regWrites = 0; HALASSERT(priv); /* Setup rf parameters */ switch (chan->channelFlags & CHANNEL_ALL) { case CHANNEL_A: case CHANNEL_T: if (chan->channel > 4000 && chan->channel < 5260) { ob5GHz = ee->ee_ob1; db5GHz = ee->ee_db1; } else if (chan->channel >= 5260 && chan->channel < 5500) { ob5GHz = ee->ee_ob2; db5GHz = ee->ee_db2; } else if (chan->channel >= 5500 && chan->channel < 5725) { ob5GHz = ee->ee_ob3; db5GHz = ee->ee_db3; } else if (chan->channel >= 5725) { ob5GHz = ee->ee_ob4; db5GHz = ee->ee_db4; } else { /* XXX else */ } rfXpdSel = ee->ee_xpd[headerInfo11A]; gainI = ee->ee_gainI[headerInfo11A]; break; case CHANNEL_B: ob2GHz = ee->ee_ob2GHz[0]; db2GHz = ee->ee_db2GHz[0]; rfXpdSel = ee->ee_xpd[headerInfo11B]; gainI = ee->ee_gainI[headerInfo11B]; break; case CHANNEL_G: case CHANNEL_108G: ob2GHz = ee->ee_ob2GHz[1]; db2GHz = ee->ee_ob2GHz[1]; rfXpdSel = ee->ee_xpd[headerInfo11G]; gainI = ee->ee_gainI[headerInfo11G]; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n", __func__, chan->channelFlags); return AH_FALSE; } /* Setup Bank 1 Write */ RF_BANK_SETUP(priv, 1, 1); /* Setup Bank 2 Write */ RF_BANK_SETUP(priv, 2, modesIndex); /* Setup Bank 3 Write */ RF_BANK_SETUP(priv, 3, modesIndex); /* Setup Bank 6 Write */ RF_BANK_SETUP(priv, 6, modesIndex); ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdSel, 1, 302, 0); ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[0], 2, 270, 0); ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[1], 2, 257, 0); if (IS_CHAN_OFDM(chan)) { ar5212ModifyRfBuffer(priv->Bank6Data, gv->currStep->paramVal[GP_PWD_138], 1, 168, 3); ar5212ModifyRfBuffer(priv->Bank6Data, gv->currStep->paramVal[GP_PWD_137], 1, 169, 3); ar5212ModifyRfBuffer(priv->Bank6Data, gv->currStep->paramVal[GP_PWD_136], 1, 170, 3); ar5212ModifyRfBuffer(priv->Bank6Data, gv->currStep->paramVal[GP_PWD_132], 1, 174, 3); ar5212ModifyRfBuffer(priv->Bank6Data, gv->currStep->paramVal[GP_PWD_131], 1, 175, 3); ar5212ModifyRfBuffer(priv->Bank6Data, gv->currStep->paramVal[GP_PWD_130], 1, 176, 3); } /* Only the 5 or 2 GHz OB/DB need to be set for a mode */ if (IS_CHAN_2GHZ(chan)) { ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 287, 0); ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 290, 0); } else { ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 279, 0); ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 282, 0); } /* Lower synth voltage for X112 Rev 2.0 only */ if (IS_RADX112_REV2(ah)) { /* Non-Reversed analyg registers - so values are pre-reversed */ ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 90, 2); ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 92, 2); ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 94, 2); ar5212ModifyRfBuffer(priv->Bank6Data, 2, 1, 254, 2); } /* Decrease Power Consumption for 5312/5213 and up */ if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) { ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 281, 1); ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 1, 3); ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 3, 3); ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 139, 3); ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 140, 3); } /* Setup Bank 7 Setup */ RF_BANK_SETUP(priv, 7, modesIndex); if (IS_CHAN_OFDM(chan)) ar5212ModifyRfBuffer(priv->Bank7Data, gv->currStep->paramVal[GP_MIXGAIN_OVR], 2, 37, 0); ar5212ModifyRfBuffer(priv->Bank7Data, gainI, 6, 14, 0); /* Adjust params for Derby TX power control */ if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) { uint32_t rfDelay, rfPeriod; rfDelay = 0xf; rfPeriod = (IS_CHAN_HALF_RATE(chan)) ? 0x8 : 0xf; ar5212ModifyRfBuffer(priv->Bank7Data, rfDelay, 4, 58, 0); ar5212ModifyRfBuffer(priv->Bank7Data, rfPeriod, 4, 70, 0); }#ifdef notyet /* Analog registers are setup - EAR can modify */ if (ar5212IsEarEngaged(pDev, chan)) uint32_t modifier; ar5212EarModify(pDev, EAR_LC_RF_WRITE, chan, &modifier);#endif /* Write Analog registers */ HAL_INI_WRITE_BANK(ah, ar5212Bank1_5112, priv->Bank1Data, regWrites); HAL_INI_WRITE_BANK(ah, ar5212Bank2_5112, priv->Bank2Data, regWrites); HAL_INI_WRITE_BANK(ah, ar5212Bank3_5112, priv->Bank3Data, regWrites); HAL_INI_WRITE_BANK(ah, ar5212Bank6_5112, priv->Bank6Data, regWrites); HAL_INI_WRITE_BANK(ah, ar5212Bank7_5112, priv->Bank7Data, regWrites); /* Now that we have reprogrammed rfgain value, clear the flag. */ ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE; return AH_TRUE;#undef RF_BANK_SETUP}/* * Read the transmit power levels from the structures taken from EEPROM * Interpolate read transmit power values for this channel * Organize the transmit power values into a table for writing into the hardware */static HAL_BOOLar5112SetPowerTable(struct ath_hal *ah, int16_t *pPowerMin, int16_t *pPowerMax, HAL_CHANNEL_INTERNAL *chan, uint16_t *rfXpdGain){ struct ath_hal_5212 *ahp = AH5212(ah); const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom; uint32_t numXpdGain = IS_RADX112_REV2(ah) ? 2 : 1; uint32_t xpdGainMask = 0; int16_t powerMid, *pPowerMid = &powerMid; const EXPN_DATA_PER_CHANNEL_5112 *pRawCh; const EEPROM_POWER_EXPN_5112 *pPowerExpn = AH_NULL; uint32_t ii, jj, kk; int16_t minPwr_t4, maxPwr_t4, Pmin, Pmid; uint32_t chan_idx_L = 0, chan_idx_R = 0; uint16_t chan_L, chan_R; int16_t pwr_table0[64]; int16_t pwr_table1[64]; uint16_t pcdacs[10]; int16_t powers[10]; uint16_t numPcd; int16_t powTableLXPD[2][64]; int16_t powTableHXPD[2][64]; int16_t tmpPowerTable[64]; uint16_t xgainList[2]; uint16_t xpdMask; switch (chan->channelFlags & CHANNEL_ALL) { case CHANNEL_A: case CHANNEL_T: pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11A]; xpdGainMask = ee->ee_xgain[headerInfo11A]; break; case CHANNEL_B: pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11B]; xpdGainMask = ee->ee_xgain[headerInfo11B]; break; case CHANNEL_G: case CHANNEL_108G: pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11G]; xpdGainMask = ee->ee_xgain[headerInfo11G]; break; default: HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown channel flags 0x%x\n", __func__, chan->channelFlags & CHANNEL_ALL); return AH_FALSE; } if ((xpdGainMask & pPowerExpn->xpdMask) < 1) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: desired xpdGainMask 0x%x not supported by " "calibrated xpdMask 0x%x\n", __func__, xpdGainMask, pPowerExpn->xpdMask); return AH_FALSE; } maxPwr_t4 = (int16_t)(2*(*pPowerMax)); /* pwr_t2 -> pwr_t4 */ minPwr_t4 = (int16_t)(2*(*pPowerMin)); /* pwr_t2 -> pwr_t4 */ xgainList[0] = 0xDEAD; xgainList[1] = 0xDEAD; kk = 0; xpdMask = pPowerExpn->xpdMask; for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) { if (((xpdMask >> jj) & 1) > 0) { if (kk > 1) { HALDEBUG(ah, HAL_DEBUG_ANY, "A maximum of 2 xpdGains supported" "in pExpnPower data\n"); return AH_FALSE; } xgainList[kk++] = (uint16_t)jj; } } ar5212GetLowerUpperIndex(chan->channel, &pPowerExpn->pChannels[0], pPowerExpn->numChannels, &chan_idx_L, &chan_idx_R); kk = 0; for (ii = chan_idx_L; ii <= chan_idx_R; ii++) { pRawCh = &(pPowerExpn->pDataPerChannel[ii]); if (xgainList[1] == 0xDEAD) { jj = xgainList[0]; numPcd = pRawCh->pDataPerXPD[jj].numPcdacs; OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0], numPcd * sizeof(uint16_t)); OS_MEMCPY(&powers[0], &pRawCh->pDataPerXPD[jj].pwr_t4[0], numPcd * sizeof(int16_t)); if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0], pRawCh->maxPower_t4, &tmpPowerTable[0])) { return AH_FALSE; } OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0], 64*sizeof(int16_t)); } else { jj = xgainList[0]; numPcd = pRawCh->pDataPerXPD[jj].numPcdacs; OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -