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