iPXE
ath9k_eeprom_9287.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008-2011 Atheros Communications Inc.
00003  *
00004  * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
00005  * Original from Linux kernel 3.0.1
00006  *
00007  * Permission to use, copy, modify, and/or distribute this software for any
00008  * purpose with or without fee is hereby granted, provided that the above
00009  * copyright notice and this permission notice appear in all copies.
00010  *
00011  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00012  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00013  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00014  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00015  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00016  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00017  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00018  */
00019 
00020 #include <ipxe/io.h>
00021 
00022 #include "hw.h"
00023 #include "ar9002_phy.h"
00024 
00025 #define SIZE_EEPROM_AR9287 (sizeof(struct ar9287_eeprom) / sizeof(u16))
00026 
00027 static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
00028 {
00029         return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
00030 }
00031 
00032 static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
00033 {
00034         return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
00035 }
00036 
00037 static int __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
00038 {
00039         struct ar9287_eeprom *eep = &ah->eeprom.map9287;
00040         struct ath_common *common = ath9k_hw_common(ah);
00041         u16 *eep_data;
00042         unsigned int addr;
00043         int eep_start_loc = AR9287_EEP_START_LOC;
00044         eep_data = (u16 *)eep;
00045 
00046         for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
00047                 if (!ath9k_hw_nvram_read(common, addr + eep_start_loc,
00048                                          eep_data)) {
00049                         DBG("ath9k: "
00050                                 "Unable to read eeprom region\n");
00051                         return 0;
00052                 }
00053                 eep_data++;
00054         }
00055 
00056         return 1;
00057 }
00058 
00059 static int __ath9k_hw_usb_ar9287_fill_eeprom(struct ath_hw *ah)
00060 {
00061         u16 *eep_data = (u16 *)&ah->eeprom.map9287;
00062 
00063         ath9k_hw_usb_gen_fill_eeprom(ah, eep_data,
00064                                      AR9287_HTC_EEP_START_LOC,
00065                                      SIZE_EEPROM_AR9287);
00066         return 1;
00067 }
00068 
00069 static int ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
00070 {
00071         struct ath_common *common = ath9k_hw_common(ah);
00072 
00073         if (!ath9k_hw_use_flash(ah)) {
00074                 DBG2("ath9k: "
00075                         "Reading from EEPROM, not flash\n");
00076         }
00077 
00078         if (common->bus_ops->ath_bus_type == ATH_USB)
00079                 return __ath9k_hw_usb_ar9287_fill_eeprom(ah);
00080         else
00081                 return __ath9k_hw_ar9287_fill_eeprom(ah);
00082 }
00083 
00084 static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
00085 {
00086         u32 sum = 0, el, integer;
00087         u16 temp, word, magic, magic2, *eepdata;
00088         unsigned int i, addr;
00089         int need_swap = 0;
00090         struct ar9287_eeprom *eep = &ah->eeprom.map9287;
00091         struct ath_common *common = ath9k_hw_common(ah);
00092 
00093         if (!ath9k_hw_use_flash(ah)) {
00094                 if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
00095                                          &magic)) {
00096                         DBG("ath9k: Reading Magic # failed\n");
00097                         return 0;
00098                 }
00099 
00100                 DBG2("ath9k: "
00101                         "Read Magic = 0x%04X\n", magic);
00102 
00103                 if (magic != AR5416_EEPROM_MAGIC) {
00104                         magic2 = swab16(magic);
00105 
00106                         if (magic2 == AR5416_EEPROM_MAGIC) {
00107                                 need_swap = 1;
00108                                 eepdata = (u16 *)(&ah->eeprom);
00109 
00110                                 for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
00111                                         temp = swab16(*eepdata);
00112                                         *eepdata = temp;
00113                                         eepdata++;
00114                                 }
00115                         } else {
00116                                 DBG("ath9k: "
00117                                         "Invalid EEPROM Magic. Endianness mismatch.\n");
00118                                 return -EINVAL;
00119                         }
00120                 }
00121         }
00122 
00123         DBG2("ath9k: need_swap = %s.\n",
00124                 need_swap ? "True" : "False");
00125 
00126         if (need_swap)
00127                 el = swab16(ah->eeprom.map9287.baseEepHeader.length);
00128         else
00129                 el = ah->eeprom.map9287.baseEepHeader.length;
00130 
00131         if (el > sizeof(struct ar9287_eeprom))
00132                 el = sizeof(struct ar9287_eeprom) / sizeof(u16);
00133         else
00134                 el = el / sizeof(u16);
00135 
00136         eepdata = (u16 *)(&ah->eeprom);
00137 
00138         for (i = 0; i < el; i++)
00139                 sum ^= *eepdata++;
00140 
00141         if (need_swap) {
00142                 word = swab16(eep->baseEepHeader.length);
00143                 eep->baseEepHeader.length = word;
00144 
00145                 word = swab16(eep->baseEepHeader.checksum);
00146                 eep->baseEepHeader.checksum = word;
00147 
00148                 word = swab16(eep->baseEepHeader.version);
00149                 eep->baseEepHeader.version = word;
00150 
00151                 word = swab16(eep->baseEepHeader.regDmn[0]);
00152                 eep->baseEepHeader.regDmn[0] = word;
00153 
00154                 word = swab16(eep->baseEepHeader.regDmn[1]);
00155                 eep->baseEepHeader.regDmn[1] = word;
00156 
00157                 word = swab16(eep->baseEepHeader.rfSilent);
00158                 eep->baseEepHeader.rfSilent = word;
00159 
00160                 word = swab16(eep->baseEepHeader.blueToothOptions);
00161                 eep->baseEepHeader.blueToothOptions = word;
00162 
00163                 word = swab16(eep->baseEepHeader.deviceCap);
00164                 eep->baseEepHeader.deviceCap = word;
00165 
00166                 integer = swab32(eep->modalHeader.antCtrlCommon);
00167                 eep->modalHeader.antCtrlCommon = integer;
00168 
00169                 for (i = 0; i < AR9287_MAX_CHAINS; i++) {
00170                         integer = swab32(eep->modalHeader.antCtrlChain[i]);
00171                         eep->modalHeader.antCtrlChain[i] = integer;
00172                 }
00173 
00174                 for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
00175                         word = swab16(eep->modalHeader.spurChans[i].spurChan);
00176                         eep->modalHeader.spurChans[i].spurChan = word;
00177                 }
00178         }
00179 
00180         if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
00181             || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
00182                 DBG("ath9k: Bad EEPROM checksum 0x%x or revision 0x%04x\n",
00183                         sum, ah->eep_ops->get_eeprom_ver(ah));
00184                 return -EINVAL;
00185         }
00186 
00187         return 0;
00188 }
00189 
00190 static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
00191                                       enum eeprom_param param)
00192 {
00193         struct ar9287_eeprom *eep = &ah->eeprom.map9287;
00194         struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
00195         struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
00196         u16 ver_minor;
00197 
00198         ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
00199 
00200         switch (param) {
00201         case EEP_NFTHRESH_2:
00202                 return pModal->noiseFloorThreshCh[0];
00203         case EEP_MAC_LSW:
00204                 return pBase->macAddr[0] << 8 | pBase->macAddr[1];
00205         case EEP_MAC_MID:
00206                 return pBase->macAddr[2] << 8 | pBase->macAddr[3];
00207         case EEP_MAC_MSW:
00208                 return pBase->macAddr[4] << 8 | pBase->macAddr[5];
00209         case EEP_REG_0:
00210                 return pBase->regDmn[0];
00211         case EEP_REG_1:
00212                 return pBase->regDmn[1];
00213         case EEP_OP_CAP:
00214                 return pBase->deviceCap;
00215         case EEP_OP_MODE:
00216                 return pBase->opCapFlags;
00217         case EEP_RF_SILENT:
00218                 return pBase->rfSilent;
00219         case EEP_MINOR_REV:
00220                 return ver_minor;
00221         case EEP_TX_MASK:
00222                 return pBase->txMask;
00223         case EEP_RX_MASK:
00224                 return pBase->rxMask;
00225         case EEP_DEV_TYPE:
00226                 return pBase->deviceType;
00227         case EEP_OL_PWRCTRL:
00228                 return pBase->openLoopPwrCntl;
00229         case EEP_TEMPSENSE_SLOPE:
00230                 if (ver_minor >= AR9287_EEP_MINOR_VER_2)
00231                         return pBase->tempSensSlope;
00232                 else
00233                         return 0;
00234         case EEP_TEMPSENSE_SLOPE_PAL_ON:
00235                 if (ver_minor >= AR9287_EEP_MINOR_VER_3)
00236                         return pBase->tempSensSlopePalOn;
00237                 else
00238                         return 0;
00239         default:
00240                 return 0;
00241         }
00242 }
00243 
00244 static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
00245                             struct ath9k_channel *chan,
00246                             struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
00247                             u8 *pCalChans,  u16 availPiers, int8_t *pPwr)
00248 {
00249         u16 idxL = 0, idxR = 0, numPiers;
00250         int match;
00251         struct chan_centers centers;
00252 
00253         ath9k_hw_get_channel_centers(ah, chan, &centers);
00254 
00255         for (numPiers = 0; numPiers < availPiers; numPiers++) {
00256                 if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED)
00257                         break;
00258         }
00259 
00260         match = ath9k_hw_get_lower_upper_index(
00261                 (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
00262                 pCalChans, numPiers, &idxL, &idxR);
00263 
00264         if (match) {
00265                 *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
00266         } else {
00267                 *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
00268                          (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
00269         }
00270 
00271 }
00272 
00273 static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
00274                                           int32_t txPower, u16 chain)
00275 {
00276         u32 tmpVal;
00277         u32 a;
00278 
00279         /* Enable OLPC for chain 0 */
00280 
00281         tmpVal = REG_READ(ah, 0xa270);
00282         tmpVal = tmpVal & 0xFCFFFFFF;
00283         tmpVal = tmpVal | (0x3 << 24);
00284         REG_WRITE(ah, 0xa270, tmpVal);
00285 
00286         /* Enable OLPC for chain 1 */
00287 
00288         tmpVal = REG_READ(ah, 0xb270);
00289         tmpVal = tmpVal & 0xFCFFFFFF;
00290         tmpVal = tmpVal | (0x3 << 24);
00291         REG_WRITE(ah, 0xb270, tmpVal);
00292 
00293         /* Write the OLPC ref power for chain 0 */
00294 
00295         if (chain == 0) {
00296                 tmpVal = REG_READ(ah, 0xa398);
00297                 tmpVal = tmpVal & 0xff00ffff;
00298                 a = (txPower)&0xff;
00299                 tmpVal = tmpVal | (a << 16);
00300                 REG_WRITE(ah, 0xa398, tmpVal);
00301         }
00302 
00303         /* Write the OLPC ref power for chain 1 */
00304 
00305         if (chain == 1) {
00306                 tmpVal = REG_READ(ah, 0xb398);
00307                 tmpVal = tmpVal & 0xff00ffff;
00308                 a = (txPower)&0xff;
00309                 tmpVal = tmpVal | (a << 16);
00310                 REG_WRITE(ah, 0xb398, tmpVal);
00311         }
00312 }
00313 
00314 static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
00315                                                 struct ath9k_channel *chan,
00316                                                 int16_t *pTxPowerIndexOffset)
00317 {
00318         struct cal_data_per_freq_ar9287 *pRawDataset;
00319         struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
00320         u8 *pCalBChans = NULL;
00321         u16 pdGainOverlap_t2;
00322         u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
00323         u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
00324         u16 numPiers = 0, i, j;
00325         u16 numXpdGain, xpdMask;
00326         u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
00327         u32 reg32, regOffset, regChainOffset, regval;
00328         int16_t diff = 0;
00329         struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
00330 
00331         xpdMask = pEepData->modalHeader.xpdGain;
00332 
00333         if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
00334             AR9287_EEP_MINOR_VER_2)
00335                 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
00336         else
00337                 pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
00338                                             AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
00339 
00340         if (IS_CHAN_2GHZ(chan)) {
00341                 pCalBChans = pEepData->calFreqPier2G;
00342                 numPiers = AR9287_NUM_2G_CAL_PIERS;
00343                 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
00344                         pRawDatasetOpenLoop =
00345                         (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
00346                         ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
00347                 }
00348         }
00349 
00350         numXpdGain = 0;
00351 
00352         /* Calculate the value of xpdgains from the xpdGain Mask */
00353         for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
00354                 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
00355                         if (numXpdGain >= AR5416_NUM_PD_GAINS)
00356                                 break;
00357                         xpdGainValues[numXpdGain] =
00358                                 (u16)(AR5416_PD_GAINS_IN_MASK-i);
00359                         numXpdGain++;
00360                 }
00361         }
00362 
00363         REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
00364                       (numXpdGain - 1) & 0x3);
00365         REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
00366                       xpdGainValues[0]);
00367         REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
00368                       xpdGainValues[1]);
00369         REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
00370                       xpdGainValues[2]);
00371 
00372         for (i = 0; i < AR9287_MAX_CHAINS; i++) {
00373                 regChainOffset = i * 0x1000;
00374 
00375                 if (pEepData->baseEepHeader.txMask & (1 << i)) {
00376                         pRawDatasetOpenLoop =
00377                         (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
00378 
00379                         if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
00380                                 int8_t txPower;
00381                                 ar9287_eeprom_get_tx_gain_index(ah, chan,
00382                                                         pRawDatasetOpenLoop,
00383                                                         pCalBChans, numPiers,
00384                                                         &txPower);
00385                                 ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
00386                         } else {
00387                                 pRawDataset =
00388                                         (struct cal_data_per_freq_ar9287 *)
00389                                         pEepData->calPierData2G[i];
00390 
00391                                 ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
00392                                                            pRawDataset,
00393                                                            pCalBChans, numPiers,
00394                                                            pdGainOverlap_t2,
00395                                                            gainBoundaries,
00396                                                            pdadcValues,
00397                                                            numXpdGain);
00398                         }
00399 
00400                         ENABLE_REGWRITE_BUFFER(ah);
00401 
00402                         if (i == 0) {
00403                                 if (!ath9k_hw_ar9287_get_eeprom(ah,
00404                                                         EEP_OL_PWRCTRL)) {
00405 
00406                                         regval = SM(pdGainOverlap_t2,
00407                                                     AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
00408                                                 | SM(gainBoundaries[0],
00409                                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
00410                                                 | SM(gainBoundaries[1],
00411                                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
00412                                                 | SM(gainBoundaries[2],
00413                                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
00414                                                 | SM(gainBoundaries[3],
00415                                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4);
00416 
00417                                         REG_WRITE(ah,
00418                                                   AR_PHY_TPCRG5 + regChainOffset,
00419                                                   regval);
00420                                 }
00421                         }
00422 
00423                         if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
00424                             pEepData->baseEepHeader.pwrTableOffset) {
00425                                 diff = (u16)(pEepData->baseEepHeader.pwrTableOffset -
00426                                              (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
00427                                 diff *= 2;
00428 
00429                                 for (j = 0; j < ((u16)AR5416_NUM_PDADC_VALUES-diff); j++)
00430                                         pdadcValues[j] = pdadcValues[j+diff];
00431 
00432                                 for (j = (u16)(AR5416_NUM_PDADC_VALUES-diff);
00433                                      j < AR5416_NUM_PDADC_VALUES; j++)
00434                                         pdadcValues[j] =
00435                                           pdadcValues[AR5416_NUM_PDADC_VALUES-diff];
00436                         }
00437 
00438                         if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
00439                                 regOffset = AR_PHY_BASE +
00440                                         (672 << 2) + regChainOffset;
00441 
00442                                 for (j = 0; j < 32; j++) {
00443                                         reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0)
00444                                                 | ((pdadcValues[4*j + 1] & 0xFF) << 8)
00445                                                 | ((pdadcValues[4*j + 2] & 0xFF) << 16)
00446                                                 | ((pdadcValues[4*j + 3] & 0xFF) << 24);
00447 
00448                                         REG_WRITE(ah, regOffset, reg32);
00449                                         regOffset += 4;
00450                                 }
00451                         }
00452                         REGWRITE_BUFFER_FLUSH(ah);
00453                 }
00454         }
00455 
00456         *pTxPowerIndexOffset = 0;
00457 }
00458 
00459 static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
00460                                                      struct ath9k_channel *chan,
00461                                                      int16_t *ratesArray,
00462                                                      u16 cfgCtl,
00463                                                      u16 AntennaReduction,
00464                                                      u16 twiceMaxRegulatoryPower,
00465                                                      u16 powerLimit)
00466 {
00467 #define CMP_CTL \
00468         (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
00469          pEepData->ctlIndex[i])
00470 
00471 #define CMP_NO_CTL \
00472         (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
00473          ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
00474 
00475 #define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6
00476 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10
00477 
00478         struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
00479         u16 twiceMaxEdgePower = MAX_RATE_POWER;
00480         static const u16 tpScaleReductionTable[5] =
00481                 { 0, 3, 6, 9, MAX_RATE_POWER };
00482         unsigned int i;
00483         int16_t twiceLargestAntenna;
00484         struct cal_ctl_data_ar9287 *rep;
00485         struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
00486                                     targetPowerCck = {0, {0, 0, 0, 0} };
00487         struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
00488                                     targetPowerCckExt = {0, {0, 0, 0, 0} };
00489         struct cal_target_power_ht targetPowerHt20,
00490                                     targetPowerHt40 = {0, {0, 0, 0, 0} };
00491         u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
00492         static const u16 ctlModesFor11g[] = {
00493                 CTL_11B, CTL_11G, CTL_2GHT20,
00494                 CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
00495         };
00496         u16 numCtlModes = 0;
00497         const u16 *pCtlMode = NULL;
00498         u16 ctlMode, freq;
00499         struct chan_centers centers;
00500         int tx_chainmask;
00501         u16 twiceMinEdgePower;
00502         struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
00503         tx_chainmask = ah->txchainmask;
00504 
00505         ath9k_hw_get_channel_centers(ah, chan, &centers);
00506 
00507         /* Compute TxPower reduction due to Antenna Gain */
00508         twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
00509                                   pEepData->modalHeader.antennaGainCh[1]);
00510         twiceLargestAntenna = (int16_t)min((AntennaReduction) -
00511                                            twiceLargestAntenna, 0);
00512 
00513         /*
00514          * scaledPower is the minimum of the user input power level
00515          * and the regulatory allowed power level.
00516          */
00517         maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
00518 
00519         if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
00520                 maxRegAllowedPower -=
00521                         (tpScaleReductionTable[(regulatory->tp_scale)] * 2);
00522 
00523         scaledPower = min(powerLimit, maxRegAllowedPower);
00524 
00525         /*
00526          * Reduce scaled Power by number of chains active
00527          * to get the per chain tx power level.
00528          */
00529         switch (ar5416_get_ntxchains(tx_chainmask)) {
00530         case 1:
00531                 break;
00532         case 2:
00533                 if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
00534                         scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
00535                 else
00536                         scaledPower = 0;
00537                 break;
00538         case 3:
00539                 if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
00540                         scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
00541                 else
00542                         scaledPower = 0;
00543                 break;
00544         }
00545         scaledPower = max((u16)0, scaledPower);
00546 
00547         /*
00548          * Get TX power from EEPROM.
00549          */
00550         if (IS_CHAN_2GHZ(chan)) {
00551                 /* CTL_11B, CTL_11G, CTL_2GHT20 */
00552                 numCtlModes =
00553                         ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
00554 
00555                 pCtlMode = ctlModesFor11g;
00556 
00557                 ath9k_hw_get_legacy_target_powers(ah, chan,
00558                                                   pEepData->calTargetPowerCck,
00559                                                   AR9287_NUM_2G_CCK_TARGET_POWERS,
00560                                                   &targetPowerCck, 4, 0);
00561                 ath9k_hw_get_legacy_target_powers(ah, chan,
00562                                                   pEepData->calTargetPower2G,
00563                                                   AR9287_NUM_2G_20_TARGET_POWERS,
00564                                                   &targetPowerOfdm, 4, 0);
00565                 ath9k_hw_get_target_powers(ah, chan,
00566                                            pEepData->calTargetPower2GHT20,
00567                                            AR9287_NUM_2G_20_TARGET_POWERS,
00568                                            &targetPowerHt20, 8, 0);
00569 
00570                 if (IS_CHAN_HT40(chan)) {
00571                         /* All 2G CTLs */
00572                         numCtlModes = ARRAY_SIZE(ctlModesFor11g);
00573                         ath9k_hw_get_target_powers(ah, chan,
00574                                                    pEepData->calTargetPower2GHT40,
00575                                                    AR9287_NUM_2G_40_TARGET_POWERS,
00576                                                    &targetPowerHt40, 8, 1);
00577                         ath9k_hw_get_legacy_target_powers(ah, chan,
00578                                                   pEepData->calTargetPowerCck,
00579                                                   AR9287_NUM_2G_CCK_TARGET_POWERS,
00580                                                   &targetPowerCckExt, 4, 1);
00581                         ath9k_hw_get_legacy_target_powers(ah, chan,
00582                                                   pEepData->calTargetPower2G,
00583                                                   AR9287_NUM_2G_20_TARGET_POWERS,
00584                                                   &targetPowerOfdmExt, 4, 1);
00585                 }
00586         }
00587 
00588         for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
00589                 int isHt40CtlMode =
00590                         (pCtlMode[ctlMode] == CTL_2GHT40) ? 1 : 0;
00591 
00592                 if (isHt40CtlMode)
00593                         freq = centers.synth_center;
00594                 else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
00595                         freq = centers.ext_center;
00596                 else
00597                         freq = centers.ctl_center;
00598 
00599                 /* Walk through the CTL indices stored in EEPROM */
00600                 for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
00601                         struct cal_ctl_edges *pRdEdgesPower;
00602 
00603                         /*
00604                          * Compare test group from regulatory channel list
00605                          * with test mode from pCtlMode list
00606                          */
00607                         if (CMP_CTL || CMP_NO_CTL) {
00608                                 rep = &(pEepData->ctlData[i]);
00609                                 pRdEdgesPower =
00610                                 rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1];
00611 
00612                                 twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
00613                                                                 pRdEdgesPower,
00614                                                                 IS_CHAN_2GHZ(chan),
00615                                                                 AR5416_NUM_BAND_EDGES);
00616 
00617                                 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
00618                                         twiceMaxEdgePower = min(twiceMaxEdgePower,
00619                                                                 twiceMinEdgePower);
00620                                 } else {
00621                                         twiceMaxEdgePower = twiceMinEdgePower;
00622                                         break;
00623                                 }
00624                         }
00625                 }
00626 
00627                 minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
00628 
00629                 /* Apply ctl mode to correct target power set */
00630                 switch (pCtlMode[ctlMode]) {
00631                 case CTL_11B:
00632                         for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
00633                                 targetPowerCck.tPow2x[i] =
00634                                         (u8)min((u16)targetPowerCck.tPow2x[i],
00635                                                 minCtlPower);
00636                         }
00637                         break;
00638                 case CTL_11A:
00639                 case CTL_11G:
00640                         for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
00641                                 targetPowerOfdm.tPow2x[i] =
00642                                         (u8)min((u16)targetPowerOfdm.tPow2x[i],
00643                                                 minCtlPower);
00644                         }
00645                         break;
00646                 case CTL_5GHT20:
00647                 case CTL_2GHT20:
00648                         for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
00649                                 targetPowerHt20.tPow2x[i] =
00650                                         (u8)min((u16)targetPowerHt20.tPow2x[i],
00651                                                 minCtlPower);
00652                         }
00653                         break;
00654                 case CTL_11B_EXT:
00655                         targetPowerCckExt.tPow2x[0] =
00656                                 (u8)min((u16)targetPowerCckExt.tPow2x[0],
00657                                         minCtlPower);
00658                         break;
00659                 case CTL_11A_EXT:
00660                 case CTL_11G_EXT:
00661                         targetPowerOfdmExt.tPow2x[0] =
00662                                 (u8)min((u16)targetPowerOfdmExt.tPow2x[0],
00663                                         minCtlPower);
00664                         break;
00665                 case CTL_5GHT40:
00666                 case CTL_2GHT40:
00667                         for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
00668                                 targetPowerHt40.tPow2x[i] =
00669                                         (u8)min((u16)targetPowerHt40.tPow2x[i],
00670                                                 minCtlPower);
00671                         }
00672                         break;
00673                 default:
00674                         break;
00675                 }
00676         }
00677 
00678         /* Now set the rates array */
00679 
00680         ratesArray[rate6mb] =
00681         ratesArray[rate9mb] =
00682         ratesArray[rate12mb] =
00683         ratesArray[rate18mb] =
00684         ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0];
00685 
00686         ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
00687         ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
00688         ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
00689         ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
00690 
00691         for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
00692                 ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
00693 
00694         if (IS_CHAN_2GHZ(chan)) {
00695                 ratesArray[rate1l] = targetPowerCck.tPow2x[0];
00696                 ratesArray[rate2s] =
00697                 ratesArray[rate2l] = targetPowerCck.tPow2x[1];
00698                 ratesArray[rate5_5s] =
00699                 ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
00700                 ratesArray[rate11s] =
00701                 ratesArray[rate11l] = targetPowerCck.tPow2x[3];
00702         }
00703         if (IS_CHAN_HT40(chan)) {
00704                 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
00705                         ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i];
00706 
00707                 ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
00708                 ratesArray[rateDupCck]  = targetPowerHt40.tPow2x[0];
00709                 ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
00710 
00711                 if (IS_CHAN_2GHZ(chan))
00712                         ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
00713         }
00714 
00715 #undef CMP_CTL
00716 #undef CMP_NO_CTL
00717 #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
00718 #undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
00719 }
00720 
00721 static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
00722                                         struct ath9k_channel *chan, u16 cfgCtl,
00723                                         u8 twiceAntennaReduction,
00724                                         u8 twiceMaxRegulatoryPower,
00725                                         u8 powerLimit, int test)
00726 {
00727         struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
00728         struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
00729         struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
00730         int16_t ratesArray[Ar5416RateSize];
00731         int16_t txPowerIndexOffset = 0;
00732         u8 ht40PowerIncForPdadc = 2;
00733         unsigned int i;
00734 
00735         memset(ratesArray, 0, sizeof(ratesArray));
00736 
00737         if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
00738             AR9287_EEP_MINOR_VER_2)
00739                 ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
00740 
00741         ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
00742                                                  &ratesArray[0], cfgCtl,
00743                                                  twiceAntennaReduction,
00744                                                  twiceMaxRegulatoryPower,
00745                                                  powerLimit);
00746 
00747         ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
00748 
00749         regulatory->max_power_level = 0;
00750         for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
00751                 ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
00752                 if (ratesArray[i] > MAX_RATE_POWER)
00753                         ratesArray[i] = MAX_RATE_POWER;
00754 
00755                 if (ratesArray[i] > regulatory->max_power_level)
00756                         regulatory->max_power_level = ratesArray[i];
00757         }
00758 
00759         if (test)
00760                 return;
00761 
00762         if (IS_CHAN_2GHZ(chan))
00763                 i = rate1l;
00764         else
00765                 i = rate6mb;
00766 
00767         regulatory->max_power_level = ratesArray[i];
00768 
00769         if (AR_SREV_9280_20_OR_LATER(ah)) {
00770                 for (i = 0; i < Ar5416RateSize; i++)
00771                         ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
00772         }
00773 
00774         ENABLE_REGWRITE_BUFFER(ah);
00775 
00776         /* OFDM power per rate */
00777         REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
00778                   ATH9K_POW_SM(ratesArray[rate18mb], 24)
00779                   | ATH9K_POW_SM(ratesArray[rate12mb], 16)
00780                   | ATH9K_POW_SM(ratesArray[rate9mb], 8)
00781                   | ATH9K_POW_SM(ratesArray[rate6mb], 0));
00782 
00783         REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
00784                   ATH9K_POW_SM(ratesArray[rate54mb], 24)
00785                   | ATH9K_POW_SM(ratesArray[rate48mb], 16)
00786                   | ATH9K_POW_SM(ratesArray[rate36mb], 8)
00787                   | ATH9K_POW_SM(ratesArray[rate24mb], 0));
00788 
00789         /* CCK power per rate */
00790         if (IS_CHAN_2GHZ(chan)) {
00791                 REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
00792                           ATH9K_POW_SM(ratesArray[rate2s], 24)
00793                           | ATH9K_POW_SM(ratesArray[rate2l], 16)
00794                           | ATH9K_POW_SM(ratesArray[rateXr], 8)
00795                           | ATH9K_POW_SM(ratesArray[rate1l], 0));
00796                 REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
00797                           ATH9K_POW_SM(ratesArray[rate11s], 24)
00798                           | ATH9K_POW_SM(ratesArray[rate11l], 16)
00799                           | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
00800                           | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
00801         }
00802 
00803         /* HT20 power per rate */
00804         REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
00805                   ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
00806                   | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
00807                   | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
00808                   | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
00809 
00810         REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
00811                   ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
00812                   | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
00813                   | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
00814                   | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
00815 
00816         /* HT40 power per rate */
00817         if (IS_CHAN_HT40(chan)) {
00818                 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
00819                         REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
00820                                   ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
00821                                   | ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
00822                                   | ATH9K_POW_SM(ratesArray[rateHt40_1], 8)
00823                                   | ATH9K_POW_SM(ratesArray[rateHt40_0], 0));
00824 
00825                         REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
00826                                   ATH9K_POW_SM(ratesArray[rateHt40_7], 24)
00827                                   | ATH9K_POW_SM(ratesArray[rateHt40_6], 16)
00828                                   | ATH9K_POW_SM(ratesArray[rateHt40_5], 8)
00829                                   | ATH9K_POW_SM(ratesArray[rateHt40_4], 0));
00830                 } else {
00831                         REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
00832                                   ATH9K_POW_SM(ratesArray[rateHt40_3] +
00833                                                ht40PowerIncForPdadc, 24)
00834                                   | ATH9K_POW_SM(ratesArray[rateHt40_2] +
00835                                                  ht40PowerIncForPdadc, 16)
00836                                   | ATH9K_POW_SM(ratesArray[rateHt40_1] +
00837                                                  ht40PowerIncForPdadc, 8)
00838                                   | ATH9K_POW_SM(ratesArray[rateHt40_0] +
00839                                                  ht40PowerIncForPdadc, 0));
00840 
00841                         REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
00842                                   ATH9K_POW_SM(ratesArray[rateHt40_7] +
00843                                                ht40PowerIncForPdadc, 24)
00844                                   | ATH9K_POW_SM(ratesArray[rateHt40_6] +
00845                                                  ht40PowerIncForPdadc, 16)
00846                                   | ATH9K_POW_SM(ratesArray[rateHt40_5] +
00847                                                  ht40PowerIncForPdadc, 8)
00848                                   | ATH9K_POW_SM(ratesArray[rateHt40_4] +
00849                                                  ht40PowerIncForPdadc, 0));
00850                 }
00851 
00852                 /* Dup/Ext power per rate */
00853                 REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
00854                           ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
00855                           | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
00856                           | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
00857                           | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
00858         }
00859         REGWRITE_BUFFER_FLUSH(ah);
00860 }
00861 
00862 static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah __unused,
00863                                       struct ath9k_channel *chan __unused)
00864 {
00865 }
00866 
00867 static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
00868                                              struct ath9k_channel *chan)
00869 {
00870         struct ar9287_eeprom *eep = &ah->eeprom.map9287;
00871         struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
00872         u32 regChainOffset, regval;
00873         u8 txRxAttenLocal;
00874         int i;
00875 
00876         pModal = &eep->modalHeader;
00877 
00878         REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
00879 
00880         for (i = 0; i < AR9287_MAX_CHAINS; i++) {
00881                 regChainOffset = i * 0x1000;
00882 
00883                 REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
00884                           pModal->antCtrlChain[i]);
00885 
00886                 REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
00887                           (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset)
00888                            & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
00889                                AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
00890                           SM(pModal->iqCalICh[i],
00891                              AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
00892                           SM(pModal->iqCalQCh[i],
00893                              AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
00894 
00895                 txRxAttenLocal = pModal->txRxAttenCh[i];
00896 
00897                 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
00898                               AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
00899                               pModal->bswMargin[i]);
00900                 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
00901                               AR_PHY_GAIN_2GHZ_XATTEN1_DB,
00902                               pModal->bswAtten[i]);
00903                 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
00904                               AR9280_PHY_RXGAIN_TXRX_ATTEN,
00905                               txRxAttenLocal);
00906                 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
00907                               AR9280_PHY_RXGAIN_TXRX_MARGIN,
00908                               pModal->rxTxMarginCh[i]);
00909         }
00910 
00911 
00912         if (IS_CHAN_HT40(chan))
00913                 REG_RMW_FIELD(ah, AR_PHY_SETTLING,
00914                               AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40);
00915         else
00916                 REG_RMW_FIELD(ah, AR_PHY_SETTLING,
00917                               AR_PHY_SETTLING_SWITCH, pModal->switchSettling);
00918 
00919         REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
00920                       AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);
00921 
00922         REG_WRITE(ah, AR_PHY_RF_CTL4,
00923                   SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
00924                   | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
00925                   | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)
00926                   | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
00927 
00928         REG_RMW_FIELD(ah, AR_PHY_RF_CTL3,
00929                       AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn);
00930 
00931         REG_RMW_FIELD(ah, AR_PHY_CCA,
00932                       AR9280_PHY_CCA_THRESH62, pModal->thresh62);
00933         REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
00934                       AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
00935 
00936         regval = REG_READ(ah, AR9287_AN_RF2G3_CH0);
00937         regval &= ~(AR9287_AN_RF2G3_DB1 |
00938                     AR9287_AN_RF2G3_DB2 |
00939                     AR9287_AN_RF2G3_OB_CCK |
00940                     AR9287_AN_RF2G3_OB_PSK |
00941                     AR9287_AN_RF2G3_OB_QAM |
00942                     AR9287_AN_RF2G3_OB_PAL_OFF);
00943         regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
00944                    SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
00945                    SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
00946                    SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
00947                    SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
00948                    SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
00949 
00950         ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval);
00951 
00952         regval = REG_READ(ah, AR9287_AN_RF2G3_CH1);
00953         regval &= ~(AR9287_AN_RF2G3_DB1 |
00954                     AR9287_AN_RF2G3_DB2 |
00955                     AR9287_AN_RF2G3_OB_CCK |
00956                     AR9287_AN_RF2G3_OB_PSK |
00957                     AR9287_AN_RF2G3_OB_QAM |
00958                     AR9287_AN_RF2G3_OB_PAL_OFF);
00959         regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
00960                    SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
00961                    SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
00962                    SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
00963                    SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
00964                    SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
00965 
00966         ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval);
00967 
00968         REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
00969                       AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
00970         REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
00971                       AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn);
00972 
00973         ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2,
00974                                   AR9287_AN_TOP2_XPABIAS_LVL,
00975                                   AR9287_AN_TOP2_XPABIAS_LVL_S,
00976                                   pModal->xpaBiasLvl);
00977 }
00978 
00979 static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
00980                                             u16 i, int is2GHz)
00981 {
00982 #define EEP_MAP9287_SPURCHAN \
00983         (ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
00984 
00985         u16 spur_val = AR_NO_SPUR;
00986 
00987         DBG2("ath9k: "
00988                 "Getting spur idx:%d is2Ghz:%d val:%x\n",
00989                 i, is2GHz, ah->config.spurchans[i][is2GHz]);
00990 
00991         switch (ah->config.spurmode) {
00992         case SPUR_DISABLE:
00993                 break;
00994         case SPUR_ENABLE_IOCTL:
00995                 spur_val = ah->config.spurchans[i][is2GHz];
00996                 DBG2("ath9k: "
00997                         "Getting spur val from new loc. %d\n", spur_val);
00998                 break;
00999         case SPUR_ENABLE_EEPROM:
01000                 spur_val = EEP_MAP9287_SPURCHAN;
01001                 break;
01002         }
01003 
01004         return spur_val;
01005 
01006 #undef EEP_MAP9287_SPURCHAN
01007 }
01008 
01009 const struct eeprom_ops eep_ar9287_ops = {
01010         .check_eeprom           = ath9k_hw_ar9287_check_eeprom,
01011         .get_eeprom             = ath9k_hw_ar9287_get_eeprom,
01012         .fill_eeprom            = ath9k_hw_ar9287_fill_eeprom,
01013         .get_eeprom_ver         = ath9k_hw_ar9287_get_eeprom_ver,
01014         .get_eeprom_rev         = ath9k_hw_ar9287_get_eeprom_rev,
01015         .set_board_values       = ath9k_hw_ar9287_set_board_values,
01016         .set_addac              = ath9k_hw_ar9287_set_addac,
01017         .set_txpower            = ath9k_hw_ar9287_set_txpower,
01018         .get_spur_channel       = ath9k_hw_ar9287_get_spur_channel
01019 };