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 /* 23 * This is almost the same as ar5416_reset.c but uses the v4k EEPROM and 24 * supports only 2Ghz operation. 25 */ 26 27 #include "opt_ah.h" 28 29 #include "ah.h" 30 #include "ah_internal.h" 31 #include "ah_devid.h" 32 33 #include "ah_eeprom_v14.h" 34 #include "ah_eeprom_v4k.h" 35 36 #include "ar9002/ar9285.h" 37 #include "ar5416/ar5416.h" 38 #include "ar5416/ar5416reg.h" 39 #include "ar5416/ar5416phy.h" 40 #include "ar9002/ar9002phy.h" 41 #include "ar9002/ar9285phy.h" 42 #include "ar9002/ar9285an.h" 43 #include "ar9002/ar9285_diversity.h" 44 45 /* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */ 46 #define EEP_MINOR(_ah) \ 47 (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK) 48 #define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2) 49 #define IS_EEP_MINOR_V3(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3) 50 51 /* Additional Time delay to wait after activiting the Base band */ 52 #define BASE_ACTIVATE_DELAY 100 /* 100 usec */ 53 #define PLL_SETTLE_DELAY 300 /* 300 usec */ 54 #define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */ 55 56 static HAL_BOOL ar9285SetPowerPerRateTable(struct ath_hal *ah, 57 struct ar5416eeprom_4k *pEepData, 58 const struct ieee80211_channel *chan, int16_t *ratesArray, 59 uint16_t cfgCtl, uint16_t AntennaReduction, 60 uint16_t twiceMaxRegulatoryPower, 61 uint16_t powerLimit); 62 static HAL_BOOL ar9285SetPowerCalTable(struct ath_hal *ah, 63 struct ar5416eeprom_4k *pEepData, 64 const struct ieee80211_channel *chan, 65 int16_t *pTxPowerIndexOffset); 66 static void ar9285GetGainBoundariesAndPdadcs(struct ath_hal *ah, 67 const struct ieee80211_channel *chan, CAL_DATA_PER_FREQ_4K *pRawDataSet, 68 uint8_t * bChans, uint16_t availPiers, 69 uint16_t tPdGainOverlap, int16_t *pMinCalPower, 70 uint16_t * pPdGainBoundaries, uint8_t * pPDADCValues, 71 uint16_t numXpdGains); 72 73 HAL_BOOL 74 ar9285SetTransmitPower(struct ath_hal *ah, 75 const struct ieee80211_channel *chan, uint16_t *rfXpdGain) 76 { 77 #define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) 78 #define N(a) (sizeof (a) / sizeof (a[0])) 79 80 MODAL_EEP4K_HEADER *pModal; 81 struct ath_hal_5212 *ahp = AH5212(ah); 82 int16_t txPowerIndexOffset = 0; 83 int i; 84 85 uint16_t cfgCtl; 86 uint16_t powerLimit; 87 uint16_t twiceAntennaReduction; 88 uint16_t twiceMaxRegulatoryPower; 89 int16_t maxPower; 90 HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 91 struct ar5416eeprom_4k *pEepData = &ee->ee_base; 92 93 HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); 94 95 AH5416(ah)->ah_ht40PowerIncForPdadc = 2; 96 97 /* Setup info for the actual eeprom */ 98 OS_MEMZERO(AH5416(ah)->ah_ratesArray, sizeof(AH5416(ah)->ah_ratesArray)); 99 cfgCtl = ath_hal_getctl(ah, chan); 100 powerLimit = chan->ic_maxregpower * 2; 101 twiceAntennaReduction = chan->ic_maxantgain; 102 twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit); 103 pModal = &pEepData->modalHeader; 104 HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", 105 __func__,chan->ic_freq, cfgCtl ); 106 107 if (IS_EEP_MINOR_V2(ah)) { 108 AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 109 } 110 111 if (!ar9285SetPowerPerRateTable(ah, pEepData, chan, 112 &AH5416(ah)->ah_ratesArray[0],cfgCtl, 113 twiceAntennaReduction, 114 twiceMaxRegulatoryPower, powerLimit)) { 115 HALDEBUG(ah, HAL_DEBUG_ANY, 116 "%s: unable to set tx power per rate table\n", __func__); 117 return AH_FALSE; 118 } 119 120 if (!ar9285SetPowerCalTable(ah, pEepData, chan, &txPowerIndexOffset)) { 121 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n", 122 __func__); 123 return AH_FALSE; 124 } 125 126 maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb], 127 AH5416(ah)->ah_ratesArray[rateHt20_0]); 128 maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rate1l]); 129 130 if (IEEE80211_IS_CHAN_HT40(chan)) { 131 maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rateHt40_0]); 132 } 133 134 ahp->ah_tx6PowerInHalfDbm = maxPower; 135 AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; 136 ahp->ah_txPowerIndexOffset = txPowerIndexOffset; 137 138 /* 139 * txPowerIndexOffset is set by the SetPowerTable() call - 140 * adjust the rate table (0 offset if rates EEPROM not loaded) 141 */ 142 for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) { 143 AH5416(ah)->ah_ratesArray[i] = (int16_t)(txPowerIndexOffset + AH5416(ah)->ah_ratesArray[i]); 144 /* -5 dBm offset for Merlin and later; this includes Kite */ 145 AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; 146 if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER) 147 AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER; 148 if (AH5416(ah)->ah_ratesArray[i] < 0) 149 AH5416(ah)->ah_ratesArray[i] = 0; 150 } 151 152 #ifdef AH_EEPROM_DUMP 153 ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray); 154 #endif 155 156 /* 157 * Adjust the HT40 power to meet the correct target TX power 158 * for 40MHz mode, based on TX power curves that are established 159 * for 20MHz mode. 160 * 161 * XXX handle overflow/too high power level? 162 */ 163 if (IEEE80211_IS_CHAN_HT40(chan)) { 164 AH5416(ah)->ah_ratesArray[rateHt40_0] += 165 AH5416(ah)->ah_ht40PowerIncForPdadc; 166 AH5416(ah)->ah_ratesArray[rateHt40_1] += 167 AH5416(ah)->ah_ht40PowerIncForPdadc; 168 AH5416(ah)->ah_ratesArray[rateHt40_2] += 169 AH5416(ah)->ah_ht40PowerIncForPdadc; 170 AH5416(ah)->ah_ratesArray[rateHt40_3] += 171 AH5416(ah)->ah_ht40PowerIncForPdadc; 172 AH5416(ah)->ah_ratesArray[rateHt40_4] += 173 AH5416(ah)->ah_ht40PowerIncForPdadc; 174 AH5416(ah)->ah_ratesArray[rateHt40_5] += 175 AH5416(ah)->ah_ht40PowerIncForPdadc; 176 AH5416(ah)->ah_ratesArray[rateHt40_6] += 177 AH5416(ah)->ah_ht40PowerIncForPdadc; 178 AH5416(ah)->ah_ratesArray[rateHt40_7] += 179 AH5416(ah)->ah_ht40PowerIncForPdadc; 180 } 181 182 /* Write the TX power rate registers */ 183 ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray); 184 185 return AH_TRUE; 186 #undef POW_SM 187 #undef N 188 } 189 190 static void 191 ar9285SetBoardGain(struct ath_hal *ah, const MODAL_EEP4K_HEADER *pModal, 192 const struct ar5416eeprom_4k *eep, uint8_t txRxAttenLocal) 193 { 194 OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, 195 pModal->antCtrlChain[0]); 196 197 OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), 198 (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)) & 199 ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 200 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 201 SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 202 SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 203 204 if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 205 AR5416_EEP_MINOR_VER_3) { 206 txRxAttenLocal = pModal->txRxAttenCh[0]; 207 208 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 209 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); 210 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 211 AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); 212 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 213 AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, pModal->xatten2Margin[0]); 214 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, 215 AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); 216 217 /* Set the block 1 value to block 0 value */ 218 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 219 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 220 pModal->bswMargin[0]); 221 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 222 AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); 223 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 224 AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, 225 pModal->xatten2Margin[0]); 226 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 227 AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); 228 } 229 230 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, 231 AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); 232 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, 233 AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); 234 235 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, 236 AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); 237 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, 238 AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); 239 } 240 241 /* 242 * Read EEPROM header info and program the device for correct operation 243 * given the channel value. 244 */ 245 HAL_BOOL 246 ar9285SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) 247 { 248 const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 249 const struct ar5416eeprom_4k *eep = &ee->ee_base; 250 const MODAL_EEP4K_HEADER *pModal; 251 uint8_t txRxAttenLocal; 252 uint8_t ob[5], db1[5], db2[5]; 253 254 pModal = &eep->modalHeader; 255 txRxAttenLocal = 23; 256 257 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 258 259 /* Single chain for 4K EEPROM*/ 260 ar9285SetBoardGain(ah, pModal, eep, txRxAttenLocal); 261 262 /* Initialize Ant Diversity settings if supported */ 263 (void) ar9285SetAntennaSwitch(ah, AH5212(ah)->ah_antControl); 264 265 /* Configure TX power calibration */ 266 if (pModal->version >= 2) { 267 ob[0] = pModal->ob_0; 268 ob[1] = pModal->ob_1; 269 ob[2] = pModal->ob_2; 270 ob[3] = pModal->ob_3; 271 ob[4] = pModal->ob_4; 272 273 db1[0] = pModal->db1_0; 274 db1[1] = pModal->db1_1; 275 db1[2] = pModal->db1_2; 276 db1[3] = pModal->db1_3; 277 db1[4] = pModal->db1_4; 278 279 db2[0] = pModal->db2_0; 280 db2[1] = pModal->db2_1; 281 db2[2] = pModal->db2_2; 282 db2[3] = pModal->db2_3; 283 db2[4] = pModal->db2_4; 284 } else if (pModal->version == 1) { 285 ob[0] = pModal->ob_0; 286 ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1; 287 db1[0] = pModal->db1_0; 288 db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1; 289 db2[0] = pModal->db2_0; 290 db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1; 291 } else { 292 int i; 293 294 for (i = 0; i < 5; i++) { 295 ob[i] = pModal->ob_0; 296 db1[i] = pModal->db1_0; 297 db2[i] = pModal->db1_0; 298 } 299 } 300 301 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_0, ob[0]); 302 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_1, ob[1]); 303 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_2, ob[2]); 304 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_3, ob[3]); 305 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_OB_4, ob[4]); 306 307 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_0, db1[0]); 308 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_1, db1[1]); 309 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_DB1_2, db1[2]); 310 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB1_3, db1[3]); 311 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB1_4, db1[4]); 312 313 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_0, db2[0]); 314 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_1, db2[1]); 315 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_2, db2[2]); 316 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_3, db2[3]); 317 OS_A_REG_RMW_FIELD(ah, AR9285_AN_RF2G4, AR9285_AN_RF2G4_DB2_4, db2[4]); 318 319 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, 320 pModal->switchSettling); 321 OS_REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, 322 pModal->adcDesiredSize); 323 324 OS_REG_WRITE(ah, AR_PHY_RF_CTL4, 325 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | 326 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | 327 SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | 328 SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 329 330 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, 331 pModal->txEndToRxOn); 332 333 OS_REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, 334 pModal->thresh62); 335 OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, 336 pModal->thresh62); 337 338 if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 339 AR5416_EEP_MINOR_VER_2) { 340 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_DATA_START, 341 pModal->txFrameToDataStart); 342 OS_REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_FRAME_TO_PA_ON, 343 pModal->txFrameToPaOn); 344 } 345 346 if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= 347 AR5416_EEP_MINOR_VER_3) { 348 if (IEEE80211_IS_CHAN_HT40(chan)) 349 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, 350 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 351 } 352 353 /* 354 * Program the CCK TX gain factor appropriately if needed. 355 * The AR9285/AR9271 has a non-constant PA tx gain behaviour 356 * for CCK versus OFDM rates; other chips deal with this 357 * differently. 358 * 359 * The mask/shift/multiply hackery is done so place the same 360 * value (bb_desired_scale) into multiple 5-bit fields. 361 * For example, AR_PHY_TX_PWRCTRL9 has bb_desired_scale written 362 * to three fields: (0..4), (5..9) and (10..14). 363 */ 364 if (AR_SREV_9271(ah) || AR_SREV_KITE(ah)) { 365 uint8_t bb_desired_scale = (pModal->bb_scale_smrt_antenna & EEP_4K_BB_DESIRED_SCALE_MASK); 366 if ((eep->baseEepHeader.txGainType == 0) && (bb_desired_scale != 0)) { 367 ath_hal_printf(ah, "[ath]: adjusting cck tx gain factor\n"); 368 uint32_t pwrctrl, mask, clr; 369 370 mask = (1<<0) | (1<<5) | (1<<10) | (1<<15) | (1<<20) | (1<<25); 371 pwrctrl = mask * bb_desired_scale; 372 clr = mask * 0x1f; 373 OS_REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr); 374 OS_REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr); 375 OS_REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr); 376 377 mask = (1<<0) | (1<<5) | (1<<15); 378 pwrctrl = mask * bb_desired_scale; 379 clr = mask * 0x1f; 380 OS_REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr); 381 382 mask = (1<<0) | (1<<5); 383 pwrctrl = mask * bb_desired_scale; 384 clr = mask * 0x1f; 385 OS_REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); 386 OS_REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); 387 } 388 } 389 390 return AH_TRUE; 391 } 392 393 /* 394 * Helper functions common for AP/CB/XB 395 */ 396 397 static HAL_BOOL 398 ar9285SetPowerPerRateTable(struct ath_hal *ah, struct ar5416eeprom_4k *pEepData, 399 const struct ieee80211_channel *chan, 400 int16_t *ratesArray, uint16_t cfgCtl, 401 uint16_t AntennaReduction, 402 uint16_t twiceMaxRegulatoryPower, 403 uint16_t powerLimit) 404 { 405 #define N(a) (sizeof(a)/sizeof(a[0])) 406 /* Local defines to distinguish between extension and control CTL's */ 407 #define EXT_ADDITIVE (0x8000) 408 #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 409 #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 410 411 uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 412 int i; 413 int16_t twiceLargestAntenna; 414 CAL_CTL_DATA_4K *rep; 415 CAL_TARGET_POWER_LEG targetPowerOfdm, targetPowerCck = {0, {0, 0, 0, 0}}; 416 CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}, targetPowerCckExt = {0, {0, 0, 0, 0}}; 417 CAL_TARGET_POWER_HT targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0}}; 418 int16_t scaledPower, minCtlPower; 419 420 #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 421 static const uint16_t ctlModesFor11g[] = { 422 CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 423 }; 424 const uint16_t *pCtlMode; 425 uint16_t numCtlModes, ctlMode, freq; 426 CHAN_CENTERS centers; 427 428 ar5416GetChannelCenters(ah, chan, ¢ers); 429 430 /* Compute TxPower reduction due to Antenna Gain */ 431 432 twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; 433 twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); 434 435 /* XXX setup for 5212 use (really used?) */ 436 ath_hal_eepromSet(ah, AR_EEP_ANTGAINMAX_2, twiceLargestAntenna); 437 438 /* 439 * scaledPower is the minimum of the user input power level and 440 * the regulatory allowed power level 441 */ 442 scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); 443 444 /* Get target powers from EEPROM - our baseline for TX Power */ 445 /* Setup for CTL modes */ 446 numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ 447 pCtlMode = ctlModesFor11g; 448 449 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 450 AR5416_4K_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); 451 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 452 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); 453 ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, 454 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); 455 456 if (IEEE80211_IS_CHAN_HT40(chan)) { 457 numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ 458 459 ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, 460 AR5416_4K_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); 461 /* Get target powers for extension channels */ 462 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 463 AR5416_4K_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); 464 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 465 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); 466 } 467 468 /* 469 * For MIMO, need to apply regulatory caps individually across dynamically 470 * running modes: CCK, OFDM, HT20, HT40 471 * 472 * The outer loop walks through each possible applicable runtime mode. 473 * The inner loop walks through each ctlIndex entry in EEPROM. 474 * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 475 * 476 */ 477 for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 478 HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || 479 (pCtlMode[ctlMode] == CTL_2GHT40); 480 if (isHt40CtlMode) { 481 freq = centers.ctl_center; 482 } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { 483 freq = centers.ext_center; 484 } else { 485 freq = centers.ctl_center; 486 } 487 488 /* walk through each CTL index stored in EEPROM */ 489 for (i = 0; (i < AR5416_4K_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 490 uint16_t twiceMinEdgePower; 491 492 /* compare test group from regulatory channel list with test mode from pCtlMode list */ 493 if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || 494 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == 495 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { 496 rep = &(pEepData->ctlData[i]); 497 twiceMinEdgePower = ar5416GetMaxEdgePower(freq, 498 rep->ctlEdges[ 499 owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1], AH_TRUE); 500 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 501 /* Find the minimum of all CTL edge powers that apply to this channel */ 502 twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower); 503 } else { 504 /* specific */ 505 twiceMaxEdgePower = twiceMinEdgePower; 506 break; 507 } 508 } 509 } 510 minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); 511 /* Apply ctl mode to correct target power set */ 512 switch(pCtlMode[ctlMode]) { 513 case CTL_11B: 514 for (i = 0; i < N(targetPowerCck.tPow2x); i++) { 515 targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); 516 } 517 break; 518 case CTL_11A: 519 case CTL_11G: 520 for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { 521 targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); 522 } 523 break; 524 case CTL_5GHT20: 525 case CTL_2GHT20: 526 for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 527 targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); 528 } 529 break; 530 case CTL_11B_EXT: 531 targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); 532 break; 533 case CTL_11G_EXT: 534 targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); 535 break; 536 case CTL_5GHT40: 537 case CTL_2GHT40: 538 for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 539 targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); 540 } 541 break; 542 default: 543 return AH_FALSE; 544 break; 545 } 546 } /* end ctl mode checking */ 547 548 /* Set rates Array from collected data */ 549 ar5416SetRatesArrayFromTargetPower(ah, chan, ratesArray, 550 &targetPowerCck, 551 &targetPowerCckExt, 552 &targetPowerOfdm, 553 &targetPowerOfdmExt, 554 &targetPowerHt20, 555 &targetPowerHt40); 556 557 return AH_TRUE; 558 #undef EXT_ADDITIVE 559 #undef CTL_11G_EXT 560 #undef CTL_11B_EXT 561 #undef SUB_NUM_CTL_MODES_AT_2G_40 562 #undef N 563 } 564 565 static HAL_BOOL 566 ar9285SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom_4k *pEepData, 567 const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset) 568 { 569 CAL_DATA_PER_FREQ_4K *pRawDataset; 570 uint8_t *pCalBChans = AH_NULL; 571 uint16_t pdGainOverlap_t2; 572 static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES]; 573 uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK]; 574 uint16_t numPiers, i; 575 int16_t tMinCalPower; 576 uint16_t numXpdGain, xpdMask; 577 uint16_t xpdGainValues[4]; /* v4k eeprom has 2; the other two stay 0 */ 578 uint32_t regChainOffset; 579 580 OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues)); 581 582 xpdMask = pEepData->modalHeader.xpdGain; 583 584 if (IS_EEP_MINOR_V2(ah)) { 585 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 586 } else { 587 pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 588 } 589 590 pCalBChans = pEepData->calFreqPier2G; 591 numPiers = AR5416_4K_NUM_2G_CAL_PIERS; 592 numXpdGain = 0; 593 594 /* Calculate the value of xpdgains from the xpdGain Mask */ 595 for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 596 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 597 if (numXpdGain >= AR5416_4K_NUM_PD_GAINS) { 598 HALASSERT(0); 599 break; 600 } 601 xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i); 602 numXpdGain++; 603 } 604 } 605 606 /* Write the detector gain biases and their number */ 607 ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues); 608 609 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 610 regChainOffset = ar5416GetRegChainOffset(ah, i); 611 if (pEepData->baseEepHeader.txMask & (1 << i)) { 612 pRawDataset = pEepData->calPierData2G[i]; 613 614 ar9285GetGainBoundariesAndPdadcs(ah, chan, pRawDataset, 615 pCalBChans, numPiers, 616 pdGainOverlap_t2, 617 &tMinCalPower, gainBoundaries, 618 pdadcValues, numXpdGain); 619 620 if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { 621 /* 622 * Note the pdadc table may not start at 0 dBm power, could be 623 * negative or greater than 0. Need to offset the power 624 * values by the amount of minPower for griffin 625 */ 626 ar5416SetGainBoundariesClosedLoop(ah, i, pdGainOverlap_t2, gainBoundaries); 627 } 628 629 /* Write the power values into the baseband power table */ 630 ar5416WritePdadcValues(ah, i, pdadcValues); 631 } 632 } 633 *pTxPowerIndexOffset = 0; 634 635 return AH_TRUE; 636 } 637 638 static void 639 ar9285GetGainBoundariesAndPdadcs(struct ath_hal *ah, 640 const struct ieee80211_channel *chan, 641 CAL_DATA_PER_FREQ_4K *pRawDataSet, 642 uint8_t * bChans, uint16_t availPiers, 643 uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries, 644 uint8_t * pPDADCValues, uint16_t numXpdGains) 645 { 646 647 int i, j, k; 648 int16_t ss; /* potentially -ve index for taking care of pdGainOverlap */ 649 uint16_t idxL, idxR, numPiers; /* Pier indexes */ 650 651 /* filled out Vpd table for all pdGains (chanL) */ 652 static uint8_t vpdTableL[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 653 654 /* filled out Vpd table for all pdGains (chanR) */ 655 static uint8_t vpdTableR[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 656 657 /* filled out Vpd table for all pdGains (interpolated) */ 658 static uint8_t vpdTableI[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 659 660 uint8_t *pVpdL, *pVpdR, *pPwrL, *pPwrR; 661 uint8_t minPwrT4[AR5416_4K_NUM_PD_GAINS]; 662 uint8_t maxPwrT4[AR5416_4K_NUM_PD_GAINS]; 663 int16_t vpdStep; 664 int16_t tmpVal; 665 uint16_t sizeCurrVpdTable, maxIndex, tgtIndex; 666 HAL_BOOL match; 667 int16_t minDelta = 0; 668 CHAN_CENTERS centers; 669 670 ar5416GetChannelCenters(ah, chan, ¢ers); 671 672 /* Trim numPiers for the number of populated channel Piers */ 673 for (numPiers = 0; numPiers < availPiers; numPiers++) { 674 if (bChans[numPiers] == AR5416_BCHAN_UNUSED) { 675 break; 676 } 677 } 678 679 /* Find pier indexes around the current channel */ 680 match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center, 681 IEEE80211_IS_CHAN_2GHZ(chan)), bChans, numPiers, &idxL, &idxR); 682 683 if (match) { 684 /* Directly fill both vpd tables from the matching index */ 685 for (i = 0; i < numXpdGains; i++) { 686 minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; 687 maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; 688 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], 689 pRawDataSet[idxL].pwrPdg[i], 690 pRawDataSet[idxL].vpdPdg[i], 691 AR5416_PD_GAIN_ICEPTS, vpdTableI[i]); 692 } 693 } else { 694 for (i = 0; i < numXpdGains; i++) { 695 pVpdL = pRawDataSet[idxL].vpdPdg[i]; 696 pPwrL = pRawDataSet[idxL].pwrPdg[i]; 697 pVpdR = pRawDataSet[idxR].vpdPdg[i]; 698 pPwrR = pRawDataSet[idxR].pwrPdg[i]; 699 700 /* Start Vpd interpolation from the max of the minimum powers */ 701 minPwrT4[i] = AH_MAX(pPwrL[0], pPwrR[0]); 702 703 /* End Vpd interpolation from the min of the max powers */ 704 maxPwrT4[i] = AH_MIN(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); 705 HALASSERT(maxPwrT4[i] > minPwrT4[i]); 706 707 /* Fill pier Vpds */ 708 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, 709 AR5416_PD_GAIN_ICEPTS, vpdTableL[i]); 710 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, 711 AR5416_PD_GAIN_ICEPTS, vpdTableR[i]); 712 713 /* Interpolate the final vpd */ 714 for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { 715 vpdTableI[i][j] = (uint8_t)(ath_ee_interpolate((uint16_t)FREQ2FBIN(centers.synth_center, 716 IEEE80211_IS_CHAN_2GHZ(chan)), 717 bChans[idxL], bChans[idxR], vpdTableL[i][j], vpdTableR[i][j])); 718 } 719 } 720 } 721 *pMinCalPower = (int16_t)(minPwrT4[0] / 2); 722 723 k = 0; /* index for the final table */ 724 for (i = 0; i < numXpdGains; i++) { 725 if (i == (numXpdGains - 1)) { 726 pPdGainBoundaries[i] = (uint16_t)(maxPwrT4[i] / 2); 727 } else { 728 pPdGainBoundaries[i] = (uint16_t)((maxPwrT4[i] + minPwrT4[i+1]) / 4); 729 } 730 731 pPdGainBoundaries[i] = (uint16_t)AH_MIN(AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); 732 733 /* NB: only applies to owl 1.0 */ 734 if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah) ) { 735 /* 736 * fix the gain delta, but get a delta that can be applied to min to 737 * keep the upper power values accurate, don't think max needs to 738 * be adjusted because should not be at that area of the table? 739 */ 740 minDelta = pPdGainBoundaries[0] - 23; 741 pPdGainBoundaries[0] = 23; 742 } 743 else { 744 minDelta = 0; 745 } 746 747 /* Find starting index for this pdGain */ 748 if (i == 0) { 749 if (AR_SREV_MERLIN_20_OR_LATER(ah)) 750 ss = (int16_t)(0 - (minPwrT4[i] / 2)); 751 else 752 ss = 0; /* for the first pdGain, start from index 0 */ 753 } else { 754 /* need overlap entries extrapolated below. */ 755 ss = (int16_t)((pPdGainBoundaries[i-1] - (minPwrT4[i] / 2)) - tPdGainOverlap + 1 + minDelta); 756 } 757 vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); 758 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 759 /* 760 *-ve ss indicates need to extrapolate data below for this pdGain 761 */ 762 while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 763 tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); 764 pPDADCValues[k++] = (uint8_t)((tmpVal < 0) ? 0 : tmpVal); 765 ss++; 766 } 767 768 sizeCurrVpdTable = (uint8_t)((maxPwrT4[i] - minPwrT4[i]) / 2 +1); 769 tgtIndex = (uint8_t)(pPdGainBoundaries[i] + tPdGainOverlap - (minPwrT4[i] / 2)); 770 maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; 771 772 while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 773 pPDADCValues[k++] = vpdTableI[i][ss++]; 774 } 775 776 vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]); 777 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 778 /* 779 * for last gain, pdGainBoundary == Pmax_t2, so will 780 * have to extrapolate 781 */ 782 if (tgtIndex >= maxIndex) { /* need to extrapolate above */ 783 while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 784 tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + 785 (ss - maxIndex +1) * vpdStep)); 786 pPDADCValues[k++] = (uint8_t)((tmpVal > 255) ? 255 : tmpVal); 787 ss++; 788 } 789 } /* extrapolated above */ 790 } /* for all pdGainUsed */ 791 792 /* Fill out pdGainBoundaries - only up to 2 allowed here, but hardware allows up to 4 */ 793 while (i < AR5416_PD_GAINS_IN_MASK) { 794 pPdGainBoundaries[i] = AR5416_4K_EEP_PD_GAIN_BOUNDARY_DEFAULT; 795 i++; 796 } 797 798 while (k < AR5416_NUM_PDADC_VALUES) { 799 pPDADCValues[k] = pPDADCValues[k-1]; 800 k++; 801 } 802 return; 803 } 804