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