Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2008-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <asm/unaligned.h>
0018 #include "hw.h"
0019 #include "ar9002_phy.h"
0020 
0021 #define SIZE_EEPROM_AR9287 (sizeof(struct ar9287_eeprom) / sizeof(u16))
0022 
0023 static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
0024 {
0025     u16 version = le16_to_cpu(ah->eeprom.map9287.baseEepHeader.version);
0026 
0027     return (version & AR5416_EEP_VER_MAJOR_MASK) >>
0028         AR5416_EEP_VER_MAJOR_SHIFT;
0029 }
0030 
0031 static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
0032 {
0033     u16 version = le16_to_cpu(ah->eeprom.map9287.baseEepHeader.version);
0034 
0035     return version & AR5416_EEP_VER_MINOR_MASK;
0036 }
0037 
0038 static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
0039 {
0040     struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0041     u16 *eep_data;
0042     int addr, eep_start_loc = AR9287_EEP_START_LOC;
0043     eep_data = (u16 *)eep;
0044 
0045     for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
0046         if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data))
0047             return false;
0048         eep_data++;
0049     }
0050 
0051     return true;
0052 }
0053 
0054 static bool __ath9k_hw_usb_ar9287_fill_eeprom(struct ath_hw *ah)
0055 {
0056     u16 *eep_data = (u16 *)&ah->eeprom.map9287;
0057 
0058     ath9k_hw_usb_gen_fill_eeprom(ah, eep_data,
0059                      AR9287_HTC_EEP_START_LOC,
0060                      SIZE_EEPROM_AR9287);
0061     return true;
0062 }
0063 
0064 static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
0065 {
0066     struct ath_common *common = ath9k_hw_common(ah);
0067 
0068     if (!ath9k_hw_use_flash(ah)) {
0069         ath_dbg(common, EEPROM, "Reading from EEPROM, not flash\n");
0070     }
0071 
0072     if (common->bus_ops->ath_bus_type == ATH_USB)
0073         return __ath9k_hw_usb_ar9287_fill_eeprom(ah);
0074     else
0075         return __ath9k_hw_ar9287_fill_eeprom(ah);
0076 }
0077 
0078 #ifdef CONFIG_ATH9K_COMMON_DEBUG
0079 static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size,
0080                     struct modal_eep_ar9287_header *modal_hdr)
0081 {
0082     PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
0083     PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1]));
0084     PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
0085     PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
0086     PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
0087     PR_EEP("Switch Settle", modal_hdr->switchSettling);
0088     PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
0089     PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]);
0090     PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
0091     PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]);
0092     PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
0093     PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
0094     PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
0095     PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
0096     PR_EEP("CCA Threshold)", modal_hdr->thresh62);
0097     PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
0098     PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
0099     PR_EEP("xpdGain", modal_hdr->xpdGain);
0100     PR_EEP("External PD", modal_hdr->xpd);
0101     PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
0102     PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]);
0103     PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
0104     PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]);
0105     PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
0106     PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
0107     PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
0108     PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
0109     PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
0110     PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
0111     PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]);
0112     PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
0113     PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]);
0114     PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
0115     PR_EEP("AR92x7 Version", modal_hdr->version);
0116     PR_EEP("DriverBias1", modal_hdr->db1);
0117     PR_EEP("DriverBias2", modal_hdr->db1);
0118     PR_EEP("CCK OutputBias", modal_hdr->ob_cck);
0119     PR_EEP("PSK OutputBias", modal_hdr->ob_psk);
0120     PR_EEP("QAM OutputBias", modal_hdr->ob_qam);
0121     PR_EEP("PAL_OFF OutputBias", modal_hdr->ob_pal_off);
0122 
0123     return len;
0124 }
0125 
0126 static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
0127                        u8 *buf, u32 len, u32 size)
0128 {
0129     struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0130     struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
0131     u32 binBuildNumber = le32_to_cpu(pBase->binBuildNumber);
0132 
0133     if (!dump_base_hdr) {
0134         len += scnprintf(buf + len, size - len,
0135                  "%20s :\n", "2GHz modal Header");
0136         len = ar9287_dump_modal_eeprom(buf, len, size,
0137                         &eep->modalHeader);
0138         goto out;
0139     }
0140 
0141     PR_EEP("Major Version", ath9k_hw_ar9287_get_eeprom_ver(ah));
0142     PR_EEP("Minor Version", ath9k_hw_ar9287_get_eeprom_rev(ah));
0143     PR_EEP("Checksum", le16_to_cpu(pBase->checksum));
0144     PR_EEP("Length", le16_to_cpu(pBase->length));
0145     PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
0146     PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
0147     PR_EEP("TX Mask", pBase->txMask);
0148     PR_EEP("RX Mask", pBase->rxMask);
0149     PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
0150     PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
0151     PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
0152                     AR5416_OPFLAGS_N_2G_HT20));
0153     PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
0154                     AR5416_OPFLAGS_N_2G_HT40));
0155     PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
0156                     AR5416_OPFLAGS_N_5G_HT20));
0157     PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
0158                     AR5416_OPFLAGS_N_5G_HT40));
0159     PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN));
0160     PR_EEP("Cal Bin Major Ver", (binBuildNumber >> 24) & 0xFF);
0161     PR_EEP("Cal Bin Minor Ver", (binBuildNumber >> 16) & 0xFF);
0162     PR_EEP("Cal Bin Build", (binBuildNumber >> 8) & 0xFF);
0163     PR_EEP("Power Table Offset", pBase->pwrTableOffset);
0164     PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
0165 
0166     len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
0167              pBase->macAddr);
0168 
0169 out:
0170     if (len > size)
0171         len = size;
0172 
0173     return len;
0174 }
0175 #else
0176 static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
0177                        u8 *buf, u32 len, u32 size)
0178 {
0179     return 0;
0180 }
0181 #endif
0182 
0183 
0184 static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
0185 {
0186     u32 el;
0187     int i, err;
0188     bool need_swap;
0189     struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0190 
0191     err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_AR9287);
0192     if (err)
0193         return err;
0194 
0195     if (need_swap)
0196         el = swab16((__force u16)eep->baseEepHeader.length);
0197     else
0198         el = le16_to_cpu(eep->baseEepHeader.length);
0199 
0200     el = min(el / sizeof(u16), SIZE_EEPROM_AR9287);
0201     if (!ath9k_hw_nvram_validate_checksum(ah, el))
0202         return -EINVAL;
0203 
0204     if (need_swap) {
0205         EEPROM_FIELD_SWAB16(eep->baseEepHeader.length);
0206         EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum);
0207         EEPROM_FIELD_SWAB16(eep->baseEepHeader.version);
0208         EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[0]);
0209         EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[1]);
0210         EEPROM_FIELD_SWAB16(eep->baseEepHeader.rfSilent);
0211         EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions);
0212         EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap);
0213         EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlCommon);
0214 
0215         for (i = 0; i < AR9287_MAX_CHAINS; i++)
0216             EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlChain[i]);
0217 
0218         for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++)
0219             EEPROM_FIELD_SWAB16(
0220                 eep->modalHeader.spurChans[i].spurChan);
0221     }
0222 
0223     if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER,
0224         AR5416_EEP_NO_BACK_VER))
0225         return -EINVAL;
0226 
0227     return 0;
0228 }
0229 
0230 #undef SIZE_EEPROM_AR9287
0231 
0232 static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
0233                       enum eeprom_param param)
0234 {
0235     struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0236     struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
0237     struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
0238     u16 ver_minor = ath9k_hw_ar9287_get_eeprom_rev(ah);
0239 
0240     switch (param) {
0241     case EEP_NFTHRESH_2:
0242         return pModal->noiseFloorThreshCh[0];
0243     case EEP_MAC_LSW:
0244         return get_unaligned_be16(pBase->macAddr);
0245     case EEP_MAC_MID:
0246         return get_unaligned_be16(pBase->macAddr + 2);
0247     case EEP_MAC_MSW:
0248         return get_unaligned_be16(pBase->macAddr + 4);
0249     case EEP_REG_0:
0250         return le16_to_cpu(pBase->regDmn[0]);
0251     case EEP_OP_CAP:
0252         return le16_to_cpu(pBase->deviceCap);
0253     case EEP_OP_MODE:
0254         return pBase->opCapFlags;
0255     case EEP_RF_SILENT:
0256         return le16_to_cpu(pBase->rfSilent);
0257     case EEP_TX_MASK:
0258         return pBase->txMask;
0259     case EEP_RX_MASK:
0260         return pBase->rxMask;
0261     case EEP_DEV_TYPE:
0262         return pBase->deviceType;
0263     case EEP_OL_PWRCTRL:
0264         return pBase->openLoopPwrCntl;
0265     case EEP_TEMPSENSE_SLOPE:
0266         if (ver_minor >= AR9287_EEP_MINOR_VER_2)
0267             return pBase->tempSensSlope;
0268         else
0269             return 0;
0270     case EEP_TEMPSENSE_SLOPE_PAL_ON:
0271         if (ver_minor >= AR9287_EEP_MINOR_VER_3)
0272             return pBase->tempSensSlopePalOn;
0273         else
0274             return 0;
0275     case EEP_ANTENNA_GAIN_2G:
0276         return max_t(u8, pModal->antennaGainCh[0],
0277                  pModal->antennaGainCh[1]);
0278     default:
0279         return 0;
0280     }
0281 }
0282 
0283 static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
0284                 struct ath9k_channel *chan,
0285                 struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
0286                 u8 *pCalChans,  u16 availPiers, int8_t *pPwr)
0287 {
0288     u16 idxL = 0, idxR = 0, numPiers;
0289     bool match;
0290     struct chan_centers centers;
0291 
0292     ath9k_hw_get_channel_centers(ah, chan, &centers);
0293 
0294     for (numPiers = 0; numPiers < availPiers; numPiers++) {
0295         if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED)
0296             break;
0297     }
0298 
0299     match = ath9k_hw_get_lower_upper_index(
0300         (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
0301         pCalChans, numPiers, &idxL, &idxR);
0302 
0303     if (match) {
0304         *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
0305     } else {
0306         *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
0307              (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
0308     }
0309 
0310 }
0311 
0312 static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
0313                       int32_t txPower, u16 chain)
0314 {
0315     u32 tmpVal;
0316     u32 a;
0317 
0318     /* Enable OLPC for chain 0 */
0319 
0320     tmpVal = REG_READ(ah, 0xa270);
0321     tmpVal = tmpVal & 0xFCFFFFFF;
0322     tmpVal = tmpVal | (0x3 << 24);
0323     REG_WRITE(ah, 0xa270, tmpVal);
0324 
0325     /* Enable OLPC for chain 1 */
0326 
0327     tmpVal = REG_READ(ah, 0xb270);
0328     tmpVal = tmpVal & 0xFCFFFFFF;
0329     tmpVal = tmpVal | (0x3 << 24);
0330     REG_WRITE(ah, 0xb270, tmpVal);
0331 
0332     /* Write the OLPC ref power for chain 0 */
0333 
0334     if (chain == 0) {
0335         tmpVal = REG_READ(ah, 0xa398);
0336         tmpVal = tmpVal & 0xff00ffff;
0337         a = (txPower)&0xff;
0338         tmpVal = tmpVal | (a << 16);
0339         REG_WRITE(ah, 0xa398, tmpVal);
0340     }
0341 
0342     /* Write the OLPC ref power for chain 1 */
0343 
0344     if (chain == 1) {
0345         tmpVal = REG_READ(ah, 0xb398);
0346         tmpVal = tmpVal & 0xff00ffff;
0347         a = (txPower)&0xff;
0348         tmpVal = tmpVal | (a << 16);
0349         REG_WRITE(ah, 0xb398, tmpVal);
0350     }
0351 }
0352 
0353 static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
0354                         struct ath9k_channel *chan)
0355 {
0356     struct cal_data_per_freq_ar9287 *pRawDataset;
0357     struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
0358     u8 *pCalBChans = NULL;
0359     u16 pdGainOverlap_t2;
0360     u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
0361     u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
0362     u16 numPiers = 0, i, j;
0363     u16 numXpdGain, xpdMask;
0364     u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
0365     u32 reg32, regOffset, regChainOffset, regval;
0366     int16_t diff = 0;
0367     struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
0368 
0369     xpdMask = pEepData->modalHeader.xpdGain;
0370 
0371     if (ath9k_hw_ar9287_get_eeprom_rev(ah) >= AR9287_EEP_MINOR_VER_2)
0372         pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
0373     else
0374         pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
0375                         AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
0376 
0377     if (IS_CHAN_2GHZ(chan)) {
0378         pCalBChans = pEepData->calFreqPier2G;
0379         numPiers = AR9287_NUM_2G_CAL_PIERS;
0380         if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
0381             pRawDatasetOpenLoop =
0382             (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
0383             ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
0384         }
0385     }
0386 
0387     numXpdGain = 0;
0388 
0389     /* Calculate the value of xpdgains from the xpdGain Mask */
0390     for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
0391         if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
0392             if (numXpdGain >= AR5416_NUM_PD_GAINS)
0393                 break;
0394             xpdGainValues[numXpdGain] =
0395                 (u16)(AR5416_PD_GAINS_IN_MASK-i);
0396             numXpdGain++;
0397         }
0398     }
0399 
0400     REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
0401               (numXpdGain - 1) & 0x3);
0402     REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
0403               xpdGainValues[0]);
0404     REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
0405               xpdGainValues[1]);
0406     REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
0407               xpdGainValues[2]);
0408 
0409     for (i = 0; i < AR9287_MAX_CHAINS; i++) {
0410         regChainOffset = i * 0x1000;
0411 
0412         if (pEepData->baseEepHeader.txMask & (1 << i)) {
0413             pRawDatasetOpenLoop =
0414             (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
0415 
0416             if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
0417                 int8_t txPower;
0418                 ar9287_eeprom_get_tx_gain_index(ah, chan,
0419                             pRawDatasetOpenLoop,
0420                             pCalBChans, numPiers,
0421                             &txPower);
0422                 ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
0423             } else {
0424                 pRawDataset =
0425                     (struct cal_data_per_freq_ar9287 *)
0426                     pEepData->calPierData2G[i];
0427 
0428                 ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
0429                                pRawDataset,
0430                                pCalBChans, numPiers,
0431                                pdGainOverlap_t2,
0432                                gainBoundaries,
0433                                pdadcValues,
0434                                numXpdGain);
0435             }
0436 
0437             ENABLE_REGWRITE_BUFFER(ah);
0438 
0439             if (i == 0) {
0440                 if (!ath9k_hw_ar9287_get_eeprom(ah,
0441                             EEP_OL_PWRCTRL)) {
0442 
0443                     regval = SM(pdGainOverlap_t2,
0444                             AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
0445                         | SM(gainBoundaries[0],
0446                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
0447                         | SM(gainBoundaries[1],
0448                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
0449                         | SM(gainBoundaries[2],
0450                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
0451                         | SM(gainBoundaries[3],
0452                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4);
0453 
0454                     REG_WRITE(ah,
0455                           AR_PHY_TPCRG5 + regChainOffset,
0456                           regval);
0457                 }
0458             }
0459 
0460             if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
0461                 pEepData->baseEepHeader.pwrTableOffset) {
0462                 diff = (u16)(pEepData->baseEepHeader.pwrTableOffset -
0463                          (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
0464                 diff *= 2;
0465 
0466                 for (j = 0; j < ((u16)AR5416_NUM_PDADC_VALUES-diff); j++)
0467                     pdadcValues[j] = pdadcValues[j+diff];
0468 
0469                 for (j = (u16)(AR5416_NUM_PDADC_VALUES-diff);
0470                      j < AR5416_NUM_PDADC_VALUES; j++)
0471                     pdadcValues[j] =
0472                       pdadcValues[AR5416_NUM_PDADC_VALUES-diff];
0473             }
0474 
0475             if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
0476                 regOffset = AR_PHY_BASE +
0477                     (672 << 2) + regChainOffset;
0478 
0479                 for (j = 0; j < 32; j++) {
0480                     reg32 = get_unaligned_le32(&pdadcValues[4 * j]);
0481 
0482                     REG_WRITE(ah, regOffset, reg32);
0483                     regOffset += 4;
0484                 }
0485             }
0486             REGWRITE_BUFFER_FLUSH(ah);
0487         }
0488     }
0489 }
0490 
0491 static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
0492                              struct ath9k_channel *chan,
0493                              int16_t *ratesArray,
0494                              u16 cfgCtl,
0495                              u16 antenna_reduction,
0496                              u16 powerLimit)
0497 {
0498 #define CMP_CTL \
0499     (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
0500      pEepData->ctlIndex[i])
0501 
0502 #define CMP_NO_CTL \
0503     (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
0504      ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
0505 
0506     u16 twiceMaxEdgePower;
0507     int i;
0508     struct cal_ctl_data_ar9287 *rep;
0509     struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
0510                     targetPowerCck = {0, {0, 0, 0, 0} };
0511     struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
0512                     targetPowerCckExt = {0, {0, 0, 0, 0} };
0513     struct cal_target_power_ht targetPowerHt20,
0514                     targetPowerHt40 = {0, {0, 0, 0, 0} };
0515     u16 scaledPower = 0, minCtlPower;
0516     static const u16 ctlModesFor11g[] = {
0517         CTL_11B, CTL_11G, CTL_2GHT20,
0518         CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
0519     };
0520     u16 numCtlModes = 0;
0521     const u16 *pCtlMode = NULL;
0522     u16 ctlMode, freq;
0523     struct chan_centers centers;
0524     int tx_chainmask;
0525     u16 twiceMinEdgePower;
0526     struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
0527     tx_chainmask = ah->txchainmask;
0528 
0529     ath9k_hw_get_channel_centers(ah, chan, &centers);
0530     scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
0531                         antenna_reduction);
0532 
0533     /*
0534      * Get TX power from EEPROM.
0535      */
0536     if (IS_CHAN_2GHZ(chan)) {
0537         /* CTL_11B, CTL_11G, CTL_2GHT20 */
0538         numCtlModes =
0539             ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
0540 
0541         pCtlMode = ctlModesFor11g;
0542 
0543         ath9k_hw_get_legacy_target_powers(ah, chan,
0544                           pEepData->calTargetPowerCck,
0545                           AR9287_NUM_2G_CCK_TARGET_POWERS,
0546                           &targetPowerCck, 4, false);
0547         ath9k_hw_get_legacy_target_powers(ah, chan,
0548                           pEepData->calTargetPower2G,
0549                           AR9287_NUM_2G_20_TARGET_POWERS,
0550                           &targetPowerOfdm, 4, false);
0551         ath9k_hw_get_target_powers(ah, chan,
0552                        pEepData->calTargetPower2GHT20,
0553                        AR9287_NUM_2G_20_TARGET_POWERS,
0554                        &targetPowerHt20, 8, false);
0555 
0556         if (IS_CHAN_HT40(chan)) {
0557             /* All 2G CTLs */
0558             numCtlModes = ARRAY_SIZE(ctlModesFor11g);
0559             ath9k_hw_get_target_powers(ah, chan,
0560                            pEepData->calTargetPower2GHT40,
0561                            AR9287_NUM_2G_40_TARGET_POWERS,
0562                            &targetPowerHt40, 8, true);
0563             ath9k_hw_get_legacy_target_powers(ah, chan,
0564                           pEepData->calTargetPowerCck,
0565                           AR9287_NUM_2G_CCK_TARGET_POWERS,
0566                           &targetPowerCckExt, 4, true);
0567             ath9k_hw_get_legacy_target_powers(ah, chan,
0568                           pEepData->calTargetPower2G,
0569                           AR9287_NUM_2G_20_TARGET_POWERS,
0570                           &targetPowerOfdmExt, 4, true);
0571         }
0572     }
0573 
0574     for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
0575         bool isHt40CtlMode =
0576             (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false;
0577 
0578         if (isHt40CtlMode)
0579             freq = centers.synth_center;
0580         else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
0581             freq = centers.ext_center;
0582         else
0583             freq = centers.ctl_center;
0584 
0585         twiceMaxEdgePower = MAX_RATE_POWER;
0586         /* Walk through the CTL indices stored in EEPROM */
0587         for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
0588             struct cal_ctl_edges *pRdEdgesPower;
0589 
0590             /*
0591              * Compare test group from regulatory channel list
0592              * with test mode from pCtlMode list
0593              */
0594             if (CMP_CTL || CMP_NO_CTL) {
0595                 rep = &(pEepData->ctlData[i]);
0596                 pRdEdgesPower =
0597                 rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1];
0598 
0599                 twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
0600                                 pRdEdgesPower,
0601                                 IS_CHAN_2GHZ(chan),
0602                                 AR5416_NUM_BAND_EDGES);
0603 
0604                 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
0605                     twiceMaxEdgePower = min(twiceMaxEdgePower,
0606                                 twiceMinEdgePower);
0607                 } else {
0608                     twiceMaxEdgePower = twiceMinEdgePower;
0609                     break;
0610                 }
0611             }
0612         }
0613 
0614         minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
0615 
0616         /* Apply ctl mode to correct target power set */
0617         switch (pCtlMode[ctlMode]) {
0618         case CTL_11B:
0619             for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
0620                 targetPowerCck.tPow2x[i] =
0621                     (u8)min((u16)targetPowerCck.tPow2x[i],
0622                         minCtlPower);
0623             }
0624             break;
0625         case CTL_11A:
0626         case CTL_11G:
0627             for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
0628                 targetPowerOfdm.tPow2x[i] =
0629                     (u8)min((u16)targetPowerOfdm.tPow2x[i],
0630                         minCtlPower);
0631             }
0632             break;
0633         case CTL_5GHT20:
0634         case CTL_2GHT20:
0635             for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
0636                 targetPowerHt20.tPow2x[i] =
0637                     (u8)min((u16)targetPowerHt20.tPow2x[i],
0638                         minCtlPower);
0639             }
0640             break;
0641         case CTL_11B_EXT:
0642             targetPowerCckExt.tPow2x[0] =
0643                 (u8)min((u16)targetPowerCckExt.tPow2x[0],
0644                     minCtlPower);
0645             break;
0646         case CTL_11A_EXT:
0647         case CTL_11G_EXT:
0648             targetPowerOfdmExt.tPow2x[0] =
0649                 (u8)min((u16)targetPowerOfdmExt.tPow2x[0],
0650                     minCtlPower);
0651             break;
0652         case CTL_5GHT40:
0653         case CTL_2GHT40:
0654             for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
0655                 targetPowerHt40.tPow2x[i] =
0656                     (u8)min((u16)targetPowerHt40.tPow2x[i],
0657                         minCtlPower);
0658             }
0659             break;
0660         default:
0661             break;
0662         }
0663     }
0664 
0665     /* Now set the rates array */
0666 
0667     ratesArray[rate6mb] =
0668     ratesArray[rate9mb] =
0669     ratesArray[rate12mb] =
0670     ratesArray[rate18mb] =
0671     ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0];
0672 
0673     ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
0674     ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
0675     ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
0676     ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
0677 
0678     for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
0679         ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
0680 
0681     if (IS_CHAN_2GHZ(chan)) {
0682         ratesArray[rate1l] = targetPowerCck.tPow2x[0];
0683         ratesArray[rate2s] =
0684         ratesArray[rate2l] = targetPowerCck.tPow2x[1];
0685         ratesArray[rate5_5s] =
0686         ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
0687         ratesArray[rate11s] =
0688         ratesArray[rate11l] = targetPowerCck.tPow2x[3];
0689     }
0690     if (IS_CHAN_HT40(chan)) {
0691         for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
0692             ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i];
0693 
0694         ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
0695         ratesArray[rateDupCck]  = targetPowerHt40.tPow2x[0];
0696         ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
0697 
0698         if (IS_CHAN_2GHZ(chan))
0699             ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
0700     }
0701 
0702 #undef CMP_CTL
0703 #undef CMP_NO_CTL
0704 }
0705 
0706 static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
0707                     struct ath9k_channel *chan, u16 cfgCtl,
0708                     u8 twiceAntennaReduction,
0709                     u8 powerLimit, bool test)
0710 {
0711     struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
0712     struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
0713     struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
0714     int16_t ratesArray[Ar5416RateSize];
0715     u8 ht40PowerIncForPdadc = 2;
0716     int i;
0717 
0718     memset(ratesArray, 0, sizeof(ratesArray));
0719 
0720     if (ath9k_hw_ar9287_get_eeprom_rev(ah) >= AR9287_EEP_MINOR_VER_2)
0721         ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
0722 
0723     ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
0724                          &ratesArray[0], cfgCtl,
0725                          twiceAntennaReduction,
0726                          powerLimit);
0727 
0728     ath9k_hw_set_ar9287_power_cal_table(ah, chan);
0729 
0730     regulatory->max_power_level = 0;
0731     for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
0732         if (ratesArray[i] > MAX_RATE_POWER)
0733             ratesArray[i] = MAX_RATE_POWER;
0734 
0735         if (ratesArray[i] > regulatory->max_power_level)
0736             regulatory->max_power_level = ratesArray[i];
0737     }
0738 
0739     ath9k_hw_update_regulatory_maxpower(ah);
0740 
0741     if (test)
0742         return;
0743 
0744     for (i = 0; i < Ar5416RateSize; i++)
0745         ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
0746 
0747     ENABLE_REGWRITE_BUFFER(ah);
0748 
0749     /* OFDM power per rate */
0750     REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
0751           ATH9K_POW_SM(ratesArray[rate18mb], 24)
0752           | ATH9K_POW_SM(ratesArray[rate12mb], 16)
0753           | ATH9K_POW_SM(ratesArray[rate9mb], 8)
0754           | ATH9K_POW_SM(ratesArray[rate6mb], 0));
0755 
0756     REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
0757           ATH9K_POW_SM(ratesArray[rate54mb], 24)
0758           | ATH9K_POW_SM(ratesArray[rate48mb], 16)
0759           | ATH9K_POW_SM(ratesArray[rate36mb], 8)
0760           | ATH9K_POW_SM(ratesArray[rate24mb], 0));
0761 
0762     /* CCK power per rate */
0763     if (IS_CHAN_2GHZ(chan)) {
0764         REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
0765               ATH9K_POW_SM(ratesArray[rate2s], 24)
0766               | ATH9K_POW_SM(ratesArray[rate2l], 16)
0767               | ATH9K_POW_SM(ratesArray[rateXr], 8)
0768               | ATH9K_POW_SM(ratesArray[rate1l], 0));
0769         REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
0770               ATH9K_POW_SM(ratesArray[rate11s], 24)
0771               | ATH9K_POW_SM(ratesArray[rate11l], 16)
0772               | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
0773               | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
0774     }
0775 
0776     /* HT20 power per rate */
0777     REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
0778           ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
0779           | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
0780           | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
0781           | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
0782 
0783     REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
0784           ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
0785           | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
0786           | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
0787           | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
0788 
0789     /* HT40 power per rate */
0790     if (IS_CHAN_HT40(chan)) {
0791         if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
0792             REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
0793                   ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
0794                   | ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
0795                   | ATH9K_POW_SM(ratesArray[rateHt40_1], 8)
0796                   | ATH9K_POW_SM(ratesArray[rateHt40_0], 0));
0797 
0798             REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
0799                   ATH9K_POW_SM(ratesArray[rateHt40_7], 24)
0800                   | ATH9K_POW_SM(ratesArray[rateHt40_6], 16)
0801                   | ATH9K_POW_SM(ratesArray[rateHt40_5], 8)
0802                   | ATH9K_POW_SM(ratesArray[rateHt40_4], 0));
0803         } else {
0804             REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
0805                   ATH9K_POW_SM(ratesArray[rateHt40_3] +
0806                            ht40PowerIncForPdadc, 24)
0807                   | ATH9K_POW_SM(ratesArray[rateHt40_2] +
0808                          ht40PowerIncForPdadc, 16)
0809                   | ATH9K_POW_SM(ratesArray[rateHt40_1] +
0810                          ht40PowerIncForPdadc, 8)
0811                   | ATH9K_POW_SM(ratesArray[rateHt40_0] +
0812                          ht40PowerIncForPdadc, 0));
0813 
0814             REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
0815                   ATH9K_POW_SM(ratesArray[rateHt40_7] +
0816                            ht40PowerIncForPdadc, 24)
0817                   | ATH9K_POW_SM(ratesArray[rateHt40_6] +
0818                          ht40PowerIncForPdadc, 16)
0819                   | ATH9K_POW_SM(ratesArray[rateHt40_5] +
0820                          ht40PowerIncForPdadc, 8)
0821                   | ATH9K_POW_SM(ratesArray[rateHt40_4] +
0822                          ht40PowerIncForPdadc, 0));
0823         }
0824 
0825         /* Dup/Ext power per rate */
0826         REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
0827               ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
0828               | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
0829               | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
0830               | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
0831     }
0832 
0833     /* TPC initializations */
0834     if (ah->tpc_enabled) {
0835         int ht40_delta;
0836 
0837         ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
0838         ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
0839         /* Enable TPC */
0840         REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
0841             MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
0842     } else {
0843         /* Disable TPC */
0844         REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
0845     }
0846 
0847     REGWRITE_BUFFER_FLUSH(ah);
0848 }
0849 
0850 static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
0851                          struct ath9k_channel *chan)
0852 {
0853     struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0854     struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
0855     u32 regChainOffset, regval;
0856     u8 txRxAttenLocal;
0857     int i;
0858 
0859     pModal = &eep->modalHeader;
0860 
0861     REG_WRITE(ah, AR_PHY_SWITCH_COM, le32_to_cpu(pModal->antCtrlCommon));
0862 
0863     for (i = 0; i < AR9287_MAX_CHAINS; i++) {
0864         regChainOffset = i * 0x1000;
0865 
0866         REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
0867               le32_to_cpu(pModal->antCtrlChain[i]));
0868 
0869         REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
0870               (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset)
0871                & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
0872                    AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
0873               SM(pModal->iqCalICh[i],
0874                  AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
0875               SM(pModal->iqCalQCh[i],
0876                  AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
0877 
0878         txRxAttenLocal = pModal->txRxAttenCh[i];
0879 
0880         REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
0881                   AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
0882                   pModal->bswMargin[i]);
0883         REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
0884                   AR_PHY_GAIN_2GHZ_XATTEN1_DB,
0885                   pModal->bswAtten[i]);
0886         REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
0887                   AR9280_PHY_RXGAIN_TXRX_ATTEN,
0888                   txRxAttenLocal);
0889         REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
0890                   AR9280_PHY_RXGAIN_TXRX_MARGIN,
0891                   pModal->rxTxMarginCh[i]);
0892     }
0893 
0894 
0895     if (IS_CHAN_HT40(chan))
0896         REG_RMW_FIELD(ah, AR_PHY_SETTLING,
0897                   AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40);
0898     else
0899         REG_RMW_FIELD(ah, AR_PHY_SETTLING,
0900                   AR_PHY_SETTLING_SWITCH, pModal->switchSettling);
0901 
0902     REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
0903               AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);
0904 
0905     REG_WRITE(ah, AR_PHY_RF_CTL4,
0906           SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
0907           | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
0908           | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)
0909           | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
0910 
0911     REG_RMW_FIELD(ah, AR_PHY_RF_CTL3,
0912               AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn);
0913 
0914     REG_RMW_FIELD(ah, AR_PHY_CCA,
0915               AR9280_PHY_CCA_THRESH62, pModal->thresh62);
0916     REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
0917               AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
0918 
0919     regval = REG_READ(ah, AR9287_AN_RF2G3_CH0);
0920     regval &= ~(AR9287_AN_RF2G3_DB1 |
0921             AR9287_AN_RF2G3_DB2 |
0922             AR9287_AN_RF2G3_OB_CCK |
0923             AR9287_AN_RF2G3_OB_PSK |
0924             AR9287_AN_RF2G3_OB_QAM |
0925             AR9287_AN_RF2G3_OB_PAL_OFF);
0926     regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
0927            SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
0928            SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
0929            SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
0930            SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
0931            SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
0932 
0933     ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval);
0934 
0935     regval = REG_READ(ah, AR9287_AN_RF2G3_CH1);
0936     regval &= ~(AR9287_AN_RF2G3_DB1 |
0937             AR9287_AN_RF2G3_DB2 |
0938             AR9287_AN_RF2G3_OB_CCK |
0939             AR9287_AN_RF2G3_OB_PSK |
0940             AR9287_AN_RF2G3_OB_QAM |
0941             AR9287_AN_RF2G3_OB_PAL_OFF);
0942     regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
0943            SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
0944            SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
0945            SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
0946            SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
0947            SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
0948 
0949     ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval);
0950 
0951     REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
0952               AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
0953     REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
0954               AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn);
0955 
0956     ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2,
0957                   AR9287_AN_TOP2_XPABIAS_LVL,
0958                   AR9287_AN_TOP2_XPABIAS_LVL_S,
0959                   pModal->xpaBiasLvl);
0960 }
0961 
0962 static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
0963                         u16 i, bool is2GHz)
0964 {
0965     __le16 spur_ch = ah->eeprom.map9287.modalHeader.spurChans[i].spurChan;
0966 
0967     return le16_to_cpu(spur_ch);
0968 }
0969 
0970 static u8 ath9k_hw_ar9287_get_eepmisc(struct ath_hw *ah)
0971 {
0972     return ah->eeprom.map9287.baseEepHeader.eepMisc;
0973 }
0974 
0975 const struct eeprom_ops eep_ar9287_ops = {
0976     .check_eeprom       = ath9k_hw_ar9287_check_eeprom,
0977     .get_eeprom     = ath9k_hw_ar9287_get_eeprom,
0978     .fill_eeprom        = ath9k_hw_ar9287_fill_eeprom,
0979     .dump_eeprom        = ath9k_hw_ar9287_dump_eeprom,
0980     .get_eeprom_ver     = ath9k_hw_ar9287_get_eeprom_ver,
0981     .get_eeprom_rev     = ath9k_hw_ar9287_get_eeprom_rev,
0982     .set_board_values   = ath9k_hw_ar9287_set_board_values,
0983     .set_txpower        = ath9k_hw_ar9287_set_txpower,
0984     .get_spur_channel   = ath9k_hw_ar9287_get_spur_channel,
0985     .get_eepmisc        = ath9k_hw_ar9287_get_eepmisc
0986 };