The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ath/ath_hal/ar5212/ar5112.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: ISC
    3  *
    4  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
    5  * Copyright (c) 2002-2008 Atheros Communications, Inc.
    6  *
    7  * Permission to use, copy, modify, and/or distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  *
   19  * $FreeBSD$
   20  */
   21 #include "opt_ah.h"
   22 
   23 #include "ah.h"
   24 #include "ah_internal.h"
   25 
   26 #include "ah_eeprom_v3.h"
   27 
   28 #include "ar5212/ar5212.h"
   29 #include "ar5212/ar5212reg.h"
   30 #include "ar5212/ar5212phy.h"
   31 
   32 #define AH_5212_5112
   33 #include "ar5212/ar5212.ini"
   34 
   35 #define N(a)    (sizeof(a)/sizeof(a[0]))
   36 
   37 struct ar5112State {
   38         RF_HAL_FUNCS    base;           /* public state, must be first */
   39         uint16_t        pcdacTable[PWR_TABLE_SIZE];
   40 
   41         uint32_t        Bank1Data[N(ar5212Bank1_5112)];
   42         uint32_t        Bank2Data[N(ar5212Bank2_5112)];
   43         uint32_t        Bank3Data[N(ar5212Bank3_5112)];
   44         uint32_t        Bank6Data[N(ar5212Bank6_5112)];
   45         uint32_t        Bank7Data[N(ar5212Bank7_5112)];
   46 };
   47 #define AR5112(ah)      ((struct ar5112State *) AH5212(ah)->ah_rfHal)
   48 
   49 static  void ar5212GetLowerUpperIndex(uint16_t v,
   50                 uint16_t *lp, uint16_t listSize,
   51                 uint32_t *vlo, uint32_t *vhi);
   52 static HAL_BOOL getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs,
   53                 int16_t *power, int16_t maxPower, int16_t *retVals);
   54 static int16_t getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4,
   55                 uint16_t retVals[]);
   56 static int16_t getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4,
   57                 int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid);
   58 static int16_t interpolate_signed(uint16_t target,
   59                 uint16_t srcLeft, uint16_t srcRight,
   60                 int16_t targetLeft, int16_t targetRight);
   61 
   62 extern  void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
   63                 uint32_t numBits, uint32_t firstBit, uint32_t column);
   64 
   65 static void
   66 ar5112WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
   67         int writes)
   68 {
   69         HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5112, modesIndex, writes);
   70         HAL_INI_WRITE_ARRAY(ah, ar5212Common_5112, 1, writes);
   71         HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5112, freqIndex, writes);
   72 }
   73 
   74 /*
   75  * Take the MHz channel value and set the Channel value
   76  *
   77  * ASSUMES: Writes enabled to analog bus
   78  */
   79 static HAL_BOOL
   80 ar5112SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan)
   81 {
   82         uint16_t freq = ath_hal_gethwchannel(ah, chan);
   83         uint32_t channelSel  = 0;
   84         uint32_t bModeSynth  = 0;
   85         uint32_t aModeRefSel = 0;
   86         uint32_t reg32       = 0;
   87 
   88         OS_MARK(ah, AH_MARK_SETCHANNEL, freq);
   89 
   90         if (freq < 4800) {
   91                 uint32_t txctl;
   92 
   93                 if (((freq - 2192) % 5) == 0) {
   94                         channelSel = ((freq - 672) * 2 - 3040)/10;
   95                         bModeSynth = 0;
   96                 } else if (((freq - 2224) % 5) == 0) {
   97                         channelSel = ((freq - 704) * 2 - 3040) / 10;
   98                         bModeSynth = 1;
   99                 } else {
  100                         HALDEBUG(ah, HAL_DEBUG_ANY,
  101                             "%s: invalid channel %u MHz\n",
  102                             __func__, freq);
  103                         return AH_FALSE;
  104                 }
  105 
  106                 channelSel = (channelSel << 2) & 0xff;
  107                 channelSel = ath_hal_reverseBits(channelSel, 8);
  108 
  109                 txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
  110                 if (freq == 2484) {
  111                         /* Enable channel spreading for channel 14 */
  112                         OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
  113                                 txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
  114                 } else {
  115                         OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
  116                                 txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
  117                 }
  118         } else if (((freq % 5) == 2) && (freq <= 5435)) {
  119                 freq = freq - 2; /* Align to even 5MHz raster */
  120                 channelSel = ath_hal_reverseBits(
  121                         (uint32_t)(((freq - 4800)*10)/25 + 1), 8);
  122                 aModeRefSel = ath_hal_reverseBits(0, 2);
  123         } else if ((freq % 20) == 0 && freq >= 5120) {
  124                 channelSel = ath_hal_reverseBits(
  125                         ((freq - 4800) / 20 << 2), 8);
  126                 aModeRefSel = ath_hal_reverseBits(3, 2);
  127         } else if ((freq % 10) == 0) {
  128                 channelSel = ath_hal_reverseBits(
  129                         ((freq - 4800) / 10 << 1), 8);
  130                 aModeRefSel = ath_hal_reverseBits(2, 2);
  131         } else if ((freq % 5) == 0) {
  132                 channelSel = ath_hal_reverseBits(
  133                         (freq - 4800) / 5, 8);
  134                 aModeRefSel = ath_hal_reverseBits(1, 2);
  135         } else {
  136                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
  137                     __func__, freq);
  138                 return AH_FALSE;
  139         }
  140 
  141         reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
  142                         (1 << 12) | 0x1;
  143         OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
  144 
  145         reg32 >>= 8;
  146         OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
  147 
  148         AH_PRIVATE(ah)->ah_curchan = chan;
  149         return AH_TRUE;
  150 }
  151 
  152 /*
  153  * Return a reference to the requested RF Bank.
  154  */
  155 static uint32_t *
  156 ar5112GetRfBank(struct ath_hal *ah, int bank)
  157 {
  158         struct ar5112State *priv = AR5112(ah);
  159 
  160         HALASSERT(priv != AH_NULL);
  161         switch (bank) {
  162         case 1: return priv->Bank1Data;
  163         case 2: return priv->Bank2Data;
  164         case 3: return priv->Bank3Data;
  165         case 6: return priv->Bank6Data;
  166         case 7: return priv->Bank7Data;
  167         }
  168         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
  169             __func__, bank);
  170         return AH_NULL;
  171 }
  172 
  173 /*
  174  * Reads EEPROM header info from device structure and programs
  175  * all rf registers
  176  *
  177  * REQUIRES: Access to the analog rf device
  178  */
  179 static HAL_BOOL
  180 ar5112SetRfRegs(struct ath_hal *ah,
  181         const struct ieee80211_channel *chan,
  182         uint16_t modesIndex, uint16_t *rfXpdGain)
  183 {
  184 #define RF_BANK_SETUP(_priv, _ix, _col) do {                                \
  185         int i;                                                              \
  186         for (i = 0; i < N(ar5212Bank##_ix##_5112); i++)                     \
  187                 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5112[i][_col];\
  188 } while (0)
  189         uint16_t freq = ath_hal_gethwchannel(ah, chan);
  190         struct ath_hal_5212 *ahp = AH5212(ah);
  191         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
  192         uint16_t rfXpdSel, gainI;
  193         uint16_t ob5GHz = 0, db5GHz = 0;
  194         uint16_t ob2GHz = 0, db2GHz = 0;
  195         struct ar5112State *priv = AR5112(ah);
  196         GAIN_VALUES *gv = &ahp->ah_gainValues;
  197         int regWrites = 0;
  198 
  199         HALASSERT(priv);
  200 
  201         HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan %u/0x%x modesIndex %u\n",
  202             __func__, chan->ic_freq, chan->ic_flags, modesIndex);
  203 
  204         /* Setup rf parameters */
  205         switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {
  206         case IEEE80211_CHAN_A:
  207                 if (freq > 4000 && freq < 5260) {
  208                         ob5GHz = ee->ee_ob1;
  209                         db5GHz = ee->ee_db1;
  210                 } else if (freq >= 5260 && freq < 5500) {
  211                         ob5GHz = ee->ee_ob2;
  212                         db5GHz = ee->ee_db2;
  213                 } else if (freq >= 5500 && freq < 5725) {
  214                         ob5GHz = ee->ee_ob3;
  215                         db5GHz = ee->ee_db3;
  216                 } else if (freq >= 5725) {
  217                         ob5GHz = ee->ee_ob4;
  218                         db5GHz = ee->ee_db4;
  219                 } else {
  220                         /* XXX else */
  221                 }
  222                 rfXpdSel = ee->ee_xpd[headerInfo11A];
  223                 gainI = ee->ee_gainI[headerInfo11A];
  224                 break;
  225         case IEEE80211_CHAN_B:
  226                 ob2GHz = ee->ee_ob2GHz[0];
  227                 db2GHz = ee->ee_db2GHz[0];
  228                 rfXpdSel = ee->ee_xpd[headerInfo11B];
  229                 gainI = ee->ee_gainI[headerInfo11B];
  230                 break;
  231         case IEEE80211_CHAN_G:
  232         case IEEE80211_CHAN_PUREG:      /* NB: really 108G */
  233                 ob2GHz = ee->ee_ob2GHz[1];
  234                 db2GHz = ee->ee_ob2GHz[1];
  235                 rfXpdSel = ee->ee_xpd[headerInfo11G];
  236                 gainI = ee->ee_gainI[headerInfo11G];
  237                 break;
  238         default:
  239                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
  240                     __func__, chan->ic_flags);
  241                 return AH_FALSE;
  242         }
  243 
  244         /* Setup Bank 1 Write */
  245         RF_BANK_SETUP(priv, 1, 1);
  246 
  247         /* Setup Bank 2 Write */
  248         RF_BANK_SETUP(priv, 2, modesIndex);
  249 
  250         /* Setup Bank 3 Write */
  251         RF_BANK_SETUP(priv, 3, modesIndex);
  252 
  253         /* Setup Bank 6 Write */
  254         RF_BANK_SETUP(priv, 6, modesIndex);
  255 
  256         ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdSel,     1, 302, 0);
  257 
  258         ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[0], 2, 270, 0);
  259         ar5212ModifyRfBuffer(priv->Bank6Data, rfXpdGain[1], 2, 257, 0);
  260 
  261         if (IEEE80211_IS_CHAN_OFDM(chan)) {
  262                 ar5212ModifyRfBuffer(priv->Bank6Data,
  263                         gv->currStep->paramVal[GP_PWD_138], 1, 168, 3);
  264                 ar5212ModifyRfBuffer(priv->Bank6Data,
  265                         gv->currStep->paramVal[GP_PWD_137], 1, 169, 3);
  266                 ar5212ModifyRfBuffer(priv->Bank6Data,
  267                         gv->currStep->paramVal[GP_PWD_136], 1, 170, 3);
  268                 ar5212ModifyRfBuffer(priv->Bank6Data,
  269                         gv->currStep->paramVal[GP_PWD_132], 1, 174, 3);
  270                 ar5212ModifyRfBuffer(priv->Bank6Data,
  271                         gv->currStep->paramVal[GP_PWD_131], 1, 175, 3);
  272                 ar5212ModifyRfBuffer(priv->Bank6Data,
  273                         gv->currStep->paramVal[GP_PWD_130], 1, 176, 3);
  274         }
  275 
  276         /* Only the 5 or 2 GHz OB/DB need to be set for a mode */
  277         if (IEEE80211_IS_CHAN_2GHZ(chan)) {
  278                 ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 287, 0);
  279                 ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 290, 0);
  280         } else {
  281                 ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 279, 0);
  282                 ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 282, 0);
  283         }
  284 
  285         /* Lower synth voltage for X112 Rev 2.0 only */
  286         if (IS_RADX112_REV2(ah)) {
  287                 /* Non-Reversed analyg registers - so values are pre-reversed */
  288                 ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 90, 2);
  289                 ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 92, 2);
  290                 ar5212ModifyRfBuffer(priv->Bank6Data, 2, 2, 94, 2);
  291                 ar5212ModifyRfBuffer(priv->Bank6Data, 2, 1, 254, 2);
  292         }
  293 
  294     /* Decrease Power Consumption for 5312/5213 and up */
  295     if (AH_PRIVATE(ah)->ah_phyRev >= AR_PHY_CHIP_ID_REV_2) {
  296         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 281, 1);
  297         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 1, 3);
  298         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 2, 3, 3);
  299         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 139, 3);
  300         ar5212ModifyRfBuffer(priv->Bank6Data, 1, 1, 140, 3);
  301     }
  302 
  303         /* Setup Bank 7 Setup */
  304         RF_BANK_SETUP(priv, 7, modesIndex);
  305         if (IEEE80211_IS_CHAN_OFDM(chan))
  306                 ar5212ModifyRfBuffer(priv->Bank7Data,
  307                         gv->currStep->paramVal[GP_MIXGAIN_OVR], 2, 37, 0);
  308 
  309         ar5212ModifyRfBuffer(priv->Bank7Data, gainI, 6, 14, 0);
  310 
  311         /* Adjust params for Derby TX power control */
  312         if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) {
  313                 uint32_t        rfDelay, rfPeriod;
  314 
  315                 rfDelay = 0xf;
  316                 rfPeriod = (IEEE80211_IS_CHAN_HALF(chan)) ?  0x8 : 0xf;
  317                 ar5212ModifyRfBuffer(priv->Bank7Data, rfDelay, 4, 58, 0);
  318                 ar5212ModifyRfBuffer(priv->Bank7Data, rfPeriod, 4, 70, 0);
  319         }
  320 
  321 #ifdef notyet
  322         /* Analog registers are setup - EAR can modify */
  323         if (ar5212IsEarEngaged(pDev, chan))
  324                 uint32_t modifier;
  325                 ar5212EarModify(pDev, EAR_LC_RF_WRITE, chan, &modifier);
  326 #endif
  327         /* Write Analog registers */
  328         HAL_INI_WRITE_BANK(ah, ar5212Bank1_5112, priv->Bank1Data, regWrites);
  329         HAL_INI_WRITE_BANK(ah, ar5212Bank2_5112, priv->Bank2Data, regWrites);
  330         HAL_INI_WRITE_BANK(ah, ar5212Bank3_5112, priv->Bank3Data, regWrites);
  331         HAL_INI_WRITE_BANK(ah, ar5212Bank6_5112, priv->Bank6Data, regWrites);
  332         HAL_INI_WRITE_BANK(ah, ar5212Bank7_5112, priv->Bank7Data, regWrites);
  333 
  334         /* Now that we have reprogrammed rfgain value, clear the flag. */
  335         ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
  336         return AH_TRUE;
  337 #undef  RF_BANK_SETUP
  338 }
  339 
  340 /*
  341  * Read the transmit power levels from the structures taken from EEPROM
  342  * Interpolate read transmit power values for this channel
  343  * Organize the transmit power values into a table for writing into the hardware
  344  */
  345 static HAL_BOOL
  346 ar5112SetPowerTable(struct ath_hal *ah,
  347         int16_t *pPowerMin, int16_t *pPowerMax,
  348         const struct ieee80211_channel *chan,
  349         uint16_t *rfXpdGain)
  350 {
  351         uint16_t freq = ath_hal_gethwchannel(ah, chan);
  352         struct ath_hal_5212 *ahp = AH5212(ah);
  353         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
  354         uint32_t numXpdGain = IS_RADX112_REV2(ah) ? 2 : 1;
  355         uint32_t    xpdGainMask = 0;
  356         int16_t     powerMid, *pPowerMid = &powerMid;
  357 
  358         const EXPN_DATA_PER_CHANNEL_5112 *pRawCh;
  359         const EEPROM_POWER_EXPN_5112     *pPowerExpn = AH_NULL;
  360 
  361         uint32_t    ii, jj, kk;
  362         int16_t     minPwr_t4, maxPwr_t4, Pmin, Pmid;
  363 
  364         uint32_t    chan_idx_L = 0, chan_idx_R = 0;
  365         uint16_t    chan_L, chan_R;
  366 
  367         int16_t     pwr_table0[64];
  368         int16_t     pwr_table1[64];
  369         uint16_t    pcdacs[10];
  370         int16_t     powers[10];
  371         uint16_t    numPcd;
  372         int16_t     powTableLXPD[2][64];
  373         int16_t     powTableHXPD[2][64];
  374         int16_t     tmpPowerTable[64];
  375         uint16_t    xgainList[2];
  376         uint16_t    xpdMask;
  377 
  378         switch (chan->ic_flags & IEEE80211_CHAN_ALLTURBOFULL) {
  379         case IEEE80211_CHAN_A:
  380         case IEEE80211_CHAN_ST:
  381                 pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11A];
  382                 xpdGainMask = ee->ee_xgain[headerInfo11A];
  383                 break;
  384         case IEEE80211_CHAN_B:
  385                 pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11B];
  386                 xpdGainMask = ee->ee_xgain[headerInfo11B];
  387                 break;
  388         case IEEE80211_CHAN_G:
  389         case IEEE80211_CHAN_108G:
  390                 pPowerExpn = &ee->ee_modePowerArray5112[headerInfo11G];
  391                 xpdGainMask = ee->ee_xgain[headerInfo11G];
  392                 break;
  393         default:
  394                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown channel flags 0x%x\n",
  395                     __func__, chan->ic_flags);
  396                 return AH_FALSE;
  397         }
  398 
  399         if ((xpdGainMask & pPowerExpn->xpdMask) < 1) {
  400                 HALDEBUG(ah, HAL_DEBUG_ANY,
  401                     "%s: desired xpdGainMask 0x%x not supported by "
  402                     "calibrated xpdMask 0x%x\n", __func__,
  403                     xpdGainMask, pPowerExpn->xpdMask);
  404                 return AH_FALSE;
  405         }
  406 
  407         maxPwr_t4 = (int16_t)(2*(*pPowerMax));  /* pwr_t2 -> pwr_t4 */
  408         minPwr_t4 = (int16_t)(2*(*pPowerMin));  /* pwr_t2 -> pwr_t4 */
  409 
  410         xgainList[0] = 0xDEAD;
  411         xgainList[1] = 0xDEAD;
  412 
  413         kk = 0;
  414         xpdMask = pPowerExpn->xpdMask;
  415         for (jj = 0; jj < NUM_XPD_PER_CHANNEL; jj++) {
  416                 if (((xpdMask >> jj) & 1) > 0) {
  417                         if (kk > 1) {
  418                                 HALDEBUG(ah, HAL_DEBUG_ANY,
  419                                     "A maximum of 2 xpdGains supported"
  420                                     "in pExpnPower data\n");
  421                                 return AH_FALSE;
  422                         }
  423                         xgainList[kk++] = (uint16_t)jj;
  424                 }
  425         }
  426 
  427         ar5212GetLowerUpperIndex(freq, &pPowerExpn->pChannels[0],
  428                 pPowerExpn->numChannels, &chan_idx_L, &chan_idx_R);
  429 
  430         kk = 0;
  431         for (ii = chan_idx_L; ii <= chan_idx_R; ii++) {
  432                 pRawCh = &(pPowerExpn->pDataPerChannel[ii]);
  433                 if (xgainList[1] == 0xDEAD) {
  434                         jj = xgainList[0];
  435                         numPcd = pRawCh->pDataPerXPD[jj].numPcdacs;
  436                         OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0],
  437                                 numPcd * sizeof(uint16_t));
  438                         OS_MEMCPY(&powers[0], &pRawCh->pDataPerXPD[jj].pwr_t4[0],
  439                                 numPcd * sizeof(int16_t));
  440                         if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0],
  441                                 pRawCh->maxPower_t4, &tmpPowerTable[0])) {
  442                                 return AH_FALSE;
  443                         }
  444                         OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0],
  445                                 64*sizeof(int16_t));
  446                 } else {
  447                         jj = xgainList[0];
  448                         numPcd = pRawCh->pDataPerXPD[jj].numPcdacs;
  449                         OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0],
  450                                 numPcd*sizeof(uint16_t));
  451                         OS_MEMCPY(&powers[0],
  452                                 &pRawCh->pDataPerXPD[jj].pwr_t4[0],
  453                                 numPcd*sizeof(int16_t));
  454                         if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0],
  455                                 pRawCh->maxPower_t4, &tmpPowerTable[0])) {
  456                                 return AH_FALSE;
  457                         }
  458                         OS_MEMCPY(&powTableLXPD[kk][0], &tmpPowerTable[0],
  459                                 64 * sizeof(int16_t));
  460 
  461                         jj = xgainList[1];
  462                         numPcd = pRawCh->pDataPerXPD[jj].numPcdacs;
  463                         OS_MEMCPY(&pcdacs[0], &pRawCh->pDataPerXPD[jj].pcdac[0],
  464                                 numPcd * sizeof(uint16_t));
  465                         OS_MEMCPY(&powers[0],
  466                                 &pRawCh->pDataPerXPD[jj].pwr_t4[0],
  467                                 numPcd * sizeof(int16_t));
  468                         if (!getFullPwrTable(numPcd, &pcdacs[0], &powers[0],
  469                                 pRawCh->maxPower_t4, &tmpPowerTable[0])) {
  470                                 return AH_FALSE;
  471                         }
  472                         OS_MEMCPY(&powTableHXPD[kk][0], &tmpPowerTable[0],
  473                                 64 * sizeof(int16_t));
  474                 }
  475                 kk++;
  476         }
  477 
  478         chan_L = pPowerExpn->pChannels[chan_idx_L];
  479         chan_R = pPowerExpn->pChannels[chan_idx_R];
  480         kk = chan_idx_R - chan_idx_L;
  481 
  482         if (xgainList[1] == 0xDEAD) {
  483                 for (jj = 0; jj < 64; jj++) {
  484                         pwr_table0[jj] = interpolate_signed(
  485                                 freq, chan_L, chan_R,
  486                                 powTableLXPD[0][jj], powTableLXPD[kk][jj]);
  487                 }
  488                 Pmin = getPminAndPcdacTableFromPowerTable(&pwr_table0[0],
  489                                 ahp->ah_pcdacTable);
  490                 *pPowerMin = (int16_t) (Pmin / 2);
  491                 *pPowerMid = (int16_t) (pwr_table0[63] / 2);
  492                 *pPowerMax = (int16_t) (pwr_table0[63] / 2);
  493                 rfXpdGain[0] = xgainList[0];
  494                 rfXpdGain[1] = rfXpdGain[0];
  495         } else {
  496                 for (jj = 0; jj < 64; jj++) {
  497                         pwr_table0[jj] = interpolate_signed(
  498                                 freq, chan_L, chan_R,
  499                                 powTableLXPD[0][jj], powTableLXPD[kk][jj]);
  500                         pwr_table1[jj] = interpolate_signed(
  501                                 freq, chan_L, chan_R,
  502                                 powTableHXPD[0][jj], powTableHXPD[kk][jj]);
  503                 }
  504                 if (numXpdGain == 2) {
  505                         Pmin = getPminAndPcdacTableFromTwoPowerTables(
  506                                 &pwr_table0[0], &pwr_table1[0],
  507                                 ahp->ah_pcdacTable, &Pmid);
  508                         *pPowerMin = (int16_t) (Pmin / 2);
  509                         *pPowerMid = (int16_t) (Pmid / 2);
  510                         *pPowerMax = (int16_t) (pwr_table0[63] / 2);
  511                         rfXpdGain[0] = xgainList[0];
  512                         rfXpdGain[1] = xgainList[1];
  513                 } else if (minPwr_t4 <= pwr_table1[63] &&
  514                            maxPwr_t4 <= pwr_table1[63]) {
  515                         Pmin = getPminAndPcdacTableFromPowerTable(
  516                                 &pwr_table1[0], ahp->ah_pcdacTable);
  517                         rfXpdGain[0] = xgainList[1];
  518                         rfXpdGain[1] = rfXpdGain[0];
  519                         *pPowerMin = (int16_t) (Pmin / 2);
  520                         *pPowerMid = (int16_t) (pwr_table1[63] / 2);
  521                         *pPowerMax = (int16_t) (pwr_table1[63] / 2);
  522                 } else {
  523                         Pmin = getPminAndPcdacTableFromPowerTable(
  524                                 &pwr_table0[0], ahp->ah_pcdacTable);
  525                         rfXpdGain[0] = xgainList[0];
  526                         rfXpdGain[1] = rfXpdGain[0];
  527                         *pPowerMin = (int16_t) (Pmin/2);
  528                         *pPowerMid = (int16_t) (pwr_table0[63] / 2);
  529                         *pPowerMax = (int16_t) (pwr_table0[63] / 2);
  530                 }
  531         }
  532 
  533         /*
  534          * Move 5112 rates to match power tables where the max
  535          * power table entry corresponds with maxPower.
  536          */
  537         HALASSERT(*pPowerMax <= PCDAC_STOP);
  538         ahp->ah_txPowerIndexOffset = PCDAC_STOP - *pPowerMax;
  539 
  540         return AH_TRUE;
  541 }
  542 
  543 /*
  544  * Returns interpolated or the scaled up interpolated value
  545  */
  546 static int16_t
  547 interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
  548         int16_t targetLeft, int16_t targetRight)
  549 {
  550         int16_t rv;
  551 
  552         if (srcRight != srcLeft) {
  553                 rv = ((target - srcLeft)*targetRight +
  554                       (srcRight - target)*targetLeft) / (srcRight - srcLeft);
  555         } else {
  556                 rv = targetLeft;
  557         }
  558         return rv;
  559 }
  560 
  561 /*
  562  * Return indices surrounding the value in sorted integer lists.
  563  *
  564  * NB: the input list is assumed to be sorted in ascending order
  565  */
  566 static void
  567 ar5212GetLowerUpperIndex(uint16_t v, uint16_t *lp, uint16_t listSize,
  568                           uint32_t *vlo, uint32_t *vhi)
  569 {
  570         uint32_t target = v;
  571         uint16_t *ep = lp+listSize;
  572         uint16_t *tp;
  573 
  574         /*
  575          * Check first and last elements for out-of-bounds conditions.
  576          */
  577         if (target < lp[0]) {
  578                 *vlo = *vhi = 0;
  579                 return;
  580         }
  581         if (target >= ep[-1]) {
  582                 *vlo = *vhi = listSize - 1;
  583                 return;
  584         }
  585 
  586         /* look for value being near or between 2 values in list */
  587         for (tp = lp; tp < ep; tp++) {
  588                 /*
  589                  * If value is close to the current value of the list
  590                  * then target is not between values, it is one of the values
  591                  */
  592                 if (*tp == target) {
  593                         *vlo = *vhi = tp - lp;
  594                         return;
  595                 }
  596                 /*
  597                  * Look for value being between current value and next value
  598                  * if so return these 2 values
  599                  */
  600                 if (target < tp[1]) {
  601                         *vlo = tp - lp;
  602                         *vhi = *vlo + 1;
  603                         return;
  604                 }
  605         }
  606 }
  607 
  608 static HAL_BOOL
  609 getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs, int16_t *power, int16_t maxPower, int16_t *retVals)
  610 {
  611         uint16_t    ii;
  612         uint16_t    idxL = 0;
  613         uint16_t    idxR = 1;
  614 
  615         if (numPcdacs < 2) {
  616                 HALDEBUG(AH_NULL, HAL_DEBUG_ANY,
  617                      "%s: at least 2 pcdac values needed [%d]\n",
  618                      __func__, numPcdacs);
  619                 return AH_FALSE;
  620         }
  621         for (ii = 0; ii < 64; ii++) {
  622                 if (ii>pcdacs[idxR] && idxR < numPcdacs-1) {
  623                         idxL++;
  624                         idxR++;
  625                 }
  626                 retVals[ii] = interpolate_signed(ii,
  627                         pcdacs[idxL], pcdacs[idxR], power[idxL], power[idxR]);
  628                 if (retVals[ii] >= maxPower) {
  629                         while (ii < 64)
  630                                 retVals[ii++] = maxPower;
  631                 }
  632         }
  633         return AH_TRUE;
  634 }
  635 
  636 /*
  637  * Takes a single calibration curve and creates a power table.
  638  * Adjusts the new power table so the max power is relative
  639  * to the maximum index in the power table.
  640  *
  641  * WARNING: rates must be adjusted for this relative power table
  642  */
  643 static int16_t
  644 getPminAndPcdacTableFromPowerTable(int16_t *pwrTableT4, uint16_t retVals[])
  645 {
  646     int16_t ii, jj, jjMax;
  647     int16_t pMin, currPower, pMax;
  648 
  649     /* If the spread is > 31.5dB, keep the upper 31.5dB range */
  650     if ((pwrTableT4[63] - pwrTableT4[0]) > 126) {
  651         pMin = pwrTableT4[63] - 126;
  652     } else {
  653         pMin = pwrTableT4[0];
  654     }
  655 
  656     pMax = pwrTableT4[63];
  657     jjMax = 63;
  658 
  659     /* Search for highest pcdac 0.25dB below maxPower */
  660     while ((pwrTableT4[jjMax] > (pMax - 1) ) && (jjMax >= 0)) {
  661         jjMax--;
  662     }
  663 
  664     jj = jjMax;
  665     currPower = pMax;
  666     for (ii = 63; ii >= 0; ii--) {
  667         while ((jj < 64) && (jj > 0) && (pwrTableT4[jj] >= currPower)) {
  668             jj--;
  669         }
  670         if (jj == 0) {
  671             while (ii >= 0) {
  672                 retVals[ii] = retVals[ii + 1];
  673                 ii--;
  674             }
  675             break;
  676         }
  677         retVals[ii] = jj;
  678         currPower -= 2;  // corresponds to a 0.5dB step
  679     }
  680     return pMin;
  681 }
  682 
  683 /*
  684  * Combines the XPD curves from two calibration sets into a single
  685  * power table and adjusts the power table so the max power is relative
  686  * to the maximum index in the power table
  687  *
  688  * WARNING: rates must be adjusted for this relative power table
  689  */
  690 static int16_t
  691 getPminAndPcdacTableFromTwoPowerTables(int16_t *pwrTableLXpdT4,
  692         int16_t *pwrTableHXpdT4, uint16_t retVals[], int16_t *pMid)
  693 {
  694     int16_t     ii, jj, jjMax;
  695     int16_t     pMin, pMax, currPower;
  696     int16_t     *pwrTableT4;
  697     uint16_t    msbFlag = 0x40;  // turns on the 7th bit of the pcdac
  698 
  699     /* If the spread is > 31.5dB, keep the upper 31.5dB range */
  700     if ((pwrTableLXpdT4[63] - pwrTableHXpdT4[0]) > 126) {
  701         pMin = pwrTableLXpdT4[63] - 126;
  702     } else {
  703         pMin = pwrTableHXpdT4[0];
  704     }
  705 
  706     pMax = pwrTableLXpdT4[63];
  707     jjMax = 63;
  708     /* Search for highest pcdac 0.25dB below maxPower */
  709     while ((pwrTableLXpdT4[jjMax] > (pMax - 1) ) && (jjMax >= 0)){
  710         jjMax--;
  711     }
  712 
  713     *pMid = pwrTableHXpdT4[63];
  714     jj = jjMax;
  715     ii = 63;
  716     currPower = pMax;
  717     pwrTableT4 = &(pwrTableLXpdT4[0]);
  718     while (ii >= 0) {
  719         if ((currPower <= *pMid) || ( (jj == 0) && (msbFlag == 0x40))){
  720             msbFlag = 0x00;
  721             pwrTableT4 = &(pwrTableHXpdT4[0]);
  722             jj = 63;
  723         }
  724         while ((jj > 0) && (pwrTableT4[jj] >= currPower)) {
  725             jj--;
  726         }
  727         if ((jj == 0) && (msbFlag == 0x00)) {
  728             while (ii >= 0) {
  729                 retVals[ii] = retVals[ii+1];
  730                 ii--;
  731             }
  732             break;
  733         }
  734         retVals[ii] = jj | msbFlag;
  735         currPower -= 2;  // corresponds to a 0.5dB step
  736         ii--;
  737     }
  738     return pMin;
  739 }
  740 
  741 static int16_t
  742 ar5112GetMinPower(struct ath_hal *ah, const EXPN_DATA_PER_CHANNEL_5112 *data)
  743 {
  744         int i, minIndex;
  745         int16_t minGain,minPwr,minPcdac,retVal;
  746 
  747         /* Assume NUM_POINTS_XPD0 > 0 */
  748         minGain = data->pDataPerXPD[0].xpd_gain;
  749         for (minIndex=0,i=1; i<NUM_XPD_PER_CHANNEL; i++) {
  750                 if (data->pDataPerXPD[i].xpd_gain < minGain) {
  751                         minIndex = i;
  752                         minGain = data->pDataPerXPD[i].xpd_gain;
  753                 }
  754         }
  755         minPwr = data->pDataPerXPD[minIndex].pwr_t4[0];
  756         minPcdac = data->pDataPerXPD[minIndex].pcdac[0];
  757         for (i=1; i<NUM_POINTS_XPD0; i++) {
  758                 if (data->pDataPerXPD[minIndex].pwr_t4[i] < minPwr) {
  759                         minPwr = data->pDataPerXPD[minIndex].pwr_t4[i];
  760                         minPcdac = data->pDataPerXPD[minIndex].pcdac[i];
  761                 }
  762         }
  763         retVal = minPwr - (minPcdac*2);
  764         return(retVal);
  765 }
  766 
  767 static HAL_BOOL
  768 ar5112GetChannelMaxMinPower(struct ath_hal *ah,
  769         const struct ieee80211_channel *chan,
  770         int16_t *maxPow, int16_t *minPow)
  771 {
  772         uint16_t freq = chan->ic_freq;          /* NB: never mapped */
  773         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
  774         int numChannels=0,i,last;
  775         int totalD, totalF,totalMin;
  776         const EXPN_DATA_PER_CHANNEL_5112 *data=AH_NULL;
  777         const EEPROM_POWER_EXPN_5112 *powerArray=AH_NULL;
  778 
  779         *maxPow = 0;
  780         if (IEEE80211_IS_CHAN_A(chan)) {
  781                 powerArray = ee->ee_modePowerArray5112;
  782                 data = powerArray[headerInfo11A].pDataPerChannel;
  783                 numChannels = powerArray[headerInfo11A].numChannels;
  784         } else if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan)) {
  785                 /* XXX - is this correct? Should we also use the same power for turbo G? */
  786                 powerArray = ee->ee_modePowerArray5112;
  787                 data = powerArray[headerInfo11G].pDataPerChannel;
  788                 numChannels = powerArray[headerInfo11G].numChannels;
  789         } else if (IEEE80211_IS_CHAN_B(chan)) {
  790                 powerArray = ee->ee_modePowerArray5112;
  791                 data = powerArray[headerInfo11B].pDataPerChannel;
  792                 numChannels = powerArray[headerInfo11B].numChannels;
  793         } else {
  794                 return (AH_TRUE);
  795         }
  796         /* Make sure the channel is in the range of the TP values 
  797          *  (freq piers)
  798          */
  799         if (numChannels < 1)
  800                 return(AH_FALSE);
  801 
  802         if ((freq < data[0].channelValue) ||
  803             (freq > data[numChannels-1].channelValue)) {
  804                 if (freq < data[0].channelValue) {
  805                         *maxPow = data[0].maxPower_t4;
  806                         *minPow = ar5112GetMinPower(ah, &data[0]);
  807                         return(AH_TRUE);
  808                 } else {
  809                         *maxPow = data[numChannels - 1].maxPower_t4;
  810                         *minPow = ar5112GetMinPower(ah, &data[numChannels - 1]);
  811                         return(AH_TRUE);
  812                 }
  813         }
  814 
  815         /* Linearly interpolate the power value now */
  816         for (last=0,i=0;
  817              (i<numChannels) && (freq > data[i].channelValue);
  818              last=i++);
  819         totalD = data[i].channelValue - data[last].channelValue;
  820         if (totalD > 0) {
  821                 totalF = data[i].maxPower_t4 - data[last].maxPower_t4;
  822                 *maxPow = (int8_t) ((totalF*(freq-data[last].channelValue) + data[last].maxPower_t4*totalD)/totalD);
  823 
  824                 totalMin = ar5112GetMinPower(ah,&data[i]) - ar5112GetMinPower(ah, &data[last]);
  825                 *minPow = (int8_t) ((totalMin*(freq-data[last].channelValue) + ar5112GetMinPower(ah, &data[last])*totalD)/totalD);
  826                 return (AH_TRUE);
  827         } else {
  828                 if (freq == data[i].channelValue) {
  829                         *maxPow = data[i].maxPower_t4;
  830                         *minPow = ar5112GetMinPower(ah, &data[i]);
  831                         return(AH_TRUE);
  832                 } else
  833                         return(AH_FALSE);
  834         }
  835 }
  836 
  837 /*
  838  * Free memory for analog bank scratch buffers
  839  */
  840 static void
  841 ar5112RfDetach(struct ath_hal *ah)
  842 {
  843         struct ath_hal_5212 *ahp = AH5212(ah);
  844 
  845         HALASSERT(ahp->ah_rfHal != AH_NULL);
  846         ath_hal_free(ahp->ah_rfHal);
  847         ahp->ah_rfHal = AH_NULL;
  848 }
  849 
  850 /*
  851  * Allocate memory for analog bank scratch buffers
  852  * Scratch Buffer will be reinitialized every reset so no need to zero now
  853  */
  854 static HAL_BOOL
  855 ar5112RfAttach(struct ath_hal *ah, HAL_STATUS *status)
  856 {
  857         struct ath_hal_5212 *ahp = AH5212(ah);
  858         struct ar5112State *priv;
  859 
  860         HALASSERT(ah->ah_magic == AR5212_MAGIC);
  861 
  862         HALASSERT(ahp->ah_rfHal == AH_NULL);
  863         priv = ath_hal_malloc(sizeof(struct ar5112State));
  864         if (priv == AH_NULL) {
  865                 HALDEBUG(ah, HAL_DEBUG_ANY,
  866                     "%s: cannot allocate private state\n", __func__);
  867                 *status = HAL_ENOMEM;           /* XXX */
  868                 return AH_FALSE;
  869         }
  870         priv->base.rfDetach             = ar5112RfDetach;
  871         priv->base.writeRegs            = ar5112WriteRegs;
  872         priv->base.getRfBank            = ar5112GetRfBank;
  873         priv->base.setChannel           = ar5112SetChannel;
  874         priv->base.setRfRegs            = ar5112SetRfRegs;
  875         priv->base.setPowerTable        = ar5112SetPowerTable;
  876         priv->base.getChannelMaxMinPower = ar5112GetChannelMaxMinPower;
  877         priv->base.getNfAdjust          = ar5212GetNfAdjust;
  878 
  879         ahp->ah_pcdacTable = priv->pcdacTable;
  880         ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
  881         ahp->ah_rfHal = &priv->base;
  882 
  883         return AH_TRUE;
  884 }
  885 
  886 static HAL_BOOL
  887 ar5112Probe(struct ath_hal *ah)
  888 {
  889         return IS_RAD5112(ah);
  890 }
  891 AH_RF(RF5112, ar5112Probe, ar5112RfAttach);

Cache object: eff061df4db03403ccf009cdf6ef9ca3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.