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 txPowerIndexOffset = 0; 337 int i; 338 339 uint16_t cfgCtl; 340 uint16_t powerLimit; 341 uint16_t twiceAntennaReduction; 342 uint16_t twiceMaxRegulatoryPower; 343 int16_t maxPower; 344 HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 345 struct ar9287_eeprom *pEepData = &ee->ee_base; 346 347 AH5416(ah)->ah_ht40PowerIncForPdadc = 2; 348 349 /* Setup info for the actual eeprom */ 350 OS_MEMZERO(AH5416(ah)->ah_ratesArray, 351 sizeof(AH5416(ah)->ah_ratesArray)); 352 cfgCtl = ath_hal_getctl(ah, chan); 353 powerLimit = chan->ic_maxregpower * 2; 354 twiceAntennaReduction = chan->ic_maxantgain; 355 twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, 356 AH_PRIVATE(ah)->ah_powerLimit); 357 pModal = &pEepData->modalHeader; 358 HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", 359 __func__,chan->ic_freq, cfgCtl ); 360 361 /* XXX Assume Minor is v2 or later */ 362 AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 363 364 /* Fetch per-rate power table for the given channel */ 365 if (! ar9287SetPowerPerRateTable(ah, pEepData, chan, 366 &AH5416(ah)->ah_ratesArray[0], 367 cfgCtl, 368 twiceAntennaReduction, 369 twiceMaxRegulatoryPower, powerLimit)) { 370 HALDEBUG(ah, HAL_DEBUG_ANY, 371 "%s: unable to set tx power per rate table\n", __func__); 372 return AH_FALSE; 373 } 374 375 /* Set TX power control calibration curves for each TX chain */ 376 ar9287SetPowerCalTable(ah, chan, &txPowerIndexOffset); 377 378 /* Calculate maximum power level */ 379 maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb], 380 AH5416(ah)->ah_ratesArray[rateHt20_0]); 381 maxPower = AH_MAX(maxPower, 382 AH5416(ah)->ah_ratesArray[rate1l]); 383 384 if (IEEE80211_IS_CHAN_HT40(chan)) 385 maxPower = AH_MAX(maxPower, 386 AH5416(ah)->ah_ratesArray[rateHt40_0]); 387 388 ahp->ah_tx6PowerInHalfDbm = maxPower; 389 AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; 390 ahp->ah_txPowerIndexOffset = txPowerIndexOffset; 391 392 /* 393 * txPowerIndexOffset is set by the SetPowerTable() call - 394 * adjust the rate table (0 offset if rates EEPROM not loaded) 395 */ 396 /* XXX what about the pwrTableOffset? */ 397 for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) { 398 AH5416(ah)->ah_ratesArray[i] = 399 (int16_t)(txPowerIndexOffset + 400 AH5416(ah)->ah_ratesArray[i]); 401 /* -5 dBm offset for Merlin and later; this includes Kiwi */ 402 AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; 403 if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER) 404 AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER; 405 if (AH5416(ah)->ah_ratesArray[i] < 0) 406 AH5416(ah)->ah_ratesArray[i] = 0; 407 } 408 409 #ifdef AH_EEPROM_DUMP 410 ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray); 411 #endif 412 413 /* 414 * Adjust the HT40 power to meet the correct target TX power 415 * for 40MHz mode, based on TX power curves that are established 416 * for 20MHz mode. 417 * 418 * XXX handle overflow/too high power level? 419 */ 420 if (IEEE80211_IS_CHAN_HT40(chan)) { 421 AH5416(ah)->ah_ratesArray[rateHt40_0] += 422 AH5416(ah)->ah_ht40PowerIncForPdadc; 423 AH5416(ah)->ah_ratesArray[rateHt40_1] += 424 AH5416(ah)->ah_ht40PowerIncForPdadc; 425 AH5416(ah)->ah_ratesArray[rateHt40_2] += 426 AH5416(ah)->ah_ht40PowerIncForPdadc; 427 AH5416(ah)->ah_ratesArray[rateHt40_3] += 428 AH5416(ah)->ah_ht40PowerIncForPdadc; 429 AH5416(ah)->ah_ratesArray[rateHt40_4] += 430 AH5416(ah)->ah_ht40PowerIncForPdadc; 431 AH5416(ah)->ah_ratesArray[rateHt40_5] += 432 AH5416(ah)->ah_ht40PowerIncForPdadc; 433 AH5416(ah)->ah_ratesArray[rateHt40_6] += 434 AH5416(ah)->ah_ht40PowerIncForPdadc; 435 AH5416(ah)->ah_ratesArray[rateHt40_7] += 436 AH5416(ah)->ah_ht40PowerIncForPdadc; 437 } 438 439 /* Write the TX power rate registers */ 440 ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray); 441 442 return AH_TRUE; 443 #undef POW_SM 444 #undef N 445 } 446 447 /* 448 * Read EEPROM header info and program the device for correct operation 449 * given the channel value. 450 */ 451 HAL_BOOL 452 ar9287SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) 453 { 454 const HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom; 455 const struct ar9287_eeprom *eep = &ee->ee_base; 456 const struct modal_eep_ar9287_header *pModal = &eep->modalHeader; 457 uint16_t antWrites[AR9287_ANT_16S]; 458 uint32_t regChainOffset, regval; 459 uint8_t txRxAttenLocal; 460 int i, j, offset_num; 461 462 pModal = &eep->modalHeader; 463 464 antWrites[0] = (uint16_t)((pModal->antCtrlCommon >> 28) & 0xF); 465 antWrites[1] = (uint16_t)((pModal->antCtrlCommon >> 24) & 0xF); 466 antWrites[2] = (uint16_t)((pModal->antCtrlCommon >> 20) & 0xF); 467 antWrites[3] = (uint16_t)((pModal->antCtrlCommon >> 16) & 0xF); 468 antWrites[4] = (uint16_t)((pModal->antCtrlCommon >> 12) & 0xF); 469 antWrites[5] = (uint16_t)((pModal->antCtrlCommon >> 8) & 0xF); 470 antWrites[6] = (uint16_t)((pModal->antCtrlCommon >> 4) & 0xF); 471 antWrites[7] = (uint16_t)(pModal->antCtrlCommon & 0xF); 472 473 offset_num = 8; 474 475 for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) { 476 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 28) & 0xf); 477 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 10) & 0x3); 478 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 8) & 0x3); 479 antWrites[j++] = 0; 480 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 6) & 0x3); 481 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 4) & 0x3); 482 antWrites[j++] = (uint16_t)((pModal->antCtrlChain[i] >> 2) & 0x3); 483 antWrites[j++] = (uint16_t)(pModal->antCtrlChain[i] & 0x3); 484 } 485 486 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 487 488 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 489 regChainOffset = i * 0x1000; 490 491 OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, 492 pModal->antCtrlChain[i]); 493 494 OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) + regChainOffset, 495 (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0) 496 + regChainOffset) 497 & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 498 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 499 SM(pModal->iqCalICh[i], 500 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 501 SM(pModal->iqCalQCh[i], 502 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 503 504 txRxAttenLocal = pModal->txRxAttenCh[i]; 505 506 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 507 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 508 pModal->bswMargin[i]); 509 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 510 AR_PHY_GAIN_2GHZ_XATTEN1_DB, 511 pModal->bswAtten[i]); 512 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 513 AR9280_PHY_RXGAIN_TXRX_ATTEN, 514 txRxAttenLocal); 515 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 516 AR9280_PHY_RXGAIN_TXRX_MARGIN, 517 pModal->rxTxMarginCh[i]); 518 } 519 520 if (IEEE80211_IS_CHAN_HT40(chan)) 521 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 522 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 523 else 524 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 525 AR_PHY_SETTLING_SWITCH, pModal->switchSettling); 526 527 OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 528 AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); 529 530 OS_REG_WRITE(ah, AR_PHY_RF_CTL4, 531 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) 532 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) 533 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) 534 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 535 536 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, 537 AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); 538 539 OS_REG_RMW_FIELD(ah, AR_PHY_CCA, 540 AR9280_PHY_CCA_THRESH62, pModal->thresh62); 541 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, 542 AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); 543 544 regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH0); 545 regval &= ~(AR9287_AN_RF2G3_DB1 | 546 AR9287_AN_RF2G3_DB2 | 547 AR9287_AN_RF2G3_OB_CCK | 548 AR9287_AN_RF2G3_OB_PSK | 549 AR9287_AN_RF2G3_OB_QAM | 550 AR9287_AN_RF2G3_OB_PAL_OFF); 551 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 552 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 553 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 554 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 555 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 556 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 557 558 /* Analog write - requires a 100usec delay */ 559 OS_A_REG_WRITE(ah, AR9287_AN_RF2G3_CH0, regval); 560 561 regval = OS_REG_READ(ah, AR9287_AN_RF2G3_CH1); 562 regval &= ~(AR9287_AN_RF2G3_DB1 | 563 AR9287_AN_RF2G3_DB2 | 564 AR9287_AN_RF2G3_OB_CCK | 565 AR9287_AN_RF2G3_OB_PSK | 566 AR9287_AN_RF2G3_OB_QAM | 567 AR9287_AN_RF2G3_OB_PAL_OFF); 568 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 569 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 570 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 571 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 572 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 573 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 574 575 OS_A_REG_WRITE(ah, AR9287_AN_RF2G3_CH1, regval); 576 577 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 578 AR_PHY_TX_FRAME_TO_DATA_START, pModal->txFrameToDataStart); 579 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 580 AR_PHY_TX_FRAME_TO_PA_ON, pModal->txFrameToPaOn); 581 582 OS_A_REG_RMW_FIELD(ah, AR9287_AN_TOP2, 583 AR9287_AN_TOP2_XPABIAS_LVL, pModal->xpaBiasLvl); 584 585 return AH_TRUE; 586 } 587