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