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/ar2316.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 "ar5212/ar5212.h"
   27 #include "ar5212/ar5212reg.h"
   28 #include "ar5212/ar5212phy.h"
   29 
   30 #include "ah_eeprom_v3.h"
   31 
   32 #define AH_5212_2316
   33 #include "ar5212/ar5212.ini"
   34 
   35 #define N(a)    (sizeof(a)/sizeof(a[0]))
   36 
   37 typedef RAW_DATA_STRUCT_2413 RAW_DATA_STRUCT_2316;
   38 typedef RAW_DATA_PER_CHANNEL_2413 RAW_DATA_PER_CHANNEL_2316;
   39 #define PWR_TABLE_SIZE_2316 PWR_TABLE_SIZE_2413
   40 
   41 struct ar2316State {
   42         RF_HAL_FUNCS    base;           /* public state, must be first */
   43         uint16_t        pcdacTable[PWR_TABLE_SIZE_2316];
   44 
   45         uint32_t        Bank1Data[N(ar5212Bank1_2316)];
   46         uint32_t        Bank2Data[N(ar5212Bank2_2316)];
   47         uint32_t        Bank3Data[N(ar5212Bank3_2316)];
   48         uint32_t        Bank6Data[N(ar5212Bank6_2316)];
   49         uint32_t        Bank7Data[N(ar5212Bank7_2316)];
   50 
   51         /*
   52          * Private state for reduced stack usage.
   53          */
   54         /* filled out Vpd table for all pdGains (chanL) */
   55         uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL]
   56                             [MAX_PWR_RANGE_IN_HALF_DB];
   57         /* filled out Vpd table for all pdGains (chanR) */
   58         uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL]
   59                             [MAX_PWR_RANGE_IN_HALF_DB];
   60         /* filled out Vpd table for all pdGains (interpolated) */
   61         uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL]
   62                             [MAX_PWR_RANGE_IN_HALF_DB];
   63 };
   64 #define AR2316(ah)      ((struct ar2316State *) AH5212(ah)->ah_rfHal)
   65 
   66 extern  void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
   67                 uint32_t numBits, uint32_t firstBit, uint32_t column);
   68 
   69 static void
   70 ar2316WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
   71         int regWrites)
   72 {
   73         struct ath_hal_5212 *ahp = AH5212(ah);
   74 
   75         HAL_INI_WRITE_ARRAY(ah, ar5212Modes_2316, modesIndex, regWrites);
   76         HAL_INI_WRITE_ARRAY(ah, ar5212Common_2316, 1, regWrites);
   77         HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_2316, freqIndex, regWrites);
   78 
   79         /* For AP51 */
   80         if (!ahp->ah_cwCalRequire) {
   81                 OS_REG_WRITE(ah, 0xa358, (OS_REG_READ(ah, 0xa358) & ~0x2));
   82         } else {
   83                 ahp->ah_cwCalRequire = AH_FALSE;
   84         }
   85 }
   86 
   87 /*
   88  * Take the MHz channel value and set the Channel value
   89  *
   90  * ASSUMES: Writes enabled to analog bus
   91  */
   92 static HAL_BOOL
   93 ar2316SetChannel(struct ath_hal *ah,  struct ieee80211_channel *chan)
   94 {
   95         uint16_t freq = ath_hal_gethwchannel(ah, chan);
   96         uint32_t channelSel  = 0;
   97         uint32_t bModeSynth  = 0;
   98         uint32_t aModeRefSel = 0;
   99         uint32_t reg32       = 0;
  100 
  101         OS_MARK(ah, AH_MARK_SETCHANNEL, freq);
  102 
  103         if (freq < 4800) {
  104                 uint32_t txctl;
  105 
  106                 if (((freq - 2192) % 5) == 0) {
  107                         channelSel = ((freq - 672) * 2 - 3040)/10;
  108                         bModeSynth = 0;
  109                 } else if (((freq - 2224) % 5) == 0) {
  110                         channelSel = ((freq - 704) * 2 - 3040) / 10;
  111                         bModeSynth = 1;
  112                 } else {
  113                         HALDEBUG(ah, HAL_DEBUG_ANY,
  114                             "%s: invalid channel %u MHz\n",
  115                             __func__, freq);
  116                         return AH_FALSE;
  117                 }
  118 
  119                 channelSel = (channelSel << 2) & 0xff;
  120                 channelSel = ath_hal_reverseBits(channelSel, 8);
  121 
  122                 txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
  123                 if (freq == 2484) {
  124                         /* Enable channel spreading for channel 14 */
  125                         OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
  126                                 txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
  127                 } else {
  128                         OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
  129                                 txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
  130                 }
  131         } else if ((freq % 20) == 0 && freq >= 5120) {
  132                 channelSel = ath_hal_reverseBits(
  133                         ((freq - 4800) / 20 << 2), 8);
  134                 aModeRefSel = ath_hal_reverseBits(3, 2);
  135         } else if ((freq % 10) == 0) {
  136                 channelSel = ath_hal_reverseBits(
  137                         ((freq - 4800) / 10 << 1), 8);
  138                 aModeRefSel = ath_hal_reverseBits(2, 2);
  139         } else if ((freq % 5) == 0) {
  140                 channelSel = ath_hal_reverseBits(
  141                         (freq - 4800) / 5, 8);
  142                 aModeRefSel = ath_hal_reverseBits(1, 2);
  143         } else {
  144                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
  145                     __func__, freq);
  146                 return AH_FALSE;
  147         }
  148 
  149         reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
  150                         (1 << 12) | 0x1;
  151         OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
  152 
  153         reg32 >>= 8;
  154         OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
  155 
  156         AH_PRIVATE(ah)->ah_curchan = chan;
  157         return AH_TRUE;
  158 }
  159 
  160 /*
  161  * Reads EEPROM header info from device structure and programs
  162  * all rf registers
  163  *
  164  * REQUIRES: Access to the analog rf device
  165  */
  166 static HAL_BOOL
  167 ar2316SetRfRegs(struct ath_hal *ah, const struct ieee80211_channel *chan,
  168         uint16_t modesIndex, uint16_t *rfXpdGain)
  169 {
  170 #define RF_BANK_SETUP(_priv, _ix, _col) do {                                \
  171         int i;                                                              \
  172         for (i = 0; i < N(ar5212Bank##_ix##_2316); i++)                     \
  173                 (_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_2316[i][_col];\
  174 } while (0)
  175         struct ath_hal_5212 *ahp = AH5212(ah);
  176         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
  177         uint16_t ob2GHz = 0, db2GHz = 0;
  178         struct ar2316State *priv = AR2316(ah);
  179         int regWrites = 0;
  180 
  181         HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan %u/0x%x modesIndex %u\n",
  182             __func__, chan->ic_freq, chan->ic_flags, modesIndex);
  183 
  184         HALASSERT(priv != AH_NULL);
  185 
  186         /* Setup rf parameters */
  187         if (IEEE80211_IS_CHAN_B(chan)) {
  188                 ob2GHz = ee->ee_obFor24;
  189                 db2GHz = ee->ee_dbFor24;
  190         } else {
  191                 ob2GHz = ee->ee_obFor24g;
  192                 db2GHz = ee->ee_dbFor24g;
  193         }
  194 
  195         /* Bank 1 Write */
  196         RF_BANK_SETUP(priv, 1, 1);
  197 
  198         /* Bank 2 Write */
  199         RF_BANK_SETUP(priv, 2, modesIndex);
  200 
  201         /* Bank 3 Write */
  202         RF_BANK_SETUP(priv, 3, modesIndex);
  203 
  204         /* Bank 6 Write */
  205         RF_BANK_SETUP(priv, 6, modesIndex);
  206 
  207         ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz,   3, 178, 0);
  208         ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz,   3, 175, 0);
  209 
  210         /* Bank 7 Setup */
  211         RF_BANK_SETUP(priv, 7, modesIndex);
  212 
  213         /* Write Analog registers */
  214         HAL_INI_WRITE_BANK(ah, ar5212Bank1_2316, priv->Bank1Data, regWrites);
  215         HAL_INI_WRITE_BANK(ah, ar5212Bank2_2316, priv->Bank2Data, regWrites);
  216         HAL_INI_WRITE_BANK(ah, ar5212Bank3_2316, priv->Bank3Data, regWrites);
  217         HAL_INI_WRITE_BANK(ah, ar5212Bank6_2316, priv->Bank6Data, regWrites);
  218         HAL_INI_WRITE_BANK(ah, ar5212Bank7_2316, priv->Bank7Data, regWrites);
  219 
  220         /* Now that we have reprogrammed rfgain value, clear the flag. */
  221         ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
  222 
  223         return AH_TRUE;
  224 #undef  RF_BANK_SETUP
  225 }
  226 
  227 /*
  228  * Return a reference to the requested RF Bank.
  229  */
  230 static uint32_t *
  231 ar2316GetRfBank(struct ath_hal *ah, int bank)
  232 {
  233         struct ar2316State *priv = AR2316(ah);
  234 
  235         HALASSERT(priv != AH_NULL);
  236         switch (bank) {
  237         case 1: return priv->Bank1Data;
  238         case 2: return priv->Bank2Data;
  239         case 3: return priv->Bank3Data;
  240         case 6: return priv->Bank6Data;
  241         case 7: return priv->Bank7Data;
  242         }
  243         HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
  244             __func__, bank);
  245         return AH_NULL;
  246 }
  247 
  248 /*
  249  * Return indices surrounding the value in sorted integer lists.
  250  *
  251  * NB: the input list is assumed to be sorted in ascending order
  252  */
  253 static void
  254 GetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize,
  255                           uint32_t *vlo, uint32_t *vhi)
  256 {
  257         int16_t target = v;
  258         const int16_t *ep = lp+listSize;
  259         const int16_t *tp;
  260 
  261         /*
  262          * Check first and last elements for out-of-bounds conditions.
  263          */
  264         if (target < lp[0]) {
  265                 *vlo = *vhi = 0;
  266                 return;
  267         }
  268         if (target >= ep[-1]) {
  269                 *vlo = *vhi = listSize - 1;
  270                 return;
  271         }
  272 
  273         /* look for value being near or between 2 values in list */
  274         for (tp = lp; tp < ep; tp++) {
  275                 /*
  276                  * If value is close to the current value of the list
  277                  * then target is not between values, it is one of the values
  278                  */
  279                 if (*tp == target) {
  280                         *vlo = *vhi = tp - (const int16_t *) lp;
  281                         return;
  282                 }
  283                 /*
  284                  * Look for value being between current value and next value
  285                  * if so return these 2 values
  286                  */
  287                 if (target < tp[1]) {
  288                         *vlo = tp - (const int16_t *) lp;
  289                         *vhi = *vlo + 1;
  290                         return;
  291                 }
  292         }
  293 }
  294 
  295 /*
  296  * Fill the Vpdlist for indices Pmax-Pmin
  297  */
  298 static HAL_BOOL
  299 ar2316FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t  Pmax,
  300                    const int16_t *pwrList, const int16_t *VpdList,
  301                    uint16_t numIntercepts, uint16_t retVpdList[][64])
  302 {
  303         uint16_t ii, jj, kk;
  304         int16_t currPwr = (int16_t)(2*Pmin);
  305         /* since Pmin is pwr*2 and pwrList is 4*pwr */
  306         uint32_t  idxL, idxR;
  307 
  308         ii = 0;
  309         jj = 0;
  310 
  311         if (numIntercepts < 2)
  312                 return AH_FALSE;
  313 
  314         while (ii <= (uint16_t)(Pmax - Pmin)) {
  315                 GetLowerUpperIndex(currPwr, pwrList, numIntercepts, 
  316                                          &(idxL), &(idxR));
  317                 if (idxR < 1)
  318                         idxR = 1;                       /* extrapolate below */
  319                 if (idxL == (uint32_t)(numIntercepts - 1))
  320                         idxL = numIntercepts - 2;       /* extrapolate above */
  321                 if (pwrList[idxL] == pwrList[idxR])
  322                         kk = VpdList[idxL];
  323                 else
  324                         kk = (uint16_t)
  325                                 (((currPwr - pwrList[idxL])*VpdList[idxR]+ 
  326                                   (pwrList[idxR] - currPwr)*VpdList[idxL])/
  327                                  (pwrList[idxR] - pwrList[idxL]));
  328                 retVpdList[pdGainIdx][ii] = kk;
  329                 ii++;
  330                 currPwr += 2;                           /* half dB steps */
  331         }
  332 
  333         return AH_TRUE;
  334 }
  335 
  336 /*
  337  * Returns interpolated or the scaled up interpolated value
  338  */
  339 static int16_t
  340 interpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
  341         int16_t targetLeft, int16_t targetRight)
  342 {
  343         int16_t rv;
  344 
  345         if (srcRight != srcLeft) {
  346                 rv = ((target - srcLeft)*targetRight +
  347                       (srcRight - target)*targetLeft) / (srcRight - srcLeft);
  348         } else {
  349                 rv = targetLeft;
  350         }
  351         return rv;
  352 }
  353 
  354 /*
  355  * Uses the data points read from EEPROM to reconstruct the pdadc power table
  356  * Called by ar2316SetPowerTable()
  357  */
  358 static int 
  359 ar2316getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel,
  360                 const RAW_DATA_STRUCT_2316 *pRawDataset,
  361                 uint16_t pdGainOverlap_t2, 
  362                 int16_t  *pMinCalPower, uint16_t pPdGainBoundaries[], 
  363                 uint16_t pPdGainValues[], uint16_t pPDADCValues[]) 
  364 {
  365         struct ar2316State *priv = AR2316(ah);
  366 #define VpdTable_L      priv->vpdTable_L
  367 #define VpdTable_R      priv->vpdTable_R
  368 #define VpdTable_I      priv->vpdTable_I
  369         uint32_t ii, jj, kk;
  370         int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */
  371         uint32_t idxL, idxR;
  372         uint32_t numPdGainsUsed = 0;
  373         /* 
  374          * If desired to support -ve power levels in future, just
  375          * change pwr_I_0 to signed 5-bits.
  376          */
  377         int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
  378         /* to accommodate -ve power levels later on. */
  379         int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
  380         /* to accommodate -ve power levels later on */
  381         uint16_t numVpd = 0;
  382         uint16_t Vpd_step;
  383         int16_t tmpVal ; 
  384         uint32_t sizeCurrVpdTable, maxIndex, tgtIndex;
  385 
  386         /* Get upper lower index */
  387         GetLowerUpperIndex(channel, pRawDataset->pChannels,
  388                                  pRawDataset->numChannels, &(idxL), &(idxR));
  389 
  390         for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
  391                 jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
  392                 /* work backwards 'cause highest pdGain for lowest power */
  393                 numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd;
  394                 if (numVpd > 0) {
  395                         pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain;
  396                         Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0];
  397                         if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) {
  398                                 Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0];
  399                         }
  400                         Pmin_t2[numPdGainsUsed] = (int16_t)
  401                                 (Pmin_t2[numPdGainsUsed] / 2);
  402                         Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1];
  403                         if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1])
  404                                 Pmax_t2[numPdGainsUsed] = 
  405                                         pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1];
  406                         Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2);
  407                         ar2316FillVpdTable(
  408                                            numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], 
  409                                            &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]), 
  410                                            &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L
  411                                            );
  412                         ar2316FillVpdTable(
  413                                            numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed], 
  414                                            &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]),
  415                                            &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R
  416                                            );
  417                         for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) {
  418                                 VpdTable_I[numPdGainsUsed][kk] = 
  419                                         interpolate_signed(
  420                                                            channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR],
  421                                                            (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]);
  422                         }
  423                         /* fill VpdTable_I for this pdGain */
  424                         numPdGainsUsed++;
  425                 }
  426                 /* if this pdGain is used */
  427         }
  428 
  429         *pMinCalPower = Pmin_t2[0];
  430         kk = 0; /* index for the final table */
  431         for (ii = 0; ii < numPdGainsUsed; ii++) {
  432                 if (ii == (numPdGainsUsed - 1))
  433                         pPdGainBoundaries[ii] = Pmax_t2[ii] +
  434                                 PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB;
  435                 else 
  436                         pPdGainBoundaries[ii] = (uint16_t)
  437                                 ((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 );
  438                 if (pPdGainBoundaries[ii] > 63) {
  439                         HALDEBUG(ah, HAL_DEBUG_ANY,
  440                             "%s: clamp pPdGainBoundaries[%d] %d\n",
  441                             __func__, ii, pPdGainBoundaries[ii]);/*XXX*/
  442                         pPdGainBoundaries[ii] = 63;
  443                 }
  444 
  445                 /* Find starting index for this pdGain */
  446                 if (ii == 0) 
  447                         ss = 0; /* for the first pdGain, start from index 0 */
  448                 else 
  449                         ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) - 
  450                                 pdGainOverlap_t2;
  451                 Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]);
  452                 Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
  453                 /*
  454                  *-ve ss indicates need to extrapolate data below for this pdGain
  455                  */
  456                 while (ss < 0) {
  457                         tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step);
  458                         pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal);
  459                         ss++;
  460                 }
  461 
  462                 sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii];
  463                 tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii];
  464                 maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
  465 
  466                 while (ss < (int16_t)maxIndex)
  467                         pPDADCValues[kk++] = VpdTable_I[ii][ss++];
  468 
  469                 Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] -
  470                                        VpdTable_I[ii][sizeCurrVpdTable-2]);
  471                 Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);           
  472                 /*
  473                  * for last gain, pdGainBoundary == Pmax_t2, so will 
  474                  * have to extrapolate
  475                  */
  476                 if (tgtIndex > maxIndex) {      /* need to extrapolate above */
  477                         while(ss < (int16_t)tgtIndex) {
  478                                 tmpVal = (uint16_t)
  479                                         (VpdTable_I[ii][sizeCurrVpdTable-1] + 
  480                                          (ss-maxIndex)*Vpd_step);
  481                                 pPDADCValues[kk++] = (tmpVal > 127) ? 
  482                                         127 : tmpVal;
  483                                 ss++;
  484                         }
  485                 }                               /* extrapolated above */
  486         }                                       /* for all pdGainUsed */
  487 
  488         while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) {
  489                 pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1];
  490                 ii++;
  491         }
  492         while (kk < 128) {
  493                 pPDADCValues[kk] = pPDADCValues[kk-1];
  494                 kk++;
  495         }
  496 
  497         return numPdGainsUsed;
  498 #undef VpdTable_L
  499 #undef VpdTable_R
  500 #undef VpdTable_I
  501 }
  502 
  503 static HAL_BOOL
  504 ar2316SetPowerTable(struct ath_hal *ah,
  505         int16_t *minPower, int16_t *maxPower,
  506         const struct ieee80211_channel *chan, 
  507         uint16_t *rfXpdGain)
  508 {
  509         struct ath_hal_5212 *ahp = AH5212(ah);
  510         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
  511         const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL;
  512         uint16_t pdGainOverlap_t2;
  513         int16_t minCalPower2316_t2;
  514         uint16_t *pdadcValues = ahp->ah_pcdacTable;
  515         uint16_t gainBoundaries[4];
  516         uint32_t reg32, regoffset;
  517         int i, numPdGainsUsed;
  518 #ifndef AH_USE_INIPDGAIN
  519         uint32_t tpcrg1;
  520 #endif
  521 
  522         HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
  523             __func__, chan->ic_freq, chan->ic_flags);
  524 
  525         if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan))
  526                 pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
  527         else if (IEEE80211_IS_CHAN_B(chan))
  528                 pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
  529         else {
  530                 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: illegal mode\n", __func__);
  531                 return AH_FALSE;
  532         }
  533 
  534         pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5),
  535                                           AR_PHY_TPCRG5_PD_GAIN_OVERLAP);
  536     
  537         numPdGainsUsed = ar2316getGainBoundariesAndPdadcsForPowers(ah,
  538                 chan->channel, pRawDataset, pdGainOverlap_t2,
  539                 &minCalPower2316_t2,gainBoundaries, rfXpdGain, pdadcValues);
  540         HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
  541 
  542 #ifdef AH_USE_INIPDGAIN
  543         /*
  544          * Use pd_gains curve from eeprom; Atheros always uses
  545          * the default curve from the ini file but some vendors
  546          * (e.g. Zcomax) want to override this curve and not
  547          * honoring their settings results in tx power 5dBm low.
  548          */
  549         OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, 
  550                          (pRawDataset->pDataPerChannel[0].numPdGains - 1));
  551 #else
  552         tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
  553         tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
  554                   | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
  555         switch (numPdGainsUsed) {
  556         case 3:
  557                 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3;
  558                 tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3);
  559                 /* fall thru... */
  560         case 2:
  561                 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2;
  562                 tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2);
  563                 /* fall thru... */
  564         case 1:
  565                 tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1;
  566                 tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1);
  567                 break;
  568         }
  569 #ifdef AH_DEBUG
  570         if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1))
  571                 HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default "
  572                     "pd_gains (default 0x%x, calculated 0x%x)\n",
  573                     __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
  574 #endif
  575         OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
  576 #endif
  577 
  578         /*
  579          * Note the pdadc table may not start at 0 dBm power, could be
  580          * negative or greater than 0.  Need to offset the power
  581          * values by the amount of minPower for griffin
  582          */
  583         if (minCalPower2316_t2 != 0)
  584                 ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower2316_t2);
  585         else
  586                 ahp->ah_txPowerIndexOffset = 0;
  587 
  588         /* Finally, write the power values into the baseband power table */
  589         regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */
  590         for (i = 0; i < 32; i++) {
  591                 reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0)  | 
  592                         ((pdadcValues[4*i + 1] & 0xFF) << 8)  |
  593                         ((pdadcValues[4*i + 2] & 0xFF) << 16) |
  594                         ((pdadcValues[4*i + 3] & 0xFF) << 24) ;        
  595                 OS_REG_WRITE(ah, regoffset, reg32);
  596                 regoffset += 4;
  597         }
  598 
  599         OS_REG_WRITE(ah, AR_PHY_TPCRG5, 
  600                      SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | 
  601                      SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
  602                      SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
  603                      SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
  604                      SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
  605 
  606         return AH_TRUE;
  607 }
  608 
  609 static int16_t
  610 ar2316GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data)
  611 {
  612         uint32_t ii,jj;
  613         uint16_t Pmin=0,numVpd;
  614 
  615         for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
  616                 jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
  617                 /* work backwards 'cause highest pdGain for lowest power */
  618                 numVpd = data->pDataPerPDGain[jj].numVpd;
  619                 if (numVpd > 0) {
  620                         Pmin = data->pDataPerPDGain[jj].pwr_t4[0];
  621                         return(Pmin);
  622                 }
  623         }
  624         return(Pmin);
  625 }
  626 
  627 static int16_t
  628 ar2316GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2316 *data)
  629 {
  630         uint32_t ii;
  631         uint16_t Pmax=0,numVpd;
  632 
  633         for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
  634                 /* work forwards cuase lowest pdGain for highest power */
  635                 numVpd = data->pDataPerPDGain[ii].numVpd;
  636                 if (numVpd > 0) {
  637                         Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1];
  638                         return(Pmax);
  639                 }
  640         }
  641         return(Pmax);
  642 }
  643 
  644 static HAL_BOOL
  645 ar2316GetChannelMaxMinPower(struct ath_hal *ah,
  646         const struct ieee80211_channel *chan,
  647         int16_t *maxPow, int16_t *minPow)
  648 {
  649         uint16_t freq = chan->ic_freq;          /* NB: never mapped */
  650         const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
  651         const RAW_DATA_STRUCT_2316 *pRawDataset = AH_NULL;
  652         const RAW_DATA_PER_CHANNEL_2316 *data=AH_NULL;
  653         uint16_t numChannels;
  654         int totalD,totalF, totalMin,last, i;
  655 
  656         *maxPow = 0;
  657 
  658         if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan))
  659                 pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
  660         else if (IEEE80211_IS_CHAN_B(chan))
  661                 pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
  662         else
  663                 return(AH_FALSE);
  664 
  665         numChannels = pRawDataset->numChannels;
  666         data = pRawDataset->pDataPerChannel;
  667 
  668         /* Make sure the channel is in the range of the TP values 
  669          *  (freq piers)
  670          */
  671         if (numChannels < 1)
  672                 return(AH_FALSE);
  673 
  674         if ((freq < data[0].channelValue) ||
  675             (freq > data[numChannels-1].channelValue)) {
  676                 if (freq < data[0].channelValue) {
  677                         *maxPow = ar2316GetMaxPower(ah, &data[0]);
  678                         *minPow = ar2316GetMinPower(ah, &data[0]);
  679                         return(AH_TRUE);
  680                 } else {
  681                         *maxPow = ar2316GetMaxPower(ah, &data[numChannels - 1]);
  682                         *minPow = ar2316GetMinPower(ah, &data[numChannels - 1]);
  683                         return(AH_TRUE);
  684                 }
  685         }
  686 
  687         /* Linearly interpolate the power value now */
  688         for (last=0,i=0; (i<numChannels) && (freq > data[i].channelValue);
  689              last = i++);
  690         totalD = data[i].channelValue - data[last].channelValue;
  691         if (totalD > 0) {
  692                 totalF = ar2316GetMaxPower(ah, &data[i]) - ar2316GetMaxPower(ah, &data[last]);
  693                 *maxPow = (int8_t) ((totalF*(freq-data[last].channelValue) + 
  694                                      ar2316GetMaxPower(ah, &data[last])*totalD)/totalD);
  695                 totalMin = ar2316GetMinPower(ah, &data[i]) - ar2316GetMinPower(ah, &data[last]);
  696                 *minPow = (int8_t) ((totalMin*(freq-data[last].channelValue) +
  697                                      ar2316GetMinPower(ah, &data[last])*totalD)/totalD);
  698                 return(AH_TRUE);
  699         } else {
  700                 if (freq == data[i].channelValue) {
  701                         *maxPow = ar2316GetMaxPower(ah, &data[i]);
  702                         *minPow = ar2316GetMinPower(ah, &data[i]);
  703                         return(AH_TRUE);
  704                 } else
  705                         return(AH_FALSE);
  706         }
  707 }
  708 
  709 /*
  710  * Free memory for analog bank scratch buffers
  711  */
  712 static void
  713 ar2316RfDetach(struct ath_hal *ah)
  714 {
  715         struct ath_hal_5212 *ahp = AH5212(ah);
  716 
  717         HALASSERT(ahp->ah_rfHal != AH_NULL);
  718         ath_hal_free(ahp->ah_rfHal);
  719         ahp->ah_rfHal = AH_NULL;
  720 }
  721 
  722 /*
  723  * Allocate memory for private state.
  724  * Scratch Buffer will be reinitialized every reset so no need to zero now
  725  */
  726 static HAL_BOOL
  727 ar2316RfAttach(struct ath_hal *ah, HAL_STATUS *status)
  728 {
  729         struct ath_hal_5212 *ahp = AH5212(ah);
  730         struct ar2316State *priv;
  731 
  732         HALASSERT(ah->ah_magic == AR5212_MAGIC);
  733 
  734         HALASSERT(ahp->ah_rfHal == AH_NULL);
  735         priv = ath_hal_malloc(sizeof(struct ar2316State));
  736         if (priv == AH_NULL) {
  737                 HALDEBUG(ah, HAL_DEBUG_ANY,
  738                     "%s: cannot allocate private state\n", __func__);
  739                 *status = HAL_ENOMEM;           /* XXX */
  740                 return AH_FALSE;
  741         }
  742         priv->base.rfDetach             = ar2316RfDetach;
  743         priv->base.writeRegs            = ar2316WriteRegs;
  744         priv->base.getRfBank            = ar2316GetRfBank;
  745         priv->base.setChannel           = ar2316SetChannel;
  746         priv->base.setRfRegs            = ar2316SetRfRegs;
  747         priv->base.setPowerTable        = ar2316SetPowerTable;
  748         priv->base.getChannelMaxMinPower = ar2316GetChannelMaxMinPower;
  749         priv->base.getNfAdjust          = ar5212GetNfAdjust;
  750 
  751         ahp->ah_pcdacTable = priv->pcdacTable;
  752         ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
  753         ahp->ah_rfHal = &priv->base;
  754 
  755         ahp->ah_cwCalRequire = AH_TRUE;         /* force initial cal */
  756 
  757         return AH_TRUE;
  758 }
  759 
  760 static HAL_BOOL
  761 ar2316Probe(struct ath_hal *ah)
  762 {
  763         return IS_2316(ah);
  764 }
  765 AH_RF(RF2316, ar2316Probe, ar2316RfAttach);

Cache object: 651191cf085251130e4adae610f5cdc1


[ 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.