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