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