1 /* 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $FreeBSD$ 18 */ 19 20 #include "opt_ah.h" 21 22 #include "ah.h" 23 #include "ah_internal.h" 24 #include "ah_devid.h" 25 26 #include "ah_eeprom_v14.h" 27 #include "ah_eeprom_9287.h" 28 29 #include "ar5416/ar5416.h" 30 #include "ar5416/ar5416reg.h" 31 #include "ar5416/ar5416phy.h" 32 33 #include "ar9002/ar9287phy.h" 34 #include "ar9002/ar9287an.h" 35 36 #include "ar9002/ar9287_olc.h" 37 #include "ar9002/ar9287_reset.h" 38 39 /* 40 * Set the TX power calibration table per-chain. 41 * 42 * This only supports open-loop TX power control for the AR9287. 43 */ 44 static void 45 ar9287SetPowerCalTable(struct ath_hal *ah, 46 const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset) 47 { 48 struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; 49 uint8_t *pCalBChans = NULL; 50 uint16_t pdGainOverlap_t2; 51 uint16_t numPiers = 0, i; 52 uint16_t numXpdGain, xpdMask; 53 uint16_t xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; 54 uint32_t regChainOffset; 55 HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 56 struct ar9287_eeprom *pEepData = &ee->ee_base; 57 58 xpdMask = pEepData->modalHeader.xpdGain; 59 60 if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= 61 AR9287_EEP_MINOR_VER_2) 62 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 63 else 64 pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), 65 AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 66 67 /* Note: Kiwi should only be 2ghz.. */ 68 if (IEEE80211_IS_CHAN_2GHZ(chan)) { 69 pCalBChans = pEepData->calFreqPier2G; 70 numPiers = AR9287_NUM_2G_CAL_PIERS; 71 pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0]; 72 AH5416(ah)->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; 73 } 74 numXpdGain = 0; 75 76 /* Calculate the value of xpdgains from the xpdGain Mask */ 77 for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 78 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 79 if (numXpdGain >= AR5416_NUM_PD_GAINS) 80 break; 81 xpdGainValues[numXpdGain] = 82 (uint16_t)(AR5416_PD_GAINS_IN_MASK-i); 83 numXpdGain++; 84 } 85 } 86 87 OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, 88 (numXpdGain - 1) & 0x3); 89 OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, 90 xpdGainValues[0]); 91 OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, 92 xpdGainValues[1]); 93 OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 94 xpdGainValues[2]); 95 96 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 97 regChainOffset = i * 0x1000; 98 99 if (pEepData->baseEepHeader.txMask & (1 << i)) { 100 int8_t txPower; 101 pRawDatasetOpenLoop = 102 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i]; 103 ar9287olcGetTxGainIndex(ah, chan, 104 pRawDatasetOpenLoop, 105 pCalBChans, numPiers, 106 &txPower); 107 ar9287olcSetPDADCs(ah, txPower, i); 108 } 109 } 110 111 *pTxPowerIndexOffset = 0; 112 } 113 114 115 /* XXX hard-coded values? */ 116 #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 117 118 /* 119 * ar9287SetPowerPerRateTable 120 * 121 * Sets the transmit power in the baseband for the given 122 * operating channel and mode. 123 * 124 * This is like the v14 EEPROM table except the 5GHz code. 125 */ 126 static HAL_BOOL 127 ar9287SetPowerPerRateTable(struct ath_hal *ah, 128 struct ar9287_eeprom *pEepData, 129 const struct ieee80211_channel *chan, 130 int16_t *ratesArray, uint16_t cfgCtl, 131 uint16_t AntennaReduction, 132 uint16_t twiceMaxRegulatoryPower, 133 uint16_t powerLimit) 134 { 135 #define N(a) (sizeof(a)/sizeof(a[0])) 136 /* Local defines to distinguish between extension and control CTL's */ 137 #define EXT_ADDITIVE (0x8000) 138 #define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) 139 #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 140 #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 141 142 uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 143 int i; 144 int16_t twiceLargestAntenna; 145 struct cal_ctl_data_ar9287 *rep; 146 CAL_TARGET_POWER_LEG targetPowerOfdm; 147 CAL_TARGET_POWER_LEG targetPowerCck = {0, {0, 0, 0, 0}}; 148 CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}; 149 CAL_TARGET_POWER_LEG targetPowerCckExt = {0, {0, 0, 0, 0}}; 150 CAL_TARGET_POWER_HT targetPowerHt20; 151 CAL_TARGET_POWER_HT targetPowerHt40 = {0, {0, 0, 0, 0}}; 152 int16_t scaledPower, minCtlPower; 153 154 #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 155 static const uint16_t ctlModesFor11g[] = { 156 CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 157 }; 158 const uint16_t *pCtlMode; 159 uint16_t numCtlModes, ctlMode, freq; 160 CHAN_CENTERS centers; 161 162 ar5416GetChannelCenters(ah, chan, ¢ers); 163 164 /* Compute TxPower reduction due to Antenna Gain */ 165 166 twiceLargestAntenna = AH_MAX( 167 pEepData->modalHeader.antennaGainCh[0], 168 pEepData->modalHeader.antennaGainCh[1]); 169 170 twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); 171 172 /* XXX setup for 5212 use (really used?) */ 173 ath_hal_eepromSet(ah, AR_EEP_ANTGAINMAX_2, twiceLargestAntenna); 174 175 /* 176 * scaledPower is the minimum of the user input power level and 177 * the regulatory allowed power level 178 */ 179 scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); 180 181 /* Reduce scaled Power by number of chains active to get to per chain tx power level */ 182 /* TODO: better value than these? */ 183 switch (owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask)) { 184 case 1: 185 break; 186 case 2: 187 scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; 188 break; 189 default: 190 return AH_FALSE; /* Unsupported number of chains */ 191 } 192 193 scaledPower = AH_MAX(0, scaledPower); 194 195 /* Get target powers from EEPROM - our baseline for TX Power */ 196 /* XXX assume channel is 2ghz */ 197 if (1) { 198 /* Setup for CTL modes */ 199 numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ 200 pCtlMode = ctlModesFor11g; 201 202 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 203 AR9287_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); 204 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 205 AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); 206 ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, 207 AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); 208 209 if (IEEE80211_IS_CHAN_HT40(chan)) { 210 numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ 211 212 ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, 213 AR9287_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); 214 /* Get target powers for extension channels */ 215 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 216 AR9287_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); 217 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 218 AR9287_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); 219 } 220 } 221 222 /* 223 * For MIMO, need to apply regulatory caps individually across dynamically 224 * running modes: CCK, OFDM, HT20, HT40 225 * 226 * The outer loop walks through each possible applicable runtime mode. 227 * The inner loop walks through each ctlIndex entry in EEPROM. 228 * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 229 * 230 */ 231 for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 232 HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || 233 (pCtlMode[ctlMode] == CTL_2GHT40); 234 if (isHt40CtlMode) { 235 freq = centers.ctl_center; 236 } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { 237 freq = centers.ext_center; 238 } else { 239 freq = centers.ctl_center; 240 } 241 242 /* walk through each CTL index stored in EEPROM */ 243 for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 244 uint16_t twiceMinEdgePower; 245 246 /* compare test group from regulatory channel list with test mode from pCtlMode list */ 247 if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || 248 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == 249 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { 250 rep = &(pEepData->ctlData[i]); 251 twiceMinEdgePower = ar5416GetMaxEdgePower(freq, 252 rep->ctlEdges[owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1], 253 IEEE80211_IS_CHAN_2GHZ(chan)); 254 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 255 /* Find the minimum of all CTL edge powers that apply to this channel */ 256 twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower); 257 } else { 258 /* specific */ 259 twiceMaxEdgePower = twiceMinEdgePower; 260 break; 261 } 262 } 263 } 264 minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); 265 /* Apply ctl mode to correct target power set */ 266 switch(pCtlMode[ctlMode]) { 267 case CTL_11B: 268 for (i = 0; i < N(targetPowerCck.tPow2x); i++) { 269 targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); 270 } 271 break; 272 case CTL_11A: 273 case CTL_11G: 274 for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { 275 targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); 276 } 277 break; 278 case CTL_5GHT20: 279 case CTL_2GHT20: 280 for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 281 targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); 282 } 283 break; 284 case CTL_11B_EXT: 285 targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); 286 break; 287 case CTL_11A_EXT: 288 case CTL_11G_EXT: 289 targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); 290 break; 291 case CTL_5GHT40: 292 case CTL_2GHT40: 293 for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 294 targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); 295 } 296 break; 297 default: 298 return AH_FALSE; 299 break; 300 } 301 } /* end ctl mode checking */ 302 303 /* Set rates Array from collected data */ 304 ar5416SetRatesArrayFromTargetPower(ah, chan, ratesArray, 305 &targetPowerCck, 306 &targetPowerCckExt, 307 &targetPowerOfdm, 308 &targetPowerOfdmExt, 309 &targetPowerHt20, 310 &targetPowerHt40); 311 return AH_TRUE; 312 #undef EXT_ADDITIVE 313 #undef CTL_11A_EXT 314 #undef CTL_11G_EXT 315 #undef CTL_11B_EXT 316 #undef SUB_NUM_CTL_MODES_AT_5G_40 317 #undef SUB_NUM_CTL_MODES_AT_2G_40 318 #undef N 319 } 320 321 #undef REDUCE_SCALED_POWER_BY_TWO_CHAIN 322 323 /* 324 * This is based off of the AR5416/AR9285 code and likely could 325 * be unified in the future. 326 */ 327 HAL_BOOL 328 ar9287SetTransmitPower(struct ath_hal *ah, 329 const struct ieee80211_channel *chan, uint16_t *rfXpdGain) 330 { 331 #define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) 332 #define N(a) (sizeof (a) / sizeof (a[0])) 333 334 const struct modal_eep_ar9287_header *pModal; 335 struct ath_hal_5212 *ahp = AH5212(ah); 336 int16_t ratesArray[Ar5416RateSize]; 337 int16_t txPowerIndexOffset = 0; 338 uint8_t ht40PowerIncForPdadc = 2; 339 int i; 340 341 uint16_t cfgCtl; 342 uint16_t powerLimit; 343 uint16_t twiceAntennaReduction; 344 uint16_t twiceMaxRegulatoryPower; 345 int16_t maxPower; 346 HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 347 struct ar9287_eeprom *pEepData = &ee->ee_base; 348 349 /* Setup info for the actual eeprom */ 350 OS_MEMZERO(ratesArray, sizeof(ratesArray)); 351 cfgCtl = ath_hal_getctl(ah, chan); 352 powerLimit = chan->ic_maxregpower * 2; 353 twiceAntennaReduction = chan->ic_maxantgain; 354 twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit); 355 pModal = &pEepData->modalHeader; 356 HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", 357 __func__,chan->ic_freq, cfgCtl ); 358 359 /* XXX Assume Minor is v2 or later */ 360 ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 361 362 /* Fetch per-rate power table for the given channel */ 363 if (! ar9287SetPowerPerRateTable(ah, pEepData, chan, 364 &ratesArray[0],cfgCtl, 365 twiceAntennaReduction, 366 twiceMaxRegulatoryPower, powerLimit)) { 367 HALDEBUG(ah, HAL_DEBUG_ANY, 368 "%s: unable to set tx power per rate table\n", __func__); 369 return AH_FALSE; 370 } 371 372 /* Set TX power control calibration curves for each TX chain */ 373 ar9287SetPowerCalTable(ah, chan, &txPowerIndexOffset); 374 375 /* Calculate maximum power level */ 376 maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]); 377 maxPower = AH_MAX(maxPower, ratesArray[rate1l]); 378 379 if (IEEE80211_IS_CHAN_HT40(chan)) 380 maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]); 381 382 ahp->ah_tx6PowerInHalfDbm = maxPower; 383 AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; 384 ahp->ah_txPowerIndexOffset = txPowerIndexOffset; 385 386 /* 387 * txPowerIndexOffset is set by the SetPowerTable() call - 388 * adjust the rate table (0 offset if rates EEPROM not loaded) 389 */ 390 /* XXX what about the pwrTableOffset? */ 391 for (i = 0; i < N(ratesArray); i++) { 392 ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); 393 /* -5 dBm offset for Merlin and later; this includes Kiwi */ 394 ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; 395 if (ratesArray[i] > AR5416_MAX_RATE_POWER) 396 ratesArray[i] = AR5416_MAX_RATE_POWER; 397 if (ratesArray[i] < 0) 398 ratesArray[i] = 0; 399 } 400 401 #ifdef AH_EEPROM_DUMP 402 ar5416PrintPowerPerRate(ah, ratesArray); 403 #endif 404 405 /* 406 * Adjust the HT40 power to meet the correct target TX power 407 * for 40MHz mode, based on TX power curves that are established 408 * for 20MHz mode. 409 * 410 * XXX handle overflow/too high power level? 411 */ 412 if (IEEE80211_IS_CHAN_HT40(chan)) { 413 ratesArray[rateHt40_0] += ht40PowerIncForPdadc; 414 ratesArray[rateHt40_1] += ht40PowerIncForPdadc; 415 ratesArray[rateHt40_2] += ht40PowerIncForPdadc; 416 ratesArray[rateHt40_3] += ht40PowerIncForPdadc; 417 ratesArray[rateHt40_4] += ht40PowerIncForPdadc; 418 ratesArray[rateHt40_5] += ht40PowerIncForPdadc; 419 ratesArray[rateHt40_6] += ht40PowerIncForPdadc; 420 ratesArray[rateHt40_7] += ht40PowerIncForPdadc; 421 } 422 423 /* Write the TX power rate registers */ 424 ar5416WriteTxPowerRateRegisters(ah, chan, ratesArray); 425 426 return AH_TRUE; 427 #undef POW_SM 428 #undef N 429 } 430 431 /* 432 * Read EEPROM header info and program the device for correct operation 433 * given the channel value. 434 */ 435 HAL_BOOL 436 ar9287SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) 437 { 438 const HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 439 const struct ar9287_eeprom *eep = &ee->ee_base; 440 const struct modal_eep_ar9287_header *pModal = &eep->modalHeader; 441 uint16_t antWrites[AR9287_ANT_16S]; 442 uint32_t regChainOffset, regval; 443 uint8_t txRxAttenLocal; 444 int i, j, offset_num; 445 446 pModal = &eep->modalHeader; 447 448 antWrites[0] = (uint16_t)((pModal->antCtrlCommon >> 28) & 0xF); 449 antWrites[1] = (uint16_t)((pModal->antCtrlCommon >> 24) & 0xF); 450 antWrites[2] = (uint16_t)((pModal->antCtrlCommon >> 20) & 0xF); 451 antWrites[3] = (uint16_t)((pModal->antCtrlCommon >> 16) & 0xF); 452 antWrites[4] = (uint16_t)((pModal->antCtrlCommon >> 12) & 0xF); 453 antWrites[5] = (uint16_t)((pModal->antCtrlCommon >> 8) & 0xF); 454 antWrites[6] = (uint16_t)((pModal->antCtrlCommon >> 4) & 0xF); 455 antWrites[7] = (uint16_t)(pModal->antCtrlCommon & 0xF); 456 457 offset_num = 8; 458 459 for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { 460 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 28) & 0xf); 461 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 10) & 0x3); 462 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 8) & 0x3); 463 antWrites[j++] = 0; 464 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 6) & 0x3); 465 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 4) & 0x3); 466 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 2) & 0x3); 467 antWrites[j++] = (uint16_t)(pModal->antCtrlChain[i] & 0x3); 468 } 469 470 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 471 472 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 473 regChainOffset = i * 0x1000; 474 475 OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, 476 pModal->antCtrlChain[i]); 477 478 OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) + regChainOffset, 479 (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) + regChainOffset) 480 & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 481 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 482 SM(pModal->iqCalICh[i], 483 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 484 SM(pModal->iqCalQCh[i], 485 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 486 487 txRxAttenLocal = pModal->txRxAttenCh[i]; 488 489 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 490 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 491 pModal->bswMargin[i]); 492 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 493 AR_PHY_GAIN_2GHZ_XATTEN1_DB, 494 pModal->bswAtten[i]); 495 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 496 AR9280_PHY_RXGAIN_TXRX_ATTEN, 497 txRxAttenLocal); 498 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 499 AR9280_PHY_RXGAIN_TXRX_MARGIN, 500 pModal->rxTxMarginCh[i]); 501 } 502 503 504 if (IEEE80211_IS_CHAN_HT40(chan)) 505 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 506 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 507 else 508 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 509 AR_PHY_SETTLING_SWITCH, pModal->switchSettling); 510 511 OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 512 AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); 513 514 OS_REG_WRITE(ah, AR_PHY_RF_CTL4, 515 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) 516 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) 517 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) 518 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 519 520 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, 521 AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); 522 523 OS_REG_RMW_FIELD(ah, AR_PHY_CCA, 524 AR9280_PHY_CCA_THRESH62, pModal->thresh62); 525 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, 526 AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); 527 528 regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH0); 529 regval &= ~(AR9287_AN_RF2G3_DB1 | 530 AR9287_AN_RF2G3_DB2 | 531 AR9287_AN_RF2G3_OB_CCK | 532 AR9287_AN_RF2G3_OB_PSK | 533 AR9287_AN_RF2G3_OB_QAM | 534 AR9287_AN_RF2G3_OB_PAL_OFF); 535 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 536 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 537 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 538 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 539 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 540 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 541 542 OS_REG_WRITE(ah, AR9287_AN_RF2G3_CH0, regval); 543 OS_DELAY(100); /* analog write */ 544 545 regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH1); 546 regval &= ~(AR9287_AN_RF2G3_DB1 | 547 AR9287_AN_RF2G3_DB2 | 548 AR9287_AN_RF2G3_OB_CCK | 549 AR9287_AN_RF2G3_OB_PSK | 550 AR9287_AN_RF2G3_OB_QAM | 551 AR9287_AN_RF2G3_OB_PAL_OFF); 552 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 553 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 554 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 555 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 556 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 557 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 558 559 OS_REG_WRITE(ah, AR9287_AN_RF2G3_CH1, regval); 560 OS_DELAY(100); /* analog write */ 561 562 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 563 AR_PHY_TX_FRAME_TO_DATA_START, pModal->txFrameToDataStart); 564 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 565 AR_PHY_TX_FRAME_TO_PA_ON, pModal->txFrameToPaOn); 566 567 OS_A_REG_RMW_FIELD(ah, AR9287_AN_TOP2, 568 AR9287_AN_TOP2_XPABIAS_LVL, pModal->xpaBiasLvl); 569 570 return AH_TRUE; 571 } 572