ar9285_reset.c revision 219586
1/* 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2002-2008 Atheros Communications, Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * $FreeBSD: head/sys/dev/ath/ath_hal/ar9002/ar9285_reset.c 219586 2011-03-13 05:54:05Z adrian $ 18 */ 19 20/* 21 * This is almost the same as ar5416_reset.c but uses the v4k EEPROM and 22 * supports only 2Ghz operation. 23 */ 24 25#include "opt_ah.h" 26 27#include "ah.h" 28#include "ah_internal.h" 29#include "ah_devid.h" 30 31#include "ah_eeprom_v14.h" 32#include "ah_eeprom_v4k.h" 33 34#include "ar9002/ar9285.h" 35#include "ar5416/ar5416.h" 36#include "ar5416/ar5416reg.h" 37#include "ar5416/ar5416phy.h" 38 39/* Eeprom versioning macros. Returns true if the version is equal or newer than the ver specified */ 40#define EEP_MINOR(_ah) \ 41 (AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK) 42#define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2) 43#define IS_EEP_MINOR_V3(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_3) 44 45/* Additional Time delay to wait after activiting the Base band */ 46#define BASE_ACTIVATE_DELAY 100 /* 100 usec */ 47#define PLL_SETTLE_DELAY 300 /* 300 usec */ 48#define RTC_PLL_SETTLE_DELAY 1000 /* 1 ms */ 49 50static HAL_BOOL ar9285SetPowerPerRateTable(struct ath_hal *ah, 51 struct ar5416eeprom_4k *pEepData, 52 const struct ieee80211_channel *chan, int16_t *ratesArray, 53 uint16_t cfgCtl, uint16_t AntennaReduction, 54 uint16_t twiceMaxRegulatoryPower, 55 uint16_t powerLimit); 56static HAL_BOOL ar9285SetPowerCalTable(struct ath_hal *ah, 57 struct ar5416eeprom_4k *pEepData, 58 const struct ieee80211_channel *chan, 59 int16_t *pTxPowerIndexOffset); 60static void ar9285GetGainBoundariesAndPdadcs(struct ath_hal *ah, 61 const struct ieee80211_channel *chan, CAL_DATA_PER_FREQ_4K *pRawDataSet, 62 uint8_t * bChans, uint16_t availPiers, 63 uint16_t tPdGainOverlap, int16_t *pMinCalPower, 64 uint16_t * pPdGainBoundaries, uint8_t * pPDADCValues, 65 uint16_t numXpdGains); 66static uint16_t ar9285GetMaxEdgePower(uint16_t, CAL_CTL_EDGES *); 67 68/* XXX gag, this is sick */ 69typedef enum Ar5416_Rates { 70 rate6mb, rate9mb, rate12mb, rate18mb, 71 rate24mb, rate36mb, rate48mb, rate54mb, 72 rate1l, rate2l, rate2s, rate5_5l, 73 rate5_5s, rate11l, rate11s, rateXr, 74 rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3, 75 rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7, 76 rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3, 77 rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7, 78 rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm, 79 Ar5416RateSize 80} AR5416_RATES; 81 82HAL_BOOL 83ar9285SetTransmitPower(struct ath_hal *ah, 84 const struct ieee80211_channel *chan, uint16_t *rfXpdGain) 85{ 86#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) 87#define N(a) (sizeof (a) / sizeof (a[0])) 88 89 MODAL_EEP4K_HEADER *pModal; 90 struct ath_hal_5212 *ahp = AH5212(ah); 91 int16_t ratesArray[Ar5416RateSize]; 92 int16_t txPowerIndexOffset = 0; 93 uint8_t ht40PowerIncForPdadc = 2; 94 int i; 95 96 uint16_t cfgCtl; 97 uint16_t powerLimit; 98 uint16_t twiceAntennaReduction; 99 uint16_t twiceMaxRegulatoryPower; 100 int16_t maxPower; 101 HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 102 struct ar5416eeprom_4k *pEepData = &ee->ee_base; 103 104 HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); 105 106 /* Setup info for the actual eeprom */ 107 OS_MEMZERO(ratesArray, sizeof(ratesArray)); 108 cfgCtl = ath_hal_getctl(ah, chan); 109 powerLimit = chan->ic_maxregpower * 2; 110 twiceAntennaReduction = chan->ic_maxantgain; 111 twiceMaxRegulatoryPower = AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit); 112 pModal = &pEepData->modalHeader; 113 HALDEBUG(ah, HAL_DEBUG_RESET, "%s Channel=%u CfgCtl=%u\n", 114 __func__,chan->ic_freq, cfgCtl ); 115 116 if (IS_EEP_MINOR_V2(ah)) { 117 ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 118 } 119 120 if (!ar9285SetPowerPerRateTable(ah, pEepData, chan, 121 &ratesArray[0],cfgCtl, 122 twiceAntennaReduction, 123 twiceMaxRegulatoryPower, powerLimit)) { 124 HALDEBUG(ah, HAL_DEBUG_ANY, 125 "%s: unable to set tx power per rate table\n", __func__); 126 return AH_FALSE; 127 } 128 129 if (!ar9285SetPowerCalTable(ah, pEepData, chan, &txPowerIndexOffset)) { 130 HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set power table\n", 131 __func__); 132 return AH_FALSE; 133 } 134 135 maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]); 136 maxPower = AH_MAX(maxPower, ratesArray[rate1l]); 137 138 if (IEEE80211_IS_CHAN_HT40(chan)) { 139 maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]); 140 } 141 142 ahp->ah_tx6PowerInHalfDbm = maxPower; 143 AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower; 144 ahp->ah_txPowerIndexOffset = txPowerIndexOffset; 145 146 /* 147 * txPowerIndexOffset is set by the SetPowerTable() call - 148 * adjust the rate table (0 offset if rates EEPROM not loaded) 149 */ 150 for (i = 0; i < N(ratesArray); i++) { 151 ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); 152 /* -5 dBm offset for Merlin and later; this includes Kite */ 153 ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; 154 if (ratesArray[i] > AR5416_MAX_RATE_POWER) 155 ratesArray[i] = AR5416_MAX_RATE_POWER; 156 if (ratesArray[i] < 0) 157 ratesArray[i] = 0; 158 } 159 160#ifdef AH_EEPROM_DUMP 161 ar5416PrintPowerPerRate(ah, ratesArray); 162#endif 163 164 /* Write the OFDM power per rate set */ 165 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, 166 POW_SM(ratesArray[rate18mb], 24) 167 | POW_SM(ratesArray[rate12mb], 16) 168 | POW_SM(ratesArray[rate9mb], 8) 169 | POW_SM(ratesArray[rate6mb], 0) 170 ); 171 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, 172 POW_SM(ratesArray[rate54mb], 24) 173 | POW_SM(ratesArray[rate48mb], 16) 174 | POW_SM(ratesArray[rate36mb], 8) 175 | POW_SM(ratesArray[rate24mb], 0) 176 ); 177 178 /* Write the CCK power per rate set */ 179 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, 180 POW_SM(ratesArray[rate2s], 24) 181 | POW_SM(ratesArray[rate2l], 16) 182 | POW_SM(ratesArray[rateXr], 8) /* XR target power */ 183 | POW_SM(ratesArray[rate1l], 0) 184 ); 185 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, 186 POW_SM(ratesArray[rate11s], 24) 187 | POW_SM(ratesArray[rate11l], 16) 188 | POW_SM(ratesArray[rate5_5s], 8) 189 | POW_SM(ratesArray[rate5_5l], 0) 190 ); 191 HALDEBUG(ah, HAL_DEBUG_RESET, 192 "%s AR_PHY_POWER_TX_RATE3=0x%x AR_PHY_POWER_TX_RATE4=0x%x\n", 193 __func__, OS_REG_READ(ah,AR_PHY_POWER_TX_RATE3), 194 OS_REG_READ(ah,AR_PHY_POWER_TX_RATE4)); 195 196 /* Write the HT20 power per rate set */ 197 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, 198 POW_SM(ratesArray[rateHt20_3], 24) 199 | POW_SM(ratesArray[rateHt20_2], 16) 200 | POW_SM(ratesArray[rateHt20_1], 8) 201 | POW_SM(ratesArray[rateHt20_0], 0) 202 ); 203 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, 204 POW_SM(ratesArray[rateHt20_7], 24) 205 | POW_SM(ratesArray[rateHt20_6], 16) 206 | POW_SM(ratesArray[rateHt20_5], 8) 207 | POW_SM(ratesArray[rateHt20_4], 0) 208 ); 209 210 if (IEEE80211_IS_CHAN_HT40(chan)) { 211 /* Write the HT40 power per rate set */ 212 /* Correct PAR difference between HT40 and HT20/LEGACY */ 213 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, 214 POW_SM(ratesArray[rateHt40_3] + ht40PowerIncForPdadc, 24) 215 | POW_SM(ratesArray[rateHt40_2] + ht40PowerIncForPdadc, 16) 216 | POW_SM(ratesArray[rateHt40_1] + ht40PowerIncForPdadc, 8) 217 | POW_SM(ratesArray[rateHt40_0] + ht40PowerIncForPdadc, 0) 218 ); 219 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, 220 POW_SM(ratesArray[rateHt40_7] + ht40PowerIncForPdadc, 24) 221 | POW_SM(ratesArray[rateHt40_6] + ht40PowerIncForPdadc, 16) 222 | POW_SM(ratesArray[rateHt40_5] + ht40PowerIncForPdadc, 8) 223 | POW_SM(ratesArray[rateHt40_4] + ht40PowerIncForPdadc, 0) 224 ); 225 /* Write the Dup/Ext 40 power per rate set */ 226 OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, 227 POW_SM(ratesArray[rateExtOfdm], 24) 228 | POW_SM(ratesArray[rateExtCck], 16) 229 | POW_SM(ratesArray[rateDupOfdm], 8) 230 | POW_SM(ratesArray[rateDupCck], 0) 231 ); 232 } 233 234 return AH_TRUE; 235#undef POW_SM 236#undef N 237} 238 239HAL_BOOL 240ar9285SetBoardValues(struct ath_hal *ah, const struct ieee80211_channel *chan) 241{ 242 const HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom; 243 const struct ar5416eeprom_4k *eep = &ee->ee_base; 244 const MODAL_EEP4K_HEADER *pModal; 245 uint8_t txRxAttenLocal = 23; 246 247 HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1); 248 pModal = &eep->modalHeader; 249 250 OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 251 OS_REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0, pModal->antCtrlChain[0]); 252 OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4, 253 (OS_REG_READ(ah, AR_PHY_TIMING_CTRL4) & 254 ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 255 SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 256 SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 257 258 if (IS_EEP_MINOR_V3(ah)) { 259 if (IEEE80211_IS_CHAN_HT40(chan)) { 260 /* Overwrite switch settling with HT40 value */ 261 OS_REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, 262 pModal->swSettleHt40); 263 } 264 txRxAttenLocal = pModal->txRxAttenCh[0]; 265 266 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 267 pModal->bswMargin[0]); 268 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN1_DB, 269 pModal->bswAtten[0]); 270 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, 271 pModal->xatten2Margin[0]); 272 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ, AR_PHY_GAIN_2GHZ_XATTEN2_DB, 273 pModal->xatten2Db[0]); 274 275 /* block 1 has the same values as block 0 */ 276 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 277 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); 278 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 279 AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); 280 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 281 AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, pModal->xatten2Margin[0]); 282 OS_REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000, 283 AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); 284 285 } 286 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, 287 AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); 288 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN, 289 AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); 290 291 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, 292 AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); 293 OS_REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000, 294 AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); 295 296 if (AR_SREV_KITE_11(ah)) 297 OS_REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); 298 299 return AH_TRUE; 300} 301 302/* 303 * Helper functions common for AP/CB/XB 304 */ 305 306static HAL_BOOL 307ar9285SetPowerPerRateTable(struct ath_hal *ah, struct ar5416eeprom_4k *pEepData, 308 const struct ieee80211_channel *chan, 309 int16_t *ratesArray, uint16_t cfgCtl, 310 uint16_t AntennaReduction, 311 uint16_t twiceMaxRegulatoryPower, 312 uint16_t powerLimit) 313{ 314#define N(a) (sizeof(a)/sizeof(a[0])) 315/* Local defines to distinguish between extension and control CTL's */ 316#define EXT_ADDITIVE (0x8000) 317#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) 318#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) 319 320 uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 321 int i; 322 int16_t twiceLargestAntenna; 323 CAL_CTL_DATA_4K *rep; 324 CAL_TARGET_POWER_LEG targetPowerOfdm, targetPowerCck = {0, {0, 0, 0, 0}}; 325 CAL_TARGET_POWER_LEG targetPowerOfdmExt = {0, {0, 0, 0, 0}}, targetPowerCckExt = {0, {0, 0, 0, 0}}; 326 CAL_TARGET_POWER_HT targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0}}; 327 int16_t scaledPower, minCtlPower; 328 329#define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ 330 static const uint16_t ctlModesFor11g[] = { 331 CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 332 }; 333 const uint16_t *pCtlMode; 334 uint16_t numCtlModes, ctlMode, freq; 335 CHAN_CENTERS centers; 336 337 ar5416GetChannelCenters(ah, chan, ¢ers); 338 339 /* Compute TxPower reduction due to Antenna Gain */ 340 341 twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; 342 twiceLargestAntenna = (int16_t)AH_MIN((AntennaReduction) - twiceLargestAntenna, 0); 343 344 /* XXX setup for 5212 use (really used?) */ 345 ath_hal_eepromSet(ah, AR_EEP_ANTGAINMAX_2, twiceLargestAntenna); 346 347 /* 348 * scaledPower is the minimum of the user input power level and 349 * the regulatory allowed power level 350 */ 351 scaledPower = AH_MIN(powerLimit, twiceMaxRegulatoryPower + twiceLargestAntenna); 352 353 /* Get target powers from EEPROM - our baseline for TX Power */ 354 /* Setup for CTL modes */ 355 numCtlModes = N(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; /* CTL_11B, CTL_11G, CTL_2GHT20 */ 356 pCtlMode = ctlModesFor11g; 357 358 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 359 AR5416_4K_NUM_2G_CCK_TARGET_POWERS, &targetPowerCck, 4, AH_FALSE); 360 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 361 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerOfdm, 4, AH_FALSE); 362 ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT20, 363 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerHt20, 8, AH_FALSE); 364 365 if (IEEE80211_IS_CHAN_HT40(chan)) { 366 numCtlModes = N(ctlModesFor11g); /* All 2G CTL's */ 367 368 ar5416GetTargetPowers(ah, chan, pEepData->calTargetPower2GHT40, 369 AR5416_4K_NUM_2G_40_TARGET_POWERS, &targetPowerHt40, 8, AH_TRUE); 370 /* Get target powers for extension channels */ 371 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPowerCck, 372 AR5416_4K_NUM_2G_CCK_TARGET_POWERS, &targetPowerCckExt, 4, AH_TRUE); 373 ar5416GetTargetPowersLeg(ah, chan, pEepData->calTargetPower2G, 374 AR5416_4K_NUM_2G_20_TARGET_POWERS, &targetPowerOfdmExt, 4, AH_TRUE); 375 } 376 377 /* 378 * For MIMO, need to apply regulatory caps individually across dynamically 379 * running modes: CCK, OFDM, HT20, HT40 380 * 381 * The outer loop walks through each possible applicable runtime mode. 382 * The inner loop walks through each ctlIndex entry in EEPROM. 383 * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. 384 * 385 */ 386 for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 387 HAL_BOOL isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || 388 (pCtlMode[ctlMode] == CTL_2GHT40); 389 if (isHt40CtlMode) { 390 freq = centers.ctl_center; 391 } else if (pCtlMode[ctlMode] & EXT_ADDITIVE) { 392 freq = centers.ext_center; 393 } else { 394 freq = centers.ctl_center; 395 } 396 397 /* walk through each CTL index stored in EEPROM */ 398 for (i = 0; (i < AR5416_4K_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 399 uint16_t twiceMinEdgePower; 400 401 /* compare test group from regulatory channel list with test mode from pCtlMode list */ 402 if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == pEepData->ctlIndex[i]) || 403 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == 404 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { 405 rep = &(pEepData->ctlData[i]); 406 twiceMinEdgePower = ar9285GetMaxEdgePower(freq, 407 rep->ctlEdges[ 408 owl_get_ntxchains(AH5416(ah)->ah_tx_chainmask) - 1]); 409 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 410 /* Find the minimum of all CTL edge powers that apply to this channel */ 411 twiceMaxEdgePower = AH_MIN(twiceMaxEdgePower, twiceMinEdgePower); 412 } else { 413 /* specific */ 414 twiceMaxEdgePower = twiceMinEdgePower; 415 break; 416 } 417 } 418 } 419 minCtlPower = (uint8_t)AH_MIN(twiceMaxEdgePower, scaledPower); 420 /* Apply ctl mode to correct target power set */ 421 switch(pCtlMode[ctlMode]) { 422 case CTL_11B: 423 for (i = 0; i < N(targetPowerCck.tPow2x); i++) { 424 targetPowerCck.tPow2x[i] = (uint8_t)AH_MIN(targetPowerCck.tPow2x[i], minCtlPower); 425 } 426 break; 427 case CTL_11A: 428 case CTL_11G: 429 for (i = 0; i < N(targetPowerOfdm.tPow2x); i++) { 430 targetPowerOfdm.tPow2x[i] = (uint8_t)AH_MIN(targetPowerOfdm.tPow2x[i], minCtlPower); 431 } 432 break; 433 case CTL_5GHT20: 434 case CTL_2GHT20: 435 for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 436 targetPowerHt20.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt20.tPow2x[i], minCtlPower); 437 } 438 break; 439 case CTL_11B_EXT: 440 targetPowerCckExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerCckExt.tPow2x[0], minCtlPower); 441 break; 442 case CTL_11G_EXT: 443 targetPowerOfdmExt.tPow2x[0] = (uint8_t)AH_MIN(targetPowerOfdmExt.tPow2x[0], minCtlPower); 444 break; 445 case CTL_5GHT40: 446 case CTL_2GHT40: 447 for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 448 targetPowerHt40.tPow2x[i] = (uint8_t)AH_MIN(targetPowerHt40.tPow2x[i], minCtlPower); 449 } 450 break; 451 default: 452 return AH_FALSE; 453 break; 454 } 455 } /* end ctl mode checking */ 456 457 /* Set rates Array from collected data */ 458 ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = ratesArray[rate18mb] = ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0]; 459 ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; 460 ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; 461 ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; 462 ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; 463 464 for (i = 0; i < N(targetPowerHt20.tPow2x); i++) { 465 ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; 466 } 467 468 ratesArray[rate1l] = targetPowerCck.tPow2x[0]; 469 ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; 470 ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; 471 ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; 472 if (IEEE80211_IS_CHAN_HT40(chan)) { 473 for (i = 0; i < N(targetPowerHt40.tPow2x); i++) { 474 ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; 475 } 476 ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; 477 ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; 478 ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; 479 if (IEEE80211_IS_CHAN_2GHZ(chan)) { 480 ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; 481 } 482 } 483 return AH_TRUE; 484#undef EXT_ADDITIVE 485#undef CTL_11G_EXT 486#undef CTL_11B_EXT 487#undef SUB_NUM_CTL_MODES_AT_2G_40 488#undef N 489} 490 491/************************************************************************** 492 * fbin2freq 493 * 494 * Get channel value from binary representation held in eeprom 495 * RETURNS: the frequency in MHz 496 */ 497static uint16_t 498fbin2freq(uint8_t fbin) 499{ 500 /* 501 * Reserved value 0xFF provides an empty definition both as 502 * an fbin and as a frequency - do not convert 503 */ 504 if (fbin == AR5416_BCHAN_UNUSED) { 505 return fbin; 506 } 507 508 return (uint16_t)(2300 + fbin); 509} 510 511/* 512 * XXX almost the same as ar5416GetMaxEdgePower. 513 */ 514static uint16_t 515ar9285GetMaxEdgePower(uint16_t freq, CAL_CTL_EDGES *pRdEdgesPower) 516{ 517 uint16_t twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 518 int i; 519 520 /* Get the edge power */ 521 for (i = 0; (i < AR5416_NUM_BAND_EDGES) && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED) ; i++) { 522 /* 523 * If there's an exact channel match or an inband flag set 524 * on the lower channel use the given rdEdgePower 525 */ 526 if (freq == fbin2freq(pRdEdgesPower[i].bChannel)) { 527 twiceMaxEdgePower = MS(pRdEdgesPower[i].tPowerFlag, CAL_CTL_EDGES_POWER); 528 break; 529 } else if ((i > 0) && (freq < fbin2freq(pRdEdgesPower[i].bChannel))) { 530 if (fbin2freq(pRdEdgesPower[i - 1].bChannel) < freq && (pRdEdgesPower[i - 1].tPowerFlag & CAL_CTL_EDGES_FLAG) != 0) { 531 twiceMaxEdgePower = MS(pRdEdgesPower[i - 1].tPowerFlag, CAL_CTL_EDGES_POWER); 532 } 533 /* Leave loop - no more affecting edges possible in this monotonic increasing list */ 534 break; 535 } 536 } 537 HALASSERT(twiceMaxEdgePower > 0); 538 return twiceMaxEdgePower; 539} 540 541 542 543static HAL_BOOL 544ar9285SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom_4k *pEepData, 545 const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset) 546{ 547 CAL_DATA_PER_FREQ_4K *pRawDataset; 548 uint8_t *pCalBChans = AH_NULL; 549 uint16_t pdGainOverlap_t2; 550 static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES]; 551 uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK]; 552 uint16_t numPiers, i; 553 int16_t tMinCalPower; 554 uint16_t numXpdGain, xpdMask; 555 uint16_t xpdGainValues[4]; /* v4k eeprom has 2; the other two stay 0 */ 556 uint32_t regChainOffset; 557 558 OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues)); 559 560 xpdMask = pEepData->modalHeader.xpdGain; 561 562 if (IS_EEP_MINOR_V2(ah)) { 563 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 564 } else { 565 pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 566 } 567 568 pCalBChans = pEepData->calFreqPier2G; 569 numPiers = AR5416_4K_NUM_2G_CAL_PIERS; 570 numXpdGain = 0; 571 572 /* Calculate the value of xpdgains from the xpdGain Mask */ 573 for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 574 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 575 if (numXpdGain >= AR5416_4K_NUM_PD_GAINS) { 576 HALASSERT(0); 577 break; 578 } 579 xpdGainValues[numXpdGain] = (uint16_t)(AR5416_PD_GAINS_IN_MASK - i); 580 numXpdGain++; 581 } 582 } 583 584 /* Write the detector gain biases and their number */ 585 ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues); 586 587 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 588 regChainOffset = ar5416GetRegChainOffset(ah, i); 589 if (pEepData->baseEepHeader.txMask & (1 << i)) { 590 pRawDataset = pEepData->calPierData2G[i]; 591 592 ar9285GetGainBoundariesAndPdadcs(ah, chan, pRawDataset, 593 pCalBChans, numPiers, 594 pdGainOverlap_t2, 595 &tMinCalPower, gainBoundaries, 596 pdadcValues, numXpdGain); 597 598 if ((i == 0) || AR_SREV_OWL_20_OR_LATER(ah)) { 599 /* 600 * Note the pdadc table may not start at 0 dBm power, could be 601 * negative or greater than 0. Need to offset the power 602 * values by the amount of minPower for griffin 603 */ 604 ar5416SetGainBoundariesClosedLoop(ah, i, pdGainOverlap_t2, gainBoundaries); 605 } 606 607 /* Write the power values into the baseband power table */ 608 ar5416WritePdadcValues(ah, i, pdadcValues); 609 } 610 } 611 *pTxPowerIndexOffset = 0; 612 613 return AH_TRUE; 614} 615 616static void 617ar9285GetGainBoundariesAndPdadcs(struct ath_hal *ah, 618 const struct ieee80211_channel *chan, 619 CAL_DATA_PER_FREQ_4K *pRawDataSet, 620 uint8_t * bChans, uint16_t availPiers, 621 uint16_t tPdGainOverlap, int16_t *pMinCalPower, uint16_t * pPdGainBoundaries, 622 uint8_t * pPDADCValues, uint16_t numXpdGains) 623{ 624 625 int i, j, k; 626 int16_t ss; /* potentially -ve index for taking care of pdGainOverlap */ 627 uint16_t idxL, idxR, numPiers; /* Pier indexes */ 628 629 /* filled out Vpd table for all pdGains (chanL) */ 630 static uint8_t vpdTableL[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 631 632 /* filled out Vpd table for all pdGains (chanR) */ 633 static uint8_t vpdTableR[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 634 635 /* filled out Vpd table for all pdGains (interpolated) */ 636 static uint8_t vpdTableI[AR5416_4K_NUM_PD_GAINS][AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 637 638 uint8_t *pVpdL, *pVpdR, *pPwrL, *pPwrR; 639 uint8_t minPwrT4[AR5416_4K_NUM_PD_GAINS]; 640 uint8_t maxPwrT4[AR5416_4K_NUM_PD_GAINS]; 641 int16_t vpdStep; 642 int16_t tmpVal; 643 uint16_t sizeCurrVpdTable, maxIndex, tgtIndex; 644 HAL_BOOL match; 645 int16_t minDelta = 0; 646 CHAN_CENTERS centers; 647 648 ar5416GetChannelCenters(ah, chan, ¢ers); 649 650 /* Trim numPiers for the number of populated channel Piers */ 651 for (numPiers = 0; numPiers < availPiers; numPiers++) { 652 if (bChans[numPiers] == AR5416_BCHAN_UNUSED) { 653 break; 654 } 655 } 656 657 /* Find pier indexes around the current channel */ 658 match = ath_ee_getLowerUpperIndex((uint8_t)FREQ2FBIN(centers.synth_center, 659 IEEE80211_IS_CHAN_2GHZ(chan)), bChans, numPiers, &idxL, &idxR); 660 661 if (match) { 662 /* Directly fill both vpd tables from the matching index */ 663 for (i = 0; i < numXpdGains; i++) { 664 minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; 665 maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; 666 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], 667 pRawDataSet[idxL].pwrPdg[i], 668 pRawDataSet[idxL].vpdPdg[i], 669 AR5416_PD_GAIN_ICEPTS, vpdTableI[i]); 670 } 671 } else { 672 for (i = 0; i < numXpdGains; i++) { 673 pVpdL = pRawDataSet[idxL].vpdPdg[i]; 674 pPwrL = pRawDataSet[idxL].pwrPdg[i]; 675 pVpdR = pRawDataSet[idxR].vpdPdg[i]; 676 pPwrR = pRawDataSet[idxR].pwrPdg[i]; 677 678 /* Start Vpd interpolation from the max of the minimum powers */ 679 minPwrT4[i] = AH_MAX(pPwrL[0], pPwrR[0]); 680 681 /* End Vpd interpolation from the min of the max powers */ 682 maxPwrT4[i] = AH_MIN(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); 683 HALASSERT(maxPwrT4[i] > minPwrT4[i]); 684 685 /* Fill pier Vpds */ 686 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrL, pVpdL, 687 AR5416_PD_GAIN_ICEPTS, vpdTableL[i]); 688 ath_ee_FillVpdTable(minPwrT4[i], maxPwrT4[i], pPwrR, pVpdR, 689 AR5416_PD_GAIN_ICEPTS, vpdTableR[i]); 690 691 /* Interpolate the final vpd */ 692 for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { 693 vpdTableI[i][j] = (uint8_t)(ath_ee_interpolate((uint16_t)FREQ2FBIN(centers.synth_center, 694 IEEE80211_IS_CHAN_2GHZ(chan)), 695 bChans[idxL], bChans[idxR], vpdTableL[i][j], vpdTableR[i][j])); 696 } 697 } 698 } 699 *pMinCalPower = (int16_t)(minPwrT4[0] / 2); 700 701 k = 0; /* index for the final table */ 702 for (i = 0; i < numXpdGains; i++) { 703 if (i == (numXpdGains - 1)) { 704 pPdGainBoundaries[i] = (uint16_t)(maxPwrT4[i] / 2); 705 } else { 706 pPdGainBoundaries[i] = (uint16_t)((maxPwrT4[i] + minPwrT4[i+1]) / 4); 707 } 708 709 pPdGainBoundaries[i] = (uint16_t)AH_MIN(AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); 710 711 /* NB: only applies to owl 1.0 */ 712 if ((i == 0) && !AR_SREV_OWL_20_OR_LATER(ah) ) { 713 /* 714 * fix the gain delta, but get a delta that can be applied to min to 715 * keep the upper power values accurate, don't think max needs to 716 * be adjusted because should not be at that area of the table? 717 */ 718 minDelta = pPdGainBoundaries[0] - 23; 719 pPdGainBoundaries[0] = 23; 720 } 721 else { 722 minDelta = 0; 723 } 724 725 /* Find starting index for this pdGain */ 726 if (i == 0) { 727 if (AR_SREV_MERLIN_20_OR_LATER(ah)) 728 ss = (int16_t)(0 - (minPwrT4[i] / 2)); 729 else 730 ss = 0; /* for the first pdGain, start from index 0 */ 731 } else { 732 /* need overlap entries extrapolated below. */ 733 ss = (int16_t)((pPdGainBoundaries[i-1] - (minPwrT4[i] / 2)) - tPdGainOverlap + 1 + minDelta); 734 } 735 vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); 736 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 737 /* 738 *-ve ss indicates need to extrapolate data below for this pdGain 739 */ 740 while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 741 tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); 742 pPDADCValues[k++] = (uint8_t)((tmpVal < 0) ? 0 : tmpVal); 743 ss++; 744 } 745 746 sizeCurrVpdTable = (uint8_t)((maxPwrT4[i] - minPwrT4[i]) / 2 +1); 747 tgtIndex = (uint8_t)(pPdGainBoundaries[i] + tPdGainOverlap - (minPwrT4[i] / 2)); 748 maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; 749 750 while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 751 pPDADCValues[k++] = vpdTableI[i][ss++]; 752 } 753 754 vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - vpdTableI[i][sizeCurrVpdTable - 2]); 755 vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 756 /* 757 * for last gain, pdGainBoundary == Pmax_t2, so will 758 * have to extrapolate 759 */ 760 if (tgtIndex >= maxIndex) { /* need to extrapolate above */ 761 while ((ss <= tgtIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 762 tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + 763 (ss - maxIndex +1) * vpdStep)); 764 pPDADCValues[k++] = (uint8_t)((tmpVal > 255) ? 255 : tmpVal); 765 ss++; 766 } 767 } /* extrapolated above */ 768 } /* for all pdGainUsed */ 769 770 /* Fill out pdGainBoundaries - only up to 2 allowed here, but hardware allows up to 4 */ 771 while (i < AR5416_PD_GAINS_IN_MASK) { 772 pPdGainBoundaries[i] = pPdGainBoundaries[i-1]; 773 i++; 774 } 775 776 while (k < AR5416_NUM_PDADC_VALUES) { 777 pPDADCValues[k] = pPDADCValues[k-1]; 778 k++; 779 } 780 return; 781} 782